Skip to content

StreamingAudioToInternet

sm0svx edited this page Oct 5, 2014 · 5 revisions

Streaming of the repeater audio e.g. to internet

Sometimes it is useful to have the output of the repeater available as a stream on internet. For example, player applet can be put on the website of the repeater to invite visitors to listen. It can also be useful during events and demos.

It is customary to install a receiver at someone’s QTH and stream the output audio to internet using one of the many available applications (usually on a Windows system), but it can be done on the repeater system as well.

Central to the solution is the availability in Alsasound of a Loopback soundcard. This is a virtual soundcard that appears in the system as two different devices, each with a number (default 8) of subdevices. They are named like this:

Loopback,0,0
Loopback,0,1
...
Loopback,0,7
Loopback,1,0
Loopback,1,1
...
Loopback,1,7

You can use those devices in any application that supports Alsasound, including SvxLink and most streaming software. When a program opens 'Loopback,0,0' for output and another program opens 'Loopback,1,0' for input, that program will receive the audio that the first program outputs. It works in the other direction at the same time, so any output sent to 'Loopback,1,0' will appear on 'Loopback,0,0' as well. There is one caveat: the parameters of the "soundcard" have to be the same at both ends (sample rate, mono/stereo, bits per sample, etc). The first program that gets to open one end of the device pair sets the parameters to its liking, and the other end has to conform to that. This sometimes leads to problems and confusion, as success or failure will often depend on the startup sequence of SvxLink and the streaming software.

In Alsasound, there is a plugin 'plughw' that is often used to access the soundcard because it would normally convert between what the application demands and what the soundcard can provide, e.g. conversion of sample rate or format. However, plughw cannot convert everything. And, plughw first tries to set the parameters that the application requests, and will only perform conversion when that is not possible. So in practice when you use plughw on both ends, it still does not always work, for example when the streaming software asks for a parameter that SvxLink cannot live with. When SvxLink would have opened the device first, it would have set the card the way it likes and it would work OK. Unfortunately, there is an open issue in SvxLink that it opens the sound device at the beginning of a transmission rather than at program startup, making it quite tricky to get everything working at startup. Until that is fixed you may need to make mods to the streaming software in the function that opens the soundcard and sets parameters (more on that later).

I recommend to use 'hw' rather than 'plughw' whereever possible, so that at least you get predictable and consistent results all the time. Use plughw only after it has been determined that a conversion is required, and use it only on one end. Also, instead of using automatic plughw conversion it is more robust to setup a fixed entry in /etc/asound.conf that has the correct parameters.

Basically, to connect some extra software to svxlink you do a setup like this:

[RepeaterLogic]
TYPE=Repeater
TX=MultiTx
# (i.e. use the MultiTx instead of connecting the Tx directly here)

[MultiTx]
TYPE=Multi
TRANSMITTERS=Tx1,TxStream
# (these are our multi transmitters, both the main Tx1 and our stream Tx)

[TxStream]
TYPE=Local
AUDIO_DEV=alsa:hw:Loopback,0,2
AUDIO_CHANNEL=0
PTT_TYPE=NONE
TIMEOUT=7200
TX_DELAY=0
PREEMPHASIS=0
# (use Loopback,0,2 as output towards the Loopback soundcard)

Note that you can omit CTCSS on this Tx even when you have it on your main Tx. This means the CTCSS is not sent to the stream listeners, where it will be annoying when they have good loudspeakers connected.

Install the Loopback soundcard at boottime by adding this line to /etc/modules:

snd-aloop

You can load the module in your running system using 'modprobe snd-aloop'.

At the other end of the Loopback, we will connect darkice as a streamer. Put the following in /etc/asound.conf:

pcm_slave.hw_Loopback_1_2 {
  pcm "hw:Loopback,1,2"
  format S16_LE
  channels 2
  rate 48000
}

pcm.plug_Loopback_1_2 {
  type plug
  slave hw_Loopback_1_2
  ttable {
    0.0 = 1
    0.1 = 1
  }
}

Now, when you open the device 'plug_Loopback_1_2' in an application, the above will force the 'Loopback,1,2' to be configured with parameters that SvxLink likes, and the explicit wiring of only the left channel. The darkice config will then be like this:

[general]
duration        = 0         # duration of encoding, in seconds. 0 means forever
bufferSecs      = 1         # size of internal slip buffer, in seconds
reconnect       = yes       # reconnect to the server(s) if disconnected
realtime        = no        # run the encoder with POSIX realtime priority
rtprio          = 3         # scheduling priority for the realtime threads

# this section describes the audio input that will be streamed
[input]
device          = plug_Loopback_1_2 # ALSA soundcard device for the audio input
sampleRate      = 22050     # sample rate in Hz. try 11025, 22050 or 44100
bitsPerSample   = 16        # bits per sample. try 16
channel         = 1         # channels. 1 = mono, 2 = stereo

Note we use 22050 samples/s here to save on bandwith towards the listeners, but the "plug" configuration and the hardwired 48000 samples/s defined for Loopback,1,2 means the Alsa system will convert from 48000 to 22050 samples/s.

As described up to here it will work when darkice is started while SvxLink has its end of the soundcard open (and thus all parameters set the way it likes). Unfortunately that means that you will have to start darkice at a moment when the repeater is transmitting. For automatic startup this is inconvenient, but this can be fixed with a small change in the darkice sourcefile src/AlsaDspSource.cpp. In the function AlsaDspSource :: open before the line u = getBufferTime(); insert this fragment:

snd_pcm_uframes_t f = 4096;
if (snd_pcm_hw_params_set_buffer_size_near(captureHandle, hwParams, &f) < 0) {
    snd_pcm_hw_params_free(hwParams);
    close();
    throw Exception( __FILE__, __LINE__, "can't set buffer size", f);
}

This will no longer be required when SvxLink issue #96 has been solved.

Clone this wiki locally