summaryrefslogtreecommitdiff
path: root/apps/playback.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/playback.c')
-rw-r--r--apps/playback.c149
1 files changed, 129 insertions, 20 deletions
diff --git a/apps/playback.c b/apps/playback.c
index 279fb15482..9bf6942e7f 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -296,8 +296,8 @@ static unsigned char sim_iram[CODEC_IRAM_SIZE]; /* IRAM codec swap buffer for si
296#define CODEC_IRAM_ORIGIN sim_iram 296#define CODEC_IRAM_ORIGIN sim_iram
297#endif 297#endif
298 298
299static unsigned char *iram_buf[2]; /* Ptr to IRAM buffers for normal/voice codecs */ 299static unsigned char *iram_buf[2] = { NULL, NULL }; /* Ptr to IRAM buffers for normal/voice codecs */
300static unsigned char *dram_buf[2]; /* Ptr to DRAM buffers for normal/voice codecs */ 300static unsigned char *dram_buf[2] = { NULL, NULL }; /* Ptr to DRAM buffers for normal/voice codecs */
301static struct mutex mutex_codecthread; /* Mutex to control which codec (normal/voice) is running */ 301static struct mutex mutex_codecthread; /* Mutex to control which codec (normal/voice) is running */
302 302
303/* Voice state */ 303/* Voice state */
@@ -307,6 +307,10 @@ static volatile bool voice_codec_loaded; /* Is voice codec loaded (V/A-) */
307static char *voicebuf; 307static char *voicebuf;
308static size_t voice_remaining; 308static size_t voice_remaining;
309 309
310#ifdef IRAM_STEAL
311static bool voice_iram_stolen = false; /* Voice IRAM has been stolen for other use */
312#endif
313
310static void (*voice_getmore)(unsigned char** start, int* size); 314static void (*voice_getmore)(unsigned char** start, int* size);
311 315
312struct voice_info { 316struct voice_info {
@@ -318,15 +322,21 @@ static void voice_thread(void);
318 322
319#endif /* PLAYBACK_VOICE */ 323#endif /* PLAYBACK_VOICE */
320 324
325/* --- Shared semi-private interfaces --- */
326
327/* imported */
328extern void talk_buffer_steal(void);
329#ifdef HAVE_RECORDING
330extern void pcm_rec_error_clear(void);
331extern unsigned long pcm_rec_status(void);
332#endif
333
334
321/* --- External interfaces --- */ 335/* --- External interfaces --- */
322 336
323void mp3_play_data(const unsigned char* start, int size, 337void mp3_play_data(const unsigned char* start, int size,
324 void (*get_more)(unsigned char** start, int* size)) 338 void (*get_more)(unsigned char** start, int* size))
325{ 339{
326 /* must reset the buffer before any playback begins if needed */
327 if (buffer_state == BUFFER_STATE_TRASHED)
328 audio_reset_buffer(pcmbuf_get_bufsize());
329
330#ifdef PLAYBACK_VOICE 340#ifdef PLAYBACK_VOICE
331 static struct voice_info voice_clip; 341 static struct voice_info voice_clip;
332 voice_clip.callback = get_more; 342 voice_clip.callback = get_more;
@@ -366,11 +376,20 @@ void mpeg_id3_options(bool _v1first)
366 376
367unsigned char *audio_get_buffer(bool talk_buf, size_t *buffer_size) 377unsigned char *audio_get_buffer(bool talk_buf, size_t *buffer_size)
368{ 378{
369 unsigned char *buf = audiobuf; 379 unsigned char *buf, *end;
370 unsigned char *end = audiobufend;
371 380
372 audio_stop(); 381 audio_stop();
373 382
383 if (buffer_size == NULL)
384 {
385 /* Special case for talk_init to use */
386 buffer_state = BUFFER_STATE_TRASHED;
387 return NULL;
388 }
389
390 buf = audiobuf;
391 end = audiobufend;
392
374 if (talk_buf || !talk_voice_required() 393 if (talk_buf || !talk_voice_required()
375 || buffer_state == BUFFER_STATE_TRASHED) 394 || buffer_state == BUFFER_STATE_TRASHED)
376 { 395 {
@@ -395,17 +414,57 @@ unsigned char *audio_get_buffer(bool talk_buf, size_t *buffer_size)
395 return buf; 414 return buf;
396} 415}
397 416
417#ifdef IRAM_STEAL
418void audio_iram_steal(void)
419{
420 /* We need to stop audio playback in order to use codec IRAM */
421 audio_stop();
422
423#ifdef PLAYBACK_VOICE
424 if (NULL != iram_buf[CODEC_IDX_VOICE])
425 {
426 /* Wait for voice to swap back in if current codec was audio */
427 while (current_codec != CODEC_IDX_VOICE)
428 yield();
429
430 voice_stop();
431
432 /* Save voice IRAM - safe to do here since state is known */
433 memcpy(iram_buf[CODEC_IDX_VOICE], (void *)CODEC_IRAM_ORIGIN,
434 CODEC_IRAM_SIZE);
435 voice_iram_stolen = true;
436 }
437 else
438 {
439 /* Nothing much to do if no voice */
440 voice_iram_stolen = false;
441 }
442#endif
443}
444#endif /* IRAM_STEAL */
445
398#ifdef HAVE_RECORDING 446#ifdef HAVE_RECORDING
399unsigned char *audio_get_recording_buffer(size_t *buffer_size) 447unsigned char *audio_get_recording_buffer(size_t *buffer_size)
400{ 448{
401 /* don't allow overwrite of voice swap area or we'll trash the 449 /* don't allow overwrite of voice swap area or we'll trash the
402 swapped-out voice codec but can use whole thing if none */ 450 swapped-out voice codec but can use whole thing if none */
403 unsigned char *end = iram_buf[CODEC_IDX_VOICE] ? 451 unsigned char *end;
404 iram_buf[CODEC_IDX_VOICE] : audiobufend;
405 452
406 audio_stop(); 453 audio_stop();
407 talk_buffer_steal(); 454 talk_buffer_steal();
408 455
456#ifdef PLAYBACK_VOICE
457#ifdef IRAM_STEAL
458 end = dram_buf[CODEC_IDX_VOICE] ?
459 dram_buf[CODEC_IDX_VOICE] : audiobufend;
460#else
461 end = iram_buf[CODEC_IDX_VOICE] ?
462 iram_buf[CODEC_IDX_VOICE] : audiobufend;
463#endif /* IRAM_STEAL */
464#else
465 end = audiobufend;
466#endif /* PLAYBACK_VOICE */
467
409 buffer_state = BUFFER_STATE_TRASHED; 468 buffer_state = BUFFER_STATE_TRASHED;
410 469
411 *buffer_size = end - audiobuf; 470 *buffer_size = end - audiobuf;
@@ -645,7 +704,6 @@ void audio_flush_and_reload_tracks(void)
645void audio_error_clear(void) 704void audio_error_clear(void)
646{ 705{
647#ifdef AUDIO_HAVE_RECORDING 706#ifdef AUDIO_HAVE_RECORDING
648 extern void pcm_rec_error_clear(void);
649 pcm_rec_error_clear(); 707 pcm_rec_error_clear();
650#endif 708#endif
651} 709}
@@ -662,7 +720,6 @@ int audio_status(void)
662 720
663#ifdef HAVE_RECORDING 721#ifdef HAVE_RECORDING
664 /* Do this here for constitency with mpeg.c version */ 722 /* Do this here for constitency with mpeg.c version */
665 extern unsigned long pcm_rec_status(void);
666 ret |= pcm_rec_status(); 723 ret |= pcm_rec_status();
667#endif 724#endif
668 725
@@ -820,7 +877,6 @@ void voice_stop(void)
820 877
821 878
822/* --- Routines called from multiple threads --- */ 879/* --- Routines called from multiple threads --- */
823
824#ifdef PLAYBACK_VOICE 880#ifdef PLAYBACK_VOICE
825static void swap_codec(void) 881static void swap_codec(void)
826{ 882{
@@ -829,8 +885,26 @@ static void swap_codec(void)
829 logf("swapping out codec:%d", my_codec); 885 logf("swapping out codec:%d", my_codec);
830 886
831 /* Save our current IRAM and DRAM */ 887 /* Save our current IRAM and DRAM */
888#ifdef IRAM_STEAL
889 if (voice_iram_stolen)
890 {
891 logf("swap: iram restore");
892 voice_iram_stolen = false;
893 /* Don't swap trashed data into buffer - _should_ always be the case
894 if voice_iram_stolen is true since the voice has been swapped in
895 before hand */
896 if (my_codec == CODEC_IDX_VOICE)
897 goto skip_iram_swap;
898 }
899#endif
900
832 memcpy(iram_buf[my_codec], (unsigned char *)CODEC_IRAM_ORIGIN, 901 memcpy(iram_buf[my_codec], (unsigned char *)CODEC_IRAM_ORIGIN,
833 CODEC_IRAM_SIZE); 902 CODEC_IRAM_SIZE);
903
904#ifdef IRAM_STEAL
905skip_iram_swap:
906#endif
907
834 memcpy(dram_buf[my_codec], codecbuf, CODEC_SIZE); 908 memcpy(dram_buf[my_codec], codecbuf, CODEC_SIZE);
835 909
836 /* Release my semaphore */ 910 /* Release my semaphore */
@@ -1085,6 +1159,21 @@ static void* voice_request_buffer_callback(size_t *realsize, size_t reqsize)
1085 { 1159 {
1086 /* Set up new voice data */ 1160 /* Set up new voice data */
1087 struct voice_info *voice_data; 1161 struct voice_info *voice_data;
1162#ifdef IRAM_STEAL
1163 if (voice_iram_stolen)
1164 {
1165 logf("voice: iram restore");
1166 memcpy((void*)CODEC_IRAM_ORIGIN,
1167 iram_buf[CODEC_IDX_VOICE],
1168 CODEC_IRAM_SIZE);
1169 voice_iram_stolen = false;
1170 }
1171#endif
1172 /* must reset the buffer before any playback
1173 begins if needed */
1174 if (buffer_state == BUFFER_STATE_TRASHED)
1175 audio_reset_buffer(pcmbuf_get_bufsize());
1176
1088 voice_is_playing = true; 1177 voice_is_playing = true;
1089 trigger_cpu_boost(); 1178 trigger_cpu_boost();
1090 voice_data = ev.data; 1179 voice_data = ev.data;
@@ -2809,6 +2898,10 @@ static void audio_fill_file_buffer(
2809 bool had_next_track = audio_next_track() != NULL; 2898 bool had_next_track = audio_next_track() != NULL;
2810 bool continue_buffering; 2899 bool continue_buffering;
2811 2900
2901 /* must reset the buffer before use if trashed */
2902 if (buffer_state != BUFFER_STATE_NORMAL)
2903 audio_reset_buffer(pcmbuf_get_bufsize());
2904
2812 if (!audio_initialize_buffer_fill(!start_play)) 2905 if (!audio_initialize_buffer_fill(!start_play))
2813 return ; 2906 return ;
2814 2907
@@ -3156,10 +3249,6 @@ static void audio_play_start(size_t offset)
3156 /* Wait for any previously playing audio to flush - TODO: Not necessary? */ 3249 /* Wait for any previously playing audio to flush - TODO: Not necessary? */
3157 audio_stop_codec_flush(); 3250 audio_stop_codec_flush();
3158 3251
3159 /* must reset the buffer before any playback begins if needed */
3160 if (buffer_state != BUFFER_STATE_NORMAL)
3161 audio_reset_buffer(pcmbuf_get_bufsize());
3162
3163 track_changed = true; 3252 track_changed = true;
3164 playlist_end = false; 3253 playlist_end = false;
3165 3254
@@ -3272,14 +3361,34 @@ static void audio_reset_buffer(size_t pcmbufsize)
3272 if (talk_voice_required()) 3361 if (talk_voice_required())
3273 { 3362 {
3274#ifdef PLAYBACK_VOICE 3363#ifdef PLAYBACK_VOICE
3364#ifdef IRAM_STEAL
3365 filebuflen -= CODEC_IRAM_SIZE + 2*CODEC_SIZE;
3366#else
3367 filebuflen -= 2*(CODEC_IRAM_SIZE + CODEC_SIZE);
3368#endif
3275 /* Allow 2 codecs at end of audio buffer */ 3369 /* Allow 2 codecs at end of audio buffer */
3276 filebuflen -= 2 * (CODEC_IRAM_SIZE + CODEC_SIZE); 3370 /* If using IRAM for plugins voice IRAM swap buffer must be dedicated
3277 3371 and out of the way of buffer usage or else a call to audio_get_buffer
3372 and subsequent buffer use might trash the swap space. A plugin
3373 initializing IRAM after getting the full buffer would present similar
3374 problem. Options include: failing the request if the other buffer
3375 has been obtained already or never allowing use of the voice IRAM
3376 buffer within the audio buffer. Using buffer_alloc basically
3377 implements the second in a more convenient way. */
3278 iram_buf[CODEC_IDX_AUDIO] = filebuf + filebuflen; 3378 iram_buf[CODEC_IDX_AUDIO] = filebuf + filebuflen;
3279 dram_buf[CODEC_IDX_AUDIO] = iram_buf[CODEC_IDX_AUDIO] + CODEC_IRAM_SIZE; 3379 dram_buf[CODEC_IDX_AUDIO] = iram_buf[CODEC_IDX_AUDIO] + CODEC_IRAM_SIZE;
3380
3381#ifdef IRAM_STEAL
3382 /* Allocate voice IRAM swap buffer once */
3383 if (iram_buf[CODEC_IDX_VOICE] == NULL)
3384 iram_buf[CODEC_IDX_VOICE] = buffer_alloc(CODEC_IRAM_SIZE);
3385 dram_buf[CODEC_IDX_VOICE] = dram_buf[CODEC_IDX_AUDIO] + CODEC_SIZE;
3386#else
3280 iram_buf[CODEC_IDX_VOICE] = dram_buf[CODEC_IDX_AUDIO] + CODEC_SIZE; 3387 iram_buf[CODEC_IDX_VOICE] = dram_buf[CODEC_IDX_AUDIO] + CODEC_SIZE;
3281 dram_buf[CODEC_IDX_VOICE] = iram_buf[CODEC_IDX_VOICE] + CODEC_IRAM_SIZE; 3388 dram_buf[CODEC_IDX_VOICE] = iram_buf[CODEC_IDX_VOICE] + CODEC_IRAM_SIZE;
3282#endif 3389#endif /* IRAM_STEAL */
3390
3391#endif /* PLAYBACK_VOICE */
3283 } 3392 }
3284 else 3393 else
3285 { 3394 {