Nothern Utah WebSDR Logo - A skep with a Yagi Northern Utah WebSDR
Configuring high-rate
(and normal-rate)
audio loopback devices

What, why, huh?

In the other pages related to higher-bandwidth (>192 kHz) 16 bit receivers on the PA3FWM WebSDR software it was (probably) mentioned somewhere that getting the raw I/Q data from the receiver - in our case, the SDRPlay RSP1a - involved setting up audio loopback devices in ALSA.  On this page, we'll describe how this might be done.  Please note that this page assumes at least some familiarity with Linux (at least the "know enough to be dangerous" level) so if you know nothing of its inner-workings, you should be prepared to consult a friend, do web searches and the like.


Important:

Before proceeding, do:

aplay -l

You should see at least one sound device in the list - possibly more - but if you see "...no soundcards found..." it may be that your OS install was done without any sound devices present  and/or that the sound system or installation of it may be broken.

A possible fix is to reinstall the sound system as follows:


sudo apt-get --purge remove linux-sound-base alsa-base alsa-utils

sudo apt-get install linux-sound-base alsa-base alsa-utils

sudo apt-get install dkms build-essential linux-headers-`uname -r` alsa-base alsa-firmware-loaders alsa-oss alsa-source alsa-tools alsa-utils

sudo usermod -a -G audio username

After this has completed, reboot ("sudo reboot") and this problem will (hopefully) be resolved.

The above is from https://askubuntu.com/questions/1032431/ubuntu-18-04-no-sound-card-detected



Setting up "snd-aloop" - the ALSA Loopback device:

To start out, let's configure some audio loopback devices using the standard "snd-aloop" module:  This module, like many other parts of ALSA, are limited to just 192 kHz, but because the set-up is the same as the "fast" version that will be introduced later, we'll discuss it first - and you might find this information useful, anyway.  This information isn't intended to be complete tutorial on setting things up (use a search engine to find out more!) but it should get you started.

First, show the currently-configured audio devices by doing:  aplay -l

This will show the available audio devices, by index number (e.g. card 0:  card 8: etc. )and the name of the audio device which may include the actual name of the hardware/manufacturer.  It will also show a list of "subdevices" which can be used to mix streams or send the output to several places at once, both of which can be very useful, but we won't be using them at this time.

For more information about subdevices, see the following links:

Configuration:

To configure a loopback in ALSA, edit the file /etc/modprobe.d/alsa-base.conf   (e.g. sudo nano /etc/modprobe.d/alsa-base.conf )

If it doesn't already exist, add the line (probably at the end):  options snd-aloop index=16,17 id=lp0,lp1 enable=1,1 pcm_streams=4,4

Up to eight loopback devices may be configure, the parameters for each one is separated by a comma (no spaces) as shown in the example above.

Explanation:

You may manually start/restart the loopback device(s) by typing:  sudo modprobe snd-aloop

Note:  
If you get an error, you may need to install "alsa-utils" to your system by doing:  sudo apt-get install alsa-utils

If all went well - after you have started "snd-aloop", you should be able to do aplay -l and see the loopback devices with the given device IDs and indexes ("card") numbers.  If nothing happened, re-check the configuration in "alsa-base.conf".

If this was successful - and if you wish to have your loopback start up at boot, edit the file /etc/modules (e.g. sudo nano /etc/modules ) and add the line:  snd-aloop .  You may wish to reboot the computer to verify that it works.

If you wish to test the loopback devices yourself by passing audio through them, read about how they may be used in this article:  https://sysplay.in/blog/linux/2019/06/playing-with-alsa-loopback-devices/

Setting up the .asoundrc file

In our case we wish to install some "plugins" to allow us to more easily direct audio to/from our applications:   Doing this may not strictly be required for our application (re:  WebSDR) but its flexibility is worth the trouble.

The ".asoundrc" file is created in the directory of the user in question:  For the WebSDR, it would be placed in the "websdr" directory (e.g. the root directory of the WebSDR's files) while being logged in as the WebSDR user.  
While we could reference the loopback devices directly, using .asound allows us to select the specific device and, if necessary, do sample rate conversions and a few other tricks without having to mess with the original loopback configurations mentioned above.

An example of what you might put into this file is as follows:

#
pcm.!default {
    type hw
    card 0
}

ctl.!default {
    type hw
    card 0
}
#
# Direct audio from receiver to "loop#_in" and point WebSDR at "loop#_out"
#
# Input from receiver - Loopback 0
#
pcm.a_loop0_in {
    type plug
    slave {
        pcm "hw:lp0,0,0"
        rate "unchanged"
        format "unchanged"
        channels "unchanged"
    }
}
#
# output to WebSDR - Loopback 0
#
pcm.a_loop0_out {
    type plug
    slave {
        pcm "hw:lp0,1,0"
        rate "unchanged"
        format "unchanged"
        channels "unchanged"
    }
}
#

Pay specific attention to the portion starting with the line "pcm.a_loop0_in":  This creates a device of type "plug" called "a_loop0_in" that points to "lp0" - our first loopback device - to which we send the raw I/Q data from our receiver.  In the section below this we create another device called "a_loop0_out", a virtual sound card that we can reference in our "websdr.cfg" file from which we can pull this data.

For example:
Although you could name them whatever you like, giving the virtual devices descriptive names is strongly suggested:  The name "a_loop0_in" clearly refers to a loopback device, instance 0 (e.g. the first one) and that it is an input device  - and the converse for its counterpart "a_loop0_out".  

To add our second defined loopback device, one would add the following to this file:

#
# Input from receiver - Loopback 1
#
pcm.a_loop1_in {
    type plug
    slave {
        pcm "hw:lp1,0,0"
        rate "unchanged"
        format "unchanged"
        channels "unchanged"
    }
}
#
# output to WebSDR - Loopback 1
#
pcm.a_loop1_out {
    type plug
    slave {
        pcm "hw:lp1,1,0"
        rate "unchanged"
        format "unchanged"
        channels "unchanged"
    }
}
#

and so on - up to eight devices.

With .asoundrc, a lot of other things may be done (sample rate and type conversion, etc.) that are beyond the scope of this document - but I'll leave such things to the curious reader.

Sending receiver data elsewhere:

Using the loopback devices, you can send the output data to more than one device such as other receivers or receive programs and other computers.  As an example, it should be possible to send raw I/Q data into another program  that can be "tuned" to a specific frequency within the raw I/Q stream to do something like decode CW, FT-8, WSPR - or, perhaps, a specific frequency.  This data - or perhaps the output of this data from that "other" program used to "tune" it - could also be sent across the network to another device.

If you do choose to stream raw receiver data over your network, remember that a wideband receiver can produce a lot of data:  On a computer with a reasonable CPU and a 1 Gbps Ethernet port (and a fairly stout network switch) this may not be much of a concern, but if you are considering sending this across a lower-bandwidth LAN - or outside our local network - you should very carefully calculate the implications of doing so.  One way to reduce a lot of raw receiver data (e.g. 192, 384 or 768 kHz of bandwidth) to something more "bite-sized" is to pre-process it with another program - "tuning" in a specific frequency within the raw data.  One way to do this is with the "CSDR" package - a command-line Linux SDR that is highly configurable.  Another package that might be useful in this regard is Soapy.

An example of using the Loopback to send audio to other programs may be found at AB9IL's web site (see this article) where the WebSDR's receivers serve double-duty, feeding other programs such as FLDigi, WSJT-X.


The "Fastloop" module:

Mentioned earlier is the fact that "snd-aloop" has a built-in speed limit of 192 kHz:  This is not a limit imposed by the ALSA core, but rather many of the associated programs and modules which were not patched since ALSA was modified to allow up to 768 kHz several years ago.  To remove this limit, we must patch and compile snd-aloop - and to avoid confusion, we will rename it to "snd-fastloop".

IMPORTANT - PLEASE READ:

The following procedure has been tested ONLY on Ubuntu 18.x and 20.04.01 LTS.   It is known to NOT work on Ubuntu 16.x as described below.  It has NOT been tested on Debian or other Linux distros.

If you have a different version of Linux and have verified that the information below works - or if you have developed a similar procedure for your distro, please let us know via the email address at the bottom of this page.

You may find the file "fastloop.tar.gz" HERE.

1)  Typically starting from the "websdr" directory of your system create a "fastloop-src" directory ("md fastloop-src"), go into it ("cd fastloop-src)" and place the "fastloop.tar.gz" file there.  In that location, extract the contents of fastloop.tar.gz and change to the resultant fastloop directory (e.g., "tar xf fastloop.tar.gz", "cd fastloop").

2)  Build the snd-fastloop.ko module:   Do this by typing "make". This will automatically download the vanilla snd-aloop source, apply the necessary changes to make it support 768 kHz sampling, and then compile it to "snd-fastloop.ko".

Note:  You may get an error (particularly if you are doing this under Unbuntu 18.x) in which case you may try deleting the first three lines of the file "fastloop.patch" and trying again.

Do not proceed until you have successfully built "snd-fastloop.ko" and note that its size is approximately 30k.  This file may still be created even if the "make" fails, but it will have either a zero length, or be much smaller than 30k.


3)  If the compilation succeeded, install the newly built module:  "sudo make modules_install". This will save the module under /lib/modules/[x.y.z]/extra/, where modprobe will find it.

It is possible - or even likely - that this step will throw a few errors related to certificates and/or keys and the installation of the module will fail.  If you like, you can go through the hassle of creating your own certificate/key (I'll let you figure out how to do this...) but if you aren't bothered about keys and things, do the following at the command line:

    sudo depmod -a

After a brief pause, the module "snd-fastloop.ko" should be installed.

If you wish to verify the installation of this module, go to /lib/modules ( cd /lib/modules ).  The sub-directory that you want will likely be the one with the highest version number:  Go into that directory where you should find the "extra" subdirectory, and in that directory you should see "snd-fastloop.ko" and its size will be somewhere around 30k.

4)  Create a file "/etc/modprobe.d/fastloop.conf", containing the  module options you want to apply. For instance, you could use something like "options snd-fastloop index=8 id=fl0 enable=1".  This is the same procedure as above, except, of course, that we are using "snd-fastloop" instead of "snd-aloop".  You can specify up to eight devices.

Comment:  You can have both "snd-aloop" and "snd-fastloop" devices at the same time, but remember that you can have only up to 32 total sound devices (0-31) - including any audio hardware that may already be installed on your system.

5)  Load the fastloop kernel module: "sudo modprobe snd-fastloop".  If all goes well, you should be able to do "aplay -l" and see the loopback devices with names like "fl0", "fl1", etc.  If you do not see that, carefully review the above steps and check for errors.

To have the module loaded automatically on every boot, you can add the line "snd-fastloop" to the file "/etc/modules" in a manner similar to that described above.

Important -  If you update your Linux distro:

If you upgrade your operating system, you will probably have to re-install "snd-fastloop".  Because it isn't part of the standard package, it won't appear in the appropriate /lib/modules subdirectory after an upgrade.  It's likely that you'll need only do step 3, above - but be prepared to do steps 1-3.


Conclusion:


The above information should be enough to get the loopback system up and running.  Again, the above has been tested and found to work on Ubuntu 18.x and 20.04, but it is not known if this same procedure will work for other Linux distributions like Debian.  If you try it on another distribution, please let us know if it works - and what it took to make it work if it didn't do so "out of the box".  At the time of writing, we don't have a Debian system on which to try/troubleshoot this installation.

Please understand that we don't have the time or inclination to try the above procedure on OSes other than Ubuntu 18 and 20 (there are so many!) so again, please let us know about your successes or failures so that we can let others know.


Acknowledgment:
 I would like to thank Gary Wong, AB1IP, for taking the time to produce and test the patch to make the "snd-fastloop" module, and for his help in writing the procedure for doing so.





Additional information:
 Back to the Northern Utah WebSDR landing page