Android Audio Patch
1. Audio Patch 概述
Audio Patch 是 Android 音频系统中用于表示音频源(source)与目标(sink)之间连接关系的机制。它允许在音频系统中创建灵活的连接路径,支持:
• 将音频流从一个或多个源路由到一个或多个目标
• 实现设备间的音频桥接
• 支持复杂的音频路由场景
2. Audio Patch 核心结构体
2.1 audio_patch 结构体
struct audio_patch {audio_patch_handle_t id; // 唯一IDunsigned int num_sources; // 源数量struct audio_port_config sources[AUDIO_PATCH_PORTS_MAX]; // 源配置数组unsigned int num_sinks; // 目标数量struct audio_port_config sinks[AUDIO_PATCH_PORTS_MAX]; // 目标配置数组
};
2.2 audio_port_config 结构体
struct audio_port_config {audio_port_handle_t id; // 端口唯一IDaudio_port_role_t role; // 源或目标audio_port_type_t type; // 设备类型unsigned int config_mask; // 配置掩码unsigned int sample_rate; // 采样率audio_channel_mask_t channel_mask; // 声道掩码audio_format_t format; // 音频格式struct audio_gain_config gain; // 增益配置union {struct audio_port_config_device_ext device; // 设备特定信息struct audio_port_config_mix_ext mix; // 混音特定信息struct audio_port_config_session_ext session; // 会话特定信息} ext;
};
3.核心函数
PatchPanel::createAudioPatch_l
1. 创建新的音频通路:
• 支持设备到设备、设备到混音、混音到设备等多种通路类型
• 处理硬件直接连接和软件桥接两种连接方式
2. 管理通路生命周期:
• 验证输入参数有效性
• 处理通路更新(释放旧通路资源)
• 创建新通路并添加到管理结构
• 处理失败时的资源清理
3. 软件桥接处理:
• 当硬件不支持直接连接时(跨模块或HAL不支持)
• 创建输入/输出线程和特殊轨道
• 在软件层实现音频数据传输
4. 特殊场景支持:
• 处理电话通话等特殊场景的配置
• 管理插入式音频模块(如DSP效果器)
• 优化延迟和性能(快速轨道等)
5.调用关系
被调用:
-
外部接口:
• AudioFlinger::createAudioPatch() 公共接口• AudioPolicyService 通过 binder 调用
-
内部递归调用:
• Patch::createConnections_l() 中调用,用于创建软件桥接的子通路• 处理通路更新时,先调用自身移除旧通路
调用:
-
硬件抽象层 (HAL):
• DeviceHalInterface::createAudioPatch() 创建硬件通路• DeviceHalInterface::releaseAudioPatch() 释放硬件通路
-
线程管理:
• IAfThreadBase::sendCreateAudioPatchConfigEvent() 通知线程创建配置• IAfThreadBase::sendReleaseAudioPatchConfigEvent() 通知线程释放配置
• openOutput_l() / openInput_l() 创建新线程
• checkPlaybackThread_l() / checkRecordThread_l() 检查线程存在
-
通路管理:
• Patch::createConnections_l() 创建软件桥接• Patch::clearConnections_l() 清理软件桥接资源
• erasePatch() 移除通路
-
资源管理:
• PatchCommandThread::createAudioPatch() / updateAudioPatch() 管理设备效果• addSoftwarePatchToInsertedModules_l() 管理插入式模块
6.函数分析
status_t PatchPanel::createAudioPatch_l(const struct audio_patch* patch,audio_patch_handle_t *handle,bool endpointPatch)
{// 参数有效性检查if (handle == NULL || patch == NULL) {return BAD_VALUE;}// 记录日志显示通路详情ALOGV("%s() num_sources %d num_sinks %d handle %d",__func__, patch->num_sources, patch->num_sinks, *handle);status_t status = NO_ERROR;audio_patch_handle_t halHandle = AUDIO_PATCH_HANDLE_NONE;// 验证通路结构有效性if (!audio_patch_is_valid(patch) || (patch->num_sinks == 0 && patch->num_sources != 2)) {return BAD_VALUE;}// 限制源数量(当前最多2个源)if (patch->num_sources > 2) {return INVALID_OPERATION;}bool reuseExistingHalPatch = false; // 标记是否重用现有的HAL通路audio_patch_handle_t oldhandle = AUDIO_PATCH_HANDLE_NONE;// 处理通路更新:移除现有通路if (*handle != AUDIO_PATCH_HANDLE_NONE) {auto iter = mPatches.find(*handle);if (iter != mPatches.end()) {ALOGV("%s() removing patch handle %d", __func__, *handle);Patch &removedPatch = iter->second;// 1. 如果是软件通路,释放相关资源if (removedPatch.isSoftware()) {removedPatch.clearConnections_l(this);}// 2. 如果新旧通路设备模块不同,释放HAL通路if (removedPatch.mHalHandle != AUDIO_PATCH_HANDLE_NONE) {audio_module_handle_t hwModule = AUDIO_MODULE_HANDLE_NONE;const struct audio_patch &oldPatch = removedPatch.mAudioPatch;oldhandle = *handle;// 检查是否需要释放HAL通路if (oldPatch.sources[0].type == AUDIO_PORT_TYPE_DEVICE &&(patch->sources[0].type != AUDIO_PORT_TYPE_DEVICE ||oldPatch.sources[0].ext.device.hw_module !=patch->sources[0].ext.device.hw_module)) {hwModule = oldPatch.sources[0].ext.device.hw_module;} else if (patch->num_sinks == 0 ||(oldPatch.sinks[0].type == AUDIO_PORT_TYPE_DEVICE &&(patch->sinks[0].type != AUDIO_PORT_TYPE_DEVICE ||oldPatch.sinks[0].ext.device.hw_module !=patch->sinks[0].ext.device.hw_module))) {hwModule = oldPatch.sinks[0].ext.device.hw_module;}// 释放HAL通路sp<DeviceHalInterface> hwDevice = findHwDeviceByModule_l(hwModule);if (hwDevice != 0) {hwDevice->releaseAudioPatch(removedPatch.mHalHandle);}halHandle = removedPatch.mHalHandle;// 检查是否可以重用现有HAL通路reuseExistingHalPatch = (hwDevice == 0) && patchesHaveSameRoute(*patch, oldPatch);}// 移除旧通路erasePatch(*handle, reuseExistingHalPatch);}}// 创建新通路对象Patch newPatch{*patch, endpointPatch};audio_module_handle_t insertedModule = AUDIO_MODULE_HANDLE_NONE;// 根据源类型处理不同情况switch (patch->sources[0].type) {case AUDIO_PORT_TYPE_DEVICE: {audio_module_handle_t srcModule = patch->sources[0].ext.device.hw_module;AudioHwDevice *audioHwDevice = findAudioHwDeviceByModule_l(srcModule);if (!audioHwDevice) {status = BAD_VALUE;goto exit;}// 检查每个目的的有效性for (unsigned int i = 0; i < patch->num_sinks; i++) {// 对混音或跨模块连接,只支持一个目的if ((patch->sinks[i].type == AUDIO_PORT_TYPE_MIX ||(patch->sinks[i].type == AUDIO_PORT_TYPE_DEVICE &&patch->sinks[i].ext.device.hw_module != srcModule)) &&patch->num_sinks > 1) {ALOGW("%s() multiple sinks for mix or across modules not supported", __func__);status = INVALID_OPERATION;goto exit;}// 拒绝连接不同类型的目的if (patch->sinks[i].type != patch->sinks[0].type) {ALOGW("%s() different sink types in same patch not supported", __func__);status = BAD_VALUE;goto exit;}}// 处理需要软件桥接的情况if ((patch->num_sources == 2) ||((patch->sinks[0].type == AUDIO_PORT_TYPE_DEVICE) &&((patch->sinks[0].ext.device.hw_module != srcModule) ||!audioHwDevice->supportsAudioPatches()))) {// 准备输出设备信息audio_devices_t outputDevice = patch->sinks[0].ext.device.type;String8 outputDeviceAddress = String8(patch->sinks[0].ext.device.address);// 处理特殊情况:2个源(重用现有输出混音)if (patch->num_sources == 2) {if (patch->sources[1].type != AUDIO_PORT_TYPE_MIX ||(patch->num_sinks != 0 && patch->sinks[0].ext.device.hw_module !=patch->sources[1].ext.mix.hw_module)) {ALOGW("%s() invalid source combination", __func__);status = INVALID_OPERATION;goto exit;}// 获取现有播放线程const sp<IAfThreadBase> thread = mAfPatchPanelCallback->checkPlaybackThread_l(patch->sources[1].ext.mix.handle);if (thread == 0) {ALOGW("%s() cannot get playback thread", __func__);status = INVALID_OPERATION;goto exit;}// 重用现有播放线程newPatch.mPlayback.setThread(thread->asIAfPlaybackThread().get(), false /*closeThread*/);} else {// 创建新的输出配置audio_config_t config = AUDIO_CONFIG_INITIALIZER;audio_config_base_t mixerConfig = AUDIO_CONFIG_BASE_INITIALIZER;audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE;// 从目的配置中获取参数if (patch->sinks[0].config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {config.sample_rate = patch->sinks[0].sample_rate;}if (patch->sinks[0].config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {config.channel_mask = patch->sinks[0].channel_mask;}if (patch->sinks[0].config_mask & AUDIO_PORT_CONFIG_FORMAT) {config.format = patch->sinks[0].format;}if (patch->sinks[0].config_mask & AUDIO_PORT_CONFIG_FLAGS) {flags = patch->sinks[0].flags.output;}// 打开新的输出线程audio_attributes_t attributes = AUDIO_ATTRIBUTES_INITIALIZER;const sp<IAfThreadBase> thread = mAfPatchPanelCallback->openOutput_l(patch->sinks[0].ext.device.hw_module,&output,&config,&mixerConfig,outputDevice,outputDeviceAddress,&flags,attributes);ALOGV("mAfPatchPanelCallback->openOutput_l() returned %p", thread.get());if (thread == 0) {status = NO_MEMORY;goto exit;}newPatch.mPlayback.setThread(thread->asIAfPlaybackThread().get());}// 准备输入设备信息audio_devices_t device = patch->sources[0].ext.device.type;String8 address = String8(patch->sources[0].ext.device.address);audio_config_t config = AUDIO_CONFIG_INITIALIZER;// 从源配置中获取参数或使用默认值if (patch->sources[0].config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {config.sample_rate = patch->sources[极客时间0].sample_rate;} else {config.sample_rate = newPatch.mPlayback.thread()->sampleRate();}if (patch->sources[0].config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {config.channel_mask = patch->sources[0].channel_mask;} else {config.channel_mask = audio_channel_in_mask_from_count(newPatch.mPlayback.thread()->channelCount());}if (patch->sources[0].config_mask & AUDIO_PORT_CONFIG_FORMAT) {config.format = patch->sources[0].format;} else {config.format = newPatch.mPlayback.thread()->format();}// 设置输入标志audio_input_flags_t flags =patch->sources[0].config_mask & AUDIO_PORT_CONFIG_FLAGS ?patch->sources[0].flags.input : AUDIO_INPUT_FLAG_NONE;// 处理电话通话特殊情况audio_source_t source = AUDIO_SOURCE_MIC;if (patch->num_sources == 2&& patch->sources[1].ext.mix.usecase.stream== AUDIO_STREAM_VOICE_CALL) {source = AUDIO_SOURCE_VOICE_COMMUNICATION;}// 打开输入线程audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;const sp<IAfThreadBase> thread = mAfPatchPanelCallback->openInput_l(srcModule,&input,&config,device,address,source,flags,outputDevice,outputDeviceAddress);ALOGV("mAfPatchPanelCallback->openInput_l() returned %p inChannelMask %08x",thread.get(), config.channel_mask);if (thread == 0) {status = NO_MEMORY;goto exit;}newPatch.mRecord.setThread(thread->asIAfRecordThread().get());// 创建软件桥接连接status = newPatch.createConnections_l(this);if (status != NO_ERROR) {goto exit;}// 如果是插入式模块,记录模块句柄if (audioHwDevice->isInsert()) {insertedModule = audioHwDevice->handle();}} else {// 处理不需要软件桥接的情况if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) {// 获取录音线程sp<IAfThreadBase> thread = mAfPatchPanelCallback->checkRecordThread_l(patch->sinks[0].ext.mix.handle);if (thread == 0) {thread = mAfPatchPanelCallback->checkMmapThread_l(patch->sinks[0].ext.mix.handle);if (thread == 0) {ALOGW("%s() bad capture I/O handle %d",__func__, patch->sinks[0].ext.mix.handle);status = BAD_VALUE;goto exit;}}// 发送创建音频配置事件mAfPatchPanelCallback->mutex().unlock();status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle);mAfPatchPanelCallback->mutex().lock();if (status == NO_ERROR) {newPatch.setThread(thread);}// 移除相同输入作为汇的旧音频通路for (auto& iter : mPatches) {if (iter.second.mAudioPatch.sinks[0].ext.mix.handle == thread->id()) {erasePatch(iter.first);break;}}} else {// 直接创建HAL音频通路sp<DeviceHalInterface> hwDevice = audioHwDevice->hwDevice();status = hwDevice->createAudioPatch(patch->num_sources,patch->sources,patch->num_sinks,patch->sinks,&halHandle);if (status == INVALID_OPERATION) goto exit;}}} break;case AUDIO_PORT_TYPE_MIX: {// 处理混音源的情况audio_module_handle_t srcModule = patch->sources[0].ext.mix.hw_module;ssize_t index = mAfPatchPanelCallback->getAudioHwDevs_l().indexOfKey(srcModule);if (index < 0) {ALOGW("%s() bad src hw module %d", __func__, srcModule);status = BAD_VALUE;goto exit;}// 准备设备描述符DeviceDescriptorBaseVector devices;for (unsigned int i = 0; i < patch->num_sinks; i++) {if (patch->sinks[i].type != AUDIO_PORT_TYPE_DEVICE) {ALOGW("%s() invalid sink type %d for mix source",__func__, patch->sinks[i].type);status = BAD_VALUE;goto exit;}// 限制汇和源必须在同一硬件模块上if (patch->sinks[i].ext.device.hw_module != srcModule) {status = BAD_VALUE;goto exit;}// 创建设备描述符sp<DeviceDescriptorBase> device = new DeviceDescriptorBase(patch->sinks[i].ext.device.type);device->setAddress(patch->sinks[i].ext.device.address);device->applyAudioPortConfig(&patch->sinks[i]);devices.push_back(device);}// 获取播放线程sp<IAfThreadBase> thread = mAfPatchPanelCallback->checkPlaybackThread_l(patch->sources[0].ext.mix.handle);if (thread == 0) {thread = mAfPatchPanelCallback->checkMmapThread_l(patch->sources[0].ext.mix.handle);if (thread == 0) {ALOGW("%s() bad playback I/O handle %d",__func__, patch->sources[0].ext.mix.handle);status = BAD_VALUE;goto exit;}}// 如果是主播放线程,更新录音线程的输出设备if (thread == mAfPatchPanelCallback->primaryPlaybackThread_l()) {mAfPatchPanelCallback->updateOutDevicesForRecordThreads_l(devices);}// 对于端点通路,检查是否可以重用现有HAL通路if (endpointPatch) {for (auto& p : mPatches) {if (!p.second.mIsEndpointPatch && patchesHaveSameRoute(newPatch.mAudioPatch, p.second.mAudioPatch)) {ALOGV("%s() Sw Bridge endpoint reusing halHandle=%d", __func__,p.second.mHalHandle);halHandle = p.second.mHalHandle;reuseExistingHalPatch = true;break;}}}// 发送创建音频配置事件mAfPatchPanelCallback->mutex().unlock();status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle);m极客时间AfPatchPanelCallback->mutex().lock();if (status == NO_ERROR) {newPatch.setThread(thread);}// 移除相同输出作为源的旧音频通路if (!endpointPatch) {for (auto& iter : mPatches) {if (iter.second.mAudioPatch.sources[0].ext.mix.handle == thread->id() &&!iter.second.mIsEndpointPatch) {erasePatch(iter.first);break;}}}} break;default:status = BAD_VALUE;goto exit;}exit:ALOGV("%s() status %d", __func__, status);// 如果创建成功,分配新句柄并存储通路if (status == NO_ERROR) {*handle = static_cast<audio_patch_handle_t>(mAfPatchPanelCallback->nextUniqueId(AUDIO_UNIQUE_ID_USE_PATCH));newPatch.mHalHandle = halHandle;// 处理设备效果:// - 跳过软件桥接(效果由端点通路持有)// - 跳过端点重用HAL通路的情况if (!(newPatch.isSoftware()|| (endpointPatch && reuseExistingHalPatch))) {if (reuseExistingHalPatch) {// 更新音频通路(HAL通路重用)mAfPatchPanelCallback->getPatchCommandThread()->updateAudioPatch(oldhandle, *handle, newPatch);} else {// 创建新的音频通路mAfPatchPanelCallback->getPatchCommandThread()->createAudioPatch(*handle, newPatch);}}// 如果是插入式模块,添加软件通路到模块跟踪if (insertedModule != AUDIO_MODULE_HANDLE_NONE) {addSoftwarePatchToInsertedModules_l(insertedModule, *handle, &newPatch.mAudioPatch);}// 存储新通路mPatches.insert(std::make_pair(*handle, std::move(newPatch)));} else {// 失败时清理资源newPatch.clearConnections_l(this);}return status;
}