From a2b6703a369f6cdbfec1f150c408dadc877631fb Mon Sep 17 00:00:00 2001 From: Michael Sevakis Date: Wed, 29 Jun 2011 06:37:04 +0000 Subject: Commit FS#12150 - Fully-functional audio mixer - and finally whip old limitations about playback of voice and other sounds when paused. Channels are independent in state and amplitude. Fade on stop/pause is handled by the channel's volume control rather than global volume which means it now works from anywhere. Opens up the possibility of plugin sounds during music playback by merely adding an additional channel enum. If any PCM drivers were not properly modified, see one of the last comments in the task for a description of the simple change that is expected. Some params are tunable in firmware/export/pcm-mixer.h as well. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30097 a1c6a512-1295-4272-9138-f99709370657 --- firmware/target/hosted/android/pcm-android.c | 54 ++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) (limited to 'firmware/target/hosted/android/pcm-android.c') diff --git a/firmware/target/hosted/android/pcm-android.c b/firmware/target/hosted/android/pcm-android.c index 88792cd76f..cbd6cb3228 100644 --- a/firmware/target/hosted/android/pcm-android.c +++ b/firmware/target/hosted/android/pcm-android.c @@ -23,14 +23,18 @@ #include #define _SYSTEM_WITH_JNI /* for getJavaEnvironment */ #include +#include #include "debug.h" #include "pcm.h" +#include "pcm-internal.h" extern JNIEnv *env_ptr; /* infos about our pcm chunks */ static size_t pcm_data_size; static char *pcm_data_start; +static int audio_locked = 0; +static pthread_mutex_t audio_lock_mutex = PTHREAD_MUTEX_INITIALIZER; /* cache frequently called methods */ static jmethodID play_pause_method; @@ -41,6 +45,20 @@ static jclass RockboxPCM_class; static jobject RockboxPCM_instance; +/* + * mutex lock/unlock wrappers neatness' sake + */ +static inline void lock_audio(void) +{ + pthread_mutex_lock(&audio_lock_mutex); +} + +static inline void unlock_audio(void) +{ + pthread_mutex_unlock(&audio_lock_mutex); +} + + /* * write pcm samples to the hardware. Calls AudioTrack.write directly (which * is usually a blocking call) @@ -54,10 +72,17 @@ JNIEXPORT jint JNICALL Java_org_rockbox_RockboxPCM_nativeWrite(JNIEnv *env, jobject this, jbyteArray temp_array, jint max_size) { + bool new_buffer = false; + + lock_audio(); + jint left = max_size; if (!pcm_data_size) /* get some initial data */ + { + new_buffer = true; pcm_play_get_more_callback((void**) &pcm_data_start, &pcm_data_size); + } while(left > 0 && pcm_data_size) { @@ -70,23 +95,49 @@ Java_org_rockbox_RockboxPCM_nativeWrite(JNIEnv *env, jobject this, ret = (*env)->CallIntMethod(env, this, write_method, temp_array, 0, transfer_size); + + if (new_buffer) + { + new_buffer = false; + pcm_play_dma_started_callback(); + + /* NOTE: might need to release the mutex and sleep here if the + buffer is shorter than the required buffer (like pcm-sdl.c) to + have the mixer clocked at a regular interval */ + } + if (ret < 0) + { + unlock_audio(); return ret; + } if (pcm_data_size == 0) /* need new data */ + { + new_buffer = true; pcm_play_get_more_callback((void**)&pcm_data_start, &pcm_data_size); + } else /* increment data pointer and feed more */ pcm_data_start += transfer_size; } + + if (new_buffer && pcm_data_size) + pcm_play_dma_started_callback(); + + unlock_audio(); return max_size - left; } void pcm_play_lock(void) { + if (++audio_locked == 1) + lock_audio(); } void pcm_play_unlock(void) { + if (--audio_locked == 0) + unlock_audio(); } void pcm_dma_apply_settings(void) @@ -153,8 +204,6 @@ void pcm_play_dma_init(void) set_volume_method = e->GetMethodID(env_ptr, RockboxPCM_class, "set_volume", "(I)V"); stop_method = e->GetMethodID(env_ptr, RockboxPCM_class, "stop", "()V"); write_method = e->GetMethodID(env_ptr, RockboxPCM_class, "write", "([BII)I"); - /* get initial pcm data, if any */ - pcm_play_get_more_callback((void*)&pcm_data_start, &pcm_data_size); } void pcm_postinit(void) @@ -173,6 +222,7 @@ void pcm_shutdown(void) JNIEnv e = *env_ptr; jmethodID release = e->GetMethodID(env_ptr, RockboxPCM_class, "release", "()V"); e->CallVoidMethod(env_ptr, RockboxPCM_instance, release); + pthread_mutex_destroy(&audio_lock_mutex); } /* Due to limitations of default_event_handler(), parameters gets swallowed when -- cgit v1.2.3