diff options
author | Eric Laurent <elaurent@google.com> | 2010-01-23 17:12:59 -0800 |
---|---|---|
committer | Eric Laurent <elaurent@google.com> | 2010-01-25 09:01:48 -0800 |
commit | 9272b4b4a44fe1f33e3030810618194f817caaec (patch) | |
tree | 0f224120f0e9b91cc9bd5b12bd44d9949acbd3cb /media/java | |
parent | ff65c8c559941cac3f64ddaf350db318f3e993bb (diff) | |
download | frameworks_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.java | 2 | ||||
-rw-r--r-- | media/java/android/media/AudioService.java | 87 | ||||
-rw-r--r-- | media/java/android/media/IAudioService.aidl | 2 |
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(); |