藍芽耳機簡單的流程分析

來源:互聯網
上載者:User

最近在關注藍芽耳機方面的問題,做下簡單的流程分析。
解碼後,在AudioFlinger裡把音頻資料寫到裝置裡。這裡主要看看AudioFlinger,AudioPolicyManager和external/bluetooth/bluez/audio裡面的android_audio_hw.c和liba2dp.c。

在AudioPolicyManager裡有裝置串連判斷。
status_t AudioPolicyManagerBase::setDeviceConnectionState(AudioSystem::audio_devices device,
                                                  AudioSystem::device_connection_state state,
                                                  const char *device_address)
{
#ifdef WITH_A2DP
            // handle A2DP device connection
            if (AudioSystem::isA2dpDevice(device)) {
                status_t status = handleA2dpConnection(device, device_address);//這裡是執行藍芽串連
                if (status != NO_ERROR) {
                    mAvailableOutputDevices &= ~device;
                    return status;
                }
            } else
#endif
}
。。。。。
status_t AudioPolicyManagerBase::handleA2dpConnection(AudioSystem::audio_devices device,
                                                 const char *device_address)
{
    ...............
       mA2dpOutput = mpClientInterface->openOutput(&outputDesc->mDevice,
                                            &outputDesc->mSamplingRate,
                                            &outputDesc->mFormat,
                                            &outputDesc->mChannels,
                                            &outputDesc->mLatency,
                                            outputDesc->mFlags);
    if (mA2dpOutput) {
        // add A2DP output descriptor
        addOutput(mA2dpOutput, outputDesc);

        //TODO: configure audio effect output stage here

        // set initial stream volume for A2DP device
        applyStreamVolumes(mA2dpOutput, device);
        if (a2dpUsedForSonification()) {
            mDuplicatedOutput = mpClientInterface->openDuplicateOutput(mA2dpOutput, mHardwareOutput);
        }
        if (mDuplicatedOutput != 0 ||
            !a2dpUsedForSonification()) {
            // If both A2DP and duplicated outputs are open, send device address to A2DP hardware
            // interface
            AudioParameter param;
            param.add(String8("a2dp_sink_address"), String8(device_address));
            mpClientInterface->setParameters(mA2dpOutput, param.toString());
            mA2dpDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);

            if (a2dpUsedForSonification()) {
                // add duplicated output descriptor
                AudioOutputDescriptor *dupOutputDesc = new AudioOutputDescriptor();
                dupOutputDesc->mOutput1 = mOutputs.valueFor(mHardwareOutput);
                dupOutputDesc->mOutput2 = mOutputs.valueFor(mA2dpOutput);
                dupOutputDesc->mSamplingRate = outputDesc->mSamplingRate;
                dupOutputDesc->mFormat = outputDesc->mFormat;
                dupOutputDesc->mChannels = outputDesc->mChannels;
                dupOutputDesc->mLatency = outputDesc->mLatency;
                addOutput(mDuplicatedOutput, dupOutputDesc);
                applyStreamVolumes(mDuplicatedOutput, device);
            }
        } else {
    .........
}
如果只是藍芽播放,那麼mDuplicatedOutput和a2dpUsedForSonification都為0,僅執行  addOutput(mA2dpOutput, outputDesc);,走類似speaker和麥克風的流程。
如果是藍芽和speaker或麥克風同時播放聲音,走mpClientInterface->openDuplicateOutput(mA2dpOutput, mHardwareOutput);注意的是,第一個參數是mA2dpOutput,藍芽的,第二個參數是mHardwareOutput,speaker或mic等其他輸出裝置。

那麼接下來我們去看看openDuplicateOutput函數。在AudioFlinger.cpp裡有定義
int AudioFlinger::openDuplicateOutput(int output1, int output2)
{
    Mutex::Autolock _l(mLock);
    MixerThread *thread1 = checkMixerThread_l(output1);
    MixerThread *thread2 = checkMixerThread_l(output2);

    if (thread1 == NULL || thread2 == NULL) {
        LOGW("openDuplicateOutput() wrong output mixer type for output %d or %d", output1, output2);
        return 0;
    }

    int id = nextUniqueId();
    DuplicatingThread *thread = new DuplicatingThread(this, thread1, id);
    thread->addOutputTrack(thread2);
    mPlaybackThreads.add(id, thread);
    // notify client processes of the new output creation
    thread->audioConfigChanged_l(AudioSystem::OUTPUT_OPENED);
    return id;
}
這個函數開啟2個線程,一個是藍芽的,另一個是mHardwareOutput,實現兩者同時播放,比如來電,簡訊,鬧鈴聲等。
先暫停在這裡,接著
static const char *audio_interfaces[] = {
    "primary",
    "a2dp",
    "usb",
};
4.0的代碼有三種audio介面,一個是primary,是codec,我們常用的speaker,mic等;二是a2dp,是藍芽;三是usb介面。
void AudioFlinger::onFirstRef()
{
    int rc = 0;

    Mutex::Autolock _l(mLock);

    /* TODO: move all this work into an Init() function */
    mHardwareStatus = AUDIO_HW_IDLE;

    for (size_t i = 0; i < ARRAY_SIZE(audio_interfaces); i++) {
        const hw_module_t *mod;
        audio_hw_device_t *dev;

        rc = load_audio_interface(audio_interfaces[i], &mod, &dev);//載入介面.so檔案
        if (rc)
            continue;

        LOGI("Loaded %s audio interface from %s (%s)", audio_interfaces[i],
             mod->name, mod->id);
        mAudioHwDevs.push(dev);
   .........
}
這裡會遍曆audio介面。
void AudioFlinger::RecordThread::onFirstRef()
{
    run(mName, PRIORITY_URGENT_AUDIO);
}
int AudioFlinger::openOutput(uint32_t *pDevices,
                                uint32_t *pSamplingRate,
                                uint32_t *pFormat,
                                uint32_t *pChannels,
                                uint32_t *pLatencyMs,
                                uint32_t flags){

           ......
             outHwDev = findSuitableHwDev_l(*pDevices);//擷取有效audio介面裝置
    if (outHwDev == NULL)
        return 0;
   //擷取介面.so庫裡面的參數資訊
    status = outHwDev->open_output_stream(outHwDev, *pDevices, (int *)&format,
                                          &channels, &samplingRate, &outStream);
    LOGV("openOutput() openOutputStream returned output %p, SamplingRate %d, Format %d, Channels %x, status %d",
            outStream,
            samplingRate,
            format,
            channels,
            status);

    mHardwareStatus = AUDIO_HW_IDLE;
    if (outStream != NULL) {
        AudioStreamOut *output = new AudioStreamOut(outHwDev, outStream);//建立這種裝置的輸出
........
}
outHwDev->open_output_stream 來自藍芽audio裡的介面函數。
再看android_audio_hw.c
static int adev_open(const hw_module_t* module, const char* name,
                     hw_device_t** device)
{
    struct adev_a2dp *adev;
    int ret;

    if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
        return -EINVAL;

    adev = calloc(1, sizeof(struct adev_a2dp));
    if (!adev)
        return -ENOMEM;

    adev->bt_enabled = true;
    adev->suspended = false;
    pthread_mutex_init(&adev->lock, NULL);
    adev->output = NULL;

    adev->device.common.tag = HARDWARE_DEVICE_TAG;
    adev->device.common.version = 0;
    adev->device.common.module = (struct hw_module_t *) module;
    adev->device.common.close = adev_close;

    adev->device.get_supported_devices = adev_get_supported_devices;
    adev->device.init_check = adev_init_check;
    adev->device.set_voice_volume = adev_set_voice_volume;
    adev->device.set_master_volume = adev_set_master_volume;
    adev->device.set_mode = adev_set_mode;
    adev->device.set_mic_mute = adev_set_mic_mute;
    adev->device.get_mic_mute = adev_get_mic_mute;
    adev->device.set_parameters = adev_set_parameters;
    adev->device.get_parameters = adev_get_parameters;
    adev->device.get_input_buffer_size = adev_get_input_buffer_size;
    adev->device.open_output_stream = adev_open_output_stream;
    adev->device.close_output_stream = adev_close_output_stream;
    adev->device.open_input_stream = adev_open_input_stream;
    adev->device.close_input_stream = adev_close_input_stream;
    adev->device.dump = adev_dump;

    *device = &adev->device.common;

    return 0;

err_str_parms_create:
    free(adev);
    return ret;
}
這樣AudioFlinger裡需要的參數,通過這裡設定。接著藍芽audio進行相關init,config,start,stop等狀態操作。當然包括藍芽讀寫。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.