2

I am currently working on an embedded board with a WM8776 which uses the MCASP1 of the AM335x. This works as expected and has expected behaviour.

What I now want to do is make a driver which can switch frequencies. I have two clocks which go in into the MCASP via a clock mux via a GPIO. If this GPIO is high I have an 24,576 clock, for 32/48/64/96/196, and so on audio and a 11,960 clock for 44.1/88.2/174 and so on audio.

My goal is now to be able to change this clock in kernel space. What I did so far was put some code to print out the current sample rate. Which went OK. I saw the sample rate which was currently transponded.

However, when I disabled the resampling of ALSA in .asoundrc I got the following error when trying to play a 96khz song one the 44.1khz (11,960mhz) clock. alsa_open:303 unable to get period size: Invalid argument

This of course is logical since there is not Integer which can achieve this perfect bitrate without resampling on this clock. The problem with this is the earlier mentioned print comment I put in the kernel did not anymore put any information about the current bitrate. So it did not reach this function, as I think ALSA already did catch this.

So, I tried to trace where this error was coming from so I could program the kernel to say: we are playing this bitrate, so we want to change to this clock when we are using this specific soundcard, whenever changing a song. But I could not find this error anywhere when spitting through the kernel sound code.

In short the use case is as followed:

Start-up frequency is 11.960Mhz. -> we now are playing a 44.1 Khz song. -> Changing to 96Khz song -> Put GPIO high (clock now at 24,512Mhz) -> Inform ALSA and MCASP clock has changed.

I know how to change MCASP from kernel space. So my question now is:

What is the first function called whenever a new playback is started(e.g. a song is changed)?

Where can I find the origin of this error?

And is there a better approach to do what I want to.

Lars
  • 23
  • 5
  • For having followed the discussion as part of @dirkt 's answer of your previous related question, I am sure I am still missing something : Anyway, to answer your question regarding the first function (indirectly) called by your playback app is likely to be snd_pcm_open() https://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html#ga8340c7dc0ac37f37afe5e7c21d6c528b unless you decide to bypass all that Alsa stuff and directly open the /dev/whatever special file for writing to the hw as jackd would. – MC68020 Nov 09 '22 at 16:14
  • @MC68020 bypassing does not seem like the best idea. What do you think your missing? – Lars Nov 09 '22 at 19:02
  • @MC68020 Your claim is indeed true, Thank you. I am now trying to find where it first access the rate (bitratr )of the playing file. I have been printing out, but without succes whenever I play an incompatibel bitrate. Do you maybe know this by heart? – Lars Nov 09 '22 at 20:26

1 Answers1

1

Ok two things: between the application playing back a stream of PCM samples and the kernel side of ALSA, there's the userland alsalib with its optional internal resampling. If the application did not disable that but requested a device as is, the kernel had no way of knowing what the original sapling rate was. It's simply not visible to the kernel in any way. This is doubly true if the application doesn't use ALSA as pure hardware interface, but uses a userland soundserver like Pulseaudio, pipe wire, esound or JACK, which might also offer userland-implemented ALSA devices, and do the mixing/resampling internally. This is the norm for modern Linux desktops.

If the application wants the hardware to sample at a specific rate, it will call snd_pcm_hw_patams from alsalib, which will do the necessary syscalls to tell your kernel driver what rate was requested. Write a minimal program that does nothing but that and strace that to see which these were!

Generally, since it's pretty common that multiple streams of potentially different rates are to be played back at the same time, it feels natural that most applications would not try to fiddle with the hardware parameters themselves - they request a correctly set up device, and that will usually include resampling-in-userland being opted in.

Marcus Müller
  • 21,602
  • 2
  • 39
  • 54
  • Ok that clears things up alot actually. Yes I figured snd_pcm_hw_params took care of this, but it never reaches this when resampling is disabled which is now clear why: it is already taken care of in userspace and will never reach the kernel. I do not use Pulseaudio this choise is made on purpose. I just searched things up a bit furter and indeed what I am looking for is in the alsalib api which makes calls to the kernel. I can both change this GPIO and clock for MCASP in user space. It seems like it is possible to make changes to alsa-lib api. Or is there an easier solution? – Lars Nov 20 '22 at 11:35
  • 1
    simply tell your application to request that automatic resampling is disabled. That's just a flag i the usual snd_pcm_… calls. – Marcus Müller Nov 20 '22 at 12:02
  • I read it a bit thorugh seems like I can indeed disable the resample from alsa-lib API. I see I can now basically caputre the Invalid argument error and then run a bash script file which enables both the GPIO and changes the clock. – Lars Nov 20 '22 at 12:23
  • Don't know why you'd ever want to use bash to do that, but yes, you can do whatever you want in reaction to a return code! – Marcus Müller Nov 20 '22 at 12:29
  • Basically I have to set /sys/class/gpio/gpioXXXX/value to 1 or 0. There is probably a better solution but I have to find out what. This will do for a first version even though it is very fragile. edit: ah i already see there is libgpiod library now adays which makes me able to do it in c without too much fuz. – Lars Nov 20 '22 at 12:34
  • you are writing a program in which you can call alsa functions. In that same programming language you can open files, and write `1` or `0` to them. There's no need for bash to open a file?! – Marcus Müller Nov 20 '22 at 12:40
  • I am sorry I am kind of new to linux programming I now see this in /dev/xx is basically just a file which can be opened in C – Lars Nov 20 '22 at 12:48
  • @Lars exactlky! – Marcus Müller Nov 20 '22 at 12:50
  • This indeed works. I managed to remove the resampling. So the /etc/sound.conf and /root/.asoundrc can not activate any resampling. I am now figuring out where the rate/channels etc are set. Thanks! – Lars Nov 23 '22 at 21:19