am 63733498: am 98de26e0: Merge change I8cc42c52 into eclair

Merge commit '6373349836237abffc3de8a3632234170bc1cfca' into eclair-mr2-plus-aosp

* commit '6373349836237abffc3de8a3632234170bc1cfca':
  Add some logging to detect if AsyncPlayer is lagging. Bug 2201082.
This commit is contained in:
Dave Sparks
2009-10-29 01:44:11 -07:00
committed by Android Git Automerger

View File

@@ -19,10 +19,12 @@ package android.media;
import android.content.Context; import android.content.Context;
import android.net.Uri; import android.net.Uri;
import android.os.PowerManager; import android.os.PowerManager;
import android.os.SystemClock;
import android.util.Log; import android.util.Log;
import java.io.IOException; import java.io.IOException;
import java.lang.IllegalStateException; import java.lang.IllegalStateException;
import java.util.LinkedList;
/** /**
* Plays a series of audio URIs, but does all the hard work on another thread * Plays a series of audio URIs, but does all the hard work on another thread
@@ -31,14 +33,15 @@ import java.lang.IllegalStateException;
public class AsyncPlayer { public class AsyncPlayer {
private static final int PLAY = 1; private static final int PLAY = 1;
private static final int STOP = 2; private static final int STOP = 2;
private static final boolean mDebug = false;
private static final class Command { private static final class Command {
Command next;
int code; int code;
Context context; Context context;
Uri uri; Uri uri;
boolean looping; boolean looping;
int stream; int stream;
long requestTime;
public String toString() { public String toString() {
return "{ code=" + code + " looping=" + looping + " stream=" + stream return "{ code=" + code + " looping=" + looping + " stream=" + stream
@@ -46,6 +49,36 @@ public class AsyncPlayer {
} }
} }
private LinkedList<Command> mCmdQueue = new LinkedList();
private void startSound(Command cmd) {
// Preparing can be slow, so if there is something else
// is playing, let it continue until we're done, so there
// is less of a glitch.
try {
if (mDebug) Log.d(mTag, "Starting playback");
MediaPlayer player = new MediaPlayer();
player.setAudioStreamType(cmd.stream);
player.setDataSource(cmd.context, cmd.uri);
player.setLooping(cmd.looping);
player.prepare();
player.start();
if (mPlayer != null) {
mPlayer.release();
}
mPlayer = player;
long delay = SystemClock.uptimeMillis() - cmd.requestTime;
if (delay > 1000) {
Log.w(mTag, "Notification sound delayed by " + delay + "msecs");
}
}
catch (IOException e) {
Log.w(mTag, "error loading sound for " + cmd.uri, e);
} catch (IllegalStateException e) {
Log.w(mTag, "IllegalStateException (content provider died?) " + cmd.uri, e);
}
}
private final class Thread extends java.lang.Thread { private final class Thread extends java.lang.Thread {
Thread() { Thread() {
super("AsyncPlayer-" + mTag); super("AsyncPlayer-" + mTag);
@@ -55,41 +88,23 @@ public class AsyncPlayer {
while (true) { while (true) {
Command cmd = null; Command cmd = null;
synchronized (mLock) { synchronized (mCmdQueue) {
if (mHead != null) { if (mDebug) Log.d(mTag, "RemoveFirst");
cmd = mHead; cmd = mCmdQueue.removeFirst();
mHead = cmd.next;
if (mTail == cmd) {
mTail = null;
}
}
} }
switch (cmd.code) { switch (cmd.code) {
case PLAY: case PLAY:
try { if (mDebug) Log.d(mTag, "PLAY");
// Preparing can be slow, so if there is something else startSound(cmd);
// is playing, let it continue until we're done, so there
// is less of a glitch.
MediaPlayer player = new MediaPlayer();
player.setAudioStreamType(cmd.stream);
player.setDataSource(cmd.context, cmd.uri);
player.setLooping(cmd.looping);
player.prepare();
player.start();
if (mPlayer != null) {
mPlayer.release();
}
mPlayer = player;
}
catch (IOException e) {
Log.w(mTag, "error loading sound for " + cmd.uri, e);
} catch (IllegalStateException e) {
Log.w(mTag, "IllegalStateException (content provider died?) " + cmd.uri, e);
}
break; break;
case STOP: case STOP:
if (mDebug) Log.d(mTag, "STOP");
if (mPlayer != null) { if (mPlayer != null) {
long delay = SystemClock.uptimeMillis() - cmd.requestTime;
if (delay > 1000) {
Log.w(mTag, "Notification stop delayed by " + delay + "msecs");
}
mPlayer.stop(); mPlayer.stop();
mPlayer.release(); mPlayer.release();
mPlayer = null; mPlayer = null;
@@ -99,8 +114,8 @@ public class AsyncPlayer {
break; break;
} }
synchronized (mLock) { synchronized (mCmdQueue) {
if (mHead == null) { if (mCmdQueue.size() == 0) {
// nothing left to do, quit // nothing left to do, quit
// doing this check after we're done prevents the case where they // doing this check after we're done prevents the case where they
// added it during the operation from spawning two threads and // added it during the operation from spawning two threads and
@@ -115,11 +130,8 @@ public class AsyncPlayer {
} }
private String mTag; private String mTag;
private Command mHead;
private Command mTail;
private Thread mThread; private Thread mThread;
private MediaPlayer mPlayer; private MediaPlayer mPlayer;
private Object mLock = new Object();
private PowerManager.WakeLock mWakeLock; private PowerManager.WakeLock mWakeLock;
// The current state according to the caller. Reality lags behind // The current state according to the caller. Reality lags behind
@@ -154,12 +166,13 @@ public class AsyncPlayer {
*/ */
public void play(Context context, Uri uri, boolean looping, int stream) { public void play(Context context, Uri uri, boolean looping, int stream) {
Command cmd = new Command(); Command cmd = new Command();
cmd.requestTime = SystemClock.uptimeMillis();
cmd.code = PLAY; cmd.code = PLAY;
cmd.context = context; cmd.context = context;
cmd.uri = uri; cmd.uri = uri;
cmd.looping = looping; cmd.looping = looping;
cmd.stream = stream; cmd.stream = stream;
synchronized (mLock) { synchronized (mCmdQueue) {
enqueueLocked(cmd); enqueueLocked(cmd);
mState = PLAY; mState = PLAY;
} }
@@ -170,11 +183,12 @@ public class AsyncPlayer {
* at this point. Calling this multiple times has no ill effects. * at this point. Calling this multiple times has no ill effects.
*/ */
public void stop() { public void stop() {
synchronized (mLock) { synchronized (mCmdQueue) {
// This check allows stop to be called multiple times without starting // This check allows stop to be called multiple times without starting
// a thread that ends up doing nothing. // a thread that ends up doing nothing.
if (mState != STOP) { if (mState != STOP) {
Command cmd = new Command(); Command cmd = new Command();
cmd.requestTime = SystemClock.uptimeMillis();
cmd.code = STOP; cmd.code = STOP;
enqueueLocked(cmd); enqueueLocked(cmd);
mState = STOP; mState = STOP;
@@ -183,12 +197,7 @@ public class AsyncPlayer {
} }
private void enqueueLocked(Command cmd) { private void enqueueLocked(Command cmd) {
if (mTail == null) { mCmdQueue.add(cmd);
mHead = cmd;
} else {
mTail.next = cmd;
}
mTail = cmd;
if (mThread == null) { if (mThread == null) {
acquireWakeLock(); acquireWakeLock();
mThread = new Thread(); mThread = new Thread();