From bd9c0b21d6209b687be5f0006c0d9dc68aefbccf Mon Sep 17 00:00:00 2001 From: Thomas Martitz Date: Wed, 4 Aug 2010 18:34:32 +0000 Subject: [PATCH] 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 --- android/src/org/rockbox/RockboxPCM.java | 69 +++++++++++--------- firmware/target/hosted/android/pcm-android.c | 4 ++ 2 files changed, 41 insertions(+), 32 deletions(-) diff --git a/android/src/org/rockbox/RockboxPCM.java b/android/src/org/rockbox/RockboxPCM.java index f2568d8406..631d925b12 100644 --- a/android/src/org/rockbox/RockboxPCM.java +++ b/android/src/org/rockbox/RockboxPCM.java @@ -29,10 +29,12 @@ import android.util.Log; public class RockboxPCM extends AudioTrack { byte[] raw_data; + private int buf_len; + private PCMListener l; private void LOG(CharSequence text) { - Log.d("RockboxBootloader", (String) text); + Log.d("Rockbox", (String) text); } public RockboxPCM() @@ -44,18 +46,11 @@ public class RockboxPCM extends AudioTrack AudioFormat.ENCODING_PCM_16BIT, 24<<10, AudioTrack.MODE_STREAM); - int buf_len = 24<<10; + buf_len = 24<<10; /* in bytes */ - raw_data = new byte[buf_len*2]; - for(int i = 0; i < raw_data.length; i++) raw_data[i] = (byte) 0x00; - /* fill with silence */ - 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)); - } + raw_data = new byte[buf_len]; /* in shorts */ + for(int i = 0; i < raw_data.length; i++) raw_data[i] = (byte)0; + l = new PCMListener(buf_len); } int bytes2frames(int bytes) { @@ -70,28 +65,37 @@ public class RockboxPCM extends AudioTrack @SuppressWarnings("unused") private void play_pause(boolean pause) { - LOG("play_pause()"); if (pause) + { pause(); + } else { 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(); + 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(); } - LOG("play_pause() return"); } @Override public void stop() throws IllegalStateException { - super.stop(); + try { + super.stop(); + } catch (IllegalStateException e) { + throw new IllegalStateException(e); + } RockboxService.stopForeground(); } @@ -115,30 +119,31 @@ public class RockboxPCM extends AudioTrack private class PCMListener implements OnPlaybackPositionUpdateListener { int max_len; + int refill_mark; byte[] buf; public PCMListener(int 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 public void onMarkerReached(AudioTrack track) { // push new data to the hardware - int result = 1; - pcmSamplesToByteArray(buf); - //LOG("Trying to write " + buf.length + " bytes"); + RockboxPCM pcm = (RockboxPCM)track; + int result = -1; + pcm.pcmSamplesToByteArray(buf); 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()) { case AudioTrack.PLAYSTATE_PLAYING: - //LOG("State PLAYING"); - break; 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; case AudioTrack.PLAYSTATE_STOPPED: LOG("State STOPPED"); @@ -147,8 +152,8 @@ public class RockboxPCM extends AudioTrack } else { - LOG("Error in onMarkerReached"); - track.stop(); + LOG("Error in onMarkerReached (result="+result+")"); + stop(); } } diff --git a/firmware/target/hosted/android/pcm-android.c b/firmware/target/hosted/android/pcm-android.c index 8c5d2597c4..649b42d421 100644 --- a/firmware/target/hosted/android/pcm-android.c +++ b/firmware/target/hosted/android/pcm-android.c @@ -72,7 +72,10 @@ Java_org_rockbox_RockboxPCM_pcmSamplesToByteArray(JNIEnv *env, retry: pcm_play_get_more_callback((void**)&pcm_data_start, &pcm_data_size); if (pcm_data_size == 0) + { + LOG("out of data\n"); return; + } if (remaining > pcm_data_size) { /* got too little data, get more ... */ (*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; /* we copied at least a bit */ remaining -= pcm_data_size; + pcm_data_size = 0; /* let's get another buch of data and try again */ goto retry; }