1
0
Fork 0
forked from len0rd/rockbox

A bit of work in the pcm driver. Should be a bit more efficient, but more importantly more dependable. Stopping playback now properly recovers if playback crashed for some reason (shouldn't happen of course).

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@27698 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Thomas Martitz 2010-08-04 18:34:32 +00:00
parent c216100f84
commit bd9c0b21d6
2 changed files with 41 additions and 32 deletions

View file

@ -29,10 +29,12 @@ import android.util.Log;
public class RockboxPCM extends AudioTrack public class RockboxPCM extends AudioTrack
{ {
byte[] raw_data; byte[] raw_data;
private int buf_len;
private PCMListener l;
private void LOG(CharSequence text) private void LOG(CharSequence text)
{ {
Log.d("RockboxBootloader", (String) text); Log.d("Rockbox", (String) text);
} }
public RockboxPCM() public RockboxPCM()
@ -44,18 +46,11 @@ public class RockboxPCM extends AudioTrack
AudioFormat.ENCODING_PCM_16BIT, AudioFormat.ENCODING_PCM_16BIT,
24<<10, 24<<10,
AudioTrack.MODE_STREAM); AudioTrack.MODE_STREAM);
int buf_len = 24<<10; buf_len = 24<<10; /* in bytes */
raw_data = new byte[buf_len*2]; raw_data = new byte[buf_len]; /* in shorts */
for(int i = 0; i < raw_data.length; i++) raw_data[i] = (byte) 0x00; for(int i = 0; i < raw_data.length; i++) raw_data[i] = (byte)0;
/* fill with silence */ l = new PCMListener(buf_len);
write(raw_data, 0, raw_data.length);
if (getState() == AudioTrack.STATE_INITIALIZED)
{
if (setNotificationMarkerPosition(bytes2frames(buf_len*2)/4) != AudioTrack.SUCCESS)
LOG("setNotificationMarkerPosition Error");
setPlaybackPositionUpdateListener(new PCMListener(buf_len*2));
}
} }
int bytes2frames(int bytes) { int bytes2frames(int bytes) {
@ -70,28 +65,37 @@ public class RockboxPCM extends AudioTrack
@SuppressWarnings("unused") @SuppressWarnings("unused")
private void play_pause(boolean pause) { private void play_pause(boolean pause) {
LOG("play_pause()");
if (pause) if (pause)
{
pause(); pause();
}
else else
{ {
if (getPlayState() == AudioTrack.PLAYSTATE_STOPPED) if (getPlayState() == AudioTrack.PLAYSTATE_STOPPED)
{ {
for(int i = 0; i < raw_data.length; i++) raw_data[i] = (byte) 0x00;
LOG("Writing silence");
/* fill with silence */
write(raw_data, 0, raw_data.length);
RockboxService.startForeground(); RockboxService.startForeground();
if (getState() == AudioTrack.STATE_INITIALIZED)
{
if (setNotificationMarkerPosition(bytes2frames(buf_len)/4) != AudioTrack.SUCCESS)
LOG("setNotificationMarkerPosition Error");
else
setPlaybackPositionUpdateListener(l);
}
/* need to fill with silence before starting playback */
write(raw_data, frames2bytes(getPlaybackHeadPosition()), raw_data.length);
} }
play(); play();
} }
LOG("play_pause() return");
} }
@Override @Override
public void stop() throws IllegalStateException public void stop() throws IllegalStateException
{ {
try {
super.stop(); super.stop();
} catch (IllegalStateException e) {
throw new IllegalStateException(e);
}
RockboxService.stopForeground(); RockboxService.stopForeground();
} }
@ -115,30 +119,31 @@ public class RockboxPCM extends AudioTrack
private class PCMListener implements OnPlaybackPositionUpdateListener { private class PCMListener implements OnPlaybackPositionUpdateListener {
int max_len; int max_len;
int refill_mark;
byte[] buf; byte[] buf;
public PCMListener(int len) { public PCMListener(int len) {
max_len = len; max_len = len;
buf = new byte[len/2]; /* refill to 100% when reached the 25% */
buf = new byte[max_len*3/4];
refill_mark = max_len - buf.length;
} }
@Override @Override
public void onMarkerReached(AudioTrack track) { public void onMarkerReached(AudioTrack track) {
// push new data to the hardware // push new data to the hardware
int result = 1; RockboxPCM pcm = (RockboxPCM)track;
pcmSamplesToByteArray(buf); int result = -1;
//LOG("Trying to write " + buf.length + " bytes"); pcm.pcmSamplesToByteArray(buf);
result = track.write(buf, 0, buf.length); result = track.write(buf, 0, buf.length);
if (result > 0) if (result >= 0)
{ {
//LOG(result + " bytes written");
track.setPlaybackPositionUpdateListener(this);
track.setNotificationMarkerPosition(bytes2frames(max_len)/4);
switch(track.getPlayState()) switch(track.getPlayState())
{ {
case AudioTrack.PLAYSTATE_PLAYING: case AudioTrack.PLAYSTATE_PLAYING:
//LOG("State PLAYING");
break;
case AudioTrack.PLAYSTATE_PAUSED: case AudioTrack.PLAYSTATE_PAUSED:
LOG("State PAUSED"); /* recharge */
setPlaybackPositionUpdateListener(this);
/* refill at 25% no matter of how many bytes we've written */
setNotificationMarkerPosition(bytes2frames(refill_mark));
break; break;
case AudioTrack.PLAYSTATE_STOPPED: case AudioTrack.PLAYSTATE_STOPPED:
LOG("State STOPPED"); LOG("State STOPPED");
@ -147,8 +152,8 @@ public class RockboxPCM extends AudioTrack
} }
else else
{ {
LOG("Error in onMarkerReached"); LOG("Error in onMarkerReached (result="+result+")");
track.stop(); stop();
} }
} }

View file

@ -72,7 +72,10 @@ Java_org_rockbox_RockboxPCM_pcmSamplesToByteArray(JNIEnv *env,
retry: retry:
pcm_play_get_more_callback((void**)&pcm_data_start, &pcm_data_size); pcm_play_get_more_callback((void**)&pcm_data_start, &pcm_data_size);
if (pcm_data_size == 0) if (pcm_data_size == 0)
{
LOG("out of data\n");
return; return;
}
if (remaining > pcm_data_size) if (remaining > pcm_data_size)
{ /* got too little data, get more ... */ { /* got too little data, get more ... */
(*env)->SetByteArrayRegion(env, arr, offset, pcm_data_size, pcm_data_start); (*env)->SetByteArrayRegion(env, arr, offset, pcm_data_size, pcm_data_start);
@ -80,6 +83,7 @@ Java_org_rockbox_RockboxPCM_pcmSamplesToByteArray(JNIEnv *env,
offset += pcm_data_size; offset += pcm_data_size;
/* we copied at least a bit */ /* we copied at least a bit */
remaining -= pcm_data_size; remaining -= pcm_data_size;
pcm_data_size = 0;
/* let's get another buch of data and try again */ /* let's get another buch of data and try again */
goto retry; goto retry;
} }