高通AudioHAL分析

这篇文章主要介绍一下AudioFlinger到hal层的一些工作流程。我们知道AudioFlinger从FIFO种读取到数据之后会调用hal的out_write函数去写入数据,我们就以这个函数为入口展开分析。

  1. out_write函数
    这个函数首先是有一些out->devices的判断,然后会判断是否是standby,如果是会调用start_output_stream去打开输出设备。然后如果pcm状态正常的情况下会调用pcm_write函数向adsp中写入数据。pcm_write是kernel的函数,我们这里只分析hal层,所以接下来我们去看一下start_output_stream函数打开设备的流程。
  2. 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输出设备的流程就大体分析完成了

  • 6
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值