总结下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 基本流程也就出来了