summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--media/java/android/media/AudioManager.java14
-rw-r--r--media/java/android/media/IAudioService.aidl6
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceBroker.java160
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceInventory.java10
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java20
-rw-r--r--services/core/java/com/android/server/audio/BtHelper.java4
6 files changed, 197 insertions, 17 deletions
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index b1d2e33df3f7..4759689335e9 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -3730,7 +3730,12 @@ public class AudioManager {
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
public void setA2dpSuspended(boolean enable) {
- AudioSystem.setParameters("A2dpSuspended=" + enable);
+ final IAudioService service = getService();
+ try {
+ service.setA2dpSuspended(enable);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -3743,7 +3748,12 @@ public class AudioManager {
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
public void setLeAudioSuspended(boolean enable) {
- AudioSystem.setParameters("LeAudioSuspended=" + enable);
+ final IAudioService service = getService();
+ try {
+ service.setLeAudioSuspended(enable);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index fe5afc5a717e..7ce189ba85d5 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -231,6 +231,12 @@ interface IAudioService {
void setBluetoothScoOn(boolean on);
+ @EnforcePermission("BLUETOOTH_STACK")
+ void setA2dpSuspended(boolean on);
+
+ @EnforcePermission("BLUETOOTH_STACK")
+ void setLeAudioSuspended(boolean enable);
+
boolean isBluetoothScoOn();
void setBluetoothA2dpOn(boolean on);
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 12681565f84c..2da9fa6088db 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -204,6 +204,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
private void init() {
setupMessaging(mContext);
+ initAudioHalBluetoothState();
initRoutingStrategyIds();
mPreferredCommunicationDevice = null;
updateActiveCommunicationDevice();
@@ -845,10 +846,100 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
}
- /**
- * Current Bluetooth SCO audio active state indicated by BtHelper via setBluetoothScoOn().
- */
+ // Current Bluetooth SCO audio active state indicated by BtHelper via setBluetoothScoOn().
+ @GuardedBy("mDeviceStateLock")
private boolean mBluetoothScoOn;
+ // value of BT_SCO parameter currently applied to audio HAL.
+ @GuardedBy("mDeviceStateLock")
+ private boolean mBluetoothScoOnApplied;
+
+ // A2DP suspend state requested by AudioManager.setA2dpSuspended() API.
+ @GuardedBy("mDeviceStateLock")
+ private boolean mBluetoothA2dpSuspendedExt;
+ // A2DP suspend state requested by AudioDeviceInventory.
+ @GuardedBy("mDeviceStateLock")
+ private boolean mBluetoothA2dpSuspendedInt;
+ // value of BT_A2dpSuspendedSCO parameter currently applied to audio HAL.
+ @GuardedBy("mDeviceStateLock")
+ private boolean mBluetoothA2dpSuspendedApplied;
+
+ // LE Audio suspend state requested by AudioManager.setLeAudioSuspended() API.
+ @GuardedBy("mDeviceStateLock")
+ private boolean mBluetoothLeSuspendedExt;
+ // LE Audio suspend state requested by AudioDeviceInventory.
+ @GuardedBy("mDeviceStateLock")
+ private boolean mBluetoothLeSuspendedInt;
+ // value of LeAudioSuspended parameter currently applied to audio HAL.
+ @GuardedBy("mDeviceStateLock")
+ private boolean mBluetoothLeSuspendedApplied;
+
+ private void initAudioHalBluetoothState() {
+ mBluetoothScoOnApplied = false;
+ AudioSystem.setParameters("BT_SCO=off");
+ mBluetoothA2dpSuspendedApplied = false;
+ AudioSystem.setParameters("A2dpSuspended=false");
+ mBluetoothLeSuspendedApplied = false;
+ AudioSystem.setParameters("LeAudioSuspended=false");
+ }
+
+ @GuardedBy("mDeviceStateLock")
+ private void updateAudioHalBluetoothState() {
+ if (mBluetoothScoOn != mBluetoothScoOnApplied) {
+ if (AudioService.DEBUG_COMM_RTE) {
+ Log.v(TAG, "updateAudioHalBluetoothState() mBluetoothScoOn: "
+ + mBluetoothScoOn + ", mBluetoothScoOnApplied: " + mBluetoothScoOnApplied);
+ }
+ if (mBluetoothScoOn) {
+ if (!mBluetoothA2dpSuspendedApplied) {
+ AudioSystem.setParameters("A2dpSuspended=true");
+ mBluetoothA2dpSuspendedApplied = true;
+ }
+ if (!mBluetoothLeSuspendedApplied) {
+ AudioSystem.setParameters("LeAudioSuspended=true");
+ mBluetoothLeSuspendedApplied = true;
+ }
+ AudioSystem.setParameters("BT_SCO=on");
+ } else {
+ AudioSystem.setParameters("BT_SCO=off");
+ }
+ mBluetoothScoOnApplied = mBluetoothScoOn;
+ }
+ if (!mBluetoothScoOnApplied) {
+ if ((mBluetoothA2dpSuspendedExt || mBluetoothA2dpSuspendedInt)
+ != mBluetoothA2dpSuspendedApplied) {
+ if (AudioService.DEBUG_COMM_RTE) {
+ Log.v(TAG, "updateAudioHalBluetoothState() mBluetoothA2dpSuspendedExt: "
+ + mBluetoothA2dpSuspendedExt
+ + ", mBluetoothA2dpSuspendedInt: " + mBluetoothA2dpSuspendedInt
+ + ", mBluetoothA2dpSuspendedApplied: "
+ + mBluetoothA2dpSuspendedApplied);
+ }
+ mBluetoothA2dpSuspendedApplied =
+ mBluetoothA2dpSuspendedExt || mBluetoothA2dpSuspendedInt;
+ if (mBluetoothA2dpSuspendedApplied) {
+ AudioSystem.setParameters("A2dpSuspended=true");
+ } else {
+ AudioSystem.setParameters("A2dpSuspended=false");
+ }
+ }
+ if ((mBluetoothLeSuspendedExt || mBluetoothLeSuspendedInt)
+ != mBluetoothLeSuspendedApplied) {
+ if (AudioService.DEBUG_COMM_RTE) {
+ Log.v(TAG, "updateAudioHalBluetoothState() mBluetoothLeSuspendedExt: "
+ + mBluetoothLeSuspendedExt
+ + ", mBluetoothLeSuspendedInt: " + mBluetoothLeSuspendedInt
+ + ", mBluetoothLeSuspendedApplied: " + mBluetoothLeSuspendedApplied);
+ }
+ mBluetoothLeSuspendedApplied =
+ mBluetoothLeSuspendedExt || mBluetoothLeSuspendedInt;
+ if (mBluetoothLeSuspendedApplied) {
+ AudioSystem.setParameters("LeAudioSuspended=true");
+ } else {
+ AudioSystem.setParameters("LeAudioSuspended=false");
+ }
+ }
+ }
+ }
/*package*/ void setBluetoothScoOn(boolean on, String eventSource) {
if (AudioService.DEBUG_COMM_RTE) {
@@ -856,10 +947,67 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
synchronized (mDeviceStateLock) {
mBluetoothScoOn = on;
+ updateAudioHalBluetoothState();
postUpdateCommunicationRouteClient(eventSource);
}
}
+ /*package*/ void setA2dpSuspended(boolean enable, boolean internal, String eventSource) {
+ if (AudioService.DEBUG_COMM_RTE) {
+ Log.v(TAG, "setA2dpSuspended source: " + eventSource + ", enable: "
+ + enable + ", internal: " + internal
+ + ", mBluetoothA2dpSuspendedInt: " + mBluetoothA2dpSuspendedInt
+ + ", mBluetoothA2dpSuspendedExt: " + mBluetoothA2dpSuspendedExt);
+ }
+ synchronized (mDeviceStateLock) {
+ if (internal) {
+ mBluetoothA2dpSuspendedInt = enable;
+ } else {
+ mBluetoothA2dpSuspendedExt = enable;
+ }
+ updateAudioHalBluetoothState();
+ }
+ }
+
+ /*package*/ void clearA2dpSuspended() {
+ if (AudioService.DEBUG_COMM_RTE) {
+ Log.v(TAG, "clearA2dpSuspended");
+ }
+ synchronized (mDeviceStateLock) {
+ mBluetoothA2dpSuspendedInt = false;
+ mBluetoothA2dpSuspendedExt = false;
+ updateAudioHalBluetoothState();
+ }
+ }
+
+ /*package*/ void setLeAudioSuspended(boolean enable, boolean internal, String eventSource) {
+ if (AudioService.DEBUG_COMM_RTE) {
+ Log.v(TAG, "setLeAudioSuspended source: " + eventSource + ", enable: "
+ + enable + ", internal: " + internal
+ + ", mBluetoothLeSuspendedInt: " + mBluetoothA2dpSuspendedInt
+ + ", mBluetoothLeSuspendedExt: " + mBluetoothA2dpSuspendedExt);
+ }
+ synchronized (mDeviceStateLock) {
+ if (internal) {
+ mBluetoothLeSuspendedInt = enable;
+ } else {
+ mBluetoothLeSuspendedExt = enable;
+ }
+ updateAudioHalBluetoothState();
+ }
+ }
+
+ /*package*/ void clearLeAudioSuspended() {
+ if (AudioService.DEBUG_COMM_RTE) {
+ Log.v(TAG, "clearLeAudioSuspended");
+ }
+ synchronized (mDeviceStateLock) {
+ mBluetoothLeSuspendedInt = false;
+ mBluetoothLeSuspendedExt = false;
+ updateAudioHalBluetoothState();
+ }
+ }
+
/*package*/ AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
synchronized (mDeviceStateLock) {
return mDeviceInventory.startWatchingRoutes(observer);
@@ -1992,12 +2140,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
"updateCommunicationRoute, preferredCommunicationDevice: "
+ preferredCommunicationDevice + " eventSource: " + eventSource)));
- if (preferredCommunicationDevice == null
- || preferredCommunicationDevice.getType() != AudioDeviceInfo.TYPE_BLUETOOTH_SCO) {
- AudioSystem.setParameters("BT_SCO=off");
- } else {
- AudioSystem.setParameters("BT_SCO=on");
- }
if (preferredCommunicationDevice == null) {
AudioDeviceAttributes defaultDevice = getDefaultCommunicationDevice();
if (defaultDevice != null) {
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 43063afb4ce7..228bc87cc20b 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -1167,7 +1167,7 @@ public class AudioDeviceInventory {
}
// Reset A2DP suspend state each time a new sink is connected
- mAudioSystem.setParameters("A2dpSuspended=false");
+ mDeviceBroker.clearA2dpSuspended();
// The convention for head tracking sensors associated with A2DP devices is to
// use a UUID derived from the MAC address as follows:
@@ -1237,7 +1237,8 @@ public class AudioDeviceInventory {
private void makeA2dpDeviceUnavailableLater(String address, int delayMs) {
// prevent any activity on the A2DP audio output to avoid unwanted
// reconnection of the sink.
- mAudioSystem.setParameters("A2dpSuspended=true");
+ mDeviceBroker.setA2dpSuspended(
+ true /*enable*/, true /*internal*/, "makeA2dpDeviceUnavailableLater");
// retrieve DeviceInfo before removing device
final String deviceKey =
DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address);
@@ -1360,7 +1361,7 @@ public class AudioDeviceInventory {
}
// Reset LEA suspend state each time a new sink is connected
- mAudioSystem.setParameters("LeAudioSuspended=false");
+ mDeviceBroker.clearLeAudioSuspended();
mConnectedDevices.put(DeviceInfo.makeDeviceListKey(device, address),
new DeviceInfo(device, name, address, AudioSystem.AUDIO_FORMAT_DEFAULT));
@@ -1409,7 +1410,8 @@ public class AudioDeviceInventory {
private void makeLeAudioDeviceUnavailableLater(String address, int device, int delayMs) {
// prevent any activity on the LEA output to avoid unwanted
// reconnection of the sink.
- mAudioSystem.setParameters("LeAudioSuspended=true");
+ mDeviceBroker.setLeAudioSuspended(
+ true /*enable*/, true /*internal*/, "makeLeAudioDeviceUnavailableLater");
// the device will be made unavailable later, so consider it disconnected right away
mConnectedDevices.remove(DeviceInfo.makeDeviceListKey(device, address));
// send the delayed message to make the device unavailable later
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index ac55f28a8ab0..263ddf44a3c1 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -6376,6 +6376,26 @@ public class AudioService extends IAudioService.Stub
mDeviceBroker.setBluetoothScoOn(on, eventSource);
}
+ /** @see AudioManager#setA2dpSuspended(boolean) */
+ @android.annotation.EnforcePermission(android.Manifest.permission.BLUETOOTH_STACK)
+ public void setA2dpSuspended(boolean enable) {
+ super.setA2dpSuspended_enforcePermission();
+ final String eventSource = new StringBuilder("setA2dpSuspended(").append(enable)
+ .append(") from u/pid:").append(Binder.getCallingUid()).append("/")
+ .append(Binder.getCallingPid()).toString();
+ mDeviceBroker.setA2dpSuspended(enable, false /*internal*/, eventSource);
+ }
+
+ /** @see AudioManager#setA2dpSuspended(boolean) */
+ @android.annotation.EnforcePermission(android.Manifest.permission.BLUETOOTH_STACK)
+ public void setLeAudioSuspended(boolean enable) {
+ super.setLeAudioSuspended_enforcePermission();
+ final String eventSource = new StringBuilder("setLeAudioSuspended(").append(enable)
+ .append(") from u/pid:").append(Binder.getCallingUid()).append("/")
+ .append(Binder.getCallingPid()).toString();
+ mDeviceBroker.setLeAudioSuspended(enable, false /*internal*/, eventSource);
+ }
+
/** @see AudioManager#isBluetoothScoOn()
* Note that it doesn't report internal state, but state seen by apps (which may have
* called setBluetoothScoOn() */
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 631d7f5a170d..8c27c3ecfd87 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -492,8 +492,8 @@ public class BtHelper {
/*package*/ synchronized void resetBluetoothSco() {
mScoAudioState = SCO_STATE_INACTIVE;
broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
- AudioSystem.setParameters("A2dpSuspended=false");
- AudioSystem.setParameters("LeAudioSuspended=false");
+ mDeviceBroker.clearA2dpSuspended();
+ mDeviceBroker.clearLeAudioSuspended();
mDeviceBroker.setBluetoothScoOn(false, "resetBluetoothSco");
}