本文以Android11 源码为基础,详细讲解USB mic的插入处理流程。解释当遇到系统同时插入两个USB MIC,为什么会选择后插入的设备。阅读代码是从底层往上层追,为了方便书写从上层往下介绍:
frameworks\base\services\usb\java\com\android\server\usb\UsbHostManager.java
usbDeviceAdded-->mUsbAlsaManager.usbDeviceAdded
frameworks\base\services\usb\java\com\android\server\usb\UsbAlsaManager.java
关键函数:usbDeviceAdded
Java
void usbDeviceAdded(String deviceAddress, UsbDevice usbDevice,
UsbDescriptorParser parser) {
...
// Scan the Alsa File Space
mCardsParser.scan() ; //扫描声卡
// Find the ALSA spec for this device address
//根据传进来的deviceAddress 确认声卡是否存在和获取声卡
AlsaCardsParser.AlsaCardRecord cardRec =
mCardsParser.findCardNumFor(deviceAddress);
if (cardRec == null) {
return;
}
// Add it to the devices list
//判断是输入还是输出设备
boolean hasInput = parser.hasInput()
&& !isDeviceBlacklisted(usbDevice.getVendorId(), usbDevice.getProductId(),
USB_BLACKLIST_INPUT);
boolean hasOutput = parser.hasOutput()
&& !isDeviceBlacklisted(usbDevice.getVendorId(), usbDevice.getProductId(),
USB_BLACKLIST_OUTPUT);
if (DEBUG) {
Slog.d(TAG, "hasInput: " + hasInput + " hasOutput:" + hasOutput);
}
...
//根据得到的数据,创建alsaDevice
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); //将alsaDevice添加到一个全局的list中
selectAlsaDevice (alsaDevice); //选择此设备
}
}
// look for MIDI devices
...
}
关键函数selectAlsaDevice:
Java
private synchronized void selectAlsaDevice(UsbAlsaDevice alsaDevice) {
// This must be where an existing USB audio device is deselected.... (I think)
//如果当前已经存在一个声卡设备,就将其删除,这一点很重要,这就是为啥应用这能获取到一直有一个mic的原因。
if (mIsSingleMode && mSelectedDevice != null) {
deselectAlsaDevice (); //这里调用删除alsaDevice,最终会调用到UsbAlsaDevice.java中的stop
}
...
mSelectedDevice = alsaDevice; //mSelectedDevice 全局的一个被选中的alsaDevice
alsaDevice.start (); //会调用到UsbAlsaDevice.java中的start
if (DEBUG) {
Slog.d(TAG, "selectAlsaDevice() - done.");
}
}
上文讲到最终会调用到selectAlsaDevice中的start 和stop ,都会执行updateWiredDeviceConnectionState函数
frameworks\base\services\usb\java\com\android\server\usb\UsbAlsaDevice.java
Java
public synchronized void updateWiredDeviceConnectionState(boolean enable) {
// Output Device
if (mHasOutput) {
...
mAudioService.setWiredDeviceConnectionState (device, outputState,
alsaCardDeviceString,
mDeviceName, TAG);
}
// Input Device
if (mHasInput) {
...
mAudioService.setWiredDeviceConnectionState (
device, inputState, alsaCardDeviceString,
mDeviceName, TAG);
}
...
}
所以在USB alsa 中最后调用到AudioService的setWiredDeviceConnectionState
这个函数的实现是在frameworks\base\services\core\java\com\android\server\audio目录下的AudioDeviceInventory.java和AudioDeviceBroker.java 文件中,他们之前相互调用,这里会有点绕;然后会执行到
handleDeviceConnection:
Java
boolean handleDeviceConnection(boolean connect, int device, String address,
String deviceName) {
...
if (connect && !isConnected) {
final int res = mAudioSystem.setDeviceConnectionState (device,
AudioSystem.DEVICE_STATE_AVAILABLE, address, deviceName,
AudioSystem.AUDIO_FORMAT_DEFAULT);
...
} else if (!connect && isConnected) {
mAudioSystem.setDeviceConnectionState (device,
AudioSystem.DEVICE_STATE_UNAVAILABLE, address, deviceName,
AudioSystem.AUDIO_FORMAT_DEFAULT);
// always remove even if disconnection failed
}
...
}
frameworks\base\services\core\java\com\android\server\audio\AudioSystemAdapter.cpp
setDeviceConnectionState->AudioSystem.setDeviceConnectionState(...)
在AudioService中通过JIN调用如下cpp
frameworks\av\media\libaudioclient\AudioSystem.cpp
setDeviceConnectionState
frameworks\av\services\audiopolicy\managerdefault\AudioPolicyManager.cpp:
setDeviceConnectionState
setDeviceConnectionStateInt
setDeviceConnectionStateInt 分别对输入输出设备插入(AUDIO_POLICY_DEVICE_STATE_AVAILABLE)和拔出(AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE)进行处理
Java
// handle output devices
if (audio_is_output_device(device->type())) {
...
switch (state)
{
// handle output device connection
case AUDIO_POLICY_DEVICE_STATE_AVAILABLE: {
...
// handle output device disconnection
case AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE: {
...
}
// handle input devices
if (audio_is_input_device(device->type())) {
...
switch (state)
{
// handle input device connection
case AUDIO_POLICY_DEVICE_STATE_AVAILABLE: {
mAvailableInputDevices.add(device)
...
// handle input device disconnection
case AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE: {
mAvailableInputDevices.remove(device)
...
}
最终由AudioPolecyManager完成设备状态更新;