[RK3288][Android6.0] 调试笔记 --- 修改录音采样率提示报错问题

Platform: Rockchip
OS: Android 6.0
Kernel: 3.10.92

需求
由于app采样率设置的是16k,而硬件用的是44.1kHz,为了避免重采样带来的损耗,因此将HAL层改了16kHz,logcat提示如下error:
01-21 23:01:23.047   210  1207 E AudioHardwareTiny: pcm_open() failed: cannot set hw params: Invalid argument

调试
调用的流程是
pcm_open -> pcm.c
    ioctl -> //cmd SNDRV_PCM_IOCTL_HW_PARAMS
        snd_pcm_capture_ioctl1 ->
            snd_pcm_common_ioctl1 ->
                snd_pcm_hw_params_user ->
                    snd_pcm_hw_params ->
                        snd_pcm_hw_refine ->
                            snd_interval_refine ->
                                snd_interval_checkempty
跑进snd_interval_checkempty()说明传进来的值在经过计算后不符合要求,所以成了empty。往回看snd_interval_refine()的第二个参数constrs_interval(constrs, k)
static inline struct snd_interval *constrs_interval(struct snd_pcm_hw_constraints *constrs,
                            snd_pcm_hw_param_t var)
{
    return &constrs->intervals[var - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL];
}
k即SNDRV_PCM_HW_PARAM_RATE, constrs即substream->runtime->hw_constraints,找到对hw_constraints中的设置是在open的时候
snd_pcm_capture_open ->
    snd_pcm_open ->
        snd_pcm_open_substream ->
            soc_pcm_open ->
                soc_pcm_apply_symmetry ->
                    snd_pcm_hw_constraint_minmax    //注意这里的最后两个参数都是soc_dai->rate
                        snd_interval_refine    //最后把这两个参数更新到hw_constraints中rate对应的interval中去
soc_pcm_apply_symmetry()需要拿出来说下
static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
                    struct snd_soc_dai *soc_dai)
{
    struct snd_soc_pcm_runtime *rtd = substream->private_data;
    int ret;
    if (!soc_dai->driver->symmetric_rates &&
        !rtd->dai_link->symmetric_rates)
        return 0;
......
    dev_info(soc_dai->dev, "ASoC: Symmetry forces %dHz rate\n", soc_dai->rate);
    //使用soc_dai->rate作为默认的采样率,这里有可能是cpu dai的也有可能是codec dai的rate
    ret = snd_pcm_hw_constraint_minmax(substream->runtime,
                       SNDRV_PCM_HW_PARAM_RATE,
                       soc_dai->rate, soc_dai->rate);
......
}
这里有个很重要的判断,判断soc_dai->driver->symmetric_rates或者rtd->dai_link->symmetric_rates是不是有设置,那么symmetric_rates有什么意义,摘录两段commit:
[RK3288][Android6.0] 调试笔记 --- 修改录音采样率提示报错问题_第1张图片

[RK3288][Android6.0] 调试笔记 --- 修改录音采样率提示报错问题_第2张图片

简单地说,就是由于audio codec由于硬件限制,而当你又要同时使用playback和capture的时候,它是无法同时输出两个不同的clock来满足不同的播放和录音采样率,所以当你使用其中一个substream的时候,另一个type的substream的采样率就会受到限制。

可以看到,rk_i2s.c也就是平台的cpu dai也做了限制:
static struct snd_soc_dai_driver rockchip_i2s_dai = {
......
    .ops = &rockchip_i2s_dai_ops,
    .symmetric_rates = 1,
};
那么上面的soc_dai->rate是在哪里设置的呢?我也是恍然大悟才想起来录音的同时先开启了playback stream,此值是在打开播放的时候设置的,困扰了我好一会,尴尬...
也正由于这个机制,之前我用tinycap直接验证录音也没发现此问题就提交了代码.
因此, 如果不是同时使用的话,那么采样率是可以修改的。

参考:
https://searchcode.com/codesearch/view/30197122/
https://git.congatec.com/arm/qmx6_kernel/commit/7912f03c2b2a0c43eae9b758fa768796fa9095d3

你可能感兴趣的:(子类__Audio)