Android系统多USB mic插入机制解析

本文以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完成设备状态更新;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值