diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2011-06-29 06:37:04 +0000 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2011-06-29 06:37:04 +0000 |
commit | a2b6703a369f6cdbfec1f150c408dadc877631fb (patch) | |
tree | 3145a8c1372c44711d38feefeba39c7d4098f139 /firmware/target/hosted/android/pcm-android.c | |
parent | 8411614b8a068a4f274c3841aa55aab1df1bc246 (diff) | |
download | rockbox-a2b6703a369f6cdbfec1f150c408dadc877631fb.tar.gz rockbox-a2b6703a369f6cdbfec1f150c408dadc877631fb.zip |
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
Diffstat (limited to 'firmware/target/hosted/android/pcm-android.c')
-rw-r--r-- | firmware/target/hosted/android/pcm-android.c | 54 |
1 files changed, 52 insertions, 2 deletions
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 @@ | |||
23 | #include <stdbool.h> | 23 | #include <stdbool.h> |
24 | #define _SYSTEM_WITH_JNI /* for getJavaEnvironment */ | 24 | #define _SYSTEM_WITH_JNI /* for getJavaEnvironment */ |
25 | #include <system.h> | 25 | #include <system.h> |
26 | #include <pthread.h> | ||
26 | #include "debug.h" | 27 | #include "debug.h" |
27 | #include "pcm.h" | 28 | #include "pcm.h" |
29 | #include "pcm-internal.h" | ||
28 | 30 | ||
29 | extern JNIEnv *env_ptr; | 31 | extern JNIEnv *env_ptr; |
30 | 32 | ||
31 | /* infos about our pcm chunks */ | 33 | /* infos about our pcm chunks */ |
32 | static size_t pcm_data_size; | 34 | static size_t pcm_data_size; |
33 | static char *pcm_data_start; | 35 | static char *pcm_data_start; |
36 | static int audio_locked = 0; | ||
37 | static pthread_mutex_t audio_lock_mutex = PTHREAD_MUTEX_INITIALIZER; | ||
34 | 38 | ||
35 | /* cache frequently called methods */ | 39 | /* cache frequently called methods */ |
36 | static jmethodID play_pause_method; | 40 | static jmethodID play_pause_method; |
@@ -42,6 +46,20 @@ static jobject RockboxPCM_instance; | |||
42 | 46 | ||
43 | 47 | ||
44 | /* | 48 | /* |
49 | * mutex lock/unlock wrappers neatness' sake | ||
50 | */ | ||
51 | static inline void lock_audio(void) | ||
52 | { | ||
53 | pthread_mutex_lock(&audio_lock_mutex); | ||
54 | } | ||
55 | |||
56 | static inline void unlock_audio(void) | ||
57 | { | ||
58 | pthread_mutex_unlock(&audio_lock_mutex); | ||
59 | } | ||
60 | |||
61 | |||
62 | /* | ||
45 | * write pcm samples to the hardware. Calls AudioTrack.write directly (which | 63 | * write pcm samples to the hardware. Calls AudioTrack.write directly (which |
46 | * is usually a blocking call) | 64 | * is usually a blocking call) |
47 | * | 65 | * |
@@ -54,10 +72,17 @@ JNIEXPORT jint JNICALL | |||
54 | Java_org_rockbox_RockboxPCM_nativeWrite(JNIEnv *env, jobject this, | 72 | Java_org_rockbox_RockboxPCM_nativeWrite(JNIEnv *env, jobject this, |
55 | jbyteArray temp_array, jint max_size) | 73 | jbyteArray temp_array, jint max_size) |
56 | { | 74 | { |
75 | bool new_buffer = false; | ||
76 | |||
77 | lock_audio(); | ||
78 | |||
57 | jint left = max_size; | 79 | jint left = max_size; |
58 | 80 | ||
59 | if (!pcm_data_size) /* get some initial data */ | 81 | if (!pcm_data_size) /* get some initial data */ |
82 | { | ||
83 | new_buffer = true; | ||
60 | pcm_play_get_more_callback((void**) &pcm_data_start, &pcm_data_size); | 84 | pcm_play_get_more_callback((void**) &pcm_data_start, &pcm_data_size); |
85 | } | ||
61 | 86 | ||
62 | while(left > 0 && pcm_data_size) | 87 | while(left > 0 && pcm_data_size) |
63 | { | 88 | { |
@@ -70,23 +95,49 @@ Java_org_rockbox_RockboxPCM_nativeWrite(JNIEnv *env, jobject this, | |||
70 | 95 | ||
71 | ret = (*env)->CallIntMethod(env, this, write_method, | 96 | ret = (*env)->CallIntMethod(env, this, write_method, |
72 | temp_array, 0, transfer_size); | 97 | temp_array, 0, transfer_size); |
98 | |||
99 | if (new_buffer) | ||
100 | { | ||
101 | new_buffer = false; | ||
102 | pcm_play_dma_started_callback(); | ||
103 | |||
104 | /* NOTE: might need to release the mutex and sleep here if the | ||
105 | buffer is shorter than the required buffer (like pcm-sdl.c) to | ||
106 | have the mixer clocked at a regular interval */ | ||
107 | } | ||
108 | |||
73 | if (ret < 0) | 109 | if (ret < 0) |
110 | { | ||
111 | unlock_audio(); | ||
74 | return ret; | 112 | return ret; |
113 | } | ||
75 | 114 | ||
76 | if (pcm_data_size == 0) /* need new data */ | 115 | if (pcm_data_size == 0) /* need new data */ |
116 | { | ||
117 | new_buffer = true; | ||
77 | pcm_play_get_more_callback((void**)&pcm_data_start, &pcm_data_size); | 118 | pcm_play_get_more_callback((void**)&pcm_data_start, &pcm_data_size); |
119 | } | ||
78 | else /* increment data pointer and feed more */ | 120 | else /* increment data pointer and feed more */ |
79 | pcm_data_start += transfer_size; | 121 | pcm_data_start += transfer_size; |
80 | } | 122 | } |
123 | |||
124 | if (new_buffer && pcm_data_size) | ||
125 | pcm_play_dma_started_callback(); | ||
126 | |||
127 | unlock_audio(); | ||
81 | return max_size - left; | 128 | return max_size - left; |
82 | } | 129 | } |
83 | 130 | ||
84 | void pcm_play_lock(void) | 131 | void pcm_play_lock(void) |
85 | { | 132 | { |
133 | if (++audio_locked == 1) | ||
134 | lock_audio(); | ||
86 | } | 135 | } |
87 | 136 | ||
88 | void pcm_play_unlock(void) | 137 | void pcm_play_unlock(void) |
89 | { | 138 | { |
139 | if (--audio_locked == 0) | ||
140 | unlock_audio(); | ||
90 | } | 141 | } |
91 | 142 | ||
92 | void pcm_dma_apply_settings(void) | 143 | void pcm_dma_apply_settings(void) |
@@ -153,8 +204,6 @@ void pcm_play_dma_init(void) | |||
153 | set_volume_method = e->GetMethodID(env_ptr, RockboxPCM_class, "set_volume", "(I)V"); | 204 | set_volume_method = e->GetMethodID(env_ptr, RockboxPCM_class, "set_volume", "(I)V"); |
154 | stop_method = e->GetMethodID(env_ptr, RockboxPCM_class, "stop", "()V"); | 205 | stop_method = e->GetMethodID(env_ptr, RockboxPCM_class, "stop", "()V"); |
155 | write_method = e->GetMethodID(env_ptr, RockboxPCM_class, "write", "([BII)I"); | 206 | write_method = e->GetMethodID(env_ptr, RockboxPCM_class, "write", "([BII)I"); |
156 | /* get initial pcm data, if any */ | ||
157 | pcm_play_get_more_callback((void*)&pcm_data_start, &pcm_data_size); | ||
158 | } | 207 | } |
159 | 208 | ||
160 | void pcm_postinit(void) | 209 | void pcm_postinit(void) |
@@ -173,6 +222,7 @@ void pcm_shutdown(void) | |||
173 | JNIEnv e = *env_ptr; | 222 | JNIEnv e = *env_ptr; |
174 | jmethodID release = e->GetMethodID(env_ptr, RockboxPCM_class, "release", "()V"); | 223 | jmethodID release = e->GetMethodID(env_ptr, RockboxPCM_class, "release", "()V"); |
175 | e->CallVoidMethod(env_ptr, RockboxPCM_instance, release); | 224 | e->CallVoidMethod(env_ptr, RockboxPCM_instance, release); |
225 | pthread_mutex_destroy(&audio_lock_mutex); | ||
176 | } | 226 | } |
177 | 227 | ||
178 | /* Due to limitations of default_event_handler(), parameters gets swallowed when | 228 | /* Due to limitations of default_event_handler(), parameters gets swallowed when |