summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/codec_thread.c370
-rw-r--r--apps/codec_thread.h5
-rw-r--r--apps/pcmbuf.c28
-rw-r--r--apps/pcmbuf.h1
-rw-r--r--apps/playback.c57
-rw-r--r--apps/playback.h1
6 files changed, 188 insertions, 274 deletions
diff --git a/apps/codec_thread.c b/apps/codec_thread.c
index 22c177589f..d4217c3789 100644
--- a/apps/codec_thread.c
+++ b/apps/codec_thread.c
@@ -20,69 +20,17 @@
20 * 20 *
21 ****************************************************************************/ 21 ****************************************************************************/
22 22
23//#include <stdio.h>
24//#include <string.h>
25//#include <stdlib.h>
26//#include <ctype.h>
27
28#include "playback.h" 23#include "playback.h"
29#include "codec_thread.h" 24#include "codec_thread.h"
30#include "system.h" 25#include "system.h"
31//#include "thread.h"
32//#include "file.h"
33//#include "panic.h"
34//#include "memory.h"
35//#include "lcd.h"
36//#include "font.h"
37//#include "button.h"
38#include "kernel.h" 26#include "kernel.h"
39//#include "tree.h"
40//#include "debug.h"
41//#include "sprintf.h"
42//#include "settings.h"
43#include "codecs.h" 27#include "codecs.h"
44//#include "audio.h"
45#include "buffering.h" 28#include "buffering.h"
46//#include "appevents.h"
47//#include "voice_thread.h"
48//#include "mp3_playback.h"
49//#include "usb.h"
50//#include "storage.h"
51//#include "screens.h"
52//#include "playlist.h"
53#include "pcmbuf.h" 29#include "pcmbuf.h"
54//#include "buffer.h"
55#include "dsp.h" 30#include "dsp.h"
56#include "abrepeat.h" 31#include "abrepeat.h"
57//#include "cuesheet.h"
58#ifdef HAVE_TAGCACHE
59//#include "tagcache.h"
60#endif
61#ifdef HAVE_LCD_BITMAP
62//#include "icons.h"
63//#include "peakmeter.h"
64//#include "action.h"
65#ifdef HAVE_ALBUMART
66//#include "albumart.h"
67//#include "bmp.h"
68#endif
69#endif
70//#include "lang.h"
71//#include "misc.h"
72//#include "sound.h"
73#include "metadata.h" 32#include "metadata.h"
74#include "splash.h" 33#include "splash.h"
75//#include "talk.h"
76//#include "ata_idle_notify.h"
77
78#ifdef HAVE_RECORDING
79//#include "recording.h"
80//#include "pcm_record.h"
81#endif
82
83#ifdef IPOD_ACCESSORY_PROTOCOL
84//#include "iap.h"
85#endif
86 34
87/* Define LOGF_ENABLE to enable logf output in this file */ 35/* Define LOGF_ENABLE to enable logf output in this file */
88/*#define LOGF_ENABLE*/ 36/*#define LOGF_ENABLE*/
@@ -110,12 +58,16 @@
110#endif 58#endif
111 59
112 60
113/* Variables are commented with the threads that use them: * 61/* Variables are commented with the threads that use them:
114 * A=audio, C=codec, V=voice. A suffix of - indicates that * 62 * A=audio, C=codec, V=voice. A suffix of - indicates that
115 * the variable is read but not updated on that thread. */ 63 * the variable is read but not updated on that thread.
64
65 * Unless otherwise noted, the extern variables are located
66 * in playback.c.
67 */
116 68
117/* Main state control */ 69/* Main state control */
118static volatile bool audio_codec_loaded SHAREDBSS_ATTR = false; /* Codec loaded? (C/A-) */ 70volatile bool audio_codec_loaded SHAREDBSS_ATTR = false; /* Codec loaded? (C/A-) */
119 71
120extern struct mp3entry *thistrack_id3, /* the currently playing track */ 72extern struct mp3entry *thistrack_id3, /* the currently playing track */
121 *othertrack_id3; /* prev track during track-change-transition, or end of playlist, 73 *othertrack_id3; /* prev track during track-change-transition, or end of playlist,
@@ -131,25 +83,35 @@ static bool codec_requested_stop = false;
131 83
132extern struct event_queue audio_queue; 84extern struct event_queue audio_queue;
133extern struct event_queue codec_queue; 85extern struct event_queue codec_queue;
134extern struct event_queue pcmbuf_queue; 86
87extern struct codec_api ci; /* from codecs.c */
135 88
136/* Codec thread */ 89/* Codec thread */
137extern struct codec_api ci; 90unsigned int codec_thread_id; /* For modifying thread priority later.
138unsigned int codec_thread_id; /* For modifying thread priority later. */ 91 Used by playback.c and pcmbuf.c */
139static struct queue_sender_list codec_queue_sender_list; 92static struct queue_sender_list codec_queue_sender_list;
140static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)] 93static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
141IBSS_ATTR; 94IBSS_ATTR;
142static const char codec_thread_name[] = "codec"; 95static const char codec_thread_name[] = "codec";
143 96
97/* function prototypes */
98static bool codec_load_next_track(void);
99
100
144/**************************************/ 101/**************************************/
145 102
146/* Function to be called by pcm buffer callbacks. 103/** misc external functions */
147 * Permissible Context(s): Audio interrupt 104
148 */ 105int get_codec_base_type(int type)
149static void pcmbuf_callback_queue_post(long id, intptr_t data)
150{ 106{
151 /* No lock since we're already in audio interrupt context */ 107 switch (type) {
152 queue_post(&pcmbuf_queue, id, data); 108 case AFMT_MPA_L1:
109 case AFMT_MPA_L2:
110 case AFMT_MPA_L3:
111 return AFMT_MPA_L3;
112 }
113
114 return type;
153} 115}
154 116
155const char *get_codec_filename(int cod_spec) 117const char *get_codec_filename(int cod_spec)
@@ -182,7 +144,30 @@ const char *get_codec_filename(int cod_spec)
182 return fname; 144 return fname;
183} /* get_codec_filename */ 145} /* get_codec_filename */
184 146
185/* --- Codec thread --- */ 147/* Borrow the codec thread and return the ID */
148void codec_thread_do_callback(void (*fn)(void), unsigned int *id)
149{
150 /* Set id before telling thread to call something; it may be
151 * needed before this function returns. */
152 if (id != NULL)
153 *id = codec_thread_id;
154
155 /* Codec thread will signal just before entering callback */
156 LOGFQUEUE("codec >| Q_CODEC_DO_CALLBACK");
157 queue_send(&codec_queue, Q_CODEC_DO_CALLBACK, (intptr_t)fn);
158}
159
160
161/** codec API callbacks */
162
163static void* codec_get_buffer(size_t *size)
164{
165 if (codec_size >= CODEC_SIZE)
166 return NULL;
167 *size = CODEC_SIZE - codec_size;
168 return &codecbuf[codec_size];
169}
170
186static bool codec_pcmbuf_insert_callback( 171static bool codec_pcmbuf_insert_callback(
187 const void *ch1, const void *ch2, int count) 172 const void *ch1, const void *ch2, int count)
188{ 173{
@@ -230,37 +215,8 @@ static bool codec_pcmbuf_insert_callback(
230 return true; 215 return true;
231} /* codec_pcmbuf_insert_callback */ 216} /* codec_pcmbuf_insert_callback */
232 217
233static void* codec_get_buffer(size_t *size)
234{
235 if (codec_size >= CODEC_SIZE)
236 return NULL;
237 *size = CODEC_SIZE - codec_size;
238 return &codecbuf[codec_size];
239}
240
241/* Between the codec and PCM track change, we need to keep updating the
242 "elapsed" value of the previous (to the codec, but current to the
243 user/PCM/WPS) track, so that the progressbar reaches the end.
244 During that transition, the WPS will display prevtrack_id3. */
245static void codec_pcmbuf_position_callback(size_t size) ICODE_ATTR;
246static void codec_pcmbuf_position_callback(size_t size)
247{
248 /* This is called from an ISR, so be quick */
249 unsigned int time = size * 1000 / 4 / NATIVE_FREQUENCY +
250 othertrack_id3->elapsed;
251
252 if (time >= othertrack_id3->length)
253 {
254 pcmbuf_set_position_callback(NULL);
255 othertrack_id3->elapsed = othertrack_id3->length;
256 }
257 else
258 othertrack_id3->elapsed = time;
259}
260
261static void codec_set_elapsed_callback(unsigned int value) 218static void codec_set_elapsed_callback(unsigned int value)
262{ 219{
263 unsigned int latency;
264 if (ci.seek_time) 220 if (ci.seek_time)
265 return; 221 return;
266 222
@@ -268,30 +224,33 @@ static void codec_set_elapsed_callback(unsigned int value)
268 ab_position_report(value); 224 ab_position_report(value);
269#endif 225#endif
270 226
271 latency = pcmbuf_get_latency(); 227 unsigned int latency = pcmbuf_get_latency();
272 if (value < latency) 228 if (value < latency)
273 thistrack_id3->elapsed = 0; 229 thistrack_id3->elapsed = 0;
274 else if (value - latency > thistrack_id3->elapsed || 230 else
275 value - latency < thistrack_id3->elapsed - 2)
276 { 231 {
277 thistrack_id3->elapsed = value - latency; 232 unsigned int elapsed = value - latency;
233 if (elapsed > thistrack_id3->elapsed ||
234 elapsed < thistrack_id3->elapsed - 2)
235 {
236 thistrack_id3->elapsed = elapsed;
237 }
278 } 238 }
279} 239}
280 240
281static void codec_set_offset_callback(size_t value) 241static void codec_set_offset_callback(size_t value)
282{ 242{
283 unsigned int latency;
284
285 if (ci.seek_time) 243 if (ci.seek_time)
286 return; 244 return;
287 245
288 latency = pcmbuf_get_latency() * thistrack_id3->bitrate / 8; 246 unsigned int latency = pcmbuf_get_latency() * thistrack_id3->bitrate / 8;
289 if (value < latency) 247 if (value < latency)
290 thistrack_id3->offset = 0; 248 thistrack_id3->offset = 0;
291 else 249 else
292 thistrack_id3->offset = value - latency; 250 thistrack_id3->offset = value - latency;
293} 251}
294 252
253/* helper function, not a callback */
295static void codec_advance_buffer_counters(size_t amount) 254static void codec_advance_buffer_counters(size_t amount)
296{ 255{
297 bufadvance(get_audio_hid(), amount); 256 bufadvance(get_audio_hid(), amount);
@@ -346,18 +305,6 @@ static void* codec_request_buffer_callback(size_t *realsize, size_t reqsize)
346 return ptr; 305 return ptr;
347} /* codec_request_buffer_callback */ 306} /* codec_request_buffer_callback */
348 307
349int get_codec_base_type(int type)
350{
351 switch (type) {
352 case AFMT_MPA_L1:
353 case AFMT_MPA_L2:
354 case AFMT_MPA_L3:
355 return AFMT_MPA_L3;
356 }
357
358 return type;
359}
360
361static void codec_advance_buffer_callback(size_t amount) 308static void codec_advance_buffer_callback(size_t amount)
362{ 309{
363 codec_advance_buffer_counters(amount); 310 codec_advance_buffer_counters(amount);
@@ -370,15 +317,26 @@ static void codec_advance_buffer_loc_callback(void *ptr)
370 codec_advance_buffer_callback(amount); 317 codec_advance_buffer_callback(amount);
371} 318}
372 319
320static bool codec_seek_buffer_callback(size_t newpos)
321{
322 logf("codec_seek_buffer_callback");
323
324 int ret = bufseek(get_audio_hid(), newpos);
325 if (ret == 0) {
326 ci.curpos = newpos;
327 return true;
328 }
329 else {
330 return false;
331 }
332}
333
373static void codec_seek_complete_callback(void) 334static void codec_seek_complete_callback(void)
374{ 335{
375 logf("seek_complete"); 336 logf("seek_complete");
376 /* If seeking-while-playing, pcm playback is actually paused (pcm_is_paused()) 337 /* If seeking-while-playing, pcm_is_paused() is true.
377 * but audio_is_paused() is false. If seeking-while-paused, audio_is_paused() is 338 * If seeking-while-paused, audio_is_paused() is true.
378 * true, but pcm playback may have actually stopped due to a previous buffer clear. 339 * A seamless seek skips this section. */
379 * The buffer clear below occurs with either condition. A seemless seek skips
380 * this section and no buffer clear occurs.
381 */
382 if (pcm_is_paused() || audio_is_paused()) 340 if (pcm_is_paused() || audio_is_paused())
383 { 341 {
384 /* Clear the buffer */ 342 /* Clear the buffer */
@@ -392,51 +350,104 @@ static void codec_seek_complete_callback(void)
392 ci.seek_time = 0; 350 ci.seek_time = 0;
393} 351}
394 352
395static bool codec_seek_buffer_callback(size_t newpos) 353static void codec_discard_codec_callback(void)
396{ 354{
397 logf("codec_seek_buffer_callback"); 355 int *codec_hid = get_codec_hid();
356 if (*codec_hid >= 0)
357 {
358 bufclose(*codec_hid);
359 *codec_hid = -1;
360 }
361}
398 362
399 int ret = bufseek(get_audio_hid(), newpos); 363static bool codec_request_next_track_callback(void)
400 if (ret == 0) { 364{
401 ci.curpos = newpos; 365 int prev_codectype;
366
367 if (ci.stop_codec || !audio_is_playing())
368 return false;
369
370 prev_codectype = get_codec_base_type(thistrack_id3->codectype);
371 if (!codec_load_next_track())
372 return false;
373
374 /* Seek to the beginning of the new track because if the struct
375 mp3entry was buffered, "elapsed" might not be zero (if the track has
376 been played already but not unbuffered) */
377 codec_seek_buffer_callback(thistrack_id3->first_frame_offset);
378 /* Check if the next codec is the same file. */
379 if (prev_codectype == get_codec_base_type(thistrack_id3->codectype))
380 {
381 logf("New track loaded");
382 codec_discard_codec_callback();
402 return true; 383 return true;
403 } 384 }
404 else { 385 else
386 {
387 logf("New codec:%d/%d", thistrack_id3->codectype, prev_codectype);
405 return false; 388 return false;
406 } 389 }
407} 390}
408 391
409static void codec_configure_callback(int setting, intptr_t value) 392static void codec_configure_callback(int setting, intptr_t value)
410{ 393{
411 switch (setting) { 394 if (!dsp_configure(ci.dsp, setting, value))
412 default: 395 { logf("Illegal key:%d", setting); }
413 if (!dsp_configure(ci.dsp, setting, value))
414 { logf("Illegal key:%d", setting); }
415 }
416} 396}
417 397
418static void codec_track_changed(void) 398/* Initialize codec API */
399void codec_init_codec_api(void)
419{ 400{
420 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED"); 401 ci.dsp = (struct dsp_config *)dsp_configure(NULL, DSP_MYDSP,
421 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0); 402 CODEC_IDX_AUDIO);
403 ci.codec_get_buffer = codec_get_buffer;
404 ci.pcmbuf_insert = codec_pcmbuf_insert_callback;
405 ci.set_elapsed = codec_set_elapsed_callback;
406 ci.read_filebuf = codec_filebuf_callback;
407 ci.request_buffer = codec_request_buffer_callback;
408 ci.advance_buffer = codec_advance_buffer_callback;
409 ci.advance_buffer_loc = codec_advance_buffer_loc_callback;
410 ci.seek_buffer = codec_seek_buffer_callback;
411 ci.seek_complete = codec_seek_complete_callback;
412 ci.request_next_track = codec_request_next_track_callback;
413 ci.discard_codec = codec_discard_codec_callback;
414 ci.set_offset = codec_set_offset_callback;
415 ci.configure = codec_configure_callback;
422} 416}
423 417
424static void codec_pcmbuf_track_changed_callback(void)
425{
426 pcmbuf_set_position_callback(NULL);
427 pcmbuf_callback_queue_post(Q_AUDIO_TRACK_CHANGED, 0);
428}
429 418
430static void codec_discard_codec_callback(void) 419/** pcmbuf track change callbacks */
420
421/* Between the codec and PCM track change, we need to keep updating the
422 "elapsed" value of the previous (to the codec, but current to the
423 user/PCM/WPS) track, so that the progressbar reaches the end.
424 During that transition, the WPS will display prevtrack_id3. */
425static void codec_pcmbuf_position_callback(size_t size) ICODE_ATTR;
426static void codec_pcmbuf_position_callback(size_t size)
431{ 427{
432 int *codec_hid = get_codec_hid(); 428 /* This is called from an ISR, so be quick */
433 if (*codec_hid >= 0) 429 unsigned int time = size * 1000 / 4 / NATIVE_FREQUENCY +
430 othertrack_id3->elapsed;
431
432 if (time >= othertrack_id3->length)
434 { 433 {
435 bufclose(*codec_hid); 434 pcmbuf_set_position_callback(NULL);
436 *codec_hid = -1; 435 othertrack_id3->elapsed = othertrack_id3->length;
437 } 436 }
437 else
438 othertrack_id3->elapsed = time;
438} 439}
439 440
441static void codec_pcmbuf_track_changed_callback(void)
442{
443 LOGFQUEUE("codec > pcmbuf/audio Q_AUDIO_TRACK_CHANGED");
444 pcmbuf_set_position_callback(NULL);
445 audio_post_track_change();
446}
447
448
449/** track change functions */
450
440static inline void codec_gapless_track_change(void) 451static inline void codec_gapless_track_change(void)
441{ 452{
442 /* callback keeps the progress bar moving while the pcmbuf empties */ 453 /* callback keeps the progress bar moving while the pcmbuf empties */
@@ -450,7 +461,8 @@ static inline void codec_crossfade_track_change(void)
450 /* Initiate automatic crossfade mode */ 461 /* Initiate automatic crossfade mode */
451 pcmbuf_crossfade_init(false); 462 pcmbuf_crossfade_init(false);
452 /* Notify the wps that the track change starts now */ 463 /* Notify the wps that the track change starts now */
453 codec_track_changed(); 464 LOGFQUEUE("codec > audio Q_AUDIO_TRACK_CHANGED");
465 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
454} 466}
455 467
456static void codec_track_skip_done(bool was_manual) 468static void codec_track_skip_done(bool was_manual)
@@ -531,35 +543,7 @@ static bool codec_load_next_track(void)
531 } 543 }
532} 544}
533 545
534static bool codec_request_next_track_callback(void) 546/** CODEC THREAD */
535{
536 int prev_codectype;
537
538 if (ci.stop_codec || !audio_is_playing())
539 return false;
540
541 prev_codectype = get_codec_base_type(thistrack_id3->codectype);
542 if (!codec_load_next_track())
543 return false;
544
545 /* Seek to the beginning of the new track because if the struct
546 mp3entry was buffered, "elapsed" might not be zero (if the track has
547 been played already but not unbuffered) */
548 codec_seek_buffer_callback(thistrack_id3->first_frame_offset);
549 /* Check if the next codec is the same file. */
550 if (prev_codectype == get_codec_base_type(thistrack_id3->codectype))
551 {
552 logf("New track loaded");
553 codec_discard_codec_callback();
554 return true;
555 }
556 else
557 {
558 logf("New codec:%d/%d", thistrack_id3->codectype, prev_codectype);
559 return false;
560 }
561}
562
563static void codec_thread(void) 547static void codec_thread(void)
564{ 548{
565 struct queue_event ev; 549 struct queue_event ev;
@@ -734,44 +718,6 @@ static void codec_thread(void)
734 } 718 }
735} 719}
736 720
737/* Borrow the codec thread and return the ID */
738void codec_thread_do_callback(void (*fn)(void), unsigned int *id)
739{
740 /* Set id before telling thread to call something; it may be
741 * needed before this function returns. */
742 if (id != NULL)
743 *id = codec_thread_id;
744
745 /* Codec thread will signal just before entering callback */
746 LOGFQUEUE("codec >| Q_CODEC_DO_CALLBACK");
747 queue_send(&codec_queue, Q_CODEC_DO_CALLBACK, (intptr_t)fn);
748}
749
750void codec_init_codec_api(void)
751{
752 /* Initialize codec api. */
753 ci.read_filebuf = codec_filebuf_callback;
754 ci.pcmbuf_insert = codec_pcmbuf_insert_callback;
755 ci.codec_get_buffer = codec_get_buffer;
756 ci.request_buffer = codec_request_buffer_callback;
757 ci.advance_buffer = codec_advance_buffer_callback;
758 ci.advance_buffer_loc = codec_advance_buffer_loc_callback;
759 ci.request_next_track = codec_request_next_track_callback;
760 ci.seek_buffer = codec_seek_buffer_callback;
761 ci.seek_complete = codec_seek_complete_callback;
762 ci.set_elapsed = codec_set_elapsed_callback;
763 ci.set_offset = codec_set_offset_callback;
764 ci.configure = codec_configure_callback;
765 ci.discard_codec = codec_discard_codec_callback;
766 ci.dsp = (struct dsp_config *)dsp_configure(NULL, DSP_MYDSP,
767 CODEC_IDX_AUDIO);
768}
769
770bool codec_is_loaded(void)
771{
772 return audio_codec_loaded;
773}
774
775void make_codec_thread(void) 721void make_codec_thread(void)
776{ 722{
777 codec_thread_id = create_thread( 723 codec_thread_id = create_thread(
diff --git a/apps/codec_thread.h b/apps/codec_thread.h
index 26a0f1fdd8..a849e07d39 100644
--- a/apps/codec_thread.h
+++ b/apps/codec_thread.h
@@ -24,12 +24,11 @@
24 24
25#include <stdbool.h> 25#include <stdbool.h>
26 26
27int get_codec_base_type(int type);
27const char *get_codec_filename(int cod_spec); 28const char *get_codec_filename(int cod_spec);
28void codec_thread_do_callback(void (*fn)(void), 29void codec_thread_do_callback(void (*fn)(void),
29 unsigned int *codec_thread_id); 30 unsigned int *codec_thread_id);
30void make_codec_thread(void);
31int get_codec_base_type(int type);
32void codec_init_codec_api(void); 31void codec_init_codec_api(void);
33bool codec_is_loaded(void); 32void make_codec_thread(void);
34 33
35#endif 34#endif
diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c
index 4a338aa900..3ec0c114da 100644
--- a/apps/pcmbuf.c
+++ b/apps/pcmbuf.c
@@ -135,12 +135,13 @@ static void pcmbuf_under_watermark(bool under);
135static bool pcmbuf_flush_fillpos(void); 135static bool pcmbuf_flush_fillpos(void);
136 136
137#define CALL_IF_EXISTS(function, args...) if (function) function(args) 137#define CALL_IF_EXISTS(function, args...) if (function) function(args)
138/* This function has 2 major logical parts (separated by brackets both for 138/* This function has 3 major logical parts (separated by brackets both for
139 * readability and variable scoping). The first part performs the 139 * readability and variable scoping). The first part performs the
140 * operastions related to finishing off the last buffer we fed to the DMA. 140 * operations related to finishing off the last buffer we fed to the DMA.
141 * The second part performs the operations involved in sending a new buffer 141 * The second part detects the end of playlist condition when the pcm
142 * to the DMA. Finally the function checks the status of the buffer and 142 * buffer is empty except for uncommitted samples. Then they are committed.
143 * boosts if necessary */ 143 * The third part performs the operations involved in sending a new buffer
144 * to the DMA. */
144static void pcmbuf_callback(unsigned char** start, size_t* size) ICODE_ATTR; 145static void pcmbuf_callback(unsigned char** start, size_t* size) ICODE_ATTR;
145static void pcmbuf_callback(unsigned char** start, size_t* size) 146static void pcmbuf_callback(unsigned char** start, size_t* size)
146{ 147{
@@ -164,6 +165,15 @@ static void pcmbuf_callback(unsigned char** start, size_t* size)
164 if (pcmbuf_current == crossfade_chunk) 165 if (pcmbuf_current == crossfade_chunk)
165 crossfade_chunk = pcmbuf_read; 166 crossfade_chunk = pcmbuf_read;
166 } 167 }
168
169 {
170 /* Commit last samples at end of playlist */
171 if (audiobuffer_fillpos && !pcmbuf_read)
172 {
173 logf("pcmbuf callback: commit last samples");
174 pcmbuf_flush_fillpos();
175 }
176 }
167 177
168 { 178 {
169 /* Send the new buffer to the pcm */ 179 /* Send the new buffer to the pcm */
@@ -1109,11 +1119,3 @@ bool pcmbuf_is_crossfade_enabled(void)
1109 1119
1110 return crossfade_enabled; 1120 return crossfade_enabled;
1111} 1121}
1112
1113/** PLAY LAST REMAINING SAMPLES AT END OF PLAYBACK
1114 * Commit any remaining samples in the PCM buffer for playback. */
1115void pcmbuf_play_remainder(void)
1116{
1117 if (audiobuffer_fillpos)
1118 pcmbuf_flush_fillpos();
1119}
diff --git a/apps/pcmbuf.h b/apps/pcmbuf.h
index 4cb1c1acb7..b4e551f74d 100644
--- a/apps/pcmbuf.h
+++ b/apps/pcmbuf.h
@@ -75,6 +75,5 @@ void pcmbuf_beep(unsigned int frequency, size_t duration, int amplitude);
75 75
76int pcmbuf_used_descs(void); 76int pcmbuf_used_descs(void);
77int pcmbuf_descs(void); 77int pcmbuf_descs(void);
78void pcmbuf_play_remainder(void);
79 78
80#endif 79#endif
diff --git a/apps/playback.c b/apps/playback.c
index 57ed3bdb96..35f1e8ff4d 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -23,70 +23,36 @@
23/* TODO: Pause should be handled in here, rather than PCMBUF so that voice can 23/* TODO: Pause should be handled in here, rather than PCMBUF so that voice can
24 * play whilst audio is paused */ 24 * play whilst audio is paused */
25 25
26//#include <stdio.h>
27#include <string.h> 26#include <string.h>
28//#include <ctype.h>
29
30#include "playback.h" 27#include "playback.h"
31#include "codec_thread.h" 28#include "codec_thread.h"
32//#include "system.h"
33//#include "thread.h"
34//#include "file.h"
35//#include "panic.h"
36//#include "memory.h"
37//#include "lcd.h"
38//#include "font.h"
39//#include "button.h"
40#include "kernel.h" 29#include "kernel.h"
41//#include "tree.h"
42//#include "debug.h"
43//#include "sprintf.h"
44//#include "settings.h"
45#include "codecs.h" 30#include "codecs.h"
46//#include "audio.h"
47#include "buffering.h" 31#include "buffering.h"
48//#include "appevents.h"
49#include "voice_thread.h" 32#include "voice_thread.h"
50//#include "mp3_playback.h"
51#include "usb.h" 33#include "usb.h"
52//#include "storage.h"
53#include "ata.h" 34#include "ata.h"
54//#include "screens.h"
55#include "playlist.h" 35#include "playlist.h"
56#include "pcmbuf.h" 36#include "pcmbuf.h"
57#include "buffer.h" 37#include "buffer.h"
58//#include "dsp.h"
59//#include "abrepeat.h"
60#include "cuesheet.h" 38#include "cuesheet.h"
61#ifdef HAVE_TAGCACHE 39#ifdef HAVE_TAGCACHE
62#include "tagcache.h" 40#include "tagcache.h"
63#endif 41#endif
64#ifdef HAVE_LCD_BITMAP 42#ifdef HAVE_LCD_BITMAP
65//#include "icons.h"
66//#include "peakmeter.h"
67//#include "action.h"
68#ifdef HAVE_ALBUMART 43#ifdef HAVE_ALBUMART
69#include "albumart.h" 44#include "albumart.h"
70//#include "bmp.h"
71#endif 45#endif
72#endif 46#endif
73//#include "lang.h"
74//#include "misc.h"
75#include "sound.h" 47#include "sound.h"
76#include "metadata.h" 48#include "metadata.h"
77#include "splash.h" 49#include "splash.h"
78#include "talk.h" 50#include "talk.h"
79//#include "ata_idle_notify.h"
80 51
81#ifdef HAVE_RECORDING 52#ifdef HAVE_RECORDING
82//#include "recording.h"
83#include "pcm_record.h" 53#include "pcm_record.h"
84#endif 54#endif
85 55
86#ifdef IPOD_ACCESSORY_PROTOCOL
87//#include "iap.h"
88#endif
89
90#define PLAYBACK_VOICE 56#define PLAYBACK_VOICE
91 57
92/* amount of guess-space to allow for codecs that must hunt and peck 58/* amount of guess-space to allow for codecs that must hunt and peck
@@ -139,8 +105,9 @@ static bool audio_thread_ready SHAREDBSS_ATTR = false;
139/* TBD: Split out "audio" and "playback" (ie. calling) threads */ 105/* TBD: Split out "audio" and "playback" (ie. calling) threads */
140 106
141/* Main state control */ 107/* Main state control */
142static volatile bool playing SHAREDBSS_ATTR = false; /* Is audio playing? (A) */ 108static volatile bool playing SHAREDBSS_ATTR = false;/* Is audio playing? (A) */
143static volatile bool paused SHAREDBSS_ATTR = false; /* Is audio paused? (A/C-) */ 109static volatile bool paused SHAREDBSS_ATTR = false; /* Is audio paused? (A/C-) */
110extern volatile bool audio_codec_loaded; /* Codec loaded? (C/A-) */
144 111
145/* Ring buffer where compressed audio and codecs are loaded */ 112/* Ring buffer where compressed audio and codecs are loaded */
146static unsigned char *filebuf = NULL; /* Start of buffer (A/C-) */ 113static unsigned char *filebuf = NULL; /* Start of buffer (A/C-) */
@@ -233,7 +200,7 @@ static size_t buffer_margin = 5; /* Buffer margin aka anti-skip buffer (A/C-) *
233/* Event queues */ 200/* Event queues */
234struct event_queue audio_queue SHAREDBSS_ATTR; 201struct event_queue audio_queue SHAREDBSS_ATTR;
235struct event_queue codec_queue SHAREDBSS_ATTR; 202struct event_queue codec_queue SHAREDBSS_ATTR;
236struct event_queue pcmbuf_queue SHAREDBSS_ATTR; 203static struct event_queue pcmbuf_queue SHAREDBSS_ATTR;
237 204
238extern struct codec_api ci; 205extern struct codec_api ci;
239extern unsigned int codec_thread_id; 206extern unsigned int codec_thread_id;
@@ -256,6 +223,13 @@ static void audio_stop_playback(void);
256 223
257/**************************************/ 224/**************************************/
258 225
226/* Post message from pcmbuf callback in the codec thread that
227 * the end of the previous track has just been played. */
228void audio_post_track_change(void)
229{
230 queue_post(&pcmbuf_queue, Q_AUDIO_TRACK_CHANGED, 0);
231}
232
259/* Scan the pcmbuf queue and return true if a message pulled. 233/* Scan the pcmbuf queue and return true if a message pulled.
260 * Permissible Context(s): Thread 234 * Permissible Context(s): Thread
261 */ 235 */
@@ -1077,7 +1051,7 @@ static bool audio_loadcodec(bool start_play)
1077 if (id3 && prev_id3 && 1051 if (id3 && prev_id3 &&
1078 get_codec_base_type(id3->codectype) == 1052 get_codec_base_type(id3->codectype) ==
1079 get_codec_base_type(prev_id3->codectype) 1053 get_codec_base_type(prev_id3->codectype)
1080 && codec_is_loaded()) 1054 && audio_codec_loaded)
1081 { 1055 {
1082 logf("Reusing prev. codec"); 1056 logf("Reusing prev. codec");
1083 return true; 1057 return true;
@@ -1634,7 +1608,7 @@ static void audio_stop_codec_flush(void)
1634 ci.stop_codec = true; 1608 ci.stop_codec = true;
1635 pcmbuf_pause(true); 1609 pcmbuf_pause(true);
1636 1610
1637 while (codec_is_loaded()) 1611 while (audio_codec_loaded)
1638 yield(); 1612 yield();
1639 1613
1640 /* If the audio codec is not loaded any more, and the audio is still 1614 /* If the audio codec is not loaded any more, and the audio is still
@@ -1652,13 +1626,6 @@ static void audio_stop_playback(void)
1652{ 1626{
1653 if (playing) 1627 if (playing)
1654 { 1628 {
1655 /* If still actively playing here, play out the last samples in the
1656 * pcm buffer before stopping. If a manual stop has occurred, the
1657 * paused flag is set, so don't continue playback.
1658 */
1659 if (!paused)
1660 pcmbuf_play_remainder();
1661
1662 /* If we were playing, save resume information */ 1629 /* If we were playing, save resume information */
1663 struct mp3entry *id3 = NULL; 1630 struct mp3entry *id3 = NULL;
1664 1631
diff --git a/apps/playback.h b/apps/playback.h
index a53d2bb2e7..95b0bef0df 100644
--- a/apps/playback.h
+++ b/apps/playback.h
@@ -69,6 +69,7 @@ enum
69}; 69};
70bool audio_restore_playback(int type); /* Restores the audio buffer to handle the requested playback */ 70bool audio_restore_playback(int type); /* Restores the audio buffer to handle the requested playback */
71size_t audio_get_filebuflen(void); 71size_t audio_get_filebuflen(void);
72void audio_post_track_change(void);
72int get_audio_hid(void); 73int get_audio_hid(void);
73int *get_codec_hid(void); 74int *get_codec_hid(void);
74void audio_set_prev_elapsed(unsigned long setting); 75void audio_set_prev_elapsed(unsigned long setting);