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
This commit is contained in:
parent
03c12a7906
commit
dace72166e
|
@ -239,14 +239,14 @@ public class RockboxPCM extends AudioTrack
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public native void pcmSamplesToByteArray(byte[] dest);
|
public native int nativeWrite(byte[] temp, int len);
|
||||||
|
|
||||||
private class PCMListener implements OnPlaybackPositionUpdateListener
|
private class PCMListener implements OnPlaybackPositionUpdateListener
|
||||||
{
|
{
|
||||||
private byte[] buf;
|
byte[] pcm_data;
|
||||||
public PCMListener(int refill_bufsize)
|
public PCMListener(int _refill_bufsize)
|
||||||
{
|
{
|
||||||
buf = new byte[refill_bufsize];
|
pcm_data = new byte[_refill_bufsize];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onMarkerReached(AudioTrack track)
|
public void onMarkerReached(AudioTrack track)
|
||||||
|
@ -254,8 +254,7 @@ public class RockboxPCM extends AudioTrack
|
||||||
/* push new data to the hardware */
|
/* push new data to the hardware */
|
||||||
RockboxPCM pcm = (RockboxPCM)track;
|
RockboxPCM pcm = (RockboxPCM)track;
|
||||||
int result = -1;
|
int result = -1;
|
||||||
pcm.pcmSamplesToByteArray(buf);
|
result = pcm.nativeWrite(pcm_data, pcm_data.length);
|
||||||
result = track.write(buf, 0, buf.length);
|
|
||||||
if (result >= 0)
|
if (result >= 0)
|
||||||
{
|
{
|
||||||
switch(getPlayState())
|
switch(getPlayState())
|
||||||
|
@ -269,6 +268,8 @@ public class RockboxPCM extends AudioTrack
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else /* stop on error */
|
||||||
|
stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onPeriodicNotification(AudioTrack track)
|
public void onPeriodicNotification(AudioTrack track)
|
||||||
|
|
|
@ -36,65 +36,49 @@ static char *pcm_data_start;
|
||||||
static jmethodID play_pause_method;
|
static jmethodID play_pause_method;
|
||||||
static jmethodID stop_method;
|
static jmethodID stop_method;
|
||||||
static jmethodID set_volume_method;
|
static jmethodID set_volume_method;
|
||||||
|
static jmethodID write_method;
|
||||||
static jclass RockboxPCM_class;
|
static jclass RockboxPCM_class;
|
||||||
static jobject RockboxPCM_instance;
|
static jobject RockboxPCM_instance;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* transfer our raw data into a java array
|
* write pcm samples to the hardware. Calls AudioTrack.write directly (which
|
||||||
|
* is usually a blocking call)
|
||||||
*
|
*
|
||||||
* a bit of a monster functions, but it should cover all cases to overcome
|
* temp_array is not strictly needed as a parameter as we could
|
||||||
* the issue that the chunk size of the java layer and our pcm chunks are
|
* create it here, but that would result in frequent garbage collection
|
||||||
* differently sized
|
|
||||||
*
|
|
||||||
* afterall, it only copies the raw pcm data from pcm_data_start to
|
|
||||||
* the passed byte[]-array
|
|
||||||
*
|
*
|
||||||
* it is called from the PositionMarker callback of AudioTrack
|
* it is called from the PositionMarker callback of AudioTrack
|
||||||
**/
|
**/
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT jint JNICALL
|
||||||
Java_org_rockbox_RockboxPCM_pcmSamplesToByteArray(JNIEnv *env,
|
Java_org_rockbox_RockboxPCM_nativeWrite(JNIEnv *env, jobject this,
|
||||||
jobject this,
|
jbyteArray temp_array, jint max_size)
|
||||||
jbyteArray arr)
|
|
||||||
{
|
{
|
||||||
(void)this;
|
jint left = max_size;
|
||||||
size_t len;
|
|
||||||
size_t array_size = (*env)->GetArrayLength(env, arr);
|
|
||||||
if (array_size > pcm_data_size)
|
|
||||||
len = pcm_data_size;
|
|
||||||
else
|
|
||||||
len = array_size;
|
|
||||||
|
|
||||||
(*env)->SetByteArrayRegion(env, arr, 0, len, pcm_data_start);
|
if (!pcm_data_size) /* get some initial data */
|
||||||
|
pcm_play_get_more_callback((void**) &pcm_data_start, &pcm_data_size);
|
||||||
|
|
||||||
if (array_size > pcm_data_size)
|
while(left > 0 && pcm_data_size)
|
||||||
{ /* didn't have enough data for the array ? */
|
{
|
||||||
size_t remaining = array_size - pcm_data_size;
|
jint ret;
|
||||||
size_t offset = len;
|
jsize transfer_size = MIN((size_t)left, pcm_data_size);
|
||||||
retry:
|
/* decrement both by the amount we're going to write */
|
||||||
pcm_play_get_more_callback((void**)&pcm_data_start, &pcm_data_size);
|
pcm_data_size -= transfer_size; left -= transfer_size;
|
||||||
if (pcm_data_size == 0)
|
(*env)->SetByteArrayRegion(env, temp_array, 0,
|
||||||
{
|
transfer_size, (jbyte*)pcm_data_start);
|
||||||
DEBUGF("out of data\n");
|
|
||||||
return;
|
ret = (*env)->CallIntMethod(env, this, write_method,
|
||||||
}
|
temp_array, 0, transfer_size);
|
||||||
if (remaining > pcm_data_size)
|
if (ret < 0)
|
||||||
{ /* got too little data, get more ... */
|
return ret;
|
||||||
(*env)->SetByteArrayRegion(env, arr, offset, pcm_data_size, pcm_data_start);
|
|
||||||
/* advance in the java array by the amount we copied */
|
if (pcm_data_size == 0) /* need new data */
|
||||||
offset += pcm_data_size;
|
pcm_play_get_more_callback((void**)&pcm_data_start, &pcm_data_size);
|
||||||
/* we copied at least a bit */
|
else /* increment data pointer and feed more */
|
||||||
remaining -= pcm_data_size;
|
pcm_data_start += transfer_size;
|
||||||
pcm_data_size = 0;
|
|
||||||
/* let's get another buch of data and try again */
|
|
||||||
goto retry;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
(*env)->SetByteArrayRegion(env, arr, offset, remaining, pcm_data_start);
|
|
||||||
len = remaining;
|
|
||||||
}
|
}
|
||||||
pcm_data_start += len;
|
return max_size - left;
|
||||||
pcm_data_size -= len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_lock(void)
|
void pcm_play_lock(void)
|
||||||
|
@ -120,7 +104,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
|
||||||
void pcm_play_dma_stop(void)
|
void pcm_play_dma_stop(void)
|
||||||
{
|
{
|
||||||
/* NOTE: due to how pcm_play_get_more_callback() works, this is
|
/* NOTE: due to how pcm_play_get_more_callback() works, this is
|
||||||
* possibly called from pcmSamplesToByteArray(), i.e. another thread.
|
* possibly called from writeNative(), i.e. another thread.
|
||||||
* => We need to discover the env_ptr */
|
* => We need to discover the env_ptr */
|
||||||
JNIEnv* env = getJavaEnvironment();
|
JNIEnv* env = getJavaEnvironment();
|
||||||
(*env)->CallVoidMethod(env,
|
(*env)->CallVoidMethod(env,
|
||||||
|
@ -168,6 +152,7 @@ void pcm_play_dma_init(void)
|
||||||
play_pause_method = e->GetMethodID(env_ptr, RockboxPCM_class, "play_pause", "(Z)V");
|
play_pause_method = e->GetMethodID(env_ptr, RockboxPCM_class, "play_pause", "(Z)V");
|
||||||
set_volume_method = e->GetMethodID(env_ptr, RockboxPCM_class, "set_volume", "(I)V");
|
set_volume_method = e->GetMethodID(env_ptr, RockboxPCM_class, "set_volume", "(I)V");
|
||||||
stop_method = e->GetMethodID(env_ptr, RockboxPCM_class, "stop", "()V");
|
stop_method = e->GetMethodID(env_ptr, RockboxPCM_class, "stop", "()V");
|
||||||
|
write_method = e->GetMethodID(env_ptr, RockboxPCM_class, "write", "([BII)I");
|
||||||
/* get initial pcm data, if any */
|
/* get initial pcm data, if any */
|
||||||
pcm_play_get_more_callback((void*)&pcm_data_start, &pcm_data_size);
|
pcm_play_get_more_callback((void*)&pcm_data_start, &pcm_data_size);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue