NotificationPlayer: release MediaPlayer on error and exception

Add a lock to synchronize changes to mPlayer in the playback
  thread and callback thread.
Refactor the exception handling CreationAndCompletionThread to
  always release the player that was set up to play the sound.
In the error and completion callbacks release the media player.

Bug: 110021815
Test: play notifications with wrong URI, verify players are released.

Change-Id: Ibbd06a64c8211dff24b4cfc5960d017721eca123
This commit is contained in:
Jean-Michel Trivi
2018-06-20 10:48:05 -07:00
parent ef6a5bf755
commit dc98489cfd

View File

@@ -86,11 +86,12 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener
// synchronized on mCompletionHandlingLock due to the Object.wait() in startSound(cmd)
mLooper = Looper.myLooper();
if (DEBUG) Log.d(mTag, "in run: new looper " + mLooper);
MediaPlayer player = null;
synchronized(this) {
AudioManager audioManager =
(AudioManager) mCmd.context.getSystemService(Context.AUDIO_SERVICE);
try {
MediaPlayer player = new MediaPlayer();
player = new MediaPlayer();
if (mCmd.attributes == null) {
mCmd.attributes = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_NOTIFICATION)
@@ -137,26 +138,26 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener
Log.e(mTag, "Exception while sleeping to sync notification playback"
+ " with ducking", e);
}
try {
player.start();
if (DEBUG) { Log.d(mTag, "player.start"); }
} catch (Exception e) {
player.start();
if (DEBUG) { Log.d(mTag, "player.start"); }
} catch (Exception e) {
if (player != null) {
player.release();
player = null;
// playing the notification didn't work, revert the focus request
abandonAudioFocusAfterError();
}
if (mPlayer != null) {
if (DEBUG) { Log.d(mTag, "mPlayer.release"); }
mPlayer.release();
}
mPlayer = player;
}
catch (Exception e) {
Log.w(mTag, "error loading sound for " + mCmd.uri, e);
// playing the notification didn't work, revert the focus request
abandonAudioFocusAfterError();
}
final MediaPlayer mp;
synchronized (mPlayerLock) {
mp = mPlayer;
mPlayer = player;
}
if (mp != null) {
if (DEBUG) { Log.d(mTag, "mPlayer.release"); }
mp.release();
}
this.notify();
}
Looper.loop();
@@ -230,14 +231,20 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener
break;
case STOP:
if (DEBUG) Log.d(mTag, "STOP");
if (mPlayer != null) {
final MediaPlayer mp;
synchronized (mPlayerLock) {
mp = mPlayer;
mPlayer = null;
}
if (mp != null) {
long delay = SystemClock.uptimeMillis() - cmd.requestTime;
if (delay > 1000) {
Log.w(mTag, "Notification stop delayed by " + delay + "msecs");
}
mPlayer.stop();
mPlayer.release();
mPlayer = null;
try {
mp.stop();
} catch (Exception e) { }
mp.release();
synchronized(mQueueAudioFocusLock) {
if (mAudioManagerWithAudioFocus != null) {
if (DEBUG) { Log.d(mTag, "in STOP: abandonning AudioFocus"); }
@@ -297,6 +304,14 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener
}
}
}
synchronized (mPlayerLock) {
if (mp == mPlayer) {
mPlayer = null;
}
}
if (mp != null) {
mp.release();
}
}
public boolean onError(MediaPlayer mp, int what, int extra) {
@@ -311,6 +326,8 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener
@GuardedBy("mCmdQueue")
private CmdThread mThread;
private final Object mPlayerLock = new Object();
@GuardedBy("mPlayerLock")
private MediaPlayer mPlayer;