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 /firmware/target/hosted/android/pcm-android.c | |
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
Diffstat (limited to 'firmware/target/hosted/android/pcm-android.c')
-rw-r--r-- | firmware/target/hosted/android/pcm-android.c | 83 |
1 files changed, 34 insertions, 49 deletions
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 | } |