If the volume control works in windows, the chain is configured correctly. Are you sure your linux host playback sw uses HW volume control, i.e. ctrl elements provided by the usb alsa driver? Most likely your volume control is software-based, directly in your player software.When using linux, the alsamixer's volume doesn't change, and I don't know why ?
I made a another test and I need to add precision.
When using windows as audio source. If I change the volume of the device on windows, the sound level doesn't change. But on the rasp, the value of the alsa mixer 'PCM' of the card UAC2_Gadget changes. So this script can retrieve the PCM volume value and set this value as volume of camillaDSP.
When using linux as audio source. If I change the volume of the device, the sound level does change. But on the rasp, no alsa mixer seems to be affected by this volume changes.
I tried to change the level of the alsa mixer of the usb gadget on my linux PC, and finaly the value of the alsa mixer 'PCM' of the card UAC2_Gadget changes !
So you're right, the sound manager on my linux doesn't change the alsamixer's volume and is probably software-based. Maybe this have something to do with the fact that my linux distribution use pulseaudio.
When using windows as audio source. If I change the volume of the device on windows, the sound level doesn't change. But on the rasp, the value of the alsa mixer 'PCM' of the card UAC2_Gadget changes. So this script can retrieve the PCM volume value and set this value as volume of camillaDSP.
When using linux as audio source. If I change the volume of the device, the sound level does change. But on the rasp, no alsa mixer seems to be affected by this volume changes.
I tried to change the level of the alsa mixer of the usb gadget on my linux PC, and finaly the value of the alsa mixer 'PCM' of the card UAC2_Gadget changes !
So you're right, the sound manager on my linux doesn't change the alsamixer's volume and is probably software-based. Maybe this have something to do with the fact that my linux distribution use pulseaudio.
PA has a very complex volume arrangement, you will have to play with it a bit and tweak as you need .
E.g. https://bbs.archlinux.org/viewtopic.php?id=260104 and https://github.com/volumio/Volumio2/issues/159#issuecomment-264633455 seem quite relevant, but google offers more links.
E.g. https://bbs.archlinux.org/viewtopic.php?id=260104 and https://github.com/volumio/Volumio2/issues/159#issuecomment-264633455 seem quite relevant, but google offers more links.
As always with audio service in linux, it's all about pain and suffering
(or it's just me ? )
Well, after a few headache, I found a way to solve my problem ! If pulseaudio doesn"t find an alsamixer which is named the right way, it use software volume control as fallback.
I found this page which seems to adress my problem : https://www.freedesktop.org/wiki/Software/PulseAudio/Backends/ALSA/Profiles/
But personnally after reading this page, I was helpless and I had to do a lot of die & retry to figure out, how this is working.
This "how-to" works on my computer, a linux mint 21 which is Ubuntu 22.04 based.
Content of uac2.conf:
Content of uac2-output.conf :
I hope this will help others people 🙂

Well, after a few headache, I found a way to solve my problem ! If pulseaudio doesn"t find an alsamixer which is named the right way, it use software volume control as fallback.
I found this page which seems to adress my problem : https://www.freedesktop.org/wiki/Software/PulseAudio/Backends/ALSA/Profiles/
Your hardware does not expose normal volume control names such as "Master", "PCM", "Headphone" etc but instead e g "Megaphone" and "Leslie speaker".
But personnally after reading this page, I was helpless and I had to do a lot of die & retry to figure out, how this is working.
This "how-to" works on my computer, a linux mint 21 which is Ubuntu 22.04 based.
- In the file /lib/udev/rules.d/90-pulseaudio.rules
Inside the section :
LABEL="pulseaudio_check_usb"
...
GOTO="pulseaudio_end"
Add udev rule :
ATTRS{idVendor}=="1d6b", ATTRS{idProduct}=="0104", ENV{PULSE_PROFILE_SET}="uac2.conf"
- Add the profile-set uac2.conf to /usr/share/pulseaudio/alsa-mixer/profile-sets/uac2.conf
"UAC2Gadget96000" in this file, must correspond to the product name of your usb audio gadget
- Add the path uac2-output.conf to /usr/share/pulseaudio/alsa-mixer/paths/uac2-output.conf
"Playback Volume" is the name of the alsamixer
Content of uac2.conf:
# This file is part of PulseAudio.
#
# PulseAudio is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# PulseAudio is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
[General]
auto-profiles = yes
[Mapping UAC2Gadget96000]
device-strings = hw:%f
channel-map = front-left,front-right
paths-output = uac2-output
priority = 15
Content of uac2-output.conf :
[General]
priority = 99
[Element Playback Volume]
switch = mute
volume = merge
override-map.1 = all
override-map.2 = all-left,all-right
I hope this will help others people 🙂
Last edited:
That's the price of the complete flexibility. You cannot do anything like this on any other OS. udev knows everything about your soundcard - which USB port/PCI slot, device serial number, etc... unlike PA which already gets an alsa device, no other details. That's why udev is tasked with customizing PA. If someone wanted to use one volume control for a USB device plugged into slot A, and a different control for the same device when plugged into slot B (such a requirement may arise, or any other) - this method of configuration would allow it.As always with audio service in linux, it's all about pain and suffering
PA can be asked to assign a profile to a soundcard directly, without involving udev ( e.g. https://unix.stackexchange.com/a/462671 ), but that may not work correctly when hot-plugging the device.
IF the USB gadget used standard naming for mixer controls (like Master Playback/Capture Volume) https://www.kernel.org/doc/html/v4.12/sound/designs/control-names.html , PA would recognize the volume control out of the box, no udev rules would be required. The gadget uses deprecated Playback/Capture Volume names in the uac2 function https://github.com/torvalds/linux/b...rivers/usb/gadget/function/f_uac2.c#L118-L119 . I may later send a patch which will allow setting custom names for these controls via configfs, after the currently proposed UAC2 patches get through and the source code settles down.
Yes, actually I began with this solution.
In default.pa, by adding :
But it was unpractical.
Indeed, If the USB gadget used the standard naming, it will be the best solution 🙂
In default.pa, by adding :
load-module module-alsa-card device_id='UAC2Gadget96000' control='Playback Volume' ignore_dB=1 deferred_volume=1
But it was unpractical.
Indeed, If the USB gadget used the standard naming, it will be the best solution 🙂
RaspberryPI OS Bookworm has been released, with some changes of the WiFi setup which by now has been shown to be a bit quirky to set up in headless mode. Apparently the WiFi parameters declarations have been migrated from the wpa_supplicant to the NetworkManager configuration. And the method as described in my former HowTo for installing iwd instead of wpa_supplicant does not work any longer. Therefore I updated the WiFi section of the HowTo to work along the changes introduced with Bookworm.
Attachments
I am trying to get an asynchronous notification of alsa events occurred on the USB gadget device of my Raspberry Pi 4.
To this end I use the
Unfortunately, the callback function is never triggered.
I suspect that the gadget driver does not send the SIGIO signal, which the alsa lib requires to get notified of incoming events.
Is there a way to instruct the gadget driver to generate a signal when an event occurs?
(I apologize if this subject has already been covered).
NOTE: The synchronous event reading with the
To this end I use the
snd_async_add_ctl_handler
and the snd_ctl_subscribe_events
interfaces of the alsa C library.Unfortunately, the callback function is never triggered.
I suspect that the gadget driver does not send the SIGIO signal, which the alsa lib requires to get notified of incoming events.
Is there a way to instruct the gadget driver to generate a signal when an event occurs?
(I apologize if this subject has already been covered).
NOTE: The synchronous event reading with the
snd_ctl_read
interface works quite well (see my litlle sample rate switcher for CamillaDSP at https://github.com/marcoevang/camilladsp-setrate)This is what the gadget does https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/u_audio.c#L503
Thank you for answering.This is what the gadget does https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/u_audio.c#L503
A function generating the SIGIO signal appears in the source code, but its invocation and/or effect are subject to a number of conditions. It is therefore not easy to understand what the gadget driver actually does at runtime.
Last edited:
It calls the notification at any change of samplerate, i.e. at start and end of capture/playback, when altsetting is being switched. This rust code listens for the notifications https://github.com/pavhofman/gaudio...eb81c34f17658e32d44f6ee2/src/bin.rs#L135-L150
Thanks a lot for your help.It calls the notification at any change of samplerate, i.e. at start and end of capture/playback, when altsetting is being switched. This rust code listens for the notifications https://github.com/pavhofman/gaudio...eb81c34f17658e32d44f6ee2/src/bin.rs#L135-L150
I am not familiar with the rust language. However, it seems that the code at line 139:
let event = ctl.read()?.unwrap()
performs a synchronous read, that is what I already do in C language with the
snd_ctl_read
interface.What I would like to obtain is an asynchronous read performed by a callback function, without the need to wait for an event to happen.
The Alsa C library provides an interface to set a callback function. As far as I understand, when the driver generates a SIGIO signal, the callback function is triggered. Unfortunately, this never happens.
Last edited:
I am afraid I cannot help with that. I do not know what API should be used on the driver side.
In any case the sync -> async should be doable in your code using another thread.
In any case the sync -> async should be doable in your code using another thread.
Yes, this could be a good viable option.In any case the sync -> async should be doable in your code using another thread.
However, I solved the issue. And the solution was trivial, but rather puzzling. The alsa control must be opened in READONLY or in NONBLOCK mode (the gadget driver does its job nicely... 🙂 ). If it is opened in ASYNC mode, as I was doing previously, the callback function is not triggered.
The alsa C library is a complex beast but, unfortunately, its documentation is very poor.
Many thanks to @phofman, who is always very supportive.
Sorry for this newbie question, but which kind of (OTG) cable do I need for a Pi4?...a spitted cable to use the original Pi power-supply (usb-c socket) and usb-a plug to the PC?
I'm asking as in the older thread, it is mentioned that a pi4 must be powered over the GPIO pins?
I'm asking as in the older thread, it is mentioned that a pi4 must be powered over the GPIO pins?
I am afraid I do not understand your question. What do you mean by source and host? The names are USB host -> USB device (or USB gadget).Will the USB audio source see a synchronous or an asynchronous host?
Thansk @phofman - Sorry to mess up standard terminology. My intented use is an ADC with USB interface to capture vinyl. For this i used the term USB audio sourche. But now understand correct wording should be USB host.
Now then. if my host are capable of asynchronous transfer will the USB gadget with before mentioned implementation and use take advanses of this?
Edit: There isn't any mentioning of either or in the USB gadget configuration script by @Daihedz
Now then. if my host are capable of asynchronous transfer will the USB gadget with before mentioned implementation and use take advanses of this?
Edit: There isn't any mentioning of either or in the USB gadget configuration script by @Daihedz
Last edited:
The other direction ADC -> CDSP -> USB gadget -> USB host should be supported too, but not tested thoroughly. I never saw any discussion about it, AFAIK there is nothing online, we discussed the CDSP support for this direction with Henrik over email.
Input endpoint (i.e. data going from device to host) is typically asynchronous. That means every relevant frame (as specified by bInterval) the device sends all new samples it has available, no explicit async feedback messages are needed.
Implementation in device MCUs is quite simple - the MCU packs into the packet whatever samples have arrived into some FIFO from the I2S input dataline.
Unfortunately adapting this to linux alsa is more difficult becase every alsa device runs on its own and the client (writing application in this case) is timed by the device. To give the client control over speed at which the gadget device consumes samples, the gadget offers alsa control "Playback Pitch 1000000" (similarly to "Capture Pitch 1000000" ctl for the other direction). This control adjusts number of samples copied from the device alsa buffer to the packet going to the USB host.
So you should configure CDSP for the other direction (just flipping the devices) and (in the final setup) run gadget_ctl configured for the other direction. Host starts capture -> gadget_ctl fires CDSP which will bridge data between the ADC alsa card and the gadget alsa card, adjusting "Playback Pitch 1000000" continually to fit the fixed ADC clock.
Input endpoint (i.e. data going from device to host) is typically asynchronous. That means every relevant frame (as specified by bInterval) the device sends all new samples it has available, no explicit async feedback messages are needed.
Implementation in device MCUs is quite simple - the MCU packs into the packet whatever samples have arrived into some FIFO from the I2S input dataline.
Unfortunately adapting this to linux alsa is more difficult becase every alsa device runs on its own and the client (writing application in this case) is timed by the device. To give the client control over speed at which the gadget device consumes samples, the gadget offers alsa control "Playback Pitch 1000000" (similarly to "Capture Pitch 1000000" ctl for the other direction). This control adjusts number of samples copied from the device alsa buffer to the packet going to the USB host.
So you should configure CDSP for the other direction (just flipping the devices) and (in the final setup) run gadget_ctl configured for the other direction. Host starts capture -> gadget_ctl fires CDSP which will bridge data between the ADC alsa card and the gadget alsa card, adjusting "Playback Pitch 1000000" continually to fit the fixed ADC clock.
Last edited:
- Home
- Source & Line
- PC Based
- Linux USB-Audio Gadget (RPi4 OTG)