Merge "AudioService: BT dual mode support" into udc-dev
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index e73cf87..3123ee6 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -1237,6 +1237,9 @@
public static final Set<Integer> DEVICE_IN_ALL_SCO_SET;
/** @hide */
public static final Set<Integer> DEVICE_IN_ALL_USB_SET;
+ /** @hide */
+ public static final Set<Integer> DEVICE_IN_ALL_BLE_SET;
+
static {
DEVICE_IN_ALL_SET = new HashSet<>();
DEVICE_IN_ALL_SET.add(DEVICE_IN_COMMUNICATION);
@@ -1276,6 +1279,66 @@
DEVICE_IN_ALL_USB_SET.add(DEVICE_IN_USB_ACCESSORY);
DEVICE_IN_ALL_USB_SET.add(DEVICE_IN_USB_DEVICE);
DEVICE_IN_ALL_USB_SET.add(DEVICE_IN_USB_HEADSET);
+
+ DEVICE_IN_ALL_BLE_SET = new HashSet<>();
+ DEVICE_IN_ALL_BLE_SET.add(DEVICE_IN_BLE_HEADSET);
+ }
+
+ /** @hide */
+ public static boolean isBluetoothDevice(int deviceType) {
+ return isBluetoothA2dpOutDevice(deviceType)
+ || isBluetoothScoDevice(deviceType)
+ || isBluetoothLeDevice(deviceType);
+ }
+
+ /** @hide */
+ public static boolean isBluetoothOutDevice(int deviceType) {
+ return isBluetoothA2dpOutDevice(deviceType)
+ || isBluetoothScoOutDevice(deviceType)
+ || isBluetoothLeOutDevice(deviceType);
+ }
+
+ /** @hide */
+ public static boolean isBluetoothInDevice(int deviceType) {
+ return isBluetoothScoInDevice(deviceType)
+ || isBluetoothLeInDevice(deviceType);
+ }
+
+ /** @hide */
+ public static boolean isBluetoothA2dpOutDevice(int deviceType) {
+ return DEVICE_OUT_ALL_A2DP_SET.contains(deviceType);
+ }
+
+ /** @hide */
+ public static boolean isBluetoothScoOutDevice(int deviceType) {
+ return DEVICE_OUT_ALL_SCO_SET.contains(deviceType);
+ }
+
+ /** @hide */
+ public static boolean isBluetoothScoInDevice(int deviceType) {
+ return DEVICE_IN_ALL_SCO_SET.contains(deviceType);
+ }
+
+ /** @hide */
+ public static boolean isBluetoothScoDevice(int deviceType) {
+ return isBluetoothScoOutDevice(deviceType)
+ || isBluetoothScoInDevice(deviceType);
+ }
+
+ /** @hide */
+ public static boolean isBluetoothLeOutDevice(int deviceType) {
+ return DEVICE_OUT_ALL_BLE_SET.contains(deviceType);
+ }
+
+ /** @hide */
+ public static boolean isBluetoothLeInDevice(int deviceType) {
+ return DEVICE_IN_ALL_BLE_SET.contains(deviceType);
+ }
+
+ /** @hide */
+ public static boolean isBluetoothLeDevice(int deviceType) {
+ return isBluetoothLeOutDevice(deviceType)
+ || isBluetoothLeInDevice(deviceType);
}
/** @hide */
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index c879fa6..bc4e8df 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -88,14 +88,14 @@
private final @NonNull AudioSystemAdapter mAudioSystem;
/** ID for Communication strategy retrieved form audio policy manager */
- private int mCommunicationStrategyId = -1;
+ /*package*/ int mCommunicationStrategyId = -1;
/** ID for Accessibility strategy retrieved form audio policy manager */
private int mAccessibilityStrategyId = -1;
/** Active communication device reported by audio policy manager */
- private AudioDeviceInfo mActiveCommunicationDevice;
+ /*package*/ AudioDeviceInfo mActiveCommunicationDevice;
/** Last preferred device set for communication strategy */
private AudioDeviceAttributes mPreferredCommunicationDevice;
@@ -755,6 +755,19 @@
mIsLeOutput = false;
}
+ BtDeviceInfo(@NonNull BtDeviceInfo src, int state) {
+ mDevice = src.mDevice;
+ mState = state;
+ mProfile = src.mProfile;
+ mSupprNoisy = src.mSupprNoisy;
+ mVolume = src.mVolume;
+ mIsLeOutput = src.mIsLeOutput;
+ mEventSource = src.mEventSource;
+ mAudioSystemDevice = src.mAudioSystemDevice;
+ mMusicDevice = src.mMusicDevice;
+ mCodec = src.mCodec;
+ }
+
// redefine equality op so we can match messages intended for this device
@Override
public boolean equals(Object o) {
@@ -821,7 +834,7 @@
* @param info struct with the (dis)connection information
*/
/*package*/ void queueOnBluetoothActiveDeviceChanged(@NonNull BtDeviceChangedData data) {
- if (data.mInfo.getProfile() == BluetoothProfile.A2DP && data.mPreviousDevice != null
+ if (data.mPreviousDevice != null
&& data.mPreviousDevice.equals(data.mNewDevice)) {
final String name = TextUtils.emptyIfNull(data.mNewDevice.getName());
new MediaMetrics.Item(MediaMetrics.Name.AUDIO_DEVICE + MediaMetrics.SEPARATOR
@@ -830,7 +843,8 @@
.set(MediaMetrics.Property.STATUS, data.mInfo.getProfile())
.record();
synchronized (mDeviceStateLock) {
- postBluetoothA2dpDeviceConfigChange(data.mNewDevice);
+ postBluetoothDeviceConfigChange(createBtDeviceInfo(data, data.mNewDevice,
+ BluetoothProfile.STATE_CONNECTED));
}
} else {
synchronized (mDeviceStateLock) {
@@ -1064,8 +1078,8 @@
new AudioModeInfo(mode, pid, uid));
}
- /*package*/ void postBluetoothA2dpDeviceConfigChange(@NonNull BluetoothDevice device) {
- sendLMsgNoDelay(MSG_L_A2DP_DEVICE_CONFIG_CHANGE, SENDMSG_QUEUE, device);
+ /*package*/ void postBluetoothDeviceConfigChange(@NonNull BtDeviceInfo info) {
+ sendLMsgNoDelay(MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE, SENDMSG_QUEUE, info);
}
/*package*/ void startBluetoothScoForClient(IBinder cb, int pid, int scoAudioMode,
@@ -1322,6 +1336,10 @@
sendIMsgNoDelay(MSG_I_SCO_AUDIO_STATE_CHANGED, SENDMSG_QUEUE, state);
}
+ /*package*/ void postNotifyPreferredAudioProfileApplied(BluetoothDevice btDevice) {
+ sendLMsgNoDelay(MSG_L_NOTIFY_PREFERRED_AUDIOPROFILE_APPLIED, SENDMSG_QUEUE, btDevice);
+ }
+
/*package*/ static final class CommunicationDeviceInfo {
final @NonNull IBinder mCb; // Identifies the requesting client for death handler
final int mPid; // Requester process ID
@@ -1397,9 +1415,11 @@
}
}
- /*package*/ boolean handleDeviceConnection(AudioDeviceAttributes attributes, boolean connect) {
+ /*package*/ boolean handleDeviceConnection(AudioDeviceAttributes attributes,
+ boolean connect, @Nullable BluetoothDevice btDevice) {
synchronized (mDeviceStateLock) {
- return mDeviceInventory.handleDeviceConnection(attributes, connect, false /*for test*/);
+ return mDeviceInventory.handleDeviceConnection(
+ attributes, connect, false /*for test*/, btDevice);
}
}
@@ -1640,13 +1660,10 @@
(String) msg.obj, msg.arg1);
}
break;
- case MSG_L_A2DP_DEVICE_CONFIG_CHANGE:
- final BluetoothDevice btDevice = (BluetoothDevice) msg.obj;
+ case MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE:
synchronized (mDeviceStateLock) {
- final int a2dpCodec = mBtHelper.getA2dpCodec(btDevice);
- mDeviceInventory.onBluetoothA2dpDeviceConfigChange(
- new BtHelper.BluetoothA2dpDeviceInfo(btDevice, -1, a2dpCodec),
- BtHelper.EVENT_DEVICE_CONFIG_CHANGE);
+ mDeviceInventory.onBluetoothDeviceConfigChange(
+ (BtDeviceInfo) msg.obj, BtHelper.EVENT_DEVICE_CONFIG_CHANGE);
}
break;
case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
@@ -1810,6 +1827,10 @@
case MSG_IL_SET_LEAUDIO_SUSPENDED: {
setLeAudioSuspended((msg.arg1 == 1), false /*internal*/, (String) msg.obj);
} break;
+ case MSG_L_NOTIFY_PREFERRED_AUDIOPROFILE_APPLIED: {
+ final BluetoothDevice btDevice = (BluetoothDevice) msg.obj;
+ BtHelper.onNotifyPreferredAudioProfileApplied(btDevice);
+ } break;
default:
Log.wtf(TAG, "Invalid message " + msg.what);
}
@@ -1845,7 +1866,7 @@
private static final int MSG_IL_BTA2DP_TIMEOUT = 10;
// process change of A2DP device configuration, obj is BluetoothDevice
- private static final int MSG_L_A2DP_DEVICE_CONFIG_CHANGE = 11;
+ private static final int MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE = 11;
private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 12;
private static final int MSG_REPORT_NEW_ROUTES = 13;
@@ -1887,13 +1908,15 @@
private static final int MSG_IL_SET_A2DP_SUSPENDED = 50;
private static final int MSG_IL_SET_LEAUDIO_SUSPENDED = 51;
+ private static final int MSG_L_NOTIFY_PREFERRED_AUDIOPROFILE_APPLIED = 52;
+
private static boolean isMessageHandledUnderWakelock(int msgId) {
switch(msgId) {
case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:
case MSG_L_SET_BT_ACTIVE_DEVICE:
case MSG_IL_BTA2DP_TIMEOUT:
case MSG_IL_BTLEAUDIO_TIMEOUT:
- case MSG_L_A2DP_DEVICE_CONFIG_CHANGE:
+ case MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE:
case MSG_TOGGLE_HDMI:
case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT:
case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT:
@@ -1985,7 +2008,7 @@
case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:
case MSG_IL_BTA2DP_TIMEOUT:
case MSG_IL_BTLEAUDIO_TIMEOUT:
- case MSG_L_A2DP_DEVICE_CONFIG_CHANGE:
+ case MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE:
if (sLastDeviceConnectMsgTime >= time) {
// add a little delay to make sure messages are ordered as expected
time = sLastDeviceConnectMsgTime + 30;
@@ -2005,7 +2028,7 @@
static {
MESSAGES_MUTE_MUSIC = new HashSet<>();
MESSAGES_MUTE_MUSIC.add(MSG_L_SET_BT_ACTIVE_DEVICE);
- MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONFIG_CHANGE);
+ MESSAGES_MUTE_MUSIC.add(MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE);
MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT);
MESSAGES_MUTE_MUSIC.add(MSG_IIL_SET_FORCE_BT_A2DP_USE);
}
@@ -2026,7 +2049,7 @@
// Do not mute on bluetooth event if music is playing on a wired headset.
if ((message == MSG_L_SET_BT_ACTIVE_DEVICE
|| message == MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT
- || message == MSG_L_A2DP_DEVICE_CONFIG_CHANGE)
+ || message == MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE)
&& AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)
&& hasIntersection(mDeviceInventory.DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET,
mAudioService.getDeviceSetForStream(AudioSystem.STREAM_MUSIC))) {
@@ -2173,6 +2196,7 @@
mDeviceInventory.removePreferredDevicesForStrategy(mCommunicationStrategyId);
mDeviceInventory.removePreferredDevicesForStrategy(mAccessibilityStrategyId);
}
+ mDeviceInventory.applyConnectedDevicesRoles();
} else {
mDeviceInventory.setPreferredDevicesForStrategy(
mCommunicationStrategyId, Arrays.asList(preferredCommunicationDevice));
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 94d796b..773df37 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -34,11 +34,15 @@
import android.media.IStrategyNonDefaultDevicesDispatcher;
import android.media.IStrategyPreferredDevicesDispatcher;
import android.media.MediaMetrics;
+import android.media.MediaRecorder.AudioSource;
+import android.media.audiopolicy.AudioProductStrategy;
import android.media.permission.ClearCallingIdentityContext;
import android.media.permission.SafeCloseable;
import android.os.Binder;
+import android.os.Bundle;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -50,6 +54,8 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.utils.EventLogger;
+import com.google.android.collect.Sets;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -179,6 +185,8 @@
final RemoteCallbackList<ICapturePresetDevicesRoleDispatcher> mDevRoleCapturePresetDispatchers =
new RemoteCallbackList<ICapturePresetDevicesRoleDispatcher>();
+ final List<AudioProductStrategy> mStrategies;
+
/*package*/ AudioDeviceInventory(@NonNull AudioDeviceBroker broker) {
this(broker, AudioSystemAdapter.getDefaultAdapter());
}
@@ -193,8 +201,10 @@
@Nullable AudioSystemAdapter audioSystem) {
mDeviceBroker = broker;
mAudioSystem = audioSystem;
+ mStrategies = AudioProductStrategy.getAudioProductStrategies();
+ mBluetoothDualModeEnabled = SystemProperties.getBoolean(
+ "persist.bluetooth.enable_dual_mode_audio", false);
}
-
/*package*/ void setDeviceBroker(@NonNull AudioDeviceBroker broker) {
mDeviceBroker = broker;
}
@@ -211,8 +221,13 @@
int mDeviceCodecFormat;
final UUID mSensorUuid;
+ /** Disabled operating modes for this device. Use a negative logic so that by default
+ * an empty list means all modes are allowed.
+ * See BluetoothAdapter.AUDIO_MODE_DUPLEX and BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY */
+ @NonNull ArraySet<String> mDisabledModes = new ArraySet(0);
+
DeviceInfo(int deviceType, String deviceName, String deviceAddress,
- int deviceCodecFormat, UUID sensorUuid) {
+ int deviceCodecFormat, @Nullable UUID sensorUuid) {
mDeviceType = deviceType;
mDeviceName = deviceName == null ? "" : deviceName;
mDeviceAddress = deviceAddress == null ? "" : deviceAddress;
@@ -220,11 +235,31 @@
mSensorUuid = sensorUuid;
}
+ void setModeDisabled(String mode) {
+ mDisabledModes.add(mode);
+ }
+ void setModeEnabled(String mode) {
+ mDisabledModes.remove(mode);
+ }
+ boolean isModeEnabled(String mode) {
+ return !mDisabledModes.contains(mode);
+ }
+ boolean isOutputOnlyModeEnabled() {
+ return isModeEnabled(BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY);
+ }
+ boolean isDuplexModeEnabled() {
+ return isModeEnabled(BluetoothAdapter.AUDIO_MODE_DUPLEX);
+ }
+
DeviceInfo(int deviceType, String deviceName, String deviceAddress,
int deviceCodecFormat) {
this(deviceType, deviceName, deviceAddress, deviceCodecFormat, null);
}
+ DeviceInfo(int deviceType, String deviceName, String deviceAddress) {
+ this(deviceType, deviceName, deviceAddress, AudioSystem.AUDIO_FORMAT_DEFAULT);
+ }
+
@Override
public String toString() {
return "[DeviceInfo: type:0x" + Integer.toHexString(mDeviceType)
@@ -232,7 +267,8 @@
+ ") name:" + mDeviceName
+ " addr:" + mDeviceAddress
+ " codec: " + Integer.toHexString(mDeviceCodecFormat)
- + " sensorUuid: " + Objects.toString(mSensorUuid) + "]";
+ + " sensorUuid: " + Objects.toString(mSensorUuid)
+ + " disabled modes: " + mDisabledModes + "]";
}
@NonNull String getKey() {
@@ -317,6 +353,7 @@
di.mDeviceCodecFormat);
}
mAppliedStrategyRoles.clear();
+ applyConnectedDevicesRoles_l();
}
synchronized (mPreferredDevices) {
mPreferredDevices.forEach((strategy, devices) -> {
@@ -397,8 +434,7 @@
btInfo.mVolume * 10, btInfo.mAudioSystemDevice,
"onSetBtActiveDevice");
}
- makeA2dpDeviceAvailable(address, BtHelper.getName(btInfo.mDevice),
- "onSetBtActiveDevice", btInfo.mCodec);
+ makeA2dpDeviceAvailable(btInfo, "onSetBtActiveDevice");
}
break;
case BluetoothProfile.HEARING_AID:
@@ -414,10 +450,7 @@
if (switchToUnavailable) {
makeLeAudioDeviceUnavailableNow(address, btInfo.mAudioSystemDevice);
} else if (switchToAvailable) {
- makeLeAudioDeviceAvailable(address, BtHelper.getName(btInfo.mDevice),
- streamType, btInfo.mVolume == -1 ? -1 : btInfo.mVolume * 10,
- btInfo.mAudioSystemDevice,
- "onSetBtActiveDevice");
+ makeLeAudioDeviceAvailable(btInfo, streamType, "onSetBtActiveDevice");
}
break;
default: throw new IllegalArgumentException("Invalid profile "
@@ -428,30 +461,30 @@
@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
- /*package*/ void onBluetoothA2dpDeviceConfigChange(
- @NonNull BtHelper.BluetoothA2dpDeviceInfo btInfo, int event) {
+ /*package*/ void onBluetoothDeviceConfigChange(
+ @NonNull AudioDeviceBroker.BtDeviceInfo btInfo, int event) {
MediaMetrics.Item mmi = new MediaMetrics.Item(mMetricsId
- + "onBluetoothA2dpDeviceConfigChange")
- .set(MediaMetrics.Property.EVENT, BtHelper.a2dpDeviceEventToString(event));
+ + "onBluetoothDeviceConfigChange")
+ .set(MediaMetrics.Property.EVENT, BtHelper.deviceEventToString(event));
- final BluetoothDevice btDevice = btInfo.getBtDevice();
+ final BluetoothDevice btDevice = btInfo.mDevice;
if (btDevice == null) {
mmi.set(MediaMetrics.Property.EARLY_RETURN, "btDevice null").record();
return;
}
if (AudioService.DEBUG_DEVICES) {
- Log.d(TAG, "onBluetoothA2dpDeviceConfigChange btDevice=" + btDevice);
+ Log.d(TAG, "onBluetoothDeviceConfigChange btDevice=" + btDevice);
}
- int a2dpVolume = btInfo.getVolume();
- @AudioSystem.AudioFormatNativeEnumForBtCodec final int a2dpCodec = btInfo.getCodec();
+ int volume = btInfo.mVolume;
+ @AudioSystem.AudioFormatNativeEnumForBtCodec final int audioCodec = btInfo.mCodec;
String address = btDevice.getAddress();
if (!BluetoothAdapter.checkBluetoothAddress(address)) {
address = "";
}
AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
- "onBluetoothA2dpDeviceConfigChange addr=" + address
- + " event=" + BtHelper.a2dpDeviceEventToString(event)));
+ "onBluetoothDeviceConfigChange addr=" + address
+ + " event=" + BtHelper.deviceEventToString(event)));
synchronized (mDevicesLock) {
if (mDeviceBroker.hasScheduledA2dpConnection(btDevice)) {
@@ -466,53 +499,53 @@
AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address);
final DeviceInfo di = mConnectedDevices.get(key);
if (di == null) {
- Log.e(TAG, "invalid null DeviceInfo in onBluetoothA2dpDeviceConfigChange");
+ Log.e(TAG, "invalid null DeviceInfo in onBluetoothDeviceConfigChange");
mmi.set(MediaMetrics.Property.EARLY_RETURN, "null DeviceInfo").record();
return;
}
mmi.set(MediaMetrics.Property.ADDRESS, address)
.set(MediaMetrics.Property.ENCODING,
- AudioSystem.audioFormatToString(a2dpCodec))
- .set(MediaMetrics.Property.INDEX, a2dpVolume)
+ AudioSystem.audioFormatToString(audioCodec))
+ .set(MediaMetrics.Property.INDEX, volume)
.set(MediaMetrics.Property.NAME, di.mDeviceName);
- if (event == BtHelper.EVENT_ACTIVE_DEVICE_CHANGE) {
- // Device is connected
- if (a2dpVolume != -1) {
- mDeviceBroker.postSetVolumeIndexOnDevice(AudioSystem.STREAM_MUSIC,
- // convert index to internal representation in VolumeStreamState
- a2dpVolume * 10,
- AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
- "onBluetoothA2dpDeviceConfigChange");
- }
- } else if (event == BtHelper.EVENT_DEVICE_CONFIG_CHANGE) {
- if (di.mDeviceCodecFormat != a2dpCodec) {
- di.mDeviceCodecFormat = a2dpCodec;
- mConnectedDevices.replace(key, di);
- }
- }
- final int res = mAudioSystem.handleDeviceConfigChange(
- AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address,
- BtHelper.getName(btDevice), a2dpCodec);
- if (res != AudioSystem.AUDIO_STATUS_OK) {
- AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
- "APM handleDeviceConfigChange failed for A2DP device addr=" + address
- + " codec=" + AudioSystem.audioFormatToString(a2dpCodec))
- .printLog(TAG));
+ if (event == BtHelper.EVENT_DEVICE_CONFIG_CHANGE) {
+ boolean a2dpCodecChange = false;
+ if (btInfo.mProfile == BluetoothProfile.A2DP) {
+ if (di.mDeviceCodecFormat != audioCodec) {
+ di.mDeviceCodecFormat = audioCodec;
+ mConnectedDevices.replace(key, di);
+ a2dpCodecChange = true;
+ }
+ final int res = mAudioSystem.handleDeviceConfigChange(
+ btInfo.mAudioSystemDevice, address,
+ BtHelper.getName(btDevice), audioCodec);
- int musicDevice = mDeviceBroker.getDeviceForStream(AudioSystem.STREAM_MUSIC);
- // force A2DP device disconnection in case of error so that AudioService state is
- // consistent with audio policy manager state
- setBluetoothActiveDevice(new AudioDeviceBroker.BtDeviceInfo(btDevice,
- BluetoothProfile.A2DP, BluetoothProfile.STATE_DISCONNECTED,
- musicDevice, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
- } else {
- AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
- "APM handleDeviceConfigChange success for A2DP device addr=" + address
- + " codec=" + AudioSystem.audioFormatToString(a2dpCodec))
- .printLog(TAG));
+ if (res != AudioSystem.AUDIO_STATUS_OK) {
+ AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
+ "APM handleDeviceConfigChange failed for A2DP device addr="
+ + address + " codec="
+ + AudioSystem.audioFormatToString(audioCodec))
+ .printLog(TAG));
+
+ // force A2DP device disconnection in case of error so that AudioService
+ // state is consistent with audio policy manager state
+ setBluetoothActiveDevice(new AudioDeviceBroker.BtDeviceInfo(btInfo,
+ BluetoothProfile.STATE_DISCONNECTED));
+ } else {
+ AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
+ "APM handleDeviceConfigChange success for A2DP device addr="
+ + address
+ + " codec=" + AudioSystem.audioFormatToString(audioCodec))
+ .printLog(TAG));
+
+ }
+ }
+ if (!a2dpCodecChange) {
+ updateBluetoothPreferredModes_l(btDevice /*connectedDevice*/);
+ }
}
}
mmi.record();
@@ -595,7 +628,7 @@
}
if (!handleDeviceConnection(wdcs.mAttributes,
- wdcs.mState == AudioService.CONNECTION_STATE_CONNECTED, wdcs.mForTest)) {
+ wdcs.mState == AudioService.CONNECTION_STATE_CONNECTED, wdcs.mForTest, null)) {
// change of connection state failed, bailout
mmi.set(MediaMetrics.Property.EARLY_RETURN, "change of connection state failed")
.record();
@@ -1134,10 +1167,11 @@
* @param connect true if connection
* @param isForTesting if true, not calling AudioSystem for the connection as this is
* just for testing
+ * @param btDevice the corresponding Bluetooth device when relevant.
* @return false if an error was reported by AudioSystem
*/
/*package*/ boolean handleDeviceConnection(AudioDeviceAttributes attributes, boolean connect,
- boolean isForTesting) {
+ boolean isForTesting, @Nullable BluetoothDevice btDevice) {
int device = attributes.getInternalType();
String address = attributes.getAddress();
String deviceName = attributes.getName();
@@ -1152,6 +1186,7 @@
.set(MediaMetrics.Property.MODE, connect
? MediaMetrics.Value.CONNECT : MediaMetrics.Value.DISCONNECT)
.set(MediaMetrics.Property.NAME, deviceName);
+ boolean status = false;
synchronized (mDevicesLock) {
final String deviceKey = DeviceInfo.makeDeviceListKey(device, address);
if (AudioService.DEBUG_DEVICES) {
@@ -1179,25 +1214,31 @@
.record();
return false;
}
- mConnectedDevices.put(deviceKey, new DeviceInfo(
- device, deviceName, address, AudioSystem.AUDIO_FORMAT_DEFAULT));
+ mConnectedDevices.put(deviceKey, new DeviceInfo(device, deviceName, address));
mDeviceBroker.postAccessoryPlugMediaUnmute(device);
- mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.CONNECTED).record();
- return true;
+ status = true;
} else if (!connect && isConnected) {
mAudioSystem.setDeviceConnectionState(attributes,
AudioSystem.DEVICE_STATE_UNAVAILABLE, AudioSystem.AUDIO_FORMAT_DEFAULT);
// always remove even if disconnection failed
mConnectedDevices.remove(deviceKey);
- purgeDevicesRoles_l();
- mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.CONNECTED).record();
- return true;
+ status = true;
}
- Log.w(TAG, "handleDeviceConnection() failed, deviceKey=" + deviceKey
- + ", deviceSpec=" + di + ", connect=" + connect);
+ if (status) {
+ if (AudioSystem.isBluetoothScoDevice(device)) {
+ updateBluetoothPreferredModes_l(connect ? btDevice : null /*connectedDevice*/);
+ if (!connect) {
+ purgeDevicesRoles_l();
+ }
+ }
+ mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.CONNECTED).record();
+ } else {
+ Log.w(TAG, "handleDeviceConnection() failed, deviceKey=" + deviceKey
+ + ", deviceSpec=" + di + ", connect=" + connect);
+ mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.DISCONNECTED).record();
+ }
}
- mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.DISCONNECTED).record();
- return false;
+ return status;
}
@@ -1406,15 +1447,20 @@
// Internal utilities
@GuardedBy("mDevicesLock")
- private void makeA2dpDeviceAvailable(String address, String name, String eventSource,
- int a2dpCodec) {
+ private void makeA2dpDeviceAvailable(AudioDeviceBroker.BtDeviceInfo btInfo,
+ String eventSource) {
+ final String address = btInfo.mDevice.getAddress();
+ final String name = BtHelper.getName(btInfo.mDevice);
+ final int a2dpCodec = btInfo.mCodec;
+
// enable A2DP before notifying A2DP connection to avoid unnecessary processing in
// audio policy manager
mDeviceBroker.setBluetoothA2dpOnInt(true, true /*fromA2dp*/, eventSource);
// at this point there could be another A2DP device already connected in APM, but it
// doesn't matter as this new one will overwrite the previous one
- final int res = mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
- AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address, name),
+ AudioDeviceAttributes ada = new AudioDeviceAttributes(
+ AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address, name);
+ final int res = mAudioSystem.setDeviceConnectionState(ada,
AudioSystem.DEVICE_STATE_AVAILABLE, a2dpCodec);
// TODO: log in MediaMetrics once distinction between connection failure and
@@ -1436,8 +1482,7 @@
// The convention for head tracking sensors associated with A2DP devices is to
// use a UUID derived from the MAC address as follows:
// time_low = 0, time_mid = 0, time_hi = 0, clock_seq = 0, node = MAC Address
- UUID sensorUuid = UuidUtils.uuidFromAudioDeviceAttributes(
- new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
+ UUID sensorUuid = UuidUtils.uuidFromAudioDeviceAttributes(ada);
final DeviceInfo di = new DeviceInfo(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, name,
address, a2dpCodec, sensorUuid);
final String diKey = di.getKey();
@@ -1448,6 +1493,208 @@
mDeviceBroker.postAccessoryPlugMediaUnmute(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
setCurrentAudioRouteNameIfPossible(name, true /*fromA2dp*/);
+
+ updateBluetoothPreferredModes_l(btInfo.mDevice /*connectedDevice*/);
+ }
+
+ static final int[] CAPTURE_PRESETS = new int[] {AudioSource.MIC, AudioSource.CAMCORDER,
+ AudioSource.VOICE_RECOGNITION, AudioSource.VOICE_COMMUNICATION,
+ AudioSource.UNPROCESSED, AudioSource.VOICE_PERFORMANCE, AudioSource.HOTWORD};
+
+ // reflects system property persist.bluetooth.enable_dual_mode_audio
+ final boolean mBluetoothDualModeEnabled;
+ /**
+ * Goes over all connected Bluetooth devices and set the audio policy device role to DISABLED
+ * or not according to their own and other devices modes.
+ * The top priority is given to LE devices, then SCO ,then A2DP.
+ */
+ @GuardedBy("mDevicesLock")
+ private void applyConnectedDevicesRoles_l() {
+ if (!mBluetoothDualModeEnabled) {
+ return;
+ }
+ DeviceInfo leOutDevice =
+ getFirstConnectedDeviceOfTypes(AudioSystem.DEVICE_OUT_ALL_BLE_SET);
+ DeviceInfo leInDevice =
+ getFirstConnectedDeviceOfTypes(AudioSystem.DEVICE_IN_ALL_BLE_SET);
+ DeviceInfo a2dpDevice =
+ getFirstConnectedDeviceOfTypes(AudioSystem.DEVICE_OUT_ALL_A2DP_SET);
+ DeviceInfo scoOutDevice =
+ getFirstConnectedDeviceOfTypes(AudioSystem.DEVICE_OUT_ALL_SCO_SET);
+ DeviceInfo scoInDevice =
+ getFirstConnectedDeviceOfTypes(AudioSystem.DEVICE_IN_ALL_SCO_SET);
+ boolean disableA2dp = (leOutDevice != null && leOutDevice.isOutputOnlyModeEnabled());
+ boolean disableSco = (leOutDevice != null && leOutDevice.isDuplexModeEnabled())
+ || (leInDevice != null && leInDevice.isDuplexModeEnabled());
+ AudioDeviceAttributes communicationDevice =
+ mDeviceBroker.mActiveCommunicationDevice == null
+ ? null : ((mDeviceBroker.isInCommunication()
+ && mDeviceBroker.mActiveCommunicationDevice != null)
+ ? new AudioDeviceAttributes(mDeviceBroker.mActiveCommunicationDevice)
+ : null);
+
+ if (AudioService.DEBUG_DEVICES) {
+ Log.i(TAG, "applyConnectedDevicesRoles_l\n - leOutDevice: " + leOutDevice
+ + "\n - leInDevice: " + leInDevice
+ + "\n - a2dpDevice: " + a2dpDevice
+ + "\n - scoOutDevice: " + scoOutDevice
+ + "\n - scoInDevice: " + scoInDevice
+ + "\n - disableA2dp: " + disableA2dp
+ + ", disableSco: " + disableSco);
+ }
+
+ for (DeviceInfo di : mConnectedDevices.values()) {
+ if (!AudioSystem.isBluetoothDevice(di.mDeviceType)) {
+ continue;
+ }
+ AudioDeviceAttributes ada =
+ new AudioDeviceAttributes(di.mDeviceType, di.mDeviceAddress, di.mDeviceName);
+ if (AudioService.DEBUG_DEVICES) {
+ Log.i(TAG, " + checking Device: " + ada);
+ }
+ if (ada.equalTypeAddress(communicationDevice)) {
+ continue;
+ }
+
+ if (AudioSystem.isBluetoothOutDevice(di.mDeviceType)) {
+ for (AudioProductStrategy strategy : mStrategies) {
+ boolean disable = false;
+ if (strategy.getId() == mDeviceBroker.mCommunicationStrategyId) {
+ if (AudioSystem.isBluetoothScoDevice(di.mDeviceType)) {
+ disable = disableSco || !di.isDuplexModeEnabled();
+ } else if (AudioSystem.isBluetoothLeDevice(di.mDeviceType)) {
+ disable = !di.isDuplexModeEnabled();
+ }
+ } else {
+ if (AudioSystem.isBluetoothA2dpOutDevice(di.mDeviceType)) {
+ disable = disableA2dp || !di.isOutputOnlyModeEnabled();
+ } else if (AudioSystem.isBluetoothScoDevice(di.mDeviceType)) {
+ disable = disableSco || !di.isOutputOnlyModeEnabled();
+ } else if (AudioSystem.isBluetoothLeDevice(di.mDeviceType)) {
+ disable = !di.isOutputOnlyModeEnabled();
+ }
+ }
+ if (AudioService.DEBUG_DEVICES) {
+ Log.i(TAG, " - strategy: " + strategy.getId()
+ + ", disable: " + disable);
+ }
+ if (disable) {
+ addDevicesRoleForStrategy(strategy.getId(),
+ AudioSystem.DEVICE_ROLE_DISABLED, Arrays.asList(ada));
+ } else {
+ removeDevicesRoleForStrategy(strategy.getId(),
+ AudioSystem.DEVICE_ROLE_DISABLED, Arrays.asList(ada));
+ }
+ }
+ }
+ if (AudioSystem.isBluetoothInDevice(di.mDeviceType)) {
+ for (int capturePreset : CAPTURE_PRESETS) {
+ boolean disable = false;
+ if (AudioSystem.isBluetoothScoDevice(di.mDeviceType)) {
+ disable = disableSco || !di.isDuplexModeEnabled();
+ } else if (AudioSystem.isBluetoothLeDevice(di.mDeviceType)) {
+ disable = !di.isDuplexModeEnabled();
+ }
+ if (AudioService.DEBUG_DEVICES) {
+ Log.i(TAG, " - capturePreset: " + capturePreset
+ + ", disable: " + disable);
+ }
+ if (disable) {
+ addDevicesRoleForCapturePreset(capturePreset,
+ AudioSystem.DEVICE_ROLE_DISABLED, Arrays.asList(ada));
+ } else {
+ removeDevicesRoleForCapturePreset(capturePreset,
+ AudioSystem.DEVICE_ROLE_DISABLED, Arrays.asList(ada));
+ }
+ }
+ }
+ }
+ }
+
+ /* package */ void applyConnectedDevicesRoles() {
+ synchronized (mDevicesLock) {
+ applyConnectedDevicesRoles_l();
+ }
+ }
+
+ @GuardedBy("mDevicesLock")
+ int checkProfileIsConnected(int profile) {
+ switch (profile) {
+ case BluetoothProfile.HEADSET:
+ if (getFirstConnectedDeviceOfTypes(
+ AudioSystem.DEVICE_OUT_ALL_SCO_SET) != null
+ || getFirstConnectedDeviceOfTypes(
+ AudioSystem.DEVICE_IN_ALL_SCO_SET) != null) {
+ return profile;
+ }
+ break;
+ case BluetoothProfile.A2DP:
+ if (getFirstConnectedDeviceOfTypes(
+ AudioSystem.DEVICE_OUT_ALL_A2DP_SET) != null) {
+ return profile;
+ }
+ break;
+ case BluetoothProfile.LE_AUDIO:
+ case BluetoothProfile.LE_AUDIO_BROADCAST:
+ if (getFirstConnectedDeviceOfTypes(
+ AudioSystem.DEVICE_OUT_ALL_BLE_SET) != null
+ || getFirstConnectedDeviceOfTypes(
+ AudioSystem.DEVICE_IN_ALL_BLE_SET) != null) {
+ return profile;
+ }
+ break;
+ default:
+ break;
+ }
+ return 0;
+ }
+
+ @GuardedBy("mDevicesLock")
+ private void updateBluetoothPreferredModes_l(BluetoothDevice connectedDevice) {
+ if (!mBluetoothDualModeEnabled) {
+ return;
+ }
+ HashSet<String> processedAddresses = new HashSet<>(0);
+ for (DeviceInfo di : mConnectedDevices.values()) {
+ if (!AudioSystem.isBluetoothDevice(di.mDeviceType)
+ || processedAddresses.contains(di.mDeviceAddress)) {
+ continue;
+ }
+ Bundle preferredProfiles = BtHelper.getPreferredAudioProfiles(di.mDeviceAddress);
+ if (AudioService.DEBUG_DEVICES) {
+ Log.i(TAG, "updateBluetoothPreferredModes_l processing device address: "
+ + di.mDeviceAddress + ", preferredProfiles: " + preferredProfiles);
+ }
+ for (DeviceInfo di2 : mConnectedDevices.values()) {
+ if (!AudioSystem.isBluetoothDevice(di2.mDeviceType)
+ || !di.mDeviceAddress.equals(di2.mDeviceAddress)) {
+ continue;
+ }
+ int profile = BtHelper.getProfileFromType(di2.mDeviceType);
+ if (profile == 0) {
+ continue;
+ }
+ int preferredProfile = checkProfileIsConnected(
+ preferredProfiles.getInt(BluetoothAdapter.AUDIO_MODE_DUPLEX));
+ if (preferredProfile == profile || preferredProfile == 0) {
+ di2.setModeEnabled(BluetoothAdapter.AUDIO_MODE_DUPLEX);
+ } else {
+ di2.setModeDisabled(BluetoothAdapter.AUDIO_MODE_DUPLEX);
+ }
+ preferredProfile = checkProfileIsConnected(
+ preferredProfiles.getInt(BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY));
+ if (preferredProfile == profile || preferredProfile == 0) {
+ di2.setModeEnabled(BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY);
+ } else {
+ di2.setModeDisabled(BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY);
+ }
+ }
+ processedAddresses.add(di.mDeviceAddress);
+ }
+ applyConnectedDevicesRoles_l();
+ if (connectedDevice != null) {
+ mDeviceBroker.postNotifyPreferredAudioProfileApplied(connectedDevice);
+ }
}
@GuardedBy("mDevicesLock")
@@ -1495,6 +1742,7 @@
// Remove A2DP routes as well
setCurrentAudioRouteNameIfPossible(null, true /*fromA2dp*/);
mmi.record();
+ updateBluetoothPreferredModes_l(null /*connectedDevice*/);
purgeDevicesRoles_l();
}
@@ -1525,8 +1773,7 @@
AudioSystem.AUDIO_FORMAT_DEFAULT);
mConnectedDevices.put(
DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
- new DeviceInfo(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, "",
- address, AudioSystem.AUDIO_FORMAT_DEFAULT));
+ new DeviceInfo(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, "", address));
}
@GuardedBy("mDevicesLock")
@@ -1552,8 +1799,7 @@
AudioSystem.AUDIO_FORMAT_DEFAULT);
mConnectedDevices.put(
DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, address),
- new DeviceInfo(AudioSystem.DEVICE_OUT_HEARING_AID, name,
- address, AudioSystem.AUDIO_FORMAT_DEFAULT));
+ new DeviceInfo(AudioSystem.DEVICE_OUT_HEARING_AID, name, address));
mDeviceBroker.postAccessoryPlugMediaUnmute(AudioSystem.DEVICE_OUT_HEARING_AID);
mDeviceBroker.postApplyVolumeOnDevice(streamType,
AudioSystem.DEVICE_OUT_HEARING_AID, "makeHearingAidDeviceAvailable");
@@ -1591,29 +1837,56 @@
* @return true if a DEVICE_OUT_HEARING_AID is connected, false otherwise.
*/
boolean isHearingAidConnected() {
+ return getFirstConnectedDeviceOfTypes(
+ Sets.newHashSet(AudioSystem.DEVICE_OUT_HEARING_AID)) != null;
+ }
+
+ /**
+ * Returns a DeviceInfo for the first connected device matching one of the supplied types
+ */
+ private DeviceInfo getFirstConnectedDeviceOfTypes(Set<Integer> internalTypes) {
+ List<DeviceInfo> devices = getConnectedDevicesOfTypes(internalTypes);
+ return devices.isEmpty() ? null : devices.get(0);
+ }
+
+ /**
+ * Returns a list of connected devices matching one of the supplied types
+ */
+ private List<DeviceInfo> getConnectedDevicesOfTypes(Set<Integer> internalTypes) {
+ ArrayList<DeviceInfo> devices = new ArrayList<>();
synchronized (mDevicesLock) {
for (DeviceInfo di : mConnectedDevices.values()) {
- if (di.mDeviceType == AudioSystem.DEVICE_OUT_HEARING_AID) {
- return true;
+ if (internalTypes.contains(di.mDeviceType)) {
+ devices.add(di);
}
}
- return false;
}
+ return devices;
+ }
+
+ /* package */ AudioDeviceAttributes getDeviceOfType(int type) {
+ DeviceInfo di = getFirstConnectedDeviceOfTypes(Sets.newHashSet(type));
+ return di == null ? null : new AudioDeviceAttributes(
+ di.mDeviceType, di.mDeviceAddress, di.mDeviceName);
}
@GuardedBy("mDevicesLock")
- private void makeLeAudioDeviceAvailable(String address, String name, int streamType,
- int volumeIndex, int device, String eventSource) {
+ private void makeLeAudioDeviceAvailable(
+ AudioDeviceBroker.BtDeviceInfo btInfo, int streamType, String eventSource) {
+ final String address = btInfo.mDevice.getAddress();
+ final String name = BtHelper.getName(btInfo.mDevice);
+ final int volumeIndex = btInfo.mVolume == -1 ? -1 : btInfo.mVolume * 10;
+ final int device = btInfo.mAudioSystemDevice;
+
if (device != AudioSystem.DEVICE_NONE) {
/* Audio Policy sees Le Audio similar to A2DP. Let's make sure
* AUDIO_POLICY_FORCE_NO_BT_A2DP is not set
*/
mDeviceBroker.setBluetoothA2dpOnInt(true, false /*fromA2dp*/, eventSource);
- final int res = AudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
- device, address, name),
- AudioSystem.DEVICE_STATE_AVAILABLE,
- AudioSystem.AUDIO_FORMAT_DEFAULT);
+ AudioDeviceAttributes ada = new AudioDeviceAttributes(device, address, name);
+ final int res = AudioSystem.setDeviceConnectionState(ada,
+ AudioSystem.DEVICE_STATE_AVAILABLE, AudioSystem.AUDIO_FORMAT_DEFAULT);
if (res != AudioSystem.AUDIO_STATUS_OK) {
AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
"APM failed to make available LE Audio device addr=" + address
@@ -1624,12 +1897,13 @@
AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
"LE Audio device addr=" + address + " now available").printLog(TAG));
}
-
// Reset LEA suspend state each time a new sink is connected
mDeviceBroker.clearLeAudioSuspended();
+ UUID sensorUuid = UuidUtils.uuidFromAudioDeviceAttributes(ada);
mConnectedDevices.put(DeviceInfo.makeDeviceListKey(device, address),
- new DeviceInfo(device, name, address, AudioSystem.AUDIO_FORMAT_DEFAULT));
+ new DeviceInfo(device, name, address, AudioSystem.AUDIO_FORMAT_DEFAULT,
+ sensorUuid));
mDeviceBroker.postAccessoryPlugMediaUnmute(device);
setCurrentAudioRouteNameIfPossible(name, /*fromA2dp=*/false);
}
@@ -1645,6 +1919,8 @@
final int maxIndex = mDeviceBroker.getMaxVssVolumeForStream(streamType);
mDeviceBroker.postSetLeAudioVolumeIndex(leAudioVolIndex, maxIndex, streamType);
mDeviceBroker.postApplyVolumeOnDevice(streamType, device, "makeLeAudioDeviceAvailable");
+
+ updateBluetoothPreferredModes_l(btInfo.mDevice /*connectedDevice*/);
}
@GuardedBy("mDevicesLock")
@@ -1669,6 +1945,7 @@
}
setCurrentAudioRouteNameIfPossible(null, false /*fromA2dp*/);
+ updateBluetoothPreferredModes_l(null /*connectedDevice*/);
purgeDevicesRoles_l();
}
@@ -2005,18 +2282,6 @@
}
}
- /* package */ AudioDeviceAttributes getDeviceOfType(int type) {
- synchronized (mDevicesLock) {
- for (DeviceInfo di : mConnectedDevices.values()) {
- if (di.mDeviceType == type) {
- return new AudioDeviceAttributes(
- di.mDeviceType, di.mDeviceAddress, di.mDeviceName);
- }
- }
- }
- return null;
- }
-
//----------------------------------------------------------
// For tests only
@@ -2027,10 +2292,12 @@
*/
@VisibleForTesting
public boolean isA2dpDeviceConnected(@NonNull BluetoothDevice device) {
- final String key = DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
- device.getAddress());
- synchronized (mDevicesLock) {
- return (mConnectedDevices.get(key) != null);
+ for (DeviceInfo di : getConnectedDevicesOfTypes(
+ Sets.newHashSet(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP))) {
+ if (di.mDeviceAddress.equals(device.getAddress())) {
+ return true;
+ }
}
+ return false;
}
}
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 8c27c3e..e46c3cc 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -33,6 +33,7 @@
import android.media.AudioSystem;
import android.media.BluetoothProfileConnectionInfo;
import android.os.Binder;
+import android.os.Bundle;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
@@ -150,60 +151,12 @@
}
}
- //----------------------------------------------------------------------
- /*package*/ static class BluetoothA2dpDeviceInfo {
- private final @NonNull BluetoothDevice mBtDevice;
- private final int mVolume;
- private final @AudioSystem.AudioFormatNativeEnumForBtCodec int mCodec;
-
- BluetoothA2dpDeviceInfo(@NonNull BluetoothDevice btDevice) {
- this(btDevice, -1, AudioSystem.AUDIO_FORMAT_DEFAULT);
- }
-
- BluetoothA2dpDeviceInfo(@NonNull BluetoothDevice btDevice, int volume, int codec) {
- mBtDevice = btDevice;
- mVolume = volume;
- mCodec = codec;
- }
-
- public @NonNull BluetoothDevice getBtDevice() {
- return mBtDevice;
- }
-
- public int getVolume() {
- return mVolume;
- }
-
- public @AudioSystem.AudioFormatNativeEnumForBtCodec int getCodec() {
- return mCodec;
- }
-
- // redefine equality op so we can match messages intended for this device
- @Override
- public boolean equals(Object o) {
- if (o == null) {
- return false;
- }
- if (this == o) {
- return true;
- }
- if (o instanceof BluetoothA2dpDeviceInfo) {
- return mBtDevice.equals(((BluetoothA2dpDeviceInfo) o).getBtDevice());
- }
- return false;
- }
-
-
- }
-
// A2DP device events
/*package*/ static final int EVENT_DEVICE_CONFIG_CHANGE = 0;
- /*package*/ static final int EVENT_ACTIVE_DEVICE_CHANGE = 1;
- /*package*/ static String a2dpDeviceEventToString(int event) {
+ /*package*/ static String deviceEventToString(int event) {
switch (event) {
case EVENT_DEVICE_CONFIG_CHANGE: return "DEVICE_CONFIG_CHANGE";
- case EVENT_ACTIVE_DEVICE_CHANGE: return "ACTIVE_DEVICE_CHANGE";
default:
return new String("invalid event:" + event);
}
@@ -620,11 +573,12 @@
return btHeadsetDeviceToAudioDevice(mBluetoothHeadsetDevice);
}
- private AudioDeviceAttributes btHeadsetDeviceToAudioDevice(BluetoothDevice btDevice) {
+ private static AudioDeviceAttributes btHeadsetDeviceToAudioDevice(BluetoothDevice btDevice) {
if (btDevice == null) {
return new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, "");
}
String address = btDevice.getAddress();
+ String name = getName(btDevice);
if (!BluetoothAdapter.checkBluetoothAddress(address)) {
address = "";
}
@@ -646,7 +600,7 @@
+ " btClass: " + (btClass == null ? "Unknown" : btClass)
+ " nativeType: " + nativeType + " address: " + address);
}
- return new AudioDeviceAttributes(nativeType, address);
+ return new AudioDeviceAttributes(nativeType, address, name);
}
private boolean handleBtScoActiveDeviceChange(BluetoothDevice btDevice, boolean isActive) {
@@ -655,12 +609,9 @@
}
int inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
AudioDeviceAttributes audioDevice = btHeadsetDeviceToAudioDevice(btDevice);
- String btDeviceName = getName(btDevice);
boolean result = false;
if (isActive) {
- result |= mDeviceBroker.handleDeviceConnection(new AudioDeviceAttributes(
- audioDevice.getInternalType(), audioDevice.getAddress(), btDeviceName),
- isActive);
+ result |= mDeviceBroker.handleDeviceConnection(audioDevice, isActive, btDevice);
} else {
int[] outDeviceTypes = {
AudioSystem.DEVICE_OUT_BLUETOOTH_SCO,
@@ -669,14 +620,14 @@
};
for (int outDeviceType : outDeviceTypes) {
result |= mDeviceBroker.handleDeviceConnection(new AudioDeviceAttributes(
- outDeviceType, audioDevice.getAddress(), btDeviceName),
- isActive);
+ outDeviceType, audioDevice.getAddress(), audioDevice.getName()),
+ isActive, btDevice);
}
}
// handleDeviceConnection() && result to make sure the method get executed
result = mDeviceBroker.handleDeviceConnection(new AudioDeviceAttributes(
- inDevice, audioDevice.getAddress(), btDeviceName),
- isActive) && result;
+ inDevice, audioDevice.getAddress(), audioDevice.getName()),
+ isActive, btDevice) && result;
return result;
}
@@ -973,6 +924,30 @@
}
}
+ /*package */ static int getProfileFromType(int deviceType) {
+ if (AudioSystem.isBluetoothA2dpOutDevice(deviceType)) {
+ return BluetoothProfile.A2DP;
+ } else if (AudioSystem.isBluetoothScoDevice(deviceType)) {
+ return BluetoothProfile.HEADSET;
+ } else if (AudioSystem.isBluetoothLeDevice(deviceType)) {
+ return BluetoothProfile.LE_AUDIO;
+ }
+ return 0; // 0 is not a valid profile
+ }
+
+ /*package */ static Bundle getPreferredAudioProfiles(String address) {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ return adapter.getPreferredAudioProfiles(adapter.getRemoteDevice(address));
+ }
+
+ /**
+ * Notifies Bluetooth framework that new preferred audio profiles for Bluetooth devices
+ * have been applied.
+ */
+ public static void onNotifyPreferredAudioProfileApplied(BluetoothDevice btDevice) {
+ BluetoothAdapter.getDefaultAdapter().notifyActiveDeviceChangeApplied(btDevice);
+ }
+
/**
* Returns the string equivalent for the btDeviceClass class.
*/