diff --git a/android/src/org/rockbox/Helper/MediaButtonReceiver.java b/android/src/org/rockbox/Helper/MediaButtonReceiver.java index eebdbb9..9a7ab31 100644 --- a/android/src/org/rockbox/Helper/MediaButtonReceiver.java +++ b/android/src/org/rockbox/Helper/MediaButtonReceiver.java @@ -91,8 +91,9 @@ public class MediaButtonReceiver RockboxService s = RockboxService.get_instance(); if (s == null || !s.isRockboxRunning()) startService(context, intent); - else if (RockboxFramebuffer.buttonHandler(key.getKeyCode(), false)) - abortBroadcast(); + else + RockboxFramebuffer.buttonHandler(key.getKeyCode(), false); + abortBroadcast(); } } } diff --git a/android/src/org/rockbox/RockboxPCM.java b/android/src/org/rockbox/RockboxPCM.java index 47bc42f..d9150e7 100644 --- a/android/src/org/rockbox/RockboxPCM.java +++ b/android/src/org/rockbox/RockboxPCM.java @@ -22,7 +22,6 @@ package org.rockbox; import java.util.Arrays; - import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -37,10 +36,6 @@ import android.util.Log; public class RockboxPCM extends AudioTrack { - private byte[] raw_data; - private PCMListener l; - private HandlerThread ht; - private Handler h = null; private static final int streamtype = AudioManager.STREAM_MUSIC; private static final int samplerate = 44100; /* should be CHANNEL_OUT_STEREO in 2.0 and above */ @@ -48,16 +43,23 @@ public class RockboxPCM extends AudioTrack AudioFormat.CHANNEL_CONFIGURATION_STEREO; private static final int encoding = AudioFormat.ENCODING_PCM_16BIT; - /* 24k is plenty, but some devices may have a higher minimum */ + /* 32k is plenty, but some devices may have a higher minimum */ private static final int buf_len = - Math.max(24<<10, getMinBufferSize(samplerate, channels, encoding)); + Math.max(32<<10, 2*getMinBufferSize(samplerate, channels, encoding)); + private PCMListener l; + private HandlerThread ht; + private Handler h = null; private AudioManager audiomanager; + private RockboxService rbservice; + private byte[] raw_data; + + private int refillmark; private int maxstreamvolume; private int setstreamvolume = -1; private float minpcmvolume; + private float curpcmvolume = 0; private float pcmrange; - private RockboxService rbservice; private void LOG(CharSequence text) { @@ -71,9 +73,12 @@ public class RockboxPCM extends AudioTrack ht = new HandlerThread("audio thread", Process.THREAD_PRIORITY_URGENT_AUDIO); ht.start(); + /* getLooper() returns null if thread isn't running */ + while(!ht.isAlive()) + Thread.yield(); + h = new Handler(ht.getLooper()); raw_data = new byte[buf_len]; /* in shorts */ Arrays.fill(raw_data, (byte) 0); - l = new PCMListener(buf_len); /* find cleaner way to get context? */ rbservice = RockboxService.get_instance(); @@ -86,6 +91,9 @@ public class RockboxPCM extends AudioTrack setupVolumeHandler(); postVolume(audiomanager.getStreamVolume(streamtype)); + refillmark = buf_len / 2; + l = new PCMListener(buf_len - refillmark); + refillmark = bytes2frames(refillmark); } private native void postVolumeChangedEvent(int volume); @@ -166,35 +174,48 @@ public class RockboxPCM extends AudioTrack { if (getState() == AudioTrack.STATE_INITIALIZED) { - if (h == null) - h = new Handler(ht.getLooper()); - if (setNotificationMarkerPosition(bytes2frames(buf_len)/4) + if (setNotificationMarkerPosition(refillmark) != AudioTrack.SUCCESS) LOG("setNotificationMarkerPosition Error"); else setPlaybackPositionUpdateListener(l, h); } - /* need to fill with silence before starting playback */ - write(raw_data, frames2bytes(getPlaybackHeadPosition()), - raw_data.length); + /* need to fill with silence before starting playback */ + write(raw_data, 0, raw_data.length); } play(); } } @Override - public void stop() throws IllegalStateException + public synchronized void stop() throws IllegalStateException { + /* flush pending data, but turn the volume off so it cannot be heard. + * This is so that we don't hear old data if music is resumed very + * quickly after (e.g. when seeking). + */ + float old_vol = curpcmvolume; try { + setStereoVolume(0, 0); + flush(); super.stop(); } catch (IllegalStateException e) { throw new IllegalStateException(e); + } finally { + setStereoVolume(old_vol, old_vol); } + Intent widgetUpdate = new Intent("org.rockbox.UpdateState"); widgetUpdate.putExtra("state", "stop"); RockboxService.get_instance().sendBroadcast(widgetUpdate); RockboxService.get_instance().stopForeground(); } + + public int setStereoVolume(float leftVolume, float rightVolume) + { + curpcmvolume = leftVolume; + return super.setStereoVolume(leftVolume, rightVolume); + } private void set_volume(int volume) { @@ -228,15 +249,10 @@ public class RockboxPCM extends AudioTrack private class PCMListener implements OnPlaybackPositionUpdateListener { - private int max_len; - private int refill_mark; private byte[] buf; - public PCMListener(int len) + public PCMListener(int refill_bufsize) { - max_len = len; - /* refill to 100% when reached the 25% */ - buf = new byte[max_len*3/4]; - refill_mark = max_len - buf.length; + buf = new byte[refill_bufsize]; } public void onMarkerReached(AudioTrack track) @@ -246,34 +262,13 @@ public class RockboxPCM extends AudioTrack int result = -1; pcm.pcmSamplesToByteArray(buf); result = track.write(buf, 0, buf.length); - if (result >= 0) - { - switch(track.getPlayState()) - { - case AudioTrack.PLAYSTATE_PLAYING: - case AudioTrack.PLAYSTATE_PAUSED: - /* refill at 25% no matter of how many - * bytes we've written */ - if (setNotificationMarkerPosition( - bytes2frames(refill_mark)) - != AudioTrack.SUCCESS) - { - LOG("Error in onMarkerReached: " + - "Could not set notification marker"); - } - else /* recharge */ - setPlaybackPositionUpdateListener(this, h); - break; - case AudioTrack.PLAYSTATE_STOPPED: - LOG("State STOPPED"); - break; - } - } - else + if (result < 0) { LOG("Error in onMarkerReached (result="+result+")"); stop(); } + else /* recharge */ + setNotificationMarkerPosition(refillmark); } public void onPeriodicNotification(AudioTrack track)