Android Audio special Introduction2 -- ICS A2DP Control

总结下ICS下,A2DP是如何工作的。


依旧默认读者了解音频基本架构。从很久以前,Android 就利用setDeviceConnectionState来切换Android 系统的音频外设切换状况。

故事就从这个函数开始将起。


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


status_t AudioPolicyManagerBase::setDeviceConnectionState(AudioSystem::audio_devices device,
                                                  AudioSystem::device_connection_state state,
                                                  const char *device_address)
{
//非A2DP内容就此省略
    

//如果不支持,直接退出
#ifndef WITH_A2DP
        if (AudioSystem::isA2dpDevice(device)) {
            LOGE("setDeviceConnectionState() invalid device: %x", device);
            return BAD_VALUE;
        }
#endif


        switch (state)
        {
        // handle output device connection
        case AudioSystem::DEVICE_STATE_AVAILABLE:
            if (mAvailableOutputDevices & device) {
                LOGW("setDeviceConnectionState() device already connected: %x", device);
                return INVALID_OPERATION;
            }
            LOGV("setDeviceConnectionState() connecting device %x", device);


            // register new device as available
            mAvailableOutputDevices |= device;


#ifdef WITH_A2DP

如果是A2DP设备,第一个需要分析的就是 handleA2dpConnection(device, device_address);
            // 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
            {
                if (AudioSystem::isBluetoothScoDevice(device)) {
                    LOGV("setDeviceConnectionState() BT SCO  device, address %s", device_address);
                    // keep track of SCO device address
                    mScoDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
                }
            }
            break;

。。。
}

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

进入正题,从 handleA2dpConnection(device, device_address)开始。


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

status_t AudioPolicyManagerBase::handleA2dpConnection(AudioSystem::audio_devices device,
                                                 const char *device_address)
{
    // when an A2DP device is connected, open an A2DP and a duplicated output
    LOGV("opening A2DP output for device %s", device_address);
    AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor();
    outputDesc->mDevice = device;
    mA2dpOutput = mpClientInterface->openOutput(&outputDesc->mDevice,
                                            &outputDesc->mSamplingRate,
                                            &outputDesc->mFormat,
                                            &outputDesc->mChannels,
                                            &outputDesc->mLatency,
                                            outputDesc->mFlags);

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

}

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

熟悉吧,大名鼎鼎的openOutput.  提到这,就要说说mpClientInterface是从哪来的了。在第一篇文章里,讲到了

AudioPolicy --> audio_policy_legacy_hal -> AudioPolicyManager --> AudioPolicyManagerBase --> policyclient --> AudioPolicy

上次用了很多篇幅讲这个过程,其实绕了一圈,真正的实现还是在AudioPolicy里。 这次就不再重复了。

 mpClientInterface->openOutput 调用的是

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

static audio_io_handle_t aps_open_output(void *service,
                                             uint32_t *pDevices,
                                             uint32_t *pSamplingRate,
                                             uint32_t *pFormat,
                                             uint32_t *pChannels,
                                             uint32_t *pLatencyMs,
                                             audio_policy_output_flags_t flags)
{
    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
    if (af == NULL) {
        LOGW("%s: could not get AudioFlinger", __func__);
        return 0;
    }
    return af->openOutput(pDevices, pSamplingRate, pFormat, pChannels,
                          pLatencyMs, flags);
}

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

最终还是AudioFlinger 在干活。。

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

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);
    if (outHwDev == NULL)
        return 0;


    status = outHwDev->open_output_stream(outHwDev, *pDevices, (int *)&format,
                                          &channels, &samplingRate, &outStream);

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

这不,调到了audio hardware层的实现了吧。

这里要先看下 findSuitableHwDev_l(*pDevices); 说道这,就要从头讲讲这些设备是怎么来的了

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

void AudioFlinger::onFirstRef()
{

    // 遍历所有音频设备,也就是每个动态库

    for (size_t i = 0; i < ARRAY_SIZE(audio_interfaces); i++) {
        
        rc = load_audio_interface(audio_interfaces[i], &mod, &dev);
        if (rc)
            continue;
        // 将找到的设备放到mAudioHwDevs存好
        mAudioHwDevs.push(dev);
        }
    }
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

这个函数是AudioFlinger 第一次运行时调用的。

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

audio_hw_device_t* AudioFlinger::findSuitableHwDev_l(uint32_t devices)
{
    /* first matching HW device is returned */
    for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
        audio_hw_device_t *dev = mAudioHwDevs[i];
        if ((dev->get_supported_devices(dev) & devices) == devices)
            return dev;
    }
    return NULL;
}

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

然后搜索全部节点,调用每个module的一个接口get_supported_devices。 我们可以通过这个接口,控制不同module对应不同的devices.

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

static uint32_t adev_get_supported_devices(const struct audio_hw_device *dev)
{
    return AUDIO_DEVICE_OUT_ALL_A2DP;
}

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

这个是专门定义在A2DP里的module提供的external/bluetooth/bluez/audio/android_audio_hw.c

好吧,我们找到了对应A2DP的module, 可以接着往下看了

    status = outHwDev->open_output_stream(outHwDev, *pDevices, (int *)&format,
                                          &channels, &samplingRate, &outStream);

让我们来研究下A2DP 是怎么open output stream的吧

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

static int adev_open_output_stream(struct audio_hw_device *dev,
                                   uint32_t devices, int *format,
                                   uint32_t *channels, uint32_t *sample_rate,
                                   struct audio_stream_out **stream_out)
{

....
    int err = pthread_create(&out->buf_thread, (const pthread_attr_t *) NULL, _out_buf_thread_func, out);
....
}

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

啊,又开了个线程,这是可跟正常的放音设备不一样了

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

static void *_out_buf_thread_func(void *context)
{
    while(!out->buf_thread_exit) {
        size_t frames;

        // 检查有没有新的数据写入
        frames = _out_frames_ready_locked(out);
        while (frames && !out->buf_thread_exit) {
            int retries = MAX_WRITE_RETRIES;
            uint64_t now;
            uint32_t elapsed_us;


            while (frames > 0 && !out->buf_thread_exit) {
            ....

                ret = a2dp_write(out->data, out->buf + out->buf_rd_idx, bytes);
            .....

            }

         }
}

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

终于到了bluez,  a2dp_write经典的写入函数

在A2DP 设备连接上时,在底部就已经开了个线程,等着写数据到bluez了。到这,A2DP 基本流程也就出来了


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值