diff options
Diffstat (limited to 'firmware/target/hosted')
-rw-r--r-- | firmware/target/hosted/android/pcm-android.c | 54 | ||||
-rw-r--r-- | firmware/target/hosted/maemo/pcm-gstreamer.c | 3 | ||||
-rw-r--r-- | firmware/target/hosted/sdl/pcm-sdl.c | 47 |
3 files changed, 100 insertions, 4 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 |
diff --git a/firmware/target/hosted/maemo/pcm-gstreamer.c b/firmware/target/hosted/maemo/pcm-gstreamer.c index e3e40f0619..6069801fba 100644 --- a/firmware/target/hosted/maemo/pcm-gstreamer.c +++ b/firmware/target/hosted/maemo/pcm-gstreamer.c | |||
@@ -54,6 +54,7 @@ | |||
54 | #endif | 54 | #endif |
55 | 55 | ||
56 | #include "pcm.h" | 56 | #include "pcm.h" |
57 | #include "pcm-internal.h" | ||
57 | #include "pcm_sampr.h" | 58 | #include "pcm_sampr.h" |
58 | 59 | ||
59 | /*#define LOGF_ENABLE*/ | 60 | /*#define LOGF_ENABLE*/ |
@@ -182,6 +183,8 @@ static void feed_data(GstElement * appsrc, guint size_hint, void *unused) | |||
182 | 183 | ||
183 | if (ret != 0) | 184 | if (ret != 0) |
184 | DEBUGF("push-buffer error result: %d\n", ret); | 185 | DEBUGF("push-buffer error result: %d\n", ret); |
186 | |||
187 | pcm_play_dma_started_callback(); | ||
185 | } else | 188 | } else |
186 | { | 189 | { |
187 | DEBUGF("feed_data: No Data.\n"); | 190 | DEBUGF("feed_data: No Data.\n"); |
diff --git a/firmware/target/hosted/sdl/pcm-sdl.c b/firmware/target/hosted/sdl/pcm-sdl.c index 7780083b99..dfdd90f29b 100644 --- a/firmware/target/hosted/sdl/pcm-sdl.c +++ b/firmware/target/hosted/sdl/pcm-sdl.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include "sound.h" | 30 | #include "sound.h" |
31 | #include "audiohw.h" | 31 | #include "audiohw.h" |
32 | #include "system.h" | 32 | #include "system.h" |
33 | #include "panic.h" | ||
33 | 34 | ||
34 | #ifdef HAVE_RECORDING | 35 | #ifdef HAVE_RECORDING |
35 | #include "audiohw.h" | 36 | #include "audiohw.h" |
@@ -39,6 +40,7 @@ | |||
39 | #endif | 40 | #endif |
40 | 41 | ||
41 | #include "pcm.h" | 42 | #include "pcm.h" |
43 | #include "pcm-internal.h" | ||
42 | #include "pcm_sampr.h" | 44 | #include "pcm_sampr.h" |
43 | 45 | ||
44 | /*#define LOGF_ENABLE*/ | 46 | /*#define LOGF_ENABLE*/ |
@@ -71,15 +73,19 @@ static struct pcm_udata | |||
71 | 73 | ||
72 | static SDL_AudioSpec obtained; | 74 | static SDL_AudioSpec obtained; |
73 | static SDL_AudioCVT cvt; | 75 | static SDL_AudioCVT cvt; |
76 | static int audio_locked = 0; | ||
77 | static SDL_mutex *audio_lock; | ||
74 | 78 | ||
75 | void pcm_play_lock(void) | 79 | void pcm_play_lock(void) |
76 | { | 80 | { |
77 | SDL_LockAudio(); | 81 | if (++audio_locked == 1) |
82 | SDL_LockMutex(audio_lock); | ||
78 | } | 83 | } |
79 | 84 | ||
80 | void pcm_play_unlock(void) | 85 | void pcm_play_unlock(void) |
81 | { | 86 | { |
82 | SDL_UnlockAudio(); | 87 | if (--audio_locked == 0) |
88 | SDL_UnlockMutex(audio_lock); | ||
83 | } | 89 | } |
84 | 90 | ||
85 | static void pcm_dma_apply_settings_nolock(void) | 91 | static void pcm_dma_apply_settings_nolock(void) |
@@ -227,14 +233,19 @@ static void write_to_soundcard(struct pcm_udata *udata) | |||
227 | static void sdl_audio_callback(struct pcm_udata *udata, Uint8 *stream, int len) | 233 | static void sdl_audio_callback(struct pcm_udata *udata, Uint8 *stream, int len) |
228 | { | 234 | { |
229 | logf("sdl_audio_callback: len %d, pcm %d\n", len, pcm_data_size); | 235 | logf("sdl_audio_callback: len %d, pcm %d\n", len, pcm_data_size); |
236 | |||
237 | bool new_buffer = false; | ||
230 | udata->stream = stream; | 238 | udata->stream = stream; |
231 | 239 | ||
240 | SDL_LockMutex(audio_lock); | ||
241 | |||
232 | /* Write what we have in the PCM buffer */ | 242 | /* Write what we have in the PCM buffer */ |
233 | if (pcm_data_size > 0) | 243 | if (pcm_data_size > 0) |
234 | goto start; | 244 | goto start; |
235 | 245 | ||
236 | /* Audio card wants more? Get some more then. */ | 246 | /* Audio card wants more? Get some more then. */ |
237 | while (len > 0) { | 247 | while (len > 0) { |
248 | new_buffer = true; | ||
238 | pcm_play_get_more_callback((void **)&pcm_data, &pcm_data_size); | 249 | pcm_play_get_more_callback((void **)&pcm_data, &pcm_data_size); |
239 | start: | 250 | start: |
240 | if (pcm_data_size != 0) { | 251 | if (pcm_data_size != 0) { |
@@ -246,6 +257,28 @@ static void sdl_audio_callback(struct pcm_udata *udata, Uint8 *stream, int len) | |||
246 | udata->num_in *= pcm_sample_bytes; | 257 | udata->num_in *= pcm_sample_bytes; |
247 | udata->num_out *= pcm_sample_bytes; | 258 | udata->num_out *= pcm_sample_bytes; |
248 | 259 | ||
260 | |||
261 | if (new_buffer) | ||
262 | { | ||
263 | new_buffer = false; | ||
264 | pcm_play_dma_started_callback(); | ||
265 | |||
266 | if ((size_t)len > udata->num_out) | ||
267 | { | ||
268 | int delay = pcm_data_size*250 / pcm_sampr - 1; | ||
269 | |||
270 | if (delay > 0) | ||
271 | { | ||
272 | SDL_UnlockMutex(audio_lock); | ||
273 | SDL_Delay(delay); | ||
274 | SDL_LockMutex(audio_lock); | ||
275 | |||
276 | if (!pcm_is_playing()) | ||
277 | break; | ||
278 | } | ||
279 | } | ||
280 | } | ||
281 | |||
249 | pcm_data += udata->num_in; | 282 | pcm_data += udata->num_in; |
250 | pcm_data_size -= udata->num_in; | 283 | pcm_data_size -= udata->num_in; |
251 | udata->stream += udata->num_out; | 284 | udata->stream += udata->num_out; |
@@ -255,6 +288,8 @@ static void sdl_audio_callback(struct pcm_udata *udata, Uint8 *stream, int len) | |||
255 | break; | 288 | break; |
256 | } | 289 | } |
257 | } | 290 | } |
291 | |||
292 | SDL_UnlockMutex(audio_lock); | ||
258 | } | 293 | } |
259 | 294 | ||
260 | const void * pcm_play_dma_get_peak_buffer(int *count) | 295 | const void * pcm_play_dma_get_peak_buffer(int *count) |
@@ -320,6 +355,14 @@ void pcm_play_dma_init(void) | |||
320 | return; | 355 | return; |
321 | } | 356 | } |
322 | 357 | ||
358 | audio_lock = SDL_CreateMutex(); | ||
359 | |||
360 | if (!audio_lock) | ||
361 | { | ||
362 | panicf("Could not create audio_lock\n"); | ||
363 | return; | ||
364 | } | ||
365 | |||
323 | SDL_AudioSpec wanted_spec; | 366 | SDL_AudioSpec wanted_spec; |
324 | #ifdef DEBUG | 367 | #ifdef DEBUG |
325 | udata.debug = NULL; | 368 | udata.debug = NULL; |