Android中AudioPatch相关分析

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_DAIAudio Mixer $FE_PCM,因此这里的后端DAI就是PRI_MI2S_RX,而前端对应的就是MultiMedia1

  • 5
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值