这篇文章主要介绍一下AudioFlinger到hal层的一些工作流程。我们知道AudioFlinger从FIFO种读取到数据之后会调用hal的out_write函数去写入数据,我们就以这个函数为入口展开分析。
- out_write函数
这个函数首先是有一些out->devices的判断,然后会判断是否是standby,如果是会调用start_output_stream去打开输出设备。然后如果pcm状态正常的情况下会调用pcm_write函数向adsp中写入数据。pcm_write是kernel的函数,我们这里只分析hal层,所以接下来我们去看一下start_output_stream函数打开设备的流程。 - start_output_stream函数
这个函数首先调用platform_get_pcm_device_id函数去获取device id,这个id的定义是取决于kernel的,也就是说hal层把这个id传给kernel,kernel根据对应的id去打开相应的通路。platform_get_pcm_device_id函数在platform.c中,主要是从pcm_device_table中根据相应的usecase去获取对应的通路id。定义如下:
static int pcm_device_table[AUDIO_USECASE_MAX][2] = {
[USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {DEEP_BUFFER_PCM_DEVICE,
DEEP_BUFFER_PCM_DEVICE},
[USECASE_AUDIO_PLAYBACK_WITH_HAPTICS] = {AUDIO_HAPTICS_PCM_DEVICE,
AUDIO_HAPTICS_PCM_DEVICE},
[USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE,
LOWLATENCY_PCM_DEVICE},
[USECASE_AUDIO_PLAYBACK_ULL] = {MULTIMEDIA3_PCM_DEVICE,
MULTIMEDIA3_PCM_DEVICE},
[USECASE_AUDIO_PLAYBACK_MULTI_CH] = {MULTIMEDIA2_PCM_DEVICE,
MULTIMEDIA2_PCM_DEVICE},
[USECASE_AUDIO_PLAYBACK_HIFI] = {MULTIMEDIA2_PCM_DEVICE,
MULTIMEDIA2_PCM_DEVICE},
[USECASE_AUDIO_PLAYBACK_TTS] = {MULTIMEDIA2_PCM_DEVICE,
MULTIMEDIA2_PCM_DEVICE},
[USECASE_AUDIO_PLAYBACK_OFFLOAD] =
{PLAYBACK_OFFLOAD_DEVICE, PLAYBACK_OFFLOAD_DEVICE},
[USECASE_AUDIO_PLAYBACK_OFFLOAD2] =
{PLAYBACK_OFFLOAD_DEVICE2, PLAYBACK_OFFLOAD_DEVICE2},
[USECASE_AUDIO_PLAYBACK_OFFLOAD3] =
{PLAYBACK_OFFLOAD_DEVICE3, PLAYBACK_OFFLOAD_DEVICE3},
[USECASE_AUDIO_PLAYBACK_OFFLOAD4] =
{PLAYBACK_OFFLOAD_DEVICE4, PLAYBACK_OFFLOAD_DEVICE4},
[USECASE_AUDIO_PLAYBACK_OFFLOAD5] =
{PLAYBACK_OFFLOAD_DEVICE5, PLAYBACK_OFFLOAD_DEVICE5},
[USECASE_AUDIO_PLAYBACK_OFFLOAD6] =
{PLAYBACK_OFFLOAD_DEVICE6, PLAYBACK_OFFLOAD_DEVICE6},
[USECASE_AUDIO_PLAYBACK_OFFLOAD7] =
{PLAYBACK_OFFLOAD_DEVICE7, PLAYBACK_OFFLOAD_DEVICE7},
[USECASE_AUDIO_PLAYBACK_OFFLOAD8] =
{PLAYBACK_OFFLOAD_DEVICE8, PLAYBACK_OFFLOAD_DEVICE8},
[USECASE_AUDIO_PLAYBACK_OFFLOAD9] =
{PLAYBACK_OFFLOAD_DEVICE9, PLAYBACK_OFFLOAD_DEVICE9},
。。。
};
然后DEEP_BUFFER_PCM_DEVICE等分别对应定义好的一个int值。
然后会调用到select_devices函数中。
3. select_devices函数
int select_devices(struct audio_device *adev, audio_usecase_t uc_id)
{
ALOGD("%s for use case (%s)", __func__, use_case_table[uc_id]);
usecase = get_usecase_from_list(adev, uc_id);
if (usecase == NULL) {
ALOGE("%s: Could not find the usecase(%d)", __func__, uc_id);
return -EINVAL;
}
if (usecase->type == PCM_PLAYBACK) {
if (usecase->stream.out == NULL) {
ALOGE("%s: stream.out is NULL", __func__);
return -EINVAL;
}
usecase->devices = usecase->stream.out->devices;
in_snd_device = SND_DEVICE_NONE;
if (out_snd_device == SND_DEVICE_NONE) {
struct stream_out *voip_out = adev->primary_output;
struct stream_in *voip_in = get_voice_communication_input(adev);
if (usecase->devices & AUDIO_DEVICE_OUT_BUS)
out_snd_device = audio_extn_auto_hal_get_output_snd_device(adev, uc_id);
else
out_snd_device = platform_get_output_snd_device(adev->platform,
usecase->stream.out);
voip_usecase = get_usecase_from_list(adev, USECASE_AUDIO_PLAYBACK_VOIP);
if (voip_usecase)
voip_out = voip_usecase->stream.out;
if (usecase->stream.out == voip_out && voip_in != NULL)
select_devices(adev, voip_in->usecase);
}
}
/* Enable new sound devices */
if (out_snd_device != SND_DEVICE_NONE) {
check_usecases_codec_backend(adev, usecase, out_snd_device);
if (platform_check_codec_asrc_support(adev->platform))
check_and_set_asrc_mode(adev, usecase, out_snd_device);
enable_snd_device(adev, out_snd_device);
}
enable_audio_route(adev, usecase);
audio_extn_qdsp_set_device(usecase);
}
这个函数会调用get_usecase_from_list函数把device和usecase等信息封装到audio_usecase结构体中,如果usecase->type是播放的话会去判断输出设备是否是AUDIO_DEVICE_OUT_BUS(这个是车机的device,因为我们是车机,所以就看一下这个if调用的函数),然后调用audio_extn_auto_hal_get_output_snd_device函数,再到auto_hal_get_output_snd_device函数,这个函数会根据device和usecase去选择hal层对应的snd_device。这个snd_device和上面传过来的device不同,传过来的device是framework上定义的一个名称,这个snd_device才是真正的hal层的device,比如framework传过来的是通过offload模式(媒体播放)设备是AUDIO_DEVICE_OUT_BUS去播放设备,在这里会根据这个usecase和device把snd_device转换成SND_DEVICE_OUT_BUS_MEDIA,如果framework传过来的是NAV(导航)模式AUDIO_DEVICE_OUT_BUS设备,那么snd_device对应的就是SND_DEVICE_OUT_BUS_NAV。同样的,如果设备不是AUDIO_DEVICE_OUT_BUS会调用platform_get_output_snd_device,但是这个函数也是做上面的一些操作,只不过这个函数相对会复杂一些,除了AUDIO_DEVICE_OUT_BUS之外所有的device转换都是从这里做的,比如headset,手机上的听筒等。最后调用enable_snd_device去打开输出设备通路,以及调用enable_audio_route去使能audio route。
4. enable_snd_device函数
这个函数首先调用platform_get_snd_device_name_extn函数使用上一步得到的snd_device去获取device_name,这个device_name就是mixer_path中所定义的名字,还是以SND_DEVICE_OUT_BUS_MEDIA为例进行分析,这里从device_table数组中得到的device_name是"bus-speaker"。然后继续往下走,会走到audio_route_apply_and_update_path函数,再到audio_route_update_path函数,这里首先根据上面获取到的device_name去解析mixer_path,然后拿到mixer_path中定义的"bus-speaker"所对应的通路,然后调用tinyalsa的mixer.c中的mixer_ctl_set_value函数去打开设备通路。
5. enable_audio_route函数
这个函数会调用platform_add_backend_name函数在通路的设备上添加设备名,用于不同的usecase定义,也就是把"headphones-44.1","speaker-and-headphones"等添加到usecase的设备名称中,主要是为了应对同样的usecase不同的设备配置不同的问题。比如同样的offload模式,有如下两种不同的定义
<path name="compress-offload-playback">
<ctl name="TERT_TDM_RX_0 Channels" value="Six" />
<ctl name="TERT_TDM_RX_0 Audio Mixer MultiMedia4" value="1" />
</path>
<path name="compress-offload-playback bt-sco">
<ctl name="SLIMBUS_7_RX Audio Mixer MultiMedia4" value="1" />
</path>
通过上面的例子我们可以看到,同样的offload模式,蓝牙的和默认的定义是完全不同的。最后这个函数和enable_snd_device函数一样也是调用audio_route_apply_and_update_path函数通过tinyalsa去打开对应的usecase。到这里hal层的打开usecase通路以及打开device输出设备的流程就大体分析完成了