blob: 870cb08d17735a1d67772caacb8a5a5c8a051925 [file] [log] [blame]
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
Nicolas Pennequinef5fa8e2008-05-05 09:40:22 +000010 * Copyright (C) 2005-2007 Miika Pekkarinen
11 * Copyright (C) 2007-2008 Nicolas Pennequin
Michael Sevakisc537d592011-04-27 03:08:23 +000012 * Copyright (C) 2011 Michael Sevakis
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +000013 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000014 * 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.
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +000018 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
Michael Sevakis65109732011-02-23 14:31:13 +000023#include "config.h"
24#include "system.h"
Jeffrey Goode9a4420b2009-10-31 19:17:36 +000025#include "kernel.h"
Michael Sevakisc537d592011-04-27 03:08:23 +000026#include "panic.h"
Thomas Martitzd0b72e22011-08-30 14:01:33 +000027#include "core_alloc.h"
Michael Sevakisc537d592011-04-27 03:08:23 +000028#include "sound.h"
29#include "ata.h"
Michael Sevakisc537d592011-04-27 03:08:23 +000030#include "codecs.h"
31#include "codec_thread.h"
32#include "voice_thread.h"
33#include "metadata.h"
Nicolas Pennequin9f4bd872007-02-14 14:40:24 +000034#include "cuesheet.h"
Michael Sevakisc537d592011-04-27 03:08:23 +000035#include "buffering.h"
36#include "talk.h"
37#include "playlist.h"
38#include "abrepeat.h"
39#include "pcmbuf.h"
Michael Sevakis5857c442013-05-31 02:41:02 -040040#include "audio_thread.h"
Michael Sevakisc537d592011-04-27 03:08:23 +000041#include "playback.h"
Michael Sevakisa2b67032011-06-29 06:37:04 +000042#include "misc.h"
Andree Buschmannc1ae7892011-08-30 19:48:08 +000043#include "settings.h"
Michael Sevakisc537d592011-04-27 03:08:23 +000044
Jonathan Gordon710ccb72006-10-25 10:17:57 +000045#ifdef HAVE_TAGCACHE
Miika Pekkarinenb7251262006-03-26 16:37:18 +000046#include "tagcache.h"
Jonathan Gordon710ccb72006-10-25 10:17:57 +000047#endif
Michael Sevakisc537d592011-04-27 03:08:23 +000048
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +000049#ifdef HAVE_LCD_BITMAP
Thomas Martitze9c10182009-10-16 19:14:41 +000050#ifdef HAVE_ALBUMART
Nicolas Pennequin9d4bed72007-11-11 12:29:37 +000051#include "albumart.h"
Thomas Martitze9c10182009-10-16 19:14:41 +000052#endif
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +000053#endif
Michael Sevakis4fc717a2006-08-28 22:38:41 +000054
Michael Sevakisc537d592011-04-27 03:08:23 +000055/* TODO: The audio thread really is doing multitasking of acting like a
56 consumer and producer of tracks. It may be advantageous to better
57 logically separate the two functions. I won't go that far just yet. */
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +000058
Michael Sevakisc537d592011-04-27 03:08:23 +000059/* Internal support for voice playback */
Miika Pekkarinen815684a2006-09-17 08:34:42 +000060#define PLAYBACK_VOICE
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +000061
Michael Sevakisc537d592011-04-27 03:08:23 +000062#if CONFIG_PLATFORM & PLATFORM_NATIVE
63/* Application builds don't support direct code loading */
64#define HAVE_CODEC_BUFFERING
65#endif
66
67/* Amount of guess-space to allow for codecs that must hunt and peck
68 * for their correct seek target, 32k seems a good size */
Brandon Low62ccbbb2006-04-11 03:55:58 +000069#define AUDIO_REBUFFER_GUESS_SIZE (1024*32)
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +000070
Nicolas Pennequinfb709522007-10-24 22:06:36 +000071/* Define LOGF_ENABLE to enable logf output in this file */
Michael Sevakisc537d592011-04-27 03:08:23 +000072/* #define LOGF_ENABLE */
Nicolas Pennequinfb709522007-10-24 22:06:36 +000073#include "logf.h"
74
Michael Sevakisc537d592011-04-27 03:08:23 +000075/* Macros to enable logf for queues
Michael Sevakis0f5cb942006-11-06 18:07:30 +000076 logging on SYS_TIMEOUT can be disabled */
Michael Sevakis77771b02007-05-09 03:48:52 +000077#ifdef SIMULATOR
Michael Sevakis0f5cb942006-11-06 18:07:30 +000078/* Define this for logf output of all queuing except SYS_TIMEOUT */
79#define PLAYBACK_LOGQUEUES
80/* Define this to logf SYS_TIMEOUT messages */
Nicolas Pennequinfb709522007-10-24 22:06:36 +000081/*#define PLAYBACK_LOGQUEUES_SYS_TIMEOUT*/
Steve Bavina3087e42006-08-31 10:01:07 +000082#endif
83
Miika Pekkarinen815684a2006-09-17 08:34:42 +000084#ifdef PLAYBACK_LOGQUEUES
Michael Sevakisa21871c2007-05-08 23:13:46 +000085#define LOGFQUEUE logf
Steve Bavina3087e42006-08-31 10:01:07 +000086#else
Michael Sevakisa21871c2007-05-08 23:13:46 +000087#define LOGFQUEUE(...)
Steve Bavina3087e42006-08-31 10:01:07 +000088#endif
89
Michael Sevakis0f5cb942006-11-06 18:07:30 +000090#ifdef PLAYBACK_LOGQUEUES_SYS_TIMEOUT
Michael Sevakisa21871c2007-05-08 23:13:46 +000091#define LOGFQUEUE_SYS_TIMEOUT logf
Michael Sevakis0f5cb942006-11-06 18:07:30 +000092#else
Michael Sevakisa21871c2007-05-08 23:13:46 +000093#define LOGFQUEUE_SYS_TIMEOUT(...)
Michael Sevakis0f5cb942006-11-06 18:07:30 +000094#endif
95
Michael Sevakisc537d592011-04-27 03:08:23 +000096/* Variables are commented with the threads that use them:
97 * A=audio, C=codec, O=other. A suffix of "-" indicates that the variable is
98 * read but not updated on that thread. Audio is the only user unless otherwise
99 * specified.
100 */
Michael Sevakis0f5cb942006-11-06 18:07:30 +0000101
Michael Sevakisc537d592011-04-27 03:08:23 +0000102/** Miscellaneous **/
Michael Sevakis5857c442013-05-31 02:41:02 -0400103extern unsigned int audio_thread_id; /* from audio_thread.c */
104extern struct event_queue audio_queue; /* from audio_thread.c */
105extern bool audio_is_initialized; /* from audio_thread.c */
106extern struct codec_api ci; /* from codecs.c */
Michael Sevakisc537d592011-04-27 03:08:23 +0000107
108/** Possible arrangements of the main buffer **/
109static enum audio_buffer_state
110{
111 AUDIOBUF_STATE_TRASHED = -1, /* trashed; must be reset */
112 AUDIOBUF_STATE_INITIALIZED = 0, /* voice+audio OR audio-only */
113 AUDIOBUF_STATE_VOICED_ONLY = 1, /* voice-only */
114} buffer_state = AUDIOBUF_STATE_TRASHED; /* (A,O) */
115
116/** Main state control **/
117static bool ff_rw_mode SHAREDBSS_ATTR = false; /* Pre-ff-rewind mode (A,O-) */
118
119enum play_status
120{
121 PLAY_STOPPED = 0,
122 PLAY_PLAYING = AUDIO_STATUS_PLAY,
123 PLAY_PAUSED = AUDIO_STATUS_PLAY | AUDIO_STATUS_PAUSE,
124} play_status = PLAY_STOPPED;
125
126/* Sizeable things that only need exist during playback and not when stopped */
127static struct audio_scratch_memory
128{
129 struct mp3entry codec_id3; /* (A,C) */
130 struct mp3entry unbuffered_id3;
131 struct cuesheet *curr_cue; /* Will follow this structure */
132} * audio_scratch_memory = NULL;
133
134/* These are used to store the current, next and optionally the peek-ahead
Jeffrey Goode8cb4b362011-05-09 21:52:06 +0000135 * mp3entry's - this guarantees that the pointer returned by audio_current/
Michael Sevakisc537d592011-04-27 03:08:23 +0000136 * next_track will be valid for the full duration of the currently playing
137 * track */
138enum audio_id3_types
139{
140 /* These are allocated statically */
141 PLAYING_ID3 = 0,
142 NEXTTRACK_ID3,
143#ifdef AUDIO_FAST_SKIP_PREVIEW
144 /* The real playing metadata must has to be protected since it contains
145 critical info for other features */
146 PLAYING_PEEK_ID3,
147#endif
148 ID3_TYPE_NUM_STATIC,
149 /* These go in the scratch memory */
150 UNBUFFERED_ID3 = ID3_TYPE_NUM_STATIC,
151 CODEC_ID3,
152};
153static struct mp3entry static_id3_entries[ID3_TYPE_NUM_STATIC]; /* (A,O) */
154
155/* Peeking functions can yield and mess us up */
Jeffrey Goode8cb4b362011-05-09 21:52:06 +0000156static struct mutex id3_mutex SHAREDBSS_ATTR; /* (A,O)*/
Michael Sevakisc537d592011-04-27 03:08:23 +0000157
158
159/** For Scrobbler support **/
160
161/* Previous track elapsed time */
162static unsigned long prev_track_elapsed = 0; /* (A,O-) */
163
164
165/** For album art support **/
166#define MAX_MULTIPLE_AA SKINNABLE_SCREENS_COUNT
167#ifdef HAVE_ALBUMART
168
169static struct albumart_slot
170{
171 struct dim dim; /* Holds width, height of the albumart */
172 int used; /* Counter; increments if something uses it */
173} albumart_slots[MAX_MULTIPLE_AA]; /* (A,O) */
174
175#define FOREACH_ALBUMART(i) for(i = 0;i < MAX_MULTIPLE_AA; i++)
176#endif /* HAVE_ALBUMART */
177
178
179/** Information used for tracking buffer fills **/
180
181/* Buffer and thread state tracking */
182static enum filling_state
183{
Michael Sevakis4db3e892011-09-01 12:15:43 +0000184 STATE_IDLE = 0, /* audio is stopped: nothing to do */
Nicolas Pennequinf68147e2008-03-28 20:18:53 +0000185 STATE_FILLING, /* adding tracks to the buffer */
186 STATE_FULL, /* can't add any more tracks */
Nicolas Pennequin0441afe2008-06-29 11:50:41 +0000187 STATE_END_OF_PLAYLIST, /* all remaining tracks have been added */
188 STATE_FINISHED, /* all remaining tracks are fully buffered */
Michael Sevakis65109732011-02-23 14:31:13 +0000189 STATE_ENDING, /* audio playback is ending */
Michael Sevakisc537d592011-04-27 03:08:23 +0000190 STATE_ENDED, /* audio playback is done */
Michael Sevakis4db3e892011-09-01 12:15:43 +0000191} filling = STATE_IDLE;
Bertrik Sikkenc97e5032008-04-28 14:13:13 +0000192
Michael Sevakisc537d592011-04-27 03:08:23 +0000193/* Track info - holds information about each track in the buffer */
194struct track_info
Jeffrey Goodedb82be42009-11-16 20:09:46 +0000195{
Michael Sevakisc537d592011-04-27 03:08:23 +0000196 /* In per-track allocated order: */
197 int id3_hid; /* Metadata handle ID */
Jeffrey Goode8cb4b362011-05-09 21:52:06 +0000198 int cuesheet_hid; /* Parsed cuesheet handle ID */
Michael Sevakisc537d592011-04-27 03:08:23 +0000199#ifdef HAVE_ALBUMART
200 int aa_hid[MAX_MULTIPLE_AA];/* Album art handle IDs */
201#endif
202#ifdef HAVE_CODEC_BUFFERING
203 int codec_hid; /* Buffered codec handle ID */
204#endif
205 int audio_hid; /* Main audio data handle ID */
206 size_t filesize; /* File total length on disk
207 TODO: This should be stored
208 in the handle or the
209 id3 and would use less
210 ram */
Jeffrey Goodedb82be42009-11-16 20:09:46 +0000211};
Michael Sevakis0f5cb942006-11-06 18:07:30 +0000212
Michael Sevakisc537d592011-04-27 03:08:23 +0000213/* Track list - holds info about all buffered tracks */
214#if MEMORYSIZE >= 32
215#define TRACK_LIST_LEN 128 /* Must be 2^int(+n) */
216#elif MEMORYSIZE >= 16
217#define TRACK_LIST_LEN 64
218#elif MEMORYSIZE >= 8
219#define TRACK_LIST_LEN 32
220#else
221#define TRACK_LIST_LEN 16
Jeffrey Goode9a4420b2009-10-31 19:17:36 +0000222#endif
223
Michael Sevakisc537d592011-04-27 03:08:23 +0000224#define TRACK_LIST_MASK (TRACK_LIST_LEN-1)
Jeffrey Goode9a4420b2009-10-31 19:17:36 +0000225
Michael Sevakisc537d592011-04-27 03:08:23 +0000226static struct
227{
228 /* read, write and current are maintained unwrapped, limited only by the
229 unsigned int range and wrap-safe comparisons are used */
Jeffrey Goode9a4420b2009-10-31 19:17:36 +0000230
Michael Sevakisc537d592011-04-27 03:08:23 +0000231 /* NOTE: there appears to be a bug in arm-elf-eabi-gcc 4.4.4 for ARMv4 where
232 if 'end' follows 'start' in this structure, track_list_count performs
233 'start - end' rather than 'end - start', giving negative count values...
234 so leave it this way for now! */
235 unsigned int end; /* Next open position */
236 unsigned int start; /* First track in list */
237 unsigned int current; /* Currently decoding track */
238 struct track_info tracks[TRACK_LIST_LEN]; /* Buffered track information */
239} track_list; /* (A, O-) */
Steve Bavin4d344572007-10-02 07:47:43 +0000240
Steve Bavin4d344572007-10-02 07:47:43 +0000241
Michael Sevakisc537d592011-04-27 03:08:23 +0000242/* Playlist steps from playlist position to next track to be buffered */
243static int playlist_peek_offset = 0;
Steve Bavin4d344572007-10-02 07:47:43 +0000244
Michael Sevakisc537d592011-04-27 03:08:23 +0000245/* Metadata handle of track load in progress (meaning all handles have not
246 yet been opened for the track, id3 always exists or the track does not)
Jeffrey Goode9a4420b2009-10-31 19:17:36 +0000247
Michael Sevakisc537d592011-04-27 03:08:23 +0000248 Tracks are keyed by their metadata handles if track list pointers are
249 insufficient to make comparisons */
250static int in_progress_id3_hid = ERR_HANDLE_NOT_FOUND;
Nicolas Pennequinf69982b2008-06-30 16:20:46 +0000251
Björn Stenberg6427d122009-01-10 21:10:56 +0000252#ifdef HAVE_DISK_STORAGE
Michael Sevakisc537d592011-04-27 03:08:23 +0000253/* Buffer margin A.K.A. anti-skip buffer (in seconds) */
254static size_t buffer_margin = 5;
Björn Stenberg6427d122009-01-10 21:10:56 +0000255#endif
Linus Nielsen Feltzing4aaa3212005-06-06 00:35:21 +0000256
Michael Sevakisc537d592011-04-27 03:08:23 +0000257/* Values returned for track loading */
258enum track_load_status
259{
260 LOAD_TRACK_ERR_START_CODEC = -6,
261 LOAD_TRACK_ERR_FINISH_FAILED = -5,
262 LOAD_TRACK_ERR_FINISH_FULL = -4,
263 LOAD_TRACK_ERR_BUSY = -3,
264 LOAD_TRACK_ERR_NO_MORE = -2,
265 LOAD_TRACK_ERR_FAILED = -1,
266 LOAD_TRACK_OK = 0,
267 LOAD_TRACK_READY = 1,
268};
269
270/** Track change controls **/
271
272/* What sort of skip is pending globally? */
273enum track_skip_type
274{
275 /* Relative to what user is intended to see: */
276 /* Codec: +0, Track List: +0, Playlist: +0 */
277 TRACK_SKIP_NONE = 0, /* no track skip */
278 /* Codec: +1, Track List: +1, Playlist: +0 */
279 TRACK_SKIP_AUTO, /* codec-initiated skip */
280 /* Codec: +1, Track List: +1, Playlist: +1 */
281 TRACK_SKIP_AUTO_NEW_PLAYLIST, /* codec-initiated skip is new playlist */
282 /* Codec: xx, Track List: +0, Playlist: +0 */
283 TRACK_SKIP_AUTO_END_PLAYLIST, /* codec-initiated end of playlist */
284 /* Manual skip: Never pends */
285 TRACK_SKIP_MANUAL, /* manual track skip */
286 /* Manual skip: Never pends */
287 TRACK_SKIP_DIR_CHANGE, /* manual directory skip */
288} skip_pending = TRACK_SKIP_NONE;
289
290/* Note about TRACK_SKIP_AUTO_NEW_PLAYLIST:
291 Fixing playlist code to be able to peek into the first song of
292 the next playlist would fix any issues and this wouldn't need
293 to be a special case since pre-advancing the playlist would be
294 unneeded - it could be much more like TRACK_SKIP_AUTO and all
295 actions that require reversal during an in-progress transition
296 would work as expected */
297
298/* Used to indicate status for the events. Must be separate to satisfy all
299 clients so the correct metadata is read when sending the change events
300 and also so that it is read correctly outside the events. */
301static bool automatic_skip = false; /* (A, O-) */
302
303/* Pending manual track skip offset */
304static int skip_offset = 0; /* (A, O) */
305
306/* Track change notification */
307static struct
308{
309 unsigned int in; /* Number of pcmbuf posts (audio isr) */
310 unsigned int out; /* Number of times audio has read the difference */
311} track_change = { 0, 0 };
312
313/** Codec status **/
Jeffrey Goode8cb4b362011-05-09 21:52:06 +0000314/* Did the codec notify us it finished while we were paused or while still
Michael Sevakisc537d592011-04-27 03:08:23 +0000315 in an automatic transition?
316
317 If paused, it is necessary to defer a codec-initiated skip until resuming
318 or else the track will move forward while not playing audio!
319
320 If in-progress, skips should not build-up ahead of where the WPS is when
321 really short tracks finish decoding.
322
323 If it is forgotten, it will be missed altogether and playback will just sit
324 there looking stupid and comatose until the user does something */
325static bool codec_skip_pending = false;
326static int codec_skip_status;
327static bool codec_seeking = false; /* Codec seeking ack expected? */
Michael Sevakis7ad2cad2011-08-28 07:45:35 +0000328static unsigned int position_key = 0;
Michael Sevakisc537d592011-04-27 03:08:23 +0000329
Michael Sevakisc537d592011-04-27 03:08:23 +0000330/* Forward declarations */
331enum audio_start_playback_flags
332{
333 AUDIO_START_RESTART = 0x1, /* "Restart" playback (flush _all_ tracks) */
334 AUDIO_START_NEWBUF = 0x2, /* Mark the audiobuffer as invalid */
335};
336
337static void audio_start_playback(size_t offset, unsigned int flags);
Magnus Holmgren1b9991c2008-10-26 20:15:10 +0000338static void audio_stop_playback(void);
Michael Sevakisc537d592011-04-27 03:08:23 +0000339static void buffer_event_buffer_low_callback(void *data);
340static void buffer_event_rebuffer_callback(void *data);
341static void buffer_event_finished_callback(void *data);
Michael Sevakis7ad2cad2011-08-28 07:45:35 +0000342void audio_pcmbuf_sync_position(void);
Michael Sevakisc537d592011-04-27 03:08:23 +0000343
Steve Bavin3cc46e72006-09-01 07:59:31 +0000344
Jeffrey Goode9a4420b2009-10-31 19:17:36 +0000345/**************************************/
Michael Sevakisf38274f2008-02-28 22:37:46 +0000346
Michael Sevakisc537d592011-04-27 03:08:23 +0000347/** --- audio_queue helpers --- **/
Michael Sevakis7ad2cad2011-08-28 07:45:35 +0000348static void audio_queue_post(long id, intptr_t data)
Jeffrey Goode5ce8e2c2009-11-04 03:58:33 +0000349{
Michael Sevakisc537d592011-04-27 03:08:23 +0000350 queue_post(&audio_queue, id, data);
Jeffrey Goode5ce8e2c2009-11-04 03:58:33 +0000351}
352
Michael Sevakisc537d592011-04-27 03:08:23 +0000353static intptr_t audio_queue_send(long id, intptr_t data)
Jeffrey Goodee8eefe92009-11-01 19:39:23 +0000354{
Michael Sevakisc537d592011-04-27 03:08:23 +0000355 return queue_send(&audio_queue, id, data);
Michael Sevakisf38274f2008-02-28 22:37:46 +0000356}
357
Jeffrey Goodedb82be42009-11-16 20:09:46 +0000358
Michael Sevakisc537d592011-04-27 03:08:23 +0000359/** --- MP3Entry --- **/
Nicolas Pennequin3e3c43c2007-10-25 21:27:45 +0000360
Michael Sevakisc537d592011-04-27 03:08:23 +0000361/* Does the mp3entry have enough info for us to use it? */
362static struct mp3entry * valid_mp3entry(const struct mp3entry *id3)
363{
364 return id3 && (id3->length != 0 || id3->filesize != 0) &&
365 id3->codectype != AFMT_UNKNOWN ? (struct mp3entry *)id3 : NULL;
366}
367
368/* Return a pointer to an mp3entry on the buffer, as it is */
369static struct mp3entry * bufgetid3(int handle_id)
Nicolas Pennequin3e3c43c2007-10-25 21:27:45 +0000370{
371 if (handle_id < 0)
372 return NULL;
373
374 struct mp3entry *id3;
375 ssize_t ret = bufgetdata(handle_id, 0, (void *)&id3);
376
Michael Sevakisbdec6382011-02-10 22:03:39 +0000377 if (ret != sizeof(struct mp3entry))
Nicolas Pennequin3e3c43c2007-10-25 21:27:45 +0000378 return NULL;
379
380 return id3;
381}
382
Michael Sevakisc537d592011-04-27 03:08:23 +0000383/* Read an mp3entry from the buffer, adjusted */
Michael Sevakisbdec6382011-02-10 22:03:39 +0000384static bool bufreadid3(int handle_id, struct mp3entry *id3out)
385{
386 struct mp3entry *id3 = bufgetid3(handle_id);
387
388 if (id3)
389 {
390 copy_mp3entry(id3out, id3);
391 return true;
392 }
393
394 return false;
395}
396
Michael Sevakisc537d592011-04-27 03:08:23 +0000397/* Lock the id3 mutex */
398static void id3_mutex_lock(void)
Nicolas Pennequin3e3c43c2007-10-25 21:27:45 +0000399{
Michael Sevakisc537d592011-04-27 03:08:23 +0000400 mutex_lock(&id3_mutex);
401}
402
403/* Unlock the id3 mutex */
404static void id3_mutex_unlock(void)
405{
406 mutex_unlock(&id3_mutex);
407}
408
409/* Return one of the collection of mp3entry pointers - collect them all here */
410static inline struct mp3entry * id3_get(enum audio_id3_types id3_num)
411{
412 switch (id3_num)
413 {
414 case UNBUFFERED_ID3:
415 return &audio_scratch_memory->unbuffered_id3;
416 case CODEC_ID3:
417 return &audio_scratch_memory->codec_id3;
418 default:
419 return &static_id3_entries[id3_num];
420 }
421}
422
423/* Copy an mp3entry into one of the mp3 entries */
424static void id3_write(enum audio_id3_types id3_num,
425 const struct mp3entry *id3_src)
426{
427 struct mp3entry *dest_id3 = id3_get(id3_num);
428
429 if (id3_src)
430 copy_mp3entry(dest_id3, id3_src);
431 else
432 wipe_mp3entry(dest_id3);
433}
434
435/* Call id3_write "safely" because peek aheads can yield, even if the fast
436 preview isn't enabled */
437static void id3_write_locked(enum audio_id3_types id3_num,
438 const struct mp3entry *id3_src)
439{
440 id3_mutex_lock();
441 id3_write(id3_num, id3_src);
442 id3_mutex_unlock();
443}
444
445
446/** --- Track info --- **/
447
448/* Close a handle and mark it invalid */
449static void track_info_close_handle(int *hid_p)
450{
451 int hid = *hid_p;
452
Brandon Low31c11642007-11-04 19:01:02 +0000453 /* bufclose returns true if the handle is not found, or if it is closed
454 * successfully, so these checks are safe on non-existant handles */
Michael Sevakisc537d592011-04-27 03:08:23 +0000455 if (hid >= 0)
456 bufclose(hid);
Nicolas Pennequin3e3c43c2007-10-25 21:27:45 +0000457
Michael Sevakisc537d592011-04-27 03:08:23 +0000458 /* Always reset to "no handle" in case it was something else */
459 *hid_p = ERR_HANDLE_NOT_FOUND;
460}
Nicolas Pennequin3e3c43c2007-10-25 21:27:45 +0000461
Michael Sevakisc537d592011-04-27 03:08:23 +0000462/* Close all handles in a struct track_info and clear it */
463static void track_info_close(struct track_info *info)
464{
465 /* Close them in the order they are allocated on the buffer to speed up
466 the handle searching */
467 track_info_close_handle(&info->id3_hid);
468 track_info_close_handle(&info->cuesheet_hid);
Nicolas Pennequin9d4bed72007-11-11 12:29:37 +0000469#ifdef HAVE_ALBUMART
Michael Sevakisc537d592011-04-27 03:08:23 +0000470 int i;
471 FOREACH_ALBUMART(i)
472 track_info_close_handle(&info->aa_hid[i]);
473#endif
474#ifdef HAVE_CODEC_BUFFERING
475 track_info_close_handle(&info->codec_hid);
476#endif
477 track_info_close_handle(&info->audio_hid);
478 info->filesize = 0;
479}
480
481/* Invalidate all members to initial values - does not close handles */
482static void track_info_wipe(struct track_info * info)
483{
484 info->id3_hid = ERR_HANDLE_NOT_FOUND;
485 info->cuesheet_hid = ERR_HANDLE_NOT_FOUND;
486#ifdef HAVE_ALBUMART
487 int i;
488 FOREACH_ALBUMART(i)
489 info->aa_hid[i] = ERR_HANDLE_NOT_FOUND;
490#endif
491#ifdef HAVE_CODEC_BUFFERING
492 info->codec_hid = ERR_HANDLE_NOT_FOUND;
493#endif
494 info->audio_hid = ERR_HANDLE_NOT_FOUND;
495 info->filesize = 0;
496}
497
498
499/** --- Track list --- **/
500
501/* Initialize the track list */
502static void track_list_init(void)
503{
504 int i;
505 for (i = 0; i < TRACK_LIST_LEN; i++)
506 track_info_wipe(&track_list.tracks[i]);
507
508 track_list.start = track_list.end = track_list.current;
509}
510
511/* Return number of items allocated in the list */
512static unsigned int track_list_count(void)
513{
514 return track_list.end - track_list.start;
515}
516
517/* Return true if the list is empty */
518static inline bool track_list_empty(void)
519{
520 return track_list.end == track_list.start;
521}
522
523/* Returns true if the list is holding the maximum number of items */
524static bool track_list_full(void)
525{
526 return track_list.end - track_list.start >= TRACK_LIST_LEN;
527}
528
529/* Test if the index is within the allocated range */
530static bool track_list_in_range(int pos)
531{
532 return (int)(pos - track_list.start) >= 0 &&
533 (int)(pos - track_list.end) < 0;
534}
535
536static struct track_info * track_list_entry(int pos)
537{
538 return &track_list.tracks[pos & TRACK_LIST_MASK];
539}
540
541/* Return the info of the last allocation plus an offset, NULL if result is
542 out of bounds */
543static struct track_info * track_list_last(int offset)
544{
545 /* Last is before the end since the end isn't inclusive */
546 unsigned int pos = track_list.end + offset - 1;
547
548 if (!track_list_in_range(pos))
549 return NULL;
550
551 return track_list_entry(pos);
552}
553
554/* Allocate space at the end for another track if not full */
555static struct track_info * track_list_alloc_track(void)
556{
557 if (track_list_full())
558 return NULL;
559
560 return track_list_entry(track_list.end++);
561}
562
563/* Remove the last track entry allocated in order to support backing out
564 of a track load */
565static void track_list_unalloc_track(void)
566{
567 if (track_list_empty())
568 return;
569
570 track_list.end--;
571
572 if (track_list.current == track_list.end &&
573 track_list.current != track_list.start)
Thomas Martitze9c10182009-10-16 19:14:41 +0000574 {
Michael Sevakisc537d592011-04-27 03:08:23 +0000575 /* Current _must_ remain within bounds */
576 track_list.current--;
577 }
578}
579
580/* Return current track plus an offset, NULL if result is out of bounds */
581static struct track_info * track_list_current(int offset)
582{
583 unsigned int pos = track_list.current + offset;
584
585 if (!track_list_in_range(pos))
586 return NULL;
587
588 return track_list_entry(pos);
589}
590
591/* Return current based upon what's intended that the user sees - not
592 necessarily where decoding is taking place */
593static struct track_info * track_list_user_current(int offset)
594{
595 if (skip_pending == TRACK_SKIP_AUTO ||
596 skip_pending == TRACK_SKIP_AUTO_NEW_PLAYLIST)
597 {
598 offset--;
599 }
600
601 return track_list_current(offset);
602}
603
604/* Advance current track by an offset, return false if result is out of
605 bounds */
606static struct track_info * track_list_advance_current(int offset)
607{
608 unsigned int pos = track_list.current + offset;
609
610 if (!track_list_in_range(pos))
611 return NULL;
612
613 track_list.current = pos;
614 return track_list_entry(pos);
615}
616
617/* Clear tracks in the list, optionally preserving the current track -
618 returns 'false' if the operation was changed */
619enum track_clear_action
620{
621 TRACK_LIST_CLEAR_ALL = 0, /* Clear all tracks */
622 TRACK_LIST_KEEP_CURRENT, /* Keep current only; clear before + after */
623 TRACK_LIST_KEEP_NEW /* Keep current and those that follow */
624};
625
626static void track_list_clear(enum track_clear_action action)
627{
628 logf("%s(%d)", __func__, (int)action);
629
630 /* Don't care now since rebuffering is imminent */
631 buf_set_watermark(0);
632
633 if (action != TRACK_LIST_CLEAR_ALL)
634 {
635 struct track_info *cur = track_list_current(0);
636
637 if (!cur || cur->id3_hid < 0)
638 action = TRACK_LIST_CLEAR_ALL; /* Nothing worthwhile keeping */
639 }
640
641 /* Noone should see this progressing */
642 int start = track_list.start;
643 int current = track_list.current;
644 int end = track_list.end;
645
646 track_list.start = current;
647
648 switch (action)
649 {
650 case TRACK_LIST_CLEAR_ALL:
651 /* Result: .start = .current, .end = .current */
652 track_list.end = current;
653 break;
654
655 case TRACK_LIST_KEEP_CURRENT:
656 /* Result: .start = .current, .end = .current + 1 */
657 track_list.end = current + 1;
658 break;
659
660 case TRACK_LIST_KEEP_NEW:
661 /* Result: .start = .current, .end = .end */
662 end = current;
663 break;
664 }
665
666 /* Close all open handles in the range except the for the current track
667 if preserving that */
668 while (start != end)
669 {
670 if (action != TRACK_LIST_KEEP_CURRENT || start != current)
Thomas Martitze9c10182009-10-16 19:14:41 +0000671 {
Michael Sevakisc537d592011-04-27 03:08:23 +0000672 struct track_info *info =
673 &track_list.tracks[start & TRACK_LIST_MASK];
674
675 /* If this is the in-progress load, abort it */
676 if (in_progress_id3_hid >= 0 &&
677 info->id3_hid == in_progress_id3_hid)
678 {
679 in_progress_id3_hid = ERR_HANDLE_NOT_FOUND;
680 }
681
682 track_info_close(info);
Thomas Martitze9c10182009-10-16 19:14:41 +0000683 }
Michael Sevakisc537d592011-04-27 03:08:23 +0000684
685 start++;
686 }
687}
688
689
690/** --- Audio buffer -- **/
691
692/* What size is needed for the scratch buffer? */
693static size_t scratch_mem_size(void)
694{
695 size_t size = sizeof (struct audio_scratch_memory);
696
697 if (global_settings.cuesheet)
698 size += sizeof (struct cuesheet);
699
700 return size;
701}
702
703/* Initialize the memory area where data is stored that is only used when
704 playing audio and anything depending upon it */
705static void scratch_mem_init(void *mem)
706{
707 audio_scratch_memory = (struct audio_scratch_memory *)mem;
708 id3_write_locked(UNBUFFERED_ID3, NULL);
709 id3_write(CODEC_ID3, NULL);
710 ci.id3 = id3_get(CODEC_ID3);
711 audio_scratch_memory->curr_cue = NULL;
712
713 if (global_settings.cuesheet)
714 {
715 audio_scratch_memory->curr_cue =
716 SKIPBYTES((struct cuesheet *)audio_scratch_memory,
717 sizeof (struct audio_scratch_memory));
718 }
719}
720
Thomas Martitzd0b72e22011-08-30 14:01:33 +0000721static int audiobuf_handle;
Thomas Martitz2a8eacd2011-11-17 17:55:02 +0000722#define AUDIO_BUFFER_RESERVE (256*1024)
Thomas Martitzd0b72e22011-08-30 14:01:33 +0000723static size_t filebuflen;
724
Thomas Martitz2a8eacd2011-11-17 17:55:02 +0000725
726size_t audio_buffer_size(void)
727{
728 if (audiobuf_handle > 0)
729 return filebuflen - AUDIO_BUFFER_RESERVE;
730 return 0;
731}
732
Thomas Martitzd0b72e22011-08-30 14:01:33 +0000733size_t audio_buffer_available(void)
734{
Thomas Martitz2a8eacd2011-11-17 17:55:02 +0000735 size_t size = 0;
736 size_t core_size = core_available();
737 if (audiobuf_handle > 0) /* if allocated return what we can give */
738 size = filebuflen - AUDIO_BUFFER_RESERVE - 128;
739 return MAX(core_size, size);
Thomas Martitzd0b72e22011-08-30 14:01:33 +0000740}
741
Thomas Martitzbaa070c2011-08-30 14:01:45 +0000742/* Set up the audio buffer for playback
743 * filebuflen must be pre-initialized with the maximum size */
Michael Sevakisda6cebb2012-05-02 17:22:28 -0400744static void audio_reset_buffer_noalloc(
745 void *filebuf, enum audio_buffer_state state)
Michael Sevakisc537d592011-04-27 03:08:23 +0000746{
747 /*
748 * Layout audio buffer as follows:
Michael Sevakisda6cebb2012-05-02 17:22:28 -0400749 * [[|TALK]|SCRATCH|BUFFERING|PCM]
Michael Sevakisc537d592011-04-27 03:08:23 +0000750 */
751
752 /* see audio_get_recording_buffer if this is modified */
753 logf("%s()", __func__);
754
755 /* If the setup of anything allocated before the file buffer is
756 changed, do check the adjustments after the buffer_alloc call
757 as it will likely be affected and need sliding over */
758
759 /* Initially set up file buffer as all space available */
Thomas Martitzd0b72e22011-08-30 14:01:33 +0000760 size_t allocsize;
Michael Sevakisc537d592011-04-27 03:08:23 +0000761
Michael Sevakisda6cebb2012-05-02 17:22:28 -0400762 /* Subtract whatever voice needs (we're called when promoting
763 the state only) */
Thomas Martitzd1322b72011-08-14 15:13:00 +0000764 allocsize = talkbuf_init(filebuf);
765 allocsize = ALIGN_UP(allocsize, sizeof (intptr_t));
766 if (allocsize > filebuflen)
767 goto bufpanic;
768
769 filebuf += allocsize;
770 filebuflen -= allocsize;
Michael Sevakisc537d592011-04-27 03:08:23 +0000771
Michael Sevakisda6cebb2012-05-02 17:22:28 -0400772 if (state == AUDIOBUF_STATE_INITIALIZED)
Michael Sevakisa802eba2011-07-09 01:49:00 +0000773 {
Michael Sevakisda6cebb2012-05-02 17:22:28 -0400774 /* Subtract whatever the pcm buffer says it used plus the guard
775 buffer */
776 allocsize = pcmbuf_init(filebuf + filebuflen);
Michael Sevakisa802eba2011-07-09 01:49:00 +0000777
Michael Sevakisda6cebb2012-05-02 17:22:28 -0400778 /* Make sure filebuflen is a pointer sized multiple after
779 adjustment */
Michael Sevakisa802eba2011-07-09 01:49:00 +0000780 allocsize = ALIGN_UP(allocsize, sizeof (intptr_t));
781 if (allocsize > filebuflen)
782 goto bufpanic;
Michael Sevakisda6cebb2012-05-02 17:22:28 -0400783
Michael Sevakisa802eba2011-07-09 01:49:00 +0000784 filebuflen -= allocsize;
Michael Sevakisda6cebb2012-05-02 17:22:28 -0400785
786 /* Scratch memory */
787 allocsize = scratch_mem_size();
788 if (allocsize > filebuflen)
789 goto bufpanic;
790
791 scratch_mem_init(filebuf);
792 filebuf += allocsize;
793 filebuflen -= allocsize;
794
795 buffering_reset(filebuf, filebuflen);
Michael Sevakisa802eba2011-07-09 01:49:00 +0000796 }
797
Michael Sevakisda6cebb2012-05-02 17:22:28 -0400798 buffer_state = state;
Michael Sevakisc537d592011-04-27 03:08:23 +0000799
800#if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
801 /* Make sure everything adds up - yes, some info is a bit redundant but
Jeffrey Goode8cb4b362011-05-09 21:52:06 +0000802 aids viewing and the summation of certain variables should add up to
Michael Sevakisc537d592011-04-27 03:08:23 +0000803 the location of others. */
804 {
Michael Sevakisc537d592011-04-27 03:08:23 +0000805 logf("fbuf: %08X", (unsigned)filebuf);
806 logf("fbufe: %08X", (unsigned)(filebuf + filebuflen));
807 logf("sbuf: %08X", (unsigned)audio_scratch_memory);
808 logf("sbufe: %08X", (unsigned)(audio_scratch_memory + allocsize));
Nicolas Pennequin9d4bed72007-11-11 12:29:37 +0000809 }
Nicolas Pennequincf37f4c2007-11-11 12:52:07 +0000810#endif
Nicolas Pennequin9d4bed72007-11-11 12:29:37 +0000811
Michael Sevakisc537d592011-04-27 03:08:23 +0000812 return;
813
814bufpanic:
815 panicf("%s(): EOM (%zu > %zu)", __func__, allocsize, filebuflen);
816}
817
Thomas Martitzbaa070c2011-08-30 14:01:45 +0000818/* Buffer must not move. */
819static int shrink_callback(int handle, unsigned hints, void* start, size_t old_size)
820{
Thomas Martitzd7e10702011-11-05 10:01:22 +0000821 struct queue_event ev;
822 static const long filter_list[][2] =
823 {
824 /* codec messages */
825 { Q_AUDIO_PLAY, Q_AUDIO_PLAY },
826 };
Thomas Martitzcf01d232011-11-03 21:51:46 +0000827 /* filebuflen is, at this point, the buffering.c buffer size,
828 * i.e. the audiobuf except voice, scratch mem, pcm, ... */
829 ssize_t extradata_size = old_size - filebuflen;
830 /* check what buflib requests */
831 size_t wanted_size = (hints & BUFLIB_SHRINK_SIZE_MASK);
832 ssize_t size = (ssize_t)old_size - wanted_size;
833 /* keep at least 256K for the buffering */
Thomas Martitz2a8eacd2011-11-17 17:55:02 +0000834 if ((size - extradata_size) < AUDIO_BUFFER_RESERVE)
Thomas Martitzcf01d232011-11-03 21:51:46 +0000835 return BUFLIB_CB_CANNOT_SHRINK;
836
Thomas Martitzd7e10702011-11-05 10:01:22 +0000837
Thomas Martitz4c5f5ef2011-09-19 20:52:00 +0000838 /* TODO: Do it without stopping playback, if possible */
Thomas Martitzd7e10702011-11-05 10:01:22 +0000839 long offset = audio_current_track()->offset;
Thomas Martitz82337dd2012-03-23 10:48:50 +0100840 /* resume if playing */
841 bool playing = (audio_status() == AUDIO_STATUS_PLAY);
Thomas Martitzd7e10702011-11-05 10:01:22 +0000842 /* There's one problem with stoping and resuming: If it happens in a too
843 * frequent fashion, the codecs lose the resume postion and playback
844 * begins from the beginning.
845 * To work around use queue_post() to effectively delay the resume in case
846 * we're called another time. However this has another problem: id3->offset
847 * gets zero since playback is stopped. Therefore, try to peek at the
848 * queue_post from the last call to get the correct offset. This also
Thomas Martitz79ffd042011-11-06 12:07:33 +0000849 * lets us conviniently remove the queue event so Q_AUDIO_PLAY is only
Thomas Martitzd7e10702011-11-05 10:01:22 +0000850 * processed once. */
851 bool play_queued = queue_peek_ex(&audio_queue, &ev, QPEEK_REMOVE_EVENTS, filter_list);
852
853 if (playing && offset > 0) /* current id3->offset is king */
854 ev.data = offset;
855
Thomas Martitz4c5f5ef2011-09-19 20:52:00 +0000856 /* don't call audio_hard_stop() as it frees this handle */
857 if (thread_self() == audio_thread_id)
858 { /* inline case Q_AUDIO_STOP (audio_hard_stop() response
859 * if we're in the audio thread */
860 audio_stop_playback();
861 queue_clear(&audio_queue);
862 }
863 else
864 audio_queue_send(Q_AUDIO_STOP, 1);
865#ifdef PLAYBACK_VOICE
866 voice_stop();
867#endif
Thomas Martitzcf01d232011-11-03 21:51:46 +0000868 /* we should be free to change the buffer now
869 * set final buffer size before calling audio_reset_buffer_noalloc()
870 * (now it's the total size, the call will subtract voice etc) */
Thomas Martitz4c5f5ef2011-09-19 20:52:00 +0000871 filebuflen = size;
Thomas Martitzbaa070c2011-08-30 14:01:45 +0000872 switch (hints & BUFLIB_SHRINK_POS_MASK)
873 {
874 case BUFLIB_SHRINK_POS_BACK:
875 core_shrink(handle, start, size);
Michael Sevakisda6cebb2012-05-02 17:22:28 -0400876 audio_reset_buffer_noalloc(start, buffer_state);
Thomas Martitzbaa070c2011-08-30 14:01:45 +0000877 break;
878 case BUFLIB_SHRINK_POS_FRONT:
879 core_shrink(handle, start + wanted_size, size);
Michael Sevakisda6cebb2012-05-02 17:22:28 -0400880 audio_reset_buffer_noalloc(start + wanted_size,
881 buffer_state);
Thomas Martitzbaa070c2011-08-30 14:01:45 +0000882 break;
883 }
Thomas Martitzd7e10702011-11-05 10:01:22 +0000884 if (playing || play_queued)
Thomas Martitz4c5f5ef2011-09-19 20:52:00 +0000885 {
Thomas Martitzd7e10702011-11-05 10:01:22 +0000886 /* post, to make subsequent calls not break the resume position */
887 audio_queue_post(Q_AUDIO_PLAY, ev.data);
Thomas Martitzbaa070c2011-08-30 14:01:45 +0000888 }
889
890 return BUFLIB_CB_OK;
891}
892
893static struct buflib_callbacks ops = {
894 .move_callback = NULL,
895 .shrink_callback = shrink_callback,
896};
897
Michael Sevakisda6cebb2012-05-02 17:22:28 -0400898static void audio_reset_buffer(enum audio_buffer_state state)
Thomas Martitzbaa070c2011-08-30 14:01:45 +0000899{
900 if (audiobuf_handle > 0)
901 {
902 core_free(audiobuf_handle);
903 audiobuf_handle = 0;
904 }
905 audiobuf_handle = core_alloc_maximum("audiobuf", &filebuflen, &ops);
Thomas Martitz4c5f5ef2011-09-19 20:52:00 +0000906 unsigned char *filebuf = core_get_data(audiobuf_handle);
Thomas Martitzbaa070c2011-08-30 14:01:45 +0000907
Michael Sevakisda6cebb2012-05-02 17:22:28 -0400908 audio_reset_buffer_noalloc(filebuf, state);
Thomas Martitzbaa070c2011-08-30 14:01:45 +0000909}
910
Michael Sevakisc537d592011-04-27 03:08:23 +0000911/* Set the buffer margin to begin rebuffering when 'seconds' from empty */
912static void audio_update_filebuf_watermark(int seconds)
913{
914 size_t bytes = 0;
915
916#ifdef HAVE_DISK_STORAGE
917 int spinup = ata_spinup_time();
918
919 if (seconds == 0)
920 {
921 /* By current setting */
922 seconds = buffer_margin;
923 }
924 else
925 {
926 /* New setting */
927 buffer_margin = seconds;
928
929 if (buf_get_watermark() == 0)
930 {
931 /* Write a watermark only if the audio thread already did so for
932 itself or it will fail to set the event and the watermark - if
933 it hasn't yet, it will use the new setting when it does */
934 return;
935 }
Jonathan Gordon24b136f2009-07-20 05:18:18 +0000936 }
937
Michael Sevakisc537d592011-04-27 03:08:23 +0000938 if (spinup)
939 seconds += (spinup / HZ) + 1;
940 else
941 seconds += 5;
942
943 seconds += buffer_margin;
944#else
945 /* flash storage */
946 seconds = 1;
947#endif
948
949 /* Watermark is a function of the bitrate of the last track in the buffer */
Jeffrey Goode8cb4b362011-05-09 21:52:06 +0000950 struct mp3entry *id3 = NULL;
Michael Sevakisc537d592011-04-27 03:08:23 +0000951 struct track_info *info = track_list_last(0);
952
953 if (info)
954 id3 = valid_mp3entry(bufgetid3(info->id3_hid));
955
956 if (id3)
957 {
Sean Bartellfe3d5802011-08-12 01:27:13 -0400958 if (!rbcodec_format_is_atomic(id3->codectype))
Michael Sevakisc537d592011-04-27 03:08:23 +0000959 {
960 bytes = id3->bitrate * (1000/8) * seconds;
961 }
962 else
963 {
964 /* Bitrate has no meaning to buffering margin for atomic audio -
Jeffrey Goode8cb4b362011-05-09 21:52:06 +0000965 rebuffer when it's the only track left unless it's the only
Michael Sevakisc537d592011-04-27 03:08:23 +0000966 track that fits, in which case we should avoid constant buffer
967 low events */
968 if (track_list_count() > 1)
969 bytes = info->filesize + 1;
970 }
971 }
972 else
973 {
974 /* Then set the minimum - this should not occur anyway */
975 logf("fwmark: No id3 for last track (s%u/c%u/e%u)",
976 track_list.start, track_list.current, track_list.end);
977 }
978
979 /* Actually setting zero disables the notification and we use that
980 to detect that it has been reset */
981 buf_set_watermark(MAX(bytes, 1));
982 logf("fwmark: %lu", (unsigned long)bytes);
983}
984
985
986/** -- Track change notification -- **/
987
988/* Check the pcmbuf track changes and return write the message into the event
989 if there are any */
990static inline bool audio_pcmbuf_track_change_scan(void)
991{
992 if (track_change.out != track_change.in)
993 {
994 track_change.out++;
995 return true;
996 }
997
998 return false;
999}
1000
1001/* Clear outstanding track change posts */
1002static inline void audio_pcmbuf_track_change_clear(void)
1003{
1004 track_change.out = track_change.in;
1005}
1006
1007/* Post a track change notification - called by audio ISR */
1008static inline void audio_pcmbuf_track_change_post(void)
1009{
1010 track_change.in++;
1011}
1012
1013
1014/** --- Helper functions --- **/
1015
1016/* Removes messages that might end up in the queue before or while processing
1017 a manual track change. Responding to them would be harmful since they
1018 belong to a previous track's playback period. Anything that would generate
1019 the stale messages must first be put into a state where it will not do so.
1020 */
1021static void audio_clear_track_notifications(void)
1022{
1023 static const long filter_list[][2] =
1024 {
1025 /* codec messages */
1026 { Q_AUDIO_CODEC_SEEK_COMPLETE, Q_AUDIO_CODEC_COMPLETE },
1027 /* track change messages */
1028 { Q_AUDIO_TRACK_CHANGED, Q_AUDIO_TRACK_CHANGED },
1029 };
1030
1031 const int filter_count = ARRAYLEN(filter_list) - 1;
1032
1033 /* Remove any pcmbuf notifications */
1034 pcmbuf_monitor_track_change(false);
1035 audio_pcmbuf_track_change_clear();
1036
1037 /* Scrub the audio queue of the old mold */
1038 while (queue_peek_ex(&audio_queue, NULL,
1039 filter_count | QPEEK_REMOVE_EVENTS,
1040 filter_list))
1041 {
1042 yield(); /* Not strictly needed, per se, ad infinitum, ra, ra */
1043 }
1044}
1045
1046/* Takes actions based upon track load status codes */
1047static void audio_handle_track_load_status(int trackstat)
1048{
1049 switch (trackstat)
1050 {
1051 case LOAD_TRACK_ERR_NO_MORE:
1052 if (track_list_count() > 0)
1053 break;
1054
1055 case LOAD_TRACK_ERR_START_CODEC:
1056 audio_queue_post(Q_AUDIO_CODEC_COMPLETE, CODEC_ERROR);
1057 break;
1058
1059 default:
1060 break;
1061 }
1062}
1063
1064/* Announce the end of playing the current track */
1065static void audio_playlist_track_finish(void)
1066{
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00001067 struct mp3entry *ply_id3 = id3_get(PLAYING_ID3);
1068 struct mp3entry *id3 = valid_mp3entry(ply_id3);
Michael Sevakisc537d592011-04-27 03:08:23 +00001069
1070 playlist_update_resume_info(filling == STATE_ENDED ? NULL : id3);
1071
1072 if (id3)
1073 {
1074 send_event(PLAYBACK_EVENT_TRACK_FINISH, id3);
1075 prev_track_elapsed = id3->elapsed;
1076 }
1077 else
1078 {
1079 prev_track_elapsed = 0;
1080 }
1081}
1082
1083/* Announce the beginning of the new track */
1084static void audio_playlist_track_change(void)
1085{
1086 struct mp3entry *id3 = valid_mp3entry(id3_get(PLAYING_ID3));
1087
1088 if (id3)
1089 send_event(PLAYBACK_EVENT_TRACK_CHANGE, id3);
1090
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00001091 position_key = pcmbuf_get_position_key();
1092
Michael Sevakisc537d592011-04-27 03:08:23 +00001093 playlist_update_resume_info(id3);
1094}
1095
1096/* Change the data for the next track and send the event */
1097static void audio_update_and_announce_next_track(const struct mp3entry *id3_next)
1098{
1099 id3_write_locked(NEXTTRACK_ID3, id3_next);
1100 send_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE,
1101 id3_get(NEXTTRACK_ID3));
1102}
1103
1104/* Bring the user current mp3entry up to date and set a new offset for the
1105 buffered metadata */
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00001106static void playing_id3_sync(struct track_info *user_info, off_t offset)
Michael Sevakisc537d592011-04-27 03:08:23 +00001107{
1108 id3_mutex_lock();
1109
1110 struct mp3entry *id3 = bufgetid3(user_info->id3_hid);
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00001111 struct mp3entry *playing_id3 = id3_get(PLAYING_ID3);
Michael Sevakisc537d592011-04-27 03:08:23 +00001112
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00001113 pcm_play_lock();
1114
1115 unsigned long e = playing_id3->elapsed;
1116 unsigned long o = playing_id3->offset;
1117
1118 id3_write(PLAYING_ID3, id3);
1119
1120 if (offset < 0)
Michael Sevakisc537d592011-04-27 03:08:23 +00001121 {
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00001122 playing_id3->elapsed = e;
1123 playing_id3->offset = o;
Michael Sevakisc537d592011-04-27 03:08:23 +00001124 offset = 0;
1125 }
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00001126
1127 pcm_play_unlock();
Michael Sevakisc537d592011-04-27 03:08:23 +00001128
1129 if (id3)
1130 id3->offset = offset;
1131
1132 id3_mutex_unlock();
1133}
1134
1135/* Wipe-out track metadata - current is optional */
1136static void wipe_track_metadata(bool current)
1137{
1138 id3_mutex_lock();
1139
1140 if (current)
1141 id3_write(PLAYING_ID3, NULL);
1142
1143 id3_write(NEXTTRACK_ID3, NULL);
1144 id3_write(UNBUFFERED_ID3, NULL);
1145
1146 id3_mutex_unlock();
1147}
1148
1149/* Called when buffering is completed on the last track handle */
1150static void filling_is_finished(void)
1151{
1152 logf("last track finished buffering");
1153
1154 /* There's no more to load or watch for */
1155 buf_set_watermark(0);
1156 filling = STATE_FINISHED;
1157}
1158
1159/* Stop the codec decoding or waiting for its data to be ready - returns
1160 'false' if the codec ended up stopped */
1161static bool halt_decoding_track(bool stop)
1162{
1163 /* If it was waiting for us to clear the buffer to make a rebuffer
1164 happen, it should cease otherwise codec_stop could deadlock waiting
1165 for the codec to go to its main loop - codec's request will now
1166 force-fail */
1167 bool retval = false;
1168
1169 buf_signal_handle(ci.audio_hid, true);
1170
1171 if (stop)
1172 codec_stop();
1173 else
1174 retval = codec_pause();
1175
1176 audio_clear_track_notifications();
1177
1178 /* We now know it's idle and not waiting for buffered data */
1179 buf_signal_handle(ci.audio_hid, false);
1180
1181 codec_skip_pending = false;
1182 codec_seeking = false;
1183
1184 return retval;
1185}
1186
Michael Sevakis5078d462011-08-23 01:37:59 +00001187/* Wait for any in-progress fade to complete */
1188static void audio_wait_fade_complete(void)
1189{
1190 /* Just loop until it's done */
1191 while (pcmbuf_fading())
1192 sleep(0);
1193}
1194
Michael Sevakisc537d592011-04-27 03:08:23 +00001195/* End the ff/rw mode */
1196static void audio_ff_rewind_end(void)
1197{
1198 /* A seamless seek (not calling audio_pre_ff_rewind) skips this
1199 section */
1200 if (ff_rw_mode)
1201 {
1202 ff_rw_mode = false;
1203
1204 if (codec_seeking)
1205 {
1206 /* Clear the buffer */
1207 pcmbuf_play_stop();
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00001208 audio_pcmbuf_sync_position();
Michael Sevakisc537d592011-04-27 03:08:23 +00001209 }
1210
1211 if (play_status != PLAY_PAUSED)
1212 {
1213 /* Seeking-while-playing, resume PCM playback */
1214 pcmbuf_pause(false);
1215 }
1216 }
1217}
1218
1219/* Complete the codec seek */
1220static void audio_complete_codec_seek(void)
1221{
1222 /* If a seek completed while paused, 'paused' is true.
1223 * If seeking from seek mode, 'ff_rw_mode' is true. */
1224 if (codec_seeking)
1225 {
1226 audio_ff_rewind_end();
1227 codec_seeking = false; /* set _after_ the call! */
1228 }
1229 /* else it's waiting and we must repond */
1230}
1231
1232/* Get the current cuesheet pointer */
1233static inline struct cuesheet * get_current_cuesheet(void)
1234{
1235 return audio_scratch_memory->curr_cue;
1236}
1237
1238/* Read the cuesheet from the buffer */
1239static void buf_read_cuesheet(int handle_id)
1240{
1241 struct cuesheet *cue = get_current_cuesheet();
1242
1243 if (!cue || handle_id < 0)
1244 return;
1245
1246 bufread(handle_id, sizeof (struct cuesheet), cue);
1247}
1248
1249/* Backend to peek/current/next track metadata interface functions -
1250 fill in the mp3entry with as much information as we may obtain about
1251 the track at the specified offset from the user current track -
1252 returns false if no information exists with us */
1253static bool audio_get_track_metadata(int offset, struct mp3entry *id3)
1254{
1255 if (play_status == PLAY_STOPPED)
1256 return false;
1257
1258 if (id3->path[0] != '\0')
1259 return true; /* Already filled */
1260
1261 struct track_info *info = track_list_user_current(offset);
1262
1263 if (!info)
1264 {
1265 struct mp3entry *ub_id3 = id3_get(UNBUFFERED_ID3);
1266
1267 if (offset > 0 && track_list_user_current(offset - 1))
1268 {
1269 /* Try the unbuffered id3 since we're moving forward */
1270 if (ub_id3->path[0] != '\0')
1271 {
1272 copy_mp3entry(id3, ub_id3);
1273 return true;
1274 }
1275 }
1276 }
1277 else if (bufreadid3(info->id3_hid, id3))
1278 {
Michael Sevakisc3e56252011-08-22 00:14:56 +00001279 id3->cuesheet = NULL;
Michael Sevakisc537d592011-04-27 03:08:23 +00001280 return true;
1281 }
1282
1283 /* We didn't find the ID3 metadata, so we fill it with the little info we
1284 have and return that */
1285
1286 char path[MAX_PATH+1];
1287 if (playlist_peek(offset, path, sizeof (path)))
1288 {
1289#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
1290 /* Try to get it from the database */
1291 if (!tagcache_fill_tags(id3, path))
1292#endif
1293 {
1294 /* By now, filename is the only source of info */
1295 fill_metadata_from_path(id3, path);
1296 }
1297
1298 return true;
1299 }
1300
1301 wipe_mp3entry(id3);
1302
1303 return false;
1304}
1305
1306/* Get a resume rewind adjusted offset from the ID3 */
Bertrik Sikken57304d12011-10-12 20:47:41 +00001307static unsigned long resume_rewind_adjusted_offset(const struct mp3entry *id3)
Michael Sevakisc537d592011-04-27 03:08:23 +00001308{
1309 unsigned long offset = id3->offset;
1310 size_t resume_rewind = global_settings.resume_rewind *
1311 id3->bitrate * (1000/8);
1312
1313 if (offset < resume_rewind)
1314 offset = 0;
1315 else
1316 offset -= resume_rewind;
1317
1318 return offset;
1319}
1320
1321/* Get the codec into ram and initialize it - keep it if it's ready */
1322static bool audio_init_codec(struct track_info *track_info,
1323 struct mp3entry *track_id3)
1324{
1325 int codt_loaded = get_audio_base_codec_type(codec_loaded());
1326 int hid = ERR_HANDLE_NOT_FOUND;
1327
1328 if (codt_loaded != AFMT_UNKNOWN)
1329 {
1330 int codt = get_audio_base_codec_type(track_id3->codectype);
1331
1332 if (codt == codt_loaded)
1333 {
1334 /* Codec is the same base type */
1335 logf("Reusing prev. codec: %d", track_id3->codectype);
1336#ifdef HAVE_CODEC_BUFFERING
1337 /* Close any buffered codec (we could have skipped directly to a
1338 format transistion that is the same format as the current track
1339 and the buffered one is no longer needed) */
1340 track_info_close_handle(&track_info->codec_hid);
1341#endif
1342 return true;
1343 }
1344 else
1345 {
1346 /* New codec - first make sure the old one's gone */
1347 logf("Removing prev. codec: %d", codt_loaded);
1348 codec_unload();
1349 }
1350 }
1351
1352 logf("New codec: %d/%d", track_id3->codectype, codec_loaded());
1353
1354#ifdef HAVE_CODEC_BUFFERING
1355 /* Codec thread will close the handle even if it fails and will load from
1356 storage if hid is not valid or the buffer load fails */
1357 hid = track_info->codec_hid;
1358 track_info->codec_hid = ERR_HANDLE_NOT_FOUND;
1359#endif
1360
1361 return codec_load(hid, track_id3->codectype);
1362 (void)track_info; /* When codec buffering isn't supported */
1363}
1364
Sean Bartell4bef5022011-08-22 01:36:25 -04001365#ifdef HAVE_TAGCACHE
1366/* Check settings for whether the file should be autoresumed */
1367enum { AUTORESUMABLE_UNKNOWN = 0, AUTORESUMABLE_TRUE, AUTORESUMABLE_FALSE };
1368static bool autoresumable(struct mp3entry *id3)
1369{
1370 char *endp, *path;
1371 size_t len;
1372 bool is_resumable;
1373
1374 if (id3->autoresumable) /* result cached? */
1375 return id3->autoresumable == AUTORESUMABLE_TRUE;
1376
1377 is_resumable = false;
1378
1379 if (id3->path)
1380 {
1381 for (path = global_settings.autoresume_paths;
1382 *path; /* search terms left? */
1383 path++)
1384 {
1385 if (*path == ':') /* Skip empty search patterns */
1386 continue;
1387
1388 /* FIXME: As soon as strcspn or strchrnul are made available in
1389 the core, the following can be made more efficient. */
1390 endp = strchr(path, ':');
1391 if (endp)
1392 len = endp - path;
1393 else
1394 len = strlen(path);
1395
1396 /* Note: At this point, len is always > 0 */
1397
1398 if (strncasecmp(id3->path, path, len) == 0)
1399 {
1400 /* Full directory-name matches only. Trailing '/' in
1401 search path OK. */
1402 if (id3->path[len] == '/' || id3->path[len - 1] == '/')
1403 {
1404 is_resumable = true;
1405 break;
1406 }
1407 }
1408 path += len - 1;
1409 }
1410 }
1411
1412 /* cache result */
1413 id3->autoresumable =
1414 is_resumable ? AUTORESUMABLE_TRUE : AUTORESUMABLE_FALSE;
1415
1416 logf("autoresumable: %s is%s resumable",
1417 id3->path, is_resumable ? "" : " not");
1418
1419 return is_resumable;
1420}
1421#endif /* HAVE_TAGCACHE */
1422
Michael Sevakisc537d592011-04-27 03:08:23 +00001423/* Start the codec for the current track scheduled to be decoded */
1424static bool audio_start_codec(bool auto_skip)
1425{
1426 struct track_info *info = track_list_current(0);
1427 struct mp3entry *cur_id3 = valid_mp3entry(bufgetid3(info->id3_hid));
1428
1429 if (!cur_id3)
1430 return false;
1431
1432 buf_pin_handle(info->id3_hid, true);
1433
1434 if (!audio_init_codec(info, cur_id3))
1435 {
1436 buf_pin_handle(info->id3_hid, false);
1437 return false;
1438 }
1439
1440#ifdef HAVE_TAGCACHE
1441 bool autoresume_enable = global_settings.autoresume_enable;
1442
1443 if (autoresume_enable && !cur_id3->offset)
1444 {
1445 /* Resume all manually selected tracks */
1446 bool resume = !auto_skip;
1447
1448 /* Send the "buffer" event to obtain the resume position for the codec */
1449 send_event(PLAYBACK_EVENT_TRACK_BUFFER, cur_id3);
1450
1451 if (!resume)
1452 {
1453 /* Automatic skip - do further tests to see if we should just
1454 ignore any autoresume position */
1455 int autoresume_automatic = global_settings.autoresume_automatic;
1456
1457 switch (autoresume_automatic)
1458 {
1459 case AUTORESUME_NEXTTRACK_ALWAYS:
1460 /* Just resume unconditionally */
1461 resume = true;
1462 break;
1463 case AUTORESUME_NEXTTRACK_NEVER:
1464 /* Force-rewind it */
1465 break;
1466 default:
1467 /* Not "never resume" - pass resume filter? */
1468 resume = autoresumable(cur_id3);
1469 }
1470 }
1471
1472 if (!resume)
1473 cur_id3->offset = 0;
1474
1475 logf("%s: Set offset for %s to %lX\n", __func__,
1476 cur_id3->title, cur_id3->offset);
1477 }
1478#endif /* HAVE_TAGCACHE */
1479
1480 /* Rewind the required amount - if an autoresume was done, this also rewinds
1481 that by the setting's amount
1482
1483 It would be best to have bookkeeping about whether or not the track
1484 sounded or not since skipping to it or else skipping to it while paused
1485 and back again will cause accumulation of silent rewinds - that's not
1486 our job to track directly nor could it be in any reasonable way
1487 */
1488 cur_id3->offset = resume_rewind_adjusted_offset(cur_id3);
1489
1490 /* Update the codec API with the metadata and track info */
1491 id3_write(CODEC_ID3, cur_id3);
1492
1493 ci.audio_hid = info->audio_hid;
1494 ci.filesize = info->filesize;
1495 buf_set_base_handle(info->audio_hid);
1496
1497 /* All required data is now available for the codec */
1498 codec_go();
1499
1500#ifdef HAVE_TAGCACHE
1501 if (!autoresume_enable || cur_id3->offset)
1502#endif
1503 {
1504 /* Send the "buffer" event now */
1505 send_event(PLAYBACK_EVENT_TRACK_BUFFER, cur_id3);
1506 }
1507
1508 buf_pin_handle(info->id3_hid, false);
1509 return true;
1510
1511 (void)auto_skip; /* ifndef HAVE_TAGCACHE */
1512}
1513
1514
1515/** --- Audio thread --- **/
1516
1517/* Load and parse a cuesheet for the file - returns false if the buffer
1518 is full */
1519static bool audio_load_cuesheet(struct track_info *info,
1520 struct mp3entry *track_id3)
1521{
1522 struct cuesheet *cue = get_current_cuesheet();
1523 track_id3->cuesheet = NULL;
1524
1525 if (cue && info->cuesheet_hid == ERR_HANDLE_NOT_FOUND)
1526 {
1527 /* If error other than a full buffer, then mark it "unsupported" to
1528 avoid reloading attempt */
1529 int hid = ERR_UNSUPPORTED_TYPE;
Nick Peskett02fd3142011-12-16 10:09:41 +00001530 struct cuesheet_file cue_file;
Michael Sevakisc537d592011-04-27 03:08:23 +00001531
1532#ifdef HAVE_IO_PRIORITY
1533 buf_back_off_storage(true);
1534#endif
Nick Peskett02fd3142011-12-16 10:09:41 +00001535 if (look_for_cuesheet_file(track_id3, &cue_file))
Michael Sevakisc537d592011-04-27 03:08:23 +00001536 {
1537 hid = bufalloc(NULL, sizeof (struct cuesheet), TYPE_CUESHEET);
1538
1539 if (hid >= 0)
1540 {
1541 void *cuesheet = NULL;
1542 bufgetdata(hid, sizeof (struct cuesheet), &cuesheet);
1543
Nick Peskett02fd3142011-12-16 10:09:41 +00001544 if (parse_cuesheet(&cue_file, (struct cuesheet *)cuesheet))
Michael Sevakisc537d592011-04-27 03:08:23 +00001545 {
1546 /* Indicate cuesheet is present (while track remains
1547 buffered) */
1548 track_id3->cuesheet = cue;
1549 }
1550 else
1551 {
1552 bufclose(hid);
1553 hid = ERR_UNSUPPORTED_TYPE;
1554 }
1555 }
1556 }
1557
1558#ifdef HAVE_IO_PRIORITY
1559 buf_back_off_storage(false);
1560#endif
1561 if (hid == ERR_BUFFER_FULL)
1562 {
1563 logf("buffer is full for now (%s)", __func__);
1564 return false;
1565 }
1566 else
1567 {
1568 if (hid < 0)
1569 logf("Cuesheet loading failed");
1570
1571 info->cuesheet_hid = hid;
1572 }
1573 }
Brandon Low31c11642007-11-04 19:01:02 +00001574
Nicolas Pennequin3e3c43c2007-10-25 21:27:45 +00001575 return true;
1576}
1577
Michael Sevakisc537d592011-04-27 03:08:23 +00001578#ifdef HAVE_ALBUMART
1579/* Load any album art for the file - returns false if the buffer is full */
1580static bool audio_load_albumart(struct track_info *info,
1581 struct mp3entry *track_id3)
1582{
1583 int i;
1584 FOREACH_ALBUMART(i)
1585 {
1586 struct bufopen_bitmap_data user_data;
1587 int *aa_hid = &info->aa_hid[i];
1588 int hid = ERR_UNSUPPORTED_TYPE;
Steve Bavin3cc46e72006-09-01 07:59:31 +00001589
Michael Sevakisc537d592011-04-27 03:08:23 +00001590 /* albumart_slots may change during a yield of bufopen,
1591 * but that's no problem */
1592 if (*aa_hid >= 0 || *aa_hid == ERR_UNSUPPORTED_TYPE ||
1593 !albumart_slots[i].used)
1594 continue;
1595
1596 memset(&user_data, 0, sizeof(user_data));
1597 user_data.dim = &albumart_slots[i].dim;
1598
1599#ifdef HAVE_IO_PRIORITY
1600 buf_back_off_storage(true);
1601#endif
1602
1603 /* We can only decode jpeg for embedded AA */
Alexander Levin63c4ef92011-12-22 18:48:43 +00001604 if (track_id3->has_embedded_albumart && track_id3->albumart.type == AA_TYPE_JPG)
Michael Sevakisc537d592011-04-27 03:08:23 +00001605 {
1606 user_data.embedded_albumart = &track_id3->albumart;
1607 hid = bufopen(track_id3->path, 0, TYPE_BITMAP, &user_data);
1608 }
1609
1610 if (hid < 0 && hid != ERR_BUFFER_FULL)
1611 {
1612 /* No embedded AA or it couldn't be loaded - try other sources */
1613 char path[MAX_PATH];
1614
1615 if (find_albumart(track_id3, path, sizeof(path),
1616 &albumart_slots[i].dim))
1617 {
1618 user_data.embedded_albumart = NULL;
1619 hid = bufopen(path, 0, TYPE_BITMAP, &user_data);
1620 }
1621 }
1622
1623#ifdef HAVE_IO_PRIORITY
1624 buf_back_off_storage(false);
1625#endif
1626 if (hid == ERR_BUFFER_FULL)
1627 {
1628 logf("buffer is full for now (%s)", __func__);
1629 return false;
1630 }
1631 else
1632 {
1633 /* If error other than a full buffer, then mark it "unsupported"
1634 to avoid reloading attempt */
1635 if (hid < 0)
1636 {
1637 logf("Album art loading failed");
1638 hid = ERR_UNSUPPORTED_TYPE;
1639 }
1640
1641 *aa_hid = hid;
1642 }
1643 }
1644
1645 return true;
1646}
1647#endif /* HAVE_ALBUMART */
1648
1649#ifdef HAVE_CODEC_BUFFERING
1650/* Load a codec for the file onto the buffer - assumes we're working from the
1651 currently loading track - not called for the current track */
Jeffrey Goode8cb4b362011-05-09 21:52:06 +00001652static bool audio_buffer_codec(struct track_info *track_info,
Michael Sevakisc537d592011-04-27 03:08:23 +00001653 struct mp3entry *track_id3)
1654{
1655 /* This will not be the current track -> it cannot be the first and the
1656 current track cannot be ahead of buffering -> there is a previous
1657 track entry which is either current or ahead of the current */
1658 struct track_info *prev_info = track_list_last(-1);
1659 struct mp3entry *prev_id3 = bufgetid3(prev_info->id3_hid);
1660
1661 /* If the previous codec is the same as this one, there is no need to
1662 put another copy of it on the file buffer (in other words, only
1663 buffer codecs at format transitions) */
1664 if (prev_id3)
1665 {
1666 int codt = get_audio_base_codec_type(track_id3->codectype);
1667 int prev_codt = get_audio_base_codec_type(prev_id3->codectype);
1668
1669 if (codt == prev_codt)
1670 {
1671 logf("Reusing prev. codec: %d", prev_id3->codectype);
1672 return true;
1673 }
1674 }
1675 /* else just load it (harmless) */
1676
1677 /* Load the codec onto the buffer if possible */
1678 const char *codec_fn = get_codec_filename(track_id3->codectype);
1679 if (!codec_fn)
1680 return false;
1681
1682 char codec_path[MAX_PATH+1]; /* Full path to codec */
1683 codec_get_full_path(codec_path, codec_fn);
1684
1685 track_info->codec_hid = bufopen(codec_path, 0, TYPE_CODEC, NULL);
1686
1687 if (track_info->codec_hid >= 0)
1688 {
1689 logf("Buffered codec: %d", afmt);
1690 return true;
1691 }
1692
1693 return false;
1694}
1695#endif /* HAVE_CODEC_BUFFERING */
1696
1697/* Load metadata for the next track (with bufopen). The rest of the track
1698 loading will be handled by audio_finish_load_track once the metadata has
1699 been actually loaded by the buffering thread.
1700
1701 Each track is arranged in the buffer as follows:
1702 <id3|[cuesheet|][album art|][codec|]audio>
1703
1704 The next will not be loaded until the previous succeeds if the buffer was
1705 full at the time. To put any metadata after audio would make those handles
1706 unmovable.
1707*/
1708static int audio_load_track(void)
1709{
1710 if (in_progress_id3_hid >= 0)
1711 {
1712 /* There must be an info pointer if the in-progress id3 is even there */
1713 struct track_info *info = track_list_last(0);
1714
1715 if (info->id3_hid == in_progress_id3_hid)
1716 {
1717 if (filling == STATE_FILLING)
1718 {
1719 /* Haven't finished the metadata but the notification is
1720 anticipated to come soon */
1721 logf("%s(): in progress ok: %d". __func__, info->id3_hid);
1722 return LOAD_TRACK_OK;
1723 }
1724 else if (filling == STATE_FULL)
1725 {
1726 /* Buffer was full trying to complete the load after the
1727 metadata finished, so attempt to continue - older handles
1728 should have been cleared already */
1729 logf("%s(): finishing load: %d". __func__, info->id3_hid);
1730 filling = STATE_FILLING;
1731 buffer_event_finished_callback(&info->id3_hid);
1732 return LOAD_TRACK_OK;
1733 }
1734 }
1735
1736 /* Some old, stray buffering message */
1737 logf("%s(): already in progress: %d". __func__, info->id3_hid);
1738 return LOAD_TRACK_ERR_BUSY;
1739 }
1740
1741 filling = STATE_FILLING;
1742
1743 struct track_info *info = track_list_alloc_track();
1744 if (info == NULL)
1745 {
1746 /* List is full so stop buffering tracks - however, attempt to obtain
1747 metadata as the unbuffered id3 */
1748 logf("No free tracks");
1749 filling = STATE_FULL;
1750 }
1751
1752 playlist_peek_offset++;
1753
1754 logf("Buffering track: s%u/c%u/e%u/p%d",
1755 track_list.start, track_list.current, track_list.end,
1756 playlist_peek_offset);
1757
1758 /* Get track name from current playlist read position */
1759 int fd = -1;
1760 char name_buf[MAX_PATH + 1];
1761 const char *trackname;
1762
1763 while (1)
1764 {
1765
1766 trackname = playlist_peek(playlist_peek_offset, name_buf,
1767 sizeof (name_buf));
1768
1769 if (!trackname)
1770 break;
1771
1772 /* Test for broken playlists by probing for the files */
1773 fd = open(trackname, O_RDONLY);
1774 if (fd >= 0)
1775 break;
1776
1777 logf("Open failed");
1778 /* Skip invalid entry from playlist */
1779 playlist_skip_entry(NULL, playlist_peek_offset);
1780
1781 /* Sync the playlist if it isn't finished */
1782 if (playlist_peek(playlist_peek_offset, NULL, 0))
1783 playlist_next(0);
1784 }
1785
1786 if (!trackname)
1787 {
1788 /* No track - exhausted the playlist entries */
1789 logf("End-of-playlist");
1790 id3_write_locked(UNBUFFERED_ID3, NULL);
1791
1792 if (filling != STATE_FULL)
1793 track_list_unalloc_track(); /* Free this entry */
1794
1795 playlist_peek_offset--; /* Maintain at last index */
1796
1797 /* We can end up here after the real last track signals its completion
1798 and miss the transition to STATE_FINISHED esp. if dropping the last
1799 songs of a playlist late in their load (2nd stage) */
1800 info = track_list_last(0);
1801
1802 if (info && buf_handle_remaining(info->audio_hid) == 0)
1803 filling_is_finished();
1804 else
1805 filling = STATE_END_OF_PLAYLIST;
1806
1807 return LOAD_TRACK_ERR_NO_MORE;
1808 }
1809
1810 /* Successfully opened the file - get track metadata */
1811 if (filling == STATE_FULL ||
1812 (info->id3_hid = bufopen(trackname, 0, TYPE_ID3, NULL)) < 0)
1813 {
1814 /* Buffer or track list is full */
1815 struct mp3entry *ub_id3;
1816
1817 playlist_peek_offset--;
1818
1819 /* Load the metadata for the first unbuffered track */
1820 ub_id3 = id3_get(UNBUFFERED_ID3);
1821 id3_mutex_lock();
1822 get_metadata(ub_id3, fd, trackname);
1823 id3_mutex_unlock();
1824
1825 if (filling != STATE_FULL)
1826 {
1827 track_list_unalloc_track();
1828 filling = STATE_FULL;
1829 }
1830
1831 logf("%s: buffer is full for now (%u tracks)", __func__,
1832 track_list_count());
1833 }
1834 else
1835 {
1836 /* Successful load initiation */
1837 info->filesize = filesize(fd);
1838 in_progress_id3_hid = info->id3_hid; /* Remember what's in-progress */
1839 }
1840
1841 close(fd);
1842 return LOAD_TRACK_OK;
1843}
1844
1845/* Second part of the track loading: We now have the metadata available, so we
1846 can load the codec, the album art and finally the audio data.
1847 This is called on the audio thread after the buffering thread calls the
1848 buffering_handle_finished_callback callback. */
1849static int audio_finish_load_track(struct track_info *info)
1850{
1851 int trackstat = LOAD_TRACK_OK;
1852
1853 if (info->id3_hid != in_progress_id3_hid)
1854 {
1855 /* We must not be here if not! */
1856 logf("%s: wrong track %d/%d", __func__, info->id3_hid,
1857 in_progress_id3_hid);
1858 return LOAD_TRACK_ERR_BUSY;
1859 }
1860
1861 /* The current track for decoding (there is always one if the list is
1862 populated) */
1863 struct track_info *cur_info = track_list_current(0);
1864 struct mp3entry *track_id3 = valid_mp3entry(bufgetid3(info->id3_hid));
1865
1866 if (!track_id3)
1867 {
1868 /* This is an error condition. Track cannot be played without valid
1869 metadata; skip the track. */
Steve Bavin89ee9222011-08-26 15:46:18 +00001870 logf("No metadata");
Michael Sevakisc537d592011-04-27 03:08:23 +00001871 trackstat = LOAD_TRACK_ERR_FINISH_FAILED;
1872 goto audio_finish_load_track_exit;
1873 }
1874
1875 /* Try to load a cuesheet for the track */
1876 if (!audio_load_cuesheet(info, track_id3))
1877 {
1878 /* No space for cuesheet on buffer, not an error */
1879 filling = STATE_FULL;
1880 goto audio_finish_load_track_exit;
1881 }
1882
1883#ifdef HAVE_ALBUMART
1884 /* Try to load album art for the track */
1885 if (!audio_load_albumart(info, track_id3))
1886 {
1887 /* No space for album art on buffer, not an error */
1888 filling = STATE_FULL;
1889 goto audio_finish_load_track_exit;
1890 }
1891#endif
1892
Michael Sevakiscaf907e2011-05-25 08:35:31 +00001893 /* All handles available to external routines are ready - audio and codec
1894 information is private */
1895
1896 if (info == track_list_user_current(0))
1897 {
1898 /* Send only when the track handles could not all be opened ahead of
1899 time for the user's current track - otherwise everything is ready
1900 by the time PLAYBACK_EVENT_TRACK_CHANGE is sent */
1901 send_event(PLAYBACK_EVENT_CUR_TRACK_READY, id3_get(PLAYING_ID3));
1902 }
1903
Michael Sevakisc537d592011-04-27 03:08:23 +00001904#ifdef HAVE_CODEC_BUFFERING
1905 /* Try to buffer a codec for the track */
1906 if (info != cur_info && !audio_buffer_codec(info, track_id3))
1907 {
1908 if (info->codec_hid == ERR_BUFFER_FULL)
1909 {
1910 /* No space for codec on buffer, not an error */
1911 filling = STATE_FULL;
1912 logf("buffer is full for now (%s)", __func__);
1913 }
1914 else
1915 {
1916 /* This is an error condition, either no codec was found, or
1917 reading the codec file failed part way through, either way,
1918 skip the track */
1919 logf("No codec for: %s", track_id3->path);
1920 trackstat = LOAD_TRACK_ERR_FINISH_FAILED;
1921 }
1922
1923 goto audio_finish_load_track_exit;
1924 }
1925#endif /* HAVE_CODEC_BUFFERING */
1926
1927 /** Finally, load the audio **/
1928 size_t file_offset = 0;
1929 track_id3->elapsed = 0;
1930
1931 if (track_id3->offset >= info->filesize)
1932 track_id3->offset = 0;
1933
1934 logf("%s: set offset for %s to %lu\n", __func__,
1935 id3->title, (unsigned long)offset);
1936
1937 /* Adjust for resume rewind so we know what to buffer - starting the codec
1938 calls it again, so we don't save it (and they shouldn't accumulate) */
1939 size_t offset = resume_rewind_adjusted_offset(track_id3);
1940
Sean Bartellfe3d5802011-08-12 01:27:13 -04001941 enum data_type audiotype = rbcodec_format_is_atomic(track_id3->codectype) ?
1942 TYPE_ATOMIC_AUDIO : TYPE_PACKET_AUDIO;
Michael Sevakisc537d592011-04-27 03:08:23 +00001943
1944 if (audiotype == TYPE_ATOMIC_AUDIO)
1945 logf("Loading atomic %d", track_id3->codectype);
1946
1947 if (format_buffers_with_offset(track_id3->codectype))
1948 {
1949 /* This format can begin buffering from any point */
1950 file_offset = offset;
1951 }
1952
1953 logf("load track: %s", track_id3->path);
1954
1955 if (file_offset > AUDIO_REBUFFER_GUESS_SIZE)
1956 {
1957 /* We can buffer later in the file, adjust the hunt-and-peck margin */
1958 file_offset -= AUDIO_REBUFFER_GUESS_SIZE;
1959 }
1960 else
1961 {
1962 /* No offset given or it is very minimal - begin at the first frame
1963 according to the metadata */
1964 file_offset = track_id3->first_frame_offset;
1965 }
1966
1967 int hid = bufopen(track_id3->path, file_offset, audiotype, NULL);
1968
1969 if (hid >= 0)
1970 {
1971 info->audio_hid = hid;
1972
1973 if (info == cur_info)
1974 {
1975 /* This is the current track to decode - should be started now */
1976 trackstat = LOAD_TRACK_READY;
1977 }
1978 }
1979 else
1980 {
1981 /* Buffer could be full but not properly so if this is the only
1982 track! */
1983 if (hid == ERR_BUFFER_FULL && audio_track_count() > 1)
1984 {
1985 filling = STATE_FULL;
1986 logf("Buffer is full for now (%s)", __func__);
1987 }
1988 else
1989 {
1990 /* Nothing to play if no audio handle - skip this */
1991 logf("Could not add audio data handle");
1992 trackstat = LOAD_TRACK_ERR_FINISH_FAILED;
1993 }
1994 }
1995
1996audio_finish_load_track_exit:
1997 if (trackstat < LOAD_TRACK_OK)
1998 {
1999 playlist_skip_entry(NULL, playlist_peek_offset);
2000 track_info_close(info);
2001 track_list_unalloc_track();
2002
2003 if (playlist_peek(playlist_peek_offset, NULL, 0))
2004 playlist_next(0);
2005
2006 playlist_peek_offset--;
2007 }
2008
2009 if (filling != STATE_FULL)
2010 {
2011 /* Load next track - error or not */
2012 in_progress_id3_hid = ERR_HANDLE_NOT_FOUND;
2013 LOGFQUEUE("audio > audio Q_AUDIO_FILL_BUFFER");
2014 audio_queue_post(Q_AUDIO_FILL_BUFFER, 0);
2015 }
2016 else
2017 {
2018 /* Full */
2019 trackstat = LOAD_TRACK_ERR_FINISH_FULL;
2020 }
2021
2022 return trackstat;
2023}
2024
2025/* Start a new track load */
2026static int audio_fill_file_buffer(void)
2027{
2028 if (play_status == PLAY_STOPPED)
2029 return LOAD_TRACK_ERR_FAILED;
2030
Thomas Martitz4c5f5ef2011-09-19 20:52:00 +00002031 trigger_cpu_boost();
2032
2033 /* Must reset the buffer before use if trashed or voice only - voice
2034 file size shouldn't have changed so we can go straight from
2035 AUDIOBUF_STATE_VOICED_ONLY to AUDIOBUF_STATE_INITIALIZED */
2036 if (buffer_state != AUDIOBUF_STATE_INITIALIZED)
Michael Sevakisda6cebb2012-05-02 17:22:28 -04002037 audio_reset_buffer(AUDIOBUF_STATE_INITIALIZED);
Thomas Martitz4c5f5ef2011-09-19 20:52:00 +00002038
Michael Sevakisc537d592011-04-27 03:08:23 +00002039 logf("Starting buffer fill");
2040
2041 int trackstat = audio_load_track();
2042
2043 if (trackstat >= LOAD_TRACK_OK)
2044 {
2045 if (track_list_current(0) == track_list_user_current(0))
2046 playlist_next(0);
2047
2048 if (filling == STATE_FULL && !track_list_user_current(1))
2049 {
2050 /* There are no user tracks on the buffer after this therefore
2051 this is the next track */
2052 audio_update_and_announce_next_track(id3_get(UNBUFFERED_ID3));
2053 }
2054 }
2055
2056 return trackstat;
2057}
2058
2059/* Discard unwanted tracks and start refill from after the specified playlist
2060 offset */
2061static int audio_reset_and_rebuffer(
2062 enum track_clear_action action, int peek_offset)
2063{
2064 logf("Forcing rebuffer: 0x%X, %d", flags, peek_offset);
2065
2066 id3_write_locked(UNBUFFERED_ID3, NULL);
2067
2068 /* Remove unwanted tracks - caller must have ensured codec isn't using
2069 any */
2070 track_list_clear(action);
2071
2072 /* Refill at specified position (-1 starts at index offset 0) */
2073 playlist_peek_offset = peek_offset;
2074
2075 /* Fill the buffer */
2076 return audio_fill_file_buffer();
2077}
2078
2079/* Handle buffering events
2080 (Q_AUDIO_BUFFERING) */
2081static void audio_on_buffering(int event)
2082{
2083 enum track_clear_action action;
2084 int peek_offset;
2085
2086 if (track_list_empty())
2087 return;
Jeffrey Goode8cb4b362011-05-09 21:52:06 +00002088
Michael Sevakisc537d592011-04-27 03:08:23 +00002089 switch (event)
2090 {
2091 case BUFFER_EVENT_BUFFER_LOW:
2092 if (filling != STATE_FULL && filling != STATE_END_OF_PLAYLIST)
2093 return; /* Should be nothing left to fill */
2094
2095 /* Clear old tracks and continue buffering where it left off */
2096 action = TRACK_LIST_KEEP_NEW;
2097 peek_offset = playlist_peek_offset;
2098 break;
2099
2100 case BUFFER_EVENT_REBUFFER:
2101 /* Remove all but the currently decoding track and redo buffering
2102 after that */
2103 action = TRACK_LIST_KEEP_CURRENT;
2104 peek_offset = (skip_pending == TRACK_SKIP_AUTO) ? 1 : 0;
2105 break;
2106
2107 default:
2108 return;
2109 }
2110
2111 switch (skip_pending)
2112 {
2113 case TRACK_SKIP_NONE:
2114 case TRACK_SKIP_AUTO:
2115 case TRACK_SKIP_AUTO_NEW_PLAYLIST:
2116 audio_reset_and_rebuffer(action, peek_offset);
2117 break;
2118
2119 case TRACK_SKIP_AUTO_END_PLAYLIST:
2120 /* Already finished */
2121 break;
2122
2123 default:
2124 /* Invalid */
2125 logf("Buffering call, inv. state: %d", (int)skip_pending);
2126 }
2127}
2128
2129/* Handle starting the next track load
2130 (Q_AUDIO_FILL_BUFFER) */
2131static void audio_on_fill_buffer(void)
2132{
2133 audio_handle_track_load_status(audio_fill_file_buffer());
2134}
2135
2136/* Handle posted load track finish event
2137 (Q_AUDIO_FINISH_LOAD_TRACK) */
2138static void audio_on_finish_load_track(int id3_hid)
2139{
2140 struct track_info *info = track_list_last(0);
2141
2142 if (!info || !buf_is_handle(id3_hid))
2143 return;
2144
2145 if (info == track_list_user_current(1))
2146 {
2147 /* Just loaded the metadata right after the current position */
2148 audio_update_and_announce_next_track(bufgetid3(info->id3_hid));
2149 }
2150
2151 if (audio_finish_load_track(info) != LOAD_TRACK_READY)
2152 return; /* Not current track */
2153
2154 bool is_user_current = info == track_list_user_current(0);
2155
2156 if (is_user_current)
2157 {
2158 /* Copy cuesheet */
2159 buf_read_cuesheet(info->cuesheet_hid);
2160 }
2161
2162 if (audio_start_codec(automatic_skip))
2163 {
2164 if (is_user_current)
2165 {
2166 /* Be sure all tagtree info is synchronized; it will be needed for the
2167 track finish event - the sync will happen when finalizing a track
2168 change otherwise */
2169 bool was_valid = valid_mp3entry(id3_get(PLAYING_ID3));
2170
2171 playing_id3_sync(info, -1);
2172
2173 if (!was_valid)
2174 {
2175 /* Playing id3 hadn't been updated yet because no valid track
2176 was yet available - treat like the first track */
2177 audio_playlist_track_change();
2178 }
2179 }
2180 }
2181 else
2182 {
2183 audio_handle_track_load_status(LOAD_TRACK_ERR_START_CODEC);
2184 }
2185}
2186
2187/* Called when handles other than metadata handles have finished buffering
2188 (Q_AUDIO_HANDLE_FINISHED) */
2189static void audio_on_handle_finished(int hid)
2190{
2191 /* Right now, only audio handles should end up calling this */
2192 if (filling == STATE_END_OF_PLAYLIST)
2193 {
2194 struct track_info *info = track_list_last(0);
2195
2196 /* Really we don't know which order the handles will actually complete
2197 to zero bytes remaining since another thread is doing it - be sure
2198 it's the right one */
2199 if (info && info->audio_hid == hid)
2200 {
2201 /* This was the last track in the playlist and we now have all the
2202 data we need */
2203 filling_is_finished();
2204 }
2205 }
2206}
2207
2208/* Called to make an outstanding track skip the current track and to send the
2209 transition events */
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00002210static void audio_finalise_track_change(void)
Michael Sevakisc537d592011-04-27 03:08:23 +00002211{
2212 switch (skip_pending)
2213 {
2214 case TRACK_SKIP_NONE: /* Manual skip */
2215 break;
2216
2217 case TRACK_SKIP_AUTO:
2218 case TRACK_SKIP_AUTO_NEW_PLAYLIST:
2219 {
2220 int playlist_delta = skip_pending == TRACK_SKIP_AUTO ? 1 : 0;
2221 audio_playlist_track_finish();
2222
2223 if (!playlist_peek(playlist_delta, NULL, 0))
2224 {
2225 /* Track ended up rejected - push things ahead like the codec blew
2226 it (because it was never started and now we're here where it
2227 should have been decoding the next track by now) - next, a
2228 directory change or end of playback will most likely happen */
2229 skip_pending = TRACK_SKIP_NONE;
2230 audio_handle_track_load_status(LOAD_TRACK_ERR_START_CODEC);
2231 return;
2232 }
2233
2234 if (!playlist_delta)
2235 break;
2236
2237 playlist_peek_offset -= playlist_delta;
2238 if (playlist_next(playlist_delta) >= 0)
2239 break;
2240 /* What!? Disappear? Hopeless bleak despair */
2241 }
2242 /* Fallthrough */
2243 case TRACK_SKIP_AUTO_END_PLAYLIST:
2244 default: /* Invalid */
2245 filling = STATE_ENDED;
2246 audio_stop_playback();
2247 return;
2248 }
2249
2250 struct track_info *info = track_list_current(0);
2251 struct mp3entry *track_id3 = NULL;
2252
2253 id3_mutex_lock();
2254
2255 /* Update the current cuesheet if any and enabled */
2256 if (info)
2257 {
2258 buf_read_cuesheet(info->cuesheet_hid);
2259 track_id3 = bufgetid3(info->id3_hid);
2260 }
2261
2262 id3_write(PLAYING_ID3, track_id3);
2263
Michael Sevakisc537d592011-04-27 03:08:23 +00002264 /* The skip is technically over */
2265 skip_pending = TRACK_SKIP_NONE;
2266
2267 /* Sync the next track information */
2268 info = track_list_current(1);
2269
2270 id3_write(NEXTTRACK_ID3, info ? bufgetid3(info->id3_hid) :
2271 id3_get(UNBUFFERED_ID3));
2272
2273 id3_mutex_unlock();
2274
2275 audio_playlist_track_change();
2276}
2277
2278/* Actually begin a transition and take care of the codec change - may complete
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00002279 it now or ask pcmbuf for notification depending on the type */
2280static void audio_begin_track_change(enum pcm_track_change_type type,
2281 int trackstat)
Michael Sevakisc537d592011-04-27 03:08:23 +00002282{
2283 /* Even if the new track is bad, the old track must be finished off */
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00002284 pcmbuf_start_track_change(type);
Michael Sevakisc537d592011-04-27 03:08:23 +00002285
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00002286 bool auto_skip = type != TRACK_CHANGE_MANUAL;
2287
2288 if (!auto_skip)
Michael Sevakisc537d592011-04-27 03:08:23 +00002289 {
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00002290 /* Manual track change happens now */
2291 audio_finalise_track_change();
2292 pcmbuf_sync_position_update();
Michael Sevakisc537d592011-04-27 03:08:23 +00002293
2294 if (play_status == PLAY_STOPPED)
2295 return; /* Stopped us */
2296 }
2297
Michael Sevakisc537d592011-04-27 03:08:23 +00002298 if (trackstat >= LOAD_TRACK_OK)
2299 {
2300 struct track_info *info = track_list_current(0);
2301
2302 if (info->audio_hid < 0)
2303 return;
2304
2305 /* Everything needed for the codec is ready - start it */
2306 if (audio_start_codec(auto_skip))
2307 {
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00002308 if (!auto_skip)
Michael Sevakisc537d592011-04-27 03:08:23 +00002309 playing_id3_sync(info, -1);
2310 return;
2311 }
2312
2313 trackstat = LOAD_TRACK_ERR_START_CODEC;
2314 }
2315
2316 audio_handle_track_load_status(trackstat);
2317}
2318
2319/* Transition to end-of-playlist state and begin wait for PCM to finish */
2320static void audio_monitor_end_of_playlist(void)
2321{
2322 skip_pending = TRACK_SKIP_AUTO_END_PLAYLIST;
2323 filling = STATE_ENDING;
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00002324 pcmbuf_start_track_change(TRACK_CHANGE_END_OF_DATA);
Michael Sevakisc537d592011-04-27 03:08:23 +00002325}
2326
2327/* Codec has completed decoding the track
2328 (usually Q_AUDIO_CODEC_COMPLETE) */
2329static void audio_on_codec_complete(int status)
2330{
2331 logf("%s(%d)", __func__, status);
2332
2333 if (play_status == PLAY_STOPPED)
2334 return;
2335
2336 /* If it didn't notify us first, don't expect "seek complete" message
2337 since the codec can't post it now - do things like it would have
2338 done */
2339 audio_complete_codec_seek();
2340
2341 if (play_status == PLAY_PAUSED || skip_pending != TRACK_SKIP_NONE)
2342 {
2343 /* Old-hay on the ip-skay - codec has completed decoding
2344
2345 Paused: We're not sounding it, so just remember that it happened
2346 and the resume will begin the transition
2347
2348 Skipping: There was already a skip in progress, remember it and
2349 allow no further progress until the PCM from the previous
2350 song has finished
2351 */
2352 codec_skip_pending = true;
2353 codec_skip_status = status;
2354 return;
2355 }
2356
2357 codec_skip_pending = false;
2358
Michael Sevakisc537d592011-04-27 03:08:23 +00002359 int trackstat = LOAD_TRACK_OK;
2360
2361 automatic_skip = true;
2362 skip_pending = TRACK_SKIP_AUTO;
2363
2364 /* Does this track have an entry allocated? */
2365 struct track_info *info = track_list_advance_current(1);
2366
2367 if (!info || info->audio_hid < 0)
2368 {
2369 bool end_of_playlist = false;
2370
2371 if (info)
2372 {
2373 /* Track load is not complete - it might have stopped on a
2374 full buffer without reaching the audio handle or we just
2375 arrived at it early
2376
2377 If this type is atomic and we couldn't get the audio,
2378 perhaps it would need to wrap to make the allocation and
2379 handles are in the way - to maximize the liklihood it can
2380 be allocated, clear all handles to reset the buffer and
2381 its indexes to 0 - for packet audio, this should not be an
2382 issue and a pointless full reload of all the track's
2383 metadata may be avoided */
2384
2385 struct mp3entry *track_id3 = bufgetid3(info->id3_hid);
2386
Sean Bartellfe3d5802011-08-12 01:27:13 -04002387 if (track_id3 && !rbcodec_format_is_atomic(track_id3->codectype))
Michael Sevakisc537d592011-04-27 03:08:23 +00002388 {
2389 /* Continue filling after this track */
2390 audio_reset_and_rebuffer(TRACK_LIST_KEEP_CURRENT, 1);
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00002391 audio_begin_track_change(TRACK_CHANGE_AUTO, trackstat);
Michael Sevakisc537d592011-04-27 03:08:23 +00002392 return;
2393 }
2394 /* else rebuffer at this track; status applies to the track we
2395 want */
2396 }
2397 else if (!playlist_peek(1, NULL, 0))
2398 {
2399 /* Play sequence is complete - directory change or other playlist
2400 resequencing - the playlist must now be advanced in order to
2401 continue since a peek ahead to the next track is not possible */
2402 skip_pending = TRACK_SKIP_AUTO_NEW_PLAYLIST;
2403 end_of_playlist = playlist_next(1) < 0;
2404 }
2405
2406 if (!end_of_playlist)
2407 {
2408 trackstat = audio_reset_and_rebuffer(TRACK_LIST_CLEAR_ALL,
2409 skip_pending == TRACK_SKIP_AUTO ? 0 : -1);
2410
2411 if (trackstat == LOAD_TRACK_ERR_NO_MORE)
2412 {
Jeffrey Goode8cb4b362011-05-09 21:52:06 +00002413 /* Failed to find anything after all - do playlist switchover
Michael Sevakisc537d592011-04-27 03:08:23 +00002414 instead */
2415 skip_pending = TRACK_SKIP_AUTO_NEW_PLAYLIST;
2416 end_of_playlist = playlist_next(1) < 0;
2417 }
2418 }
2419
2420 if (end_of_playlist)
2421 {
2422 audio_monitor_end_of_playlist();
2423 return;
2424 }
2425 }
2426
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00002427 audio_begin_track_change(TRACK_CHANGE_AUTO, trackstat);
Michael Sevakisc537d592011-04-27 03:08:23 +00002428}
2429
2430/* Called when codec completes seek operation
2431 (usually Q_AUDIO_CODEC_SEEK_COMPLETE) */
2432static void audio_on_codec_seek_complete(void)
2433{
2434 logf("%s()", __func__);
2435 audio_complete_codec_seek();
2436 codec_go();
2437}
2438
2439/* Called when PCM track change has completed
2440 (Q_AUDIO_TRACK_CHANGED) */
2441static void audio_on_track_changed(void)
2442{
2443 /* Finish whatever is pending so that the WPS is in sync */
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00002444 audio_finalise_track_change();
Michael Sevakisc537d592011-04-27 03:08:23 +00002445
2446 if (codec_skip_pending)
2447 {
2448 /* Codec got ahead completing a short track - complete the
2449 codec's skip and begin the next */
2450 codec_skip_pending = false;
2451 audio_on_codec_complete(codec_skip_status);
2452 }
2453}
2454
2455/* Begin playback from an idle state, transition to a new playlist or
2456 invalidate the buffer and resume (if playing).
2457 (usually Q_AUDIO_PLAY, Q_AUDIO_REMAKE_AUDIO_BUFFER) */
2458static void audio_start_playback(size_t offset, unsigned int flags)
2459{
2460 enum play_status old_status = play_status;
2461
2462 if (flags & AUDIO_START_NEWBUF)
2463 {
2464 /* Mark the buffer dirty - if not playing, it will be reset next
2465 time */
2466 if (buffer_state == AUDIOBUF_STATE_INITIALIZED)
2467 buffer_state = AUDIOBUF_STATE_VOICED_ONLY;
2468 }
2469
2470 if (old_status != PLAY_STOPPED)
2471 {
2472 logf("%s(%lu): skipping", __func__, (unsigned long)offset);
2473
2474 halt_decoding_track(true);
2475
2476 automatic_skip = false;
2477 ff_rw_mode = false;
2478
2479 if (flags & AUDIO_START_RESTART)
2480 {
2481 /* Clear out some stuff to resume the current track where it
2482 left off */
2483 pcmbuf_play_stop();
2484 offset = id3_get(PLAYING_ID3)->offset;
2485 track_list_clear(TRACK_LIST_CLEAR_ALL);
2486 }
2487 else
2488 {
2489 /* This is more-or-less treated as manual track transition */
2490 /* Save resume information for current track */
2491 audio_playlist_track_finish();
2492 track_list_clear(TRACK_LIST_CLEAR_ALL);
2493
2494 /* Indicate manual track change */
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00002495 pcmbuf_start_track_change(TRACK_CHANGE_MANUAL);
Michael Sevakisc537d592011-04-27 03:08:23 +00002496 wipe_track_metadata(true);
2497 }
2498
2499 /* Set after track finish event in case skip was in progress */
2500 skip_pending = TRACK_SKIP_NONE;
2501 }
2502 else
2503 {
2504 if (flags & AUDIO_START_RESTART)
2505 return; /* Must already be playing */
2506
2507 /* Cold playback start from a stopped state */
2508 logf("%s(%lu): starting", __func__, offset);
2509
2510 /* Set audio parameters */
2511#if INPUT_SRC_CAPS != 0
2512 audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
2513 audio_set_output_source(AUDIO_SRC_PLAYBACK);
2514#endif
2515#ifndef PLATFORM_HAS_VOLUME_CHANGE
2516 sound_set_volume(global_settings.volume);
2517#endif
Michael Sevakisa2b67032011-06-29 06:37:04 +00002518 /* Be sure channel is audible */
2519 pcmbuf_fade(false, true);
2520
Michael Sevakisc537d592011-04-27 03:08:23 +00002521 /* Update our state */
2522 play_status = PLAY_PLAYING;
2523 }
2524
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00002525 /* Codec's position should be available as soon as it knows it */
2526 position_key = pcmbuf_get_position_key();
2527 pcmbuf_sync_position_update();
2528
Michael Sevakisc537d592011-04-27 03:08:23 +00002529 /* Start fill from beginning of playlist */
2530 playlist_peek_offset = -1;
2531 buf_set_base_handle(-1);
2532
2533 /* Officially playing */
2534 queue_reply(&audio_queue, 1);
2535
2536 /* Add these now - finish event for the first id3 will most likely be sent
2537 immediately */
2538 add_event(BUFFER_EVENT_REBUFFER, false, buffer_event_rebuffer_callback);
2539 add_event(BUFFER_EVENT_FINISHED, false, buffer_event_finished_callback);
2540
2541 if (old_status == PLAY_STOPPED)
2542 {
2543 /* Send coldstart event */
2544 send_event(PLAYBACK_EVENT_START_PLAYBACK, NULL);
2545 }
2546
Thomas Martitz4c5f5ef2011-09-19 20:52:00 +00002547 /* Fill the buffer */
Michael Sevakisc537d592011-04-27 03:08:23 +00002548 int trackstat = audio_fill_file_buffer();
2549
2550 if (trackstat >= LOAD_TRACK_OK)
2551 {
2552 /* This is the currently playing track - get metadata, stat */
2553 playing_id3_sync(track_list_current(0), offset);
2554
2555 if (valid_mp3entry(id3_get(PLAYING_ID3)))
2556 {
2557 /* Only if actually changing tracks... */
2558 if (!(flags & AUDIO_START_RESTART))
2559 audio_playlist_track_change();
2560 }
2561 }
2562 else
2563 {
2564 /* Found nothing playable */
2565 audio_handle_track_load_status(trackstat);
2566 }
2567}
2568
2569/* Stop playback and enter an idle state
2570 (usually Q_AUDIO_STOP) */
2571static void audio_stop_playback(void)
2572{
2573 logf("%s()", __func__);
2574
2575 if (play_status == PLAY_STOPPED)
2576 return;
2577
Michael Sevakis5078d462011-08-23 01:37:59 +00002578 bool do_fade = global_settings.fade_on_stop && filling != STATE_ENDED;
2579
2580 pcmbuf_fade(do_fade, false);
2581
2582 /* Wait for fade-out */
2583 audio_wait_fade_complete();
Michael Sevakisa2b67032011-06-29 06:37:04 +00002584
Michael Sevakisc537d592011-04-27 03:08:23 +00002585 /* Stop the codec and unload it */
2586 halt_decoding_track(true);
2587 pcmbuf_play_stop();
2588 codec_unload();
2589
2590 /* Save resume information - "filling" might have been set to
2591 "STATE_ENDED" by caller in order to facilitate end of playlist */
2592 audio_playlist_track_finish();
2593
2594 skip_pending = TRACK_SKIP_NONE;
2595 automatic_skip = false;
2596
2597 /* Close all tracks and mark them NULL */
2598 remove_event(BUFFER_EVENT_REBUFFER, buffer_event_rebuffer_callback);
2599 remove_event(BUFFER_EVENT_FINISHED, buffer_event_finished_callback);
2600 remove_event(BUFFER_EVENT_BUFFER_LOW, buffer_event_buffer_low_callback);
2601
2602 track_list_clear(TRACK_LIST_CLEAR_ALL);
2603
2604 /* Update our state */
2605 ff_rw_mode = false;
2606 play_status = PLAY_STOPPED;
2607
2608 wipe_track_metadata(true);
2609
2610 /* Go idle */
2611 filling = STATE_IDLE;
2612 cancel_cpu_boost();
2613}
2614
2615/* Pause the playback of the current track
2616 (Q_AUDIO_PAUSE) */
2617static void audio_on_pause(bool pause)
2618{
2619 logf("%s(%s)", __func__, pause ? "true" : "false");
2620
2621 if (play_status == PLAY_STOPPED || pause == (play_status == PLAY_PAUSED))
2622 return;
2623
Michael Sevakisc537d592011-04-27 03:08:23 +00002624 play_status = pause ? PLAY_PAUSED : PLAY_PLAYING;
2625
2626 if (!pause && codec_skip_pending)
2627 {
2628 /* Actually do the skip that is due - resets the status flag */
2629 audio_on_codec_complete(codec_skip_status);
2630 }
Michael Sevakis5078d462011-08-23 01:37:59 +00002631
2632 bool do_fade = global_settings.fade_on_stop;
2633
2634 pcmbuf_fade(do_fade, !pause);
2635
2636 if (!ff_rw_mode && !(do_fade && pause))
2637 {
2638 /* Not in ff/rw mode - can actually change the audio state now */
2639 pcmbuf_pause(pause);
2640 }
Michael Sevakisc537d592011-04-27 03:08:23 +00002641}
2642
2643/* Skip a certain number of tracks forwards or backwards
2644 (Q_AUDIO_SKIP) */
2645static void audio_on_skip(void)
2646{
2647 id3_mutex_lock();
2648
2649 /* Eat the delta to keep it synced, even if not playing */
2650 int toskip = skip_offset;
2651 skip_offset = 0;
2652
2653 logf("%s(): %d", __func__, toskip);
2654
2655 id3_mutex_unlock();
2656
2657 if (play_status == PLAY_STOPPED)
2658 return;
2659
2660 /* Force codec to abort this track */
2661 halt_decoding_track(true);
2662
2663 /* Kill the ff/rw halt */
2664 ff_rw_mode = false;
2665
2666 /* Manual skip */
2667 automatic_skip = false;
2668
2669 /* If there was an auto skip in progress, there will be residual
2670 advancement of the playlist and/or track list so compensation will be
2671 required in order to end up in the right spot */
2672 int track_list_delta = toskip;
2673 int playlist_delta = toskip;
2674
2675 if (skip_pending != TRACK_SKIP_NONE)
2676 {
2677 if (skip_pending != TRACK_SKIP_AUTO_END_PLAYLIST)
2678 track_list_delta--;
2679
2680 if (skip_pending == TRACK_SKIP_AUTO_NEW_PLAYLIST)
2681 playlist_delta--;
2682 }
2683
2684 audio_playlist_track_finish();
2685 skip_pending = TRACK_SKIP_NONE;
2686