Audio: use preferred device for strategy for communication route

Replaced use of forced usage for communication by set preferred device
for strategy to control communication route in audio policy manager.

Also do not use forced usage for record which was redundant with forced
usage for communication.

Bug: 161358428
Test: audio smoke tests

Change-Id: I665257fc5903b663096104b0424781d9799635a5
This commit is contained in:
Eric Laurent
2020-11-24 10:16:45 +01:00
parent 202c7f6472
commit c78b49af77
7 changed files with 164 additions and 75 deletions

View File

@@ -298,20 +298,25 @@ static sp<JNIAudioPortCallback> setJniCallback(JNIEnv* env,
return old; return old;
} }
#define check_AudioSystem_Command(status) _check_AudioSystem_Command(__func__, (status)) #define check_AudioSystem_Command(...) _check_AudioSystem_Command(__func__, __VA_ARGS__)
static int _check_AudioSystem_Command(const char* caller, status_t status) static int _check_AudioSystem_Command(const char *caller, status_t status,
{ std::vector<status_t> ignoredErrors = {}) {
ALOGE_IF(status, "Command failed for %s: %d", caller, status); int jniStatus = kAudioStatusOk;
switch (status) { switch (status) {
case DEAD_OBJECT: case DEAD_OBJECT:
return kAudioStatusMediaServerDied; jniStatus = kAudioStatusMediaServerDied;
break;
case NO_ERROR: case NO_ERROR:
return kAudioStatusOk; break;
default: default:
if (std::find(begin(ignoredErrors), end(ignoredErrors), status) == end(ignoredErrors)) {
jniStatus = kAudioStatusError;
}
break; break;
} }
return kAudioStatusError; ALOGE_IF(jniStatus != kAudioStatusOk, "Command failed for %s: %d", caller, status);
return jniStatus;
} }
static jint getVectorOfAudioDeviceTypeAddr(JNIEnv *env, jintArray deviceTypes, static jint getVectorOfAudioDeviceTypeAddr(JNIEnv *env, jintArray deviceTypes,
@@ -2350,9 +2355,12 @@ static jint android_media_AudioSystem_setDevicesRoleForStrategy(JNIEnv *env, job
static jint android_media_AudioSystem_removeDevicesRoleForStrategy(JNIEnv *env, jobject thiz, static jint android_media_AudioSystem_removeDevicesRoleForStrategy(JNIEnv *env, jobject thiz,
jint strategy, jint role) { jint strategy, jint role) {
return (jint)check_AudioSystem_Command( return (jint)
AudioSystem::removeDevicesRoleForStrategy((product_strategy_t)strategy, check_AudioSystem_Command(AudioSystem::removeDevicesRoleForStrategy((product_strategy_t)
(device_role_t)role)); strategy,
(device_role_t)
role),
{NAME_NOT_FOUND});
} }
static jint android_media_AudioSystem_getDevicesForRoleAndStrategy(JNIEnv *env, jobject thiz, static jint android_media_AudioSystem_getDevicesForRoleAndStrategy(JNIEnv *env, jobject thiz,

View File

@@ -120,7 +120,13 @@ public final class AudioDeviceAttributes implements Parcelable {
mAddress = address; mAddress = address;
} }
/*package*/ AudioDeviceAttributes(int nativeType, @NonNull String address) { /**
* @hide
* Constructor from internal device type and address
* @param type the internal device type, as defined in {@link AudioSystem}
* @param address the address of the device, or an empty string for devices without one
*/
public AudioDeviceAttributes(int nativeType, @NonNull String address) {
mRole = (nativeType & AudioSystem.DEVICE_BIT_IN) != 0 ? ROLE_INPUT : ROLE_OUTPUT; mRole = (nativeType & AudioSystem.DEVICE_BIT_IN) != 0 ? ROLE_INPUT : ROLE_OUTPUT;
mType = AudioDeviceInfo.convertInternalDeviceToDeviceType(nativeType); mType = AudioDeviceInfo.convertInternalDeviceToDeviceType(nativeType);
mAddress = address; mAddress = address;
@@ -191,10 +197,8 @@ public final class AudioDeviceAttributes implements Parcelable {
public String toString() { public String toString() {
return new String("AudioDeviceAttributes:" return new String("AudioDeviceAttributes:"
+ " role:" + roleToString(mRole) + " role:" + roleToString(mRole)
+ " type:" + (mRole == ROLE_OUTPUT ? AudioSystem.getOutputDeviceName( + " type:" + (mRole == ROLE_OUTPUT ? AudioSystem.getOutputDeviceName(mNativeType)
AudioDeviceInfo.convertDeviceTypeToInternalDevice(mType)) : AudioSystem.getInputDeviceName(mNativeType))
: AudioSystem.getInputDeviceName(
AudioDeviceInfo.convertDeviceTypeToInternalDevice(mType)))
+ " addr:" + mAddress); + " addr:" + mAddress);
} }

View File

@@ -1730,7 +1730,7 @@ public class AudioSystem
int[] types = new int[devices.size()]; int[] types = new int[devices.size()];
String[] addresses = new String[devices.size()]; String[] addresses = new String[devices.size()];
for (int i = 0; i < devices.size(); ++i) { for (int i = 0; i < devices.size(); ++i) {
types[i] = AudioDeviceInfo.convertDeviceTypeToInternalDevice(devices.get(i).getType()); types[i] = devices.get(i).getInternalType();
addresses[i] = devices.get(i).getAddress(); addresses[i] = devices.get(i).getAddress();
} }
return setDevicesRoleForStrategy(strategy, role, types, addresses); return setDevicesRoleForStrategy(strategy, role, types, addresses);

View File

@@ -16,6 +16,7 @@
package com.android.server.audio; package com.android.server.audio;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable;
import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothHeadset;
@@ -34,6 +35,7 @@ import android.media.ICapturePresetDevicesRoleDispatcher;
import android.media.ICommunicationDeviceDispatcher; import android.media.ICommunicationDeviceDispatcher;
import android.media.IStrategyPreferredDevicesDispatcher; import android.media.IStrategyPreferredDevicesDispatcher;
import android.media.MediaMetrics; import android.media.MediaMetrics;
import android.media.audiopolicy.AudioProductStrategy;
import android.os.Binder; import android.os.Binder;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
@@ -51,6 +53,7 @@ import android.util.PrintWriterPrinter;
import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@@ -77,7 +80,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
private final @NonNull Context mContext; private final @NonNull Context mContext;
/** Forced device usage for communications sent to AudioSystem */ /** Forced device usage for communications sent to AudioSystem */
private int mForcedUseForComm; private AudioDeviceAttributes mPreferredDeviceforComm;
private int mCommunicationStrategyId = -1;
// Manages all connected devices, only ever accessed on the message loop // Manages all connected devices, only ever accessed on the message loop
private final AudioDeviceInventory mDeviceInventory; private final AudioDeviceInventory mDeviceInventory;
@@ -133,10 +137,23 @@ import java.util.concurrent.atomic.AtomicBoolean;
init(); init();
} }
private void initCommunicationStrategyId() {
List<AudioProductStrategy> strategies = AudioProductStrategy.getAudioProductStrategies();
for (AudioProductStrategy strategy : strategies) {
if (strategy.getAudioAttributesForLegacyStreamType(AudioSystem.STREAM_VOICE_CALL)
!= null) {
mCommunicationStrategyId = strategy.getId();
return;
}
}
mCommunicationStrategyId = -1;
}
private void init() { private void init() {
setupMessaging(mContext); setupMessaging(mContext);
mForcedUseForComm = AudioSystem.FORCE_NONE; mPreferredDeviceforComm = null;
initCommunicationStrategyId();
} }
/*package*/ Context getContext() { /*package*/ Context getContext() {
@@ -221,8 +238,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
synchronized (mDeviceStateLock) { synchronized (mDeviceStateLock) {
AudioDeviceAttributes device = null; AudioDeviceAttributes device = null;
if (on) { if (on) {
device = new AudioDeviceAttributes(AudioDeviceAttributes.ROLE_OUTPUT, device = new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_SPEAKER, "");
AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, "");
} else { } else {
CommunicationRouteClient client = getCommunicationRouteClientForPid(pid); CommunicationRouteClient client = getCommunicationRouteClientForPid(pid);
if (client == null || !client.requestsSpeakerphone()) { if (client == null || !client.requestsSpeakerphone()) {
@@ -275,6 +291,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
if (AudioService.DEBUG_COMM_RTE) { if (AudioService.DEBUG_COMM_RTE) {
Log.v(TAG, "setCommunicationRouteForClient: device: " + device); Log.v(TAG, "setCommunicationRouteForClient: device: " + device);
} }
AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
"setCommunicationRouteForClient for pid: " + pid
+ " device: " + device
+ " from API: " + eventSource)).printLog(TAG));
final boolean wasBtScoRequested = isBluetoothScoRequested(); final boolean wasBtScoRequested = isBluetoothScoRequested();
final boolean wasSpeakerphoneRequested = isSpeakerphoneRequested(); final boolean wasSpeakerphoneRequested = isSpeakerphoneRequested();
@@ -393,7 +413,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
* @return true if speakerphone is active, false otherwise. * @return true if speakerphone is active, false otherwise.
*/ */
/*package*/ boolean isSpeakerphoneOn() { /*package*/ boolean isSpeakerphoneOn() {
return getForcedUseForComm() == AudioSystem.FORCE_SPEAKER; AudioDeviceAttributes device = getPreferredDeviceForComm();
if (device == null) {
return false;
}
return device.getInternalType() == AudioSystem.DEVICE_OUT_SPEAKER;
} }
/** /**
@@ -560,7 +584,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
* @return true if Bluetooth SCO is active , false otherwise. * @return true if Bluetooth SCO is active , false otherwise.
*/ */
/*package*/ boolean isBluetoothScoOn() { /*package*/ boolean isBluetoothScoOn() {
return getForcedUseForComm() == AudioSystem.FORCE_BT_SCO; AudioDeviceAttributes device = getPreferredDeviceForComm();
if (device == null) {
return false;
}
return AudioSystem.DEVICE_OUT_ALL_SCO_SET.contains(device.getInternalType());
} }
/*package*/ AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) { /*package*/ AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
@@ -612,8 +640,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
synchronized (mSetModeLock) { synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) { synchronized (mDeviceStateLock) {
AudioDeviceAttributes device = new AudioDeviceAttributes( AudioDeviceAttributes device =
AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BLUETOOTH_SCO, ""); new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, "");
setCommunicationRouteForClient(cb, pid, device, scoAudioMode, eventSource); setCommunicationRouteForClient(cb, pid, device, scoAudioMode, eventSource);
} }
} }
@@ -643,10 +671,19 @@ import java.util.concurrent.atomic.AtomicBoolean;
return mDeviceInventory.setPreferredDevicesForStrategySync(strategy, devices); return mDeviceInventory.setPreferredDevicesForStrategySync(strategy, devices);
} }
/*package*/ void postSetPreferredDevicesForStrategy(int strategy,
@NonNull List<AudioDeviceAttributes> devices) {
sendILMsgNoDelay(MSG_IL_SET_PREF_DEVICES_FOR_STRATEGY, SENDMSG_REPLACE, strategy, devices);
}
/*package*/ int removePreferredDevicesForStrategySync(int strategy) { /*package*/ int removePreferredDevicesForStrategySync(int strategy) {
return mDeviceInventory.removePreferredDevicesForStrategySync(strategy); return mDeviceInventory.removePreferredDevicesForStrategySync(strategy);
} }
/*package*/ void postRemovePreferredDevicesForStrategy(int strategy) {
sendIMsgNoDelay(MSG_I_REMOVE_PREF_DEVICES_FOR_STRATEGY, SENDMSG_REPLACE, strategy);
}
/*package*/ void registerStrategyPreferredDevicesDispatcher( /*package*/ void registerStrategyPreferredDevicesDispatcher(
@NonNull IStrategyPreferredDevicesDispatcher dispatcher) { @NonNull IStrategyPreferredDevicesDispatcher dispatcher) {
mDeviceInventory.registerStrategyPreferredDevicesDispatcher(dispatcher); mDeviceInventory.registerStrategyPreferredDevicesDispatcher(dispatcher);
@@ -971,9 +1008,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
pw.println(" " + prefix + "pid: " + cl.getPid() + " device: " pw.println(" " + prefix + "pid: " + cl.getPid() + " device: "
+ cl.getDevice() + " cb: " + cl.getBinder()); }); + cl.getDevice() + " cb: " + cl.getBinder()); });
pw.println("\n" + prefix + "mForcedUseForComm: " pw.println("\n" + prefix + "mPreferredDeviceforComm: "
+ AudioSystem.forceUseConfigToString(mForcedUseForComm)); + mPreferredDeviceforComm);
pw.println(prefix + "mModeOwnerPid: " + mModeOwnerPid); pw.println(prefix + "mCommunicationStrategyId: "
+ mCommunicationStrategyId);
pw.println("\n" + prefix + "mModeOwnerPid: " + mModeOwnerPid);
mBtHelper.dump(pw, prefix); mBtHelper.dump(pw, prefix);
} }
@@ -1068,6 +1108,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
case MSG_RESTORE_DEVICES: case MSG_RESTORE_DEVICES:
synchronized (mSetModeLock) { synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) { synchronized (mDeviceStateLock) {
initCommunicationStrategyId();
mDeviceInventory.onRestoreDevices(); mDeviceInventory.onRestoreDevices();
mBtHelper.onAudioServerDiedRestoreA2dp(); mBtHelper.onAudioServerDiedRestoreA2dp();
onUpdateCommunicationRoute("MSG_RESTORE_DEVICES"); onUpdateCommunicationRoute("MSG_RESTORE_DEVICES");
@@ -1277,6 +1318,17 @@ import java.util.concurrent.atomic.AtomicBoolean;
final int strategy = msg.arg1; final int strategy = msg.arg1;
mDeviceInventory.onSaveRemovePreferredDevices(strategy); mDeviceInventory.onSaveRemovePreferredDevices(strategy);
} break; } break;
case MSG_IL_SET_PREF_DEVICES_FOR_STRATEGY: {
final int strategy = msg.arg1;
final List<AudioDeviceAttributes> devices =
(List<AudioDeviceAttributes>) msg.obj;
setPreferredDevicesForStrategySync(strategy, devices);
} break;
case MSG_I_REMOVE_PREF_DEVICES_FOR_STRATEGY: {
final int strategy = msg.arg1;
removePreferredDevicesForStrategySync(strategy);
} break;
case MSG_CHECK_MUTE_MUSIC: case MSG_CHECK_MUTE_MUSIC:
checkMessagesMuteMusic(0); checkMessagesMuteMusic(0);
break; break;
@@ -1369,7 +1421,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
private static final int MSG_I_SAVE_CLEAR_PREF_DEVICES_FOR_CAPTURE_PRESET = 38; private static final int MSG_I_SAVE_CLEAR_PREF_DEVICES_FOR_CAPTURE_PRESET = 38;
private static final int MSG_L_UPDATE_COMMUNICATION_ROUTE = 39; private static final int MSG_L_UPDATE_COMMUNICATION_ROUTE = 39;
private static final int MSG_IL_SET_PREF_DEVICES_FOR_STRATEGY = 40;
private static final int MSG_I_REMOVE_PREF_DEVICES_FOR_STRATEGY = 41;
private static boolean isMessageHandledUnderWakelock(int msgId) { private static boolean isMessageHandledUnderWakelock(int msgId) {
switch(msgId) { switch(msgId) {
@@ -1609,16 +1662,25 @@ import java.util.concurrent.atomic.AtomicBoolean;
* @return selected forced usage for communication. * @return selected forced usage for communication.
*/ */
@GuardedBy("mDeviceStateLock") @GuardedBy("mDeviceStateLock")
private int getForcedUseForComm() { @Nullable private AudioDeviceAttributes getPreferredDeviceForComm() {
boolean btSCoOn = mBluetoothScoOn && mBtHelper.isBluetoothScoOn(); boolean btSCoOn = mBluetoothScoOn && mBtHelper.isBluetoothScoOn();
if (btSCoOn) { if (btSCoOn) {
return AudioSystem.FORCE_BT_SCO; // Use the SCO device known to BtHelper so that it matches exactly
// what has been communicated to audio policy manager. The device
// returned by requestedCommunicationDevice() can be a dummy SCO device if legacy
// APIs are used to start SCO audio.
AudioDeviceAttributes device = mBtHelper.getHeadsetAudioDevice();
if (device != null) {
return device;
}
} }
if (isSpeakerphoneRequested()) { AudioDeviceAttributes device = requestedCommunicationDevice();
return AudioSystem.FORCE_SPEAKER; if (device == null
|| AudioSystem.DEVICE_OUT_ALL_SCO_SET.contains(device.getInternalType())) {
// Do not indicate BT SCO selection if SCO is requested but SCO is not ON
return null;
} }
return AudioSystem.FORCE_NONE; return device;
} }
/** /**
@@ -1628,30 +1690,24 @@ import java.util.concurrent.atomic.AtomicBoolean;
// @GuardedBy("mSetModeLock") // @GuardedBy("mSetModeLock")
@GuardedBy("mDeviceStateLock") @GuardedBy("mDeviceStateLock")
private void onUpdateCommunicationRoute(String eventSource) { private void onUpdateCommunicationRoute(String eventSource) {
mForcedUseForComm = getForcedUseForComm(); mPreferredDeviceforComm = getPreferredDeviceForComm();
if (AudioService.DEBUG_COMM_RTE) { if (AudioService.DEBUG_COMM_RTE) {
Log.v(TAG, "onUpdateCommunicationRoute, mForcedUseForComm: " + mForcedUseForComm Log.v(TAG, "onUpdateCommunicationRoute, mPreferredDeviceforComm: "
+ " eventSource: " + eventSource); + mPreferredDeviceforComm + " eventSource: " + eventSource);
} }
if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) { if (mPreferredDeviceforComm == null
AudioSystem.setParameters("BT_SCO=on"); || !AudioSystem.DEVICE_OUT_ALL_SCO_SET.contains(
setForceUse_Async( mPreferredDeviceforComm.getInternalType())) {
AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_BT_SCO, eventSource);
setForceUse_Async(
AudioSystem.FOR_RECORD, AudioSystem.FORCE_BT_SCO, eventSource);
} else {
AudioSystem.setParameters("BT_SCO=off"); AudioSystem.setParameters("BT_SCO=off");
setForceUse_Async( } else {
AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, eventSource); AudioSystem.setParameters("BT_SCO=on");
if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER) { }
setForceUse_Async( if (mPreferredDeviceforComm == null) {
AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_SPEAKER, eventSource); postRemovePreferredDevicesForStrategy(mCommunicationStrategyId);
} else { } else {
setForceUse_Async( postSetPreferredDevicesForStrategy(
AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_NONE, eventSource); mCommunicationStrategyId, Arrays.asList(mPreferredDeviceforComm));
}
} }
mAudioService.postUpdateRingerModeServiceInt(); mAudioService.postUpdateRingerModeServiceInt();
dispatchCommunicationDevice(); dispatchCommunicationDevice();

View File

@@ -648,6 +648,10 @@ public class AudioDeviceInventory {
/*package*/ int setPreferredDevicesForStrategySync(int strategy, /*package*/ int setPreferredDevicesForStrategySync(int strategy,
@NonNull List<AudioDeviceAttributes> devices) { @NonNull List<AudioDeviceAttributes> devices) {
final long identity = Binder.clearCallingIdentity(); final long identity = Binder.clearCallingIdentity();
AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
"setPreferredDevicesForStrategySync, strategy: " + strategy
+ " devices: " + devices)).printLog(TAG));
final int status = mAudioSystem.setDevicesRoleForStrategy( final int status = mAudioSystem.setDevicesRoleForStrategy(
strategy, AudioSystem.DEVICE_ROLE_PREFERRED, devices); strategy, AudioSystem.DEVICE_ROLE_PREFERRED, devices);
Binder.restoreCallingIdentity(identity); Binder.restoreCallingIdentity(identity);

View File

@@ -5121,8 +5121,7 @@ public class AudioService extends IAudioService.Stub
switch (mPlatformType) { switch (mPlatformType) {
case AudioSystem.PLATFORM_VOICE: case AudioSystem.PLATFORM_VOICE:
if (isInCommunication()) { if (isInCommunication()) {
if (mAudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) if (mDeviceBroker.isBluetoothScoOn()) {
== AudioSystem.FORCE_BT_SCO) {
// Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO..."); // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
return AudioSystem.STREAM_BLUETOOTH_SCO; return AudioSystem.STREAM_BLUETOOTH_SCO;
} else { } else {
@@ -5158,8 +5157,7 @@ public class AudioService extends IAudioService.Stub
} }
default: default:
if (isInCommunication()) { if (isInCommunication()) {
if (mAudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) if (mDeviceBroker.isBluetoothScoOn()) {
== AudioSystem.FORCE_BT_SCO) {
if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO"); if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
return AudioSystem.STREAM_BLUETOOTH_SCO; return AudioSystem.STREAM_BLUETOOTH_SCO;
} else { } else {

View File

@@ -27,6 +27,7 @@ import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothHearingAid; import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothProfile;
import android.content.Intent; import android.content.Intent;
import android.media.AudioDeviceAttributes;
import android.media.AudioManager; import android.media.AudioManager;
import android.media.AudioSystem; import android.media.AudioSystem;
import android.os.Binder; import android.os.Binder;
@@ -530,46 +531,64 @@ public class BtHelper {
mDeviceBroker.postBroadcastScoConnectionState(state); mDeviceBroker.postBroadcastScoConnectionState(state);
} }
private boolean handleBtScoActiveDeviceChange(BluetoothDevice btDevice, boolean isActive) { @Nullable AudioDeviceAttributes getHeadsetAudioDevice() {
if (btDevice == null) { if (mBluetoothHeadsetDevice == null) {
return true; return null;
} }
return btHeadsetDeviceToAudioDevice(mBluetoothHeadsetDevice);
}
private AudioDeviceAttributes btHeadsetDeviceToAudioDevice(BluetoothDevice btDevice) {
String address = btDevice.getAddress(); String address = btDevice.getAddress();
if (!BluetoothAdapter.checkBluetoothAddress(address)) {
address = "";
}
BluetoothClass btClass = btDevice.getBluetoothClass(); BluetoothClass btClass = btDevice.getBluetoothClass();
int inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET; int nativeType = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
int[] outDeviceTypes = {
AudioSystem.DEVICE_OUT_BLUETOOTH_SCO,
AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET,
AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT
};
if (btClass != null) { if (btClass != null) {
switch (btClass.getDeviceClass()) { switch (btClass.getDeviceClass()) {
case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET: case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE: case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
outDeviceTypes = new int[] { AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET }; nativeType = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
break; break;
case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO: case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
outDeviceTypes = new int[] { AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT }; nativeType = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
break; break;
} }
} }
if (!BluetoothAdapter.checkBluetoothAddress(address)) { if (AudioService.DEBUG_DEVICES) {
address = ""; Log.i(TAG, "btHeadsetDeviceToAudioDevice btDevice: " + btDevice
+ " btClass: " + (btClass == null ? "Unknown" : btClass)
+ " nativeType: " + nativeType + " address: " + address);
} }
return new AudioDeviceAttributes(nativeType, address);
}
private boolean handleBtScoActiveDeviceChange(BluetoothDevice btDevice, boolean isActive) {
if (btDevice == null) {
return true;
}
int inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
AudioDeviceAttributes audioDevice = btHeadsetDeviceToAudioDevice(btDevice);
String btDeviceName = getName(btDevice); String btDeviceName = getName(btDevice);
boolean result = false; boolean result = false;
if (isActive) { if (isActive) {
result |= mDeviceBroker.handleDeviceConnection( result |= mDeviceBroker.handleDeviceConnection(isActive, audioDevice.getInternalType(),
isActive, outDeviceTypes[0], address, btDeviceName); audioDevice.getAddress(), btDeviceName);
} else { } else {
int[] outDeviceTypes = {
AudioSystem.DEVICE_OUT_BLUETOOTH_SCO,
AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET,
AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT
};
for (int outDeviceType : outDeviceTypes) { for (int outDeviceType : outDeviceTypes) {
result |= mDeviceBroker.handleDeviceConnection( result |= mDeviceBroker.handleDeviceConnection(
isActive, outDeviceType, address, btDeviceName); isActive, outDeviceType, audioDevice.getAddress(), btDeviceName);
} }
} }
// handleDeviceConnection() && result to make sure the method get executed // handleDeviceConnection() && result to make sure the method get executed
result = mDeviceBroker.handleDeviceConnection( result = mDeviceBroker.handleDeviceConnection(
isActive, inDevice, address, btDeviceName) && result; isActive, inDevice, audioDevice.getAddress(), btDeviceName) && result;
return result; return result;
} }