summaryrefslogtreecommitdiffstats
path: root/media/java
diff options
context:
space:
mode:
authorEric Laurent <elaurent@google.com>2010-01-23 17:12:59 -0800
committerEric Laurent <elaurent@google.com>2010-01-25 09:01:48 -0800
commit9272b4b4a44fe1f33e3030810618194f817caaec (patch)
tree0f224120f0e9b91cc9bd5b12bd44d9949acbd3cb /media/java
parentff65c8c559941cac3f64ddaf350db318f3e993bb (diff)
downloadframeworks_base-9272b4b4a44fe1f33e3030810618194f817caaec.zip
frameworks_base-9272b4b4a44fe1f33e3030810618194f817caaec.tar.gz
frameworks_base-9272b4b4a44fe1f33e3030810618194f817caaec.tar.bz2
Fix issue 2349345: Media sound output stuck on earpiece rather than speaker.
This change fixes a problem occuring when an application (for instance a VoIP application) changes the audio mode to MODE_IN_CALL and crashes. In this case, the audio routing policy remains as if we were in call until the audio mode is changed back to MODE_NORMAL, for instance when a new call made or received and terminated. The fix consists in registering a death receipient to the binder that made the setMode() request and resetting the audio mode in case of client process crash.
Diffstat (limited to 'media/java')
-rw-r--r--media/java/android/media/AudioManager.java2
-rw-r--r--media/java/android/media/AudioService.java87
-rw-r--r--media/java/android/media/IAudioService.aidl2
3 files changed, 86 insertions, 5 deletions
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index bb16215a..c2e6142 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -797,7 +797,7 @@ public class AudioManager {
public void setMode(int mode) {
IAudioService service = getService();
try {
- service.setMode(mode);
+ service.setMode(mode, mICallBack);
} catch (RemoteException e) {
Log.e(TAG, "Dead object in setMode", e);
}
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 482fc4f..9362305 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -54,7 +54,6 @@ import java.util.Iterator;
import java.util.Map;
import java.util.Set;
-
/**
* The implementation of the volume manager service.
* <p>
@@ -231,6 +230,9 @@ public class AudioService extends IAudioService.Stub {
// Forced device usage for communications
private int mForcedUseForComm;
+ // List of binder death handlers for setMode() client processes.
+ // The last process to have called setMode() is at the top of the list.
+ private ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
///////////////////////////////////////////////////////////////////////////
// Construction
@@ -248,11 +250,13 @@ public class AudioService extends IAudioService.Stub {
mVolumePanel = new VolumePanel(context, this);
mSettingsObserver = new SettingsObserver();
- mMode = AudioSystem.MODE_NORMAL;
mForcedUseForComm = AudioSystem.FORCE_NONE;
createAudioSystemThread();
readPersistedSettings();
createStreamStates();
+ // Call setMode() to initialize mSetModeDeathHandlers
+ mMode = AudioSystem.MODE_INVALID;
+ setMode(AudioSystem.MODE_NORMAL, null);
mMediaServerOk = true;
AudioSystem.setErrorCallback(mAudioSystemCallback);
loadSoundEffects();
@@ -582,8 +586,54 @@ public class AudioService extends IAudioService.Stub {
return existingValue;
}
+ private class SetModeDeathHandler implements IBinder.DeathRecipient {
+ private IBinder mCb; // To be notified of client's death
+ private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
+
+ SetModeDeathHandler(IBinder cb) {
+ mCb = cb;
+ }
+
+ public void binderDied() {
+ synchronized(mSetModeDeathHandlers) {
+ Log.w(TAG, "setMode() client died");
+ int index = mSetModeDeathHandlers.indexOf(this);
+ if (index < 0) {
+ Log.w(TAG, "unregistered setMode() client died");
+ } else {
+ mSetModeDeathHandlers.remove(this);
+ // If dead client was a the top of client list,
+ // apply next mode in the stack
+ if (index == 0) {
+ // mSetModeDeathHandlers is never empty as the initial entry
+ // created when AudioService starts is never removed
+ SetModeDeathHandler hdlr = mSetModeDeathHandlers.get(0);
+ int mode = hdlr.getMode();
+ if (AudioService.this.mMode != mode) {
+ if (AudioSystem.setPhoneState(mode) == AudioSystem.AUDIO_STATUS_OK) {
+ AudioService.this.mMode = mode;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public void setMode(int mode) {
+ mMode = mode;
+ }
+
+ public int getMode() {
+ return mMode;
+ }
+
+ public IBinder getBinder() {
+ return mCb;
+ }
+ }
+
/** @see AudioManager#setMode(int) */
- public void setMode(int mode) {
+ public void setMode(int mode, IBinder cb) {
if (!checkAudioSettingsPermission("setMode()")) {
return;
}
@@ -599,6 +649,37 @@ public class AudioService extends IAudioService.Stub {
if (mode != mMode) {
if (AudioSystem.setPhoneState(mode) == AudioSystem.AUDIO_STATUS_OK) {
mMode = mode;
+
+ synchronized(mSetModeDeathHandlers) {
+ SetModeDeathHandler hdlr = null;
+ Iterator iter = mSetModeDeathHandlers.iterator();
+ while (iter.hasNext()) {
+ SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
+ if (h.getBinder() == cb) {
+ hdlr = h;
+ // Remove from client list so that it is re-inserted at top of list
+ iter.remove();
+ break;
+ }
+ }
+ if (hdlr == null) {
+ hdlr = new SetModeDeathHandler(cb);
+ // cb is null when setMode() is called by AudioService constructor
+ if (cb != null) {
+ // Register for client death notification
+ try {
+ cb.linkToDeath(hdlr, 0);
+ } catch (RemoteException e) {
+ // Client has died!
+ Log.w(TAG, "setMode() could not link to "+cb+" binder death");
+ }
+ }
+ }
+ // Last client to call setMode() is always at top of client list
+ // as required by SetModeDeathHandler.binderDied()
+ mSetModeDeathHandlers.add(0, hdlr);
+ hdlr.setMode(mode);
+ }
}
}
int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index d3d2d29..83581d2 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -47,7 +47,7 @@ interface IAudioService {
boolean shouldVibrate(int vibrateType);
- void setMode(int mode);
+ void setMode(int mode, IBinder cb);
int getMode();