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)