AudioPatch中有篇文章分析的蛮好的,链接在这儿
但是针对高通平台(例如MSM8953/SDM660等)其实是不支持的AudioPatch的,原因如下:
frameworks\av\services\audioflinger\Threads.cpp
status_t AudioFlinger::PlaybackThread::createAudioPatch_l(const struct audio_patch *patch,
audio_patch_handle_t *handle)
{
...
if (mOutput->audioHwDev->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
audio_hw_device_t *hwDevice = mOutput->audioHwDev->hwDevice();
status = hwDevice->create_audio_patch(hwDevice,
patch->num_sources,
patch->sources,
patch->num_sinks,
patch->sinks,
handle);
} else {
char *address;
if (strcmp(patch->sinks[0].ext.device.address, "") != 0) {
//FIXME: we only support address on first sink with HAL version < 3.0
address = audio_device_address_to_parameter(
patch->sinks[0].ext.device.type,
patch->sinks[0].ext.device.address);
} else {
address = (char *)calloc(1, 1);
}
AudioParameter param = AudioParameter(String8(address));
free(address);
param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), (int)type);
status = mOutput->stream->common.set_parameters(&mOutput->stream->common,
param.toString().string());
*handle = AUDIO_PATCH_HANDLE_NONE;
}
if (configChanged) {
mPrevOutDevice = type;
sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED);
}
...
}
如上AudioPatch只对AUDIO_DEVICE_API_VERSION_3_0
以上的版本做支持,我们看看高通的版本号是多少
hardware\qcom\audio\hal\Audio_hw.c
static int adev_open(const hw_module_t *module, const char *name,
hw_device_t **device)
{
...
adev->device.common.tag = HARDWARE_DEVICE_TAG;
adev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
adev->device.common.module = (struct hw_module_t *)module;
adev->device.common.close = adev_close;
...
}
如上我们发现高通的版本号是AUDIO_DEVICE_API_VERSION_2_0
,其低于AudioPatch要求的版本号,因此并不支持。AudioPolicy下发的AudioPatch会在AudioFlinger中转化为set_parameters向Hal下发。
hardware\qcom\audio\hal\Audio_hw.c
static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
{
struct stream_out *out = (struct stream_out *)stream;
struct audio_device *adev = out->dev;
struct str_parms *parms;
char value[32];
int ret = 0, val = 0, err;
ALOGE("%s: enter: usecase(%d: %s) kvpairs: %s",
__func__, out->usecase, use_case_table[out->usecase], kvpairs);
...
}
关于这里的传入参数做下说明:
关于第一个参数
out->usecase:来自于audiofinger的openOutputStream方法,调用路径请查看:音频输出设备是如何决定的,需要注意的是每条音频路径的openOutputStream只会在APS初始化的时候调用一次,之后音频播放的时候不会再次调用,它会传递到Audio_hw.c的adev_open_output_stream
} else if (out->devices == AUDIO_DEVICE_OUT_TELEPHONY_TX) {
...
out->usecase = USECASE_AUDIO_PLAYBACK_AFE_PROXY;
如上Hal会根据传入设备的类型来决定usecase的值。
关于第二个参数
kvpairs来自于上文提到的createAudioPatch_l
,注意下面这个字段:
param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), (int)type);
在APS初始化的时候,会将系统可用音频路径的PlaybackThread创建好(offload的除外),在这个过程中也会调用可用音频路径的默认输出设备(一般是Speaker,Voice的是听筒)的setOutputDevice,从而为每条可用音频路径设置默认的路由。
因此,APS初始化后,会打出如下Log:
01-27 05:26:07.504 4588 4588 E APM_AudioPolicyManager: Jon,deviceList size = 1
01-27 05:26:07.506 4588 4595 E AudioFlinger: Jon,address =
01-27 05:26:07.506 4588 4595 E audio_hw_primary: out_set_parameters: Jon, enter: usecase(1: low-latency-playback) kvpairs: routing=2
01-27 05:26:07.518 4588 4588 E APM_AudioPolicyManager: Jon,deviceList size = 1
01-27 05:26:07.519 4588 4597 E AudioFlinger: Jon,address =
01-27 05:26:07.520 4588 4597 E audio_hw_primary: out_set_parameters: Jon, enter: usecase(12: audio-ull-playback) kvpairs: routing=2
01-27 05:26:07.524 4588 4588 E APM_AudioPolicyManager: Jon,deviceList size = 1
01-27 05:26:07.525 4588 4598 E AudioFlinger: Jon,address =
01-27 05:26:07.525 4588 4598 E audio_hw_primary: out_set_parameters: Jon, enter: usecase(0: deep-buffer-playback) kvpairs: routing=2
01-27 05:26:07.530 4588 4588 E APM_AudioPolicyManager: Jon,deviceList size = 1
01-27 05:26:07.531 4588 4600 E AudioFlinger: Jon,address =
01-27 05:26:07.531 4588 4600 E audio_hw_primary: out_set_parameters: Jon, enter: usecase(38: afe-proxy-playback) kvpairs: routing=65536
但是由于初始化阶段,所有的stream并没有被active,因此select_devices
没有机会在这个时候被调度到
既然如此,那么问题来了,Hal是在什么时候为Stream真正设置输出的呢,答案是在track->start
后真正向Hal下发数据的时候,如下:
hardware\qcom\audio\hal\Audio_hw.c
static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
size_t bytes)
{
...
if (out->standby) {
out->standby = false;
pthread_mutex_lock(&adev->lock);
if (out->usecase == USECASE_COMPRESS_VOIP_CALL)
ret = voice_extn_compress_voip_start_output_stream(out);
else
ret = start_output_stream(out);
pthread_mutex_unlock(&adev->lock);
/* ToDo: If use case is compress offload should return 0 */
if (ret != 0) {
out->standby = true;
goto exit;
}
if (last_known_cal_step != -1) {
ALOGD("%s: retry previous failed cal level set", __func__);
audio_hw_send_gain_dep_calibration(last_known_cal_step);
}
}
...
}
答案就在start_output_stream中,而且很明显在单次音频的播放中,start_output_stream只会被调用一次。
int start_output_stream(struct stream_out *out)
{
...
//Hal选择音频的输出设备
select_devices(adev, out->usecase);
...
pcm_open
pcm_prepare
pcm_start
...
}
关于 HAL的音频通路,参看Qualcomm Audio HAL 音频通路设置
int select_devices(struct audio_device *adev, audio_usecase_t uc_id)
{
...
//获取在start_output_stream中设置的usecase
usecase = get_usecase_from_list(adev, uc_id);
...
//禁止当前声卡设备
if (usecase->out_snd_device != SND_DEVICE_NONE) {
disable_audio_route(adev, usecase);
disable_snd_device(adev, usecase->out_snd_device);
}
//使能新的声卡设备
if (out_snd_device != SND_DEVICE_NONE) {
//检查是否有其他的usecase需要切换路由
check_usecases_codec_backend(adev, usecase, out_snd_device);
enable_snd_device(adev, out_snd_device);
}
...
//使能新的音频路由
enable_audio_route(adev, usecase);
...
}
这里的enable_snd_device
的作用可以理解为通过tinymix进行下面的操作:
tinymix 'RX3 MIX1 INP1' 'RX1'
tinymix 'SPK' ‘Switch’
也就是将BE DAIs ----> device之间的硬件通路打开
这里的enable_audio_route
的作用可以理解为通过tinymix进行下面的操作:
tinymix 'PRI_MI2S_RX Audio Mixer MultiMedia1' 1
也就是将FE PCMs---->BE DAIs之间的硬件通路打开
回放类型的路由控件名称一般是: $BE_DAI
Audio Mixer $FE_PCM
,因此这里的后端DAI就是PRI_MI2S_RX,而前端对应的就是MultiMedia1