summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Martitz <kugel@rockbox.org>2011-06-05 09:44:57 +0000
committerThomas Martitz <kugel@rockbox.org>2011-06-05 09:44:57 +0000
commitdace72166e5250e2ea0a9beb6451f5e4da9e50e2 (patch)
tree47c2e602c55908a4b3a72a43d9baf20418e69f66
parent03c12a790649c199f415f86366fc02ccee0f9004 (diff)
downloadrockbox-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.java13
-rw-r--r--firmware/target/hosted/android/pcm-android.c83
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;
36static jmethodID play_pause_method; 36static jmethodID play_pause_method;
37static jmethodID stop_method; 37static jmethodID stop_method;
38static jmethodID set_volume_method; 38static jmethodID set_volume_method;
39static jmethodID write_method;
39static jclass RockboxPCM_class; 40static jclass RockboxPCM_class;
40static jobject RockboxPCM_instance; 41static 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 **/
55JNIEXPORT void JNICALL 53JNIEXPORT jint JNICALL
56Java_org_rockbox_RockboxPCM_pcmSamplesToByteArray(JNIEnv *env, 54Java_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
100void pcm_play_lock(void) 84void pcm_play_lock(void)
@@ -120,7 +104,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
120void pcm_play_dma_stop(void) 104void 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}