using a Raspberry Pi 4 as a USB DSP-DAC

Status
This old topic is closed. If you want to reopen this topic, contact a moderator using the "Report Post" button.
Does RPi HDMI really support 24-bit audio? Last time (Oct-2018) I asked the answer was no. Apparently the HDMI audio could on Pi could really support 24-bit PCM and some their developer wrote on github issue that they had added it but later removed because of some incompatibility issues with some device.

At least in 4.19 there isn't support for 24-bit format:
linux/bcm2835-pcm.c at rpi-4.19.y * raspberrypi/linux * GitHub
(they have oddly moved the driver under vc04_services).

This may be too early for 5.3:
linux/bcm2835-pcm.c at rpi-5.3.y * raspberrypi/linux * GitHub

No 24-bit support (yet).

There is this issue:
Alsa driver limited to 16-bit / 48kHz audio files * Issue #494 * raspberrypi/linux * GitHub

The driver supplied with Raspbian does not, but it is a simple matter to modify the source code and re-compile the kernel. I outlined all the steps to do this in this thread:
2-in, 8-out DSP platform using the Raspberry Pi + HATs

The directions in the thread were developed for the Pi 3. Since that time I have also done the mod on a Pi 4:
Code:
pi@Pi4gadget:~/linux/drivers/staging/vc04_services/bcm2835-audio $ nano ./bcm2835-pcm.c

The section of code pertaining to HDMI looks like this after my modifications:
Code:
static const struct snd_pcm_hardware snd_bcm2835_playback_spdif_hw = {
        .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
                 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
                 SNDRV_PCM_INFO_DRAIN_TRIGGER | SNDRV_PCM_INFO_SYNC_APPLPTR),
        .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE,
        .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_44100 |
        SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
        .rate_min = 44100,
        .rate_max = 192000,
        .channels_min = 2,
        .channels_max = 8,
        .buffer_bytes_max = 512 * 1024,
        .period_bytes_min = 1 * 1024,
        .period_bytes_max = 512 * 1024,
        .periods_min = 1,
        .periods_max = 128,
};
 
Last edited:
Have you tried it?

Anyone else?

Instructions and info can be found here:
using a Raspberry Pi 4 as a USB DSP-DAC

I have reviewed the package prior to trying it. I have a couple of questions:

- Why should I not power the RPi through PC USB? I'm able to run my RPi4 with PC usb power without problems when I underclock it to 1 GHz. And I don't have any other means to power it than usb, so it's either PC usb power or no usb connection to PC.

- If PC usb power is a NOGO, I should try it through LAN and ethernet instead. Could you make an guide and packge for that?

- Somewhere on this thread you wrote that the delay is roughly 500 ms, measured with eye-hand. Thats way too much for something like pc gaming, could be OK for movies, if lipsync settings allow that much delay. Is there a way to make it smaller?

I'm afreaid I cannot test the package as-is today, but maybe I/we can cook next week.
 
I have reviewed the package prior to trying it. I have a couple of questions:

- Why should I not power the RPi through PC USB? I'm able to run my RPi4 with PC usb power without problems when I underclock it to 1 GHz. And I don't have any other means to power it than usb, so it's either PC usb power or no usb connection to PC.

It's your equipment, so you can do what you want. Obviously you have already tried it... According to what I read:
Current requirement:
The Raspberry Pi 4 spec recommends a 3 A supply (15 W), with a minimum current of 2.5 A if downstream USB peripherals consume less than 500 mA in total.


When you underclock, you are reducing the power requirement. The USB-C spec says the connection should be able to supply up to 2A of 5V power, and assuming you do not connect anything that would consume power (e.g. USB DAC) then you may be OK. I do not recommend it in general because some careless person might damage their gear and then blame me for that. Also, I do not know the details of USB-C and it has many different modes of operation. I'm just not sure.

- Somewhere on this thread you wrote that the delay is roughly 500 ms, measured with eye-hand.

In my initial trials I got this figure because I had not specified any values for the various send/receive audio buffers. The defaults are around 200msec each, plus some RTP buffering in addition to that. In total it comes to around 500msec if you use the default values without modification.

You will find buffer control user variables at the top of each batch/script file. This lets you control the total latency to some degree. The values are set to 60msec each. You can try to make them as low as possible until the audio breaks, then set them slightly higher. Try 10msec. Go as low as you like - it will not hurt anything but at some point the audio will stop.
 
Okey, I'll get back to this asap. Just for the record, my Raspberry Pi 4 is now running 24/7 with no problems with 5V, 1A power supply (old phone charger) underclocked to 1 GHz. I didn't touch voltages yet. Usage is very light. I've been running it sort whiles from pc usb 3.1 port, which power output I don't know. I think it's a lot safer to underclock than it is to overclock :)
 
UPDATE: I tried and failed and succeeded.

I did the steps on the pi, booted while connected to pc and I could not connect to it or see it on my Windows. Leds were on, but no other sign of life. Not sure where I went wrong, but the /etc/dhcpcd.conf file didn't exist previously, should it have?

Also before trying to modify your script to suit ethernet lan cable connection, I saw a clever way of counting received packet count. But is it suitable, since that will climb with just the putty connection on?

Nevertheles I went on, and changed "/sys/class/net/usb0/statistics/rx_packets" to "eth0", put some ip addresses up and started running scripts. I used "plughw:CARD=Audio,DEV=0" for alsa device, this one is different from the "hw" prefixed, does it make a difference? I will try other options tomorrow.

I got on the pi:
Code:
Program execution began at: 09/09/19 23:07:41

09/09/19 23:07:42  new status:
IP: up, no data flow, gstreamer not running

09/09/19 23:09:07  new status:
IP: up, receiving audio data, gstreamer not running

action: gstreamer pipeline launched at 09/09/19 23:09:07

09/09/19 23:09:10  new status:
IP: up, receiving audio data, gstreamer pipeline is running

And on the pc:
Code:
Program started at ma 09.09.2019 23.09.03,32
-------------------------------------------------------------

destination IP 192.168.0.100 can be reached. Launching gstreamer at ma 09.09.2019 23.09.05,51

the connection is active and gstreamer is running

And I can hear music from my speakers! I have usb-dac with external power supply etc. It's too late now to audibly validate that the music sounds as it should, I will resume tomorrow.
 
Last edited:
Hi Jukka,

It looks like you got it working over your LAN. It's possible that trying to power the Pi via USB-C at the same time that you are trying to connect the USB ethernet gadget is not working for you because either (A) those are not possible at the same time, (B) you do not have the right USB-C cable, or (C) something else. Like I said, USB-C is complicated...

Not sure why you do not have the /etc/dhcpcd.conf file... I have the latest version of Raspbian on my Pi 4 and I believe it was included along with the OS files.

Regarding the packet counting: if you are getting false readings about audio data, you can increase the threshold variable. You can test how the packet count is increasing by using cat to read the variable manually, and do it about 1x per second:
Code:
cat /sys/class/net/eth0/statistics/rx_packets
You can increase the threshold as you wish. I think I check the count every 2 seconds in the script. In the worst case, some data flow from SSH will trigger a false turn on of Gstreamer but since there will not be any audio data coming into port 1234 no audio will be produced, when data flow stops, Gstreamer will automatically be terminated.

The output you showed from the Windows and Pi scripts seems about right. I can see when audio started flowing. Do some listening and post your thoughts here.
 
Last edited:
Hi Charlie!

Something is not right. I fired everything up and when listening to music, I can hear music alright, but it's lower in volume than expected, NO bass and mostly on the right channel. This sounds like some format incompatibilty. I changed alsadevice to "hw:" prefixed version, results the same. What do? I'm new to Linux, so this is beyond me.

Is there a way to check audio device capabilities? I could check all playback settings so that I'm using supported formats. All I know from my usb-dac manufacturers specs is 16/24 bits and up to 96 KHz with usb.

PS. I din't notice this last night, because I was using minimal volume, barely audible, in order to not disturb my family asleep.
 
Last edited:
Hi Charlie!

Something is not right. I fired everything up and when listening to music, I can hear music alright, but it's lower in volume than expected, NO bass and mostly on the right channel. This sounds like some format incompatibilty. I changed alsadevice to "hw:" prefixed version, results the same. What do? I'm new to Linux, so this is beyond me.

Is there a way to check audio device capabilities? I could check all playback settings so that I'm using supported formats. All I know from my usb-dac manufacturers specs is 16/24 bits and up to 96 KHz with usb.

PS. I din't notice this last night, because I was using minimal volume, barely audible, in order to not disturb my family asleep.

The format must remain the same, starting with the playback device in Windows that is the default device. This is the one that will give the audio to WASAPI for Gstreamer to stream from the Windows computer.

First step is to decide what sample rate and audio format you want to use. As an example, let's say you want to use 24 bits and 48kHz. Then you follow these steps:
1. On your Windows machine, set the default playback device sound settings to 24 bits and 48kHz.
2. In the stream_my_audio.bat file on the Windows computer, make sure that you have on line 13:
SET bit_depth=24
3. In the "receive_my_audio.sh" file on the Pi, make sure that you have:
bit_depth=24 (this is the stream format)
sample_rate=48000 (this is the stream format)
4. You can also check:
output_audio_format=S24LE
The output_audio_format is the format that will be sent to the DAC. It does not have to be the same format as what is streamed. In Gstreamer, S24LE is the ALSA format S24_3LE. Other common formats include S16LE and S32LE. Use whatever you want the DAC to use.

If the format you choose initially is not supported by the default Windows playback device, you can either choose a supported format or use another device (e.g. like the VB-Cable I suggested) that will support your desired format by choosing that one to be the default playback device. Whatever you choose, follow the steps above and substitute the rate and format that your Windows playback audio device is using.

Please check these settings, make sure everything is consistent, and try it again.
 
Last edited:
Okey, here's an update.

I found a script called alsa-capabilities and it reported the following for my dac:
Code:
 1) USB Audio Class Digital alsa audio output interface `hw:1,0'
 - device name       = Audio
 - interface name    = USB Audio
 - usb audio class   = 2 - isochronous asynchronous
 - character device  = /dev/snd/pcmC1D0p
 - encoding formats  = S24_3LE
 - monitor file      = /proc/asound/card1/pcm0p/sub0/hw_params
 - stream file       = /proc/asound/card1/stream0

If I put "S24_3LE" to the Pi script, it will print "action: gstreamer pipeline launched at 09/10/19 18:57:22" in a loop and no sound. Reverted back to "S24LE".

Using lower than "96000" in sample rate results in "slowmotion" playback. This is the same wheter I put any default sample rate into settings of the Windows default playback device (mobo integrated soundcard). I restarted the Windows script in between and made no changes to it. Again no difference between "plughw:" and "hw:" prefixed audio devices. If I set Windows playback rate to any and pi rate 96k, the pace of the music normal, but original no bass, pan to right problems are still in effect. Maybe the Windows configs are not correct/don't change as they should?
 
Okey, here's an update.

I found a script called alsa-capabilities and it reported the following for my dac:
Code:
 1) USB Audio Class Digital alsa audio output interface `hw:1,0'
 - device name       = Audio
 - interface name    = USB Audio
 - usb audio class   = 2 - isochronous asynchronous
 - character device  = /dev/snd/pcmC1D0p
 - encoding formats  = S24_3LE
 - monitor file      = /proc/asound/card1/pcm0p/sub0/hw_params
 - stream file       = /proc/asound/card1/stream0

If I put "S24_3LE" to the Pi script, it will print "action: gstreamer pipeline launched at 09/10/19 18:57:22" in a loop and no sound. Reverted back to "S24LE".

Using lower than "96000" in sample rate results in "slowmotion" playback. This is the same wheter I put any default sample rate into settings of the Windows default playback device (mobo integrated soundcard). I restarted the Windows script in between and made no changes to it. Again no difference between "plughw:" and "hw:" prefixed audio devices. If I set Windows playback rate to any and pi rate 96k, the pace of the music normal, but original no bass, pan to right problems are still in effect. Maybe the Windows configs are not correct/don't change as they should?

The loop is Gstreamer failing because you tell it to use a format that is not known, and the script restarting it over and over. Gstreamer does not know the format "S24_3LE". Like I explained above, you must use the Gstreamer equivalent of S24LE in the Pi script.

You can check the supported sample rates for your DAC by typing:
Code:
aplay -D hw:1,0 --dump-hw-params /dev/zero
You will see info about supported rates and formats. Please post the output here.

What playback device is the default one under Windows? What is the format you selected for it? This video has an example of how to select the playback format:
YouTube
If the playback software can change the sample rate and audio format, perhaps to the native format of the file to be bit perfect, the audio will not sound correct.

Please, on your Windows machine, install VB-Cable and configure that as your default playback device. See:
VB-Audio Virtual Apps
Set both recording and playback of VB-Cable to the one you want (e.g. 24/96).

Also, plughw: allows ALSA to resample or reformat the audio that is being sent to the DAC by Gstreamer. That's is not needed, or wanted. I would instead stream in a format that the DAC already supports and use hw: instead.
 
I was wondering if this project is still being kept active?

Lately I have been looking for a solution to use this solution (or similar) for bidirectional audio.
Essentially just 2 pairs audio in and 2 pairs audio out.

I was wondering if the audio part also works for Mac.
Also, is there some kind of easy manual somewhere?
I have been reading and digging through a lot of pages, but it's a little bit difficult to understand what exactly is possible and what not.
Besides bidirectional audio, is it also possible to send mutli-channel to be separated and send to other pi's as well?
 
Last edited:
I was wondering if this project is still being kept active?

Lately I have been looking for a solution to use this solution (or similar) for bidirectional audio.
Essentially just 2 pairs audio in and 2 pairs audio out.

I was wondering if the audio part also works for Mac.
Also, is there some kind of easy manual somewhere?
I have been reading and digging through a lot of pages, but it's a little bit difficult to understand what exactly is possible and what not.
Besides bidirectional audio, is it also possible to send mutli-channel to be separated and send to other pi's as well?

I don't think bi-directional audio is possible. Not sure, because that is outside the scope of the project and I never thought to try it.

Forum member phofman could give you a better answer. He has more experiences with the USB-OTG interface in general and is familiar with the driver code.

Not to steer you elsewhere, but why not just buy a USB pro-audio interface? This will have very good recording and playback capabilites. Most modern ones are full duplex (can simultaneously record and play back audio).
 
I don't think bi-directional audio is possible. Not sure, because that is outside the scope of the project and I never thought to try it.

Forum member phofman could give you a better answer. He has more experiences with the USB-OTG interface in general and is familiar with the driver code.

Not to steer you elsewhere, but why not just buy a USB pro-audio interface? This will have very good recording and playback capabilites. Most modern ones are full duplex (can simultaneously record and play back audio).

Thanks
Yeah, I am (well) aware of these USB interfaces.
The idea is to make something similar from scratch (just for fun) that's a bit more capable.
So this whole project basically ticks all the marks.

Another way would be using an audio over ethernet solution.
With a 100mbit port there is plenty over bandwidth.
I am not quite sure yet how virtual cable (and the like) will handle that.
Plus practically it will like the same; usb to ethernet adapeter -> ethernet cable -> ethernet port.

That's why I thought gadget mode option would be a little easier.

I worked out pretty much every alternative as well, but these two (ethernet and gadget mode) are what I keep coming back to over again.
 
The UAC2 gadget is duplex, each direction is basically independent (any samplerate/channels, formats).

Current status - fixed maximum throughput in both directions. I am not sure my patches are already included, the linux-usb mailing list has a bit unusual policy for picking patches compared to the very organized alsa-devel.

The remaining issues (nice handling of the alsa devices and async mode) are still on my TODO list. Perhaps the async mode could be implemented by a very capable driver professional, I will have to revive the discussion 'Re: usb:gadget:f_uac2: EP OUT is adaptive instead of async' - MARC
 
The UAC2 gadget is duplex, each direction is basically independent (any samplerate/channels, formats).

Current status - fixed maximum throughput in both directions. I am not sure my patches are already included, the linux-usb mailing list has a bit unusual policy for picking patches compared to the very organized alsa-devel.

The remaining issues (nice handling of the alsa devices and async mode) are still on my TODO list. Perhaps the async mode could be implemented by a very capable driver professional, I will have to revive the discussion 'Re: usb:gadget:f_uac2: EP OUT is adaptive instead of async' - MARC

Thanks, what about latency?
 
Status
This old topic is closed. If you want to reopen this topic, contact a moderator using the "Report Post" button.