A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
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}