美文网首页
Android6.0----关于USB麦克风框架

Android6.0----关于USB麦克风框架

作者: JEFF_张 | 来源:发表于2018-05-17 14:09 被阅读0次

    最近遇到一个问题:插入带麦克风的USB摄像头,摄像头可以正常输出图像但是没有声音,跟踪了一下整个框架记录一下

    先从kernel入手:

    kernel/sound/usb/card.c

    当插入USB麦克风,USB Core会通过注册的usb_audio_ids 匹配到usb_audio_probe()函数

    static struct usb_device_id usb_audio_ids [] = {

    #include "quirks-table.h"

        { .match_flags = (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS),

          .bInterfaceClass = USB_CLASS_AUDIO,

          .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL },

        { } /* Terminating entry */

    };

    MODULE_DEVICE_TABLE(usb, usb_audio_ids);

    /*

    * entry point for linux usb interface

    */

    static struct usb_driver usb_audio_driver = {

    .name = "snd-usb-audio",

    .probe = usb_audio_probe,

    .disconnect = usb_audio_disconnect,

    .suspend = usb_audio_suspend,

    .resume = usb_audio_resume,

    .id_table = usb_audio_ids,

    .supports_autosuspend = 1,

    };

    static int usb_audio_probe(struct usb_interface *intf,

      const struct usb_device_id *id)

    {

    struct snd_usb_audio *chip;

    chip = snd_usb_audio_probe(interface_to_usbdev(intf), intf, id);

    if (chip) {

    usb_set_intfdata(intf, chip);

    return 0;

    } else

    return -EIO;

    }

    snd_usb_audio_probe()函数会调用snd_usb_create_quirk()

    static struct snd_usb_audio * snd_usb_audio_probe(struct usb_device *dev,struct usb_interface *intf,const struct usb_device_id *usb_id)

    {

    。。。。。。。。。。。。。。。。。。。

    if (!chip->ctrl_intf)

    chip->ctrl_intf = alts;

    chip->txfr_quirk = 0;

    err = 1; /* continue */

    if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) {

    /* need some special handlings */

    if ((err = snd_usb_create_quirk(chip, intf, &usb_audio_driver, quirk)) < 0)

    goto __error;

    }

    if (err > 0) {

    /* create normal USB audio interfaces */

    if (snd_usb_create_streams(chip, ifnum) < 0 ||

        snd_usb_create_mixer(chip, ifnum, ignore_ctl_error) < 0) {

    goto __error;

    }

    }

    /* we are allowed to call snd_card_register() many times */

    if (snd_card_register(chip->card) < 0) {

    goto __error;

    }

    。。。。。。。。。。。。。。。。。。。。。。。。。。

    }

    int snd_usb_create_quirk(struct snd_usb_audio *chip,struct usb_interface *iface,struct usb_driver *driver,const struct snd_usb_audio_quirk *quirk)

    {

    typedef int (*quirk_func_t)(struct snd_usb_audio *,

        struct usb_interface *,

        struct usb_driver *,

        const struct snd_usb_audio_quirk *);

    static const quirk_func_t quirk_funcs[] = {

    [QUIRK_IGNORE_INTERFACE] = ignore_interface_quirk,

    [QUIRK_COMPOSITE] = create_composite_quirk,

    [QUIRK_MIDI_STANDARD_INTERFACE] = create_any_midi_quirk,

    [QUIRK_MIDI_FIXED_ENDPOINT] = create_any_midi_quirk,

    [QUIRK_MIDI_YAMAHA] = create_any_midi_quirk,

    [QUIRK_MIDI_MIDIMAN] = create_any_midi_quirk,

    [QUIRK_MIDI_NOVATION] = create_any_midi_quirk,

    [QUIRK_MIDI_RAW_BYTES] = create_any_midi_quirk,

    [QUIRK_MIDI_EMAGIC] = create_any_midi_quirk,

    [QUIRK_MIDI_CME] = create_any_midi_quirk,

    [QUIRK_MIDI_AKAI] = create_any_midi_quirk,

    [QUIRK_MIDI_FTDI] = create_any_midi_quirk,

    [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk,

    [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk,

    [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk,

    [QUIRK_AUDIO_ALIGN_TRANSFER] = create_align_transfer_quirk,

    [QUIRK_AUDIO_STANDARD_MIXER] = create_standard_mixer_quirk,

    };

    if (quirk->type < QUIRK_TYPE_COUNT) {

    return quirk_funcs[quirk->type](chip, iface, driver, quirk);

    } else {

    snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type);

    return -ENXIO;

    }

    }

    static int create_uaxx_quirk(struct snd_usb_audio *chip,

        struct usb_interface *iface,

        struct usb_driver *driver,

        const struct snd_usb_audio_quirk *quirk)

    {

    。。。。。。

    err = snd_usb_add_audio_stream(chip, stream, fp);

    。。。。。。

    }

    int snd_usb_add_audio_stream(struct snd_usb_audio *chip,

        int stream,

        struct audioformat *fp)

    {

    err = snd_pcm_new(chip->card, "USB Audio", chip->pcm_devs,

      stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0,

      stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1,

      &pcm);

    }

    static int _snd_pcm_new(struct snd_card *card, const char *id, int device,

    int playback_count, int capture_count, bool internal,

    struct snd_pcm **rpcm)

    {

    struct snd_pcm *pcm;

    int err;

    static struct snd_device_ops ops = {

    .dev_free = snd_pcm_dev_free,

    .dev_register = snd_pcm_dev_register,

    .dev_disconnect = snd_pcm_dev_disconnect,

    };

    if (snd_BUG_ON(!card))

    return -ENXIO;

    if (rpcm)

    *rpcm = NULL;

    pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);

    if (pcm == NULL) {

    snd_printk(KERN_ERR "Cannot allocate PCM\n");

    return -ENOMEM;

    }

    pcm->card = card;

    pcm->device = device;

    pcm->internal = internal;

    }

    static int snd_pcm_dev_register(struct snd_device *device)

    {

    int cidx, err;

    struct snd_pcm_substream *substream;

    struct snd_pcm_notify *notify;

    char str[16];

    struct snd_pcm *pcm;

    struct device *dev;

    if (snd_BUG_ON(!device || !device->device_data))

    return -ENXIO;

    pcm = device->device_data;

    mutex_lock(®ister_mutex);

    err = snd_pcm_add(pcm);

    if (err) {

    mutex_unlock(®ister_mutex);

    return err;

    }

    for (cidx = 0; cidx < 2; cidx++) {

    int devtype = -1;

    if (pcm->streams[cidx].substream == NULL || pcm->internal)

    continue;

    switch (cidx) {

    case SNDRV_PCM_STREAM_PLAYBACK:

    sprintf(str, "pcmC%iD%ip", pcm->card->number, pcm->device);

    devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK;

    break;

    case SNDRV_PCM_STREAM_CAPTURE:

    sprintf(str, "pcmC%iD%ic", pcm->card->number, pcm->device);

    devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE;

    break;

    }

    /* device pointer to use, pcm->dev takes precedence if

    * it is assigned, otherwise fall back to card's device

    * if possible */

    dev = pcm->dev;

    if (!dev)

    dev = snd_card_get_device_link(pcm->card);

    /* register pcm */

    err = snd_register_device_for_dev(devtype, pcm->card,

      pcm->device,

      &snd_pcm_f_ops[cidx],

      pcm, str, dev);

    if (err < 0) {

    list_del(&pcm->list);

    mutex_unlock(®ister_mutex);

    return err;

    }

    snd_add_device_sysfs_file(devtype, pcm->card, pcm->device,

      &pcm_attrs);

    for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)

    snd_pcm_timer_init(substream);

    }

    list_for_each_entry(notify, &snd_pcm_notify_list, list)

    notify->n_register(pcm);

    mutex_unlock(®ister_mutex);

    return 0;

    }

    最终会在: /dev/snd/pcm*   创建出节点。

    进入framework/base/services/usb/java/com/android/server/usb/UsbAlsaManager.java

    private static final String ALSA_DIRECTORY = "/dev/snd/";

    private final FileObserver mAlsaObserver = new FileObserver(ALSA_DIRECTORY,

                FileObserver.CREATE | FileObserver.DELETE) {

            public void onEvent(int event, String path) {

                switch (event) {

                    case FileObserver.CREATE:

                        alsaFileAdded(path);

                        break;

                    case FileObserver.DELETE:

                        alsaFileRemoved(path);

                        break;

                }

            }

        };

    当/dev/snd/目录下有新的设备节点创建时调用:alsaFileAdded()

    private void alsaFileAdded(String name) {

            int type = AlsaDevice.TYPE_UNKNOWN;

            int card = -1, device = -1;

            if (name.startsWith("pcmC")) {

                if (name.endsWith("p")) {

                    type = AlsaDevice.TYPE_PLAYBACK;

                } else if (name.endsWith("c")) {

                    type = AlsaDevice.TYPE_CAPTURE;

                }

            } else if (name.startsWith("midiC")) {

                type = AlsaDevice.TYPE_MIDI;

            }

            if (type != AlsaDevice.TYPE_UNKNOWN) {

                try {

                    int c_index = name.indexOf('C');

                    int d_index = name.indexOf('D');

                    int end = name.length();

                    if (type == AlsaDevice.TYPE_PLAYBACK || type == AlsaDevice.TYPE_CAPTURE) {

                        // skip trailing 'p' or 'c'

                        end--;

                    }

                    card = Integer.parseInt(name.substring(c_index + 1, d_index));

                    device = Integer.parseInt(name.substring(d_index + 1, end));

                } catch (Exception e) {

                    Slog.e(TAG, "Could not parse ALSA file name " + name, e);

                    return;

                }

                synchronized(mAlsaDevices) {

                    if (mAlsaDevices.get(name) == null) {

                        AlsaDevice alsaDevice = new AlsaDevice(type, card, device);

                        Slog.d(TAG, "Adding ALSA device " + alsaDevice);

                        mAlsaDevices.put(name, alsaDevice);

                        mAlsaDevices.notifyAll();

                    }

                }

            }

        }

    最后会调到:usbDeviceAdded()

    void usbDeviceAdded(UsbDevice usbDevice) {

    ...................................

    ArrayList prevScanRecs = mCardsParser.getScanRecords();

    mCardsParser.scan();

    /*

    mCardsParser.scan()的时候会读取声卡生成记录系统有多少逻辑设备的文件:/proc/asound/cards

    cat  /proc/asound/cards 信息如下:

     0 [msm8939sndcards]: msm8939-snd-car - msm8939-snd-card-skuk

                                                 msm8939-snd-card-skuk

    1 [C170          ]: USB-Audio - Webcam C170

                              Webcam C170 at usb-msm_hsusb_host-1.4.1, high speed

    public void scan() {

    if (DEBUG) { Slog.i(TAG, "AlsaCardsParser.scan()"); } mCardRecords = new ArrayList();

            File cardsFile = new File(kCardsFilePath); //kCardsFilePath=/proc/asound/cards

            try {

                FileReader reader = new FileReader(cardsFile);

                BufferedReader bufferedReader = new BufferedReader(reader);

                String line = "";

                while ((line = bufferedReader.readLine()) != null) {

                    AlsaCardRecord cardRecord = new AlsaCardRecord();

                    cardRecord.parse(line, 0);

                    line = bufferedReader.readLine();

                    if (line == null) {

                        break;

                    }

                    cardRecord.parse(line, 1);

                    mCardRecords.add(cardRecord);

                }

                reader.close();

            } catch (FileNotFoundException e) {

                e.printStackTrace();

            } catch (IOException e) {

                e.printStackTrace();

            }

        }

    */

    ..................................

    if (mCardsParser.isCardUsb(addedCard)) {

                UsbAudioDevice audioDevice = selectAudioCard(addedCard);

                if (audioDevice != null) {

                    mAudioDevices.put(usbDevice, audioDevice);

                }

    ..................................

    }

    UsbAudioDevice selectAudioCard(int card) {

    ..................................

    notifyDeviceState(audioDevice, true);

    ...................................

    }

    private void notifyDeviceState(UsbAudioDevice audioDevice, boolean enabled) {

    ...........................

    // Capture Device

                if (audioDevice.mHasCapture) {

                  int device = (audioDevice == mAccessoryAudioDevice ?

                            AudioSystem.DEVICE_IN_USB_ACCESSORY :

                            AudioSystem.DEVICE_IN_USB_DEVICE);

                    mAudioService.setWiredDeviceConnectionState(

                            device, state, address, audioDevice.mDeviceName, TAG);

                }

    ...........................

    }

    frameworks/base/services/core/java/com/android/server/audio/AudioService.java

    public void setWiredDeviceConnectionState(int type, int state, String address, String name,

                String caller) {

            synchronized (mConnectedDevices) {

                int delay = checkSendBecomingNoisyIntent(type, state);

                queueMsgUnderWakeLock(mAudioHandler,

                        MSG_SET_WIRED_DEVICE_CONNECTION_STATE,

                        0,

                        0,

                        new WiredDeviceConnectionState(type, state, address, name, caller),

                        delay);

            }

        }

    public void handleMessage(Message msg) {

    ..............................

    case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:

                        {  WiredDeviceConnectionState connectState =

                                (WiredDeviceConnectionState)msg.obj;

                            onSetWiredDeviceConnectionState(connectState.mType, connectState.mState,

                                    connectState.mAddress, connectState.mName, connectState.mCaller);

                            mAudioEventWakeLock.release();

                        }

                        break;

    ..............................

    }

    private void onSetWiredDeviceConnectionState(int device, int state, String address,

                String deviceName, String caller) {

    .............................................................

    boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||

                                (((device & AudioSystem.DEVICE_BIT_IN) != 0) &&

                                ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));

                if (!handleDeviceConnection(state == 1, device, address, deviceName)) {

                    // change of connection state failed, bailout

                    return;

                }

    ............................................................

    }

    private boolean handleDeviceConnection(boolean connect, int device, String address,

                String deviceName) {

    ........................................

    if (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));

                    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;

                }

    ..........................................

    }

    frameworks/base/media/java/android/media/AudioSystem.java

    public static native int setDeviceConnectionState(int device, int state,

                                                          String device_address, String device_name);

    通过JNI调到:frameworks/base/core/jni/android_media_AudioSystem.cpp

    static jintandroid_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address, jstring device_name){ const char *c_address = env->GetStringUTFChars(device_address, NULL); const char *c_name = env->GetStringUTFChars(device_name, NULL); int status = check_AudioSystem_Command(AudioSystem::setDeviceConnectionState(static_cast(device), static_cast(state),

                                              c_address, c_name));

        env->ReleaseStringUTFChars(device_address, c_address);

        env->ReleaseStringUTFChars(device_name, c_name);

        return (jint) status;

    }

    frameworks/av/media/libmedia/AudioSystem.cpp

    status_t AudioSystem::setDeviceConnectionState(audio_devices_t device, audio_policy_dev_state_t state, const char *device_address, const char *device_name){ const sp& aps = AudioSystem::get_audio_policy_service();

        const char *address = "";

        const char *name = "";

        if (aps == 0) return PERMISSION_DENIED;

        if (device_address != NULL) {

            address = device_address;

        }

        if (device_name != NULL) {

            name = device_name;

        }

        return aps->setDeviceConnectionState(device, state, address, name);

    }

    最终调到:

    hardware\qcom\audio\policy_hal\AudioPolicyManager.cpp

    status_t AudioPolicyManagerCustom::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)) { SortedVectorinputs; ssize_t index = mAvailableInputDevices.indexOf(devDesc); switch (state) { // handle input device connection case AUDIO_POLICY_DEVICE_STATE_AVAILABLE: { if (index >= 0) { ALOGW("setDeviceConnectionState() device already connected: %d", device); return INVALID_OPERATION; } sp module = mHwModules.getModuleForDevice(device);

                if (module == NULL) {

                    ALOGW("setDeviceConnectionState(): could not find HW module for device %08x",

                          device);

                    return INVALID_OPERATION;

                }

                if (checkInputsForDevice(devDesc, state, inputs, devDesc->mAddress) != NO_ERROR) {

                    return INVALID_OPERATION;

                }

                index = mAvailableInputDevices.add(devDesc);//添加到可用输入设备列表中待选

                if (index >= 0) {

                    mAvailableInputDevices[index]->attach(module);

                } else {

                    return NO_MEMORY;

                }

                // Set connect to HALs

                AudioParameter param = AudioParameter(devDesc->mAddress);

                param.addInt(String8(AUDIO_PARAMETER_DEVICE_CONNECT), device);

                mpClientInterface->setParameters(AUDIO_IO_HANDLE_NONE, param.toString());

                // Propagate device availability to Engine

                mEngine->setDeviceConnectionState(devDesc, state);

            } break;

    ..........................................................

    }

    没有插入USB麦克风是输入设备列表LOG如下:

    APM::Devices: Device id:5 type:0x80000004:Built-In Mic, addr:

    APM::AudioPort:    Port[nm:, type:1, role:1]

    APM::Devices: Device id:6 type:0x80000080:Built-In Back Mic, addr:

    APM::AudioPort:    Port[nm:, type:1, role:1]

    APM::Devices: Device id:9 type:0x80000100:Reroute Submix In, addr:0

    APM::AudioPort:    Port[nm:, type:1, role:1]

    APM::Devices: Device id:7 type:0x80000040:Telephony Rx, addr:

    APM::AudioPort:    Port[nm:, type:1, role:1]

    APM::Devices: Device id:8 type:0x80002000:FM Tuner In, addr:

    APM::AudioPort:    Port[nm:, type:1, role:1]

    当插入USB麦克风是输入设备列表LOG如下:

    APM::Devices: Device id:5 type:0x80000004:Built-In Mic, addr:

    APM::AudioPort:    Port[nm:, type:1, role:1]

    APM::Devices: Device id:6 type:0x80000080:Built-In Back Mic, addr:

    APM::AudioPort:    Port[nm:, type:1, role:1]

    APM::Devices: Device id:9 type:0x80000100:Reroute Submix In, addr:0

    APM::AudioPort:    Port[nm:, type:1, role:1]

    APM::Devices: Device id:7 type:0x80000040:Telephony Rx, addr:

    APM::AudioPort:    Port[nm:, type:1, role:1]

    APM::Devices: Device id:8 type:0x80002000:FM Tuner In, addr:

    APM::AudioPort:    Port[nm:, type:1, role:1]

    APM::Devices: Device id:13 type:0x80001000:USB Device In, addr:card=1;device=0;

    APM::AudioPort: Port[nm:USB-Audio - Webcam C170, type:1, role:1]

    -----------------------------------------------------------------------------------------------------------------------

    当APP通过:audioRecord =new AudioRecord(MediaRecorder.AudioSource.MIC, frequency,

            channelConfiguration, audioEncoding, recBufSize);

             audioRecord.startRecording();

    最终会转到

    status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,

                                                audio_io_handle_t *input,

                                                audio_session_t session,

                                                uid_t uid,

                                                uint32_t samplingRate,

                                                audio_format_t format,

                                                audio_channel_mask_t channelMask,

                                                audio_input_flags_t flags,

                                                audio_port_handle_t selectedDeviceId,

                                                input_type_t *inputType)

    {

    。。。。。。。。。。。。。。。

    //根据输入源类型我们在app中选择的是inputSource=MediaRecorder.AudioSource.MIC

    device = getDeviceAndMixForInputSource(inputSource, &policyMix);

    。。。。。。。

    }

    audio_devices_t AudioPolicyManager::getDeviceAndMixForInputSource(audio_source_t inputSource,AudioMix **policyMix)

    {

        audio_devices_t availableDeviceTypes = mAvailableInputDevices.types() & ~AUDIO_DEVICE_BIT_IN;

        audio_devices_t selectedDeviceFromMix =

              mPolicyMixes.getDeviceAndMixForInputSource(inputSource, availableDeviceTypes, policyMix);

        if (selectedDeviceFromMix != AUDIO_DEVICE_NONE) {

            return selectedDeviceFromMix;

        }

        return getDeviceForInputSource(inputSource);

    }

    audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t inputSource){ for (size_t routeIndex = 0; routeIndex < mInputRoutes.size(); routeIndex++) { sp route = mInputRoutes.valueAt(routeIndex);

            if (inputSource == route->mSource && route->isActive()) {

                return route->mDeviceDescriptor->type();

            }

        }

        return mEngine->getDeviceForInputSource(inputSource);

    }

    audio_devices_t Engine::getDeviceForInputSource(audio_source_t inputSource) const

    {

    。。。。。。。。。。。

    switch (inputSource) {

        case AUDIO_SOURCE_VOICE_UPLINK:

          if (availableDeviceTypes & AUDIO_DEVICE_IN_VOICE_CALL) {

              device = AUDIO_DEVICE_IN_VOICE_CALL;

              break;

          }

          break;

        case AUDIO_SOURCE_DEFAULT:

        case AUDIO_SOURCE_MIC:

        if (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) {

            device = AUDIO_DEVICE_IN_BLUETOOTH_A2DP;

        } else if ((mForceUse[AUDIO_POLICY_FORCE_FOR_RECORD] == AUDIO_POLICY_FORCE_BT_SCO) &&

            (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET)) {

            device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;

        } else if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {

            device = AUDIO_DEVICE_IN_WIRED_HEADSET;

        } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {

            device = AUDIO_DEVICE_IN_USB_DEVICE;

        } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {

            device = AUDIO_DEVICE_IN_BUILTIN_MIC;

        }

        break;

    。。。。。。。。

    }

    从次可以看出系统选择麦克风的优先顺序

    相关文章

      网友评论

          本文标题:Android6.0----关于USB麦克风框架

          本文链接:https://www.haomeiwen.com/subject/xloudftx.html