summaryrefslogtreecommitdiff
path: root/apps/playback.c
diff options
context:
space:
mode:
authorBrandon Low <lostlogic@rockbox.org>2007-01-26 18:35:49 +0000
committerBrandon Low <lostlogic@rockbox.org>2007-01-26 18:35:49 +0000
commitbe95ff457038cb443b1936a70306dc20d24d8481 (patch)
tree025f307be10ce25f80dc8b6d58528a9574f028a5 /apps/playback.c
parent7d409adba4ac5dcdf66898ba0a2ca32e274f5c1b (diff)
downloadrockbox-be95ff457038cb443b1936a70306dc20d24d8481.tar.gz
rockbox-be95ff457038cb443b1936a70306dc20d24d8481.zip
No functional changes. Code police and comment clarity improvements.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@12120 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/playback.c')
-rw-r--r--apps/playback.c214
1 files changed, 124 insertions, 90 deletions
diff --git a/apps/playback.c b/apps/playback.c
index 9c81210dcc..c4f590c34f 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -197,68 +197,87 @@ static bool audio_is_initialized = false;
197/* TBD: Split out "audio" and "playback" (ie. calling) threads */ 197/* TBD: Split out "audio" and "playback" (ie. calling) threads */
198 198
199/* Main state control */ 199/* Main state control */
200static volatile bool audio_codec_loaded; /* Is codec loaded? (C/A-) */ 200static volatile bool audio_codec_loaded; /* Is codec loaded? (C/A-) */
201static volatile bool playing; /* Is audio playing? (A) */ 201static volatile bool playing; /* Is audio playing? (A) */
202static volatile bool paused; /* Is audio paused? (A/C-) */ 202static volatile bool paused; /* Is audio paused? (A/C-) */
203static volatile bool filling IDATA_ATTR; /* Is file buffer currently being refilled? (A/C-) */ 203static volatile bool filling IDATA_ATTR; /* Is file buffer refilling? (A/C-) */
204 204
205/* Ring buffer where tracks and codecs are loaded */ 205/* Ring buffer where compressed audio and codecs are loaded */
206static unsigned char *filebuf; /* Pointer to start of ring buffer (A/C-) */ 206static unsigned char *filebuf; /* Start of buffer (A/C-) */
207size_t filebuflen; /* Total size of the ring buffer FIXME: make static (A/C-)*/ 207/* FIXME: make filebuflen static */
208static volatile size_t buf_ridx IDATA_ATTR; /* Ring buffer read position (A/C) FIXME? should be (C/A-) */ 208size_t filebuflen; /* Size of buffer (A/C-) */
209static volatile size_t buf_widx IDATA_ATTR; /* Ring buffer read position (A/C-) */ 209/* FIXME: make buf_ridx (C/A-) */
210 210static volatile size_t buf_ridx IDATA_ATTR; /* Buffer read position (A/C)*/
211#define BUFFER_STATE_TRASHED -1 /* Buffer is in a trashed state and must be reset */ 211static volatile size_t buf_widx IDATA_ATTR; /* Buffer write position (A/C-) */
212#define BUFFER_STATE_NORMAL 0 /* Buffer is arranged for voice and audio */ 212
213#define BUFFER_STATE_VOICED_ONLY 1 /* Buffer is arranged for voice-only use */ 213/* Possible arrangements of the buffer */
214#define BUFFER_STATE_TRASHED -1 /* trashed; must be reset */
215#define BUFFER_STATE_NORMAL 0 /* voice+audio OR audio-only */
216#define BUFFER_STATE_VOICED_ONLY 1 /* voice-only */
214static int buffer_state = BUFFER_STATE_TRASHED; /* Buffer state */ 217static int buffer_state = BUFFER_STATE_TRASHED; /* Buffer state */
215 218
219/* Compressed ring buffer helper macros */
220/* Buffer pointer (p) plus value (v), wrapped if necessary */
216#define RINGBUF_ADD(p,v) ((p+v)<filebuflen ? p+v : p+v-filebuflen) 221#define RINGBUF_ADD(p,v) ((p+v)<filebuflen ? p+v : p+v-filebuflen)
222/* Buffer pointer (p) minus value (v), wrapped if necessary */
217#define RINGBUF_SUB(p,v) ((p>=v) ? p-v : p+filebuflen-v) 223#define RINGBUF_SUB(p,v) ((p>=v) ? p-v : p+filebuflen-v)
218#define RINGBUF_ADD_CROSS(p1,v,p2) ((p1<p2)?(int)(p1+v)-(int)p2:(int)(p1+v-p2)-(int)filebuflen) 224/* How far value (v) plus buffer pointer (p1) will cross buffer pointer (p2) */
219#define FILEBUFUSED RINGBUF_SUB(buf_widx, buf_ridx) /* Bytes available in the buffer */ 225#define RINGBUF_ADD_CROSS(p1,v,p2) \
220 226 ((p1<p2)?(int)(p1+v)-(int)p2:(int)(p1+v-p2)-(int)filebuflen)
221/* Track info buffer */ 227/* Bytes available in the buffer */
222static struct track_info tracks[MAX_TRACK]; /* Track info structure about songs in the file buffer (A/C-) */ 228#define FILEBUFUSED RINGBUF_SUB(buf_widx, buf_ridx)
223static volatile int track_ridx; /* Track being decoded (A/C-) */ 229
224static int track_widx; /* Track being buffered (A) */ 230/* Track info structure about songs in the file buffer (A/C-) */
225static bool track_changed; /* Set to indicate track has changed (A) */ 231static struct track_info tracks[MAX_TRACK];
226static struct track_info *prev_ti; /* Pointer to previous track played info (A/C-) */ 232static volatile int track_ridx; /* Track being decoded (A/C-) */
227 233static int track_widx; /* Track being buffered (A) */
228#define CUR_TI (&tracks[track_ridx]) /* Pointer to current track playing info (A/C-) */ 234
229 235static struct track_info *prev_ti; /* Previous track info pointer (A/C-) */
230/* Audio buffering controls */ 236#define CUR_TI (&tracks[track_ridx]) /* Playing track info pointer (A/C-) */
231static int last_peek_offset; /* Step count to the next unbuffered track (A) */ 237
232static int current_fd; /* Partially loaded track file handle to continue buffering (A) */ 238/* Set by the audio thread when the current track information has updated
239 * and the WPS may need to update its cached information */
240static bool track_changed;
241
242/* Information used only for filling the buffer */
243/* Playlist steps from playing track to next track to be buffered (A) */
244static int last_peek_offset;
245/* Partially loaded track file handle to continue buffering (A) */
246static int current_fd;
233 247
234/* Scrobbler support */ 248/* Scrobbler support */
235static unsigned long prev_track_elapsed; /* Previous track elapsed time (C/A-) */ 249static unsigned long prev_track_elapsed; /* Previous track elapsed time (C/A-)*/
236 250
237/* Track change controls */ 251/* Track change controls */
238static bool automatic_skip = false; /* Was the skip being executed manual or automatic? (C/A-) */ 252static bool automatic_skip = false; /* Who initiated in-progress skip? (C/A-) */
239static bool playlist_end = false; /* Have we reached end of the current playlist? (A) */ 253static bool playlist_end = false; /* Has the current playlist ended? (A) */
240static bool dir_skip = false; /* Is a directory skip pending? (A) */ 254static bool dir_skip = false; /* Is a directory skip pending? (A) */
241static bool new_playlist = false; /* Are we starting a new playlist? (A) */ 255static bool new_playlist = false; /* Are we starting a new playlist? (A) */
242static int wps_offset = 0; /* Pending track change offset, to keep WPS responsive (A) */ 256/* Pending track change offset, to keep WPS responsive (A) */
243 257static int wps_offset = 0;
244/* Callbacks.. */ 258
245void (*track_changed_callback)(struct mp3entry *id3); /* ...when current track has really changed */ 259/* Callbacks which applications or plugins may set */
246void (*track_buffer_callback)(struct mp3entry *id3, bool last_track); /* ...when track has been buffered */ 260/* When the playing track has changed from the user's perspective */
247void (*track_unbuffer_callback)(struct mp3entry *id3, bool last_track); /* ...when track is being unbuffered */ 261void (*track_changed_callback)(struct mp3entry *id3);
262/* When a track has been buffered */
263void (*track_buffer_callback)(struct mp3entry *id3, bool last_track);
264/* When a track's buffer has been overwritten or cleared */
265void (*track_unbuffer_callback)(struct mp3entry *id3, bool last_track);
248 266
249/* Configuration */ 267/* Configuration */
250static size_t conf_watermark; /* Low water mark (A/C) FIXME */ 268static size_t conf_watermark; /* Level to trigger filebuf fill (A/C) FIXME */
251static size_t conf_filechunk; /* Largest chunk the codec accepts (A/C) FIXME */ 269static size_t conf_filechunk; /* Largest chunk the codec accepts (A/C) FIXME */
252static size_t conf_preseek; /* Codec pre-seek margin (A/C) FIXME */ 270static size_t conf_preseek; /* Codec pre-seek margin (A/C) FIXME */
253static size_t buffer_margin; /* Buffer margin aka anti-skip buffer (A/C-) */ 271static size_t buffer_margin; /* Buffer margin aka anti-skip buffer (A/C-) */
254static bool v1first = false; /* ID3 data control, true if V1 then V2 (A) */ 272static bool v1first = false; /* ID3 data control, true if V1 then V2 (A) */
255#if MEM > 8 273#if MEM > 8
256static size_t high_watermark; /* High watermark for rebuffer (A/V/other) */ 274static size_t high_watermark; /* High watermark for rebuffer (A/V/other) */
257#endif 275#endif
258 276
259/* Multiple threads */ 277/* Multiple threads */
260static const char *get_codec_filename(int enc_spec); /* Returns codec filename (A-/C-/V-) */ 278static const char *get_codec_filename(int enc_spec); /* (A-/C-/V-) */
261static void set_filebuf_watermark(int seconds); /* Set low watermark (A/C) FIXME */ 279/* Set the watermark to trigger buffer fill (A/C) FIXME */
280static void set_filebuf_watermark(int seconds);
262 281
263/* Audio thread */ 282/* Audio thread */
264static struct event_queue audio_queue; 283static struct event_queue audio_queue;
@@ -277,9 +296,9 @@ static struct event_queue codec_queue;
277static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)] 296static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
278IBSS_ATTR; 297IBSS_ATTR;
279static const char codec_thread_name[] = "codec"; 298static const char codec_thread_name[] = "codec";
280struct thread_entry *codec_thread_p; /* For modifying thread priority later. */ 299struct thread_entry *codec_thread_p; /* For modifying thread priority later. */
281 300
282volatile int current_codec IDATA_ATTR; /* Current codec (normal/voice) */ 301volatile int current_codec IDATA_ATTR; /* Current codec (normal/voice) */
283 302
284/* Voice thread */ 303/* Voice thread */
285#ifdef PLAYBACK_VOICE 304#ifdef PLAYBACK_VOICE
@@ -296,24 +315,29 @@ static const char voice_thread_name[] = "voice codec";
296extern unsigned char codecbuf[]; /* DRAM codec swap buffer */ 315extern unsigned char codecbuf[]; /* DRAM codec swap buffer */
297 316
298#ifdef SIMULATOR 317#ifdef SIMULATOR
299static unsigned char sim_iram[CODEC_IRAM_SIZE]; /* IRAM codec swap buffer for sim*/ 318/* IRAM codec swap buffer for sim*/
319static unsigned char sim_iram[CODEC_IRAM_SIZE];
300#undef CODEC_IRAM_ORIGIN 320#undef CODEC_IRAM_ORIGIN
301#define CODEC_IRAM_ORIGIN sim_iram 321#define CODEC_IRAM_ORIGIN sim_iram
302#endif 322#endif
303 323
304static unsigned char *iram_buf[2] = { NULL, NULL }; /* Ptr to IRAM buffers for normal/voice codecs */ 324/* Pointer to IRAM buffers for normal/voice codecs */
305static unsigned char *dram_buf[2] = { NULL, NULL }; /* Ptr to DRAM buffers for normal/voice codecs */ 325static unsigned char *iram_buf[2] = { NULL, NULL };
306static struct mutex mutex_codecthread; /* Mutex to control which codec (normal/voice) is running */ 326/* Pointer to DRAM buffers for normal/voice codecs */
327static unsigned char *dram_buf[2] = { NULL, NULL };
328/* Mutex to control which codec (normal/voice) is running */
329static struct mutex mutex_codecthread;
307 330
308/* Voice state */ 331/* Voice state */
309static volatile bool voice_thread_start; /* Set to trigger voice playback (A/V) */ 332static volatile bool voice_thread_start; /* Triggers voice playback (A/V) */
310static volatile bool voice_is_playing; /* Is voice currently playing? (V) */ 333static volatile bool voice_is_playing; /* Is voice currently playing? (V) */
311static volatile bool voice_codec_loaded; /* Is voice codec loaded (V/A-) */ 334static volatile bool voice_codec_loaded; /* Is voice codec loaded (V/A-) */
312static char *voicebuf; 335static char *voicebuf;
313static size_t voice_remaining; 336static size_t voice_remaining;
314 337
315#ifdef IRAM_STEAL 338#ifdef IRAM_STEAL
316static bool voice_iram_stolen = false; /* Voice IRAM has been stolen for other use */ 339/* Voice IRAM has been stolen for other use */
340static bool voice_iram_stolen = false;
317#endif 341#endif
318 342
319static void (*voice_getmore)(unsigned char** start, int* size); 343static void (*voice_getmore)(unsigned char** start, int* size);
@@ -655,7 +679,7 @@ void audio_next(void)
655 679
656 LOGFQUEUE("audio > audio Q_AUDIO_SKIP 1"); 680 LOGFQUEUE("audio > audio Q_AUDIO_SKIP 1");
657 queue_post(&audio_queue, Q_AUDIO_SKIP, 1); 681 queue_post(&audio_queue, Q_AUDIO_SKIP, 1);
658 /* Keep wps fast while our message travels inside deep playback queues. */ 682 /* Update wps while our message travels inside deep playback queues. */
659 wps_offset++; 683 wps_offset++;
660 track_changed = true; 684 track_changed = true;
661 } 685 }
@@ -676,7 +700,7 @@ void audio_prev(void)
676 700
677 LOGFQUEUE("audio > audio Q_AUDIO_SKIP -1"); 701 LOGFQUEUE("audio > audio Q_AUDIO_SKIP -1");
678 queue_post(&audio_queue, Q_AUDIO_SKIP, -1); 702 queue_post(&audio_queue, Q_AUDIO_SKIP, -1);
679 /* Keep wps fast while our message travels inside deep playback queues. */ 703 /* Update wps while our message travels inside deep playback queues. */
680 wps_offset--; 704 wps_offset--;
681 track_changed = true; 705 track_changed = true;
682 } 706 }
@@ -1047,7 +1071,8 @@ static bool voice_pcmbuf_insert_split_callback(
1047 if (playing) 1071 if (playing)
1048 { 1072 {
1049 pcmbuf_mix_voice(output_size); 1073 pcmbuf_mix_voice(output_size);
1050 if ((pcmbuf_usage() < 10 || pcmbuf_mix_free() < 30) && audio_codec_loaded) 1074 if ((pcmbuf_usage() < 10 || pcmbuf_mix_free() < 30) &&
1075 audio_codec_loaded)
1051 swap_codec(); 1076 swap_codec();
1052 } 1077 }
1053 else 1078 else
@@ -1807,8 +1832,24 @@ static void codec_discard_codec_callback(void)
1807#endif 1832#endif
1808} 1833}
1809 1834
1835static inline void codec_gapless_track_change(void) {
1836 /* callback keeps the progress bar moving while the pcmbuf empties */
1837 pcmbuf_set_position_callback(codec_pcmbuf_position_callback);
1838 /* set the pcmbuf callback for when the track really changes */
1839 pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback);
1840}
1841
1842static inline void codec_crossfade_track_change(void) {
1843 /* Initiate automatic crossfade mode */
1844 pcmbuf_crossfade_init(false);
1845 /* Notify the wps that the track change starts now */
1846 codec_track_changed();
1847}
1848
1810static void codec_track_skip_done(bool was_manual) 1849static void codec_track_skip_done(bool was_manual)
1811{ 1850{
1851 int crossfade_mode = global_settings.crossfade;
1852
1812 /* Manual track change (always crossfade or flush audio). */ 1853 /* Manual track change (always crossfade or flush audio). */
1813 if (was_manual) 1854 if (was_manual)
1814 { 1855 {
@@ -1818,34 +1859,24 @@ static void codec_track_skip_done(bool was_manual)
1818 } 1859 }
1819 /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */ 1860 /* Automatic track change w/crossfade, if not in "Track Skip Only" mode. */
1820 else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active() 1861 else if (pcmbuf_is_crossfade_enabled() && !pcmbuf_is_crossfade_active()
1821 && global_settings.crossfade != CROSSFADE_ENABLE_TRACKSKIP ) 1862 && crossfade_mode != CROSSFADE_ENABLE_TRACKSKIP)
1822 { 1863 {
1823 if ( global_settings.crossfade 1864 if (crossfade_mode == CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP)
1824 == CROSSFADE_ENABLE_SHUFFLE_AND_TRACKSKIP )
1825 { 1865 {
1826 if (global_settings.playlist_shuffle) /* shuffle mode is on, so crossfade: */ 1866 if (global_settings.playlist_shuffle)
1827 { 1867 /* shuffle mode is on, so crossfade: */
1828 pcmbuf_crossfade_init(false); 1868 codec_crossfade_track_change();
1829 codec_track_changed(); 1869 else
1830 } 1870 /* shuffle mode is off, so do a gapless track change */
1831 else /* shuffle mode is off, so do a gapless track change */ 1871 codec_gapless_track_change();
1832 {
1833 pcmbuf_set_position_callback(codec_pcmbuf_position_callback); /* Gapless playback */
1834 pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback); /* copied from below */
1835 }
1836 } 1872 }
1837 else /* normal crossfade: */ 1873 else
1838 { 1874 /* normal crossfade: */
1839 pcmbuf_crossfade_init(false); 1875 codec_crossfade_track_change();
1840 codec_track_changed();
1841 }
1842 } 1876 }
1843 /* Gapless playback. */
1844 else 1877 else
1845 { 1878 /* normal gapless playback. */
1846 pcmbuf_set_position_callback(codec_pcmbuf_position_callback); 1879 codec_gapless_track_change();
1847 pcmbuf_set_event_handler(codec_pcmbuf_track_changed_callback);
1848 }
1849} 1880}
1850 1881
1851static bool codec_load_next_track(void) 1882static bool codec_load_next_track(void)
@@ -2076,7 +2107,8 @@ static void codec_thread(void)
2076 * triggering the WPS exit */ 2107 * triggering the WPS exit */
2077 while(pcm_is_playing()) 2108 while(pcm_is_playing())
2078 { 2109 {
2079 CUR_TI->id3.elapsed = CUR_TI->id3.length - pcmbuf_get_latency(); 2110 CUR_TI->id3.elapsed =
2111 CUR_TI->id3.length - pcmbuf_get_latency();
2080 sleep(1); 2112 sleep(1);
2081 } 2113 }
2082 LOGFQUEUE("codec > audio Q_AUDIO_STOP"); 2114 LOGFQUEUE("codec > audio Q_AUDIO_STOP");
@@ -2092,7 +2124,8 @@ static void codec_thread(void)
2092 } 2124 }
2093 else 2125 else
2094 { 2126 {
2095 const char *codec_fn = get_codec_filename(CUR_TI->id3.codectype); 2127 const char *codec_fn =
2128 get_codec_filename(CUR_TI->id3.codectype);
2096 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK"); 2129 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
2097 queue_post(&codec_queue, Q_CODEC_LOAD_DISK, 2130 queue_post(&codec_queue, Q_CODEC_LOAD_DISK,
2098 (intptr_t)codec_fn); 2131 (intptr_t)codec_fn);
@@ -2516,7 +2549,8 @@ static bool audio_loadcodec(bool start_play)
2516 int prev_track; 2549 int prev_track;
2517 char codec_path[MAX_PATH]; /* Full path to codec */ 2550 char codec_path[MAX_PATH]; /* Full path to codec */
2518 2551
2519 const char * codec_fn = get_codec_filename(tracks[track_widx].id3.codectype); 2552 const char * codec_fn =
2553 get_codec_filename(tracks[track_widx].id3.codectype);
2520 if (codec_fn == NULL) 2554 if (codec_fn == NULL)
2521 return false; 2555 return false;
2522 2556
@@ -3520,9 +3554,9 @@ static void audio_playback_init(void)
3520 id3_voice.length = 1000000L; 3554 id3_voice.length = 1000000L;
3521#endif 3555#endif
3522 3556
3523 codec_thread_p = create_thread(codec_thread, codec_stack, 3557 codec_thread_p = create_thread(
3524 sizeof(codec_stack), 3558 codec_thread, codec_stack, sizeof(codec_stack),
3525 codec_thread_name IF_PRIO(, PRIORITY_PLAYBACK)); 3559 codec_thread_name IF_PRIO(, PRIORITY_PLAYBACK));
3526 3560
3527 while (1) 3561 while (1)
3528 { 3562 {