summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceBroker.java37
-rw-r--r--services/core/java/com/android/server/audio/BtHelper.java45
2 files changed, 73 insertions, 9 deletions
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 22b0aebca6c4..074d3fe10816 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -224,12 +224,35 @@ import java.util.concurrent.atomic.AtomicBoolean;
if (!addSpeakerphoneClient(cb, pid, on)) {
return false;
}
+ if (on) {
+ // Cancel BT SCO ON request by this same client: speakerphone and BT SCO routes
+ // are mutually exclusive.
+ // See symmetrical operation for startBluetoothScoForClient_Sync().
+ mBtHelper.stopBluetoothScoForPid(pid);
+ }
final boolean wasOn = isSpeakerphoneOn();
updateSpeakerphoneOn(eventSource);
return (wasOn != isSpeakerphoneOn());
}
}
+ /**
+ * Turns speakerphone off for a given pid and update speakerphone state.
+ * @param pid
+ */
+ @GuardedBy("mDeviceStateLock")
+ private void setSpeakerphoneOffForPid(int pid) {
+ SpeakerphoneClient client = getSpeakerphoneClientForPid(pid);
+ if (client == null) {
+ return;
+ }
+ client.unregisterDeathRecipient();
+ mSpeakerphoneClients.remove(client);
+ final String eventSource = new StringBuilder("setSpeakerphoneOffForPid(")
+ .append(pid).append(")").toString();
+ updateSpeakerphoneOn(eventSource);
+ }
+
@GuardedBy("mDeviceStateLock")
private void updateSpeakerphoneOn(String eventSource) {
if (isSpeakerphoneOnRequested()) {
@@ -488,6 +511,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
/*package*/ void startBluetoothScoForClient_Sync(IBinder cb, int scoAudioMode,
@NonNull String eventSource) {
synchronized (mDeviceStateLock) {
+ // Cancel speakerphone ON request by this same client: speakerphone and BT SCO routes
+ // are mutually exclusive.
+ // See symmetrical operation for setSpeakerphoneOn(true).
+ setSpeakerphoneOffForPid(Binder.getCallingPid());
mBtHelper.startBluetoothScoForClient(cb, scoAudioMode, eventSource);
}
}
@@ -1381,6 +1408,16 @@ import java.util.concurrent.atomic.AtomicBoolean;
return false;
}
+ @GuardedBy("mDeviceStateLock")
+ private SpeakerphoneClient getSpeakerphoneClientForPid(int pid) {
+ for (SpeakerphoneClient cl : mSpeakerphoneClients) {
+ if (cl.getPid() == pid) {
+ return cl;
+ }
+ }
+ return null;
+ }
+
// List of clients requesting speakerPhone ON
@GuardedBy("mDeviceStateLock")
private final @NonNull ArrayList<SpeakerphoneClient> mSpeakerphoneClients =
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index b4c41b274dbe..7616557ac80f 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -432,19 +432,36 @@ public class BtHelper {
// and this must be done on behalf of system server to make sure permissions are granted.
final long ident = Binder.clearCallingIdentity();
if (client != null) {
- AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(eventSource));
- client.requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED,
- SCO_MODE_VIRTUAL_CALL);
- // If a disconnection is pending, the client will be removed whne clearAllScoClients()
- // is called form receiveBtEvent()
- if (mScoAudioState != SCO_STATE_DEACTIVATE_REQ
- && mScoAudioState != SCO_STATE_DEACTIVATING) {
- client.remove(false /*stop */, true /*unregister*/);
- }
+ stopAndRemoveClient(client, eventSource);
}
Binder.restoreCallingIdentity(ident);
}
+ // @GuardedBy("AudioDeviceBroker.mSetModeLock")
+ @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+ /*package*/ synchronized void stopBluetoothScoForPid(int pid) {
+ ScoClient client = getScoClientForPid(pid);
+ if (client == null) {
+ return;
+ }
+ final String eventSource = new StringBuilder("stopBluetoothScoForPid(")
+ .append(pid).append(")").toString();
+ stopAndRemoveClient(client, eventSource);
+ }
+
+ @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+ // @GuardedBy("BtHelper.this")
+ private void stopAndRemoveClient(ScoClient client, @NonNull String eventSource) {
+ AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(eventSource));
+ client.requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED,
+ SCO_MODE_VIRTUAL_CALL);
+ // If a disconnection is pending, the client will be removed when clearAllScoClients()
+ // is called form receiveBtEvent()
+ if (mScoAudioState != SCO_STATE_DEACTIVATE_REQ
+ && mScoAudioState != SCO_STATE_DEACTIVATING) {
+ client.remove(false /*stop */, true /*unregister*/);
+ }
+ }
/*package*/ synchronized void setHearingAidVolume(int index, int streamType) {
if (mHearingAid == null) {
@@ -974,6 +991,16 @@ public class BtHelper {
return null;
}
+ @GuardedBy("BtHelper.this")
+ private ScoClient getScoClientForPid(int pid) {
+ for (ScoClient cl : mScoClients) {
+ if (cl.getPid() == pid) {
+ return cl;
+ }
+ }
+ return null;
+ }
+
// @GuardedBy("AudioDeviceBroker.mSetModeLock")
//@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
@GuardedBy("BtHelper.this")