diff options
author | Thomas Martitz <kugel@rockbox.org> | 2011-06-05 09:44:57 +0000 |
---|---|---|
committer | Thomas Martitz <kugel@rockbox.org> | 2011-06-05 09:44:57 +0000 |
commit | dace72166e5250e2ea0a9beb6451f5e4da9e50e2 (patch) | |
tree | 47c2e602c55908a4b3a72a43d9baf20418e69f66 | |
parent | 03c12a790649c199f415f86366fc02ccee0f9004 (diff) | |
download | rockbox-dace72166e5250e2ea0a9beb6451f5e4da9e50e2.tar.gz rockbox-dace72166e5250e2ea0a9beb6451f5e4da9e50e2.zip |
Android: Greatly simplify the pcm callback mechanism on both, the Java and the C side. Should be more reliable now (if the old wasn't already).
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29963 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | android/src/org/rockbox/RockboxPCM.java | 13 | ||||
-rw-r--r-- | firmware/target/hosted/android/pcm-android.c | 83 |
2 files changed, 41 insertions, 55 deletions
diff --git a/android/src/org/rockbox/RockboxPCM.java b/android/src/org/rockbox/RockboxPCM.java index 48178fcc92..eaccddb76a 100644 --- a/android/src/org/rockbox/RockboxPCM.java +++ b/android/src/org/rockbox/RockboxPCM.java | |||
@@ -239,14 +239,14 @@ public class RockboxPCM extends AudioTrack | |||
239 | } | 239 | } |
240 | } | 240 | } |
241 | 241 | ||
242 | public native void pcmSamplesToByteArray(byte[] dest); | 242 | public native int nativeWrite(byte[] temp, int len); |
243 | 243 | ||
244 | private class PCMListener implements OnPlaybackPositionUpdateListener | 244 | private class PCMListener implements OnPlaybackPositionUpdateListener |
245 | { | 245 | { |
246 | private byte[] buf; | 246 | byte[] pcm_data; |
247 | public PCMListener(int refill_bufsize) | 247 | public PCMListener(int _refill_bufsize) |
248 | { | 248 | { |
249 | buf = new byte[refill_bufsize]; | 249 | pcm_data = new byte[_refill_bufsize]; |
250 | } | 250 | } |
251 | 251 | ||
252 | public void onMarkerReached(AudioTrack track) | 252 | public void onMarkerReached(AudioTrack track) |
@@ -254,8 +254,7 @@ public class RockboxPCM extends AudioTrack | |||
254 | /* push new data to the hardware */ | 254 | /* push new data to the hardware */ |
255 | RockboxPCM pcm = (RockboxPCM)track; | 255 | RockboxPCM pcm = (RockboxPCM)track; |
256 | int result = -1; | 256 | int result = -1; |
257 | pcm.pcmSamplesToByteArray(buf); | 257 | result = pcm.nativeWrite(pcm_data, pcm_data.length); |
258 | result = track.write(buf, 0, buf.length); | ||
259 | if (result >= 0) | 258 | if (result >= 0) |
260 | { | 259 | { |
261 | switch(getPlayState()) | 260 | switch(getPlayState()) |
@@ -269,6 +268,8 @@ public class RockboxPCM extends AudioTrack | |||
269 | break; | 268 | break; |
270 | } | 269 | } |
271 | } | 270 | } |
271 | else /* stop on error */ | ||
272 | stop(); | ||
272 | } | 273 | } |
273 | 274 | ||
274 | public void onPeriodicNotification(AudioTrack track) | 275 | public void onPeriodicNotification(AudioTrack track) |
diff --git a/firmware/target/hosted/android/pcm-android.c b/firmware/target/hosted/android/pcm-android.c index ae8e9a296d..88792cd76f 100644 --- a/firmware/target/hosted/android/pcm-android.c +++ b/firmware/target/hosted/android/pcm-android.c | |||
@@ -36,65 +36,49 @@ static char *pcm_data_start; | |||
36 | static jmethodID play_pause_method; | 36 | static jmethodID play_pause_method; |
37 | static jmethodID stop_method; | 37 | static jmethodID stop_method; |
38 | static jmethodID set_volume_method; | 38 | static jmethodID set_volume_method; |
39 | static jmethodID write_method; | ||
39 | static jclass RockboxPCM_class; | 40 | static jclass RockboxPCM_class; |
40 | static jobject RockboxPCM_instance; | 41 | static jobject RockboxPCM_instance; |
41 | 42 | ||
42 | 43 | ||
43 | /* | 44 | /* |
44 | * transfer our raw data into a java array | 45 | * write pcm samples to the hardware. Calls AudioTrack.write directly (which |
46 | * is usually a blocking call) | ||
45 | * | 47 | * |
46 | * a bit of a monster functions, but it should cover all cases to overcome | 48 | * temp_array is not strictly needed as a parameter as we could |
47 | * the issue that the chunk size of the java layer and our pcm chunks are | 49 | * create it here, but that would result in frequent garbage collection |
48 | * differently sized | ||
49 | * | ||
50 | * afterall, it only copies the raw pcm data from pcm_data_start to | ||
51 | * the passed byte[]-array | ||
52 | * | 50 | * |
53 | * it is called from the PositionMarker callback of AudioTrack | 51 | * it is called from the PositionMarker callback of AudioTrack |
54 | **/ | 52 | **/ |
55 | JNIEXPORT void JNICALL | 53 | JNIEXPORT jint JNICALL |
56 | Java_org_rockbox_RockboxPCM_pcmSamplesToByteArray(JNIEnv *env, | 54 | Java_org_rockbox_RockboxPCM_nativeWrite(JNIEnv *env, jobject this, |
57 | jobject this, | 55 | jbyteArray temp_array, jint max_size) |
58 | jbyteArray arr) | ||
59 | { | 56 | { |
60 | (void)this; | 57 | jint left = max_size; |
61 | size_t len; | 58 | |
62 | size_t array_size = (*env)->GetArrayLength(env, arr); | 59 | if (!pcm_data_size) /* get some initial data */ |
63 | if (array_size > pcm_data_size) | 60 | pcm_play_get_more_callback((void**) &pcm_data_start, &pcm_data_size); |
64 | len = pcm_data_size; | 61 | |
65 | else | 62 | while(left > 0 && pcm_data_size) |
66 | len = array_size; | 63 | { |
67 | 64 | jint ret; | |
68 | (*env)->SetByteArrayRegion(env, arr, 0, len, pcm_data_start); | 65 | jsize transfer_size = MIN((size_t)left, pcm_data_size); |
69 | 66 | /* decrement both by the amount we're going to write */ | |
70 | if (array_size > pcm_data_size) | 67 | pcm_data_size -= transfer_size; left -= transfer_size; |
71 | { /* didn't have enough data for the array ? */ | 68 | (*env)->SetByteArrayRegion(env, temp_array, 0, |
72 | size_t remaining = array_size - pcm_data_size; | 69 | transfer_size, (jbyte*)pcm_data_start); |
73 | size_t offset = len; | 70 | |
74 | retry: | 71 | ret = (*env)->CallIntMethod(env, this, write_method, |
75 | pcm_play_get_more_callback((void**)&pcm_data_start, &pcm_data_size); | 72 | temp_array, 0, transfer_size); |
76 | if (pcm_data_size == 0) | 73 | if (ret < 0) |
77 | { | 74 | return ret; |
78 | DEBUGF("out of data\n"); | 75 | |
79 | return; | 76 | if (pcm_data_size == 0) /* need new data */ |
80 | } | 77 | pcm_play_get_more_callback((void**)&pcm_data_start, &pcm_data_size); |
81 | if (remaining > pcm_data_size) | 78 | else /* increment data pointer and feed more */ |
82 | { /* got too little data, get more ... */ | 79 | pcm_data_start += transfer_size; |
83 | (*env)->SetByteArrayRegion(env, arr, offset, pcm_data_size, pcm_data_start); | ||
84 | /* advance in the java array by the amount we copied */ | ||
85 | offset += pcm_data_size; | ||
86 | /* we copied at least a bit */ | ||
87 | remaining -= pcm_data_size; | ||
88 | pcm_data_size = 0; | ||
89 | /* let's get another buch of data and try again */ | ||
90 | goto retry; | ||
91 | } | ||
92 | else | ||
93 | (*env)->SetByteArrayRegion(env, arr, offset, remaining, pcm_data_start); | ||
94 | len = remaining; | ||
95 | } | 80 | } |
96 | pcm_data_start += len; | 81 | return max_size - left; |
97 | pcm_data_size -= len; | ||
98 | } | 82 | } |
99 | 83 | ||
100 | void pcm_play_lock(void) | 84 | void pcm_play_lock(void) |
@@ -120,7 +104,7 @@ void pcm_play_dma_start(const void *addr, size_t size) | |||
120 | void pcm_play_dma_stop(void) | 104 | void pcm_play_dma_stop(void) |
121 | { | 105 | { |
122 | /* NOTE: due to how pcm_play_get_more_callback() works, this is | 106 | /* NOTE: due to how pcm_play_get_more_callback() works, this is |
123 | * possibly called from pcmSamplesToByteArray(), i.e. another thread. | 107 | * possibly called from writeNative(), i.e. another thread. |
124 | * => We need to discover the env_ptr */ | 108 | * => We need to discover the env_ptr */ |
125 | JNIEnv* env = getJavaEnvironment(); | 109 | JNIEnv* env = getJavaEnvironment(); |
126 | (*env)->CallVoidMethod(env, | 110 | (*env)->CallVoidMethod(env, |
@@ -168,6 +152,7 @@ void pcm_play_dma_init(void) | |||
168 | play_pause_method = e->GetMethodID(env_ptr, RockboxPCM_class, "play_pause", "(Z)V"); | 152 | play_pause_method = e->GetMethodID(env_ptr, RockboxPCM_class, "play_pause", "(Z)V"); |
169 | set_volume_method = e->GetMethodID(env_ptr, RockboxPCM_class, "set_volume", "(I)V"); | 153 | set_volume_method = e->GetMethodID(env_ptr, RockboxPCM_class, "set_volume", "(I)V"); |
170 | stop_method = e->GetMethodID(env_ptr, RockboxPCM_class, "stop", "()V"); | 154 | stop_method = e->GetMethodID(env_ptr, RockboxPCM_class, "stop", "()V"); |
155 | write_method = e->GetMethodID(env_ptr, RockboxPCM_class, "write", "([BII)I"); | ||
171 | /* get initial pcm data, if any */ | 156 | /* get initial pcm data, if any */ |
172 | pcm_play_get_more_callback((void*)&pcm_data_start, &pcm_data_size); | 157 | pcm_play_get_more_callback((void*)&pcm_data_start, &pcm_data_size); |
173 | } | 158 | } |