做音频开发,避免不了和蓝牙打交道,尤其是做系统开发,又是不同的模块,所以很多问题很难界定。因而,了解一下蓝牙,对整体的系统架的理解会更加完善。同样的,有线耳机和A2DP在Audio的处理有很多相似处。
蓝牙连接处理
Audio这边提提供了多种方式和蓝牙进行交互~
广播接收
AudioService定义了AudioServiceBroadcastReceiver,会接收蓝牙的广播:
// Register for device connection intent broadcasts.
IntentFilter intentFilter =
new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
... ...
intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
... ...
intentFilter.addAction(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION);
intentFilter.addAction(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION);
AudioManager接口
public void startBluetoothSco()
public void stopBluetoothSco()
public boolean isBluetoothScoOn()
public void setBluetoothScoOn(boolean on)
public boolean isBluetoothA2dpOn()
public void startBluetoothScoVirtualCall()
public void handleBluetoothA2dpDeviceConfigChange(BluetoothDevice device)
public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
Listener监听
这里主要是监听BluetoothProfile.ServiceListener,监听服务断开和打开
/**
* An interface for notifying BluetoothProfile IPC clients when they have
* been connected or disconnected to the service.
*/
public interface ServiceListener {
/**
* Called to notify the client when the proxy object has been
* connected to the service.
* @param profile - One of {@link #HEALTH}, {@link #HEADSET} or
* {@link #A2DP}
* @param proxy - One of {@link BluetoothHealth}, {@link BluetoothHeadset} or
* {@link BluetoothA2dp}
*/
public void onServiceConnected(int profile, BluetoothProfile proxy);
/**
* Called to notify the client that this proxy object has been
* disconnected from the service.
* @param profile - One of {@link #HEALTH}, {@link #HEADSET} or
* {@link #A2DP}
*/
public void onServiceDisconnected(int profile);
}
蓝牙耳机和AudioService的交互
这里用来测试的蓝牙耳机是Philips SHB5800。连接时,会上报A2DP和SCO两个profile的连接事件。
蓝牙的状态
蓝牙的状态,主要有如下几个状态,定义在BluetoothProfile中:
* frameworks/base/core/java/android/bluetooth/BluetoothProfile.java
/** The profile is in disconnected state */
public static final int STATE_DISCONNECTED = 0;
/** The profile is in connecting state */
public static final int STATE_CONNECTING = 1;
/** The profile is in connected state */
public static final int STATE_CONNECTED = 2;
/** The profile is in disconnecting state */
public static final int STATE_DISCONNECTING = 3;
A2DP给AudioService上报连接状态
A2DP是通过AudioManager接口和Audio模块进行交互的,通过setBluetoothA2dpDeviceConnectionState接口,Bluetooth会调两次,上报两次状态。
第一次,状态为state = 1
,STATE_CONNECTING 连接中状态:
04-28 09:21:38.653 27417 27468 D AudioManager: setBluetoothA2dpDeviceConnectionState: state = 1
第二次,状态为state = 2
,STATE_CONNECTED 已连接状态:
04-28 09:21:42.168 27417 27468 D AudioManager: setBluetoothA2dpDeviceConnectionState: state = 2
两次状态上报,都是Bluetooth应用上报的,调用栈如下:
04-28 09:21:38.653 27417 27468 W System.err: at android.media.AudioManager.setBluetoothA2dpDeviceConnectionState(AudioManager.java:3698)
04-28 09:21:38.653 27417 27468 W System.err: at com.android.bluetooth.a2dp.A2dpStateMachine.broadcastConnectionState(A2dpStateMachine.java:952)
04-28 09:21:38.653 27417 27468 W System.err: at com.android.bluetooth.a2dp.A2dpStateMachine.-wrap4(Unknown Source:0)
04-28 09:21:38.654 27417 27468 W System.err: at com.android.bluetooth.a2dp.A2dpStateMachine$Disconnected.processMessage(A2dpStateMachine.java:304)
04-28 09:21:38.654 27417 27468 W System.err: at com.android.internal.util.StateMachine$SmHandler.processMsg(StateMachine.java:992)
04-28 09:21:38.654 27417 27468 W System.err: at com.android.internal.util.StateMachine$SmHandler.handleMessage(StateMachine.java:809)
04-28 09:21:38.654 27417 27468 W System.err: at android.os.Handler.dispatchMessage(Handler.java:106)
04-28 09:21:38.654 27417 27468 W System.err: at android.os.Looper.loop(Looper.java:175)
04-28 09:21:38.655 27417 27468 W System.err: at android.os.HandlerThread.run(HandlerThread.java:65)
AudioService的setBluetoothA2dpDeviceConnectionState实现如下:
* frameworks/base/services/core/java/com/android/server/audio/AudioService.java
public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
{
if (mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE, device)) {
return 0;
}
return setBluetoothA2dpDeviceConnectionStateInt(
device, state, profile, AudioSystem.DEVICE_NONE);
}
setBluetoothA2dpDeviceConnectionStateInt只处理A2DP和A2DP_SINK:
public int setBluetoothA2dpDeviceConnectionStateInt(
BluetoothDevice device, int state, int profile, int musicDevice)
{
int delay;
if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
throw new IllegalArgumentException("invalid profile " + profile);
}
synchronized (mConnectedDevices) {
if (profile == BluetoothProfile.A2DP) {
int intState = (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0;
delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
intState, musicDevice);
} else {
delay = 0;
}
queueMsgUnderWakeLock(mAudioHandler,
(profile == BluetoothProfile.A2DP ?
MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
state,
0 /* arg2 unused */,
device,
delay);
}
return delay;
}
对A2DP,MSG_SET_A2DP_SINK_CONNECTION_STATE处理如下:
case MSG_SET_A2DP_SINK_CONNECTION_STATE:
onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1);
mAudioEventWakeLock.release();
break;
具体处理在onSetA2dpSinkConnectionState中处理:
private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
{
... ...
synchronized (mConnectedDevices) {
final String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
btDevice.getAddress());
final DeviceListSpec deviceSpec = mConnectedDevices.get(key);
boolean isConnected = deviceSpec != null;
if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
if (btDevice.isBluetoothDock()) {
if (state == BluetoothProfile.STATE_DISCONNECTED) {
// introduction of a delay for transient disconnections of docks when
// power is rapidly turned off/on, this message will be canceled if
// we reconnect the dock under a preset delay
makeA2dpDeviceUnavailableLater(address, BTA2DP_DOCK_TIMEOUT_MILLIS);
// the next time isConnected is evaluated, it will be false for the dock
}
} else {
makeA2dpDeviceUnavailableNow(address);
}
synchronized (mCurAudioRoutes) {
if (mCurAudioRoutes.bluetoothName != null) {
mCurAudioRoutes.bluetoothName = null;
sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
SENDMSG_NOOP, 0, 0, null, 0);
}
}
} else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
if (btDevice.isBluetoothDock()) {
// this could be a reconnection after a transient disconnection
cancelA2dpDeviceTimeout();
mDockAddress = address;
} else {
// this could be a connection of another A2DP device before the timeout of
// a dock: cancel the dock timeout, and make the dock unavailable now
if(hasScheduledA2dpDockTimeout()) {
cancelA2dpDeviceTimeout();
makeA2dpDeviceUnavailableNow(mDockAddress);
}
}
makeA2dpDeviceAvailable(address, btDevice.getName(),
"onSetA2dpSinkConnectionState");
synchronized (mCurAudioRoutes) {
String name = btDevice.getAliasName();
if (!TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) {
mCurAudioRoutes.bluetoothName = name;
sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
SENDMSG_NOOP, 0, 0, null, 0);
}
}
}
}
}
- state 为 1,STATE_CONNECTING时,什么也没有做,走不进调节判断中去。
- state 为 12,STATE_CONNECTED时,走到
else if
,关键的是调到了makeA2dpDeviceAvailable
makeA2dpDeviceAvailable 函数如下:
private void makeA2dpDeviceAvailable(String address, String name, String eventSource) {
// enable A2DP before notifying A2DP connection to avoid unnecessary processing in
// audio policy manager
VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
setBluetoothA2dpOnInt(true, eventSource);
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
AudioSystem.DEVICE_STATE_AVAILABLE, address, name);
// Reset A2DP suspend state each time a new sink is connected
AudioSystem.setParameters("A2dpSuspended=false");
mConnectedDevices.put(
makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address),
new DeviceListSpec(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, name,
address));
sendMsg(mAudioHandler, MSG_ACCESSORY_PLUG_MEDIA_UNMUTE, SENDMSG_QUEUE,
AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, null, 0);
}
makeA2dpDeviceAvailable 时,主要做了以下几件事:
- 发送消息MSG_SET_DEVICE_VOLUME, 设置新的A2DP的音量,各种类型的音量都会设置
04-28 11:01:47.274 823 1101 D AudioService: applyDeviceVolumemStreamType:3,device:128
04-28 11:01:47.275 823 1101 D AudioService: applyDeviceVolumemStreamType:10,device:128
04-28 11:01:47.277 823 1101 D AudioService: applyDeviceVolumemStreamType:2,device:128
04-28 11:01:47.277 823 1101 D AudioService: applyDeviceVolumemStreamType:8,device:128
04-28 11:01:47.280 823 1101 D AudioService: applyDeviceVolumemStreamType:1,device:128
- A2DP打开,setBluetoothA2dpOnInt,默认Media用A2DP
public void setBluetoothA2dpOnInt(boolean on, String eventSource) {
synchronized (mBluetoothA2dpEnabledLock) {
mBluetoothA2dpEnabled = on;
mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
setForceUseInt_SyncDevices(AudioSystem.FOR_MEDIA,
mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
eventSource);
}
}
强制使用A2DP
private void setForceUseInt_SyncDevices(int usage, int config, String eventSource) {
if (usage == AudioSystem.FOR_MEDIA) {
sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
SENDMSG_NOOP, 0, 0, null, 0);
}
mForceUseLogger.log(new ForceUseEvent(usage, config, eventSource));
if(LOGD){
Log.i(TAG,new StringBuilder("setForceUse(")
.append(AudioSystem.forceUseUsageToString(usage))
.append(", ").append(AudioSystem.forceUseConfigToString(config))
.append(") due to ").append(eventSource).toString());
}
AudioSystem.setForceUse(usage, config);
}
强制使用A2DP通过,AudioSystem的setForceUse接口完成的。
-
给native报A2DP连接的状态,通过AudioSystem的setDeviceConnectionState接口完成
-
将连接上的A2DP添加到mConnectedDevices中,以DeviceListSpec进行封装
回到onSetA2dpSinkConnectionState函数,一般会上报新的Audio线路MSG_REPORT_NEW_ROUTES。
SCO给AudioService上报连接状态
相比A2DP的接口调用,SCO是通过Receiver监听的。AudioServiceBroadcastReceiver在收到ACTION_CONNECTION_STATE_CHANGED时,Audio将同SCO的状态。A2DP只能做音频输出,而SCO可以做音频输出也可以做音频的输入。
输出: AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET(0x20)
输入: AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET (0x8)
大概的栈如下:
04-28 14:13:19.599 805 805 W System.err: at com.android.server.audio.AudioService.handleDeviceConnection(AudioService.java:5604)
04-28 14:13:19.599 805 805 W System.err: at com.android.server.audio.AudioService.setBtScoDeviceConnectionState(AudioService.java:3481)
04-28 14:13:19.599 805 805 W System.err: at com.android.server.audio.AudioService$AudioServiceBroadcastReceiver.onReceive(AudioService.java:5971)
ACTION_CONNECTION_STATE_CHANGED是从Bluetooth发出来的。
private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
... ...
} else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
BluetoothProfile.STATE_DISCONNECTED);
BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
setBtScoDeviceConnectionState(btDevice, state);
} else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
setBtScoDeviceConnectionState中,将处理SCO的input和output。
void setBtScoDeviceConnectionState(BluetoothDevice btDevice, int state) {
... ...
// 类型转换
String address = btDevice.getAddress();
BluetoothClass btClass = btDevice.getBluetoothClass();
int outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
int inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
if (btClass != null) {
switch (btClass.getDeviceClass()) {
case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
break;
case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
break;
}
}
// 处理连接,outDevice和inDevice
boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
String btDeviceName = btDevice.getName();
boolean success =
handleDeviceConnection(connected, outDevice, address, btDeviceName) &&
handleDeviceConnection(connected, inDevice, address, btDeviceName);
// 只要headset是连着的,就不断开
if ((state == BluetoothProfile.STATE_DISCONNECTED ||
state == BluetoothProfile.STATE_DISCONNECTING) &&
mBluetoothHeadset != null &&
mBluetoothHeadset.getAudioState(btDevice) == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
Log.w(TAG, "SCO connected through another device, returning");
return;
}
// 赋值给mBluetoothHeadsetDevice ***BUG? 貌似有Bug,两个设备的时候怎么处理?***
synchronized (mScoClients) {
if (connected) {
mBluetoothHeadsetDevice = btDevice;
} else {
mBluetoothHeadsetDevice = null;
resetBluetoothSco();
}
}
}
setBtScoDeviceConnectionState大部分处理在handleDeviceConnection中完成
private boolean handleDeviceConnection(boolean connect, int device, String address,
String deviceName) {
synchronized (mConnectedDevices) {
String deviceKey = makeDeviceListKey(device, address);
DeviceListSpec deviceSpec = mConnectedDevices.get(deviceKey);
boolean isConnected = deviceSpec != null;
if (connect && !isConnected) { // connect现在的状态,isConnected原来的状态
final int res = AudioSystem.setDeviceConnectionState(device,
AudioSystem.DEVICE_STATE_AVAILABLE, address, deviceName);
if (res != AudioSystem.AUDIO_STATUS_OK) {
Slog.e(TAG, "not connecting device 0x" + Integer.toHexString(device) +
" due to command error " + res );
return false;
}
mConnectedDevices.put(deviceKey, new DeviceListSpec(device, deviceName, address));
sendMsg(mAudioHandler, MSG_ACCESSORY_PLUG_MEDIA_UNMUTE, SENDMSG_QUEUE,
device, 0, null, 0);
return true;
} else if (!connect && isConnected) {
AudioSystem.setDeviceConnectionState(device,
AudioSystem.DEVICE_STATE_UNAVAILABLE, address, deviceName);
// always remove even if disconnection failed
mConnectedDevices.remove(deviceKey);
return true;
}
}
return false;
}
- 连接时,通过AudioSystem的setDeviceConnectionState接口,同步到native层。注意这里的参数为AudioSystem.DEVICE_STATE_AVAILABLE
- SCO的设备同样添加到mConnectedDevices中
- 如果是unmute的设备,通过MSG_ACCESSORY_PLUG_MEDIA_UNMUTE,恢复音量
private void onAccessoryPlugMediaUnmute(int newDevice) {
if (DEBUG_VOL) {
Log.i(TAG, String.format("onAccessoryPlugMediaUnmute newDevice=%d [%s]",
newDevice, AudioSystem.getOutputDeviceName(newDevice)));
}
synchronized (mConnectedDevices) {
if (mNm.getZenMode() != Settings.Global.ZEN_MODE_NO_INTERRUPTIONS
&& (newDevice & DEVICE_MEDIA_UNMUTED_ON_PLUG) != 0
&& mStreamStates[AudioSystem.STREAM_MUSIC].mIsMuted
&& mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(newDevice) != 0
&& (newDevice & AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC)) != 0)
{
mStreamStates[AudioSystem.STREAM_MUSIC].mute(false);
}
}
}
有线耳机的连接状态
耳机的连接和Bluetooth的连接很类似,耳机可以做输出也可以做为输入:
输出: AUDIO_DEVICE_OUT_WIRED_HEADSET(0x4)
输入: AUDIO_DEVICE_IN_WIRED_HEADSET (0x10)
有线耳机基本都是通过AudioManager的setWiredDeviceConnectionState接口同步的状态。从WiredAccessoryManager上报的状态:
04-28 15:40:05.859 992 992 W System.err: at android.media.AudioManager.setWiredDeviceConnectionState(AudioManager.java:3670)
04-28 15:40:05.859 992 992 W System.err: at com.android.server.WiredAccessoryManager.setDeviceStateLocked(WiredAccessoryManager.java:293)
04-28 15:40:05.859 992 992 W System.err: at com.android.server.WiredAccessoryManager.setDevicesState(WiredAccessoryManager.java:249)
04-28 15:40:05.859 992 992 W System.err: at com.android.server.WiredAccessoryManager.-wrap1(Unknown Source:0)
04-28 15:40:05.859 992 992 W System.err: at com.android.server.WiredAccessoryManager$1.handleMessage(WiredAccessoryManager.java:232)
04-28 15:40:05.859 992 992 W System.err: at android.os.Handler.dispatchMessage(Handler.java:106)
后续的流程也是通过handleDeviceConnection函数处理的,前面我们已经分析过。
04-28 15:16:51.860 805 1097 W System.err: at com.android.server.audio.AudioService.handleDeviceConnection(AudioService.java:5604)
04-28 15:16:51.860 805 1097 W System.err: at com.android.server.audio.AudioService.onSetWiredDeviceConnectionState(AudioService.java:5830
Audio添加音频设备
不管是A2DP,SCO,还是有线耳机,都会通过AudioSystem的setDeviceConnectionState函数,将配件的状态转给底层。下面我来看看,底层是怎么处理的。
AudioPolicy处理音频设备状态
setDeviceConnectionState是一个native函数,通过JNI,将调到了native的AudioSystem中。
status_t AudioSystem::setDeviceConnectionState(audio_devices_t device,
audio_policy_dev_state_t state,
const char *device_address,
const char *device_name)
{
... ...
return aps->setDeviceConnectionState(device, state, address, name);
}
最终是在AudioPolicyManager.cpp中处理的:
status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device,
audio_policy_dev_state_t state,
const char *device_address,
const char *device_name)
{
return setDeviceConnectionStateInt(device, state, device_address, device_name);
}
AudioPolicyManager用两个DeviceVector,分别管理系统中的可用的音频输入输出设备。
DeviceVector mAvailableOutputDevices; // all available output devices
DeviceVector mAvailableInputDevices; // all available input devices
在setDeviceConnectionStateInt函数中,对设备的状态进行处理,根据状态维护mAvailableOutputDevices
和mAvailableInputDevices
。
status_t AudioPolicyManager::setDeviceConnectionStateInt(audio_devices_t device,
audio_policy_dev_state_t state,
const char *device_address,
const char *device_name)
{
// connect/disconnect only 1 device at a time
if (!audio_is_output_device(device) && !audio_is_input_device(device)) return BAD_VALUE;
sp<DeviceDescriptor> devDesc =
mHwModules.getDeviceDescriptor(device, device_address, device_name);
先获取状态变化的设备getDeviceDescriptor。getDeviceDescriptor是从hw_mode中去获取驱动支持的设备。
下面,分分别来看输入,输入的设备的状态:
状态值:
* system/media/audio/include/system/audio_policy.h
typedef enum {
AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
AUDIO_POLICY_DEVICE_STATE_CNT,
AUDIO_POLICY_DEVICE_STATE_MAX = AUDIO_POLICY_DEVICE_STATE_CNT - 1,
} audio_policy_dev_state_t;
音频输出设备处理
输出设备,用mAvailableOutputDevices维护,主要是连接和断开时的处理。听筒,Speaker等手机自带的设备,一般只有启动的时候才会处理一下,其他时间都是不需要处理的。所以主要是还是我们所说的,蓝牙耳机,有线耳机等。
- 音频设备连接
status_t AudioPolicyManager::setDeviceConnectionStateInt(audio_devices_t device,
audio_policy_dev_state_t state,
const char *device_address,
const char *device_name)
{
... ...
// handle output devices
if (audio_is_output_device(device)) {
SortedVector <audio_io_handle_t> outputs;
ssize_t index = mAvailableOutputDevices.indexOf(devDesc);
mPreviousOutputs = mOutputs;
switch (state)
{
// handle output device connection
case AUDIO_POLICY_DEVICE_STATE_AVAILABLE: {
... ...
// register new device as available
index = mAvailableOutputDevices.add(devDesc);
if (index >= 0) {
sp<HwModule> module = mHwModules.getModuleForDevice(device);
if (module == 0) {
ALOGD("setDeviceConnectionState() could not find HW module for device %08x",
device);
mAvailableOutputDevices.remove(devDesc);
return INVALID_OPERATION;
}
mAvailableOutputDevices[index]->attach(module);
} else {
return NO_MEMORY;
}
// Before checking outputs, broadcast connect event to allow HAL to retrieve dynamic
// parameters on newly connected devices (instead of opening the outputs...)
broadcastDeviceConnectionState(device, state, devDesc->mAddress);
if (checkOutputsForDevice(devDesc, state, outputs, devDesc->mAddress) != NO_ERROR) {
mAvailableOutputDevices.remove(devDesc);
broadcastDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
devDesc->mAddress);
return INVALID_OPERATION;
}
// Propagate device availability to Engine
mEngine->setDeviceConnectionState(devDesc, state);
... ...
} break;
输出设备连接时,主要做以下几件事:
- 将新连接的音频设备,添加到mAvailableOutputDevices中,且让设备和具体的HwModule关联。
- 广播设备已连接状态,broadcastDeviceConnectionState
- checkOutputsForDevice,确认设备是连接是否正确
- 将状态传给mEngine
- 音频设备断开
status_t AudioPolicyManager::setDeviceConnectionStateInt(audio_devices_t device,
audio_policy_dev_state_t state,
const char *device_address,
const char *device_name)
{
... ...
// handle output devices
if (audio_is_output_device(device)) {
.... ....
// handle output device disconnection
case AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE: {
... ...
// Send Disconnect to HALs
broadcastDeviceConnectionState(device, state, devDesc->mAddress);
// remove device from available output devices
mAvailableOutputDevices.remove(devDesc);
checkOutputsForDevice(devDesc, state, outputs, devDesc->mAddress);
// Propagate device availability to Engine
mEngine->setDeviceConnectionState(devDesc, state);
} break;
default:
ALOGE("setDeviceConnectionState() invalid state: %x", state);
return BAD_VALUE;
}
断开时,将设备从mAvailableOutputDevices中删掉,其他处理和连接时类似。注意这里的checkOutputsForDevice
,这里将更新输出设备mOutputs。
设备更新完成后,就需要更新策略了,切换通路,确保音频的输出通路可用且正确。
status_t AudioPolicyManager::setDeviceConnectionStateInt(audio_devices_t device,
audio_policy_dev_state_t state,
const char *device_address,
const char *device_name)
{
... ...
// handle output devices
if (audio_is_output_device(device)) {
.... ....
// checkA2dpSuspend must run before checkOutputForAllStrategies so that A2DP
// output is suspended before any tracks are moved to it
checkA2dpSuspend();
checkOutputForAllStrategies();
// outputs must be closed after checkOutputForAllStrategies() is executed
if (!outputs.isEmpty()) {
for (size_t i = 0; i < outputs.size(); i++) {
sp<SwAudioOutputDescriptor> desc = mOutputs.valueFor(outputs[i]);
// close unused outputs after device disconnection or direct outputs that have been
// opened by checkOutputsForDevice() to query dynamic parameters
if ((state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) ||
(((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) &&
(desc->mDirectOpenCount == 0))) {
closeOutput(outputs[i]);
}
}
// check again after closing A2DP output to reset mA2dpSuspended if needed
checkA2dpSuspend();
}
updateDevicesAndOutputs();
if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) {
audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/);
updateCallRouting(newDevice);
}
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
if ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) || (desc != mPrimaryOutput)) {
audio_devices_t newDevice = getNewOutputDevice(desc, true /*fromCache*/);
// do not force device change on duplicated output because if device is 0, it will
// also force a device 0 for the two outputs it is duplicated to which may override
// a valid device selection on those outputs.
bool force = !desc->isDuplicated()
&& (!device_distinguishes_on_address(device)
// always force when disconnecting (a non-duplicated device)
|| (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE));
newDevice = mpAudioPolicyMTKInterface->fm_correctDeviceFromSetDeviceConnectionStateInt(desc, newDevice, force);
setOutputDevice(desc, newDevice, force, 0);
}
}
if (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) {
cleanUpForDevice(devDesc);
}
mpClientInterface->onAudioPortListUpdate();
return NO_ERROR;
} // end if is output device
这里主要做了以下几件事:
- 阻塞式的检查A2DP的状态 checkA2dpSuspend。
- 检查所以策略的输出 checkOutputForAllStrategies
- 更新输出设备 updateDevicesAndOutputs
- 更新电话通路 updateCallRouting
- 设置输出设备 setOutputDevice,包括音量等。
- 回调给Client,音频断开更新 onAudioPortListUpdate。
音频输入设备处理
status_t AudioPolicyManager::setDeviceConnectionStateInt(audio_devices_t device,
audio_policy_dev_state_t state,
const char *device_address,
const char *device_name)
{
... ...
// handle input devices
if (audio_is_input_device(device)) {
SortedVector <audio_io_handle_t> inputs;
ssize_t index = mAvailableInputDevices.indexOf(devDesc);
switch (state)
{
// handle input device connection
case AUDIO_POLICY_DEVICE_STATE_AVAILABLE: {
... ...
// Before checking intputs, broadcast connect event to allow HAL to retrieve dynamic
// parameters on newly connected devices (instead of opening the inputs...)
broadcastDeviceConnectionState(device, state, devDesc->mAddress);
if (checkInputsForDevice(devDesc, state, inputs, devDesc->mAddress) != NO_ERROR) {
broadcastDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
devDesc->mAddress);
return INVALID_OPERATION;
}
index = mAvailableInputDevices.add(devDesc);
if (index >= 0) {
mAvailableInputDevices[index]->attach(module);
} else {
return NO_MEMORY;
}
// Propagate device availability to Engine
mEngine->setDeviceConnectionState(devDesc, state);
} break;
// handle input device disconnection
case AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE: {
... ...
// Set Disconnect to HALs
broadcastDeviceConnectionState(device, state, devDesc->mAddress);
checkInputsForDevice(devDesc, state, inputs, devDesc->mAddress);
mAvailableInputDevices.remove(devDesc);
// Propagate device availability to Engine
mEngine->setDeviceConnectionState(devDesc, state);
} break;
default:
ALOGE("setDeviceConnectionState() invalid state: %x", state);
return BAD_VALUE;
}
closeAllInputs();
// As the input device list can impact the output device selection, update
// getDeviceForStrategy() cache
updateDevicesAndOutputs();
if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) {
audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/);
updateCallRouting(newDevice);
}
if (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) {
cleanUpForDevice(devDesc);
}
mpClientInterface->onAudioPortListUpdate();
return NO_ERROR;
} // end if is input device
ALOGW("setDeviceConnectionState() invalid device: %x", device);
return BAD_VALUE;
}
音频输入设备的连接和断开处理,和输出设备的类似,这里就不多说,这里维护的是mAvailableInputDevices。
选择输出设备
播放音频时,将选择具体的音频设备~~
getDevicesForStream
getDeviceForStrategy
这里选择的设备就是我们添加到mAvailableOutputDevices中的可用的输出设备。
录音时,也为输入source选择设备。
getDeviceForInputSource
这里选择的设备就是我们添加到mAvailableInputDevices中的可用的输入设备。