alsa sample rate跟踪 <1>

深入探讨ALSA中采样率的跟踪机制,通过分析代码路径和堆栈调用,揭示采样率的确定过程及ALSA如何处理asound.conf配置与驱动参数之间的关系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

alsa sample rate跟踪 <1>

本计划全部放在一篇中,后来发现太长。
因此截取成四篇,一口气看800多行,确实够烦的!

之前以为alsa lib中的rate plugin之所以被调用,是因为在asound.conf中指定了硬件的sample rate,例如rate 48000。
但实际测试下来,发现不是这么回事。
无论asound.conf中是否有rate 48000,驱动中得到的params中的rate都是48000。

这是什么原因呢?一时想不明白。
先把rate经过的路线画出来吧。
rate包含在params中,那就顺着params看吧。
我们直接接触的是声卡驱动,params相关的函数就是XXXX_hw_params了。
在函数XXXX_hw_params中把sample rate打印出来,发现已经是48000了。
通过dump_stack把kernel中的调用堆栈打印出来,如下:

[   65.259240] [<8003bd9c>] (unwind_backtrace+0x0/0xf8) from [<7f312248>] (imx_3stack_surround_hw_params+0x38/0x4c8 [snd_soc_imx_saf7741])
[   65.274646] [<7f312248>] (imx_3stack_surround_hw_params+0x38/0x4c8 [snd_soc_imx_saf7741]) from [<7f1c3d50>] (soc_pcm_hw_params+0x4c/0x1a8 [snd_soc_core])
[   65.291480] [<7f1c3d50>] (soc_pcm_hw_params+0x4c/0x1a8 [snd_soc_core]) from [<7f116e6c>] (snd_pcm_common_ioctl1+0x844/0xea0 [snd_pcm])
[   65.304804] [<7f116e6c>] (snd_pcm_common_ioctl1+0x844/0xea0 [snd_pcm]) from [<7f1178f0>] (snd_pcm_playback_ioctl1+0x40/0x3e0 [snd_pcm])
[   65.317841] [<7f1178f0>] (snd_pcm_playback_ioctl1+0x40/0x3e0 [snd_pcm]) from [<800f0000>] (do_vfs_ioctl+0x80/0x54c)
[   65.328629] [<800f0000>] (do_vfs_ioctl+0x80/0x54c) from [<800f0504>] (sys_ioctl+0x38/0x5c)
[   65.337306] [<800f0504>] (sys_ioctl+0x38/0x5c) from [<800350c0>] (ret_fast_syscall+0x0/0x30)


 

我们只关心params相关。
snd_pcm_common_ioctl1的部分内容:

static int snd_pcm_common_ioctl1(struct file *file,
     struct snd_pcm_substream *substream,
     unsigned int cmd, void __user *arg)
{
...
 case SNDRV_PCM_IOCTL_HW_PARAMS:
  return snd_pcm_hw_params_user(substream, arg);
...
}


 

函数snd_pcm_hw_params_user的实现:

static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream,
      struct snd_pcm_hw_params __user * _params)
{
 struct snd_pcm_hw_params *params;
 int err;

 params = memdup_user(_params, sizeof(*params));
 if (IS_ERR(params))
  return PTR_ERR(params);

 err = snd_pcm_hw_params(substream, params);
 if (copy_to_user(_params, params, sizeof(*params))) {
  if (!err)
   err = -EFAULT;
 }

 kfree(params);
 return err;
}


 

在kernel中被传来传去的params原来就诞生在snd_pcm_hw_params_user函数中。
结合函数snd_pcm_common_ioctl1可知,user层调用了一个ioctl,command为SNDRV_PCM_IOCTL_HW_PARAMS,并将params作为arg参数传给内核。
内核中将arg重新copy到params并使用。

内核中的代码还是比较清晰的。
阅读上面dump_stack的调用堆栈可知,内核中将params传递给函数XXXX_hw_params之前,并没有修改params。
也就是说XXXX_hw_params中的sample rate为48000,并不是在内核中产生的。
那就继续往上追踪,也就是alsa lib了。

alsa lib中的代码不是那么清晰。
当时,不是说代码写的不好(呵呵,能实现这些东东的,可都是大牛),是因为alsa lib中要处理很多种情况,并且要解析asound.conf文件,
根据音频文件参数,硬件参数,以及alsa配置文件(asound.conf是其中之一)来决定需要进行什么样的处理。
呵呵,说到底还是没能对alsa lib完全理解,所以它在面前仍然是一个庞然大物,没有庖丁解牛的感觉。
一时半会也不能把alsa lib全部搞透,暂时也没时间详细研究,先只关系params吧。

在alsa lib中搜索SNDRV_PCM_IOCTL_HW_PARAMS,发现其出现的地方:

static inline int hw_params_call(snd_pcm_hw_t *pcm_hw, snd_pcm_hw_params_t *params)
{
 /* check for new hw_params structure; it's available from 2.0.2 version of PCM API */
 if (SNDRV_PROTOCOL_VERSION(2, 0, 2) <= pcm_hw->version)
  return ioctl(pcm_hw->fd, SNDRV_PCM_IOCTL_HW_PARAMS, params);
 return use_old_hw_params_ioctl(pcm_hw->fd, SND_PCM_IOCTL_HW_PARAMS_OLD, params);
}


 

上溯:

static int snd_pcm_hw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
{
 snd_pcm_hw_t *hw = pcm->private_data;
 int err;
 if (hw_params_call(hw, params) < 0) {
  err = -errno;
  SYSMSG("SNDRV_PCM_IOCTL_HW_PARAMS failed (%i)", err);
  return err;
 }
 params->info &= ~0xf0000000;
 params->info |= (pcm->monotonic ? SND_PCM_INFO_MONOTONIC : 0);
 err = sync_ptr(hw, 0);
 if (err < 0)
  return err;
 if (pcm->stream == SND_PCM_STREAM_CAPTURE) {
  snd_pcm_set_appl_ptr(pcm, &hw->mmap_control->appl_ptr, hw->fd,
         SNDRV_PCM_MMAP_OFFSET_CONTROL);
 }
 return 0;
}


 

原来是在snd_pcm_hw_hw_params中发起的ioctl。
snd_pcm_hw_hw_params赋值给了结构体snd_pcm_hw_ops:

static const snd_pcm_ops_t snd_pcm_hw_ops = {
...
 .hw_params = snd_pcm_hw_hw_params,
...
}



看代码最怕这种,给函数都带上相同的面具,让你摸不清谁是谁。
揭开它们面具最好的方法就是让它们都报上名来,呵呵。
在所有的hw_params函数中各加一句log,把各自函数名打印出来,顺便把进入各函数时的sample rate也打印出来,以方便我们查询sample rate究竟是在哪儿被改变的。
结合kernel中代码,可知根据params取得sample rate的方式为:
(&params->intervals[SNDRV_PCM_HW_PARAM_RATE - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL])->min
通过打印log,发现hw_params被调用的信息如下:

snd_pcm_hw_params - rate=48000
_snd_pcm_hw_params - rate=48000
snd_pcm_hw_hw_params - rate=48000
snd_pcm_hw_params - rate=16000
_snd_pcm_hw_params - rate=16000
snd_pcm_plug_hw_params - rate=16000
_snd_pcm_hw_params - rate=16000
snd_pcm_rate_hw_params - rate=16000
snd_pcm_generic_hw_params - rate=48000
_snd_pcm_hw_params - rate=48000
snd_pcm_direct_hw_params - rate=48000


 

函数snd_pcm_hw_params的实现:

/** \brief Install one PCM hardware configuration chosen from a configuration space and #snd_pcm_prepare it
 * \param pcm PCM handle
 * \param params Configuration space definition container
 * \return 0 on success otherwise a negative error code
 *
 * The configuration is chosen fixing single parameters in this order:
 * first access, first format, first subformat, min channels, min rate, 
 * min period time, max buffer size, min tick time
 *
 * After this call, #snd_pcm_prepare() is called automatically and
 * the stream is brought to \c #SND_PCM_STATE_PREPARED state.
 *
 * The hardware parameters cannot be changed when the stream is
 * running (active). The software parameters can be changed
 * at any time.
 */
int snd_pcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
 int err;
 assert(pcm && params);
 err = _snd_pcm_hw_params(pcm, params);
 if (err < 0)
  return err;
 err = snd_pcm_prepare(pcm);
 return err;
}



snd_pcm_hw_params与_snd_pcm_hw_params调用关系以及明了了。
接着要看看:
1、snd_pcm_hw_hw_params,snd_pcm_plug_hw_params,snd_pcm_rate_hw_params,snd_pcm_generic_hw_params和snd_pcm_direct_hw_params是如何被调用的。
2、以及snd_pcm_hw_params和几处单独的_snd_pcm_hw_params是如何被调用的。

 

<?xml version="1.0" encoding="UTF-8"?> <!-- Copyright (C) 2015 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <!-- Default Volume Tables included by Audio Policy Configuration file --> <!-- Full Default Volume table for all device category --> <volumes> <reference name="FULL_SCALE_VOLUME_CURVE"> <!-- Full Scale reference Volume Curve --> <point>0,0</point> <point>100,0</point> </reference> <reference name="SILENT_VOLUME_CURVE"> <point>0,-9600</point> <point>100,-9600</point> </reference> <!-- #ifndef OPLUS_BUG_STABILITY //YaJun.Li@MM.AudioServer.Policy, 2019/08/21,Add for voice volume --> <reference name="DEFAULT_VOICE_VOLUME_CURVE"> <!-- Default Voice reference Volume Curve --> <point>0,-5400</point> <point>1,-4700</point> <point>2,-4200</point> <point>3,-3800</point> <point>4,-3400</point> <point>5,-3000</point> <point>6,-2600</point> <point>7,-2200</point> <point>8,-1800</point> <point>9,-1500</point> <point>10,-1200</point> <point>11,-900</point> <point>12,-600</point> <point>13,-300</point> <point>14,0</point> </reference> <!-- #endif OPLUS_BUG_STABILITY --> <reference name="DEFAULT_SYSTEM_VOLUME_CURVE"> <!-- Default System reference Volume Curve --> <point>1,-6000</point> <point>2,-3100</point> <point>3,-2800</point> <point>4,-2600</point> <point>5,-2400</point> <point>6,-2200</point> <point>7,-2000</point> <point>8,-1800</point> <point>9,-1600</point> <point>10,-1400</point> <point>11,-1200</point> <point>12,-1000</point> <point>13,-800</point> <point>14,-600</point> <point>15,-400</point> <point>16,-200</point> </reference> <reference name="DEFAULT_MEDIA_VOLUME_CURVE"> <!-- Default Media reference Volume Curve --> <!-- #ifndef OPLUS_BUG_STABILITY //YaJun.Li@PSW.MM.AudioServer.Policy, 2019/08/21 //Modify for headset music min and default volume <point>1,-5800</point> <point>20,-4000</point> <point>60,-1700</point> <point>100,0</point> #else /* OPLUS_BUG_STABILITY */ --> <point>1,-7000</point> <point>5,-6200</point> <point>10,-5700</point> <point>15,-5100</point> <point>20,-4500</point> <point>25,-4000</point> <point>30,-3500</point> <point>35,-3100</point> <point>40,-2700</point> <point>45,-2400</point> <point>50,-2100</point> <point>55,-1700</point> <point>60,-1300</point> <point>65,-1000</point> <point>70,-700</point> <point>75,-400</point> <point>80,-100</point> <!-- #endif /* OPLUS_BUG_STABILITY */ --> </reference> <!-- #ifdef OPLUS_BUG_STABILITY //Qinhui.Gu@PSW.MM.AudioServer.Policy, 2019/12/11, add USB_HEADSET device category for tuning separately --> <reference name="DEFAULT_MEDIA_VOLUME_CURVE_USB_HEADSET"> <!-- USB_HEADSET Media reference Volume Curve --> <point>1,-6400</point> <point>5,-6200</point> <point>10,-5600</point> <point>15,-5000</point> <point>20,-4400</point> <point>25,-3800</point> <point>30,-3400</point> <point>35,-3100</point> <point>40,-2800</point> <point>45,-2500</point> <point>50,-2200</point> <point>55,-1800</point> <point>60,-1500</point> <point>65,-1200</point> <point>70,-800</point> <point>75,-400</point> <point>80,-150</point> </reference> <!-- #endif /* OPLUS_BUG_STABILITY */ --> <reference name="DEFAULT_MEDIA_VOLUME_CURVE_A2DP"> <!-- Default Media reference Volume Curve --> <!-- #ifndef OPLUS_BUG_STABILITY //YaJun.Li@PSW.MM.AudioServer.Policy, 2019/08/21, // Modify for bluetooth headset music min and default volume <point>1,-5800</point> <point>20,-4000</point> <point>60,-1700</point> <point>100,0</point> #else /* OPLUS_BUG_STABILITY */ --> <point>1,-6400</point> <point>5,-5500</point> <point>10,-5000</point> <point>15,-4500</point> <point>20,-4000</point> <point>25,-3700</point> <point>30,-3400</point> <point>35,-3100</point> <point>40,-2800</point> <point>45,-2500</point> <point>50,-2200</point> <point>55,-1800</point> <point>60,-1400</point> <point>65,-1100</point> <point>70,-700</point> <point>75,-400</point> <point>80,-150</point> <!-- #endif /* OPLUS_BUG_STABILITY */ --> </reference> <reference name="DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE"> <!--Default Volume Curve --> <point>1,-4950</point> <point>33,-3350</point> <point>66,-1700</point> <point>100,0</point> </reference> <reference name="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE"> <!-- Default is Speaker Media Volume Curve --> <!-- #ifndef OPLUS_BUG_STABILITY //YaJun.Li@PSW.MM.AudioServer.Policy, 2019/08/21 //Modify for speaker music default volume for 19065 <point>1,-5800</point> <point>20,-4000</point> <point>60,-1700</point> <point>100,0</point> #else /* OPLUS_BUG_STABILITY */ --> <point>1,-7000</point> <point>5,-5200</point> <point>10,-4500</point> <point>15,-3900</point> <point>20,-3400</point> <point>25,-3000</point> <point>30,-2700</point> <point>35,-2450</point> <point>40,-2150</point> <point>45,-1850</point> <point>50,-1650</point> <point>55,-1350</point> <point>60,-1100</point> <point>65,-800</point> <point>70,-650</point> <point>75,-400</point> <point>80,0</point> <!-- #endif /* OPLUS_BUG_STABILITY */ --> </reference> <reference name="DEFAULT_DEVICE_CATEGORY_EARPIECE_VOLUME_CURVE"> <!--Default Volume Curve --> <point>1,-4950</point> <point>33,-3350</point> <point>66,-1700</point> <point>100,0</point> </reference> <reference name="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"> <!-- Default is Ext Media System Volume Curve --> <point>1,-5800</point> <point>20,-4000</point> <point>60,-2100</point> <point>100,-1000</point> </reference> <reference name="DEFAULT_HEARING_AID_VOLUME_CURVE"> <!-- Default Hearing Aid Volume Curve --> <point>1,-12700</point> <point>20,-8000</point> <point>60,-4000</point> <point>100,0</point> </reference> <!-- **************************************************************** --> <!-- Non-mutable default volume curves: --> <!-- * first point is always for index 0 --> <!-- * attenuation is small enough that stream can still be heard --> <reference name="DEFAULT_NON_MUTABLE_VOLUME_CURVE"> <!-- Default non-mutable reference Volume Curve --> <!-- based on DEFAULT_MEDIA_VOLUME_CURVE --> <point>0,-5800</point> <point>20,-4000</point> <point>60,-1700</point> <point>100,0</point> </reference> <reference name="DEFAULT_NON_MUTABLE_HEADSET_VOLUME_CURVE"> <!--Default non-mutable Volume Curve for headset --> <!-- based on DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE --> <point>0,-4950</point> <point>33,-3350</point> <point>66,-1700</point> <point>100,0</point> </reference> <reference name="DEFAULT_NON_MUTABLE_SPEAKER_VOLUME_CURVE"> <!-- Default non-mutable Speaker Volume Curve --> <!-- based on DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE --> <point>0,-5800</point> <point>20,-4000</point> <point>60,-1700</point> <point>100,0</point> </reference> <reference name="DEFAULT_NON_MUTABLE_EARPIECE_VOLUME_CURVE"> <!--Default non-mutable Volume Curve --> <!-- based on DEFAULT_DEVICE_CATEGORY_EARPIECE_VOLUME_CURVE --> <point>0,-4950</point> <point>33,-3350</point> <point>66,-1700</point> <point>100,0</point> </reference> <reference name="DEFAULT_NON_MUTABLE_EXT_VOLUME_CURVE"> <!-- Default non-mutable Ext Media System Volume Curve --> <!-- based on DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE --> <point>0,-5800</point> <point>20,-4000</point> <point>60,-2100</point> <point>100,-1000</point> </reference> <reference name="DEFAULT_NON_MUTABLE_HEARING_AID_VOLUME_CURVE"> <!-- Default non-mutable Hearing Aid Volume Curve --> <!-- based on DEFAULT_HEARING_AID_VOLUME_CURVE --> <point>0,-12700</point> <point>20,-8000</point> <point>60,-4000</point> <point>100,0</point> </reference> </volumes> 以上文件路径:/odm/etc/audio/default_volume_tables.xml 一加13 Coloros15,安卓版本15,修改该文件,绕过安卓音频SRC实现系统全局自适应采样率(Dynamic sampling rates)、自适应位深(Bit_perfect)(保持音频文件原始位深,16bit文件不升级位深)、禁用升频和重采样,关闭所有音频音效(effect)以及影响音频质量无损输出的一切音频处理,最大程度上抑制并降低音频抖动(jitter)(最大化优化时钟管理和同步)、最大程度降低音频失真和噪声以及电源纹波和噪声,以输出输入最干净无污染最高质量的HIFI无损原始音频信号直出,输出修改过的完整文件
最新发布
08-12
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值