diff options
Diffstat (limited to 'firmware/target/hosted/android')
-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 |