我目前正在开发带有 WM8776 的嵌入式板,该板使用 AM335x 的 MCASP1。这按预期工作并具有预期行为。
我现在想做的是制作一个可以切换频率的驱动器。我有两个时钟,它们通过时钟复用器通过 GPIO 进入 MCASP。如果这个 GPIO 为高电平,我有一个 24,576 时钟,用于 32/48/64/96/196 等音频,还有一个 11,960 时钟,用于 44.1/88.2/174 等音频。
我现在的目标是能够更改内核空间中的时钟。到目前为止我所做的是输入一些代码来打印当前的采样率。一切顺利。我看到了当前转发的采样率。
但是,当我在 .asoundrc 中禁用 ALSA 重采样时,尝试在 44.1khz (11,960mhz) 时钟上播放 96khz 歌曲时出现以下错误。
alsa_open:303 unable to get period size: Invalid argument
这当然是合乎逻辑的,因为没有 Integer 可以在不在此时钟上重新采样的情况下实现完美的比特率。问题是前面提到的我放入内核中的打印注释不再包含有关当前比特率的任何信息。所以它没有达到这个功能,因为我认为 ALSA 已经抓住了这个。
所以,我试图追踪这个错误的来源,这样我就可以对内核进行编程,说:我们正在播放这个比特率,所以当我们使用这个特定的声卡时,每当改变一首歌曲时,我们想要改变到这个时钟。但是当我查看内核声音代码时,我在任何地方都找不到这个错误。
简而言之,用例如下:
启动频率为11.960Mhz。 -> 我们现在正在播放一首 44.1 Khz 的歌曲。 -> 更改为 96Khz 歌曲 -> 将 GPIO 设置为高电平(时钟现在为 24,512Mhz) -> 通知 ALSA 和 MCASP 时钟已更改。
我知道如何从内核空间更改 MCASP。所以我现在的问题是:
每当开始新的播放时(例如更改歌曲),第一个调用的函数是什么?
我在哪里可以找到这个错误的根源?
有没有更好的方法来做我想做的事。
答案1
有两件事:在播放 PCM 样本流的应用程序和 ALSA 的内核端之间,有用户态 alsalib 及其可选的内部重采样。如果应用程序没有禁用它,而是按原样请求设备,则内核无法知道原始的树苗速率是多少。它对内核来说根本不可见。如果应用程序不使用 ALSA 作为纯硬件接口,而是使用用户态声音服务器(例如 Pulseaudio、管道线、esound 或 JACK)(它们也可能提供用户态实现的 ALSA 设备,并在内部进行混合/重采样),则情况更加正确。这是现代 Linux 桌面的标准。
如果应用程序希望硬件以特定速率采样,它将snd_pcm_hw_patams
从 alsalib 调用,这将执行必要的系统调用来告诉内核驱动程序请求的速率。编写一个除此之外什么也不做的最小程序,然后对其进行跟踪以查看它们是什么!
一般来说,由于同时播放多个可能不同速率的流是很常见的,因此大多数应用程序很自然不会尝试摆弄硬件参数本身 - 它们请求正确设置的设备,并且通常会包括选择的用户空间重采样。