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:
parent
c216100f84
commit
bd9c0b21d6
2 changed files with 41 additions and 32 deletions
|
@ -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
|
||||||
{
|
{
|
||||||
super.stop();
|
try {
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue