源码分析基于android9.0
通常带线耳机分类
- 模拟耳机
平时常用的3.5mm或6.3mm接口耳机,接收模拟信号(音频数据需要先处理,转码成pcm格式)
Android中模拟耳机由WiredAccessoryManager获取上报的事件,调用AudioService.setWiredDeviceConnectionState传递信息给AudioService,更新设备信息。 - 数字耳机
例如USB Type-c耳机,接收数字信号(音频数据不需要解码成pcm,由耳机进行转换)
Android中由UsbAlsaManager负责usb音频设备连接断开事件,调用AudioService.setWiredDeviceConnectionState传递信息给AudioService。
使用扬声器播放音乐,此时插入耳机,则音乐切换从耳机播放出。这里以插入数字耳机为例分析下音频设备切换流程。
一、Framework层
当设备插入usb 耳机,UsbHostManager会接收到usb设备事件调用usbDeviceAdded函数,调到UsbAlsaManager.usbDeviceAdded函数。
UsbAlsaManager.java
void usbDeviceAdded(String deviceAddress, UsbDevice usbDevice,
UsbDescriptorParser parser) {
//...
if (hasInput || hasOutput) {
UsbAlsaDevice alsaDevice =
new UsbAlsaDevice(mAudioService, cardRec.getCardNum(), 0 /*device*/,
deviceAddress, hasOutput, hasInput,
isInputHeadset, isOutputHeadset);
if (alsaDevice != null) {
alsaDevice.setDeviceNameAndDescription(
cardRec.getCardName(), cardRec.getCardDescription());
mAlsaDevices.add(0, alsaDevice);
selectAlsaDevice(alsaDevice);
}
}
}
private synchronized void selectAlsaDevice(UsbAlsaDevice alsaDevice) {
//.......
mSelectedDevice = alsaDevice;
alsaDevice.start();
}
- 创建UsbAlsaDevice,并设置信息;
- 设置为mSelectedDevice;
- 调用UsbAlsaDevice start,更新设备连接状态;
接着看UsbAlsaDevice start
public synchronized void start() {
mSelected = true;
mInputState = 0;
mOutputState = 0;
startJackDetect();
updateWiredDeviceConnectionState(true);
}
public synchronized void updateWiredDeviceConnectionState(boolean enable) {
//.......
if (mHasOutput) {
mAudioService.setWiredDeviceConnectionState(device, outputState,
alsaCardDeviceString,
mDeviceName, TAG);
}
if (mHasInput) {
mAudioService.setWiredDeviceConnectionState(
device, inputState, alsaCardDeviceString,
mDeviceName, TAG);
}
}
调用AudioService,设置设备连接状态。
AudioService
接下来分析AudioService中流程
public void setWiredDeviceConnectionState(int type, int state, String address, String name,
String caller) {
synchronized (mConnectedDevices) {
if (DEBUG_DEVICES) {
Slog.i(TAG, "setWiredDeviceConnectionState(" + state + " nm: " + name + " addr:"
+ address + ")");
}
int delay = checkSendBecomingNoisyIntent(type, state, AudioSystem.DEVICE_NONE);
queueMsgUnderWakeLock(mAudioHandler,
MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
0 /* arg1 unused */,
0 /* arg2 unused */,
new WiredDeviceConnectionState(type, state, address, name, caller),
delay);
}
}
发送Message消息,由AudioHandler处理
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
{
WiredDeviceConnectionState connectState =
(WiredDeviceConnectionState)msg.obj;
mDeviceLogger.log(new WiredDevConnectEvent(connectState));
onSetWiredDeviceConnectionState(connectState.mType, connectState.mState,
connectState.mAddress, connectState.mName, connectState.mCaller);
mAudioEventWakeLock.release();
}
break;
}
}
接着看onSetWiredDeviceConnectionState函数
private void onSetWiredDeviceConnectionState(int device, int state, String address,
String deviceName, String caller) {
synchronized (mConnectedDevices) {
if ((state == 0) && ((device & DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG) != 0)) {
setBluetoothA2dpOnInt(true, "onSetWiredDeviceConnectionState state 0");
}
if (!handleDeviceConnection(state == 1, device, address, deviceName)) {
// change of connection state failed, bailout
return;
}
//.....
}
sendDeviceConnectionIntent(device, state, address, deviceName);
updateAudioRoutes(device, state);
}
- 如果是设备拔出,则设置A2dp;
- handleDeviceConnection 处理设备连接;
- 发送广播、更新audio通路;
接着分析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) {
//连接 处理
final int res = AudioSystem.setDeviceConnectionState(device,
AudioSystem.DEVICE_STATE_AVAILABLE, address, deviceName);
if (res != AudioSystem.AUDIO_STATUS_OK) {
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处理状态,连接或者断开连接都调用此流程,只是参数不同,连接对应DEVICE_STATE_AVAILABLE。
接着看AudioSystem
AudioSystem
AudioSystem.java
public static native int setDeviceConnectionState(int device, int state,
String device_address,