Merge changes from topic "comm_routing" am: 8553f77dce

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1534433

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: I35def97c4eda8d484e42addde6b43377d748f578
This commit is contained in:
Eric Laurent
2020-12-23 12:58:54 +00:00
committed by Automerger Merge Worker
7 changed files with 164 additions and 75 deletions

View File

@@ -294,20 +294,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,
@@ -2381,9 +2386,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

@@ -1712,7 +1712,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

@@ -4972,8 +4972,7 @@ public class AudioService extends IAudioService.Stub
switch (mPlatformType) { switch (mPlatformType) {
case AudioSystem.PLATFORM_VOICE: case AudioSystem.PLATFORM_VOICE:
if (isInCommunication()) { if (isInCommunication()) {
if (AudioSystem.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 {
@@ -5009,8 +5008,7 @@ public class AudioService extends IAudioService.Stub
} }
default: default:
if (isInCommunication()) { if (isInCommunication()) {
if (AudioSystem.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;
} }