A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 4357 lines 129 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2005-2007 Miika Pekkarinen 11 * Copyright (C) 2007-2008 Nicolas Pennequin 12 * Copyright (C) 2011 Michael Sevakis 13 * 14 * This program is free software; you can redistribute it and/or 15 * modify it under the terms of the GNU General Public License 16 * as published by the Free Software Foundation; either version 2 17 * of the License, or (at your option) any later version. 18 * 19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 20 * KIND, either express or implied. 21 * 22 ****************************************************************************/ 23#include "config.h" 24#include "system.h" 25#include "version.h" 26#include "kernel.h" 27#include "panic.h" 28#include "core_alloc.h" 29#include "sound.h" 30#include "codecs.h" 31#include "codec_thread.h" 32#include "voice_thread.h" 33#include "metadata.h" 34#include "cuesheet.h" 35#include "buffering.h" 36#include "talk.h" 37#include "playlist.h" 38#include "abrepeat.h" 39#ifdef HAVE_PLAY_FREQ 40#include "pcm_mixer.h" 41#endif 42#include "pcmbuf.h" 43#include "audio_thread.h" 44#include "playback.h" 45#include "storage.h" 46#include "misc.h" 47#include "settings.h" 48#include "audiohw.h" 49#include "general.h" 50#include <stdio.h> 51 52#ifdef HAVE_TAGCACHE 53#include "tagcache.h" 54#endif 55 56#ifdef HAVE_ALBUMART 57#include "albumart.h" 58#endif 59 60#ifdef HAVE_PLAY_FREQ 61#include "pcm_mixer.h" 62#endif 63 64#if defined(SIMULATOR) || defined(SDLAPP) 65#include <strings.h> /* For strncasecmp() */ 66#endif 67 68#ifdef USB_ENABLE_AUDIO 69#include "usbstack/usb_audio.h" 70#include "splash.h" 71#include "lang.h" 72#endif 73 74/* TODO: The audio thread really is doing multitasking of acting like a 75 consumer and producer of tracks. It may be advantageous to better 76 logically separate the two functions. I won't go that far just yet. */ 77 78/* Internal support for voice playback */ 79#define PLAYBACK_VOICE 80 81#if CONFIG_PLATFORM & PLATFORM_NATIVE 82/* Application builds don't support direct code loading */ 83#define HAVE_CODEC_BUFFERING 84#endif 85 86/* Amount of guess-space to allow for codecs that must hunt and peck 87 * for their correct seek target, 32k seems a good size */ 88#define AUDIO_REBUFFER_GUESS_SIZE (1024*32) 89 90/* Define LOGF_ENABLE to enable logf output in this file */ 91#if 0 92#define LOGF_ENABLE 93#endif 94#include "logf.h" 95 96/* Macros to enable logf for queues 97 logging on SYS_TIMEOUT can be disabled */ 98#ifdef SIMULATOR 99/* Define this for logf output of all queuing except SYS_TIMEOUT */ 100#define PLAYBACK_LOGQUEUES 101/* Define this to logf SYS_TIMEOUT messages */ 102/*#define PLAYBACK_LOGQUEUES_SYS_TIMEOUT*/ 103#endif 104 105#ifdef PLAYBACK_LOGQUEUES 106#define LOGFQUEUE logf 107#else 108#define LOGFQUEUE(...) 109#endif 110 111#ifdef PLAYBACK_LOGQUEUES_SYS_TIMEOUT 112#define LOGFQUEUE_SYS_TIMEOUT logf 113#else 114#define LOGFQUEUE_SYS_TIMEOUT(...) 115#endif 116 117/* Variables are commented with the threads that use them: 118 * A=audio, C=codec, O=other. A suffix of "-" indicates that the variable is 119 * read but not updated on that thread. Audio is the only user unless otherwise 120 * specified. 121 */ 122 123/** Miscellaneous **/ 124extern unsigned int audio_thread_id; /* from audio_thread.c */ 125extern struct event_queue audio_queue; /* from audio_thread.c */ 126extern bool audio_is_initialized; /* from audio_thread.c */ 127extern struct codec_api ci; /* from codecs.c */ 128 129/** Possible arrangements of the main buffer **/ 130static enum audio_buffer_state 131{ 132 AUDIOBUF_STATE_TRASHED = -1, /* trashed; must be reset */ 133 AUDIOBUF_STATE_INITIALIZED = 0, /* voice+audio OR audio-only */ 134} buffer_state = AUDIOBUF_STATE_TRASHED; /* (A,O) */ 135 136/** Main state control **/ 137static bool ff_rw_mode SHAREDBSS_ATTR = false; /* Pre-ff-rewind mode (A,O-) */ 138 139static enum play_status 140{ 141 PLAY_STOPPED = 0, 142 PLAY_PLAYING = AUDIO_STATUS_PLAY, 143 PLAY_PAUSED = AUDIO_STATUS_PLAY | AUDIO_STATUS_PAUSE, 144} play_status = PLAY_STOPPED; 145 146/* Sizeable things that only need exist during playback and not when stopped */ 147static struct audio_scratch_memory 148{ 149 struct mp3entry codec_id3; /* (A,C) */ 150 struct mp3entry unbuffered_id3; 151 struct cuesheet *curr_cue; /* Will follow this structure */ 152} * audio_scratch_memory = NULL; 153 154/* These are used to store the current, next and optionally the peek-ahead 155 * mp3entry's - this guarantees that the pointer returned by audio_current/ 156 * next_track will be valid for the full duration of the currently playing 157 * track */ 158enum audio_id3_types 159{ 160 /* These are allocated statically */ 161 PLAYING_ID3 = 0, 162 NEXTTRACK_ID3, 163#ifdef AUDIO_FAST_SKIP_PREVIEW 164 /* The real playing metadata must has to be protected since it contains 165 critical info for other features */ 166 PLAYING_PEEK_ID3, 167#endif 168 ID3_TYPE_NUM_STATIC, 169 /* These go in the scratch memory */ 170 UNBUFFERED_ID3 = ID3_TYPE_NUM_STATIC, 171 CODEC_ID3, 172}; 173static struct mp3entry static_id3_entries[ID3_TYPE_NUM_STATIC]; /* (A,O) */ 174 175struct audio_resume_info 176{ 177 unsigned long elapsed; 178 unsigned long offset; 179}; 180 181/* Peeking functions can yield and mess us up */ 182static struct mutex id3_mutex SHAREDBSS_ATTR; /* (A,O)*/ 183 184/** For album art support **/ 185#define MAX_MULTIPLE_AA SKINNABLE_SCREENS_COUNT 186#ifdef HAVE_ALBUMART 187 188static int albumart_mode = -1; 189 190static struct albumart_slot 191{ 192 struct dim dim; /* Holds width, height of the albumart */ 193 int used; /* Counter; increments if something uses it */ 194} albumart_slots[MAX_MULTIPLE_AA]; /* (A,O) */ 195 196static char last_folder_aa_path[MAX_PATH] = "\0"; 197static int last_folder_aa_hid[MAX_MULTIPLE_AA] = {0}; 198 199#define FOREACH_ALBUMART(i) for (int i = 0; i < MAX_MULTIPLE_AA; i++) 200#endif /* HAVE_ALBUMART */ 201 202 203/** Information used for tracking buffer fills **/ 204 205/* Buffer and thread state tracking */ 206static enum filling_state 207{ 208 STATE_IDLE = 0, /* audio is stopped: nothing to do */ 209 STATE_FILLING, /* adding tracks to the buffer */ 210 STATE_FULL, /* can't add any more tracks */ 211 STATE_END_OF_PLAYLIST, /* all remaining tracks have been added */ 212 STATE_FINISHED, /* all remaining tracks are fully buffered */ 213 STATE_ENDING, /* audio playback is ending */ 214 STATE_ENDED, /* audio playback is done */ 215 STATE_STOPPED, /* buffering is stopped explicitly */ 216} filling = STATE_IDLE; 217 218/* Track info - holds information about each track in the buffer */ 219#ifdef HAVE_ALBUMART 220#define TRACK_INFO_AA MAX_MULTIPLE_AA 221#else 222#define TRACK_INFO_AA 0 223#endif 224 225#ifdef HAVE_CODEC_BUFFERING 226#define TRACK_INFO_CODEC 1 227#else 228#define TRACK_INFO_CODEC 0 229#endif 230 231#define TRACK_INFO_HANDLES (3 + TRACK_INFO_AA + TRACK_INFO_CODEC) 232 233struct track_info 234{ 235 int self_hid; /* handle for the info on buffer */ 236 237 /* In per-track allocated order: */ 238 union { 239 int handle[TRACK_INFO_HANDLES]; /* array mirror for efficient wipe/close */ 240 struct { 241 int id3_hid; /* Metadata handle ID */ 242 int cuesheet_hid; /* Parsed cuesheet handle ID */ 243#ifdef HAVE_ALBUMART 244 int aa_hid[MAX_MULTIPLE_AA]; /* Album art handle IDs */ 245#endif 246#ifdef HAVE_CODEC_BUFFERING 247 int codec_hid; /* Buffered codec handle ID */ 248#endif 249 int audio_hid; /* Main audio data handle ID */ 250 }; }; 251}; 252 253/* On-buffer info format; includes links */ 254struct track_buf_info 255{ 256 int link[2]; /* prev/next handles */ 257 struct track_info info; 258}; 259 260#define FOR_EACH_TRACK_INFO_HANDLE(i) \ 261 for (int i = 0; i < TRACK_INFO_HANDLES; i++) 262 263static struct 264{ 265 /* TODO: perhaps cache -1/+1 delta handles if speed ever matters much 266 because those lookups are common; also could cache a few recent 267 acccesses */ 268 int first_hid; /* handle of first track in list */ 269 int current_hid; /* handle of track delta 0 */ 270 int last_hid; /* handle of last track in list */ 271 int in_progress_hid; /* track in process of loading */ 272 unsigned int count; /* number of tracks in list */ 273} track_list; /* (A, O-) */ 274 275 276/* Playlist steps from playlist position to next track to be buffered */ 277static int playlist_peek_offset = 0; 278 279#ifdef HAVE_DISK_STORAGE 280/* Buffer margin A.K.A. anti-skip buffer (in seconds) */ 281static size_t buffer_margin = 5; 282#endif 283 284/* Values returned for track loading */ 285enum track_load_status 286{ 287 LOAD_TRACK_ERR_START_CODEC = -6, 288 LOAD_TRACK_ERR_FINISH_FAILED = -5, 289 LOAD_TRACK_ERR_FINISH_FULL = -4, 290 LOAD_TRACK_ERR_BUSY = -3, 291 LOAD_TRACK_ERR_NO_MORE = -2, 292 LOAD_TRACK_ERR_FAILED = -1, 293 LOAD_TRACK_OK = 0, 294 LOAD_TRACK_READY = 1, 295}; 296 297/** Track change controls **/ 298 299/* What sort of skip is pending globally? */ 300static enum track_skip_type 301{ 302 /* Relative to what user is intended to see: */ 303 /* Codec: +0, Track List: +0, Playlist: +0 */ 304 TRACK_SKIP_NONE = 0, /* no track skip */ 305 /* Codec: +1, Track List: +1, Playlist: +0 */ 306 TRACK_SKIP_AUTO, /* codec-initiated skip */ 307 /* Codec: +1, Track List: +1, Playlist: +1 */ 308 TRACK_SKIP_AUTO_NEW_PLAYLIST, /* codec-initiated skip is new playlist */ 309 /* Codec: xx, Track List: +0, Playlist: +0 */ 310 TRACK_SKIP_AUTO_END_PLAYLIST, /* codec-initiated end of playlist */ 311 /* Manual skip: Never pends */ 312 TRACK_SKIP_MANUAL, /* manual track skip */ 313 /* Manual skip: Never pends */ 314 TRACK_SKIP_DIR_CHANGE, /* manual directory skip */ 315} skip_pending = TRACK_SKIP_NONE; 316 317/* Note about TRACK_SKIP_AUTO_NEW_PLAYLIST: 318 Fixing playlist code to be able to peek into the first song of 319 the next playlist would fix any issues and this wouldn't need 320 to be a special case since pre-advancing the playlist would be 321 unneeded - it could be much more like TRACK_SKIP_AUTO and all 322 actions that require reversal during an in-progress transition 323 would work as expected */ 324 325/* Used to indicate status for the events. Must be separate to satisfy all 326 clients so the correct metadata is read when sending the change events. */ 327static unsigned int track_event_flags = TEF_NONE; /* (A, O-) */ 328 329/* Pending manual track skip offset */ 330static int skip_offset = 0; /* (A, O) */ 331 332static bool track_skip_is_manual = false; 333 334/* Track change notification */ 335static struct 336{ 337 unsigned int in; /* Number of pcmbuf posts (audio isr) */ 338 unsigned int out; /* Number of times audio has read the difference */ 339} track_change = { 0, 0 }; 340 341/** Codec status **/ 342/* Did the codec notify us it finished while we were paused or while still 343 in an automatic transition? 344 345 If paused, it is necessary to defer a codec-initiated skip until resuming 346 or else the track will move forward while not playing audio! 347 348 If in-progress, skips should not build-up ahead of where the WPS is when 349 really short tracks finish decoding. 350 351 If it is forgotten, it will be missed altogether and playback will just sit 352 there looking stupid and comatose until the user does something */ 353static bool codec_skip_pending = false; 354static int codec_skip_status; 355static bool codec_seeking = false; /* Codec seeking ack expected? */ 356static unsigned int position_key = 0; 357 358#define PLAYBACK_LOG_PATH ROCKBOX_DIR "/playback.log" 359#define PLAYBACK_LOG_MAX_FILESZ_BYTES (511 << 10) /* 512k approx 1000-2500 tracks */ 360#define PLAYBACK_LOG_MIN_ELAPSED_MS (500) /* 500 milliseconds */ 361#if (CONFIG_STORAGE & STORAGE_ATA) 362#define PLAYBACK_LOG_BUFSZ (MAX_PATH * 10) 363static int playback_log_handle = 0; /* core_alloc handle for playback log buffer */ 364#endif 365 366/* Forward declarations */ 367enum audio_start_playback_flags 368{ 369 AUDIO_START_RESTART = 0x1, /* "Restart" playback (flush _all_ tracks) */ 370 AUDIO_START_NEWBUF = 0x2, /* Mark the audiobuffer as invalid */ 371}; 372 373static void audio_start_playback(const struct audio_resume_info *resume_info, 374 unsigned int flags); 375static void audio_stop_playback(void); 376static void buffer_event_buffer_low_callback(unsigned short id, void *data, void *user_data); 377static void buffer_event_rebuffer_callback(unsigned short id, void *data); 378static void buffer_event_finished_callback(unsigned short id, void *data); 379void audio_pcmbuf_sync_position(void); 380 381 382/**************************************/ 383 384/** --- MP3Entry --- **/ 385 386/* Does the mp3entry have enough info for us to use it? */ 387static struct mp3entry * valid_mp3entry(const struct mp3entry *id3) 388{ 389 return id3 && (id3->length != 0 || id3->filesize != 0) && 390 id3->codectype != AFMT_UNKNOWN ? (struct mp3entry *)id3 : NULL; 391} 392 393/* Return a pointer to an mp3entry on the buffer, as it is */ 394static struct mp3entry * bufgetid3(int handle_id) 395{ 396 if (handle_id < 0) 397 return NULL; 398 399 struct mp3entry *id3; 400 ssize_t ret = bufgetdata(handle_id, 0, (void *)&id3); 401 402 if (ret != sizeof(struct mp3entry)) 403 return NULL; 404 405 return id3; 406} 407 408/* Read an mp3entry from the buffer, adjusted */ 409static bool bufreadid3(int handle_id, struct mp3entry *id3out) 410{ 411 struct mp3entry *id3 = bufgetid3(handle_id); 412 413 if (id3) 414 { 415 copy_mp3entry(id3out, id3); 416 return true; 417 } 418 419 return false; 420} 421 422/* Lock the id3 mutex */ 423static void id3_mutex_lock(void) 424{ 425 mutex_lock(&id3_mutex); 426} 427 428/* Unlock the id3 mutex */ 429static void id3_mutex_unlock(void) 430{ 431 mutex_unlock(&id3_mutex); 432} 433 434/* Return one of the collection of mp3entry pointers - collect them all here */ 435static inline struct mp3entry * id3_get(enum audio_id3_types id3_num) 436{ 437 switch (id3_num) 438 { 439 case UNBUFFERED_ID3: 440 return &audio_scratch_memory->unbuffered_id3; 441 case CODEC_ID3: 442 return &audio_scratch_memory->codec_id3; 443 default: 444 return &static_id3_entries[id3_num]; 445 } 446} 447 448struct mp3entry* get_temp_mp3entry(struct mp3entry *free) 449{ 450 /* free should be NULL on first call pass back the returned mp3entry to unlock */ 451 enum audio_id3_types id3_num = UNBUFFERED_ID3; 452 /* playback hasn't started return NEXTTRACK_ID3 (statically allocated) */ 453 if (!audio_scratch_memory) 454 id3_num = NEXTTRACK_ID3; 455 456 if (free) 457 { 458 /* scratch_mem_init() has to aquire the lock 459 * to change id3_num via audio_scratch_memory.. */ 460 if (free == id3_get(id3_num)) 461 id3_mutex_unlock(); 462 463 return NULL; 464 } 465 id3_mutex_lock(); 466 467 struct mp3entry *temp_id3 = id3_get(id3_num); 468 wipe_mp3entry(temp_id3); 469 return temp_id3; 470} 471 472/* Copy an mp3entry into one of the mp3 entries */ 473static void id3_write(enum audio_id3_types id3_num, 474 const struct mp3entry *id3_src) 475{ 476 struct mp3entry *dest_id3 = id3_get(id3_num); 477 478 if (id3_src) 479 copy_mp3entry(dest_id3, id3_src); 480 else 481 wipe_mp3entry(dest_id3); 482} 483 484/* Call id3_write "safely" because peek aheads can yield, even if the fast 485 preview isn't enabled */ 486static void id3_write_locked(enum audio_id3_types id3_num, 487 const struct mp3entry *id3_src) 488{ 489 id3_mutex_lock(); 490 id3_write(id3_num, id3_src); 491 id3_mutex_unlock(); 492} 493 494 495/** --- Track info --- **/ 496 497#ifdef HAVE_CODEC_BUFFERING 498static void track_info_close_handle(int *hidp) 499{ 500 bufclose(*hidp); 501 *hidp = ERR_HANDLE_NOT_FOUND; 502} 503#endif /* HAVE_CODEC_BUFFERING */ 504 505/* Invalidate all members to initial values - does not close handles or sync */ 506static void track_info_wipe(struct track_info *infop) 507{ 508 /* don't touch ->self_hid */ 509 510 FOR_EACH_TRACK_INFO_HANDLE(i) 511 infop->handle[i] = ERR_HANDLE_NOT_FOUND; 512} 513 514/** --- Track list --- **/ 515 516/* Clear tracks in the list, optionally preserving the current track - 517 returns 'false' if the operation was changed */ 518enum track_clear_action 519{ 520 TRACK_LIST_CLEAR_ALL = 0, /* Clear all tracks */ 521 TRACK_LIST_KEEP_CURRENT, /* Keep current only; clear before + after */ 522 TRACK_LIST_KEEP_NEW /* Keep current and those that follow */ 523}; 524 525/* Initialize the track list */ 526static void INIT_ATTR track_list_init(void) 527{ 528 track_list.first_hid = 0; 529 track_list.current_hid = 0; 530 track_list.last_hid = 0; 531 track_list.in_progress_hid = 0; 532 track_list.count = 0; 533} 534 535/* Return number of items allocated in the list */ 536static inline unsigned int track_list_count(void) 537{ 538 return track_list.count; 539} 540 541/* Return true if the list is empty */ 542static inline bool track_list_empty(void) 543{ 544 return track_list.count == 0; 545} 546 547/* Returns a pointer to the track info data on the buffer */ 548static struct track_buf_info * track_buf_info_get(int hid) 549{ 550 void *p; 551 ssize_t size = bufgetdata(hid, sizeof (struct track_buf_info), &p); 552 return size == (ssize_t)sizeof (struct track_buf_info) ? p : NULL; 553} 554 555/* Synchronize the buffer object with the cached track info */ 556static bool track_info_sync(const struct track_info *infop) 557{ 558 struct track_buf_info *tbip = track_buf_info_get(infop->self_hid); 559 if (!tbip) 560 return false; 561 562 tbip->info = *infop; 563 return true; 564} 565 566/* Return track info a given offset from the info referenced by hid and 567 * place a copy into *infop, if provided */ 568static struct track_buf_info * 569 track_list_get_info_from(int hid, int offset, struct track_info *infop) 570{ 571 int sgn = SGN(offset); 572 struct track_buf_info *tbip; 573 574 while (1) 575 { 576 if (!(tbip = track_buf_info_get(hid))) 577 break; 578 579 if (!offset) 580 break; 581 582 if ((hid = tbip->link[(unsigned)(sgn + 1) / 2]) <= 0) 583 { 584 tbip = NULL; 585 break; 586 } 587 588 offset -= sgn; 589 } 590 591 if (infop) 592 { 593 if (tbip) 594 { 595 *infop = tbip->info; 596 } 597 else 598 { 599 track_info_wipe(infop); 600 infop->self_hid = ERR_HANDLE_NOT_FOUND; 601 } 602 } 603 604 return tbip; 605} 606 607/* Commit the track info to the buffer updated with the provided source info */ 608static bool track_list_commit_buf_info(struct track_buf_info *tbip, 609 const struct track_info *src_infop) 610{ 611 /* Leaves the list unmodified if anything fails */ 612 if (tbip->link[1] != ERR_HANDLE_NOT_FOUND) 613 return false; 614 615 int hid = tbip->info.self_hid; 616 int last_hid = track_list.last_hid; 617 struct track_buf_info *last_tbip = NULL; 618 619 if (last_hid > 0 && !(last_tbip = track_buf_info_get(last_hid))) 620 return false; 621 622 tbip->info = *src_infop; 623 624 /* Insert last */ 625 tbip->link[0] = last_hid; 626 tbip->link[1] = 0; /* "In list" */ 627 628 if (last_tbip) 629 { 630 last_tbip->link[1] = hid; 631 } 632 else 633 { 634 track_list.first_hid = hid; 635 track_list.current_hid = hid; 636 } 637 638 track_list.last_hid = hid; 639 track_list.count++; 640 return true; 641} 642 643#ifdef HAVE_ALBUMART 644static inline void clear_cached_aa_handles(int* aa_handles) 645{ 646 if (last_folder_aa_path[0] == 0) 647 return; 648 649 FOREACH_ALBUMART(i) 650 { 651 if (aa_handles[i] == last_folder_aa_hid[i]) 652 aa_handles[i] = 0; 653 } 654} 655#endif //HAVE_ALBUMART 656 657/* Free the track buffer entry and possibly remove it from the list if it 658 was succesfully added at some point */ 659static void track_list_free_buf_info(struct track_buf_info *tbip) 660{ 661 int hid = tbip->info.self_hid; 662 int next_hid = tbip->link[1]; 663 664 if (next_hid != ERR_HANDLE_NOT_FOUND) 665 { 666 int prev_hid = tbip->link[0]; 667 struct track_buf_info *prev_tbip = NULL; 668 struct track_buf_info *next_tbip = NULL; 669 670 if ((prev_hid > 0 && !(prev_tbip = track_buf_info_get(prev_hid))) || 671 (next_hid > 0 && !(next_tbip = track_buf_info_get(next_hid)))) 672 { 673 return; 674 } 675 676 /* If this one is the current track; new current track is next one, 677 if any, else, the previous */ 678 if (hid == track_list.current_hid) 679 track_list.current_hid = next_hid > 0 ? next_hid : prev_hid; 680 681 /* Fixup list links */ 682 if (prev_tbip) 683 prev_tbip->link[1] = next_hid; 684 else 685 track_list.first_hid = next_hid; 686 687 if (next_tbip) 688 next_tbip->link[0] = prev_hid; 689 else 690 track_list.last_hid = prev_hid; 691 692 track_list.count--; 693 } 694 695 /* No movement allowed during bufclose calls */ 696 buf_pin_handle(hid, true); 697 698#ifdef HAVE_ALBUMART 699 clear_cached_aa_handles(tbip->info.aa_hid); 700#endif 701 FOR_EACH_TRACK_INFO_HANDLE(i) 702 bufclose(tbip->info.handle[i]); 703 704 /* Finally, the handle itself */ 705 bufclose(hid); 706} 707 708/* Return current track plus an offset */ 709static bool track_list_current(int offset, struct track_info *infop) 710{ 711 return !!track_list_get_info_from(track_list.current_hid, offset, infop); 712} 713 714/* Return current based upon what's intended that the user sees - not 715 necessarily where decoding is taking place */ 716static bool track_list_user_current(int offset, struct track_info *infop) 717{ 718 if (skip_pending == TRACK_SKIP_AUTO || 719 skip_pending == TRACK_SKIP_AUTO_NEW_PLAYLIST) 720 { 721 offset--; 722 } 723 724 return !!track_list_get_info_from(track_list.current_hid, offset, infop); 725} 726 727/* Advance current track by an offset, return false if result is out of 728 bounds */ 729static bool track_list_advance_current(int offset, struct track_info *infop) 730{ 731 struct track_buf_info *new_bufinfop = 732 track_list_get_info_from(track_list.current_hid, offset, infop); 733 734 if (!new_bufinfop) 735 return false; 736 737 track_list.current_hid = new_bufinfop->info.self_hid; 738 return true; 739} 740 741/* Return the info of the last allocation plus an offset, NULL if result is 742 out of bounds */ 743static bool track_list_last(int offset, struct track_info *infop) 744{ 745 return !!track_list_get_info_from(track_list.last_hid, offset, infop); 746} 747 748/* Allocate a new struct track_info on the buffer; does not add to list */ 749static bool track_list_alloc_info(struct track_info *infop) 750{ 751 int hid = bufalloc(NULL, sizeof (struct track_buf_info), TYPE_RAW_ATOMIC); 752 753 track_info_wipe(infop); 754 755 struct track_buf_info *tbip = track_buf_info_get(hid); 756 if (!tbip) 757 { 758 infop->self_hid = ERR_HANDLE_NOT_FOUND; 759 bufclose(hid); 760 return false; 761 } 762 763 infop->self_hid = hid; 764 765 tbip->link[0] = 0; 766 tbip->link[1] = ERR_HANDLE_NOT_FOUND; /* "Not in list" */ 767 tbip->info.self_hid = hid; 768 track_info_wipe(&tbip->info); 769 770 return true; 771} 772 773/* Actually commit the track info to the track list */ 774static bool track_list_commit_info(const struct track_info *infop) 775{ 776 struct track_buf_info *tbip = track_buf_info_get(infop->self_hid); 777 if (!tbip) 778 return false; 779 780 return track_list_commit_buf_info(tbip, infop); 781} 782 783/* Free the track entry and possibly remove it from the list if it was 784 succesfully added at some point */ 785static void track_list_free_info(struct track_info *infop) 786{ 787 struct track_buf_info *tbip = track_buf_info_get(infop->self_hid); 788 if (!tbip) 789 return; 790 791 track_list_free_buf_info(tbip); 792} 793 794/* Close all open handles in the range except the for the current track 795 if preserving that */ 796static void track_list_clear(unsigned int action) 797{ 798 logf("%s:action=%u", __func__, action); 799 800 /* Don't care now since rebuffering is imminent */ 801 buf_set_watermark(0); 802 803 if (action != TRACK_LIST_CLEAR_ALL) 804 { 805 struct track_info info; 806 if (!track_list_current(0, &info) || info.id3_hid < 0) 807 action = TRACK_LIST_CLEAR_ALL; /* Nothing worthwhile keeping */ 808 } 809 810 int hid = track_list.first_hid; 811 int current_hid = track_list.current_hid; 812 int last_hid = action == TRACK_LIST_KEEP_NEW ? current_hid : 0; 813 814 while (hid != last_hid) 815 { 816 struct track_buf_info *tbip = track_buf_info_get(hid); 817 if (!tbip) 818 break; 819 820 int next_hid = tbip->link[1]; 821 822 if (action != TRACK_LIST_KEEP_CURRENT || hid != current_hid) 823 { 824 /* If this is the in-progress load, abort it */ 825 if (hid == track_list.in_progress_hid) 826 track_list.in_progress_hid = 0; 827 828 track_list_free_buf_info(tbip); 829 } 830 831 hid = next_hid; 832 } 833} 834 835 836/** --- Audio buffer -- **/ 837 838/* What size is needed for the scratch buffer? */ 839static size_t scratch_mem_size(void) 840{ 841 size_t size = sizeof (struct audio_scratch_memory); 842 843 if (global_settings.cuesheet) 844 size += sizeof (struct cuesheet); 845 846 return size; 847} 848 849/* Initialize the memory area where data is stored that is only used when 850 playing audio and anything depending upon it */ 851static void scratch_mem_init(void *mem) 852{ 853 audio_scratch_memory = (struct audio_scratch_memory *)mem; 854 id3_write_locked(UNBUFFERED_ID3, NULL); 855 id3_write(CODEC_ID3, NULL); 856 ci.id3 = id3_get(CODEC_ID3); 857 audio_scratch_memory->curr_cue = NULL; 858 859 if (global_settings.cuesheet) 860 { 861 audio_scratch_memory->curr_cue = 862 SKIPBYTES((struct cuesheet *)audio_scratch_memory, 863 sizeof (struct audio_scratch_memory)); 864 } 865} 866 867static int audiobuf_handle; 868#define AUDIO_BUFFER_RESERVE (256*1024) 869static size_t filebuflen; 870 871 872size_t audio_buffer_size(void) 873{ 874 if (audiobuf_handle > 0) 875 return filebuflen - AUDIO_BUFFER_RESERVE; 876 return 0; 877} 878 879size_t audio_buffer_available(void) 880{ 881 size_t size = 0; 882 size_t core_size = core_available(); 883 if (audiobuf_handle > 0) /* if allocated return what we can give */ 884 size = filebuflen - AUDIO_BUFFER_RESERVE - 128; 885 return MAX(core_size, size); 886} 887 888#ifdef HAVE_ALBUMART 889static void clear_last_folder_album_art(void) 890{ 891 if(last_folder_aa_path[0] == 0) 892 return; 893 894 last_folder_aa_path[0] = 0; 895 FOREACH_ALBUMART(i) 896 { 897 bufclose(last_folder_aa_hid[i]); 898 last_folder_aa_hid[i] = 0; 899 } 900} 901#endif 902 903/* Set up the audio buffer for playback 904 * filebuflen must be pre-initialized with the maximum size */ 905static void audio_reset_buffer_noalloc( 906 void *filebuf) 907{ 908 /* 909 * Layout audio buffer as follows: 910 * [|SCRATCH|BUFFERING|PCM] 911 */ 912 logf("%s()", __func__); 913 914 /* If the setup of anything allocated before the file buffer is 915 changed, do check the adjustments after the buffer_alloc call 916 as it will likely be affected and need sliding over */ 917 size_t allocsize; 918 /* Subtract whatever the pcm buffer says it used plus the guard 919 buffer */ 920 allocsize = pcmbuf_init(filebuf + filebuflen); 921 922 /* Make sure filebuflen is a pointer sized multiple after 923 adjustment */ 924 allocsize = ALIGN_UP(allocsize, sizeof (intptr_t)); 925 if (allocsize > filebuflen) 926 goto bufpanic; 927 928 filebuflen -= allocsize; 929 930 /* Scratch memory */ 931 allocsize = scratch_mem_size(); 932 if (allocsize > filebuflen) 933 goto bufpanic; 934 935 scratch_mem_init(filebuf); 936 filebuf += allocsize; 937 filebuflen -= allocsize; 938 939#ifdef HAVE_ALBUMART 940 clear_last_folder_album_art(); 941#endif 942 943 buffering_reset(filebuf, filebuflen); 944 945 buffer_state = AUDIOBUF_STATE_INITIALIZED; 946 947#if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE) 948 /* Make sure everything adds up - yes, some info is a bit redundant but 949 aids viewing and the summation of certain variables should add up to 950 the location of others. */ 951 { 952 logf("fbuf: %08X", (unsigned)filebuf); 953 logf("fbufe: %08X", (unsigned)(filebuf + filebuflen)); 954 logf("sbuf: %08X", (unsigned)audio_scratch_memory); 955 logf("sbufe: %08X", (unsigned)(audio_scratch_memory + allocsize)); 956 } 957#endif 958 959 return; 960 961bufpanic: 962 panicf("%s(): EOM (%zu > %zu)", __func__, allocsize, filebuflen); 963} 964 965/* Buffer must not move. */ 966static int shrink_callback(int handle, unsigned hints, void* start, size_t old_size) 967{ 968 struct queue_event ev; 969 static const long filter_list[][2] = 970 { 971 /* codec messages */ 972 { Q_AUDIO_PLAY, Q_AUDIO_PLAY }, 973 }; 974 975 static struct audio_resume_info resume; 976 977 bool give_up = false; 978 979 /* filebuflen is, at this point, the buffering.c buffer size, 980 * i.e. the audiobuf except voice, scratch mem, pcm, ... */ 981 ssize_t extradata_size = old_size - filebuflen; 982 /* check what buflib requests */ 983 size_t wanted_size = (hints & BUFLIB_SHRINK_SIZE_MASK); 984 ssize_t size = (ssize_t)old_size - wanted_size; 985 986 if ((size - extradata_size) < AUDIO_BUFFER_RESERVE) 987 { 988 /* check if buflib needs the memory really hard. if yes we give 989 * up playback for now, otherwise refuse to shrink to keep at least 990 * 256K for the buffering */ 991 if ((hints & BUFLIB_SHRINK_POS_MASK) == BUFLIB_SHRINK_POS_MASK) 992 give_up = true; 993 else 994 return BUFLIB_CB_CANNOT_SHRINK; 995 } 996 997 998 /* TODO: Do it without stopping playback, if possible */ 999 struct mp3entry *id3 = audio_current_track(); 1000 unsigned long elapsed = id3->elapsed; 1001 unsigned long offset = id3->offset; 1002 /* resume if playing */ 1003 bool playing = (audio_status() == AUDIO_STATUS_PLAY); 1004 /* There's one problem with stoping and resuming: If it happens in a too 1005 * frequent fashion, the codecs lose the resume postion and playback 1006 * begins from the beginning. 1007 * To work around use queue_post() to effectively delay the resume in case 1008 * we're called another time. However this has another problem: id3->offset 1009 * gets zero since playback is stopped. Therefore, try to peek at the 1010 * queue_post from the last call to get the correct offset. This also 1011 * lets us conviniently remove the queue event so Q_AUDIO_PLAY is only 1012 * processed once. */ 1013 bool play_queued = queue_peek_ex(&audio_queue, &ev, QPEEK_REMOVE_EVENTS, 1014 filter_list); 1015 1016 if (playing && (elapsed > 0 || offset > 0)) 1017 { 1018 if (play_queued) 1019 resume = *(struct audio_resume_info *)ev.data; 1020 1021 /* current id3->elapsed/offset are king */ 1022 if (elapsed > 0) 1023 resume.elapsed = elapsed; 1024 1025 if (offset > 0) 1026 resume.offset = offset; 1027 } 1028 1029 /* don't call audio_hard_stop() as it frees this handle */ 1030 if (thread_self() == audio_thread_id) 1031 { /* inline case Q_AUDIO_STOP (audio_hard_stop() response 1032 * if we're in the audio thread */ 1033 audio_stop_playback(); 1034 queue_clear(&audio_queue); 1035 } 1036 else 1037 audio_queue_send(Q_AUDIO_STOP, 1); 1038#ifdef PLAYBACK_VOICE 1039 voice_stop(); 1040#endif 1041 1042 /* we should be free to change the buffer now */ 1043 if (give_up) 1044 { 1045 buffer_state = AUDIOBUF_STATE_TRASHED; 1046 audiobuf_handle = core_free(audiobuf_handle); 1047 return BUFLIB_CB_OK; 1048 } 1049 /* set final buffer size before calling audio_reset_buffer_noalloc() 1050 * (now it's the total size, the call will subtract voice etc) */ 1051 filebuflen = size; 1052 switch (hints & BUFLIB_SHRINK_POS_MASK) 1053 { 1054 case BUFLIB_SHRINK_POS_BACK: 1055 core_shrink(handle, start, size); 1056 audio_reset_buffer_noalloc(start); 1057 break; 1058 case BUFLIB_SHRINK_POS_FRONT: 1059 core_shrink(handle, start + wanted_size, size); 1060 audio_reset_buffer_noalloc(start + wanted_size); 1061 break; 1062 } 1063 if (playing || play_queued) 1064 { 1065 /* post, to make subsequent calls not break the resume position */ 1066 audio_queue_post(Q_AUDIO_PLAY, (intptr_t)&resume); 1067 } 1068 1069 return BUFLIB_CB_OK; 1070} 1071 1072static struct buflib_callbacks ops = { 1073 .move_callback = NULL, 1074 .shrink_callback = shrink_callback, 1075}; 1076 1077static void audio_reset_buffer(void) 1078{ 1079 if (audiobuf_handle > 0) 1080 { 1081 core_free(audiobuf_handle); 1082 audiobuf_handle = 0; 1083 } 1084 if (core_allocatable() < pcmbuf_size_reqd()) 1085 talk_buffer_set_policy(TALK_BUFFER_LOOSE); /* back off voice buffer */ 1086 audiobuf_handle = core_alloc_maximum(&filebuflen, &ops); 1087 1088 if (audiobuf_handle > 0) 1089 audio_reset_buffer_noalloc(core_get_data(audiobuf_handle)); 1090 else 1091 /* someone is abusing core_alloc_maximum(). Fix this evil guy instead of 1092 * trying to handle OOM without hope */ 1093 panicf("%s(): OOM!\n", __func__); 1094} 1095 1096/* Set the buffer margin to begin rebuffering when 'seconds' from empty */ 1097static void audio_update_filebuf_watermark(int seconds) 1098{ 1099 size_t bytes = 0; 1100 1101#ifdef HAVE_DISK_STORAGE 1102 int spinup = storage_spinup_time(); 1103 1104 if (seconds == 0) 1105 { 1106 /* By current setting */ 1107 seconds = buffer_margin; 1108 } 1109 else 1110 { 1111 /* New setting */ 1112 buffer_margin = seconds; 1113 1114 if (buf_get_watermark() == 0) 1115 { 1116 /* Write a watermark only if the audio thread already did so for 1117 itself or it will fail to set the event and the watermark - if 1118 it hasn't yet, it will use the new setting when it does */ 1119 return; 1120 } 1121 } 1122 1123 if (spinup) 1124 seconds += (spinup / HZ) + 1; 1125 else 1126 seconds += 5; 1127 1128 seconds += buffer_margin; 1129#else 1130 /* flash storage */ 1131 seconds = 1; 1132#endif 1133 1134 /* Watermark is a function of the bitrate of the last track in the buffer */ 1135 struct track_info info; 1136 struct mp3entry *id3 = NULL; 1137 1138 if (track_list_last(0, &info)) 1139 id3 = valid_mp3entry(bufgetid3(info.id3_hid)); 1140 1141 if (id3) 1142 { 1143 if (!rbcodec_format_is_atomic(id3->codectype)) 1144 { 1145 bytes = id3->bitrate * (1000/8) * seconds; 1146 } 1147 else 1148 { 1149 /* Bitrate has no meaning to buffering margin for atomic audio - 1150 rebuffer when it's the only track left unless it's the only 1151 track that fits, in which case we should avoid constant buffer 1152 low events */ 1153 if (track_list_count() > 1) 1154 bytes = buf_filesize(info.audio_hid) + 1; 1155 } 1156 } 1157 else 1158 { 1159 /* Then set the minimum - this should not occur anyway */ 1160 logf("fwmark: No id3 for last track (f=%d:c=%d:l=%d)", 1161 track_list.first_hid, track_list.current_hid, track_list.last_hid); 1162 } 1163 1164 /* Actually setting zero disables the notification and we use that 1165 to detect that it has been reset */ 1166 buf_set_watermark(MAX(bytes, 1)); 1167 logf("fwmark: %zu", bytes); 1168} 1169 1170 1171/** -- Track change notification -- **/ 1172 1173/* Check the pcmbuf track changes and return write the message into the event 1174 if there are any */ 1175static inline bool audio_pcmbuf_track_change_scan(void) 1176{ 1177 if (track_change.out != track_change.in) 1178 { 1179 track_change.out++; 1180 return true; 1181 } 1182 1183 return false; 1184} 1185 1186/* Clear outstanding track change posts */ 1187static inline void audio_pcmbuf_track_change_clear(void) 1188{ 1189 track_change.out = track_change.in; 1190} 1191 1192/* Post a track change notification - called by audio ISR */ 1193static inline void audio_pcmbuf_track_change_post(void) 1194{ 1195 track_change.in++; 1196} 1197 1198 1199/** --- Helper functions --- **/ 1200 1201/* Removes messages that might end up in the queue before or while processing 1202 a manual track change. Responding to them would be harmful since they 1203 belong to a previous track's playback period. Anything that would generate 1204 the stale messages must first be put into a state where it will not do so. 1205 */ 1206static void audio_clear_track_notifications(void) 1207{ 1208 static const long filter_list[][2] = 1209 { 1210 /* codec messages */ 1211 { Q_AUDIO_CODEC_SEEK_COMPLETE, Q_AUDIO_CODEC_COMPLETE }, 1212 /* track change messages */ 1213 { Q_AUDIO_TRACK_CHANGED, Q_AUDIO_TRACK_CHANGED }, 1214 }; 1215 1216 const int filter_count = ARRAYLEN(filter_list) - 1; 1217 1218 /* Remove any pcmbuf notifications */ 1219 pcmbuf_monitor_track_change(false); 1220 audio_pcmbuf_track_change_clear(); 1221 1222 /* Scrub the audio queue of the old mold */ 1223 while (queue_peek_ex(&audio_queue, NULL, 1224 filter_count | QPEEK_REMOVE_EVENTS, 1225 filter_list)) 1226 { 1227 yield(); /* Not strictly needed, per se, ad infinitum, ra, ra */ 1228 } 1229} 1230 1231/* Takes actions based upon track load status codes */ 1232static void audio_handle_track_load_status(int trackstat) 1233{ 1234 switch (trackstat) 1235 { 1236 case LOAD_TRACK_ERR_NO_MORE: 1237 if (track_list_count() > 0) 1238 break; 1239 1240 case LOAD_TRACK_ERR_START_CODEC: 1241 audio_queue_post(Q_AUDIO_CODEC_COMPLETE, CODEC_ERROR); 1242 break; 1243 1244 default: 1245 break; 1246 } 1247} 1248 1249void allocate_playback_log(void) INIT_ATTR; 1250void allocate_playback_log(void) 1251{ 1252 int fd; 1253 char filename[MAX_PATH]; 1254 1255 if (!global_settings.playback_log) 1256 return; 1257 1258#if (CONFIG_STORAGE & STORAGE_ATA) 1259 if (playback_log_handle == 0) 1260 { 1261 playback_log_handle = core_alloc(PLAYBACK_LOG_BUFSZ); 1262 if (playback_log_handle > 0) 1263 { 1264 DEBUGF("%s Allocated %d bytes\n", __func__, PLAYBACK_LOG_BUFSZ); 1265 char *buf = core_get_data(playback_log_handle); 1266 buf[0] = '\0'; 1267 } 1268 } 1269#endif 1270 1271 while (1) 1272 { 1273 DEBUGF("Opening %s \n", PLAYBACK_LOG_PATH); 1274 fd = open(PLAYBACK_LOG_PATH, O_WRONLY|O_CREAT|O_APPEND, 0666); 1275 if (fd >= 0) 1276 { 1277 /* check if the playback log is excessive */ 1278 if (lseek(fd, 0, SEEK_END) > PLAYBACK_LOG_MAX_FILESZ_BYTES) 1279 { 1280 close(fd); 1281 create_numbered_filename(filename, ROCKBOX_DIR, "playback_", 1282 ".log", 4 IF_CNFN_NUM_(, NULL)); 1283 DEBUGF("Renaming %s => %s\n", PLAYBACK_LOG_PATH, filename); 1284 if (rename(PLAYBACK_LOG_PATH, filename) < 0) 1285 break; /*failure*/ 1286 continue; 1287 } 1288 else 1289 { 1290#if CONFIG_RTC 1291 create_datetime_filename(filename, "", " Time ", "", false); 1292 fdprintf(fd, "# Started Ver. %s %s\n", rbversion, filename); 1293#else 1294 fdprintf(fd, "# Started Ver. %s\n", rbversion); 1295#endif 1296 } 1297 close(fd); 1298 } 1299 break; 1300 } 1301} 1302 1303void add_playbacklog(struct mp3entry *id3) 1304{ 1305 if (!global_settings.playback_log) 1306 return; 1307 unsigned long timestamp = 0; 1308 ssize_t used = 0; 1309#if (CONFIG_STORAGE & STORAGE_ATA) 1310 ssize_t bufsz = 0; 1311 char *buf = NULL; 1312 /* if the user just enabled playback logging rather than stopping playback 1313 * to allocate a buffer or if buffer too large just flush direct to disk 1314 * buffer will attempt to be allocated next start-up */ 1315 if (playback_log_handle > 0) 1316 { 1317 buf = core_get_data(playback_log_handle); 1318 used = strlen(buf); 1319 if (used < PLAYBACK_LOG_BUFSZ) 1320 { 1321 bufsz = PLAYBACK_LOG_BUFSZ - used; 1322 buf += used; 1323 } 1324 DEBUGF("%s Used %lu Remain: %lu\n", __func__, used, bufsz); 1325 } 1326#endif 1327 if (id3 && id3->elapsed > PLAYBACK_LOG_MIN_ELAPSED_MS) 1328 { 1329#if CONFIG_RTC 1330 timestamp = mktime(get_time()); 1331#else 1332 timestamp = current_tick * (1000 / HZ); /* milliseconds */ 1333#endif 1334#if (CONFIG_STORAGE & STORAGE_ATA) 1335 if (buf) /* we have a buffer allocd from core */ 1336 { 1337 /*10:10:10:MAX_PATH\n*/ 1338 ssize_t entrylen = snprintf(buf, bufsz,"%lu:%ld:%ld:%s\n", 1339 timestamp, (long)id3->elapsed, (long)id3->length, id3->path); 1340 1341 if (entrylen < bufsz) 1342 { 1343 DEBUGF("BUFFERED: time: %lu elapsed %ld/%ld saving file: %s\n", 1344 timestamp, (long)id3->elapsed, (long)id3->length, id3->path); 1345 return; /* succeed or snprintf fail return */ 1346 } 1347 buf[0] = '\0'; 1348 } 1349 /* that didn't fit, flush buffer & write this entry to disk */ 1350#endif 1351 } 1352 else 1353 id3 = NULL; 1354 1355 if (id3 || used > 0) /* flush */ 1356 { 1357 DEBUGF("Opening %s \n", PLAYBACK_LOG_PATH); 1358 int fd = open(PLAYBACK_LOG_PATH, O_WRONLY|O_CREAT|O_APPEND, 0666); 1359 if (fd < 0) 1360 { 1361 return; /* failure */ 1362 } 1363#if (CONFIG_STORAGE & STORAGE_ATA) 1364 if (buf) /* we have a buffer allocd from core */ 1365 { 1366 buf = core_get_data_pinned(playback_log_handle); /* we might yield - pin it*/ 1367 write(fd, buf, used); 1368 DEBUGF("%s Writing %lu bytes of buf:\n%s\n", __func__, used, buf); 1369 buf[0] = '\0'; 1370 core_put_data_pinned(buf); 1371 } 1372#endif 1373 if (id3) 1374 { 1375 /* we have the timestamp from when we tried to add to buffer */ 1376 DEBUGF("LOGGED: time: %lu elapsed %ld/%ld saving file: %s\n", 1377 timestamp, (long)id3->elapsed, (long)id3->length, id3->path); 1378 fdprintf(fd, "%lu:%ld:%ld:%s\n", 1379 timestamp, (long)id3->elapsed, (long)id3->length, id3->path); 1380 } 1381 1382 close(fd); 1383 return; 1384 } 1385} 1386 1387/* Send track events that use a struct track_event for data */ 1388static void send_track_event(unsigned int id, unsigned int flags, 1389 struct mp3entry *id3) 1390{ 1391 if (id3 == id3_get(PLAYING_ID3)) 1392 flags |= TEF_CURRENT; 1393 1394 send_event(id, &(struct track_event){ .flags = flags, .id3 = id3 }); 1395} 1396 1397/* Announce the end of playing the current track */ 1398static void audio_playlist_track_finish(void) 1399{ 1400 struct mp3entry *ply_id3 = id3_get(PLAYING_ID3); 1401 struct mp3entry *id3 = valid_mp3entry(ply_id3); 1402 1403 playlist_update_resume_info(filling == STATE_ENDED ? NULL : id3); 1404 if (id3) 1405 { 1406 add_playbacklog(id3); 1407 send_track_event(PLAYBACK_EVENT_TRACK_FINISH, 1408 track_event_flags, id3); 1409 } 1410} 1411 1412/* Announce the beginning of the new track */ 1413static void audio_playlist_track_change(void) 1414{ 1415 struct mp3entry *id3 = valid_mp3entry(id3_get(PLAYING_ID3)); 1416 1417 if (id3) 1418 { 1419 send_track_event(PLAYBACK_EVENT_TRACK_CHANGE, 1420 track_event_flags, id3); 1421 } 1422 1423 position_key = pcmbuf_get_position_key(); 1424 1425 playlist_update_resume_info(id3); 1426} 1427 1428/* Change the data for the next track and send the event */ 1429static void audio_update_and_announce_next_track(const struct mp3entry *id3_next) 1430{ 1431 id3_write_locked(NEXTTRACK_ID3, id3_next); 1432 send_track_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, 1433 0, id3_get(NEXTTRACK_ID3)); 1434} 1435 1436/* Bring the user current mp3entry up to date and set a new offset for the 1437 buffered metadata */ 1438static void playing_id3_sync(struct track_info *user_infop, struct audio_resume_info *resume_info, bool skip_resume_adjustments) 1439{ 1440 id3_mutex_lock(); 1441 1442 struct mp3entry *id3 = bufgetid3(user_infop->id3_hid); 1443 1444 pcm_play_lock(); 1445 1446 if (id3) 1447 { 1448 if (resume_info) 1449 { 1450 id3->elapsed = resume_info->elapsed; 1451 id3->offset = resume_info->offset; 1452 } 1453 id3->skip_resume_adjustments = skip_resume_adjustments; 1454 } 1455 1456 id3_write(PLAYING_ID3, id3); 1457 1458 if (!resume_info && id3) 1459 { 1460 id3->offset = 0; 1461 id3->elapsed = 0; 1462 id3->skip_resume_adjustments = false; 1463 } 1464 1465 pcm_play_unlock(); 1466 1467 id3_mutex_unlock(); 1468} 1469 1470/* Wipe-out track metadata - current is optional */ 1471static void wipe_track_metadata(bool current) 1472{ 1473 id3_mutex_lock(); 1474 1475 if (current) 1476 id3_write(PLAYING_ID3, NULL); 1477 1478 id3_write(NEXTTRACK_ID3, NULL); 1479 id3_write(UNBUFFERED_ID3, NULL); 1480 1481 id3_mutex_unlock(); 1482} 1483 1484/* Called when buffering is completed on the last track handle */ 1485static void filling_is_finished(void) 1486{ 1487 logf("last track finished buffering"); 1488 1489 /* There's no more to load or watch for */ 1490 buf_set_watermark(0); 1491 filling = STATE_FINISHED; 1492} 1493 1494/* Stop the codec decoding or waiting for its data to be ready - returns 1495 'false' if the codec ended up stopped */ 1496static bool halt_decoding_track(bool stop) 1497{ 1498 /* If it was waiting for us to clear the buffer to make a rebuffer 1499 happen, it should cease otherwise codec_stop could deadlock waiting 1500 for the codec to go to its main loop - codec's request will now 1501 force-fail */ 1502 bool retval = false; 1503 1504 buf_signal_handle(ci.audio_hid, true); 1505 1506 if (stop) 1507 codec_stop(); 1508 else 1509 retval = codec_pause(); 1510 1511 audio_clear_track_notifications(); 1512 1513 /* We now know it's idle and not waiting for buffered data */ 1514 buf_signal_handle(ci.audio_hid, false); 1515 1516 codec_skip_pending = false; 1517 codec_seeking = false; 1518 1519 return retval; 1520} 1521 1522/* Wait for any in-progress fade to complete */ 1523static void audio_wait_fade_complete(void) 1524{ 1525 /* Just loop until it's done */ 1526 while (pcmbuf_fading()) 1527 sleep(0); 1528} 1529 1530/* End the ff/rw mode */ 1531static void audio_ff_rewind_end(void) 1532{ 1533 /* A seamless seek (not calling audio_pre_ff_rewind) skips this 1534 section */ 1535 if (ff_rw_mode) 1536 { 1537 ff_rw_mode = false; 1538 1539 if (codec_seeking) 1540 { 1541 /* Clear the buffer */ 1542 pcmbuf_play_stop(); 1543 audio_pcmbuf_sync_position(); 1544 } 1545 1546 if (play_status != PLAY_PAUSED) 1547 { 1548 /* Seeking-while-playing, resume PCM playback */ 1549 pcmbuf_pause(false); 1550 } 1551 } 1552} 1553 1554/* Complete the codec seek */ 1555static void audio_complete_codec_seek(void) 1556{ 1557 /* If a seek completed while paused, 'paused' is true. 1558 * If seeking from seek mode, 'ff_rw_mode' is true. */ 1559 if (codec_seeking) 1560 { 1561 audio_ff_rewind_end(); 1562 codec_seeking = false; /* set _after_ the call! */ 1563 } 1564 /* else it's waiting and we must repond */ 1565} 1566 1567/* Get the current cuesheet pointer */ 1568static inline struct cuesheet * get_current_cuesheet(void) 1569{ 1570 return audio_scratch_memory->curr_cue; 1571} 1572 1573/* Read the cuesheet from the buffer */ 1574static void buf_read_cuesheet(int handle_id) 1575{ 1576 struct cuesheet *cue = get_current_cuesheet(); 1577 1578 if (!cue || handle_id < 0) 1579 return; 1580 1581 bufread(handle_id, sizeof (struct cuesheet), cue); 1582} 1583 1584/* Backend to peek/current/next track metadata interface functions - 1585 fill in the mp3entry with as much information as we may obtain about 1586 the track at the specified offset from the user current track - 1587 returns false if no information exists with us */ 1588static bool audio_get_track_metadata(int offset, struct mp3entry *id3) 1589{ 1590 if (play_status == PLAY_STOPPED) 1591 return false; 1592 1593 if (id3->path[0] != '\0') 1594 return true; /* Already filled */ 1595 1596 struct track_info info; 1597 1598 if (!track_list_user_current(offset, &info)) 1599 { 1600 struct mp3entry *ub_id3 = id3_get(UNBUFFERED_ID3); 1601 1602 if (offset > 0 && track_list_user_current(offset - 1, NULL)) 1603 { 1604 /* Try the unbuffered id3 since we're moving forward */ 1605 if (ub_id3->path[0] != '\0') 1606 { 1607 copy_mp3entry(id3, ub_id3); 1608 return true; 1609 } 1610 } 1611 } 1612 else if (bufreadid3(info.id3_hid, id3)) 1613 { 1614 id3->cuesheet = NULL; 1615 return true; 1616 } 1617 1618 /* We didn't find the ID3 metadata, so we fill it with the little info we 1619 have and return that */ 1620 1621 char path[MAX_PATH+1]; 1622 if (playlist_peek(offset, path, sizeof (path))) 1623 { 1624#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE) 1625 /* Try to get it from the database */ 1626 if (!tagcache_fill_tags(id3, path)) 1627#endif 1628 { 1629 /* By now, filename is the only source of info */ 1630 fill_metadata_from_path(id3, path); 1631 } 1632 1633 return true; 1634 } 1635 1636 wipe_mp3entry(id3); 1637 1638 return false; 1639} 1640 1641/* Get resume rewind adjusted progress from the ID3 */ 1642static void resume_rewind_adjust_progress(const struct mp3entry *id3, 1643 unsigned long *elapsed, 1644 unsigned long *offset) 1645{ 1646 unsigned int rewind = MAX(global_settings.resume_rewind, 0); 1647 unsigned long d_e = rewind*1000; 1648 *elapsed = id3->elapsed - MIN(id3->elapsed, d_e); 1649 unsigned long d_o = rewind * id3->bitrate * (1000/8); 1650 *offset = id3->offset - MIN(id3->offset, d_o); 1651} 1652 1653/* Get the codec into ram and initialize it - keep it if it's ready */ 1654static bool audio_init_codec(struct track_info *track_infop, 1655 struct mp3entry *track_id3) 1656{ 1657 int codt_loaded = get_audio_base_codec_type(codec_loaded()); 1658 int hid = ERR_HANDLE_NOT_FOUND; 1659 1660 if (codt_loaded != AFMT_UNKNOWN) 1661 { 1662 int codt = get_audio_base_codec_type(track_id3->codectype); 1663 1664 if (codt == codt_loaded) 1665 { 1666 /* Codec is the same base type */ 1667 logf("Reusing prev. codec: %d", track_id3->codectype); 1668#ifdef HAVE_CODEC_BUFFERING 1669 /* Close any buffered codec (we could have skipped directly to a 1670 format transistion that is the same format as the current track 1671 and the buffered one is no longer needed) */ 1672 track_info_close_handle(&track_infop->codec_hid); 1673 track_info_sync(track_infop); 1674#endif /* HAVE_CODEC_BUFFERING */ 1675 return true; 1676 } 1677 else 1678 { 1679 /* New codec - first make sure the old one's gone */ 1680 logf("Removing prev. codec: %d", codt_loaded); 1681 codec_unload(); 1682 } 1683 } 1684 1685 logf("New codec: %d/%d", track_id3->codectype, codec_loaded()); 1686 1687#ifdef HAVE_CODEC_BUFFERING 1688 /* Codec thread will close the handle even if it fails and will load from 1689 storage if hid is not valid or the buffer load fails */ 1690 hid = track_infop->codec_hid; 1691 track_infop->codec_hid = ERR_HANDLE_NOT_FOUND; 1692 track_info_sync(track_infop); 1693#endif 1694 1695 return codec_load(hid, track_id3->codectype); 1696 (void)track_infop; /* When codec buffering isn't supported */ 1697} 1698 1699#ifdef HAVE_TAGCACHE 1700/* Check settings for whether the file should be autoresumed */ 1701enum { AUTORESUMABLE_UNKNOWN = 0, AUTORESUMABLE_TRUE, AUTORESUMABLE_FALSE }; 1702static bool autoresumable(struct mp3entry *id3) 1703{ 1704 char *path; 1705 size_t len; 1706 bool is_resumable; 1707 1708 if (id3->autoresumable) /* result cached? */ 1709 return id3->autoresumable == AUTORESUMABLE_TRUE; 1710 1711 is_resumable = false; 1712 1713 if (*id3->path) 1714 { 1715 for (path = global_settings.autoresume_paths; 1716 *path; /* search terms left? */ 1717 path++) 1718 { 1719 if (*path == ':') /* Skip empty search patterns */ 1720 continue; 1721 1722 len = strcspn(path, ":"); 1723 1724 /* Note: At this point, len is always > 0 */ 1725 1726 if (strncasecmp(id3->path, path, len) == 0) 1727 { 1728 /* Full directory-name matches only. Trailing '/' in 1729 search path OK. */ 1730 if (id3->path[len] == '/' || id3->path[len - 1] == '/') 1731 { 1732 is_resumable = true; 1733 break; 1734 } 1735 } 1736 path += len - 1; 1737 } 1738 } 1739 1740 /* cache result */ 1741 id3->autoresumable = 1742 is_resumable ? AUTORESUMABLE_TRUE : AUTORESUMABLE_FALSE; 1743 1744 logf("autoresumable: %s is%s resumable", 1745 id3->path, is_resumable ? "" : " not"); 1746 1747 return is_resumable; 1748} 1749#endif /* HAVE_TAGCACHE */ 1750 1751/* Start the codec for the current track scheduled to be decoded */ 1752static bool audio_start_codec(bool auto_skip) 1753{ 1754 struct track_info info; 1755 track_list_current(0, &info); 1756 1757 struct mp3entry *cur_id3 = valid_mp3entry(bufgetid3(info.id3_hid)); 1758 1759 if (!cur_id3) 1760 return false; 1761 1762 buf_pin_handle(info.id3_hid, true); 1763 1764 if (!audio_init_codec(&info, cur_id3)) 1765 { 1766 buf_pin_handle(info.id3_hid, false); 1767 return false; 1768 } 1769 1770 #ifdef HAVE_TAGCACHE 1771 bool autoresume_enable = !cur_id3->skip_resume_adjustments && global_settings.autoresume_enable; 1772 1773 if (autoresume_enable && !(cur_id3->elapsed || cur_id3->offset)) 1774 { 1775 /* Resume all manually selected tracks */ 1776 bool resume = !auto_skip; 1777 1778 /* Send the "buffer" event to obtain the resume position for the codec */ 1779 send_track_event(PLAYBACK_EVENT_TRACK_BUFFER, 0, cur_id3); 1780 1781 if (!resume) 1782 { 1783 /* Automatic skip - do further tests to see if we should just 1784 ignore any autoresume position */ 1785 int autoresume_automatic = global_settings.autoresume_automatic; 1786 1787 switch (autoresume_automatic) 1788 { 1789 case AUTORESUME_NEXTTRACK_ALWAYS: 1790 /* Just resume unconditionally */ 1791 resume = true; 1792 break; 1793 case AUTORESUME_NEXTTRACK_NEVER: 1794 /* Force-rewind it */ 1795 break; 1796 default: 1797 /* Not "never resume" - pass resume filter? */ 1798 resume = autoresumable(cur_id3); 1799 } 1800 } 1801 1802 if (!resume) 1803 { 1804 cur_id3->elapsed = 0; 1805 cur_id3->offset = 0; 1806 } 1807 1808 logf("%s: Set resume for %s to %lu %lX", __func__, 1809 cur_id3->title, cur_id3->elapsed, cur_id3->offset); 1810 } 1811#endif /* HAVE_TAGCACHE */ 1812 1813 /* Rewind the required amount - if an autoresume was done, this also rewinds 1814 that by the setting's amount 1815 1816 It would be best to have bookkeeping about whether or not the track 1817 sounded or not since skipping to it or else skipping to it while paused 1818 and back again will cause accumulation of silent rewinds - that's not 1819 our job to track directly nor could it be in any reasonable way 1820 */ 1821 if (!cur_id3->skip_resume_adjustments) 1822 { 1823 resume_rewind_adjust_progress(cur_id3, &cur_id3->elapsed, &cur_id3->offset); 1824 cur_id3->skip_resume_adjustments = true; 1825 } 1826 1827 /* Update the codec API with the metadata and track info */ 1828 id3_write(CODEC_ID3, cur_id3); 1829 1830 ci.audio_hid = info.audio_hid; 1831 ci.filesize = buf_filesize(info.audio_hid); 1832 buf_set_base_handle(info.audio_hid); 1833 1834 /* All required data is now available for the codec */ 1835 codec_go(); 1836 1837#ifdef HAVE_TAGCACHE 1838 if (!autoresume_enable || cur_id3->elapsed || cur_id3->offset) 1839#endif 1840 { 1841 /* Send the "buffer" event now */ 1842 send_track_event(PLAYBACK_EVENT_TRACK_BUFFER, 0, cur_id3); 1843 } 1844 1845 buf_pin_handle(info.id3_hid, false); 1846 return true; 1847 1848 (void)auto_skip; /* ifndef HAVE_TAGCACHE */ 1849} 1850 1851 1852/** --- Audio thread --- **/ 1853 1854/* Load and parse a cuesheet for the file - returns false if the buffer 1855 is full */ 1856static bool audio_load_cuesheet(struct track_info *infop, 1857 struct mp3entry *track_id3) 1858{ 1859 struct cuesheet *cue = get_current_cuesheet(); 1860 track_id3->cuesheet = NULL; 1861 1862 if (cue && infop->cuesheet_hid == ERR_HANDLE_NOT_FOUND) 1863 { 1864 /* If error other than a full buffer, then mark it "unsupported" to 1865 avoid reloading attempt */ 1866 int hid = ERR_UNSUPPORTED_TYPE; 1867 struct cuesheet_file cue_file; 1868 1869 if (look_for_cuesheet_file(track_id3, &cue_file)) 1870 { 1871 hid = bufalloc(NULL, sizeof (struct cuesheet), TYPE_CUESHEET); 1872 1873 if (hid >= 0) 1874 { 1875 void *cuesheet = NULL; 1876 bufgetdata(hid, sizeof (struct cuesheet), &cuesheet); 1877 1878 if (parse_cuesheet(&cue_file, (struct cuesheet *)cuesheet)) 1879 { 1880 /* Indicate cuesheet is present (while track remains 1881 buffered) */ 1882 track_id3->cuesheet = cue; 1883 } 1884 else 1885 { 1886 bufclose(hid); 1887 hid = ERR_UNSUPPORTED_TYPE; 1888 } 1889 } 1890 } 1891 1892 if (hid == ERR_BUFFER_FULL) 1893 { 1894 logf("buffer is full for now (%s)", __func__); 1895 return false; 1896 } 1897 else 1898 { 1899 if (hid < 0) 1900 logf("Cuesheet loading failed"); 1901 1902 infop->cuesheet_hid = hid; 1903 } 1904 } 1905 1906 return true; 1907} 1908 1909#ifdef HAVE_ALBUMART 1910 1911void set_albumart_mode(int setting) 1912{ 1913 if (albumart_mode != -1 && 1914 albumart_mode != setting) 1915 playback_update_aa_dims(); 1916 albumart_mode = setting; 1917} 1918 1919static int load_album_art_from_path(char *path, struct bufopen_bitmap_data *user_data, bool is_current_track, int i) 1920{ 1921 user_data->embedded_albumart = NULL; 1922 1923 bool same_path = strcmp(last_folder_aa_path, path) == 0; 1924 if (same_path && last_folder_aa_hid[i] != 0) 1925 return last_folder_aa_hid[i]; 1926 1927 // To simplify caching logic a bit we keep track only for first AA path 1928 // If other album arts use different path (like dimension specific arts) just skip caching for them 1929 bool is_cacheable = i == 0 && (is_current_track || last_folder_aa_path[0] == 0); 1930 if (!same_path && is_cacheable) 1931 { 1932 clear_last_folder_album_art(); 1933 strcpy(last_folder_aa_path, path); 1934 } 1935 int hid = bufopen(path, 0, TYPE_BITMAP, user_data); 1936 if (hid != ERR_BUFFER_FULL && (same_path || is_cacheable)) 1937 last_folder_aa_hid[i] = hid; 1938 return hid; 1939} 1940 1941/* Load any album art for the file - returns false if the buffer is full */ 1942static int audio_load_albumart(struct track_info *infop, 1943 struct mp3entry *track_id3, bool is_current_track) 1944{ 1945 FOREACH_ALBUMART(i) 1946 { 1947 struct bufopen_bitmap_data user_data; 1948 int *aa_hid = &infop->aa_hid[i]; 1949 int hid = ERR_UNSUPPORTED_TYPE; 1950 bool checked_image_file = false; 1951 1952 /* albumart_slots may change during a yield of bufopen, 1953 * but that's no problem */ 1954 if (*aa_hid >= 0 || *aa_hid == ERR_UNSUPPORTED_TYPE || 1955 !albumart_slots[i].used) 1956 continue; 1957 1958 memset(&user_data, 0, sizeof(user_data)); 1959 user_data.dim = &albumart_slots[i].dim; 1960 1961 char path[MAX_PATH]; 1962 if(global_settings.album_art == AA_PREFER_IMAGE_FILE) 1963 { 1964 if (find_albumart(track_id3, path, sizeof(path), 1965 &albumart_slots[i].dim)) 1966 { 1967 hid = load_album_art_from_path(path, &user_data, is_current_track, i); 1968 } 1969 checked_image_file = true; 1970 } 1971 1972 /* We can only decode jpeg for embedded AA */ 1973 if (global_settings.album_art != AA_OFF && 1974 hid < 0 && hid != ERR_BUFFER_FULL && 1975 track_id3->has_embedded_albumart && (track_id3->albumart.type & AA_CLEAR_FLAGS_MASK) == AA_TYPE_JPG) 1976 { 1977 if (is_current_track) 1978 clear_last_folder_album_art(); 1979 user_data.embedded_albumart = &track_id3->albumart; 1980 hid = bufopen(track_id3->path, 0, TYPE_BITMAP, &user_data); 1981 } 1982 1983 if (global_settings.album_art != AA_OFF && !checked_image_file && 1984 hid < 0 && hid != ERR_BUFFER_FULL) 1985 { 1986 /* No embedded AA or it couldn't be loaded - try other sources */ 1987 if (find_albumart(track_id3, path, sizeof(path), 1988 &albumart_slots[i].dim)) 1989 { 1990 hid = load_album_art_from_path(path, &user_data, is_current_track, i); 1991 } 1992 } 1993 1994 if (hid == ERR_BUFFER_FULL) 1995 { 1996 logf("buffer is full for now (%s)", __func__); 1997 return ERR_BUFFER_FULL; 1998 } 1999 else if (hid == ERR_BITMAP_TOO_LARGE){ 2000 logf("image is too large to fit in buffer (%s)", __func__); 2001 return ERR_BITMAP_TOO_LARGE; 2002 } 2003 else 2004 { 2005 /* If error other than a full buffer, then mark it "unsupported" 2006 to avoid reloading attempt */ 2007 if (hid < 0) 2008 { 2009 logf("Album art loading failed"); 2010 hid = ERR_UNSUPPORTED_TYPE; 2011 } 2012 else 2013 { 2014 logf("Loaded album art:%dx%d", user_data.dim->width, 2015 user_data.dim->height); 2016 } 2017 2018 *aa_hid = hid; 2019 } 2020 } 2021 2022 return true; 2023} 2024#endif /* HAVE_ALBUMART */ 2025 2026#ifdef HAVE_CODEC_BUFFERING 2027/* Load a codec for the file onto the buffer - assumes we're working from the 2028 currently loading track - not called for the current track */ 2029static bool audio_buffer_codec(struct track_info *track_infop, 2030 struct mp3entry *track_id3) 2031{ 2032 /* This will not be the current track -> it cannot be the first and the 2033 current track cannot be ahead of buffering -> there is a previous 2034 track entry which is either current or ahead of the current */ 2035 struct track_info prev_info; 2036 track_list_last(-1, &prev_info); 2037 2038 struct mp3entry *prev_id3 = bufgetid3(prev_info.id3_hid); 2039 2040 /* If the previous codec is the same as this one, there is no need to 2041 put another copy of it on the file buffer (in other words, only 2042 buffer codecs at format transitions) */ 2043 if (prev_id3) 2044 { 2045 int codt = get_audio_base_codec_type(track_id3->codectype); 2046 int prev_codt = get_audio_base_codec_type(prev_id3->codectype); 2047 2048 if (codt == prev_codt) 2049 { 2050 logf("Reusing prev. codec: %d", prev_id3->codectype); 2051 return true; 2052 } 2053 } 2054 /* else just load it (harmless) */ 2055 2056 /* Load the codec onto the buffer if possible */ 2057 const char *codec_fn = get_codec_filename(track_id3->codectype); 2058 if (!codec_fn) 2059 return false; 2060 2061 char codec_path[MAX_PATH+1]; /* Full path to codec */ 2062 codec_get_full_path(codec_path, codec_fn); 2063 2064 track_infop->codec_hid = bufopen(codec_path, 0, TYPE_CODEC, NULL); 2065 2066 if (track_infop->codec_hid > 0) 2067 { 2068 logf("Buffered codec: %d", track_infop->codec_hid); 2069 return true; 2070 } 2071 2072 return false; 2073} 2074#endif /* HAVE_CODEC_BUFFERING */ 2075 2076/* Load metadata for the next track (with bufopen). The rest of the track 2077 loading will be handled by audio_finish_load_track once the metadata has 2078 been actually loaded by the buffering thread. 2079 2080 Each track is arranged in the buffer as follows: 2081 <id3|[cuesheet|][album art|][codec|]audio> 2082 2083 The next will not be loaded until the previous succeeds if the buffer was 2084 full at the time. To put any metadata after audio would make those handles 2085 unmovable. 2086*/ 2087static int audio_load_track(void) 2088{ 2089 struct track_info info; 2090 2091 if (track_list.in_progress_hid > 0) 2092 { 2093 /* There must be an info pointer if the in-progress id3 is even there */ 2094 if (track_list_last(0, &info) && info.self_hid == track_list.in_progress_hid) 2095 { 2096 if (filling == STATE_FILLING) 2097 { 2098 /* Haven't finished the metadata but the notification is 2099 anticipated to come soon */ 2100 logf("%s:in progress:id=%d", __func__, info.self_hid); 2101 return LOAD_TRACK_OK; 2102 } 2103 else if (filling == STATE_FULL) 2104 { 2105 /* Buffer was full trying to complete the load after the 2106 metadata finished, so attempt to continue - older handles 2107 should have been cleared already */ 2108 logf("%s:finished:id=%d", __func__, info.self_hid); 2109 filling = STATE_FILLING; 2110 buffer_event_finished_callback(BUFFER_EVENT_FINISHED, &info.id3_hid); 2111 return LOAD_TRACK_OK; 2112 } 2113 } 2114 2115 /* Some old, stray buffering message */ 2116 logf("%s:busy:id=%d", __func__, info.self_hid); 2117 return LOAD_TRACK_ERR_BUSY; 2118 } 2119 2120 filling = STATE_FILLING; 2121 2122 if (!track_list_alloc_info(&info)) 2123 { 2124 /* List is full so stop buffering tracks - however, attempt to obtain 2125 metadata as the unbuffered id3 */ 2126 logf("buffer full:alloc"); 2127 filling = STATE_FULL; 2128 } 2129 2130 playlist_peek_offset++; 2131 2132 logf("Buffering track:f=%d:c=%d:l=%d:pk=%d", 2133 track_list.first_hid, track_list.current_hid, track_list.last_hid, 2134 playlist_peek_offset); 2135 2136 /* Get track name from current playlist read position */ 2137 int fd = -1; 2138 char path_buf[MAX_PATH + 1]; 2139 const char *path; 2140 2141 while (1) 2142 { 2143 path = playlist_peek(playlist_peek_offset, 2144 path_buf, 2145 sizeof (path_buf)); 2146 2147 if (!path) 2148 break; 2149 2150 /* Test for broken playlists by probing for the files */ 2151 if (file_exists(path)) 2152 { 2153 fd = open(path, O_RDONLY); 2154 if (fd >= 0) 2155 break; 2156 } 2157 logf("Open failed %s", path); 2158 2159 /* only skip if failed track has a successor in playlist */ 2160 if (!playlist_peek(playlist_peek_offset + 1, NULL, 0)) 2161 break; 2162 2163 /* Skip invalid entry from playlist */ 2164 playlist_skip_entry(NULL, playlist_peek_offset); 2165 2166 /* Sync the playlist if it isn't finished */ 2167 if (playlist_peek(playlist_peek_offset, NULL, 0)) 2168 playlist_next(0); 2169 } 2170 2171 if (!path) 2172 { 2173 /* No track - exhausted the playlist entries */ 2174 logf("End-of-playlist"); 2175 id3_write_locked(UNBUFFERED_ID3, NULL); 2176 2177 if (filling != STATE_FULL) 2178 track_list_free_info(&info); /* Free this entry */ 2179 2180 playlist_peek_offset--; /* Maintain at last index */ 2181 2182 /* We can end up here after the real last track signals its completion 2183 and miss the transition to STATE_FINISHED esp. if dropping the last 2184 songs of a playlist late in their load (2nd stage) */ 2185 if (track_list_last(0, &info) && buf_handle_remaining(info.audio_hid) == 0) 2186 filling_is_finished(); 2187 else 2188 filling = STATE_END_OF_PLAYLIST; 2189 2190 return LOAD_TRACK_ERR_NO_MORE; 2191 } 2192 2193 /* Successfully opened the file - get track metadata */ 2194 if (filling == STATE_FULL || 2195 (info.id3_hid = bufopen(path, 0, TYPE_ID3, NULL)) < 0) 2196 { 2197 /* Buffer or track list is full */ 2198 struct mp3entry *ub_id3; 2199 2200 playlist_peek_offset--; 2201 2202 /* Load the metadata for the first unbuffered track */ 2203 ub_id3 = id3_get(UNBUFFERED_ID3); 2204 2205 if (fd >= 0) 2206 { 2207 id3_mutex_lock(); 2208 get_metadata(ub_id3, fd, path); 2209 id3_mutex_unlock(); 2210 } 2211 2212 if (filling != STATE_FULL) 2213 { 2214 track_list_free_info(&info); 2215 filling = STATE_FULL; 2216 } 2217 2218 logf("%s: buffer is full for now (%u tracks)", __func__, 2219 track_list_count()); 2220 } 2221 else 2222 { 2223 if (!track_list_commit_info(&info)) 2224 { 2225 track_list_free_info(&info); 2226 track_list.in_progress_hid = 0; 2227 if (fd >= 0) 2228 close(fd); 2229 return LOAD_TRACK_ERR_FAILED; 2230 } 2231 2232 /* Successful load initiation */ 2233 track_list.in_progress_hid = info.self_hid; 2234 } 2235 if (fd >= 0) 2236 close(fd); 2237 return LOAD_TRACK_OK; 2238} 2239 2240#ifdef HAVE_PLAY_FREQ 2241static bool audio_auto_change_frequency(struct mp3entry *id3, bool play); 2242#endif 2243 2244/* Second part of the track loading: We now have the metadata available, so we 2245 can load the codec, the album art and finally the audio data. 2246 This is called on the audio thread after the buffering thread calls the 2247 buffering_handle_finished_callback callback. */ 2248static int audio_finish_load_track(struct track_info *infop) 2249{ 2250 int trackstat = LOAD_TRACK_OK; 2251 2252 if (infop->self_hid != track_list.in_progress_hid) 2253 { 2254 /* We must not be here if not! */ 2255 logf("%s:wrong track:hids=%d!=%d", __func__, infop->self_hid, 2256 track_list.in_progress_hid); 2257 return LOAD_TRACK_ERR_BUSY; 2258 } 2259 2260 /* The current track for decoding (there is always one if the list is 2261 populated) */ 2262 struct track_info cur_info; 2263 track_list_current(0, &cur_info); 2264 2265 struct mp3entry *track_id3 = valid_mp3entry(bufgetid3(infop->id3_hid)); 2266 2267 if (!track_id3) 2268 { 2269 /* This is an error condition. Track cannot be played without valid 2270 metadata; skip the track. */ 2271 logf("No metadata"); 2272 trackstat = LOAD_TRACK_ERR_FINISH_FAILED; 2273 goto audio_finish_load_track_exit; 2274 } 2275 2276 struct track_info user_cur; 2277 2278#ifdef HAVE_PLAY_FREQ 2279 track_list_user_current(0, &user_cur); 2280 bool is_current_user = infop->self_hid == user_cur.self_hid; 2281 if (audio_auto_change_frequency(track_id3, is_current_user)) 2282 { 2283 // frequency switch requires full re-buffering, so stop buffering 2284 filling = STATE_STOPPED; 2285 logf("buffering stopped (current_track: %b, current_user: %b)", infop->self_hid == cur_info.self_hid, is_current_user); 2286 if (is_current_user) 2287 // audio_finish_load_track_exit not needed as playback restart is already initiated 2288 return trackstat; 2289 2290 goto audio_finish_load_track_exit; 2291 } 2292#endif 2293 2294 /* Try to load a cuesheet for the track */ 2295 if (!audio_load_cuesheet(infop, track_id3)) 2296 { 2297 /* No space for cuesheet on buffer, not an error */ 2298 filling = STATE_FULL; 2299 goto audio_finish_load_track_exit; 2300 } 2301 2302#ifdef HAVE_ALBUMART 2303 /* Try to load album art for the track */ 2304 int retval = audio_load_albumart(infop, track_id3, infop->self_hid == cur_info.self_hid); 2305 if (retval == ERR_BITMAP_TOO_LARGE) 2306 { 2307 /* No space for album art on buffer because the file is larger than the buffer. 2308 Ignore the file and keep buffering */ 2309 } else if (retval == ERR_BUFFER_FULL) 2310 { 2311 /* No space for album art on buffer, not an error */ 2312 filling = STATE_FULL; 2313 goto audio_finish_load_track_exit; 2314 } 2315#endif 2316 2317 /* All handles available to external routines are ready - audio and codec 2318 information is private */ 2319 2320 track_list_user_current(0, &user_cur); 2321 if (infop->self_hid == user_cur.self_hid) 2322 { 2323 /* Send only when the track handles could not all be opened ahead of 2324 time for the user's current track - otherwise everything is ready 2325 by the time PLAYBACK_EVENT_TRACK_CHANGE is sent */ 2326 send_track_event(PLAYBACK_EVENT_CUR_TRACK_READY, 0, 2327 id3_get(PLAYING_ID3)); 2328 } 2329 2330#ifdef HAVE_CODEC_BUFFERING 2331 /* Try to buffer a codec for the track */ 2332 if (infop->self_hid != cur_info.self_hid 2333 && !audio_buffer_codec(infop, track_id3)) 2334 { 2335 if (infop->codec_hid == ERR_BUFFER_FULL) 2336 { 2337 /* No space for codec on buffer, not an error */ 2338 filling = STATE_FULL; 2339 logf("%s:STATE_FULL", __func__); 2340 } 2341 else 2342 { 2343 /* This is an error condition, either no codec was found, or 2344 reading the codec file failed part way through, either way, 2345 skip the track */ 2346 logf("No codec for: %s", track_id3->path); 2347 trackstat = LOAD_TRACK_ERR_FINISH_FAILED; 2348 } 2349 2350 goto audio_finish_load_track_exit; 2351 } 2352#endif /* HAVE_CODEC_BUFFERING */ 2353 2354 /** Finally, load the audio **/ 2355 off_t file_offset = 0; 2356 2357 /* Adjust for resume rewind so we know what to buffer - starting the codec 2358 calls it again, so we don't save it (and they shouldn't accumulate) */ 2359 unsigned long elapsed, offset; 2360 resume_rewind_adjust_progress(track_id3, &elapsed, &offset); 2361 2362 enum data_type audiotype = rbcodec_format_is_atomic(track_id3->codectype) ? 2363 TYPE_ATOMIC_AUDIO : TYPE_PACKET_AUDIO; 2364 2365 if (audiotype == TYPE_ATOMIC_AUDIO) 2366 logf("Loading atomic %d", track_id3->codectype); 2367 2368 if (format_buffers_with_offset(track_id3->codectype)) 2369 { 2370 /* This format can begin buffering from any point */ 2371 file_offset = offset; 2372 } 2373 2374 logf("load track: %s", track_id3->path); 2375 2376 if (file_offset > AUDIO_REBUFFER_GUESS_SIZE) 2377 { 2378 /* We can buffer later in the file, adjust the hunt-and-peck margin */ 2379 file_offset -= AUDIO_REBUFFER_GUESS_SIZE; 2380 } 2381 else 2382 { 2383 /* No offset given or it is very minimal - begin at the first frame 2384 according to the metadata */ 2385 file_offset = track_id3->first_frame_offset; 2386 } 2387 2388 int hid = bufopen(track_id3->path, file_offset, audiotype, NULL); 2389 2390 if (hid >= 0) 2391 { 2392 infop->audio_hid = hid; 2393 2394 /* 2395 * Fix up elapsed time and offset if past the end 2396 */ 2397 if (track_id3->elapsed > track_id3->length) 2398 track_id3->elapsed = 0; 2399 2400 if ((off_t)track_id3->offset >= buf_filesize(infop->audio_hid)) 2401 track_id3->offset = 0; 2402 2403 logf("%s: set resume for %s to %lu %lX", __func__, 2404 track_id3->title, track_id3->elapsed, track_id3->offset); 2405 2406 if (infop->self_hid == cur_info.self_hid) 2407 { 2408 /* This is the current track to decode - should be started now */ 2409 trackstat = LOAD_TRACK_READY; 2410 } 2411 } 2412 else 2413 { 2414 /* Buffer could be full but not properly so if this is the only 2415 track! */ 2416 if (hid == ERR_BUFFER_FULL && audio_track_count() > 1) 2417 { 2418 filling = STATE_FULL; 2419 logf("Buffer is full for now (%s)", __func__); 2420 } 2421 else 2422 { 2423 /* Nothing to play if no audio handle - skip this */ 2424 logf("Could not add audio data handle"); 2425 trackstat = LOAD_TRACK_ERR_FINISH_FAILED; 2426 } 2427 } 2428 2429audio_finish_load_track_exit: 2430 if (trackstat >= LOAD_TRACK_OK && !track_info_sync(infop)) 2431 { 2432 logf("Track info sync failed"); 2433 trackstat = LOAD_TRACK_ERR_FINISH_FAILED; 2434 } 2435 2436 if (trackstat < LOAD_TRACK_OK) 2437 { 2438 playlist_skip_entry(NULL, playlist_peek_offset); 2439 track_list_free_info(infop); 2440 2441 if (playlist_peek(playlist_peek_offset, NULL, 0)) 2442 playlist_next(0); 2443 2444 playlist_peek_offset--; 2445 } 2446 2447 if (filling != STATE_FULL && filling != STATE_STOPPED) 2448 { 2449 /* Load next track - error or not */ 2450 track_list.in_progress_hid = 0; 2451 LOGFQUEUE("audio > audio Q_AUDIO_FILL_BUFFER"); 2452 audio_queue_post(Q_AUDIO_FILL_BUFFER, 0); 2453 } 2454 else 2455 { 2456 /* Full */ 2457 trackstat = LOAD_TRACK_ERR_FINISH_FULL; 2458 } 2459 2460 return trackstat; 2461} 2462 2463/* Start a new track load */ 2464static int audio_fill_file_buffer(void) 2465{ 2466 if (play_status == PLAY_STOPPED) 2467 return LOAD_TRACK_ERR_FAILED; 2468 2469 trigger_cpu_boost(); 2470 2471 /* Must reset the buffer before use if trashed or voice only - voice 2472 file size shouldn't have changed so we can go straight from 2473 AUDIOBUF_STATE_VOICED_ONLY to AUDIOBUF_STATE_INITIALIZED */ 2474 if (buffer_state != AUDIOBUF_STATE_INITIALIZED || 2475 !pcmbuf_is_same_size()) 2476 { 2477 audio_reset_buffer(); 2478 } 2479 2480 logf("Starting buffer fill"); 2481 2482 int trackstat = audio_load_track(); 2483 2484 if (trackstat >= LOAD_TRACK_OK) 2485 { 2486 struct track_info info, user_cur; 2487 track_list_current(0, &info); 2488 track_list_user_current(0, &user_cur); 2489 2490 if (info.self_hid == user_cur.self_hid) 2491 playlist_next(0); 2492 2493 if (filling == STATE_FULL && !track_list_user_current(1, NULL)) 2494 { 2495 /* There are no user tracks on the buffer after this therefore 2496 this is the next track */ 2497 audio_update_and_announce_next_track(id3_get(UNBUFFERED_ID3)); 2498 } 2499 } 2500 2501 return trackstat; 2502} 2503 2504/* Discard unwanted tracks and start refill from after the specified playlist 2505 offset */ 2506static int audio_reset_and_rebuffer( 2507 enum track_clear_action action, int peek_offset) 2508{ 2509 logf("Forcing rebuffer: 0x%X, %d", action, peek_offset); 2510 2511 id3_write_locked(UNBUFFERED_ID3, NULL); 2512 2513 /* Remove unwanted tracks - caller must have ensured codec isn't using 2514 any */ 2515 track_list_clear(action); 2516 2517 /* Refill at specified position (-1 starts at index offset 0) */ 2518 playlist_peek_offset = peek_offset; 2519 2520 /* Fill the buffer */ 2521 return audio_fill_file_buffer(); 2522} 2523 2524/* Handle buffering events 2525 (Q_AUDIO_BUFFERING) */ 2526static void audio_on_buffering(int event) 2527{ 2528 enum track_clear_action action; 2529 int peek_offset; 2530 2531 if (track_list_empty()) 2532 return; 2533 2534 switch (event) 2535 { 2536 case BUFFER_EVENT_BUFFER_LOW: 2537 if (filling != STATE_FULL && filling != STATE_END_OF_PLAYLIST) 2538 return; /* Should be nothing left to fill */ 2539 2540 /* Clear old tracks and continue buffering where it left off */ 2541 action = TRACK_LIST_KEEP_NEW; 2542 peek_offset = playlist_peek_offset; 2543 break; 2544 2545 case BUFFER_EVENT_REBUFFER: 2546 /* Remove all but the currently decoding track and redo buffering 2547 after that */ 2548 action = TRACK_LIST_KEEP_CURRENT; 2549 peek_offset = (skip_pending == TRACK_SKIP_AUTO) ? 1 : 0; 2550 break; 2551 2552 default: 2553 return; 2554 } 2555 2556 switch (skip_pending) 2557 { 2558 case TRACK_SKIP_NONE: 2559 case TRACK_SKIP_AUTO: 2560 case TRACK_SKIP_AUTO_NEW_PLAYLIST: 2561 audio_reset_and_rebuffer(action, peek_offset); 2562 break; 2563 2564 case TRACK_SKIP_AUTO_END_PLAYLIST: 2565 /* Already finished */ 2566 break; 2567 2568 default: 2569 /* Invalid */ 2570 logf("Buffering call, inv. state: %d", (int)skip_pending); 2571 } 2572} 2573 2574/* Handle starting the next track load 2575 (Q_AUDIO_FILL_BUFFER) */ 2576static void audio_on_fill_buffer(void) 2577{ 2578 audio_handle_track_load_status(audio_fill_file_buffer()); 2579} 2580 2581/* Handle posted load track finish event 2582 (Q_AUDIO_FINISH_LOAD_TRACK) */ 2583static void audio_on_finish_load_track(int id3_hid) 2584{ 2585 struct track_info info, user_cur; 2586 2587 if (!buf_is_handle(id3_hid) || !track_list_last(0, &info)) 2588 return; 2589 2590 track_list_user_current(1, &user_cur); 2591 if (info.self_hid == user_cur.self_hid) 2592 { 2593 /* Just loaded the metadata right after the current position */ 2594 audio_update_and_announce_next_track(bufgetid3(info.id3_hid)); 2595 } 2596 2597 if (audio_finish_load_track(&info) != LOAD_TRACK_READY) 2598 return; /* Not current track */ 2599 2600 track_list_user_current(0, &user_cur); 2601 bool is_user_current = info.self_hid == user_cur.self_hid; 2602 2603 if (is_user_current) 2604 { 2605 /* Copy cuesheet */ 2606 buf_read_cuesheet(info.cuesheet_hid); 2607 } 2608 2609 if (audio_start_codec(track_event_flags & TEF_AUTO_SKIP)) 2610 { 2611 if (is_user_current) 2612 { 2613 /* Be sure all tagtree info is synchronized; it will be needed for the 2614 track finish event - the sync will happen when finalizing a track 2615 change otherwise */ 2616 bool was_valid = valid_mp3entry(id3_get(PLAYING_ID3)); 2617 2618 playing_id3_sync(&info, NULL, true); 2619 2620 if (!was_valid) 2621 { 2622 /* Playing id3 hadn't been updated yet because no valid track 2623 was yet available - treat like the first track */ 2624 audio_playlist_track_change(); 2625 } 2626 } 2627 } 2628 else 2629 { 2630 audio_handle_track_load_status(LOAD_TRACK_ERR_START_CODEC); 2631 } 2632} 2633 2634/* Called when handles other than metadata handles have finished buffering 2635 (Q_AUDIO_HANDLE_FINISHED) */ 2636static void audio_on_handle_finished(int hid) 2637{ 2638 /* Right now, only audio handles should end up calling this */ 2639 if (filling == STATE_END_OF_PLAYLIST) 2640 { 2641 struct track_info info; 2642 2643 /* Really we don't know which order the handles will actually complete 2644 to zero bytes remaining since another thread is doing it - be sure 2645 it's the right one */ 2646 if (track_list_last(0, &info) && info.audio_hid == hid) 2647 { 2648 /* This was the last track in the playlist and we now have all the 2649 data we need */ 2650 filling_is_finished(); 2651 } 2652 } 2653} 2654 2655static inline char* single_mode_get_id3_tag(struct mp3entry *id3) 2656{ 2657 struct mp3entry *valid_id3 = valid_mp3entry(id3); 2658 if (valid_id3 == NULL) 2659 return NULL; 2660 2661 switch (global_settings.single_mode) 2662 { 2663 case SINGLE_MODE_ALBUM: 2664 return valid_id3->album; 2665 case SINGLE_MODE_ALBUM_ARTIST: 2666 return valid_id3->albumartist; 2667 case SINGLE_MODE_ARTIST: 2668 return valid_id3->artist; 2669 case SINGLE_MODE_COMPOSER: 2670 return valid_id3->composer; 2671 case SINGLE_MODE_GROUPING: 2672 return valid_id3->grouping; 2673 case SINGLE_MODE_GENRE: 2674 return valid_id3->genre_string; 2675 } 2676 2677 return NULL; 2678} 2679 2680static bool single_mode_do_pause(int id3_hid) 2681{ 2682 if (global_settings.single_mode != SINGLE_MODE_OFF && global_settings.party_mode == 0 && 2683 ((skip_pending == TRACK_SKIP_AUTO) || (skip_pending == TRACK_SKIP_AUTO_NEW_PLAYLIST))) { 2684 2685 if (global_settings.single_mode == SINGLE_MODE_TRACK) 2686 return true; 2687 2688 char *previous_tag = single_mode_get_id3_tag(id3_get(PLAYING_ID3)); 2689 char *new_tag = single_mode_get_id3_tag(bufgetid3(id3_hid)); 2690 return previous_tag == NULL || 2691 new_tag == NULL || 2692 strcmp(previous_tag, new_tag) != 0; 2693 } 2694 return false; 2695} 2696 2697/* Called to make an outstanding track skip the current track and to send the 2698 transition events */ 2699static void audio_finalise_track_change(void) 2700{ 2701 switch (skip_pending) 2702 { 2703 case TRACK_SKIP_NONE: /* Manual skip */ 2704 break; 2705 2706 case TRACK_SKIP_AUTO: 2707 case TRACK_SKIP_AUTO_NEW_PLAYLIST: 2708 { 2709 int playlist_delta = skip_pending == TRACK_SKIP_AUTO ? 1 : 0; 2710 audio_playlist_track_finish(); 2711 2712 if (!playlist_peek(playlist_delta, NULL, 0)) 2713 { 2714 /* Track ended up rejected - push things ahead like the codec blew 2715 it (because it was never started and now we're here where it 2716 should have been decoding the next track by now) - next, a 2717 directory change or end of playback will most likely happen */ 2718 skip_pending = TRACK_SKIP_NONE; 2719 audio_handle_track_load_status(LOAD_TRACK_ERR_START_CODEC); 2720 return; 2721 } 2722 2723 if (!playlist_delta) 2724 break; 2725 2726 playlist_peek_offset -= playlist_delta; 2727 if (playlist_next(playlist_delta) >= 0) 2728 break; 2729 /* What!? Disappear? Hopeless bleak despair */ 2730 } 2731 /* Fallthrough */ 2732 case TRACK_SKIP_AUTO_END_PLAYLIST: 2733 default: /* Invalid */ 2734 filling = STATE_ENDED; 2735 audio_stop_playback(); 2736 return; 2737 } 2738 2739 struct track_info info; 2740 bool have_info = track_list_current(0, &info); 2741 struct mp3entry *track_id3 = NULL; 2742 2743 /* Update the current cuesheet if any and enabled */ 2744 if (have_info) 2745 { 2746 buf_read_cuesheet(info.cuesheet_hid); 2747 track_id3 = bufgetid3(info.id3_hid); 2748 2749 if (single_mode_do_pause(info.id3_hid)) 2750 { 2751 play_status = PLAY_PAUSED; 2752 pcmbuf_pause(true); 2753 } 2754 } 2755 /* Sync the next track information */ 2756 have_info = track_list_current(1, &info); 2757 2758 id3_mutex_lock(); 2759 2760 id3_write(PLAYING_ID3, track_id3); 2761 2762 /* The skip is technically over */ 2763 skip_pending = TRACK_SKIP_NONE; 2764 2765 id3_write(NEXTTRACK_ID3, have_info ? bufgetid3(info.id3_hid) : 2766 id3_get(UNBUFFERED_ID3)); 2767 2768 id3_mutex_unlock(); 2769 2770 audio_playlist_track_change(); 2771 2772#ifdef HAVE_PLAY_FREQ 2773 if (filling == STATE_STOPPED) 2774 audio_auto_change_frequency(track_id3, true); 2775#endif 2776} 2777 2778/* Actually begin a transition and take care of the codec change - may complete 2779 it now or ask pcmbuf for notification depending on the type */ 2780static void audio_begin_track_change(enum pcm_track_change_type type, 2781 int trackstat) 2782{ 2783 /* Even if the new track is bad, the old track must be finished off */ 2784 pcmbuf_start_track_change(type); 2785 2786 track_skip_is_manual = (type == TRACK_CHANGE_MANUAL); 2787 2788 if (track_skip_is_manual) 2789 { 2790 /* Manual track change happens now */ 2791 audio_finalise_track_change(); 2792 pcmbuf_sync_position_update(); 2793 2794 if (play_status == PLAY_STOPPED) 2795 return; /* Stopped us */ 2796 } 2797 2798 if (trackstat >= LOAD_TRACK_OK) 2799 { 2800 struct track_info info; 2801 if (track_list_current(0, &info)) 2802 { 2803 if (info.audio_hid < 0) 2804 return; 2805 2806 /* Everything needed for the codec is ready - start it */ 2807 if (audio_start_codec(!track_skip_is_manual)) 2808 { 2809 if (track_skip_is_manual) 2810 playing_id3_sync(&info, NULL, true); 2811 return; 2812 } 2813 } 2814 2815 trackstat = LOAD_TRACK_ERR_START_CODEC; 2816 } 2817 2818 audio_handle_track_load_status(trackstat); 2819} 2820 2821/* Transition to end-of-playlist state and begin wait for PCM to finish */ 2822static void audio_monitor_end_of_playlist(void) 2823{ 2824 skip_pending = TRACK_SKIP_AUTO_END_PLAYLIST; 2825 filling = STATE_ENDING; 2826 pcmbuf_start_track_change(TRACK_CHANGE_END_OF_DATA); 2827} 2828 2829/* Does this track have an entry allocated? */ 2830static bool audio_can_change_track(int *trackstat, int *id3_hid) 2831{ 2832 struct track_info info; 2833 bool have_track = track_list_advance_current(1, &info); 2834 *id3_hid = info.id3_hid; 2835 if (!have_track || info.audio_hid < 0) 2836 { 2837 bool end_of_playlist = false; 2838 2839 if (have_track) 2840 { 2841 if (filling == STATE_STOPPED) 2842 { 2843 audio_begin_track_change(TRACK_CHANGE_END_OF_DATA, *trackstat); 2844 return false; 2845 } 2846 2847 /* Track load is not complete - it might have stopped on a 2848 full buffer without reaching the audio handle or we just 2849 arrived at it early 2850 2851 If this type is atomic and we couldn't get the audio, 2852 perhaps it would need to wrap to make the allocation and 2853 handles are in the way - to maximize the liklihood it can 2854 be allocated, clear all handles to reset the buffer and 2855 its indexes to 0 - for packet audio, this should not be an 2856 issue and a pointless full reload of all the track's 2857 metadata may be avoided */ 2858 2859 struct mp3entry *track_id3 = bufgetid3(info.id3_hid); 2860 2861 if (track_id3 && !rbcodec_format_is_atomic(track_id3->codectype)) 2862 { 2863 /* Continue filling after this track */ 2864 audio_reset_and_rebuffer(TRACK_LIST_KEEP_CURRENT, 1); 2865 return true; 2866 } 2867 /* else rebuffer at this track; status applies to the track we 2868 want */ 2869 } 2870 else if (!playlist_peek(1, NULL, 0)) 2871 { 2872 /* Play sequence is complete - directory change or other playlist 2873 resequencing - the playlist must now be advanced in order to 2874 continue since a peek ahead to the next track is not possible */ 2875 skip_pending = TRACK_SKIP_AUTO_NEW_PLAYLIST; 2876 end_of_playlist = playlist_next(1) < 0; 2877 } 2878 2879 if (!end_of_playlist) 2880 { 2881 *trackstat = audio_reset_and_rebuffer(TRACK_LIST_CLEAR_ALL, 2882 skip_pending == TRACK_SKIP_AUTO ? 0 : -1); 2883 2884 if (*trackstat == LOAD_TRACK_ERR_NO_MORE) 2885 { 2886 /* Failed to find anything after all - do playlist switchover 2887 instead */ 2888 skip_pending = TRACK_SKIP_AUTO_NEW_PLAYLIST; 2889 end_of_playlist = playlist_next(1) < 0; 2890 } 2891 } 2892 2893 if (end_of_playlist) 2894 { 2895 audio_monitor_end_of_playlist(); 2896 return false; 2897 } 2898 } 2899 return true; 2900} 2901 2902/* Codec has completed decoding the track 2903 (usually Q_AUDIO_CODEC_COMPLETE) */ 2904static void audio_on_codec_complete(int status) 2905{ 2906 logf("%s(%d)", __func__, status); 2907 2908 if (play_status == PLAY_STOPPED) 2909 return; 2910 2911 /* If it didn't notify us first, don't expect "seek complete" message 2912 since the codec can't post it now - do things like it would have 2913 done */ 2914 audio_complete_codec_seek(); 2915 2916 if (play_status == PLAY_PAUSED || skip_pending != TRACK_SKIP_NONE) 2917 { 2918 /* Old-hay on the ip-skay - codec has completed decoding 2919 2920 Paused: We're not sounding it, so just remember that it happened 2921 and the resume will begin the transition 2922 2923 Skipping: There was already a skip in progress, remember it and 2924 allow no further progress until the PCM from the previous 2925 song has finished 2926 2927 This function will be reentered upon completing the existing 2928 transition in order to do the one that was just tried (below) 2929 */ 2930 codec_skip_pending = true; 2931 codec_skip_status = status; 2932 2933 /* PCM buffer must know; audio could still be filling and hasn't 2934 yet reached the play watermark */ 2935 pcmbuf_start_track_change(TRACK_CHANGE_AUTO_PILEUP); 2936 return; 2937 } 2938 2939 codec_skip_pending = false; 2940 2941 int trackstat = LOAD_TRACK_OK; 2942 2943 track_event_flags = TEF_AUTO_SKIP; 2944 skip_pending = TRACK_SKIP_AUTO; 2945 2946 int id3_hid = 0; 2947 if (audio_can_change_track(&trackstat, &id3_hid)) 2948 { 2949 audio_begin_track_change( 2950 single_mode_do_pause(id3_hid) 2951 ? TRACK_CHANGE_END_OF_DATA 2952 : TRACK_CHANGE_AUTO, trackstat); 2953 } 2954} 2955 2956/* Called when codec completes seek operation 2957 (usually Q_AUDIO_CODEC_SEEK_COMPLETE) */ 2958static void audio_on_codec_seek_complete(void) 2959{ 2960 logf("%s()", __func__); 2961 audio_complete_codec_seek(); 2962 codec_go(); 2963} 2964 2965/* Called when PCM track change has completed 2966 (Q_AUDIO_TRACK_CHANGED) */ 2967static void audio_on_track_changed(void) 2968{ 2969 /* Finish whatever is pending so that the WPS is in sync */ 2970 audio_finalise_track_change(); 2971 2972 if (codec_skip_pending) 2973 { 2974 /* Codec got ahead completing a short track - complete the 2975 codec's skip and begin the next */ 2976 codec_skip_pending = false; 2977 audio_on_codec_complete(codec_skip_status); 2978 } 2979} 2980 2981/* Begin playback from an idle state, transition to a new playlist or 2982 invalidate the buffer and resume (if playing). 2983 (usually Q_AUDIO_PLAY, Q_AUDIO_REMAKE_AUDIO_BUFFER) */ 2984static void audio_start_playback(const struct audio_resume_info *resume_info, 2985 unsigned int flags) 2986{ 2987/* 2988 * Refuse to start playback if usb audio is active. See gui_wps_show() for 2989 * a splash message to the user. 2990 * NOTE: if USBAudio ever gets its own DSP channel, this block can go away! 2991 */ 2992#ifdef USB_ENABLE_AUDIO 2993 if (usb_audio_get_active()) 2994 { 2995 queue_reply(&audio_queue, 0); 2996 return; 2997 } 2998#endif 2999 static struct audio_resume_info resume = { 0, 0 }; 3000 enum play_status old_status = play_status; 3001 3002 bool skip_resume_adjustments = false; 3003 if (resume_info) 3004 { 3005 resume.elapsed = resume_info->elapsed; 3006 resume.offset = resume_info->offset; 3007 } 3008 else 3009 { 3010 resume.elapsed = 0; 3011 resume.offset = 0; 3012 } 3013 3014 if (flags & AUDIO_START_NEWBUF) 3015 { 3016 /* Mark the buffer dirty - if not playing, it will be reset next 3017 time */ 3018 if (buffer_state == AUDIOBUF_STATE_INITIALIZED) 3019 buffer_state = AUDIOBUF_STATE_TRASHED; 3020 } 3021 3022 if (old_status != PLAY_STOPPED) 3023 { 3024 logf("%s(%lu, %lu): skipping", __func__, resume.elapsed, 3025 resume.offset); 3026 3027 halt_decoding_track(true); 3028 3029 track_event_flags = TEF_NONE; 3030 ff_rw_mode = false; 3031 3032 if (flags & AUDIO_START_RESTART) 3033 { 3034 /* Clear out some stuff to resume the current track where it 3035 left off */ 3036 pcmbuf_play_stop(); 3037 3038 resume.elapsed = id3_get(PLAYING_ID3)->elapsed; 3039 resume.offset = id3_get(PLAYING_ID3)->offset; 3040 skip_resume_adjustments = id3_get(PLAYING_ID3)->skip_resume_adjustments; 3041 3042 track_list_clear(TRACK_LIST_CLEAR_ALL); 3043 pcmbuf_update_frequency(); 3044 } 3045 else 3046 { 3047 /* This is more-or-less treated as manual track transition */ 3048 /* Save resume information for current track */ 3049 audio_playlist_track_finish(); 3050 track_list_clear(TRACK_LIST_CLEAR_ALL); 3051 3052 /* Indicate manual track change */ 3053 pcmbuf_start_track_change(TRACK_CHANGE_MANUAL); 3054 wipe_track_metadata(true); 3055 } 3056 pcmbuf_update_frequency(); 3057 3058 /* Set after track finish event in case skip was in progress */ 3059 skip_pending = TRACK_SKIP_NONE; 3060 } 3061 else 3062 { 3063 if (flags & AUDIO_START_RESTART) 3064 return; /* Must already be playing */ 3065 3066 /* Cold playback start from a stopped state */ 3067 logf("%s(%lu, %lu): starting", __func__, resume.elapsed, 3068 resume.offset); 3069 3070 /* Set audio parameters */ 3071#if INPUT_SRC_CAPS != 0 3072 audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK); 3073 audio_set_output_source(AUDIO_SRC_PLAYBACK); 3074#endif 3075#ifndef PLATFORM_HAS_VOLUME_CHANGE 3076 sound_set_volume(global_status.volume); 3077#endif 3078 pcmbuf_update_frequency(); 3079 3080 /* Be sure channel is audible */ 3081 pcmbuf_fade(false, true); 3082 3083 /* Update our state */ 3084 play_status = PLAY_PLAYING; 3085 } 3086 3087 /* Codec's position should be available as soon as it knows it */ 3088 position_key = pcmbuf_get_position_key(); 3089 pcmbuf_sync_position_update(); 3090 3091 /* Start fill from beginning of playlist */ 3092 playlist_peek_offset = -1; 3093 buf_set_base_handle(-1); 3094 3095 /* Officially playing */ 3096 queue_reply(&audio_queue, 1); 3097 3098 /* Add these now - finish event for the first id3 will most likely be sent 3099 immediately */ 3100 add_event(BUFFER_EVENT_REBUFFER, buffer_event_rebuffer_callback); 3101 add_event(BUFFER_EVENT_FINISHED, buffer_event_finished_callback); 3102 3103 if (old_status == PLAY_STOPPED) 3104 { 3105 /* Send coldstart event */ 3106 send_event(PLAYBACK_EVENT_START_PLAYBACK, NULL); 3107 } 3108 3109 /* Fill the buffer */ 3110 int trackstat = audio_fill_file_buffer(); 3111 3112 if (trackstat >= LOAD_TRACK_OK) 3113 { 3114 /* This is the currently playing track - get metadata, stat */ 3115 struct track_info info; 3116 track_list_current(0, &info); 3117 playing_id3_sync(&info, &resume, skip_resume_adjustments); 3118 3119 if (valid_mp3entry(id3_get(PLAYING_ID3))) 3120 { 3121 /* Only if actually changing tracks... */ 3122 if (!(flags & AUDIO_START_RESTART)) 3123 audio_playlist_track_change(); 3124 } 3125 } 3126 else 3127 { 3128 /* Found nothing playable */ 3129 audio_handle_track_load_status(trackstat); 3130 } 3131} 3132 3133/* Stop playback and enter an idle state 3134 (usually Q_AUDIO_STOP) */ 3135static void audio_stop_playback(void) 3136{ 3137 logf("%s()", __func__); 3138 3139 if (play_status == PLAY_STOPPED) 3140 return; 3141 3142 bool do_fade = global_settings.fade_on_stop && filling != STATE_ENDED; 3143 3144 pcmbuf_fade(do_fade, false); 3145 3146 /* Wait for fade-out */ 3147 audio_wait_fade_complete(); 3148 3149 /* Stop the codec and unload it */ 3150 halt_decoding_track(true); 3151 pcmbuf_play_stop(); 3152 codec_unload(); 3153 3154 /* Save resume information - "filling" might have been set to 3155 "STATE_ENDED" by caller in order to facilitate end of playlist */ 3156 audio_playlist_track_finish(); 3157 3158 skip_pending = TRACK_SKIP_NONE; 3159 track_event_flags = TEF_NONE; 3160 track_skip_is_manual = false; 3161 3162 /* Close all tracks and mark them NULL */ 3163 remove_event(BUFFER_EVENT_REBUFFER, buffer_event_rebuffer_callback); 3164 remove_event(BUFFER_EVENT_FINISHED, buffer_event_finished_callback); 3165 remove_event_ex(BUFFER_EVENT_BUFFER_LOW, buffer_event_buffer_low_callback, NULL); 3166 3167 track_list_clear(TRACK_LIST_CLEAR_ALL); 3168 3169 /* Update our state */ 3170 ff_rw_mode = false; 3171 play_status = PLAY_STOPPED; 3172 3173 wipe_track_metadata(true); 3174#ifdef HAVE_ALBUMART 3175 clear_last_folder_album_art(); 3176#endif 3177 /* Go idle */ 3178 filling = STATE_IDLE; 3179 cancel_cpu_boost(); 3180 add_playbacklog(NULL); /* flush playback log */ 3181} 3182 3183/* Pause the playback of the current track 3184 (Q_AUDIO_PAUSE) */ 3185static void audio_on_pause(bool pause) 3186{ 3187 logf("%s(%s)", __func__, pause ? "true" : "false"); 3188 3189 if (play_status == PLAY_STOPPED || pause == (play_status == PLAY_PAUSED)) 3190 return; 3191 3192 play_status = pause ? PLAY_PAUSED : PLAY_PLAYING; 3193 3194 if (!pause && codec_skip_pending) 3195 { 3196 /* Actually do the skip that is due - resets the status flag */ 3197 audio_on_codec_complete(codec_skip_status); 3198 } 3199 3200 bool do_fade = global_settings.fade_on_stop; 3201 3202 pcmbuf_fade(do_fade, !pause); 3203 3204 if (!ff_rw_mode && !(do_fade && pause)) 3205 { 3206 /* Not in ff/rw mode - can actually change the audio state now */ 3207 pcmbuf_pause(pause); 3208 } 3209} 3210 3211/* Skip a certain number of tracks forwards or backwards 3212 (Q_AUDIO_SKIP) */ 3213static void audio_on_skip(void) 3214{ 3215 id3_mutex_lock(); 3216 3217 /* Eat the delta to keep it synced, even if not playing */ 3218 int toskip = skip_offset; 3219 skip_offset = 0; 3220 3221 logf("%s(): %d", __func__, toskip); 3222 3223 id3_mutex_unlock(); 3224 3225 if (play_status == PLAY_STOPPED) 3226 return; 3227 3228 /* Force codec to abort this track */ 3229 halt_decoding_track(true); 3230 3231 /* Kill the ff/rw halt */ 3232 ff_rw_mode = false; 3233 3234 /* Manual skip */ 3235 track_event_flags = TEF_NONE; 3236 3237 if (toskip == 1 && global_settings.repeat_mode == REPEAT_ONE) 3238 { 3239 audio_reset_and_rebuffer(TRACK_LIST_KEEP_CURRENT, 1); 3240 } 3241 3242 /* If there was an auto skip in progress, there will be residual 3243 advancement of the playlist and/or track list so compensation will be 3244 required in order to end up in the right spot */ 3245 int track_list_delta = toskip; 3246 int playlist_delta = toskip; 3247 3248 if (skip_pending != TRACK_SKIP_NONE) 3249 { 3250 if (skip_pending != TRACK_SKIP_AUTO_END_PLAYLIST) 3251 track_list_delta--; 3252 3253 if (skip_pending == TRACK_SKIP_AUTO_NEW_PLAYLIST) 3254 playlist_delta--; 3255 } 3256 3257 audio_playlist_track_finish(); 3258 skip_pending = TRACK_SKIP_NONE; 3259 3260 /* Update the playlist current track now */ 3261 int pl_retval; 3262 while ((pl_retval = playlist_next(playlist_delta)) < 0) 3263 { 3264 if (pl_retval < -1) 3265 { 3266 /* Some variety of fatal error while updating playlist */ 3267 filling = STATE_ENDED; 3268 audio_stop_playback(); 3269 return; 3270 } 3271 3272 /* Manual skip out of range (because the playlist wasn't updated 3273 yet by us and so the check in audio_skip returned 'ok') - bring 3274 back into range */ 3275 int d = toskip < 0 ? 1 : -1; 3276 3277 while (!playlist_check(playlist_delta)) 3278 { 3279 if (playlist_delta == d) 3280 { 3281 /* Had to move the opposite direction to correct, which is 3282 wrong - this is the end */ 3283 filling = STATE_ENDED; 3284 audio_stop_playback(); 3285 return; 3286 } 3287 3288 playlist_delta += d; 3289 track_list_delta += d; 3290 } 3291 } 3292 track_skip_is_manual = false; 3293 /* Adjust things by how much the playlist was manually moved */ 3294 playlist_peek_offset -= playlist_delta; 3295 3296 int trackstat = LOAD_TRACK_OK; 3297 3298 struct track_info info; 3299 if (!track_list_advance_current(track_list_delta, &info) 3300 || info.audio_hid < 0) 3301 { 3302 /* We don't know the next track thus we know we don't have it */ 3303 trackstat = audio_reset_and_rebuffer(TRACK_LIST_CLEAR_ALL, -1); 3304 } 3305 3306 audio_begin_track_change(TRACK_CHANGE_MANUAL, trackstat); 3307} 3308 3309/* Skip to the next/previous directory 3310 (Q_AUDIO_DIR_SKIP) */ 3311static void audio_on_dir_skip(int direction) 3312{ 3313 logf("%s(%d)", __func__, direction); 3314 3315 id3_mutex_lock(); 3316 skip_offset = 0; 3317 id3_mutex_unlock(); 3318 3319 if (play_status == PLAY_STOPPED) 3320 return; 3321 3322 /* Force codec to abort this track */ 3323 halt_decoding_track(true); 3324 3325 /* Kill the ff/rw halt */ 3326 ff_rw_mode = false; 3327 3328 /* Manual skip */ 3329 track_event_flags = TEF_NONE; 3330 3331 audio_playlist_track_finish(); 3332 3333 /* Unless automatic and gapless, skips do not pend */ 3334 skip_pending = TRACK_SKIP_NONE; 3335 3336 /* Regardless of the return value we need to rebuffer. If it fails the old 3337 playlist will resume, else the next dir will start playing. */ 3338 playlist_next_dir(direction); 3339 3340 wipe_track_metadata(false); 3341 3342 int trackstat = audio_reset_and_rebuffer(TRACK_LIST_CLEAR_ALL, -1); 3343 3344 if (trackstat == LOAD_TRACK_ERR_NO_MORE) 3345 { 3346 /* The day the music died - finish-off whatever is playing and call it 3347 quits */ 3348 audio_monitor_end_of_playlist(); 3349 return; 3350 } 3351 3352 audio_begin_track_change(TRACK_CHANGE_MANUAL, trackstat); 3353} 3354 3355/* Enter seek mode in order to start a seek 3356 (Q_AUDIO_PRE_FF_REWIND) */ 3357static void audio_on_pre_ff_rewind(void) 3358{ 3359 logf("%s()", __func__); 3360 3361 if (play_status == PLAY_STOPPED || ff_rw_mode) 3362 return; 3363 3364 ff_rw_mode = true; 3365 3366 audio_wait_fade_complete(); 3367 3368 if (play_status == PLAY_PAUSED) 3369 return; 3370 3371 pcmbuf_pause(true); 3372} 3373 3374/* Seek the playback of the current track to the specified time 3375 (Q_AUDIO_FF_REWIND) */ 3376static void audio_on_ff_rewind(long time) 3377{ 3378 logf("%s(%ld)", __func__, time); 3379 3380 if (play_status == PLAY_STOPPED) 3381 return; 3382 3383 enum track_skip_type pending = skip_pending; 3384 3385 switch (pending) 3386 { 3387 case TRACK_SKIP_NONE: /* The usual case */ 3388 case TRACK_SKIP_AUTO: /* Have to back it out (fun!) */ 3389 case TRACK_SKIP_AUTO_END_PLAYLIST: /* Still have the last codec used */ 3390 { 3391 struct mp3entry *id3 = id3_get(PLAYING_ID3); 3392 struct mp3entry *ci_id3 = id3_get(CODEC_ID3); 3393 3394 track_event_flags = TEF_NONE; 3395 3396 if (time < 0) 3397 { 3398 time = id3->length + time; 3399 if (time < 0) 3400 time = 0; 3401 } 3402 /* Send event before clobbering the time if rewinding. */ 3403 if (time == 0) 3404 { 3405 send_track_event(PLAYBACK_EVENT_TRACK_FINISH, 3406 track_event_flags | TEF_REWIND, id3); 3407 } 3408 3409 id3->elapsed = time; 3410 queue_reply(&audio_queue, 1); 3411 3412 bool haltres = halt_decoding_track(pending == TRACK_SKIP_AUTO); 3413 3414 /* Need this set in case ff/rw mode + error but _after_ the codec 3415 halt that will reset it */ 3416 codec_seeking = true; 3417 3418 /* If in transition, key will have changed - sync to it */ 3419 position_key = pcmbuf_get_position_key(); 3420 3421 if (pending == TRACK_SKIP_AUTO && !track_list_advance_current(-1, NULL)) 3422 { 3423 /* Not in list - must rebuffer at the current playlist index */ 3424 if (audio_reset_and_rebuffer(TRACK_LIST_CLEAR_ALL, -1) 3425 < LOAD_TRACK_OK) 3426 { 3427 /* Codec is stopped */ 3428 break; 3429 } 3430 } 3431 3432 /* Set after audio_fill_file_buffer to disable playing id3 clobber if 3433 rebuffer is needed */ 3434 skip_pending = TRACK_SKIP_NONE; 3435 3436 struct track_info cur_info; 3437 track_list_current(0, &cur_info); 3438 3439 bool finish_load = cur_info.audio_hid < 0; 3440 if (finish_load) 3441 { 3442 // track is not yet loaded so simply update resume details for upcoming finish_load_track and quit 3443 playing_id3_sync(&cur_info, &(struct audio_resume_info){ time, 0 }, true); 3444 return; 3445 } 3446 3447 if (pending == TRACK_SKIP_AUTO) 3448 { 3449 if (!bufreadid3(cur_info.id3_hid, ci_id3) || 3450 !audio_init_codec(&cur_info, ci_id3)) 3451 { 3452 /* We should have still been able to get it - skip it and move 3453 onto the next one - like it or not this track is broken */ 3454 break; 3455 } 3456 3457 /* Set the codec API to the correct metadata and track info */ 3458 ci.audio_hid = cur_info.audio_hid; 3459 ci.filesize = buf_filesize(cur_info.audio_hid); 3460 buf_set_base_handle(cur_info.audio_hid); 3461 } 3462 3463 if (!haltres) 3464 { 3465 /* If codec must be (re)started, reset the resume info so that 3466 it doesn't execute resume procedures */ 3467 ci_id3->elapsed = 0; 3468 ci_id3->offset = 0; 3469 } 3470 3471 codec_seek(time); 3472 return; 3473 } 3474 3475 case TRACK_SKIP_AUTO_NEW_PLAYLIST: 3476 { 3477 /* We cannot do this because the playlist must be reversed by one 3478 and it doesn't always return the same song when going backwards 3479 across boundaries as forwards (either because of randomization 3480 or inconsistency in deciding what the previous track should be), 3481 therefore the whole operation would often end up as nonsense - 3482 lock out seeking for a couple seconds */ 3483 3484 /* Sure as heck cancel seek mode too! */ 3485 audio_ff_rewind_end(); 3486 return; 3487 } 3488 3489 default: 3490 /* Won't see this */ 3491 return; 3492 } 3493 3494 if (play_status == PLAY_STOPPED) 3495 { 3496 /* Playback ended because of an error completing a track load */ 3497 return; 3498 } 3499 3500 /* Always fake it as a codec start error which will handle mode 3501 cancellations and skip to the next track */ 3502 audio_handle_track_load_status(LOAD_TRACK_ERR_START_CODEC); 3503} 3504 3505/* Invalidates all but currently playing track 3506 (Q_AUDIO_FLUSH) */ 3507static void audio_on_audio_flush(void) 3508{ 3509 logf("%s", __func__); 3510 3511 if (track_list_empty()) 3512 return; /* Nothing to flush out */ 3513 3514 switch (skip_pending) 3515 { 3516 case TRACK_SKIP_NONE: 3517 case TRACK_SKIP_AUTO_END_PLAYLIST: 3518 /* Remove all but the currently playing track from the list and 3519 refill after that */ 3520 track_list_clear(TRACK_LIST_KEEP_CURRENT); 3521 playlist_peek_offset = 0; 3522 id3_write_locked(UNBUFFERED_ID3, NULL); 3523 audio_update_and_announce_next_track(NULL); 3524 3525 /* Ignore return since it's about the next track, not this one */ 3526 audio_fill_file_buffer(); 3527 3528 if (skip_pending == TRACK_SKIP_NONE) 3529 break; 3530 3531 /* There's now a track after this one now - convert to auto skip - 3532 no skip should pend right now because multiple flush messages can 3533 be fired which would cause a restart in the below cases */ 3534 skip_pending = TRACK_SKIP_NONE; 3535 audio_clear_track_notifications(); 3536 audio_queue_post(Q_AUDIO_CODEC_COMPLETE, CODEC_OK); 3537 break; 3538 3539 case TRACK_SKIP_AUTO: 3540 case TRACK_SKIP_AUTO_NEW_PLAYLIST: 3541 /* Precisely removing what it already decoded for the next track is 3542 not possible so a restart is required in order to continue the 3543 currently playing track without the now invalid future track 3544 playing */ 3545 audio_start_playback(NULL, AUDIO_START_RESTART); 3546 break; 3547 3548 default: /* Nothing else is a state */ 3549 break; 3550 } 3551} 3552 3553/* Called by audio thread when playback is started */ 3554void audio_playback_handler(struct queue_event *ev) 3555{ 3556 while (1) 3557 { 3558 switch (ev->id) 3559 { 3560 /** Codec and track change messages **/ 3561 case Q_AUDIO_CODEC_COMPLETE: 3562 /* Codec is done processing track and has gone idle */ 3563 LOGFQUEUE("playback < Q_AUDIO_CODEC_COMPLETE: %ld", 3564 (long)ev->data); 3565 audio_on_codec_complete(ev->data); 3566 break; 3567 3568 case Q_AUDIO_CODEC_SEEK_COMPLETE: 3569 /* Codec is done seeking */ 3570 LOGFQUEUE("playback < Q_AUDIO_SEEK_COMPLETE"); 3571 audio_on_codec_seek_complete(); 3572 break; 3573 3574 case Q_AUDIO_TRACK_CHANGED: 3575 /* PCM track change done */ 3576 LOGFQUEUE("playback < Q_AUDIO_TRACK_CHANGED"); 3577 audio_on_track_changed(); 3578 break; 3579 3580 /** Control messages **/ 3581 case Q_AUDIO_PLAY: 3582 LOGFQUEUE("playback < Q_AUDIO_PLAY"); 3583 audio_start_playback((struct audio_resume_info *)ev->data, 0); 3584 break; 3585 3586#ifdef HAVE_RECORDING 3587 /* So we can go straight from playback to recording */ 3588 case Q_AUDIO_INIT_RECORDING: 3589#endif 3590 case SYS_USB_CONNECTED: 3591 case Q_AUDIO_STOP: 3592 LOGFQUEUE("playback < Q_AUDIO_STOP"); 3593 audio_stop_playback(); 3594 if (ev->data != 0) 3595 queue_clear(&audio_queue); 3596 return; /* no more playback */ 3597 3598 case Q_AUDIO_PAUSE: 3599 LOGFQUEUE("playback < Q_AUDIO_PAUSE"); 3600 audio_on_pause(ev->data); 3601 break; 3602 3603 case Q_AUDIO_SKIP: 3604 LOGFQUEUE("playback < Q_AUDIO_SKIP"); 3605 audio_on_skip(); 3606 break; 3607 3608 case Q_AUDIO_DIR_SKIP: 3609 LOGFQUEUE("playback < Q_AUDIO_DIR_SKIP"); 3610 audio_on_dir_skip(ev->data); 3611 break; 3612 3613 case Q_AUDIO_PRE_FF_REWIND: 3614 LOGFQUEUE("playback < Q_AUDIO_PRE_FF_REWIND"); 3615 audio_on_pre_ff_rewind(); 3616 break; 3617 3618 case Q_AUDIO_FF_REWIND: 3619 LOGFQUEUE("playback < Q_AUDIO_FF_REWIND"); 3620 audio_on_ff_rewind(ev->data); 3621 break; 3622 3623 case Q_AUDIO_FLUSH: 3624 LOGFQUEUE("playback < Q_AUDIO_FLUSH: %d", (int)ev->data); 3625 audio_on_audio_flush(); 3626 break; 3627 3628 /** Buffering messages **/ 3629 case Q_AUDIO_BUFFERING: 3630 /* some buffering event */ 3631 LOGFQUEUE("playback < Q_AUDIO_BUFFERING: %d", (int)ev->data); 3632 audio_on_buffering(ev->data); 3633 break; 3634 3635 case Q_AUDIO_FILL_BUFFER: 3636 /* continue buffering next track */ 3637 LOGFQUEUE("playback < Q_AUDIO_FILL_BUFFER"); 3638 audio_on_fill_buffer(); 3639 break; 3640 3641 case Q_AUDIO_FINISH_LOAD_TRACK: 3642 /* metadata is buffered */ 3643 LOGFQUEUE("playback < Q_AUDIO_FINISH_LOAD_TRACK"); 3644 audio_on_finish_load_track(ev->data); 3645 break; 3646 3647 case Q_AUDIO_HANDLE_FINISHED: 3648 /* some other type is buffered */ 3649 LOGFQUEUE("playback < Q_AUDIO_HANDLE_FINISHED"); 3650 audio_on_handle_finished(ev->data); 3651 break; 3652 3653 /** Miscellaneous messages **/ 3654 case Q_AUDIO_REMAKE_AUDIO_BUFFER: 3655 /* buffer needs to be reinitialized */ 3656 LOGFQUEUE("playback < Q_AUDIO_REMAKE_AUDIO_BUFFER"); 3657 audio_start_playback(NULL, AUDIO_START_RESTART | AUDIO_START_NEWBUF); 3658 if (play_status == PLAY_STOPPED) 3659 return; /* just need to change buffer state */ 3660 break; 3661 3662#ifdef HAVE_DISK_STORAGE 3663 case Q_AUDIO_UPDATE_WATERMARK: 3664 /* buffering watermark needs updating */ 3665 LOGFQUEUE("playback < Q_AUDIO_UPDATE_WATERMARK: %d", 3666 (int)ev->data); 3667 audio_update_filebuf_watermark(ev->data); 3668 if (play_status == PLAY_STOPPED) 3669 return; /* just need to update setting */ 3670 break; 3671#endif /* HAVE_DISK_STORAGE */ 3672 3673 case SYS_TIMEOUT: 3674 LOGFQUEUE_SYS_TIMEOUT("playback < SYS_TIMEOUT"); 3675 break; 3676 3677 default: 3678 /* LOGFQUEUE("audio < default : %08lX", ev->id); */ 3679 break; 3680 } /* end switch */ 3681 3682 switch (filling) 3683 { 3684 /* Active states */ 3685 case STATE_FULL: 3686 case STATE_END_OF_PLAYLIST: 3687 if (buf_get_watermark() == 0) 3688 { 3689 /* End of buffering for now, let's calculate the watermark, 3690 register for a low buffer event and unboost */ 3691 audio_update_filebuf_watermark(0); 3692 add_event_ex(BUFFER_EVENT_BUFFER_LOW, true, 3693 buffer_event_buffer_low_callback, NULL); 3694 } 3695 /* Fall-through */ 3696 case STATE_FINISHED: 3697 case STATE_STOPPED: 3698 /* All data was buffered */ 3699 cancel_cpu_boost(); 3700 /* Fall-through */ 3701 case STATE_FILLING: 3702 case STATE_ENDING: 3703 if (audio_pcmbuf_track_change_scan()) 3704 { 3705 /* Transfer notification to audio queue event */ 3706 ev->id = Q_AUDIO_TRACK_CHANGED; 3707 ev->data = 1; 3708 } 3709 else 3710 { 3711 /* If doing auto skip, poll pcmbuf track notifications a bit 3712 faster to promply detect the transition */ 3713 queue_wait_w_tmo(&audio_queue, ev, 3714 skip_pending == TRACK_SKIP_NONE ? HZ/2 : HZ/10); 3715 } 3716 break; 3717 3718 /* Idle states */ 3719 default: 3720 queue_wait(&audio_queue, ev); 3721 } 3722 } /* end while */ 3723} 3724 3725 3726/* --- Buffering callbacks --- */ 3727 3728/* Called when fullness is below the watermark level */ 3729static void buffer_event_buffer_low_callback(unsigned short id, void *ev_data, void *user_data) 3730{ 3731 logf("low buffer callback"); 3732 LOGFQUEUE("buffering > audio Q_AUDIO_BUFFERING: buffer low"); 3733 audio_queue_post(Q_AUDIO_BUFFERING, BUFFER_EVENT_BUFFER_LOW); 3734 (void)id; 3735 (void)ev_data; 3736 (void)user_data; 3737} 3738 3739/* Called when handles must be discarded in order to buffer new data */ 3740static void buffer_event_rebuffer_callback(unsigned short id, void *ev_data) 3741{ 3742 logf("rebuffer callback"); 3743 LOGFQUEUE("buffering > audio Q_AUDIO_BUFFERING: rebuffer"); 3744 audio_queue_post(Q_AUDIO_BUFFERING, BUFFER_EVENT_REBUFFER); 3745 (void)id; 3746 (void)ev_data; 3747} 3748 3749/* A handle has completed buffering and all required data is available */ 3750static void buffer_event_finished_callback(unsigned short id, void *ev_data) 3751{ 3752 (void)id; 3753 int hid = *(const int *)ev_data; 3754 int htype = buf_handle_data_type(hid); 3755 3756 logf("handle %d finished buffering (type:%d)", hid, htype); 3757 3758 /* Limit queue traffic */ 3759 switch (htype) 3760 { 3761 case TYPE_ID3: 3762 /* The metadata handle for the last loaded track has been buffered. 3763 We can ask the audio thread to load the rest of the track's data. */ 3764 LOGFQUEUE("buffering > audio Q_AUDIO_FINISH_LOAD_TRACK: %d", hid); 3765 audio_queue_post(Q_AUDIO_FINISH_LOAD_TRACK, hid); 3766 break; 3767 3768 case TYPE_PACKET_AUDIO: 3769 case TYPE_ATOMIC_AUDIO: 3770 LOGFQUEUE("buffering > audio Q_AUDIO_HANDLE_FINISHED: %d", hid); 3771 audio_queue_post(Q_AUDIO_HANDLE_FINISHED, hid); 3772 break; 3773 3774 default: 3775 /* Don't care to know about these */ 3776 break; 3777 } 3778} 3779 3780 3781/** -- Codec callbacks -- **/ 3782 3783/* Update elapsed time for next PCM insert */ 3784void audio_codec_update_elapsed(unsigned long elapsed) 3785{ 3786 ab_position_report(elapsed); 3787 3788 /* Save in codec's id3 where it is used at next pcm insert */ 3789 id3_get(CODEC_ID3)->elapsed = elapsed; 3790} 3791 3792/* Update offset for next PCM insert */ 3793void audio_codec_update_offset(size_t offset) 3794{ 3795 /* Save in codec's id3 where it is used at next pcm insert */ 3796 id3_get(CODEC_ID3)->offset = offset; 3797} 3798 3799/* Codec has finished running */ 3800void audio_codec_complete(int status) 3801{ 3802#ifdef AB_REPEAT_ENABLE 3803 if (status >= CODEC_OK) 3804 { 3805 /* Normal automatic skip */ 3806 ab_end_of_track_report(); 3807 } 3808#endif 3809 3810 LOGFQUEUE("codec > audio Q_AUDIO_CODEC_COMPLETE: %d", status); 3811 audio_queue_post(Q_AUDIO_CODEC_COMPLETE, status); 3812} 3813 3814/* Codec has finished seeking */ 3815void audio_codec_seek_complete(void) 3816{ 3817 LOGFQUEUE("codec > audio Q_AUDIO_CODEC_SEEK_COMPLETE"); 3818 audio_queue_post(Q_AUDIO_CODEC_SEEK_COMPLETE, 0); 3819} 3820 3821 3822/** --- Pcmbuf callbacks --- **/ 3823 3824/* Update the elapsed and offset from the information cached during the 3825 PCM buffer insert */ 3826void audio_pcmbuf_position_callback(unsigned long elapsed, off_t offset, 3827 unsigned int key) 3828{ 3829 if (key == position_key) 3830 { 3831 struct mp3entry *id3 = id3_get(PLAYING_ID3); 3832 id3->elapsed = elapsed; 3833 id3->offset = offset; 3834 } 3835} 3836 3837/* Synchronize position info to the codec's */ 3838void audio_pcmbuf_sync_position(void) 3839{ 3840 audio_pcmbuf_position_callback(ci.id3->elapsed, ci.id3->offset, 3841 pcmbuf_get_position_key()); 3842} 3843 3844/* Post message from pcmbuf that the end of the previous track has just 3845 * been played */ 3846void audio_pcmbuf_track_change(bool pcmbuf) 3847{ 3848 if (pcmbuf) 3849 { 3850 /* Notify of the change in special-purpose semaphore object */ 3851 LOGFQUEUE("pcmbuf > pcmbuf Q_AUDIO_TRACK_CHANGED"); 3852 audio_pcmbuf_track_change_post(); 3853 } 3854 else 3855 { 3856 /* Safe to post directly to the queue */ 3857 LOGFQUEUE("pcmbuf > audio Q_AUDIO_TRACK_CHANGED"); 3858 audio_queue_post(Q_AUDIO_TRACK_CHANGED, 0); 3859 } 3860} 3861 3862/* May pcmbuf start PCM playback when the buffer is full enough? */ 3863bool audio_pcmbuf_may_play(void) 3864{ 3865 return play_status == PLAY_PLAYING && !ff_rw_mode; 3866} 3867 3868 3869/** -- External interfaces -- **/ 3870 3871/* Get a copy of the id3 data for the for current track + offset + skip delta */ 3872bool audio_peek_track(struct mp3entry *id3, int offset) 3873{ 3874 bool retval = false; 3875 3876 id3_mutex_lock(); 3877 3878 if (play_status != PLAY_STOPPED) 3879 { 3880 id3->path[0] = '\0'; /* Null path means it should be filled now */ 3881 retval = audio_get_track_metadata(offset + skip_offset, id3) && 3882 id3->path[0] != '\0'; 3883 } 3884 3885 id3_mutex_unlock(); 3886 3887 return retval; 3888} 3889 3890/* Return the mp3entry for the currently playing track */ 3891struct mp3entry * audio_current_track(void) 3892{ 3893 struct mp3entry *id3; 3894 3895 id3_mutex_lock(); 3896 3897#ifdef AUDIO_FAST_SKIP_PREVIEW 3898 if (skip_offset != 0) 3899 { 3900 /* This is a peekahead */ 3901 id3 = id3_get(PLAYING_PEEK_ID3); 3902 audio_peek_track(id3, 0); 3903 } 3904 else 3905#endif 3906 { 3907 /* Normal case */ 3908 id3 = id3_get(PLAYING_ID3); 3909 audio_get_track_metadata(0, id3); 3910 } 3911 3912 id3_mutex_unlock(); 3913 3914 return id3; 3915} 3916 3917/* Obtains the mp3entry for the next track from the current */ 3918struct mp3entry * audio_next_track(void) 3919{ 3920 struct mp3entry *id3 = id3_get(NEXTTRACK_ID3); 3921 3922 id3_mutex_lock(); 3923 3924#ifdef AUDIO_FAST_SKIP_PREVIEW 3925 if (skip_offset != 0) 3926 { 3927 /* This is a peekahead */ 3928 if (!audio_peek_track(id3, 1)) 3929 id3 = NULL; 3930 } 3931 else 3932#endif 3933 { 3934 /* Normal case */ 3935 if (!audio_get_track_metadata(1, id3)) 3936 id3 = NULL; 3937 } 3938 3939 id3_mutex_unlock(); 3940 3941 return id3; 3942} 3943 3944/* Start playback at the specified elapsed time or offset */ 3945void audio_play(unsigned long elapsed, unsigned long offset) 3946{ 3947 logf("audio_play"); 3948 3949#ifdef PLAYBACK_VOICE 3950 /* Truncate any existing voice output so we don't have spelling 3951 * etc. over the first part of the played track */ 3952 talk_force_shutup(); 3953#endif 3954 3955 LOGFQUEUE("audio >| audio Q_AUDIO_PLAY: %lu %lX", elapsed, offset); 3956 audio_queue_send(Q_AUDIO_PLAY, 3957 (intptr_t)&(struct audio_resume_info){ elapsed, offset }); 3958} 3959 3960/* Stop playback if playing */ 3961void audio_stop(void) 3962{ 3963 LOGFQUEUE("audio >| audio Q_AUDIO_STOP"); 3964 audio_queue_send(Q_AUDIO_STOP, 0); 3965} 3966 3967/* Pause playback if playing */ 3968void audio_pause(void) 3969{ 3970 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE"); 3971 audio_queue_send(Q_AUDIO_PAUSE, true); 3972} 3973 3974/* This sends a stop message and the audio thread will dump all its 3975 subsequent messages */ 3976void audio_hard_stop(void) 3977{ 3978 /* Stop playback */ 3979 LOGFQUEUE("audio >| audio Q_AUDIO_STOP: 1"); 3980 audio_queue_send(Q_AUDIO_STOP, 1); 3981#ifdef PLAYBACK_VOICE 3982 voice_stop(); 3983#endif 3984 audiobuf_handle = core_free(audiobuf_handle); 3985} 3986 3987/* Resume playback if paused */ 3988void audio_resume(void) 3989{ 3990 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE resume"); 3991 audio_queue_send(Q_AUDIO_PAUSE, false); 3992} 3993 3994/* Internal function used by REPEAT_ONE extern playlist.c */ 3995bool audio_pending_track_skip_is_manual(void) 3996{ 3997 logf("Track change is: %s", track_skip_is_manual ? "Manual": "Auto"); 3998 return track_skip_is_manual; 3999} 4000 4001/* Skip the specified number of tracks forward or backward from the current */ 4002void audio_skip(int offset) 4003{ 4004 id3_mutex_lock(); 4005 4006 /* If offset has to be backed-out to stay in range, no skip is done */ 4007 int accum = skip_offset + offset; 4008 4009 while (offset != 0 && !playlist_check(accum)) 4010 { 4011 offset += offset < 0 ? 1 : -1; 4012 accum = skip_offset + offset; 4013 } 4014 4015 if (offset != 0) 4016 { 4017 /* Accumulate net manual skip count since the audio thread last 4018 processed one */ 4019 skip_offset = accum; 4020 4021 system_sound_play(SOUND_TRACK_SKIP); 4022 4023 LOGFQUEUE("audio > audio Q_AUDIO_SKIP %d", offset); 4024 4025#ifdef AUDIO_FAST_SKIP_PREVIEW 4026 /* Do this before posting so that the audio thread can correct us 4027 when things settle down - additionally, if audio gets a message 4028 and the delta is zero, the Q_AUDIO_SKIP handler (audio_on_skip) 4029 handler a skip event with the correct info but doesn't skip */ 4030 send_event(PLAYBACK_EVENT_TRACK_SKIP, NULL); 4031#endif /* AUDIO_FAST_SKIP_PREVIEW */ 4032 4033 /* Playback only needs the final state even if more than one is 4034 processed because it wasn't removed in time */ 4035 queue_remove_from_head(&audio_queue, Q_AUDIO_SKIP); 4036 audio_queue_post(Q_AUDIO_SKIP, 0); 4037 } 4038 else 4039 { 4040 /* No more tracks */ 4041 system_sound_play(SOUND_TRACK_NO_MORE); 4042 } 4043 4044 id3_mutex_unlock(); 4045} 4046 4047/* Skip one track forward from the current */ 4048void audio_next(void) 4049{ 4050 audio_skip(1); 4051} 4052 4053/* Skip one track backward from the current */ 4054void audio_prev(void) 4055{ 4056 audio_skip(-1); 4057} 4058 4059/* Move one directory forward */ 4060void audio_next_dir(void) 4061{ 4062 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP 1"); 4063 audio_queue_post(Q_AUDIO_DIR_SKIP, 1); 4064} 4065 4066/* Move one directory backward */ 4067void audio_prev_dir(void) 4068{ 4069 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP -1"); 4070 audio_queue_post(Q_AUDIO_DIR_SKIP, -1); 4071} 4072 4073/* Pause playback in order to start a seek that flushes the old audio */ 4074void audio_pre_ff_rewind(void) 4075{ 4076 LOGFQUEUE("audio > audio Q_AUDIO_PRE_FF_REWIND"); 4077 audio_queue_post(Q_AUDIO_PRE_FF_REWIND, 0); 4078} 4079 4080/* Seek to the new time in the current track */ 4081void audio_ff_rewind(long time) 4082{ 4083 LOGFQUEUE("audio > audio Q_AUDIO_FF_REWIND"); 4084 audio_queue_post(Q_AUDIO_FF_REWIND, time); 4085} 4086 4087/* Clear all but the currently playing track then rebuffer */ 4088void audio_flush_and_reload_tracks(void) 4089{ 4090 LOGFQUEUE("audio > audio Q_AUDIO_FLUSH"); 4091 audio_queue_post(Q_AUDIO_FLUSH, 0); 4092} 4093 4094/** --- Miscellaneous public interfaces --- **/ 4095 4096#ifdef HAVE_ALBUMART 4097/* Return which album art handle is current for the user in the given slot */ 4098int playback_current_aa_hid(int slot) 4099{ 4100 if ((unsigned)slot < MAX_MULTIPLE_AA) 4101 { 4102 struct track_info user_cur; 4103 bool have_info = track_list_user_current(skip_offset, &user_cur); 4104 4105 if (!have_info && abs(skip_offset) <= 1) 4106 { 4107 /* Give the actual position a go */ 4108 have_info = track_list_user_current(0, &user_cur); 4109 } 4110 4111 if (have_info) 4112 return user_cur.aa_hid[slot]; 4113 } 4114 4115 return ERR_HANDLE_NOT_FOUND; 4116} 4117 4118/* Find an album art slot that doesn't match the dimensions of another that 4119 is already claimed - increment the use count if it is */ 4120int playback_claim_aa_slot(struct dim *dim) 4121{ 4122 /* First try to find a slot already having the size to reuse it since we 4123 don't want albumart of the same size buffered multiple times */ 4124 FOREACH_ALBUMART(i) 4125 { 4126 struct albumart_slot *slot = &albumart_slots[i]; 4127 4128 if (slot->dim.width == dim->width && 4129 slot->dim.height == dim->height) 4130 { 4131 slot->used++; 4132 return i; 4133 } 4134 } 4135 4136 /* Size is new, find a free slot */ 4137 FOREACH_ALBUMART(i) 4138 { 4139 if (!albumart_slots[i].used) 4140 { 4141 albumart_slots[i].used++; 4142 albumart_slots[i].dim = *dim; 4143 return i; 4144 } 4145 } 4146 4147 /* Sorry, no free slot */ 4148 return -1; 4149} 4150 4151/* Invalidate the albumart_slot - decrement the use count if > 0 */ 4152void playback_release_aa_slot(int slot) 4153{ 4154 if ((unsigned)slot < MAX_MULTIPLE_AA) 4155 { 4156 struct albumart_slot *aa_slot = &albumart_slots[slot]; 4157 4158 if (aa_slot->used > 0) 4159 aa_slot->used--; 4160 } 4161} 4162 4163void playback_update_aa_dims(void) 4164{ 4165 LOGFQUEUE("audio >| audio Q_AUDIO_REMAKE_AUDIO_BUFFER"); 4166 audio_queue_send(Q_AUDIO_REMAKE_AUDIO_BUFFER, 0); 4167} 4168#endif /* HAVE_ALBUMART */ 4169 4170/* Return file byte offset */ 4171int audio_get_file_pos(void) 4172{ 4173 return id3_get(PLAYING_ID3)->offset; 4174} 4175 4176/* Return total file buffer length after accounting for the talk buf */ 4177size_t audio_get_filebuflen(void) 4178{ 4179 return buf_length(); 4180} 4181 4182/* How many tracks exist on the buffer - full or partial */ 4183unsigned int audio_track_count(void) 4184#ifndef __APPLE__ 4185 __attribute__((alias("track_list_count"))); 4186#else 4187{ 4188 return track_list_count(); 4189} 4190#endif 4191 4192/* Return total ringbuffer space occupied - ridx to widx */ 4193long audio_filebufused(void) 4194{ 4195 return buf_used(); 4196} 4197 4198 4199/** -- Settings -- **/ 4200 4201/* Enable or disable cuesheet support and allocate/don't allocate the 4202 extra associated resources */ 4203void audio_set_cuesheet(bool enable) 4204{ 4205 if (play_status == PLAY_STOPPED || !enable != !get_current_cuesheet()) 4206 { 4207 LOGFQUEUE("audio >| audio Q_AUDIO_REMAKE_AUDIO_BUFFER"); 4208 audio_queue_send(Q_AUDIO_REMAKE_AUDIO_BUFFER, 0); 4209 } 4210} 4211 4212#ifdef HAVE_DISK_STORAGE 4213/* Set the audio antiskip buffer margin in SECONDS */ 4214void audio_set_buffer_margin(int seconds) 4215{ 4216 logf("buffer margin: %u", (unsigned) seconds); 4217 LOGFQUEUE("audio > audio Q_AUDIO_UPDATE_WATERMARK: %u",(unsigned) seconds); 4218 audio_queue_post(Q_AUDIO_UPDATE_WATERMARK, (unsigned) seconds); /*SECONDS*/ 4219} 4220#endif /* HAVE_DISK_STORAGE */ 4221 4222#ifdef HAVE_CROSSFADE 4223/* Take necessary steps to enable or disable the crossfade setting */ 4224void audio_set_crossfade(int enable) 4225{ 4226 /* Tell it the next setting to use */ 4227 pcmbuf_request_crossfade_enable(enable); 4228 4229 /* Return if size hasn't changed or this is too early to determine 4230 which in the second case there's no way we could be playing 4231 anything at all */ 4232 if (!pcmbuf_is_same_size()) 4233 { 4234 LOGFQUEUE("audio >| audio Q_AUDIO_REMAKE_AUDIO_BUFFER"); 4235 audio_queue_send(Q_AUDIO_REMAKE_AUDIO_BUFFER, 0); 4236 } 4237} 4238#endif /* HAVE_CROSSFADE */ 4239 4240#ifdef HAVE_PLAY_FREQ 4241static unsigned long audio_guess_frequency(struct mp3entry *id3) 4242{ 4243 switch (id3->frequency) 4244 { 4245#if HAVE_PLAY_FREQ >= 48 4246 case 44100: 4247 return SAMPR_44; 4248 case 48000: 4249 return SAMPR_48; 4250#endif 4251#if HAVE_PLAY_FREQ >= 96 4252 case 88200: 4253 return SAMPR_88; 4254 case 96000: 4255 return SAMPR_96; 4256#endif 4257#if HAVE_PLAY_FREQ >= 192 4258 case 176400: 4259 return SAMPR_176; 4260 case 192000: 4261 return SAMPR_192; 4262#endif 4263 default: 4264 return (id3->frequency % 4000) ? SAMPR_44 : SAMPR_48; 4265 } 4266} 4267 4268static bool audio_auto_change_frequency(struct mp3entry *id3, bool play) 4269{ 4270 if (!valid_mp3entry(id3)) 4271 return false; 4272 unsigned long guessed_frequency = global_settings.play_frequency == 0 ? audio_guess_frequency(id3) : 0; 4273 if (guessed_frequency && mixer_get_frequency() != guessed_frequency) 4274 { 4275 if (!play) 4276 return true; 4277 4278#ifdef PLAYBACK_VOICE 4279 voice_stop(); 4280#endif 4281 mixer_set_frequency(guessed_frequency); 4282 audio_queue_post(Q_AUDIO_REMAKE_AUDIO_BUFFER, 0); 4283 return true; 4284 } 4285 return false; 4286} 4287 4288void audio_set_playback_frequency(unsigned int sample_rate_hz) 4289{ 4290 /* sample_rate_hz == 0 is "automatic", and also a sentinel */ 4291#if HAVE_PLAY_FREQ >= 192 4292 static const unsigned int play_sampr[] = {SAMPR_44, SAMPR_48, SAMPR_88, SAMPR_96, SAMPR_176, SAMPR_192, 0 }; 4293#elif HAVE_PLAY_FREQ >= 96 4294 static const unsigned int play_sampr[] = {SAMPR_44, SAMPR_48, SAMPR_88, SAMPR_96, 0 }; 4295#elif HAVE_PLAY_FREQ >= 48 4296 static const unsigned int play_sampr[] = {SAMPR_44, SAMPR_48, 0 }; 4297#else 4298 #error "HAVE_PLAY_FREQ < 48 ??" 4299#endif 4300 const unsigned int *p_sampr = play_sampr; 4301 unsigned int sampr = 0; 4302 4303 while (*p_sampr != 0) 4304 { 4305 if (*p_sampr == sample_rate_hz) 4306 { 4307 sampr = *p_sampr; 4308 break; 4309 } 4310 p_sampr++; 4311 } 4312 4313 if (sampr == 0) 4314 { 4315 if (audio_status() & (AUDIO_STATUS_PLAY | AUDIO_STATUS_PAUSE)) 4316 { 4317 sampr = audio_guess_frequency(audio_current_track()); 4318 } 4319 else 4320 { 4321 logf("could not set sample rate to %u hz", sample_rate_hz); 4322 return; /* leave as is */ 4323 } 4324 } 4325 4326 if (sampr != mixer_get_frequency()) 4327 { 4328 mixer_set_frequency(sampr); 4329 LOGFQUEUE("audio >| audio Q_AUDIO_REMAKE_AUDIO_BUFFER"); 4330 audio_queue_send(Q_AUDIO_REMAKE_AUDIO_BUFFER, 0); 4331 } 4332} 4333#endif /* HAVE_PLAY_FREQ */ 4334 4335unsigned int playback_status(void) 4336{ 4337 return play_status; 4338} 4339 4340/** -- Startup -- **/ 4341void INIT_ATTR playback_init(void) 4342{ 4343 logf("playback: initializing"); 4344 4345 /* Initialize the track buffering system */ 4346 mutex_init(&id3_mutex); 4347 track_list_init(); 4348 buffering_init(); 4349 pcmbuf_update_frequency(); 4350#ifdef HAVE_CROSSFADE 4351 /* Set crossfade setting for next buffer init which should be about... */ 4352 pcmbuf_request_crossfade_enable(global_settings.crossfade); 4353#endif 4354#ifdef HAVE_DISK_STORAGE 4355 audio_set_buffer_margin(global_settings.buffer_margin); 4356#endif 4357}