diff options
Diffstat (limited to 'apps/playback.c')
-rw-r--r-- | apps/playback.c | 92 |
1 files changed, 53 insertions, 39 deletions
diff --git a/apps/playback.c b/apps/playback.c index b80c68384f..0fd1c21daf 100644 --- a/apps/playback.c +++ b/apps/playback.c | |||
@@ -290,8 +290,8 @@ static void set_current_codec(int codec_idx); | |||
290 | static void set_filebuf_watermark(int seconds); | 290 | static void set_filebuf_watermark(int seconds); |
291 | 291 | ||
292 | /* Audio thread */ | 292 | /* Audio thread */ |
293 | static struct event_queue audio_queue; | 293 | static struct event_queue audio_queue NOCACHEBSS_ATTR; |
294 | static struct queue_sender_list audio_queue_sender_list; | 294 | static struct queue_sender_list audio_queue_sender_list NOCACHEBSS_ATTR; |
295 | static long audio_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)]; | 295 | static long audio_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)]; |
296 | static const char audio_thread_name[] = "audio"; | 296 | static const char audio_thread_name[] = "audio"; |
297 | 297 | ||
@@ -340,9 +340,10 @@ static unsigned char *dram_buf = NULL; | |||
340 | automatically swaps in the other and the swap when unlocking should not | 340 | automatically swaps in the other and the swap when unlocking should not |
341 | happen if the parity is even. | 341 | happen if the parity is even. |
342 | */ | 342 | */ |
343 | static bool swap_codec_parity = false; /* true=odd, false=even */ | 343 | static bool swap_codec_parity NOCACHEBSS_ATTR = false; /* true=odd, false=even */ |
344 | /* Mutex to control which codec (normal/voice) is running */ | 344 | /* Locking to control which codec (normal/voice) is running */ |
345 | static struct mutex mutex_codecthread NOCACHEBSS_ATTR; | 345 | static struct semaphore sem_codecthread NOCACHEBSS_ATTR; |
346 | static struct event event_codecthread NOCACHEBSS_ATTR; | ||
346 | 347 | ||
347 | /* Voice state */ | 348 | /* Voice state */ |
348 | static volatile bool voice_thread_start = false; /* Triggers voice playback (A/V) */ | 349 | static volatile bool voice_thread_start = false; /* Triggers voice playback (A/V) */ |
@@ -424,8 +425,7 @@ static void wait_for_voice_swap_in(void) | |||
424 | if (NULL == iram_buf) | 425 | if (NULL == iram_buf) |
425 | return; | 426 | return; |
426 | 427 | ||
427 | while (current_codec != CODEC_IDX_VOICE) | 428 | event_wait(&event_codecthread, STATE_NONSIGNALED); |
428 | yield(); | ||
429 | #endif /* PLAYBACK_VOICE */ | 429 | #endif /* PLAYBACK_VOICE */ |
430 | } | 430 | } |
431 | 431 | ||
@@ -924,21 +924,21 @@ static void swap_codec(void) | |||
924 | } | 924 | } |
925 | 925 | ||
926 | /* Release my semaphore */ | 926 | /* Release my semaphore */ |
927 | mutex_unlock(&mutex_codecthread); | 927 | semaphore_release(&sem_codecthread); |
928 | logf("unlocked: %d", my_codec); | 928 | logf("unlocked: %d", my_codec); |
929 | 929 | ||
930 | /* Loop until the other codec has locked and run */ | 930 | /* Wait for other codec */ |
931 | do { | 931 | event_wait(&event_codecthread, |
932 | /* Release my semaphore and force a task switch. */ | 932 | (my_codec == CODEC_IDX_AUDIO) ? STATE_NONSIGNALED : STATE_SIGNALED); |
933 | yield(); | ||
934 | } while (my_codec == current_codec); | ||
935 | 933 | ||
936 | /* Wait for other codec to unlock */ | 934 | /* Wait for other codec to unlock */ |
937 | mutex_lock(&mutex_codecthread); | 935 | logf("waiting for lock: %d", my_codec); |
936 | semaphore_wait(&sem_codecthread); | ||
938 | 937 | ||
939 | /* Take control */ | 938 | /* Take control */ |
940 | logf("waiting for lock: %d", my_codec); | ||
941 | set_current_codec(my_codec); | 939 | set_current_codec(my_codec); |
940 | event_set_state(&event_codecthread, | ||
941 | (my_codec == CODEC_IDX_AUDIO) ? STATE_SIGNALED : STATE_NONSIGNALED); | ||
942 | 942 | ||
943 | /* Reload our IRAM and DRAM */ | 943 | /* Reload our IRAM and DRAM */ |
944 | memswap128(iram_buf, CODEC_IRAM_ORIGIN, CODEC_IRAM_SIZE); | 944 | memswap128(iram_buf, CODEC_IRAM_ORIGIN, CODEC_IRAM_SIZE); |
@@ -1161,7 +1161,7 @@ static bool voice_on_voice_stop(bool aborting, size_t *realsize) | |||
1161 | 1161 | ||
1162 | static void* voice_request_buffer_callback(size_t *realsize, size_t reqsize) | 1162 | static void* voice_request_buffer_callback(size_t *realsize, size_t reqsize) |
1163 | { | 1163 | { |
1164 | struct event ev; | 1164 | struct queue_event ev; |
1165 | 1165 | ||
1166 | if (ci_voice.new_track) | 1166 | if (ci_voice.new_track) |
1167 | { | 1167 | { |
@@ -1332,7 +1332,8 @@ static void voice_thread(void) | |||
1332 | { | 1332 | { |
1333 | logf("Loading voice codec"); | 1333 | logf("Loading voice codec"); |
1334 | voice_codec_loaded = true; | 1334 | voice_codec_loaded = true; |
1335 | mutex_lock(&mutex_codecthread); | 1335 | semaphore_wait(&sem_codecthread); |
1336 | event_set_state(&event_codecthread, false); | ||
1336 | set_current_codec(CODEC_IDX_VOICE); | 1337 | set_current_codec(CODEC_IDX_VOICE); |
1337 | dsp_configure(DSP_RESET, 0); | 1338 | dsp_configure(DSP_RESET, 0); |
1338 | voice_remaining = 0; | 1339 | voice_remaining = 0; |
@@ -1344,9 +1345,8 @@ static void voice_thread(void) | |||
1344 | 1345 | ||
1345 | logf("Voice codec finished"); | 1346 | logf("Voice codec finished"); |
1346 | voice_codec_loaded = false; | 1347 | voice_codec_loaded = false; |
1347 | mutex_unlock(&mutex_codecthread); | ||
1348 | voice_thread_p = NULL; | 1348 | voice_thread_p = NULL; |
1349 | remove_thread(NULL); | 1349 | semaphore_release(&sem_codecthread); |
1350 | } /* voice_thread */ | 1350 | } /* voice_thread */ |
1351 | 1351 | ||
1352 | #endif /* PLAYBACK_VOICE */ | 1352 | #endif /* PLAYBACK_VOICE */ |
@@ -1968,7 +1968,7 @@ static bool codec_request_next_track_callback(void) | |||
1968 | 1968 | ||
1969 | static void codec_thread(void) | 1969 | static void codec_thread(void) |
1970 | { | 1970 | { |
1971 | struct event ev; | 1971 | struct queue_event ev; |
1972 | int status; | 1972 | int status; |
1973 | size_t wrap; | 1973 | size_t wrap; |
1974 | 1974 | ||
@@ -1988,13 +1988,14 @@ static void codec_thread(void) | |||
1988 | LOGFQUEUE("codec > voice Q_AUDIO_PLAY"); | 1988 | LOGFQUEUE("codec > voice Q_AUDIO_PLAY"); |
1989 | queue_post(&voice_queue, Q_AUDIO_PLAY, 0); | 1989 | queue_post(&voice_queue, Q_AUDIO_PLAY, 0); |
1990 | } | 1990 | } |
1991 | mutex_lock(&mutex_codecthread); | 1991 | semaphore_wait(&sem_codecthread); |
1992 | event_set_state(&event_codecthread, true); | ||
1992 | #endif | 1993 | #endif |
1993 | set_current_codec(CODEC_IDX_AUDIO); | 1994 | set_current_codec(CODEC_IDX_AUDIO); |
1994 | ci.stop_codec = false; | 1995 | ci.stop_codec = false; |
1995 | status = codec_load_file((const char *)ev.data, &ci); | 1996 | status = codec_load_file((const char *)ev.data, &ci); |
1996 | #ifdef PLAYBACK_VOICE | 1997 | #ifdef PLAYBACK_VOICE |
1997 | mutex_unlock(&mutex_codecthread); | 1998 | semaphore_release(&sem_codecthread); |
1998 | #endif | 1999 | #endif |
1999 | break; | 2000 | break; |
2000 | 2001 | ||
@@ -2019,7 +2020,8 @@ static void codec_thread(void) | |||
2019 | LOGFQUEUE("codec > voice Q_AUDIO_PLAY"); | 2020 | LOGFQUEUE("codec > voice Q_AUDIO_PLAY"); |
2020 | queue_post(&voice_queue, Q_AUDIO_PLAY, 0); | 2021 | queue_post(&voice_queue, Q_AUDIO_PLAY, 0); |
2021 | } | 2022 | } |
2022 | mutex_lock(&mutex_codecthread); | 2023 | semaphore_wait(&sem_codecthread); |
2024 | event_set_state(&event_codecthread, true); | ||
2023 | #endif | 2025 | #endif |
2024 | set_current_codec(CODEC_IDX_AUDIO); | 2026 | set_current_codec(CODEC_IDX_AUDIO); |
2025 | ci.stop_codec = false; | 2027 | ci.stop_codec = false; |
@@ -2027,7 +2029,7 @@ static void codec_thread(void) | |||
2027 | status = codec_load_ram(CUR_TI->codecbuf, CUR_TI->codecsize, | 2029 | status = codec_load_ram(CUR_TI->codecbuf, CUR_TI->codecsize, |
2028 | &filebuf[0], wrap, &ci); | 2030 | &filebuf[0], wrap, &ci); |
2029 | #ifdef PLAYBACK_VOICE | 2031 | #ifdef PLAYBACK_VOICE |
2030 | mutex_unlock(&mutex_codecthread); | 2032 | semaphore_release(&sem_codecthread); |
2031 | #endif | 2033 | #endif |
2032 | break; | 2034 | break; |
2033 | 2035 | ||
@@ -2041,14 +2043,15 @@ static void codec_thread(void) | |||
2041 | LOGFQUEUE("codec > voice Q_ENCODER_RECORD"); | 2043 | LOGFQUEUE("codec > voice Q_ENCODER_RECORD"); |
2042 | queue_post(&voice_queue, Q_ENCODER_RECORD, 0); | 2044 | queue_post(&voice_queue, Q_ENCODER_RECORD, 0); |
2043 | } | 2045 | } |
2044 | mutex_lock(&mutex_codecthread); | 2046 | semaphore_wait(&sem_codecthread); |
2047 | event_set_state(&event_codecthread, true); | ||
2045 | #endif | 2048 | #endif |
2046 | logf("loading encoder"); | 2049 | logf("loading encoder"); |
2047 | set_current_codec(CODEC_IDX_AUDIO); | 2050 | set_current_codec(CODEC_IDX_AUDIO); |
2048 | ci.stop_encoder = false; | 2051 | ci.stop_encoder = false; |
2049 | status = codec_load_file((const char *)ev.data, &ci); | 2052 | status = codec_load_file((const char *)ev.data, &ci); |
2050 | #ifdef PLAYBACK_VOICE | 2053 | #ifdef PLAYBACK_VOICE |
2051 | mutex_unlock(&mutex_codecthread); | 2054 | semaphore_release(&sem_codecthread); |
2052 | #endif | 2055 | #endif |
2053 | logf("encoder stopped"); | 2056 | logf("encoder stopped"); |
2054 | break; | 2057 | break; |
@@ -3594,13 +3597,13 @@ static bool ata_fillbuffer_callback(void) | |||
3594 | 3597 | ||
3595 | static void audio_thread(void) | 3598 | static void audio_thread(void) |
3596 | { | 3599 | { |
3597 | struct event ev; | 3600 | struct queue_event ev; |
3598 | 3601 | ||
3599 | pcm_postinit(); | 3602 | pcm_postinit(); |
3600 | 3603 | ||
3601 | #ifdef PLAYBACK_VOICE | 3604 | #ifdef PLAYBACK_VOICE |
3602 | /* Unlock mutex that init stage locks before creating this thread */ | 3605 | /* Unlock semaphore that init stage locks before creating this thread */ |
3603 | mutex_unlock(&mutex_codecthread); | 3606 | semaphore_release(&sem_codecthread); |
3604 | 3607 | ||
3605 | /* Buffers must be set up by now - should panic - really */ | 3608 | /* Buffers must be set up by now - should panic - really */ |
3606 | if (buffer_state != BUFFER_STATE_INITIALIZED) | 3609 | if (buffer_state != BUFFER_STATE_INITIALIZED) |
@@ -3764,7 +3767,9 @@ void audio_init(void) | |||
3764 | #ifdef PLAYBACK_VOICE | 3767 | #ifdef PLAYBACK_VOICE |
3765 | static bool voicetagtrue = true; | 3768 | static bool voicetagtrue = true; |
3766 | static struct mp3entry id3_voice; | 3769 | static struct mp3entry id3_voice; |
3770 | struct thread_entry *voice_thread_p = NULL; | ||
3767 | #endif | 3771 | #endif |
3772 | struct thread_entry *audio_thread_p; | ||
3768 | 3773 | ||
3769 | /* Can never do this twice */ | 3774 | /* Can never do this twice */ |
3770 | if (audio_is_initialized) | 3775 | if (audio_is_initialized) |
@@ -3779,11 +3784,11 @@ void audio_init(void) | |||
3779 | to send messages. Thread creation will be delayed however so nothing | 3784 | to send messages. Thread creation will be delayed however so nothing |
3780 | starts running until ready if something yields such as talk_init. */ | 3785 | starts running until ready if something yields such as talk_init. */ |
3781 | #ifdef PLAYBACK_VOICE | 3786 | #ifdef PLAYBACK_VOICE |
3782 | mutex_init(&mutex_codecthread); | ||
3783 | /* Take ownership of lock to prevent playback of anything before audio | 3787 | /* Take ownership of lock to prevent playback of anything before audio |
3784 | hardware is initialized - audio thread unlocks it after final init | 3788 | hardware is initialized - audio thread unlocks it after final init |
3785 | stage */ | 3789 | stage */ |
3786 | mutex_lock(&mutex_codecthread); | 3790 | semaphore_init(&sem_codecthread, 1, 0); |
3791 | event_init(&event_codecthread, EVENT_MANUAL | STATE_SIGNALED); | ||
3787 | #endif | 3792 | #endif |
3788 | queue_init(&audio_queue, true); | 3793 | queue_init(&audio_queue, true); |
3789 | queue_enable_queue_send(&audio_queue, &audio_queue_sender_list); | 3794 | queue_enable_queue_send(&audio_queue, &audio_queue_sender_list); |
@@ -3842,16 +3847,16 @@ void audio_init(void) | |||
3842 | talk first */ | 3847 | talk first */ |
3843 | talk_init(); | 3848 | talk_init(); |
3844 | 3849 | ||
3845 | /* Create the threads late now that we shouldn't be yielding again before | ||
3846 | returning */ | ||
3847 | codec_thread_p = create_thread( | 3850 | codec_thread_p = create_thread( |
3848 | codec_thread, codec_stack, sizeof(codec_stack), | 3851 | codec_thread, codec_stack, sizeof(codec_stack), |
3852 | CREATE_THREAD_FROZEN, | ||
3849 | codec_thread_name IF_PRIO(, PRIORITY_PLAYBACK) | 3853 | codec_thread_name IF_PRIO(, PRIORITY_PLAYBACK) |
3850 | IF_COP(, CPU, true)); | 3854 | IF_COP(, CPU)); |
3851 | 3855 | ||
3852 | create_thread(audio_thread, audio_stack, sizeof(audio_stack), | 3856 | audio_thread_p = create_thread(audio_thread, audio_stack, |
3857 | sizeof(audio_stack), CREATE_THREAD_FROZEN, | ||
3853 | audio_thread_name IF_PRIO(, PRIORITY_BUFFERING) | 3858 | audio_thread_name IF_PRIO(, PRIORITY_BUFFERING) |
3854 | IF_COP(, CPU, false)); | 3859 | IF_COP(, CPU)); |
3855 | 3860 | ||
3856 | #ifdef PLAYBACK_VOICE | 3861 | #ifdef PLAYBACK_VOICE |
3857 | /* TODO: Change this around when various speech codecs can be used */ | 3862 | /* TODO: Change this around when various speech codecs can be used */ |
@@ -3859,9 +3864,10 @@ void audio_init(void) | |||
3859 | { | 3864 | { |
3860 | logf("Starting voice codec"); | 3865 | logf("Starting voice codec"); |
3861 | queue_init(&voice_queue, true); | 3866 | queue_init(&voice_queue, true); |
3862 | create_thread(voice_thread, voice_stack, | 3867 | voice_thread_p = create_thread(voice_thread, voice_stack, |
3863 | sizeof(voice_stack), voice_thread_name | 3868 | sizeof(voice_stack), CREATE_THREAD_FROZEN, |
3864 | IF_PRIO(, PRIORITY_PLAYBACK) IF_COP(, CPU, false)); | 3869 | voice_thread_name |
3870 | IF_PRIO(, PRIORITY_PLAYBACK) IF_COP(, CPU)); | ||
3865 | } | 3871 | } |
3866 | #endif | 3872 | #endif |
3867 | 3873 | ||
@@ -3881,5 +3887,13 @@ void audio_init(void) | |||
3881 | #ifndef HAVE_FLASH_STORAGE | 3887 | #ifndef HAVE_FLASH_STORAGE |
3882 | audio_set_buffer_margin(global_settings.buffer_margin); | 3888 | audio_set_buffer_margin(global_settings.buffer_margin); |
3883 | #endif | 3889 | #endif |
3890 | |||
3891 | /* it's safe to let the threads run now */ | ||
3892 | thread_thaw(codec_thread_p); | ||
3893 | #ifdef PLAYBACK_VOICE | ||
3894 | if (voice_thread_p) | ||
3895 | thread_thaw(voice_thread_p); | ||
3896 | #endif | ||
3897 | thread_thaw(audio_thread_p); | ||
3884 | } /* audio_init */ | 3898 | } /* audio_init */ |
3885 | 3899 | ||