linux/ALSA SRC重采样造成的问题及解决

背景:

在给imx6移植声卡驱动的时候出现一个怪异的现象:

codec做I2S主机,imx6做I2S从机,codec设置的采样率固定为8Khz,但是使用aplay命令播放8K采样率的PCM文件的时候出现播的很慢很慢,如果我把codec采样率设置到44.1K的时候,或者我使用aplay -r44100命令即骗aplay我播放的音频文件是44.1K的时候,播放就能正常!

出现此现象我一度以为是imx6的分频没设好,时钟不准,NND。

最后发现是alsa-lib搞的鬼。


解决:

/usr/share/alsa目录下有alsa-lib的配置文件,alsa.conf这个文件是配置的总入口,发现里面又导入了两个配置文件

在我的系统里没有发现.asoundrc这个文件。

而上面描述现象出现的根源就是/etc/asound.conf这个文件搞的鬼。

这个文件最后面有如下配置:

看到没有,默认导入了asymed这个插件,而asymed这个插件指定了播放和采集的采样率为44.1K,也就是说无论你播放的是什么采样率的文件,都会给你重采样到44.1K。

oh no~~

所以,我把上面两个44100改为8000,一切正常。岁月静好,现世安稳!

<think>我们正在处理一个编译错误,错误信息显示在赋值时函数指针类型不兼容。具体来说,是将一个接受一个参数的函数赋值给一个需要两个参数的函数指针。 错误信息: [OHOS ERROR] [NINJA] ../../drivers/peripheral/audio/supportlibs/alsa_adapter/src/alsa_snd_capture.c:896:23: error: incompatible function pointer types assigning to 'int32_t (*)(struct AlsaCapture *, const struct AudioHwCaptureParam *)' (aka 'int (*)(struct AlsaCapture *, const struct AudioHwCaptureParam *)') from 'int32_t (struct AlsaCapture *)' (aka 'int (struct AlsaCapture *)') [-Werror,-Wincompatible-function-pointer-types] [OHOS ERROR] [NINJA] captureIns->Start = CaptureStartImpl; 分析: 函数指针类型要求两个参数:第一个是struct AlsaCapture*,第二个是const struct AudioHwCaptureParam*。 但是,我们提供的函数CaptureStartImpl只接受一个参数:struct AlsaCapture*。 解决方案: 有两种方法: 1. 修改CaptureStartImpl函数,使其接受两个参数(推荐,因为符合接口定义)。 2. 修改函数指针的定义,使其匹配CaptureStartImpl的函数签名(如果确实不需要第二个参数,但需要确保设计上合理)。 根据错误信息,我们是在alsa_snd_capture.c文件中进行赋值操作。因此,我们需要检查CaptureStartImpl函数的声明和定义。 步骤: 1. 找到CaptureStartImpl函数的定义(可能在同一个文件或其他文件中)。 2. 检查函数指针Start在结构体中的定义(通常在头文件中)。 假设我们在头文件中找到结构体定义如下(示例): ```c struct AlsaCapture { // ... 其他成员 int32_t (*Start)(struct AlsaCapture *, const struct AudioHwCaptureParam *); // ... 其他成员 }; ``` 而CaptureStartImpl的定义可能是: ```c int32_t CaptureStartImpl(struct AlsaCapture *captureIns) { // ... 实现 } ``` 修复方法:修改CaptureStartImpl,增加第二个参数(即使不使用,也要保持参数一致): ```c int32_t CaptureStartImpl(struct AlsaCapture *captureIns, const struct AudioHwCaptureParam *handleData) { // 可能不需要使用handleData,但为了匹配签名,我们添加这个参数 // 实现代码,注意如果不需要handleData,可以忽略它,但要确保不影响逻辑 return 0; // 示例返回值 } ``` 如果第二个参数确实不需要,可以在函数体内不使用它,但函数签名必须一致。 另外,还需要检查所有调用Start函数的地方,确保传递了两个参数。例如: ```c captureIns->Start(captureIns, &param); // 两个参数 ``` 如果之前调用时只传递了一个参数,那么也需要修改。 但是,根据错误信息,赋值的地方是在alsa_snd_capture.c:896行,所以我们应该先修改CaptureStartImpl的定义。 如果CaptureStartImpl定义在另一个文件中(比如alsa_lib_capture.c),那么我们需要修改那个文件中的函数定义。 根据用户提供的文件路径:/drivers/peripheral/audio/supportlibs/alsa_adapter/src/alsa_lib_capture.c 我们可能需要在这个文件中修改CaptureStartImpl函数。 因此,具体步骤: 1. 打开alsa_lib_capture.c文件,找到CaptureStartImpl函数。 2. 修改函数签名,增加第二个参数(const struct AudioHwCaptureParam *handleData)。 3. 在函数体内,如果不需要handleData,可以添加一个避免未使用参数的宏(例如:(void)handleData;)来防止编译器警告。 4. 重新编译。 注意:如果其他地方有使用这个函数,也要确保它们符合新的签名(通常只有这个赋值点,但也要检查)。 如果还有其他类似的函数指针赋值错误,也需要同样处理。 示例修改代码: ```c // 修改前 int32_t CaptureStartImpl(struct AlsaCapture *captureIns) { // ... 原有代码 } // 修改后 int32_t CaptureStartImpl(struct AlsaCapture *captureIns, const struct AudioHwCaptureParam *handleData) { (void)handleData; // 避免未使用参数的警告 // ... 原有代码 } ``` 这样,函数指针赋值时类型就一致了。 另外,如果这个函数在头文件中有声明,也需要更新声明。 但是,如果函数是静态函数(只在本文件使用),则只需要修改本文件中的定义和声明(如果有)。 总结:核心是保持函数签名与函数指针类型一致。 最后,根据要求,我们需要在回答后提出3-5个相关问题。</think>### 错误分析与解决方案 #### 错误原因解析: 在文件 `alsa_lib_capture.c` 中,函数指针赋值出现类型不兼容: ```c captureIns->Start = CaptureStartImpl; // 错误行 ``` - **核心问题**: 1. 函数指针类型定义要求: ```c int32_t (*)(struct AlsaCapture *, const struct AudioHwCaptureParam *) ``` 2. 实际函数签名: ```c int32_t CaptureStartImpl(struct AlsaCapture *) // 缺少第二个参数 ``` 3. 参数数量不匹配导致类型系统报错(-Wincompatible-function-pointer-types) ### 修复方案 #### 方案1:修正函数实现(推荐) ```c // 修改前 int32_t CaptureStartImpl(struct AlsaCapture *captureIns) // 修改后(添加缺失参数) int32_t CaptureStartImpl(struct AlsaCapture *captureIns, const struct AudioHwCaptureParam *handleData) { (void)handleData; // 标记未使用参数避免警告 // 原有实现逻辑... } ``` #### 方案2:适配器模式(兼容旧实现) ```c // 创建适配函数 static int32_t CaptureStartAdapter( struct AlsaCapture *captureIns, const struct AudioHwCaptureParam *handleData) { (void)handleData; return CaptureStartImpl(captureIns); // 调用原函数 } // 修改赋值语句 captureIns->Start = CaptureStartAdapter; // 类型匹配 ``` ### 关键验证步骤: 1. **函数签名检查**: ```bash grep -rn "CaptureStartImpl" drivers/peripheral/audio/ grep -rn "Start.*AlsaCapture" include/ ``` 2. **编译器增强检测**: ```gn # BUILD.gn 添加严格检查 cflags = [ "-Werror=incompatible-pointer-types", "-Werror=strict-prototypes" ] ``` 3. **运行时验证**: ```c // 单元测试中添加参数检查 TEST_F(AudioCaptureTest, StartFunctionSignature) { struct AudioHwCaptureParam param = {0}; ASSERT_EQ(captureIns->Start(captureIns, &param), HDF_SUCCESS); } ``` ### 预防措施: 1. **头文件保护机制**: ```c // alsa_capture.h #ifdef CHECK_INTERFACE _Static_assert( __builtin_types_compatible_p( typeof(captureIns->Start), int32_t(*)(struct AlsaCapture*, const struct AudioHwCaptureParam*) ), "接口签名不匹配" ); #endif ``` 2. **自动化接口文档生成**: ```doxygen /// \fn int32_t Start(struct AlsaCapture*, const struct AudioHwCaptureParam*) /// \brief 启动音频捕获 struct AlsaCapture { int32_t (*Start)(struct AlsaCapture*, const struct AudioHwCaptureParam*); }; ``` 3. **版本化接口定义**: ```c // 接口版本控制 #define AUDIO_CAPTURE_ABI_VERSION 2 struct AlsaCapture { uint32_t abi_version; union { int32_t (*Start_v1)(struct AlsaCapture*); int32_t (*Start_v2)(struct AlsaCapture*, const struct AudioHwCaptureParam*); }; }; // 初始化时设置版本 captureIns->abi_version = AUDIO_CAPTURE_ABI_VERSION; ``` 4. **CLion 实时检测配置**: ```xml <!-- .idea/checkstyle-idea.xml --> <rule name="FunctionPointerMatch"> <pattern>(\w+\s*\*\s*\w+)\s*=\s*\w+;</pattern> <message>函数指针类型必须严格匹配</message> </rule> ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值