summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Eric Laurent <elaurent@google.com> 2011-09-09 08:27:04 -0700
committer Android (Google) Code Review <android-gerrit@google.com> 2011-09-09 08:27:04 -0700
commitebf6478f557c20fc1c23f9537fcdc3f3c66decb4 (patch)
treec5551bed9dd3a33ecd1e13aa8e220811e83bf9ce
parentce0027532dc10bf9b25f4eeff1a7540f10fe9a26 (diff)
parent9f103de83f2d5d472960dcf1401e95b2ab57a477 (diff)
Merge "Fix issue 4673378: switching from VoIP to GSM call"
-rw-r--r--media/java/android/media/AudioService.java188
1 files changed, 108 insertions, 80 deletions
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 9d9b6eadc8ad..f5e14169c194 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -343,9 +343,8 @@ public class AudioService extends IAudioService.Stub {
readPersistedSettings();
mSettingsObserver = new SettingsObserver();
createStreamStates();
- // Call setMode() to initialize mSetModeDeathHandlers
- mMode = AudioSystem.MODE_INVALID;
- setMode(AudioSystem.MODE_NORMAL, null);
+
+ mMode = AudioSystem.MODE_NORMAL;
mMediaServerOk = true;
// Call setRingerModeInt() to apply correct mute
@@ -768,37 +767,27 @@ public class AudioService extends IAudioService.Stub {
private int mPid;
private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
- SetModeDeathHandler(IBinder cb) {
+ SetModeDeathHandler(IBinder cb, int pid) {
mCb = cb;
- mPid = Binder.getCallingPid();
+ mPid = pid;
}
public void binderDied() {
+ IBinder newModeOwner = null;
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;
- if (mode != AudioSystem.MODE_NORMAL) {
- disconnectBluetoothSco(mCb);
- }
- }
- }
- }
+ newModeOwner = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid);
}
}
+ // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
+ // SCO connections not started by the application changing the mode
+ if (newModeOwner != null) {
+ disconnectBluetoothSco(newModeOwner);
+ }
}
public int getPid() {
@@ -828,60 +817,97 @@ public class AudioService extends IAudioService.Stub {
return;
}
- synchronized (mSettingsLock) {
+ IBinder newModeOwner = null;
+ synchronized(mSetModeDeathHandlers) {
if (mode == AudioSystem.MODE_CURRENT) {
mode = mMode;
}
- if (mode != mMode) {
+ newModeOwner = setModeInt(mode, cb, Binder.getCallingPid());
+ }
+ // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
+ // SCO connections not started by the application changing the mode
+ if (newModeOwner != null) {
+ disconnectBluetoothSco(newModeOwner);
+ }
+ }
- // automatically handle audio focus for mode changes
- handleFocusForCalls(mMode, mode, cb);
+ // must be called synchronized on mSetModeDeathHandlers
+ // setModeInt() returns a non null IBInder if the audio mode was successfully set to
+ // any mode other than NORMAL.
+ IBinder setModeInt(int mode, IBinder cb, int pid) {
+ IBinder newModeOwner = null;
+ if (cb == null) {
+ Log.e(TAG, "setModeInt() called with null binder");
+ return newModeOwner;
+ }
- if (AudioSystem.setPhoneState(mode) == AudioSystem.AUDIO_STATUS_OK) {
- mMode = mode;
+ SetModeDeathHandler hdlr = null;
+ Iterator iter = mSetModeDeathHandlers.iterator();
+ while (iter.hasNext()) {
+ SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
+ if (h.getPid() == pid) {
+ hdlr = h;
+ // Remove from client list so that it is re-inserted at top of list
+ iter.remove();
+ hdlr.getBinder().unlinkToDeath(hdlr, 0);
+ break;
+ }
+ }
+ int status = AudioSystem.AUDIO_STATUS_OK;
+ do {
+ if (mode == AudioSystem.MODE_NORMAL) {
+ // get new mode from client at top the list if any
+ if (!mSetModeDeathHandlers.isEmpty()) {
+ hdlr = mSetModeDeathHandlers.get(0);
+ cb = hdlr.getBinder();
+ mode = hdlr.getMode();
+ }
+ } else {
+ if (hdlr == null) {
+ hdlr = new SetModeDeathHandler(cb, pid);
+ }
+ // 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");
+ }
- 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);
- }
+ // Last client to call setMode() is always at top of client list
+ // as required by SetModeDeathHandler.binderDied()
+ mSetModeDeathHandlers.add(0, hdlr);
+ hdlr.setMode(mode);
+ }
- // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
- // SCO connections not started by the application changing the mode
- if (mode != AudioSystem.MODE_NORMAL) {
- disconnectBluetoothSco(cb);
+ if (mode != mMode) {
+ status = AudioSystem.setPhoneState(mode);
+ if (status == AudioSystem.AUDIO_STATUS_OK) {
+ // automatically handle audio focus for mode changes
+ handleFocusForCalls(mMode, mode, cb);
+ mMode = mode;
+ } else {
+ if (hdlr != null) {
+ mSetModeDeathHandlers.remove(hdlr);
+ cb.unlinkToDeath(hdlr, 0);
}
+ // force reading new top of mSetModeDeathHandlers stack
+ mode = AudioSystem.MODE_NORMAL;
}
+ } else {
+ status = AudioSystem.AUDIO_STATUS_OK;
+ }
+ } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
+
+ if (status == AudioSystem.AUDIO_STATUS_OK) {
+ if (mode != AudioSystem.MODE_NORMAL) {
+ newModeOwner = cb;
}
int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
int index = mStreamStates[STREAM_VOLUME_ALIAS[streamType]].mIndex;
setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, true, false);
}
+ return newModeOwner;
}
/** pre-condition: oldMode != newMode */
@@ -1345,28 +1371,30 @@ public class AudioService extends IAudioService.Stub {
broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
// Accept SCO audio activation only in NORMAL audio mode or if the mode is
// currently controlled by the same client process.
- if ((AudioService.this.mMode == AudioSystem.MODE_NORMAL ||
- mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
- (mScoAudioState == SCO_STATE_INACTIVE ||
- mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
- if (mScoAudioState == SCO_STATE_INACTIVE) {
- if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
- if (mBluetoothHeadset.startScoUsingVirtualVoiceCall(
- mBluetoothHeadsetDevice)) {
- mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
- } else {
- broadcastScoConnectionState(
- AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+ synchronized(mSetModeDeathHandlers) {
+ if ((mSetModeDeathHandlers.isEmpty() ||
+ mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
+ (mScoAudioState == SCO_STATE_INACTIVE ||
+ mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
+ if (mScoAudioState == SCO_STATE_INACTIVE) {
+ if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
+ if (mBluetoothHeadset.startScoUsingVirtualVoiceCall(
+ mBluetoothHeadsetDevice)) {
+ mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
+ } else {
+ broadcastScoConnectionState(
+ AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+ }
+ } else if (getBluetoothHeadset()) {
+ mScoAudioState = SCO_STATE_ACTIVATE_REQ;
}
- } else if (getBluetoothHeadset()) {
- mScoAudioState = SCO_STATE_ACTIVATE_REQ;
+ } else {
+ mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
+ broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
}
} else {
- mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
- broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
+ broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
}
- } else {
- broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
}
} else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
(mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||