Skip to content
Snippets Groups Projects

AURA Engine Core

Contributor Covenant Latest Release pipeline status

Engine Core is a multi-channel playout server for radio stations based on Liquidsoap. It is able to broadcast via audio device outputs or connect to Icecast streams.

This documentation is primarily meant for developers. For using the AURA Community Radio Suite check out the documentation at docs.aura.radio

To learn more about Automated Radio go to aura.radio.

Channel Routing

Playout channels are routed this way:

graph TD
    iq0[Queue A] -->|in_queue_0| mix
    iq1[Queue B] -->|in_queue_1| mix
    is0[Stream A] -->|in_stream_0| mix
    is1[Stream B] -->|in_stream_1| mix
    il0[Line In 1-5] -->|in_line_0..4| mix
    ff[Fallback Folder] -->|fallback_folder| which_fallback
    fpls[Fallback Playlist] -->|fallback_playlist| which_fallback
    mix["  Mixer  "] --> silence_detector
    which_fallback{or} -->| | silence_detector{Silence Detector}
    silence_detector -->| | output[Output]
    output --> |output.alsa| C[fa:fa-play Audio Interface]
    output --> |output.icecast| D[fa:fa-play Icecast]

Prerequisites

Before you begin, ensure you have met the following requirements:

Installing Engine Core

Install system dependencies:

apt install curl alsa-utils libasound2-dev libavcodec-dev libavdevice-dev libavformat-dev libavutil-dev libflac-dev libjack-dev libpulse-dev libswresample-dev libswscale-dev libssl-dev ffmpeg opam

Build Liquidsoap with additional libraries:

opam depext alsa pulseaudio bjack ffmpeg samplerate flac taglib mad lame vorbis flac opus cry ocurl liquidsoap -y
opam install alsa pulseaudio bjack ffmpeg samplerate flac taglib mad lame vorbis flac opus cry ocurl liquidsoap -y

Now initialize the project environment for development

make init.dev

This command also creates a default configuration file config/engine-core.ini.

Configuring Engine Core

Configure the audio interface

You get the most glitch-free experience when using PipeWire as your media server. To avoid any play-out malfunctions ensure that no other media server is running. PipeWire is capable of replacing PulseAudio while still having the full functionality of PulseAudio if you want to keep PulseAudio. To check if PipeWire has replaced PulseAudio, run make audio.pa.status. This command should return a line like

Server Name: PulseAudio (on PipeWire 0.3.80)

To check if PipeWire is up and running you can use

systemctl --user status pipewire

Choose your audio system ALSA / JACK

At the moment we recommend running engine-core with JACK. ALSA support for the complete AURA system was dropped in favour of JACK but might be added back in. In either case PipeWire takes care of your devices and connections.

Configure JACK/ALSA

Have a look at config/sample.engine-core.ini. Here you can set things like the log level and much more. For JACK no adaptations are necessary.

For ALSA you might want to set a different audio device or even configure your own. An example can be found in config/sample.asoundrc. Very important is the alsa_buffer, if you experience jitter, cracklings or other audio artifacts you should increase this number. If the buffer is to large you will experience bad latency, to reduce the latency you have to reduce the buffer size.

When you are finished copy the configuration config/sample.engine-core.ini to config/engine-core.ini.

cp config/sample.engine-core.ini config/engine-core.ini

Configure the audio source locations

Engine Core is requires different audio sources in order to perform the playout.

Configure the location for fallback music

By default fallback audio is retrieved from the fallback folder. A local folder for any emergency playback, also called Station Fallback.

audio/fallback/

All audio files inside are played in a randomized order, in situations where nothing is scheduled. The folder is being watched for changes. So you can add/remove audio on the fly.

This fallback feature is enabled by default, but can be turned off in via the configuration.

Instead of the fallback folder you can use a playlist in the playlist folder for fallback scenarios. Its default file location is:

audio/playlist/station-fallback-playlist.m3u

Also this playlist is being watched for changes. You'll need to set the configuration option fallback_type="playlist" to enable this instead of the fallback folder.

Configure the audio source folder

This is the location for actually scheduled audio files. They are provided by Tank.

audio/source

If you are running all AURA services on a single instance you should be fine with just creating a symbolic link to the relevant Tank folder (ln -s $TANK_STORE_PATH audio/source). But in some distributed and redundant production scenario you might think about more advanced options on how to sync your audio files between machines.

You can find some ideas in the doc "Setting up the Audio Store".

Configure via environment variables

Many settings of Engine Core can also be set via environment variables. They are primarily used for Docker deployments. Check the Makefile and sample.env for hints on environment variables.

Running Engine Core

To make the playout server play some music first create the folder audio/fallback/ if it doesn't exist and drop some music files. This folder is picked up as a so-called Station Fallback in case no other music is scheduled or if silence is detected.

To start the server execute

make run

Connect Audio Device

Now connect your audio device(s) with engine-core. There are two ways to achieve this:

  • use an UI like qpwgraph, simply draw connections between the desired devices
  • use the PipeWire cli tool pw-link
# List the input ports
pw-link -i
# List the output ports
pw-link -o
# An example for connecting an output port with an input port
pw-link "lineout_0:out_1" "alsa_output.usb-BEHRINGER_UMC202HD_192k_12345678-00.stereo-fallback:playback_FR"
# An example for connecting an input port with an output port
pw-link "alsa_input.usb-Yamaha_Corporation_Yamaha_AG06MK2-00.pro-input-0:capture_AUX0" "in_line_0:in_0"

Voilá, you should hear some music!

Running Engine Core with docker compose

When running engine-core with docker compose you need a different configuration file to start with. Have a look at config/sample.engine-core.docker.ini and copy it to config/engine-core.ini (FIXME: this uses the overwrite in /etc/aura/ and is not the best of options). Do not change the paths here, rather change them in sample.env and copy this file to .env. Make sure the directories in .env are read and writable for the user used in the container, mainly aura(2872:2872).

It is important to set the PIPEWIRE_USER_ID to the uid of the user running pipewire. To check which user is running the pipewire server run the following:

ps -fp $(pgrep -d, -x pipewire)

# UID          PID    PPID  C STIME TTY          TIME CMD
# loxbie      2034    2025  0 09:19 ?        00:00:00 /usr/bin/pipewire
id -u loxbie

# 1000

You can now build the container with

docker compose build

And start it with

docker compose up

Connect your audio device(s) with engine-core as mentioned above. If you want engine-core to automatically connect your device every time you start it, you can also pass a device via the .env file to engine-core. For this you need the device alias and the channel names of your device. To get these run

docker compose run engine-core wpexec /etc/wireplumber/scripts/ls-ports.lua

This dumps details on every connected audio device. Grab the port.alias of your device and enter it in the .env. Press CTRL + C to exit the script.

Example Configuration

Device Dump

{ ["audio.channel"] = AUX0,
["port.physical"] = true,
["port.alias"] = Yamaha AG06MK2:capture_AUX0,
["node.id"] = 61,
["format.dsp"] = 32 bit float mono audio,
["port.direction"] = out,
["port.name"] = capture_AUX0,
["port.terminal"] = true,
["object.serial"] = 324,
["object.id"] = 66,
["object.path"] = alsa:pcm:1:hw:1,0:capture:capture_0,
["port.id"] = 0,
} 

.env Settings

# Audio Device Settings
AURA_ENGINE_OUTPUT_DEVICE=Yamaha AG06MK2:playback
AURA_ENGINE_OUTPUT_CHANNEL_LEFT=AUX0
AURA_ENGINE_OUTPUT_CHANNEL_RIGHT=AUX1
AURA_ENGINE_INPUT_DEVICE=Yamaha AG06MK2:capture
AURA_ENGINE_INPUT_CHANNEL_LEFT=AUX0
AURA_ENGINE_INPUT_CHANNEL_RIGHT=AUX1

Voilá, you should hear some music!

Advanced tips for development

Control playout via telnet

Connect to Liquidsoap via Telnet

make tns

List available commands

help

List all available channels

list

List all input channels connected to the mixer

mixer.inputs

Set the volume of mixer input 0 to 100%

mixer.volume 0 100

Push some audio file to the filesystem in_queue_0

in_queue_0.push /path/to/your/file.mp3

Select line in as your input where 4 is the number from mixer.inputs

mixer.select 4 true