diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2006-11-18 02:18:29 +0000 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2006-11-18 02:18:29 +0000 |
commit | acc29d95be85c9cfd0d8f74dda813d7d1082e2ec (patch) | |
tree | 81fdd154d122b393d6254968cba5bc90b63e4741 /apps/playback.c | |
parent | e2a262ee258769136eadc58c2bc8e3aa53db1a71 (diff) | |
download | rockbox-acc29d95be85c9cfd0d8f74dda813d7d1082e2ec.tar.gz rockbox-acc29d95be85c9cfd0d8f74dda813d7d1082e2ec.zip |
SWCODEC/IRAM: Save voice IRAM when a plugin initializes its IRAM. Defines two macros for declaring and initializing IRAM. Plugins should use these instead. See mp3_encoder, doom, etc. for details. Further tweaks in buffer restoration after other use. Hiding of some interfaces that should only be used by buffer management.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11544 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/playback.c')
-rw-r--r-- | apps/playback.c | 149 |
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 | ||
299 | static unsigned char *iram_buf[2]; /* Ptr to IRAM buffers for normal/voice codecs */ | 299 | static unsigned char *iram_buf[2] = { NULL, NULL }; /* Ptr to IRAM buffers for normal/voice codecs */ |
300 | static unsigned char *dram_buf[2]; /* Ptr to DRAM buffers for normal/voice codecs */ | 300 | static unsigned char *dram_buf[2] = { NULL, NULL }; /* Ptr to DRAM buffers for normal/voice codecs */ |
301 | static struct mutex mutex_codecthread; /* Mutex to control which codec (normal/voice) is running */ | 301 | static 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-) */ | |||
307 | static char *voicebuf; | 307 | static char *voicebuf; |
308 | static size_t voice_remaining; | 308 | static size_t voice_remaining; |
309 | 309 | ||
310 | #ifdef IRAM_STEAL | ||
311 | static bool voice_iram_stolen = false; /* Voice IRAM has been stolen for other use */ | ||
312 | #endif | ||
313 | |||
310 | static void (*voice_getmore)(unsigned char** start, int* size); | 314 | static void (*voice_getmore)(unsigned char** start, int* size); |
311 | 315 | ||
312 | struct voice_info { | 316 | struct 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 */ | ||
328 | extern void talk_buffer_steal(void); | ||
329 | #ifdef HAVE_RECORDING | ||
330 | extern void pcm_rec_error_clear(void); | ||
331 | extern unsigned long pcm_rec_status(void); | ||
332 | #endif | ||
333 | |||
334 | |||
321 | /* --- External interfaces --- */ | 335 | /* --- External interfaces --- */ |
322 | 336 | ||
323 | void mp3_play_data(const unsigned char* start, int size, | 337 | void 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 | ||
367 | unsigned char *audio_get_buffer(bool talk_buf, size_t *buffer_size) | 377 | unsigned 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 | ||
418 | void 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 |
399 | unsigned char *audio_get_recording_buffer(size_t *buffer_size) | 447 | unsigned 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) | |||
645 | void audio_error_clear(void) | 704 | void 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 |
825 | static void swap_codec(void) | 881 | static 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 | ||
905 | skip_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 | { |