blob: 7dad08644a4da9350698917564e5e266a3c6a168 [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"
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +000027#include "buffer.h"
Michael Sevakisc537d592011-04-27 03:08:23 +000028#include "sound.h"
29#include "ata.h"
30#include "usb.h"
31#include "codecs.h"
32#include "codec_thread.h"
33#include "voice_thread.h"
34#include "metadata.h"
Nicolas Pennequin9f4bd872007-02-14 14:40:24 +000035#include "cuesheet.h"
Michael Sevakisc537d592011-04-27 03:08:23 +000036#include "buffering.h"
37#include "talk.h"
38#include "playlist.h"
39#include "abrepeat.h"
40#include "pcmbuf.h"
41#include "playback.h"
Michael Sevakisa2b67032011-06-29 06:37:04 +000042#include "misc.h"
Michael Sevakisc537d592011-04-27 03:08:23 +000043
Jonathan Gordon710ccb72006-10-25 10:17:57 +000044#ifdef HAVE_TAGCACHE
Miika Pekkarinenb7251262006-03-26 16:37:18 +000045#include "tagcache.h"
Jonathan Gordon710ccb72006-10-25 10:17:57 +000046#endif
Michael Sevakisc537d592011-04-27 03:08:23 +000047
48#ifdef AUDIO_HAVE_RECORDING
49#include "pcm_record.h"
50#endif
51
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +000052#ifdef HAVE_LCD_BITMAP
Thomas Martitze9c10182009-10-16 19:14:41 +000053#ifdef HAVE_ALBUMART
Nicolas Pennequin9d4bed72007-11-11 12:29:37 +000054#include "albumart.h"
Thomas Martitze9c10182009-10-16 19:14:41 +000055#endif
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +000056#endif
Michael Sevakis4fc717a2006-08-28 22:38:41 +000057
Michael Sevakisc537d592011-04-27 03:08:23 +000058/* TODO: The audio thread really is doing multitasking of acting like a
59 consumer and producer of tracks. It may be advantageous to better
60 logically separate the two functions. I won't go that far just yet. */
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +000061
Michael Sevakisc537d592011-04-27 03:08:23 +000062/* Internal support for voice playback */
Miika Pekkarinen815684a2006-09-17 08:34:42 +000063#define PLAYBACK_VOICE
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +000064
Michael Sevakisc537d592011-04-27 03:08:23 +000065#if CONFIG_PLATFORM & PLATFORM_NATIVE
66/* Application builds don't support direct code loading */
67#define HAVE_CODEC_BUFFERING
68#endif
69
70/* Amount of guess-space to allow for codecs that must hunt and peck
71 * for their correct seek target, 32k seems a good size */
Brandon Low62ccbbb2006-04-11 03:55:58 +000072#define AUDIO_REBUFFER_GUESS_SIZE (1024*32)
Linus Nielsen Feltzing1c497e62005-06-05 23:05:10 +000073
Nicolas Pennequinfb709522007-10-24 22:06:36 +000074/* Define LOGF_ENABLE to enable logf output in this file */
Michael Sevakisc537d592011-04-27 03:08:23 +000075/* #define LOGF_ENABLE */
Nicolas Pennequinfb709522007-10-24 22:06:36 +000076#include "logf.h"
77
Michael Sevakisc537d592011-04-27 03:08:23 +000078/* Macros to enable logf for queues
Michael Sevakis0f5cb942006-11-06 18:07:30 +000079 logging on SYS_TIMEOUT can be disabled */
Michael Sevakis77771b02007-05-09 03:48:52 +000080#ifdef SIMULATOR
Michael Sevakis0f5cb942006-11-06 18:07:30 +000081/* Define this for logf output of all queuing except SYS_TIMEOUT */
82#define PLAYBACK_LOGQUEUES
83/* Define this to logf SYS_TIMEOUT messages */
Nicolas Pennequinfb709522007-10-24 22:06:36 +000084/*#define PLAYBACK_LOGQUEUES_SYS_TIMEOUT*/
Steve Bavina3087e42006-08-31 10:01:07 +000085#endif
86
Miika Pekkarinen815684a2006-09-17 08:34:42 +000087#ifdef PLAYBACK_LOGQUEUES
Michael Sevakisa21871c2007-05-08 23:13:46 +000088#define LOGFQUEUE logf
Steve Bavina3087e42006-08-31 10:01:07 +000089#else
Michael Sevakisa21871c2007-05-08 23:13:46 +000090#define LOGFQUEUE(...)
Steve Bavina3087e42006-08-31 10:01:07 +000091#endif
92
Michael Sevakis0f5cb942006-11-06 18:07:30 +000093#ifdef PLAYBACK_LOGQUEUES_SYS_TIMEOUT
Michael Sevakisa21871c2007-05-08 23:13:46 +000094#define LOGFQUEUE_SYS_TIMEOUT logf
Michael Sevakis0f5cb942006-11-06 18:07:30 +000095#else
Michael Sevakisa21871c2007-05-08 23:13:46 +000096#define LOGFQUEUE_SYS_TIMEOUT(...)
Michael Sevakis0f5cb942006-11-06 18:07:30 +000097#endif
98
Michael Sevakisc537d592011-04-27 03:08:23 +000099/* Variables are commented with the threads that use them:
100 * A=audio, C=codec, O=other. A suffix of "-" indicates that the variable is
101 * read but not updated on that thread. Audio is the only user unless otherwise
102 * specified.
103 */
Michael Sevakis0f5cb942006-11-06 18:07:30 +0000104
Michael Sevakisc537d592011-04-27 03:08:23 +0000105/** Miscellaneous **/
106bool audio_is_initialized = false; /* (A,O-) */
107extern struct codec_api ci; /* (A,C) */
108
109/** Possible arrangements of the main buffer **/
110static enum audio_buffer_state
111{
112 AUDIOBUF_STATE_TRASHED = -1, /* trashed; must be reset */
113 AUDIOBUF_STATE_INITIALIZED = 0, /* voice+audio OR audio-only */
114 AUDIOBUF_STATE_VOICED_ONLY = 1, /* voice-only */
115} buffer_state = AUDIOBUF_STATE_TRASHED; /* (A,O) */
116
117/** Main state control **/
118static bool ff_rw_mode SHAREDBSS_ATTR = false; /* Pre-ff-rewind mode (A,O-) */
119
120enum play_status
121{
122 PLAY_STOPPED = 0,
123 PLAY_PLAYING = AUDIO_STATUS_PLAY,
124 PLAY_PAUSED = AUDIO_STATUS_PLAY | AUDIO_STATUS_PAUSE,
125} play_status = PLAY_STOPPED;
126
127/* Sizeable things that only need exist during playback and not when stopped */
128static struct audio_scratch_memory
129{
130 struct mp3entry codec_id3; /* (A,C) */
131 struct mp3entry unbuffered_id3;
132 struct cuesheet *curr_cue; /* Will follow this structure */
133} * audio_scratch_memory = NULL;
134
135/* These are used to store the current, next and optionally the peek-ahead
Jeffrey Goode8cb4b362011-05-09 21:52:06 +0000136 * mp3entry's - this guarantees that the pointer returned by audio_current/
Michael Sevakisc537d592011-04-27 03:08:23 +0000137 * next_track will be valid for the full duration of the currently playing
138 * track */
139enum audio_id3_types
140{
141 /* These are allocated statically */
142 PLAYING_ID3 = 0,
143 NEXTTRACK_ID3,
144#ifdef AUDIO_FAST_SKIP_PREVIEW
145 /* The real playing metadata must has to be protected since it contains
146 critical info for other features */
147 PLAYING_PEEK_ID3,
148#endif
149 ID3_TYPE_NUM_STATIC,
150 /* These go in the scratch memory */
151 UNBUFFERED_ID3 = ID3_TYPE_NUM_STATIC,
152 CODEC_ID3,
153};
154static struct mp3entry static_id3_entries[ID3_TYPE_NUM_STATIC]; /* (A,O) */
155
156/* Peeking functions can yield and mess us up */
Jeffrey Goode8cb4b362011-05-09 21:52:06 +0000157static struct mutex id3_mutex SHAREDBSS_ATTR; /* (A,O)*/
Michael Sevakisc537d592011-04-27 03:08:23 +0000158
159
160/** For Scrobbler support **/
161
162/* Previous track elapsed time */
163static unsigned long prev_track_elapsed = 0; /* (A,O-) */
164
165
166/** For album art support **/
167#define MAX_MULTIPLE_AA SKINNABLE_SCREENS_COUNT
168#ifdef HAVE_ALBUMART
169
170static struct albumart_slot
171{
172 struct dim dim; /* Holds width, height of the albumart */
173 int used; /* Counter; increments if something uses it */
174} albumart_slots[MAX_MULTIPLE_AA]; /* (A,O) */
175
176#define FOREACH_ALBUMART(i) for(i = 0;i < MAX_MULTIPLE_AA; i++)
177#endif /* HAVE_ALBUMART */
178
179
180/** Information used for tracking buffer fills **/
181
182/* Buffer and thread state tracking */
183static enum filling_state
184{
185 STATE_BOOT = 0, /* audio thread is not ready yet */
Nicolas Pennequinf68147e2008-03-28 20:18:53 +0000186 STATE_IDLE, /* audio is stopped: nothing to do */
187 STATE_FILLING, /* adding tracks to the buffer */
188 STATE_FULL, /* can't add any more tracks */
Nicolas Pennequin0441afe2008-06-29 11:50:41 +0000189 STATE_END_OF_PLAYLIST, /* all remaining tracks have been added */
190 STATE_FINISHED, /* all remaining tracks are fully buffered */
Michael Sevakis65109732011-02-23 14:31:13 +0000191 STATE_ENDING, /* audio playback is ending */
Michael Sevakisc537d592011-04-27 03:08:23 +0000192 STATE_ENDED, /* audio playback is done */
Michael Sevakis65109732011-02-23 14:31:13 +0000193#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
194 STATE_USB, /* USB mode, ignore most messages */
195#endif
Michael Sevakisc537d592011-04-27 03:08:23 +0000196} filling = STATE_BOOT;
Bertrik Sikkenc97e5032008-04-28 14:13:13 +0000197
Michael Sevakisc537d592011-04-27 03:08:23 +0000198/* Track info - holds information about each track in the buffer */
199struct track_info
Jeffrey Goodedb82be42009-11-16 20:09:46 +0000200{
Michael Sevakisc537d592011-04-27 03:08:23 +0000201 /* In per-track allocated order: */
202 int id3_hid; /* Metadata handle ID */
Jeffrey Goode8cb4b362011-05-09 21:52:06 +0000203 int cuesheet_hid; /* Parsed cuesheet handle ID */
Michael Sevakisc537d592011-04-27 03:08:23 +0000204#ifdef HAVE_ALBUMART
205 int aa_hid[MAX_MULTIPLE_AA];/* Album art handle IDs */
206#endif
207#ifdef HAVE_CODEC_BUFFERING
208 int codec_hid; /* Buffered codec handle ID */
209#endif
210 int audio_hid; /* Main audio data handle ID */
211 size_t filesize; /* File total length on disk
212 TODO: This should be stored
213 in the handle or the
214 id3 and would use less
215 ram */
Jeffrey Goodedb82be42009-11-16 20:09:46 +0000216};
Michael Sevakis0f5cb942006-11-06 18:07:30 +0000217
Michael Sevakisc537d592011-04-27 03:08:23 +0000218/* Track list - holds info about all buffered tracks */
219#if MEMORYSIZE >= 32
220#define TRACK_LIST_LEN 128 /* Must be 2^int(+n) */
221#elif MEMORYSIZE >= 16
222#define TRACK_LIST_LEN 64
223#elif MEMORYSIZE >= 8
224#define TRACK_LIST_LEN 32
225#else
226#define TRACK_LIST_LEN 16
Jeffrey Goode9a4420b2009-10-31 19:17:36 +0000227#endif
228
Michael Sevakisc537d592011-04-27 03:08:23 +0000229#define TRACK_LIST_MASK (TRACK_LIST_LEN-1)
Jeffrey Goode9a4420b2009-10-31 19:17:36 +0000230
Michael Sevakisc537d592011-04-27 03:08:23 +0000231static struct
232{
233 /* read, write and current are maintained unwrapped, limited only by the
234 unsigned int range and wrap-safe comparisons are used */
Jeffrey Goode9a4420b2009-10-31 19:17:36 +0000235
Michael Sevakisc537d592011-04-27 03:08:23 +0000236 /* NOTE: there appears to be a bug in arm-elf-eabi-gcc 4.4.4 for ARMv4 where
237 if 'end' follows 'start' in this structure, track_list_count performs
238 'start - end' rather than 'end - start', giving negative count values...
239 so leave it this way for now! */
240 unsigned int end; /* Next open position */
241 unsigned int start; /* First track in list */
242 unsigned int current; /* Currently decoding track */
243 struct track_info tracks[TRACK_LIST_LEN]; /* Buffered track information */
244} track_list; /* (A, O-) */
Steve Bavin4d344572007-10-02 07:47:43 +0000245
Steve Bavin4d344572007-10-02 07:47:43 +0000246
Michael Sevakisc537d592011-04-27 03:08:23 +0000247/* Playlist steps from playlist position to next track to be buffered */
248static int playlist_peek_offset = 0;
Steve Bavin4d344572007-10-02 07:47:43 +0000249
Michael Sevakisc537d592011-04-27 03:08:23 +0000250/* Metadata handle of track load in progress (meaning all handles have not
251 yet been opened for the track, id3 always exists or the track does not)
Jeffrey Goode9a4420b2009-10-31 19:17:36 +0000252
Michael Sevakisc537d592011-04-27 03:08:23 +0000253 Tracks are keyed by their metadata handles if track list pointers are
254 insufficient to make comparisons */
255static int in_progress_id3_hid = ERR_HANDLE_NOT_FOUND;
Nicolas Pennequinf69982b2008-06-30 16:20:46 +0000256
Björn Stenberg6427d122009-01-10 21:10:56 +0000257#ifdef HAVE_DISK_STORAGE
Michael Sevakisc537d592011-04-27 03:08:23 +0000258/* Buffer margin A.K.A. anti-skip buffer (in seconds) */
259static size_t buffer_margin = 5;
Björn Stenberg6427d122009-01-10 21:10:56 +0000260#endif
Linus Nielsen Feltzing4aaa3212005-06-06 00:35:21 +0000261
Michael Sevakisc537d592011-04-27 03:08:23 +0000262/* Values returned for track loading */
263enum track_load_status
264{
265 LOAD_TRACK_ERR_START_CODEC = -6,
266 LOAD_TRACK_ERR_FINISH_FAILED = -5,
267 LOAD_TRACK_ERR_FINISH_FULL = -4,
268 LOAD_TRACK_ERR_BUSY = -3,
269 LOAD_TRACK_ERR_NO_MORE = -2,
270 LOAD_TRACK_ERR_FAILED = -1,
271 LOAD_TRACK_OK = 0,
272 LOAD_TRACK_READY = 1,
273};
274
275/** Track change controls **/
276
277/* What sort of skip is pending globally? */
278enum track_skip_type
279{
280 /* Relative to what user is intended to see: */
281 /* Codec: +0, Track List: +0, Playlist: +0 */
282 TRACK_SKIP_NONE = 0, /* no track skip */
283 /* Codec: +1, Track List: +1, Playlist: +0 */
284 TRACK_SKIP_AUTO, /* codec-initiated skip */
285 /* Codec: +1, Track List: +1, Playlist: +1 */
286 TRACK_SKIP_AUTO_NEW_PLAYLIST, /* codec-initiated skip is new playlist */
287 /* Codec: xx, Track List: +0, Playlist: +0 */
288 TRACK_SKIP_AUTO_END_PLAYLIST, /* codec-initiated end of playlist */
289 /* Manual skip: Never pends */
290 TRACK_SKIP_MANUAL, /* manual track skip */
291 /* Manual skip: Never pends */
292 TRACK_SKIP_DIR_CHANGE, /* manual directory skip */
293} skip_pending = TRACK_SKIP_NONE;
294
295/* Note about TRACK_SKIP_AUTO_NEW_PLAYLIST:
296 Fixing playlist code to be able to peek into the first song of
297 the next playlist would fix any issues and this wouldn't need
298 to be a special case since pre-advancing the playlist would be
299 unneeded - it could be much more like TRACK_SKIP_AUTO and all
300 actions that require reversal during an in-progress transition
301 would work as expected */
302
303/* Used to indicate status for the events. Must be separate to satisfy all
304 clients so the correct metadata is read when sending the change events
305 and also so that it is read correctly outside the events. */
306static bool automatic_skip = false; /* (A, O-) */
307
308/* Pending manual track skip offset */
309static int skip_offset = 0; /* (A, O) */
310
311/* Track change notification */
312static struct
313{
314 unsigned int in; /* Number of pcmbuf posts (audio isr) */
315 unsigned int out; /* Number of times audio has read the difference */
316} track_change = { 0, 0 };
317
318/** Codec status **/
Jeffrey Goode8cb4b362011-05-09 21:52:06 +0000319/* Did the codec notify us it finished while we were paused or while still
Michael Sevakisc537d592011-04-27 03:08:23 +0000320 in an automatic transition?
321
322 If paused, it is necessary to defer a codec-initiated skip until resuming
323 or else the track will move forward while not playing audio!
324
325 If in-progress, skips should not build-up ahead of where the WPS is when
326 really short tracks finish decoding.
327
328 If it is forgotten, it will be missed altogether and playback will just sit
329 there looking stupid and comatose until the user does something */
330static bool codec_skip_pending = false;
331static int codec_skip_status;
332static bool codec_seeking = false; /* Codec seeking ack expected? */
Michael Sevakis7ad2cad2011-08-28 07:45:35 +0000333static unsigned int position_key = 0;
Michael Sevakisc537d592011-04-27 03:08:23 +0000334
Jeffrey Goode9a4420b2009-10-31 19:17:36 +0000335/* Event queues */
Michael Sevakisc537d592011-04-27 03:08:23 +0000336static struct event_queue audio_queue SHAREDBSS_ATTR;
Miika Pekkarinen5899ed52005-06-08 10:33:01 +0000337
Steve Bavin3cc46e72006-09-01 07:59:31 +0000338/* Audio thread */
Michael Sevakis05099142008-04-06 04:34:57 +0000339static struct queue_sender_list audio_queue_sender_list SHAREDBSS_ATTR;
Steve Bavin3cc46e72006-09-01 07:59:31 +0000340static long audio_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)];
341static const char audio_thread_name[] = "audio";
Michael Sevakisc537d592011-04-27 03:08:23 +0000342static unsigned int audio_thread_id = 0;
Steve Bavin3cc46e72006-09-01 07:59:31 +0000343
Michael Sevakisc537d592011-04-27 03:08:23 +0000344/* Forward declarations */
345enum audio_start_playback_flags
346{
347 AUDIO_START_RESTART = 0x1, /* "Restart" playback (flush _all_ tracks) */
348 AUDIO_START_NEWBUF = 0x2, /* Mark the audiobuffer as invalid */
349};
350
351static void audio_start_playback(size_t offset, unsigned int flags);
Magnus Holmgren1b9991c2008-10-26 20:15:10 +0000352static void audio_stop_playback(void);
Michael Sevakisc537d592011-04-27 03:08:23 +0000353static void buffer_event_buffer_low_callback(void *data);
354static void buffer_event_rebuffer_callback(void *data);
355static void buffer_event_finished_callback(void *data);
Michael Sevakis7ad2cad2011-08-28 07:45:35 +0000356void audio_pcmbuf_sync_position(void);
Michael Sevakisc537d592011-04-27 03:08:23 +0000357
Steve Bavin3cc46e72006-09-01 07:59:31 +0000358
Jeffrey Goode9a4420b2009-10-31 19:17:36 +0000359/**************************************/
Michael Sevakisf38274f2008-02-28 22:37:46 +0000360
Michael Sevakisc537d592011-04-27 03:08:23 +0000361/** --- audio_queue helpers --- **/
Michael Sevakis7ad2cad2011-08-28 07:45:35 +0000362static void audio_queue_post(long id, intptr_t data)
Jeffrey Goode5ce8e2c2009-11-04 03:58:33 +0000363{
Michael Sevakisc537d592011-04-27 03:08:23 +0000364 queue_post(&audio_queue, id, data);
Jeffrey Goode5ce8e2c2009-11-04 03:58:33 +0000365}
366
Michael Sevakisc537d592011-04-27 03:08:23 +0000367static intptr_t audio_queue_send(long id, intptr_t data)
Jeffrey Goodee8eefe92009-11-01 19:39:23 +0000368{
Michael Sevakisc537d592011-04-27 03:08:23 +0000369 return queue_send(&audio_queue, id, data);
Michael Sevakisf38274f2008-02-28 22:37:46 +0000370}
371
Jeffrey Goodedb82be42009-11-16 20:09:46 +0000372
Michael Sevakisc537d592011-04-27 03:08:23 +0000373/** --- MP3Entry --- **/
Nicolas Pennequin3e3c43c2007-10-25 21:27:45 +0000374
Michael Sevakisc537d592011-04-27 03:08:23 +0000375/* Does the mp3entry have enough info for us to use it? */
376static struct mp3entry * valid_mp3entry(const struct mp3entry *id3)
377{
378 return id3 && (id3->length != 0 || id3->filesize != 0) &&
379 id3->codectype != AFMT_UNKNOWN ? (struct mp3entry *)id3 : NULL;
380}
381
382/* Return a pointer to an mp3entry on the buffer, as it is */
383static struct mp3entry * bufgetid3(int handle_id)
Nicolas Pennequin3e3c43c2007-10-25 21:27:45 +0000384{
385 if (handle_id < 0)
386 return NULL;
387
388 struct mp3entry *id3;
389 ssize_t ret = bufgetdata(handle_id, 0, (void *)&id3);
390
Michael Sevakisbdec6382011-02-10 22:03:39 +0000391 if (ret != sizeof(struct mp3entry))
Nicolas Pennequin3e3c43c2007-10-25 21:27:45 +0000392 return NULL;
393
394 return id3;
395}
396
Michael Sevakisc537d592011-04-27 03:08:23 +0000397/* Read an mp3entry from the buffer, adjusted */
Michael Sevakisbdec6382011-02-10 22:03:39 +0000398static bool bufreadid3(int handle_id, struct mp3entry *id3out)
399{
400 struct mp3entry *id3 = bufgetid3(handle_id);
401
402 if (id3)
403 {
404 copy_mp3entry(id3out, id3);
405 return true;
406 }
407
408 return false;
409}
410
Michael Sevakisc537d592011-04-27 03:08:23 +0000411/* Lock the id3 mutex */
412static void id3_mutex_lock(void)
Nicolas Pennequin3e3c43c2007-10-25 21:27:45 +0000413{
Michael Sevakisc537d592011-04-27 03:08:23 +0000414 mutex_lock(&id3_mutex);
415}
416
417/* Unlock the id3 mutex */
418static void id3_mutex_unlock(void)
419{
420 mutex_unlock(&id3_mutex);
421}
422
423/* Return one of the collection of mp3entry pointers - collect them all here */
424static inline struct mp3entry * id3_get(enum audio_id3_types id3_num)
425{
426 switch (id3_num)
427 {
428 case UNBUFFERED_ID3:
429 return &audio_scratch_memory->unbuffered_id3;
430 case CODEC_ID3:
431 return &audio_scratch_memory->codec_id3;
432 default:
433 return &static_id3_entries[id3_num];
434 }
435}
436
437/* Copy an mp3entry into one of the mp3 entries */
438static void id3_write(enum audio_id3_types id3_num,
439 const struct mp3entry *id3_src)
440{
441 struct mp3entry *dest_id3 = id3_get(id3_num);
442
443 if (id3_src)
444 copy_mp3entry(dest_id3, id3_src);
445 else
446 wipe_mp3entry(dest_id3);
447}
448
449/* Call id3_write "safely" because peek aheads can yield, even if the fast
450 preview isn't enabled */
451static void id3_write_locked(enum audio_id3_types id3_num,
452 const struct mp3entry *id3_src)
453{
454 id3_mutex_lock();
455 id3_write(id3_num, id3_src);
456 id3_mutex_unlock();
457}
458
459
460/** --- Track info --- **/
461
462/* Close a handle and mark it invalid */
463static void track_info_close_handle(int *hid_p)
464{
465 int hid = *hid_p;
466
Brandon Low31c11642007-11-04 19:01:02 +0000467 /* bufclose returns true if the handle is not found, or if it is closed
468 * successfully, so these checks are safe on non-existant handles */
Michael Sevakisc537d592011-04-27 03:08:23 +0000469 if (hid >= 0)
470 bufclose(hid);
Nicolas Pennequin3e3c43c2007-10-25 21:27:45 +0000471
Michael Sevakisc537d592011-04-27 03:08:23 +0000472 /* Always reset to "no handle" in case it was something else */
473 *hid_p = ERR_HANDLE_NOT_FOUND;
474}
Nicolas Pennequin3e3c43c2007-10-25 21:27:45 +0000475
Michael Sevakisc537d592011-04-27 03:08:23 +0000476/* Close all handles in a struct track_info and clear it */
477static void track_info_close(struct track_info *info)
478{
479 /* Close them in the order they are allocated on the buffer to speed up
480 the handle searching */
481 track_info_close_handle(&info->id3_hid);
482 track_info_close_handle(&info->cuesheet_hid);
Nicolas Pennequin9d4bed72007-11-11 12:29:37 +0000483#ifdef HAVE_ALBUMART
Michael Sevakisc537d592011-04-27 03:08:23 +0000484 int i;
485 FOREACH_ALBUMART(i)
486 track_info_close_handle(&info->aa_hid[i]);
487#endif
488#ifdef HAVE_CODEC_BUFFERING
489 track_info_close_handle(&info->codec_hid);
490#endif
491 track_info_close_handle(&info->audio_hid);
492 info->filesize = 0;
493}
494
495/* Invalidate all members to initial values - does not close handles */
496static void track_info_wipe(struct track_info * info)
497{
498 info->id3_hid = ERR_HANDLE_NOT_FOUND;
499 info->cuesheet_hid = ERR_HANDLE_NOT_FOUND;
500#ifdef HAVE_ALBUMART
501 int i;
502 FOREACH_ALBUMART(i)
503 info->aa_hid[i] = ERR_HANDLE_NOT_FOUND;
504#endif
505#ifdef HAVE_CODEC_BUFFERING
506 info->codec_hid = ERR_HANDLE_NOT_FOUND;
507#endif
508 info->audio_hid = ERR_HANDLE_NOT_FOUND;
509 info->filesize = 0;
510}
511
512
513/** --- Track list --- **/
514
515/* Initialize the track list */
516static void track_list_init(void)
517{
518 int i;
519 for (i = 0; i < TRACK_LIST_LEN; i++)
520 track_info_wipe(&track_list.tracks[i]);
521
522 track_list.start = track_list.end = track_list.current;
523}
524
525/* Return number of items allocated in the list */
526static unsigned int track_list_count(void)
527{
528 return track_list.end - track_list.start;
529}
530
531/* Return true if the list is empty */
532static inline bool track_list_empty(void)
533{
534 return track_list.end == track_list.start;
535}
536
537/* Returns true if the list is holding the maximum number of items */
538static bool track_list_full(void)
539{
540 return track_list.end - track_list.start >= TRACK_LIST_LEN;
541}
542
543/* Test if the index is within the allocated range */
544static bool track_list_in_range(int pos)
545{
546 return (int)(pos - track_list.start) >= 0 &&
547 (int)(pos - track_list.end) < 0;
548}
549
550static struct track_info * track_list_entry(int pos)
551{
552 return &track_list.tracks[pos & TRACK_LIST_MASK];
553}
554
555/* Return the info of the last allocation plus an offset, NULL if result is
556 out of bounds */
557static struct track_info * track_list_last(int offset)
558{
559 /* Last is before the end since the end isn't inclusive */
560 unsigned int pos = track_list.end + offset - 1;
561
562 if (!track_list_in_range(pos))
563 return NULL;
564
565 return track_list_entry(pos);
566}
567
568/* Allocate space at the end for another track if not full */
569static struct track_info * track_list_alloc_track(void)
570{
571 if (track_list_full())
572 return NULL;
573
574 return track_list_entry(track_list.end++);
575}
576
577/* Remove the last track entry allocated in order to support backing out
578 of a track load */
579static void track_list_unalloc_track(void)
580{
581 if (track_list_empty())
582 return;
583
584 track_list.end--;
585
586 if (track_list.current == track_list.end &&
587 track_list.current != track_list.start)
Thomas Martitze9c10182009-10-16 19:14:41 +0000588 {
Michael Sevakisc537d592011-04-27 03:08:23 +0000589 /* Current _must_ remain within bounds */
590 track_list.current--;
591 }
592}
593
594/* Return current track plus an offset, NULL if result is out of bounds */
595static struct track_info * track_list_current(int offset)
596{
597 unsigned int pos = track_list.current + offset;
598
599 if (!track_list_in_range(pos))
600 return NULL;
601
602 return track_list_entry(pos);
603}
604
605/* Return current based upon what's intended that the user sees - not
606 necessarily where decoding is taking place */
607static struct track_info * track_list_user_current(int offset)
608{
609 if (skip_pending == TRACK_SKIP_AUTO ||
610 skip_pending == TRACK_SKIP_AUTO_NEW_PLAYLIST)
611 {
612 offset--;
613 }
614
615 return track_list_current(offset);
616}
617
618/* Advance current track by an offset, return false if result is out of
619 bounds */
620static struct track_info * track_list_advance_current(int offset)
621{
622 unsigned int pos = track_list.current + offset;
623
624 if (!track_list_in_range(pos))
625 return NULL;
626
627 track_list.current = pos;
628 return track_list_entry(pos);
629}
630
631/* Clear tracks in the list, optionally preserving the current track -
632 returns 'false' if the operation was changed */
633enum track_clear_action
634{
635 TRACK_LIST_CLEAR_ALL = 0, /* Clear all tracks */
636 TRACK_LIST_KEEP_CURRENT, /* Keep current only; clear before + after */
637 TRACK_LIST_KEEP_NEW /* Keep current and those that follow */
638};
639
640static void track_list_clear(enum track_clear_action action)
641{
642 logf("%s(%d)", __func__, (int)action);
643
644 /* Don't care now since rebuffering is imminent */
645 buf_set_watermark(0);
646
647 if (action != TRACK_LIST_CLEAR_ALL)
648 {
649 struct track_info *cur = track_list_current(0);
650
651 if (!cur || cur->id3_hid < 0)
652 action = TRACK_LIST_CLEAR_ALL; /* Nothing worthwhile keeping */
653 }
654
655 /* Noone should see this progressing */
656 int start = track_list.start;
657 int current = track_list.current;
658 int end = track_list.end;
659
660 track_list.start = current;
661
662 switch (action)
663 {
664 case TRACK_LIST_CLEAR_ALL:
665 /* Result: .start = .current, .end = .current */
666 track_list.end = current;
667 break;
668
669 case TRACK_LIST_KEEP_CURRENT:
670 /* Result: .start = .current, .end = .current + 1 */
671 track_list.end = current + 1;
672 break;
673
674 case TRACK_LIST_KEEP_NEW:
675 /* Result: .start = .current, .end = .end */
676 end = current;
677 break;
678 }
679
680 /* Close all open handles in the range except the for the current track
681 if preserving that */
682 while (start != end)
683 {
684 if (action != TRACK_LIST_KEEP_CURRENT || start != current)
Thomas Martitze9c10182009-10-16 19:14:41 +0000685 {
Michael Sevakisc537d592011-04-27 03:08:23 +0000686 struct track_info *info =
687 &track_list.tracks[start & TRACK_LIST_MASK];
688
689 /* If this is the in-progress load, abort it */
690 if (in_progress_id3_hid >= 0 &&
691 info->id3_hid == in_progress_id3_hid)
692 {
693 in_progress_id3_hid = ERR_HANDLE_NOT_FOUND;
694 }
695
696 track_info_close(info);
Thomas Martitze9c10182009-10-16 19:14:41 +0000697 }
Michael Sevakisc537d592011-04-27 03:08:23 +0000698
699 start++;
700 }
701}
702
703
704/** --- Audio buffer -- **/
705
706/* What size is needed for the scratch buffer? */
707static size_t scratch_mem_size(void)
708{
709 size_t size = sizeof (struct audio_scratch_memory);
710
711 if (global_settings.cuesheet)
712 size += sizeof (struct cuesheet);
713
714 return size;
715}
716
717/* Initialize the memory area where data is stored that is only used when
718 playing audio and anything depending upon it */
719static void scratch_mem_init(void *mem)
720{
721 audio_scratch_memory = (struct audio_scratch_memory *)mem;
722 id3_write_locked(UNBUFFERED_ID3, NULL);
723 id3_write(CODEC_ID3, NULL);
724 ci.id3 = id3_get(CODEC_ID3);
725 audio_scratch_memory->curr_cue = NULL;
726
727 if (global_settings.cuesheet)
728 {
729 audio_scratch_memory->curr_cue =
730 SKIPBYTES((struct cuesheet *)audio_scratch_memory,
731 sizeof (struct audio_scratch_memory));
732 }
733}
734
735/* Set up the audio buffer for playback */
736static void audio_reset_buffer(void)
737{
738 /*
739 * Layout audio buffer as follows:
Michael Sevakisa802eba2011-07-09 01:49:00 +0000740 * [[|TALK]|SCRATCH|BUFFERING|PCM|[VOICE|]]
Michael Sevakisc537d592011-04-27 03:08:23 +0000741 */
742
743 /* see audio_get_recording_buffer if this is modified */
744 logf("%s()", __func__);
745
Thomas Martitzd1322b72011-08-14 15:13:00 +0000746 /* release the buffer on behalf of any caller of audio_get_buffer() */
747 buffer_release_buffer(0);
748
Michael Sevakisc537d592011-04-27 03:08:23 +0000749 /* If the setup of anything allocated before the file buffer is
750 changed, do check the adjustments after the buffer_alloc call
751 as it will likely be affected and need sliding over */
752
753 /* Initially set up file buffer as all space available */
Thomas Martitzd1322b72011-08-14 15:13:00 +0000754 size_t filebuflen, allocsize;
755 unsigned char *filebuf = buffer_get_buffer(&filebuflen);
Michael Sevakisc537d592011-04-27 03:08:23 +0000756
Thomas Martitzd1322b72011-08-14 15:13:00 +0000757 /* Subtract whatever voice needs */
758 allocsize = talkbuf_init(filebuf);
759 allocsize = ALIGN_UP(allocsize, sizeof (intptr_t));
760 if (allocsize > filebuflen)
761 goto bufpanic;
762
763 filebuf += allocsize;
764 filebuflen -= allocsize;
Michael Sevakisc537d592011-04-27 03:08:23 +0000765
Michael Sevakisa802eba2011-07-09 01:49:00 +0000766 if (talk_voice_required())
767 {
768 /* Need a space for voice PCM output */
769 allocsize = voicebuf_init(filebuf + filebuflen);
770
771 allocsize = ALIGN_UP(allocsize, sizeof (intptr_t));
772 if (allocsize > filebuflen)
773 goto bufpanic;
774
775 filebuflen -= allocsize;
776 }
777
Michael Sevakisc537d592011-04-27 03:08:23 +0000778 /* Subtract whatever the pcm buffer says it used plus the guard buffer */
779 allocsize = pcmbuf_init(filebuf + filebuflen);
780
781 /* Make sure filebuflen is a pointer sized multiple after adjustment */
782 allocsize = ALIGN_UP(allocsize, sizeof (intptr_t));
783 if (allocsize > filebuflen)
784 goto bufpanic;
785
786 filebuflen -= allocsize;
787
788 /* Scratch memory */
789 allocsize = scratch_mem_size();
790 if (allocsize > filebuflen)
791 goto bufpanic;
792
793 scratch_mem_init(filebuf);
794 filebuf += allocsize;
795 filebuflen -= allocsize;
796
797 buffering_reset(filebuf, filebuflen);
798
799 /* Clear any references to the file buffer */
800 buffer_state = AUDIOBUF_STATE_INITIALIZED;
801
802#if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
803 /* Make sure everything adds up - yes, some info is a bit redundant but
Jeffrey Goode8cb4b362011-05-09 21:52:06 +0000804 aids viewing and the summation of certain variables should add up to
Michael Sevakisc537d592011-04-27 03:08:23 +0000805 the location of others. */
806 {
Michael Sevakisc537d592011-04-27 03:08:23 +0000807 logf("fbuf: %08X", (unsigned)filebuf);
808 logf("fbufe: %08X", (unsigned)(filebuf + filebuflen));
809 logf("sbuf: %08X", (unsigned)audio_scratch_memory);
810 logf("sbufe: %08X", (unsigned)(audio_scratch_memory + allocsize));
Nicolas Pennequin9d4bed72007-11-11 12:29:37 +0000811 }
Nicolas Pennequincf37f4c2007-11-11 12:52:07 +0000812#endif
Nicolas Pennequin9d4bed72007-11-11 12:29:37 +0000813
Michael Sevakisc537d592011-04-27 03:08:23 +0000814 return;
815
816bufpanic:
817 panicf("%s(): EOM (%zu > %zu)", __func__, allocsize, filebuflen);
818}
819
820/* Set the buffer margin to begin rebuffering when 'seconds' from empty */
821static void audio_update_filebuf_watermark(int seconds)
822{
823 size_t bytes = 0;
824
825#ifdef HAVE_DISK_STORAGE
826 int spinup = ata_spinup_time();
827
828 if (seconds == 0)
829 {
830 /* By current setting */
831 seconds = buffer_margin;
832 }
833 else
834 {
835 /* New setting */
836 buffer_margin = seconds;
837
838 if (buf_get_watermark() == 0)
839 {
840 /* Write a watermark only if the audio thread already did so for
841 itself or it will fail to set the event and the watermark - if
842 it hasn't yet, it will use the new setting when it does */
843 return;
844 }
Jonathan Gordon24b136f2009-07-20 05:18:18 +0000845 }
846
Michael Sevakisc537d592011-04-27 03:08:23 +0000847 if (spinup)
848 seconds += (spinup / HZ) + 1;
849 else
850 seconds += 5;
851
852 seconds += buffer_margin;
853#else
854 /* flash storage */
855 seconds = 1;
856#endif
857
858 /* Watermark is a function of the bitrate of the last track in the buffer */
Jeffrey Goode8cb4b362011-05-09 21:52:06 +0000859 struct mp3entry *id3 = NULL;
Michael Sevakisc537d592011-04-27 03:08:23 +0000860 struct track_info *info = track_list_last(0);
861
862 if (info)
863 id3 = valid_mp3entry(bufgetid3(info->id3_hid));
864
865 if (id3)
866 {
867 if (get_audio_base_data_type(id3->codectype) == TYPE_PACKET_AUDIO)
868 {
869 bytes = id3->bitrate * (1000/8) * seconds;
870 }
871 else
872 {
873 /* Bitrate has no meaning to buffering margin for atomic audio -
Jeffrey Goode8cb4b362011-05-09 21:52:06 +0000874 rebuffer when it's the only track left unless it's the only
Michael Sevakisc537d592011-04-27 03:08:23 +0000875 track that fits, in which case we should avoid constant buffer
876 low events */
877 if (track_list_count() > 1)
878 bytes = info->filesize + 1;
879 }
880 }
881 else
882 {
883 /* Then set the minimum - this should not occur anyway */
884 logf("fwmark: No id3 for last track (s%u/c%u/e%u)",
885 track_list.start, track_list.current, track_list.end);
886 }
887
888 /* Actually setting zero disables the notification and we use that
889 to detect that it has been reset */
890 buf_set_watermark(MAX(bytes, 1));
891 logf("fwmark: %lu", (unsigned long)bytes);
892}
893
894
895/** -- Track change notification -- **/
896
897/* Check the pcmbuf track changes and return write the message into the event
898 if there are any */
899static inline bool audio_pcmbuf_track_change_scan(void)
900{
901 if (track_change.out != track_change.in)
902 {
903 track_change.out++;
904 return true;
905 }
906
907 return false;
908}
909
910/* Clear outstanding track change posts */
911static inline void audio_pcmbuf_track_change_clear(void)
912{
913 track_change.out = track_change.in;
914}
915
916/* Post a track change notification - called by audio ISR */
917static inline void audio_pcmbuf_track_change_post(void)
918{
919 track_change.in++;
920}
921
922
923/** --- Helper functions --- **/
924
925/* Removes messages that might end up in the queue before or while processing
926 a manual track change. Responding to them would be harmful since they
927 belong to a previous track's playback period. Anything that would generate
928 the stale messages must first be put into a state where it will not do so.
929 */
930static void audio_clear_track_notifications(void)
931{
932 static const long filter_list[][2] =
933 {
934 /* codec messages */
935 { Q_AUDIO_CODEC_SEEK_COMPLETE, Q_AUDIO_CODEC_COMPLETE },
936 /* track change messages */
937 { Q_AUDIO_TRACK_CHANGED, Q_AUDIO_TRACK_CHANGED },
938 };
939
940 const int filter_count = ARRAYLEN(filter_list) - 1;
941
942 /* Remove any pcmbuf notifications */
943 pcmbuf_monitor_track_change(false);
944 audio_pcmbuf_track_change_clear();
945
946 /* Scrub the audio queue of the old mold */
947 while (queue_peek_ex(&audio_queue, NULL,
948 filter_count | QPEEK_REMOVE_EVENTS,
949 filter_list))
950 {
951 yield(); /* Not strictly needed, per se, ad infinitum, ra, ra */
952 }
953}
954
955/* Takes actions based upon track load status codes */
956static void audio_handle_track_load_status(int trackstat)
957{
958 switch (trackstat)
959 {
960 case LOAD_TRACK_ERR_NO_MORE:
961 if (track_list_count() > 0)
962 break;
963
964 case LOAD_TRACK_ERR_START_CODEC:
965 audio_queue_post(Q_AUDIO_CODEC_COMPLETE, CODEC_ERROR);
966 break;
967
968 default:
969 break;
970 }
971}
972
973/* Announce the end of playing the current track */
974static void audio_playlist_track_finish(void)
975{
Michael Sevakis7ad2cad2011-08-28 07:45:35 +0000976 struct mp3entry *ply_id3 = id3_get(PLAYING_ID3);
977 struct mp3entry *id3 = valid_mp3entry(ply_id3);
Michael Sevakisc537d592011-04-27 03:08:23 +0000978
979 playlist_update_resume_info(filling == STATE_ENDED ? NULL : id3);
980
981 if (id3)
982 {
983 send_event(PLAYBACK_EVENT_TRACK_FINISH, id3);
984 prev_track_elapsed = id3->elapsed;
985 }
986 else
987 {
988 prev_track_elapsed = 0;
989 }
990}
991
992/* Announce the beginning of the new track */
993static void audio_playlist_track_change(void)
994{
995 struct mp3entry *id3 = valid_mp3entry(id3_get(PLAYING_ID3));
996
997 if (id3)
998 send_event(PLAYBACK_EVENT_TRACK_CHANGE, id3);
999
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00001000 position_key = pcmbuf_get_position_key();
1001
Michael Sevakisc537d592011-04-27 03:08:23 +00001002 playlist_update_resume_info(id3);
1003}
1004
1005/* Change the data for the next track and send the event */
1006static void audio_update_and_announce_next_track(const struct mp3entry *id3_next)
1007{
1008 id3_write_locked(NEXTTRACK_ID3, id3_next);
1009 send_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE,
1010 id3_get(NEXTTRACK_ID3));
1011}
1012
1013/* Bring the user current mp3entry up to date and set a new offset for the
1014 buffered metadata */
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00001015static void playing_id3_sync(struct track_info *user_info, off_t offset)
Michael Sevakisc537d592011-04-27 03:08:23 +00001016{
1017 id3_mutex_lock();
1018
1019 struct mp3entry *id3 = bufgetid3(user_info->id3_hid);
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00001020 struct mp3entry *playing_id3 = id3_get(PLAYING_ID3);
Michael Sevakisc537d592011-04-27 03:08:23 +00001021
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00001022 pcm_play_lock();
1023
1024 unsigned long e = playing_id3->elapsed;
1025 unsigned long o = playing_id3->offset;
1026
1027 id3_write(PLAYING_ID3, id3);
1028
1029 if (offset < 0)
Michael Sevakisc537d592011-04-27 03:08:23 +00001030 {
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00001031 playing_id3->elapsed = e;
1032 playing_id3->offset = o;
Michael Sevakisc537d592011-04-27 03:08:23 +00001033 offset = 0;
1034 }
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00001035
1036 pcm_play_unlock();
Michael Sevakisc537d592011-04-27 03:08:23 +00001037
1038 if (id3)
1039 id3->offset = offset;
1040
1041 id3_mutex_unlock();
1042}
1043
1044/* Wipe-out track metadata - current is optional */
1045static void wipe_track_metadata(bool current)
1046{
1047 id3_mutex_lock();
1048
1049 if (current)
1050 id3_write(PLAYING_ID3, NULL);
1051
1052 id3_write(NEXTTRACK_ID3, NULL);
1053 id3_write(UNBUFFERED_ID3, NULL);
1054
1055 id3_mutex_unlock();
1056}
1057
1058/* Called when buffering is completed on the last track handle */
1059static void filling_is_finished(void)
1060{
1061 logf("last track finished buffering");
1062
1063 /* There's no more to load or watch for */
1064 buf_set_watermark(0);
1065 filling = STATE_FINISHED;
1066}
1067
1068/* Stop the codec decoding or waiting for its data to be ready - returns
1069 'false' if the codec ended up stopped */
1070static bool halt_decoding_track(bool stop)
1071{
1072 /* If it was waiting for us to clear the buffer to make a rebuffer
1073 happen, it should cease otherwise codec_stop could deadlock waiting
1074 for the codec to go to its main loop - codec's request will now
1075 force-fail */
1076 bool retval = false;
1077
1078 buf_signal_handle(ci.audio_hid, true);
1079
1080 if (stop)
1081 codec_stop();
1082 else
1083 retval = codec_pause();
1084
1085 audio_clear_track_notifications();
1086
1087 /* We now know it's idle and not waiting for buffered data */
1088 buf_signal_handle(ci.audio_hid, false);
1089
1090 codec_skip_pending = false;
1091 codec_seeking = false;
1092
1093 return retval;
1094}
1095
Michael Sevakis5078d462011-08-23 01:37:59 +00001096/* Wait for any in-progress fade to complete */
1097static void audio_wait_fade_complete(void)
1098{
1099 /* Just loop until it's done */
1100 while (pcmbuf_fading())
1101 sleep(0);
1102}
1103
Michael Sevakisc537d592011-04-27 03:08:23 +00001104/* End the ff/rw mode */
1105static void audio_ff_rewind_end(void)
1106{
1107 /* A seamless seek (not calling audio_pre_ff_rewind) skips this
1108 section */
1109 if (ff_rw_mode)
1110 {
1111 ff_rw_mode = false;
1112
1113 if (codec_seeking)
1114 {
1115 /* Clear the buffer */
1116 pcmbuf_play_stop();
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00001117 audio_pcmbuf_sync_position();
Michael Sevakisc537d592011-04-27 03:08:23 +00001118 }
1119
1120 if (play_status != PLAY_PAUSED)
1121 {
1122 /* Seeking-while-playing, resume PCM playback */
1123 pcmbuf_pause(false);
1124 }
1125 }
1126}
1127
1128/* Complete the codec seek */
1129static void audio_complete_codec_seek(void)
1130{
1131 /* If a seek completed while paused, 'paused' is true.
1132 * If seeking from seek mode, 'ff_rw_mode' is true. */
1133 if (codec_seeking)
1134 {
1135 audio_ff_rewind_end();
1136 codec_seeking = false; /* set _after_ the call! */
1137 }
1138 /* else it's waiting and we must repond */
1139}
1140
1141/* Get the current cuesheet pointer */
1142static inline struct cuesheet * get_current_cuesheet(void)
1143{
1144 return audio_scratch_memory->curr_cue;
1145}
1146
1147/* Read the cuesheet from the buffer */
1148static void buf_read_cuesheet(int handle_id)
1149{
1150 struct cuesheet *cue = get_current_cuesheet();
1151
1152 if (!cue || handle_id < 0)
1153 return;
1154
1155 bufread(handle_id, sizeof (struct cuesheet), cue);
1156}
1157
1158/* Backend to peek/current/next track metadata interface functions -
1159 fill in the mp3entry with as much information as we may obtain about
1160 the track at the specified offset from the user current track -
1161 returns false if no information exists with us */
1162static bool audio_get_track_metadata(int offset, struct mp3entry *id3)
1163{
1164 if (play_status == PLAY_STOPPED)
1165 return false;
1166
1167 if (id3->path[0] != '\0')
1168 return true; /* Already filled */
1169
1170 struct track_info *info = track_list_user_current(offset);
1171
1172 if (!info)
1173 {
1174 struct mp3entry *ub_id3 = id3_get(UNBUFFERED_ID3);
1175
1176 if (offset > 0 && track_list_user_current(offset - 1))
1177 {
1178 /* Try the unbuffered id3 since we're moving forward */
1179 if (ub_id3->path[0] != '\0')
1180 {
1181 copy_mp3entry(id3, ub_id3);
1182 return true;
1183 }
1184 }
1185 }
1186 else if (bufreadid3(info->id3_hid, id3))
1187 {
Michael Sevakisc3e56252011-08-22 00:14:56 +00001188 id3->cuesheet = NULL;
Michael Sevakisc537d592011-04-27 03:08:23 +00001189 return true;
1190 }
1191
1192 /* We didn't find the ID3 metadata, so we fill it with the little info we
1193 have and return that */
1194
1195 char path[MAX_PATH+1];
1196 if (playlist_peek(offset, path, sizeof (path)))
1197 {
1198#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
1199 /* Try to get it from the database */
1200 if (!tagcache_fill_tags(id3, path))
1201#endif
1202 {
1203 /* By now, filename is the only source of info */
1204 fill_metadata_from_path(id3, path);
1205 }
1206
1207 return true;
1208 }
1209
1210 wipe_mp3entry(id3);
1211
1212 return false;
1213}
1214
1215/* Get a resume rewind adjusted offset from the ID3 */
1216unsigned long resume_rewind_adjusted_offset(const struct mp3entry *id3)
1217{
1218 unsigned long offset = id3->offset;
1219 size_t resume_rewind = global_settings.resume_rewind *
1220 id3->bitrate * (1000/8);
1221
1222 if (offset < resume_rewind)
1223 offset = 0;
1224 else
1225 offset -= resume_rewind;
1226
1227 return offset;
1228}
1229
1230/* Get the codec into ram and initialize it - keep it if it's ready */
1231static bool audio_init_codec(struct track_info *track_info,
1232 struct mp3entry *track_id3)
1233{
1234 int codt_loaded = get_audio_base_codec_type(codec_loaded());
1235 int hid = ERR_HANDLE_NOT_FOUND;
1236
1237 if (codt_loaded != AFMT_UNKNOWN)
1238 {
1239 int codt = get_audio_base_codec_type(track_id3->codectype);
1240
1241 if (codt == codt_loaded)
1242 {
1243 /* Codec is the same base type */
1244 logf("Reusing prev. codec: %d", track_id3->codectype);
1245#ifdef HAVE_CODEC_BUFFERING
1246 /* Close any buffered codec (we could have skipped directly to a
1247 format transistion that is the same format as the current track
1248 and the buffered one is no longer needed) */
1249 track_info_close_handle(&track_info->codec_hid);
1250#endif
1251 return true;
1252 }
1253 else
1254 {
1255 /* New codec - first make sure the old one's gone */
1256 logf("Removing prev. codec: %d", codt_loaded);
1257 codec_unload();
1258 }
1259 }
1260
1261 logf("New codec: %d/%d", track_id3->codectype, codec_loaded());
1262
1263#ifdef HAVE_CODEC_BUFFERING
1264 /* Codec thread will close the handle even if it fails and will load from
1265 storage if hid is not valid or the buffer load fails */
1266 hid = track_info->codec_hid;
1267 track_info->codec_hid = ERR_HANDLE_NOT_FOUND;
1268#endif
1269
1270 return codec_load(hid, track_id3->codectype);
1271 (void)track_info; /* When codec buffering isn't supported */
1272}
1273
1274/* Start the codec for the current track scheduled to be decoded */
1275static bool audio_start_codec(bool auto_skip)
1276{
1277 struct track_info *info = track_list_current(0);
1278 struct mp3entry *cur_id3 = valid_mp3entry(bufgetid3(info->id3_hid));
1279
1280 if (!cur_id3)
1281 return false;
1282
1283 buf_pin_handle(info->id3_hid, true);
1284
1285 if (!audio_init_codec(info, cur_id3))
1286 {
1287 buf_pin_handle(info->id3_hid, false);
1288 return false;
1289 }
1290
1291#ifdef HAVE_TAGCACHE
1292 bool autoresume_enable = global_settings.autoresume_enable;
1293
1294 if (autoresume_enable && !cur_id3->offset)
1295 {
1296 /* Resume all manually selected tracks */
1297 bool resume = !auto_skip;
1298
1299 /* Send the "buffer" event to obtain the resume position for the codec */
1300 send_event(PLAYBACK_EVENT_TRACK_BUFFER, cur_id3);
1301
1302 if (!resume)
1303 {
1304 /* Automatic skip - do further tests to see if we should just
1305 ignore any autoresume position */
1306 int autoresume_automatic = global_settings.autoresume_automatic;
1307
1308 switch (autoresume_automatic)
1309 {
1310 case AUTORESUME_NEXTTRACK_ALWAYS:
1311 /* Just resume unconditionally */
1312 resume = true;
1313 break;
1314 case AUTORESUME_NEXTTRACK_NEVER:
1315 /* Force-rewind it */
1316 break;
1317 default:
1318 /* Not "never resume" - pass resume filter? */
1319 resume = autoresumable(cur_id3);
1320 }
1321 }
1322
1323 if (!resume)
1324 cur_id3->offset = 0;
1325
1326 logf("%s: Set offset for %s to %lX\n", __func__,
1327 cur_id3->title, cur_id3->offset);
1328 }
1329#endif /* HAVE_TAGCACHE */
1330
1331 /* Rewind the required amount - if an autoresume was done, this also rewinds
1332 that by the setting's amount
1333
1334 It would be best to have bookkeeping about whether or not the track
1335 sounded or not since skipping to it or else skipping to it while paused
1336 and back again will cause accumulation of silent rewinds - that's not
1337 our job to track directly nor could it be in any reasonable way
1338 */
1339 cur_id3->offset = resume_rewind_adjusted_offset(cur_id3);
1340
1341 /* Update the codec API with the metadata and track info */
1342 id3_write(CODEC_ID3, cur_id3);
1343
1344 ci.audio_hid = info->audio_hid;
1345 ci.filesize = info->filesize;
1346 buf_set_base_handle(info->audio_hid);
1347
1348 /* All required data is now available for the codec */
1349 codec_go();
1350
1351#ifdef HAVE_TAGCACHE
1352 if (!autoresume_enable || cur_id3->offset)
1353#endif
1354 {
1355 /* Send the "buffer" event now */
1356 send_event(PLAYBACK_EVENT_TRACK_BUFFER, cur_id3);
1357 }
1358
1359 buf_pin_handle(info->id3_hid, false);
1360 return true;
1361
1362 (void)auto_skip; /* ifndef HAVE_TAGCACHE */
1363}
1364
1365
1366/** --- Audio thread --- **/
1367
1368/* Load and parse a cuesheet for the file - returns false if the buffer
1369 is full */
1370static bool audio_load_cuesheet(struct track_info *info,
1371 struct mp3entry *track_id3)
1372{
1373 struct cuesheet *cue = get_current_cuesheet();
1374 track_id3->cuesheet = NULL;
1375
1376 if (cue && info->cuesheet_hid == ERR_HANDLE_NOT_FOUND)
1377 {
1378 /* If error other than a full buffer, then mark it "unsupported" to
1379 avoid reloading attempt */
1380 int hid = ERR_UNSUPPORTED_TYPE;
1381 char cuepath[MAX_PATH];
1382
1383#ifdef HAVE_IO_PRIORITY
1384 buf_back_off_storage(true);
1385#endif
1386 if (look_for_cuesheet_file(track_id3->path, cuepath))
1387 {
1388 hid = bufalloc(NULL, sizeof (struct cuesheet), TYPE_CUESHEET);
1389
1390 if (hid >= 0)
1391 {
1392 void *cuesheet = NULL;
1393 bufgetdata(hid, sizeof (struct cuesheet), &cuesheet);
1394
1395 if (parse_cuesheet(cuepath, (struct cuesheet *)cuesheet))
1396 {
1397 /* Indicate cuesheet is present (while track remains
1398 buffered) */
1399 track_id3->cuesheet = cue;
1400 }
1401 else
1402 {
1403 bufclose(hid);
1404 hid = ERR_UNSUPPORTED_TYPE;
1405 }
1406 }
1407 }
1408
1409#ifdef HAVE_IO_PRIORITY
1410 buf_back_off_storage(false);
1411#endif
1412 if (hid == ERR_BUFFER_FULL)
1413 {
1414 logf("buffer is full for now (%s)", __func__);
1415 return false;
1416 }
1417 else
1418 {
1419 if (hid < 0)
1420 logf("Cuesheet loading failed");
1421
1422 info->cuesheet_hid = hid;
1423 }
1424 }
Brandon Low31c11642007-11-04 19:01:02 +00001425
Nicolas Pennequin3e3c43c2007-10-25 21:27:45 +00001426 return true;
1427}
1428
Michael Sevakisc537d592011-04-27 03:08:23 +00001429#ifdef HAVE_ALBUMART
1430/* Load any album art for the file - returns false if the buffer is full */
1431static bool audio_load_albumart(struct track_info *info,
1432 struct mp3entry *track_id3)
1433{
1434 int i;
1435 FOREACH_ALBUMART(i)
1436 {
1437 struct bufopen_bitmap_data user_data;
1438 int *aa_hid = &info->aa_hid[i];
1439 int hid = ERR_UNSUPPORTED_TYPE;
Steve Bavin3cc46e72006-09-01 07:59:31 +00001440
Michael Sevakisc537d592011-04-27 03:08:23 +00001441 /* albumart_slots may change during a yield of bufopen,
1442 * but that's no problem */
1443 if (*aa_hid >= 0 || *aa_hid == ERR_UNSUPPORTED_TYPE ||
1444 !albumart_slots[i].used)
1445 continue;
1446
1447 memset(&user_data, 0, sizeof(user_data));
1448 user_data.dim = &albumart_slots[i].dim;
1449
1450#ifdef HAVE_IO_PRIORITY
1451 buf_back_off_storage(true);
1452#endif
1453
1454 /* We can only decode jpeg for embedded AA */
1455 if (track_id3->embed_albumart && track_id3->albumart.type == AA_TYPE_JPG)
1456 {
1457 user_data.embedded_albumart = &track_id3->albumart;
1458 hid = bufopen(track_id3->path, 0, TYPE_BITMAP, &user_data);
1459 }
1460
1461 if (hid < 0 && hid != ERR_BUFFER_FULL)
1462 {
1463 /* No embedded AA or it couldn't be loaded - try other sources */
1464 char path[MAX_PATH];
1465
1466 if (find_albumart(track_id3, path, sizeof(path),
1467 &albumart_slots[i].dim))
1468 {
1469 user_data.embedded_albumart = NULL;
1470 hid = bufopen(path, 0, TYPE_BITMAP, &user_data);
1471 }
1472 }
1473
1474#ifdef HAVE_IO_PRIORITY
1475 buf_back_off_storage(false);
1476#endif
1477 if (hid == ERR_BUFFER_FULL)
1478 {
1479 logf("buffer is full for now (%s)", __func__);
1480 return false;
1481 }
1482 else
1483 {
1484 /* If error other than a full buffer, then mark it "unsupported"
1485 to avoid reloading attempt */
1486 if (hid < 0)
1487 {
1488 logf("Album art loading failed");
1489 hid = ERR_UNSUPPORTED_TYPE;
1490 }
1491
1492 *aa_hid = hid;
1493 }
1494 }
1495
1496 return true;
1497}
1498#endif /* HAVE_ALBUMART */
1499
1500#ifdef HAVE_CODEC_BUFFERING
1501/* Load a codec for the file onto the buffer - assumes we're working from the
1502 currently loading track - not called for the current track */
Jeffrey Goode8cb4b362011-05-09 21:52:06 +00001503static bool audio_buffer_codec(struct track_info *track_info,
Michael Sevakisc537d592011-04-27 03:08:23 +00001504 struct mp3entry *track_id3)
1505{
1506 /* This will not be the current track -> it cannot be the first and the
1507 current track cannot be ahead of buffering -> there is a previous
1508 track entry which is either current or ahead of the current */
1509 struct track_info *prev_info = track_list_last(-1);
1510 struct mp3entry *prev_id3 = bufgetid3(prev_info->id3_hid);
1511
1512 /* If the previous codec is the same as this one, there is no need to
1513 put another copy of it on the file buffer (in other words, only
1514 buffer codecs at format transitions) */
1515 if (prev_id3)
1516 {
1517 int codt = get_audio_base_codec_type(track_id3->codectype);
1518 int prev_codt = get_audio_base_codec_type(prev_id3->codectype);
1519
1520 if (codt == prev_codt)
1521 {
1522 logf("Reusing prev. codec: %d", prev_id3->codectype);
1523 return true;
1524 }
1525 }
1526 /* else just load it (harmless) */
1527
1528 /* Load the codec onto the buffer if possible */
1529 const char *codec_fn = get_codec_filename(track_id3->codectype);
1530 if (!codec_fn)
1531 return false;
1532
1533 char codec_path[MAX_PATH+1]; /* Full path to codec */
1534 codec_get_full_path(codec_path, codec_fn);
1535
1536 track_info->codec_hid = bufopen(codec_path, 0, TYPE_CODEC, NULL);
1537
1538 if (track_info->codec_hid >= 0)
1539 {
1540 logf("Buffered codec: %d", afmt);
1541 return true;
1542 }
1543
1544 return false;
1545}
1546#endif /* HAVE_CODEC_BUFFERING */
1547
1548/* Load metadata for the next track (with bufopen). The rest of the track
1549 loading will be handled by audio_finish_load_track once the metadata has
1550 been actually loaded by the buffering thread.
1551
1552 Each track is arranged in the buffer as follows:
1553 <id3|[cuesheet|][album art|][codec|]audio>
1554
1555 The next will not be loaded until the previous succeeds if the buffer was
1556 full at the time. To put any metadata after audio would make those handles
1557 unmovable.
1558*/
1559static int audio_load_track(void)
1560{
1561 if (in_progress_id3_hid >= 0)
1562 {
1563 /* There must be an info pointer if the in-progress id3 is even there */
1564 struct track_info *info = track_list_last(0);
1565
1566 if (info->id3_hid == in_progress_id3_hid)
1567 {
1568 if (filling == STATE_FILLING)
1569 {
1570 /* Haven't finished the metadata but the notification is
1571 anticipated to come soon */
1572 logf("%s(): in progress ok: %d". __func__, info->id3_hid);
1573 return LOAD_TRACK_OK;
1574 }
1575 else if (filling == STATE_FULL)
1576 {
1577 /* Buffer was full trying to complete the load after the
1578 metadata finished, so attempt to continue - older handles
1579 should have been cleared already */
1580 logf("%s(): finishing load: %d". __func__, info->id3_hid);
1581 filling = STATE_FILLING;
1582 buffer_event_finished_callback(&info->id3_hid);
1583 return LOAD_TRACK_OK;
1584 }
1585 }
1586
1587 /* Some old, stray buffering message */
1588 logf("%s(): already in progress: %d". __func__, info->id3_hid);
1589 return LOAD_TRACK_ERR_BUSY;
1590 }
1591
1592 filling = STATE_FILLING;
1593
1594 struct track_info *info = track_list_alloc_track();
1595 if (info == NULL)
1596 {
1597 /* List is full so stop buffering tracks - however, attempt to obtain
1598 metadata as the unbuffered id3 */
1599 logf("No free tracks");
1600 filling = STATE_FULL;
1601 }
1602
1603 playlist_peek_offset++;
1604
1605 logf("Buffering track: s%u/c%u/e%u/p%d",
1606 track_list.start, track_list.current, track_list.end,
1607 playlist_peek_offset);
1608
1609 /* Get track name from current playlist read position */
1610 int fd = -1;
1611 char name_buf[MAX_PATH + 1];
1612 const char *trackname;
1613
1614 while (1)
1615 {
1616
1617 trackname = playlist_peek(playlist_peek_offset, name_buf,
1618 sizeof (name_buf));
1619
1620 if (!trackname)
1621 break;
1622
1623 /* Test for broken playlists by probing for the files */
1624 fd = open(trackname, O_RDONLY);
1625 if (fd >= 0)
1626 break;
1627
1628 logf("Open failed");
1629 /* Skip invalid entry from playlist */
1630 playlist_skip_entry(NULL, playlist_peek_offset);
1631
1632 /* Sync the playlist if it isn't finished */
1633 if (playlist_peek(playlist_peek_offset, NULL, 0))
1634 playlist_next(0);
1635 }
1636
1637 if (!trackname)
1638 {
1639 /* No track - exhausted the playlist entries */
1640 logf("End-of-playlist");
1641 id3_write_locked(UNBUFFERED_ID3, NULL);
1642
1643 if (filling != STATE_FULL)
1644 track_list_unalloc_track(); /* Free this entry */
1645
1646 playlist_peek_offset--; /* Maintain at last index */
1647
1648 /* We can end up here after the real last track signals its completion
1649 and miss the transition to STATE_FINISHED esp. if dropping the last
1650 songs of a playlist late in their load (2nd stage) */
1651 info = track_list_last(0);
1652
1653 if (info && buf_handle_remaining(info->audio_hid) == 0)
1654 filling_is_finished();
1655 else
1656 filling = STATE_END_OF_PLAYLIST;
1657
1658 return LOAD_TRACK_ERR_NO_MORE;
1659 }
1660
1661 /* Successfully opened the file - get track metadata */
1662 if (filling == STATE_FULL ||
1663 (info->id3_hid = bufopen(trackname, 0, TYPE_ID3, NULL)) < 0)
1664 {
1665 /* Buffer or track list is full */
1666 struct mp3entry *ub_id3;
1667
1668 playlist_peek_offset--;
1669
1670 /* Load the metadata for the first unbuffered track */
1671 ub_id3 = id3_get(UNBUFFERED_ID3);
1672 id3_mutex_lock();
1673 get_metadata(ub_id3, fd, trackname);
1674 id3_mutex_unlock();
1675
1676 if (filling != STATE_FULL)
1677 {
1678 track_list_unalloc_track();
1679 filling = STATE_FULL;
1680 }
1681
1682 logf("%s: buffer is full for now (%u tracks)", __func__,
1683 track_list_count());
1684 }
1685 else
1686 {
1687 /* Successful load initiation */
1688 info->filesize = filesize(fd);
1689 in_progress_id3_hid = info->id3_hid; /* Remember what's in-progress */
1690 }
1691
1692 close(fd);
1693 return LOAD_TRACK_OK;
1694}
1695
1696/* Second part of the track loading: We now have the metadata available, so we
1697 can load the codec, the album art and finally the audio data.
1698 This is called on the audio thread after the buffering thread calls the
1699 buffering_handle_finished_callback callback. */
1700static int audio_finish_load_track(struct track_info *info)
1701{
1702 int trackstat = LOAD_TRACK_OK;
1703
1704 if (info->id3_hid != in_progress_id3_hid)
1705 {
1706 /* We must not be here if not! */
1707 logf("%s: wrong track %d/%d", __func__, info->id3_hid,
1708 in_progress_id3_hid);
1709 return LOAD_TRACK_ERR_BUSY;
1710 }
1711
1712 /* The current track for decoding (there is always one if the list is
1713 populated) */
1714 struct track_info *cur_info = track_list_current(0);
1715 struct mp3entry *track_id3 = valid_mp3entry(bufgetid3(info->id3_hid));
1716
1717 if (!track_id3)
1718 {
1719 /* This is an error condition. Track cannot be played without valid
1720 metadata; skip the track. */
Steve Bavin89ee9222011-08-26 15:46:18 +00001721 logf("No metadata");
Michael Sevakisc537d592011-04-27 03:08:23 +00001722 trackstat = LOAD_TRACK_ERR_FINISH_FAILED;
1723 goto audio_finish_load_track_exit;
1724 }
1725
1726 /* Try to load a cuesheet for the track */
1727 if (!audio_load_cuesheet(info, track_id3))
1728 {
1729 /* No space for cuesheet on buffer, not an error */
1730 filling = STATE_FULL;
1731 goto audio_finish_load_track_exit;
1732 }
1733
1734#ifdef HAVE_ALBUMART
1735 /* Try to load album art for the track */
1736 if (!audio_load_albumart(info, track_id3))
1737 {
1738 /* No space for album art on buffer, not an error */
1739 filling = STATE_FULL;
1740 goto audio_finish_load_track_exit;
1741 }
1742#endif
1743
Michael Sevakiscaf907e2011-05-25 08:35:31 +00001744 /* All handles available to external routines are ready - audio and codec
1745 information is private */
1746
1747 if (info == track_list_user_current(0))
1748 {
1749 /* Send only when the track handles could not all be opened ahead of
1750 time for the user's current track - otherwise everything is ready
1751 by the time PLAYBACK_EVENT_TRACK_CHANGE is sent */
1752 send_event(PLAYBACK_EVENT_CUR_TRACK_READY, id3_get(PLAYING_ID3));
1753 }
1754
Michael Sevakisc537d592011-04-27 03:08:23 +00001755#ifdef HAVE_CODEC_BUFFERING
1756 /* Try to buffer a codec for the track */
1757 if (info != cur_info && !audio_buffer_codec(info, track_id3))
1758 {
1759 if (info->codec_hid == ERR_BUFFER_FULL)
1760 {
1761 /* No space for codec on buffer, not an error */
1762 filling = STATE_FULL;
1763 logf("buffer is full for now (%s)", __func__);
1764 }
1765 else
1766 {
1767 /* This is an error condition, either no codec was found, or
1768 reading the codec file failed part way through, either way,
1769 skip the track */
1770 logf("No codec for: %s", track_id3->path);
1771 trackstat = LOAD_TRACK_ERR_FINISH_FAILED;
1772 }
1773
1774 goto audio_finish_load_track_exit;
1775 }
1776#endif /* HAVE_CODEC_BUFFERING */
1777
1778 /** Finally, load the audio **/
1779 size_t file_offset = 0;
1780 track_id3->elapsed = 0;
1781
1782 if (track_id3->offset >= info->filesize)
1783 track_id3->offset = 0;
1784
1785 logf("%s: set offset for %s to %lu\n", __func__,
1786 id3->title, (unsigned long)offset);
1787
1788 /* Adjust for resume rewind so we know what to buffer - starting the codec
1789 calls it again, so we don't save it (and they shouldn't accumulate) */
1790 size_t offset = resume_rewind_adjusted_offset(track_id3);
1791
1792 enum data_type audiotype = get_audio_base_data_type(track_id3->codectype);
1793
1794 if (audiotype == TYPE_ATOMIC_AUDIO)
1795 logf("Loading atomic %d", track_id3->codectype);
1796
1797 if (format_buffers_with_offset(track_id3->codectype))
1798 {
1799 /* This format can begin buffering from any point */
1800 file_offset = offset;
1801 }
1802
1803 logf("load track: %s", track_id3->path);
1804
1805 if (file_offset > AUDIO_REBUFFER_GUESS_SIZE)
1806 {
1807 /* We can buffer later in the file, adjust the hunt-and-peck margin */
1808 file_offset -= AUDIO_REBUFFER_GUESS_SIZE;
1809 }
1810 else
1811 {
1812 /* No offset given or it is very minimal - begin at the first frame
1813 according to the metadata */
1814 file_offset = track_id3->first_frame_offset;
1815 }
1816
1817 int hid = bufopen(track_id3->path, file_offset, audiotype, NULL);
1818
1819 if (hid >= 0)
1820 {
1821 info->audio_hid = hid;
1822
1823 if (info == cur_info)
1824 {
1825 /* This is the current track to decode - should be started now */
1826 trackstat = LOAD_TRACK_READY;
1827 }
1828 }
1829 else
1830 {
1831 /* Buffer could be full but not properly so if this is the only
1832 track! */
1833 if (hid == ERR_BUFFER_FULL && audio_track_count() > 1)
1834 {
1835 filling = STATE_FULL;
1836 logf("Buffer is full for now (%s)", __func__);
1837 }
1838 else
1839 {
1840 /* Nothing to play if no audio handle - skip this */
1841 logf("Could not add audio data handle");
1842 trackstat = LOAD_TRACK_ERR_FINISH_FAILED;
1843 }
1844 }
1845
1846audio_finish_load_track_exit:
1847 if (trackstat < LOAD_TRACK_OK)
1848 {
1849 playlist_skip_entry(NULL, playlist_peek_offset);
1850 track_info_close(info);
1851 track_list_unalloc_track();
1852
1853 if (playlist_peek(playlist_peek_offset, NULL, 0))
1854 playlist_next(0);
1855
1856 playlist_peek_offset--;
1857 }
1858
1859 if (filling != STATE_FULL)
1860 {
1861 /* Load next track - error or not */
1862 in_progress_id3_hid = ERR_HANDLE_NOT_FOUND;
1863 LOGFQUEUE("audio > audio Q_AUDIO_FILL_BUFFER");
1864 audio_queue_post(Q_AUDIO_FILL_BUFFER, 0);
1865 }
1866 else
1867 {
1868 /* Full */
1869 trackstat = LOAD_TRACK_ERR_FINISH_FULL;
1870 }
1871
1872 return trackstat;
1873}
1874
1875/* Start a new track load */
1876static int audio_fill_file_buffer(void)
1877{
1878 if (play_status == PLAY_STOPPED)
1879 return LOAD_TRACK_ERR_FAILED;
1880
1881 trigger_cpu_boost();
1882
1883 /* Must reset the buffer before use if trashed or voice only - voice
1884 file size shouldn't have changed so we can go straight from
1885 AUDIOBUF_STATE_VOICED_ONLY to AUDIOBUF_STATE_INITIALIZED */
1886 if (buffer_state != AUDIOBUF_STATE_INITIALIZED)
1887 audio_reset_buffer();
1888
1889 logf("Starting buffer fill");
1890
1891 int trackstat = audio_load_track();
1892
1893 if (trackstat >= LOAD_TRACK_OK)
1894 {
1895 if (track_list_current(0) == track_list_user_current(0))
1896 playlist_next(0);
1897
1898 if (filling == STATE_FULL && !track_list_user_current(1))
1899 {
1900 /* There are no user tracks on the buffer after this therefore
1901 this is the next track */
1902 audio_update_and_announce_next_track(id3_get(UNBUFFERED_ID3));
1903 }
1904 }
1905
1906 return trackstat;
1907}
1908
1909/* Discard unwanted tracks and start refill from after the specified playlist
1910 offset */
1911static int audio_reset_and_rebuffer(
1912 enum track_clear_action action, int peek_offset)
1913{
1914 logf("Forcing rebuffer: 0x%X, %d", flags, peek_offset);
1915
1916 id3_write_locked(UNBUFFERED_ID3, NULL);
1917
1918 /* Remove unwanted tracks - caller must have ensured codec isn't using
1919 any */
1920 track_list_clear(action);
1921
1922 /* Refill at specified position (-1 starts at index offset 0) */
1923 playlist_peek_offset = peek_offset;
1924
1925 /* Fill the buffer */
1926 return audio_fill_file_buffer();
1927}
1928
1929/* Handle buffering events
1930 (Q_AUDIO_BUFFERING) */
1931static void audio_on_buffering(int event)
1932{
1933 enum track_clear_action action;
1934 int peek_offset;
1935
1936 if (track_list_empty())
1937 return;
Jeffrey Goode8cb4b362011-05-09 21:52:06 +00001938
Michael Sevakisc537d592011-04-27 03:08:23 +00001939 switch (event)
1940 {
1941 case BUFFER_EVENT_BUFFER_LOW:
1942 if (filling != STATE_FULL && filling != STATE_END_OF_PLAYLIST)
1943 return; /* Should be nothing left to fill */
1944
1945 /* Clear old tracks and continue buffering where it left off */
1946 action = TRACK_LIST_KEEP_NEW;
1947 peek_offset = playlist_peek_offset;
1948 break;
1949
1950 case BUFFER_EVENT_REBUFFER:
1951 /* Remove all but the currently decoding track and redo buffering
1952 after that */
1953 action = TRACK_LIST_KEEP_CURRENT;
1954 peek_offset = (skip_pending == TRACK_SKIP_AUTO) ? 1 : 0;
1955 break;
1956
1957 default:
1958 return;
1959 }
1960
1961 switch (skip_pending)
1962 {
1963 case TRACK_SKIP_NONE:
1964 case TRACK_SKIP_AUTO:
1965 case TRACK_SKIP_AUTO_NEW_PLAYLIST:
1966 audio_reset_and_rebuffer(action, peek_offset);
1967 break;
1968
1969 case TRACK_SKIP_AUTO_END_PLAYLIST:
1970 /* Already finished */
1971 break;
1972
1973 default:
1974 /* Invalid */
1975 logf("Buffering call, inv. state: %d", (int)skip_pending);
1976 }
1977}
1978
1979/* Handle starting the next track load
1980 (Q_AUDIO_FILL_BUFFER) */
1981static void audio_on_fill_buffer(void)
1982{
1983 audio_handle_track_load_status(audio_fill_file_buffer());
1984}
1985
1986/* Handle posted load track finish event
1987 (Q_AUDIO_FINISH_LOAD_TRACK) */
1988static void audio_on_finish_load_track(int id3_hid)
1989{
1990 struct track_info *info = track_list_last(0);
1991
1992 if (!info || !buf_is_handle(id3_hid))
1993 return;
1994
1995 if (info == track_list_user_current(1))
1996 {
1997 /* Just loaded the metadata right after the current position */
1998 audio_update_and_announce_next_track(bufgetid3(info->id3_hid));
1999 }
2000
2001 if (audio_finish_load_track(info) != LOAD_TRACK_READY)
2002 return; /* Not current track */
2003
2004 bool is_user_current = info == track_list_user_current(0);
2005
2006 if (is_user_current)
2007 {
2008 /* Copy cuesheet */
2009 buf_read_cuesheet(info->cuesheet_hid);
2010 }
2011
2012 if (audio_start_codec(automatic_skip))
2013 {
2014 if (is_user_current)
2015 {
2016 /* Be sure all tagtree info is synchronized; it will be needed for the
2017 track finish event - the sync will happen when finalizing a track
2018 change otherwise */
2019 bool was_valid = valid_mp3entry(id3_get(PLAYING_ID3));
2020
2021 playing_id3_sync(info, -1);
2022
2023 if (!was_valid)
2024 {
2025 /* Playing id3 hadn't been updated yet because no valid track
2026 was yet available - treat like the first track */
2027 audio_playlist_track_change();
2028 }
2029 }
2030 }
2031 else
2032 {
2033 audio_handle_track_load_status(LOAD_TRACK_ERR_START_CODEC);
2034 }
2035}
2036
2037/* Called when handles other than metadata handles have finished buffering
2038 (Q_AUDIO_HANDLE_FINISHED) */
2039static void audio_on_handle_finished(int hid)
2040{
2041 /* Right now, only audio handles should end up calling this */
2042 if (filling == STATE_END_OF_PLAYLIST)
2043 {
2044 struct track_info *info = track_list_last(0);
2045
2046 /* Really we don't know which order the handles will actually complete
2047 to zero bytes remaining since another thread is doing it - be sure
2048 it's the right one */
2049 if (info && info->audio_hid == hid)
2050 {
2051 /* This was the last track in the playlist and we now have all the
2052 data we need */
2053 filling_is_finished();
2054 }
2055 }
2056}
2057
2058/* Called to make an outstanding track skip the current track and to send the
2059 transition events */
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00002060static void audio_finalise_track_change(void)
Michael Sevakisc537d592011-04-27 03:08:23 +00002061{
2062 switch (skip_pending)
2063 {
2064 case TRACK_SKIP_NONE: /* Manual skip */
2065 break;
2066
2067 case TRACK_SKIP_AUTO:
2068 case TRACK_SKIP_AUTO_NEW_PLAYLIST:
2069 {
2070 int playlist_delta = skip_pending == TRACK_SKIP_AUTO ? 1 : 0;
2071 audio_playlist_track_finish();
2072
2073 if (!playlist_peek(playlist_delta, NULL, 0))
2074 {
2075 /* Track ended up rejected - push things ahead like the codec blew
2076 it (because it was never started and now we're here where it
2077 should have been decoding the next track by now) - next, a
2078 directory change or end of playback will most likely happen */
2079 skip_pending = TRACK_SKIP_NONE;
2080 audio_handle_track_load_status(LOAD_TRACK_ERR_START_CODEC);
2081 return;
2082 }
2083
2084 if (!playlist_delta)
2085 break;
2086
2087 playlist_peek_offset -= playlist_delta;
2088 if (playlist_next(playlist_delta) >= 0)
2089 break;
2090 /* What!? Disappear? Hopeless bleak despair */
2091 }
2092 /* Fallthrough */
2093 case TRACK_SKIP_AUTO_END_PLAYLIST:
2094 default: /* Invalid */
2095 filling = STATE_ENDED;
2096 audio_stop_playback();
2097 return;
2098 }
2099
2100 struct track_info *info = track_list_current(0);
2101 struct mp3entry *track_id3 = NULL;
2102
2103 id3_mutex_lock();
2104
2105 /* Update the current cuesheet if any and enabled */
2106 if (info)
2107 {
2108 buf_read_cuesheet(info->cuesheet_hid);
2109 track_id3 = bufgetid3(info->id3_hid);
2110 }
2111
2112 id3_write(PLAYING_ID3, track_id3);
2113
Michael Sevakisc537d592011-04-27 03:08:23 +00002114 /* The skip is technically over */
2115 skip_pending = TRACK_SKIP_NONE;
2116
2117 /* Sync the next track information */
2118 info = track_list_current(1);
2119
2120 id3_write(NEXTTRACK_ID3, info ? bufgetid3(info->id3_hid) :
2121 id3_get(UNBUFFERED_ID3));
2122
2123 id3_mutex_unlock();
2124
2125 audio_playlist_track_change();
2126}
2127
2128/* Actually begin a transition and take care of the codec change - may complete
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00002129 it now or ask pcmbuf for notification depending on the type */
2130static void audio_begin_track_change(enum pcm_track_change_type type,
2131 int trackstat)
Michael Sevakisc537d592011-04-27 03:08:23 +00002132{
2133 /* Even if the new track is bad, the old track must be finished off */
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00002134 pcmbuf_start_track_change(type);
Michael Sevakisc537d592011-04-27 03:08:23 +00002135
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00002136 bool auto_skip = type != TRACK_CHANGE_MANUAL;
2137
2138 if (!auto_skip)
Michael Sevakisc537d592011-04-27 03:08:23 +00002139 {
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00002140 /* Manual track change happens now */
2141 audio_finalise_track_change();
2142 pcmbuf_sync_position_update();
Michael Sevakisc537d592011-04-27 03:08:23 +00002143
2144 if (play_status == PLAY_STOPPED)
2145 return; /* Stopped us */
2146 }
2147
Michael Sevakisc537d592011-04-27 03:08:23 +00002148 if (trackstat >= LOAD_TRACK_OK)
2149 {
2150 struct track_info *info = track_list_current(0);
2151
2152 if (info->audio_hid < 0)
2153 return;
2154
2155 /* Everything needed for the codec is ready - start it */
2156 if (audio_start_codec(auto_skip))
2157 {
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00002158 if (!auto_skip)
Michael Sevakisc537d592011-04-27 03:08:23 +00002159 playing_id3_sync(info, -1);
2160 return;
2161 }
2162
2163 trackstat = LOAD_TRACK_ERR_START_CODEC;
2164 }
2165
2166 audio_handle_track_load_status(trackstat);
2167}
2168
2169/* Transition to end-of-playlist state and begin wait for PCM to finish */
2170static void audio_monitor_end_of_playlist(void)
2171{
2172 skip_pending = TRACK_SKIP_AUTO_END_PLAYLIST;
2173 filling = STATE_ENDING;
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00002174 pcmbuf_start_track_change(TRACK_CHANGE_END_OF_DATA);
Michael Sevakisc537d592011-04-27 03:08:23 +00002175}
2176
2177/* Codec has completed decoding the track
2178 (usually Q_AUDIO_CODEC_COMPLETE) */
2179static void audio_on_codec_complete(int status)
2180{
2181 logf("%s(%d)", __func__, status);
2182
2183 if (play_status == PLAY_STOPPED)
2184 return;
2185
2186 /* If it didn't notify us first, don't expect "seek complete" message
2187 since the codec can't post it now - do things like it would have
2188 done */
2189 audio_complete_codec_seek();
2190
2191 if (play_status == PLAY_PAUSED || skip_pending != TRACK_SKIP_NONE)
2192 {
2193 /* Old-hay on the ip-skay - codec has completed decoding
2194
2195 Paused: We're not sounding it, so just remember that it happened
2196 and the resume will begin the transition
2197
2198 Skipping: There was already a skip in progress, remember it and
2199 allow no further progress until the PCM from the previous
2200 song has finished
2201 */
2202 codec_skip_pending = true;
2203 codec_skip_status = status;
2204 return;
2205 }
2206
2207 codec_skip_pending = false;
2208
Michael Sevakisc537d592011-04-27 03:08:23 +00002209 int trackstat = LOAD_TRACK_OK;
2210
2211 automatic_skip = true;
2212 skip_pending = TRACK_SKIP_AUTO;
2213
2214 /* Does this track have an entry allocated? */
2215 struct track_info *info = track_list_advance_current(1);
2216
2217 if (!info || info->audio_hid < 0)
2218 {
2219 bool end_of_playlist = false;
2220
2221 if (info)
2222 {
2223 /* Track load is not complete - it might have stopped on a
2224 full buffer without reaching the audio handle or we just
2225 arrived at it early
2226
2227 If this type is atomic and we couldn't get the audio,
2228 perhaps it would need to wrap to make the allocation and
2229 handles are in the way - to maximize the liklihood it can
2230 be allocated, clear all handles to reset the buffer and
2231 its indexes to 0 - for packet audio, this should not be an
2232 issue and a pointless full reload of all the track's
2233 metadata may be avoided */
2234
2235 struct mp3entry *track_id3 = bufgetid3(info->id3_hid);
2236
2237 if (track_id3 &&
2238 get_audio_base_data_type(track_id3->codectype)
2239 == TYPE_PACKET_AUDIO)
2240 {
2241 /* Continue filling after this track */
2242 audio_reset_and_rebuffer(TRACK_LIST_KEEP_CURRENT, 1);
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00002243 audio_begin_track_change(TRACK_CHANGE_AUTO, trackstat);
Michael Sevakisc537d592011-04-27 03:08:23 +00002244 return;
2245 }
2246 /* else rebuffer at this track; status applies to the track we
2247 want */
2248 }
2249 else if (!playlist_peek(1, NULL, 0))
2250 {
2251 /* Play sequence is complete - directory change or other playlist
2252 resequencing - the playlist must now be advanced in order to
2253 continue since a peek ahead to the next track is not possible */
2254 skip_pending = TRACK_SKIP_AUTO_NEW_PLAYLIST;
2255 end_of_playlist = playlist_next(1) < 0;
2256 }
2257
2258 if (!end_of_playlist)
2259 {
2260 trackstat = audio_reset_and_rebuffer(TRACK_LIST_CLEAR_ALL,
2261 skip_pending == TRACK_SKIP_AUTO ? 0 : -1);
2262
2263 if (trackstat == LOAD_TRACK_ERR_NO_MORE)
2264 {
Jeffrey Goode8cb4b362011-05-09 21:52:06 +00002265 /* Failed to find anything after all - do playlist switchover
Michael Sevakisc537d592011-04-27 03:08:23 +00002266 instead */
2267 skip_pending = TRACK_SKIP_AUTO_NEW_PLAYLIST;
2268 end_of_playlist = playlist_next(1) < 0;
2269 }
2270 }
2271
2272 if (end_of_playlist)
2273 {
2274 audio_monitor_end_of_playlist();
2275 return;
2276 }
2277 }
2278
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00002279 audio_begin_track_change(TRACK_CHANGE_AUTO, trackstat);
Michael Sevakisc537d592011-04-27 03:08:23 +00002280}
2281
2282/* Called when codec completes seek operation
2283 (usually Q_AUDIO_CODEC_SEEK_COMPLETE) */
2284static void audio_on_codec_seek_complete(void)
2285{
2286 logf("%s()", __func__);
2287 audio_complete_codec_seek();
2288 codec_go();
2289}
2290
2291/* Called when PCM track change has completed
2292 (Q_AUDIO_TRACK_CHANGED) */
2293static void audio_on_track_changed(void)
2294{
2295 /* Finish whatever is pending so that the WPS is in sync */
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00002296 audio_finalise_track_change();
Michael Sevakisc537d592011-04-27 03:08:23 +00002297
2298 if (codec_skip_pending)
2299 {
2300 /* Codec got ahead completing a short track - complete the
2301 codec's skip and begin the next */
2302 codec_skip_pending = false;
2303 audio_on_codec_complete(codec_skip_status);
2304 }
2305}
2306
2307/* Begin playback from an idle state, transition to a new playlist or
2308 invalidate the buffer and resume (if playing).
2309 (usually Q_AUDIO_PLAY, Q_AUDIO_REMAKE_AUDIO_BUFFER) */
2310static void audio_start_playback(size_t offset, unsigned int flags)
2311{
2312 enum play_status old_status = play_status;
2313
2314 if (flags & AUDIO_START_NEWBUF)
2315 {
2316 /* Mark the buffer dirty - if not playing, it will be reset next
2317 time */
2318 if (buffer_state == AUDIOBUF_STATE_INITIALIZED)
2319 buffer_state = AUDIOBUF_STATE_VOICED_ONLY;
2320 }
2321
2322 if (old_status != PLAY_STOPPED)
2323 {
2324 logf("%s(%lu): skipping", __func__, (unsigned long)offset);
2325
2326 halt_decoding_track(true);
2327
2328 automatic_skip = false;
2329 ff_rw_mode = false;
2330
2331 if (flags & AUDIO_START_RESTART)
2332 {
2333 /* Clear out some stuff to resume the current track where it
2334 left off */
2335 pcmbuf_play_stop();
2336 offset = id3_get(PLAYING_ID3)->offset;
2337 track_list_clear(TRACK_LIST_CLEAR_ALL);
2338 }
2339 else
2340 {
2341 /* This is more-or-less treated as manual track transition */
2342 /* Save resume information for current track */
2343 audio_playlist_track_finish();
2344 track_list_clear(TRACK_LIST_CLEAR_ALL);
2345
2346 /* Indicate manual track change */
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00002347 pcmbuf_start_track_change(TRACK_CHANGE_MANUAL);
Michael Sevakisc537d592011-04-27 03:08:23 +00002348 wipe_track_metadata(true);
2349 }
2350
2351 /* Set after track finish event in case skip was in progress */
2352 skip_pending = TRACK_SKIP_NONE;
2353 }
2354 else
2355 {
2356 if (flags & AUDIO_START_RESTART)
2357 return; /* Must already be playing */
2358
2359 /* Cold playback start from a stopped state */
2360 logf("%s(%lu): starting", __func__, offset);
2361
2362 /* Set audio parameters */
2363#if INPUT_SRC_CAPS != 0
2364 audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
2365 audio_set_output_source(AUDIO_SRC_PLAYBACK);
2366#endif
2367#ifndef PLATFORM_HAS_VOLUME_CHANGE
2368 sound_set_volume(global_settings.volume);
2369#endif
Michael Sevakisa2b67032011-06-29 06:37:04 +00002370 /* Be sure channel is audible */
2371 pcmbuf_fade(false, true);
2372
Michael Sevakisc537d592011-04-27 03:08:23 +00002373 /* Update our state */
2374 play_status = PLAY_PLAYING;
2375 }
2376
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00002377 /* Codec's position should be available as soon as it knows it */
2378 position_key = pcmbuf_get_position_key();
2379 pcmbuf_sync_position_update();
2380
Michael Sevakisc537d592011-04-27 03:08:23 +00002381 /* Start fill from beginning of playlist */
2382 playlist_peek_offset = -1;
2383 buf_set_base_handle(-1);
2384
2385 /* Officially playing */
2386 queue_reply(&audio_queue, 1);
2387
2388 /* Add these now - finish event for the first id3 will most likely be sent
2389 immediately */
2390 add_event(BUFFER_EVENT_REBUFFER, false, buffer_event_rebuffer_callback);
2391 add_event(BUFFER_EVENT_FINISHED, false, buffer_event_finished_callback);
2392
2393 if (old_status == PLAY_STOPPED)
2394 {
2395 /* Send coldstart event */
2396 send_event(PLAYBACK_EVENT_START_PLAYBACK, NULL);
2397 }
2398
2399 /* Fill the buffer */
2400 int trackstat = audio_fill_file_buffer();
2401
2402 if (trackstat >= LOAD_TRACK_OK)
2403 {
2404 /* This is the currently playing track - get metadata, stat */
2405 playing_id3_sync(track_list_current(0), offset);
2406
2407 if (valid_mp3entry(id3_get(PLAYING_ID3)))
2408 {
2409 /* Only if actually changing tracks... */
2410 if (!(flags & AUDIO_START_RESTART))
2411 audio_playlist_track_change();
2412 }
2413 }
2414 else
2415 {
2416 /* Found nothing playable */
2417 audio_handle_track_load_status(trackstat);
2418 }
2419}
2420
2421/* Stop playback and enter an idle state
2422 (usually Q_AUDIO_STOP) */
2423static void audio_stop_playback(void)
2424{
2425 logf("%s()", __func__);
2426
2427 if (play_status == PLAY_STOPPED)
2428 return;
2429
Michael Sevakis5078d462011-08-23 01:37:59 +00002430 bool do_fade = global_settings.fade_on_stop && filling != STATE_ENDED;
2431
2432 pcmbuf_fade(do_fade, false);
2433
2434 /* Wait for fade-out */
2435 audio_wait_fade_complete();
Michael Sevakisa2b67032011-06-29 06:37:04 +00002436
Michael Sevakisc537d592011-04-27 03:08:23 +00002437 /* Stop the codec and unload it */
2438 halt_decoding_track(true);
2439 pcmbuf_play_stop();
2440 codec_unload();
2441
2442 /* Save resume information - "filling" might have been set to
2443 "STATE_ENDED" by caller in order to facilitate end of playlist */
2444 audio_playlist_track_finish();
2445
2446 skip_pending = TRACK_SKIP_NONE;
2447 automatic_skip = false;
2448
2449 /* Close all tracks and mark them NULL */
2450 remove_event(BUFFER_EVENT_REBUFFER, buffer_event_rebuffer_callback);
2451 remove_event(BUFFER_EVENT_FINISHED, buffer_event_finished_callback);
2452 remove_event(BUFFER_EVENT_BUFFER_LOW, buffer_event_buffer_low_callback);
2453
2454 track_list_clear(TRACK_LIST_CLEAR_ALL);
2455
2456 /* Update our state */
2457 ff_rw_mode = false;
2458 play_status = PLAY_STOPPED;
2459
2460 wipe_track_metadata(true);
2461
2462 /* Go idle */
2463 filling = STATE_IDLE;
2464 cancel_cpu_boost();
2465}
2466
2467/* Pause the playback of the current track
2468 (Q_AUDIO_PAUSE) */
2469static void audio_on_pause(bool pause)
2470{
2471 logf("%s(%s)", __func__, pause ? "true" : "false");
2472
2473 if (play_status == PLAY_STOPPED || pause == (play_status == PLAY_PAUSED))
2474 return;
2475
Michael Sevakisc537d592011-04-27 03:08:23 +00002476 play_status = pause ? PLAY_PAUSED : PLAY_PLAYING;
2477
2478 if (!pause && codec_skip_pending)
2479 {
2480 /* Actually do the skip that is due - resets the status flag */
2481 audio_on_codec_complete(codec_skip_status);
2482 }
Michael Sevakis5078d462011-08-23 01:37:59 +00002483
2484 bool do_fade = global_settings.fade_on_stop;
2485
2486 pcmbuf_fade(do_fade, !pause);
2487
2488 if (!ff_rw_mode && !(do_fade && pause))
2489 {
2490 /* Not in ff/rw mode - can actually change the audio state now */
2491 pcmbuf_pause(pause);
2492 }
Michael Sevakisc537d592011-04-27 03:08:23 +00002493}
2494
2495/* Skip a certain number of tracks forwards or backwards
2496 (Q_AUDIO_SKIP) */
2497static void audio_on_skip(void)
2498{
2499 id3_mutex_lock();
2500
2501 /* Eat the delta to keep it synced, even if not playing */
2502 int toskip = skip_offset;
2503 skip_offset = 0;
2504
2505 logf("%s(): %d", __func__, toskip);
2506
2507 id3_mutex_unlock();
2508
2509 if (play_status == PLAY_STOPPED)
2510 return;
2511
2512 /* Force codec to abort this track */
2513 halt_decoding_track(true);
2514
2515 /* Kill the ff/rw halt */
2516 ff_rw_mode = false;
2517
2518 /* Manual skip */
2519 automatic_skip = false;
2520
2521 /* If there was an auto skip in progress, there will be residual
2522 advancement of the playlist and/or track list so compensation will be
2523 required in order to end up in the right spot */
2524 int track_list_delta = toskip;
2525 int playlist_delta = toskip;
2526
2527 if (skip_pending != TRACK_SKIP_NONE)
2528 {
2529 if (skip_pending != TRACK_SKIP_AUTO_END_PLAYLIST)
2530 track_list_delta--;
2531
2532 if (skip_pending == TRACK_SKIP_AUTO_NEW_PLAYLIST)
2533 playlist_delta--;
2534 }
2535
2536 audio_playlist_track_finish();
2537 skip_pending = TRACK_SKIP_NONE;
2538
2539 /* Update the playlist current track now */
2540 while (playlist_next(playlist_delta) < 0)
2541 {
2542 /* Manual skip out of range (because the playlist wasn't updated
2543 yet by us and so the check in audio_skip returned 'ok') - bring
2544 back into range */
2545 int d = toskip < 0 ? 1 : -1;
2546
2547 while (!playlist_check(playlist_delta))
2548 {
2549 if (playlist_delta == d)
2550 {
2551 /* Had to move the opposite direction to correct, which is
2552 wrong - this is the end */
2553 filling = STATE_ENDED;
2554 audio_stop_playback();
2555 return;
2556 }
2557
2558 playlist_delta += d;
2559 track_list_delta += d;
2560 }
2561 }
2562
2563 /* Adjust things by how much the playlist was manually moved */
2564 playlist_peek_offset -= playlist_delta;
2565
2566 struct track_info *info = track_list_advance_current(track_list_delta);
2567 int trackstat = LOAD_TRACK_OK;
2568
2569 if (!info || info->audio_hid < 0)
2570 {
2571 /* We don't know the next track thus we know we don't have it */
2572 trackstat = audio_reset_and_rebuffer(TRACK_LIST_CLEAR_ALL, -1);
2573 }
2574
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00002575 audio_begin_track_change(TRACK_CHANGE_MANUAL, trackstat);
Michael Sevakisc537d592011-04-27 03:08:23 +00002576}
2577
2578/* Skip to the next/previous directory
2579 (Q_AUDIO_DIR_SKIP) */
2580static void audio_on_dir_skip(int direction)
2581{
2582 logf("%s(%d)", __func__, direction);
2583
2584 id3_mutex_lock();
2585 skip_offset = 0;
2586 id3_mutex_unlock();
2587
2588 if (play_status == PLAY_STOPPED)
2589 return;
2590
2591 /* Force codec to abort this track */
2592 halt_decoding_track(true);
2593
2594 /* Kill the ff/rw halt */
2595 ff_rw_mode = false;
2596
2597 /* Manual skip */
2598 automatic_skip = false;
2599
2600 audio_playlist_track_finish();
2601
2602 /* Unless automatic and gapless, skips do not pend */
2603 skip_pending = TRACK_SKIP_NONE;
2604
2605 /* Regardless of the return value we need to rebuffer. If it fails the old
2606 playlist will resume, else the next dir will start playing. */
2607 playlist_next_dir(direction);
2608
2609 wipe_track_metadata(false);
2610
2611 int trackstat = audio_reset_and_rebuffer(TRACK_LIST_CLEAR_ALL, -1);
2612
2613 if (trackstat == LOAD_TRACK_ERR_NO_MORE)
2614 {
2615 /* The day the music died - finish-off whatever is playing and call it
2616 quits */
2617 audio_monitor_end_of_playlist();
2618 return;
2619 }
2620
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00002621 audio_begin_track_change(TRACK_CHANGE_MANUAL, trackstat);
Michael Sevakisc537d592011-04-27 03:08:23 +00002622}
2623
2624/* Enter seek mode in order to start a seek
2625 (Q_AUDIO_PRE_FF_REWIND) */
2626static void audio_on_pre_ff_rewind(void)
2627{
2628 logf("%s()", __func__);
2629
2630 if (play_status == PLAY_STOPPED || ff_rw_mode)
2631 return;
2632
2633 ff_rw_mode = true;
2634
Michael Sevakis5078d462011-08-23 01:37:59 +00002635 audio_wait_fade_complete();
2636
Michael Sevakisc537d592011-04-27 03:08:23 +00002637 if (play_status == PLAY_PAUSED)
2638 return;
2639
2640 pcmbuf_pause(true);
2641}
2642
2643/* Seek the playback of the current track to the specified time
2644 (Q_AUDIO_FF_REWIND) */
2645static void audio_on_ff_rewind(long time)
2646{
2647 logf("%s(%ld)", __func__, time);
2648
2649 if (play_status == PLAY_STOPPED)
2650 return;
2651
2652 enum track_skip_type pending = skip_pending;
2653
2654 switch (pending)
2655 {
2656 case TRACK_SKIP_NONE: /* The usual case */
2657 case TRACK_SKIP_AUTO: /* Have to back it out (fun!) */
2658 case TRACK_SKIP_AUTO_END_PLAYLIST: /* Still have the last codec used */
2659 {
2660 struct mp3entry *id3 = id3_get(PLAYING_ID3);
2661 struct mp3entry *ci_id3 = id3_get(CODEC_ID3);
2662
2663 automatic_skip = false;
2664
2665 /* Send event before clobbering the time */
2666 /* FIXME: Nasty, but the tagtree expects this so that rewinding and
2667 then skipping back to this track resumes properly. Something else
2668 should be sent. We're not _really_ finishing the track are we? */
2669 if (time == 0)
2670 send_event(PLAYBACK_EVENT_TRACK_FINISH, id3);
2671
Michael Sevakisc537d592011-04-27 03:08:23 +00002672 id3->elapsed = time;
2673 queue_reply(&audio_queue, 1);
2674
2675 bool haltres = halt_decoding_track(pending == TRACK_SKIP_AUTO);
2676
2677 /* Need this set in case ff/rw mode + error but _after_ the codec
2678 halt that will reset it */
2679 codec_seeking = true;
2680
Michael Sevakis7ad2cad2011-08-28 07:45:35 +00002681 /* If in transition, key will have changed - sync to it */
2682 position_key = pcmbuf_get_position_key();
2683
Michael Sevakisc537d592011-04-27 03:08:23 +00002684 if (pending == TRACK_SKIP_AUTO)
2685 {
2686 if (!track_list_advance_current(-1))
2687 {
2688 /* Not in list - must rebuffer at the current playlist index */
2689 if (audio_reset_and_rebuffer(TRACK_LIST_CLEAR_ALL, -1)
2690 < LOAD_TRACK_OK)
2691 {
2692 /* Codec is stopped */
2693 break;
2694 }
2695 }
2696 }
2697
2698 /* Set after audio_fill_file_buffer to disable playing id3 clobber if
2699 rebuffer is needed */
2700 skip_pending = TRACK_SKIP_NONE;
2701 struct track_info *cur_info = track_list_current(0);
2702
2703 /* Track must complete the loading _now_ since a codec and audio
2704 handle are needed in order to do the seek */
2705 if (cur_info->audio_hid < 0 &&
2706 audio_finish_load_track(cur_info) != LOAD_TRACK_READY)
2707 {
2708 /* Call above should push any load sequence - no need for
2709 halt_decoding_track here if no skip was pending here because
2710 there would not be a codec started if no audio handle was yet
2711 opened */
2712 break;
2713 }
2714
2715 if (pending == TRACK_SKIP_AUTO)
2716 {
2717 if (!bufreadid3(cur_info->id3_hid, ci_id3) ||
2718 !audio_init_codec(cur_info, ci_id3))
2719 {
2720 /* We should have still been able to get it - skip it and move
Jeffrey Goode8cb4b362011-05-09 21:52:06 +00002721 onto the next one - like it or not this track is broken */
Michael Sevakisc537d592011-04-27 03:08:23 +00002722 break;
2723 }
2724
2725 /* Set the codec API to the correct metadata and track info */
2726 ci.audio_hid = cur_info->audio_hid;
2727 ci.filesize = cur_info->filesize;
2728 buf_set_base_handle(cur_info->audio_hid);
2729 }
2730
2731 if (!haltres)
2732 {
2733 /* If codec must be (re)started, reset the offset */
2734 ci_id3->offset = 0;
2735 }
2736
2737 codec_seek(time);
2738 return;
2739 }
2740
2741 case TRACK_SKIP_AUTO_NEW_PLAYLIST:
2742 {
2743 /* We cannot do this because the playlist must be reversed by one
2744 and it doesn't always return the same song when going backwards
2745 across boundaries as forwards (either because of randomization
2746 or inconsistency in deciding what the previous track should be),
2747 therefore the whole operation would often end up as nonsense -
2748 lock out seeking for a couple seconds */
2749
2750 /* Sure as heck cancel seek mode too! */
2751 audio_ff_rewind_end();
2752 return;
2753 }
2754
2755 default:
2756 /* Won't see this */
2757 return;
2758 }
2759
2760 if (play_status == PLAY_STOPPED)
2761 {
2762 /* Playback ended because of an error completing a track load */
2763 return;
2764 }
2765
2766 /* Always fake it as a codec start error which will handle mode
2767 cancellations and skip to the next track */
2768 audio_handle_track_load_status(LOAD_TRACK_ERR_START_CODEC);
2769}
2770
2771/* Invalidates all but currently playing track
2772 (Q_AUDIO_FLUSH) */
2773static void audio_on_audio_flush(void)
2774{
2775 logf("%s", __func__);
2776
2777 if (track_list_empty())
2778 return; /* Nothing to flush out */
2779
2780 switch (skip_pending)
2781 {
2782 case TRACK_SKIP_NONE:
2783 case TRACK_SKIP_AUTO_END_PLAYLIST:
2784 /* Remove all but the currently playing track from the list and
2785 refill after that */
2786 track_list_clear(TRACK_LIST_KEEP_CURRENT);
2787 playlist_peek_offset = 0;
2788 id3_write_locked(UNBUFFERED_ID3, NULL);
2789 audio_update_and_announce_next_track(NULL);
2790
Jeffrey Goode8cb4b362011-05-09 21:52:06 +00002791 /* Ignore return since it's about the next track, not this one */
Michael Sevakisc537d592011-04-27 03:08:23 +00002792 audio_fill_file_buffer();