A tool to route streams from ODR-AudioEnc


License
MIT
Install
pip install odroute==0.2.0

Documentation

ODR Stream Router

Build Status

A tool to route ODR-AudioEnc zmq streams.

The aim of odroute is to achieve two goals:

  • Provide a way to handle a fallback for DAB+ streams generated with ODR-AudioEnc, e.g. in the situation when running a dedicated encoder box in the studio, but in case of connection- or encoder-failure an automatic failover to a central encoder instance (encoding a webstream) is desired.
  • Provide a way to distribute DAB+ streams through a single connection from an encoder to multiple instances of ODR-DabMux.

The tool can be configured while running, adding/removing inputs without interruptions.

Installation

Via PyPi

pip install odroute

From GitHub

pip install -e git+https://github.com/digris/odr-stream-router.git#egg=odroute

From Source

git clone https://github.com/digris/odr-stream-router.git
cd odr-stream-router

# pip
pip install -e .

# or setup.py
python setup.py develop

Without installation

# using system distribution packages (python3-yaml and python3-zmq debian packages)
# without installing at all:

python odroute.py

Usage

odroute run --help

Simple CLI Example

Listen on ports 5001 and 5002 and output the active port to tcp://localhost:9001 - switching inputs after 0.5 seconds of 'inactivity/activity'.

-s/--source and -o/--output can both be specified multiple times.

The priority of the input ports is specified through the order. So in this example port 5001 is forwarded if available, else packages from the socket on 5002 are used.

odroute -v run -s 5001 -s 5002 -o tcp://localhost:9001 -d 0.5

UNIX DGRAM remote control interface

The ODR Stream Router includes a remote control interface that uses a UNIX datagram socket.

Example python code:

import socket
s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
s.sendto("help".encode(), "./thesocket")
answer, addr = s.recvfrom(4096)
print(answer.decode())

Configuration via .yml file

Alternatively odroute can read its configuration from file. When specifying a config file (in .yml format) all other CLI options are ignored in favour of options in config-file resp. their defaults.

All options in the .yml file are optional - if not given the corresponding defaults will be used.

Config file example

# config.yml
version: 1
name: my-router-instance-name
source_ports:
 - 7000
 - 7001

destinations:
 - tcp://127.0.0.1:7010
 - tcp://127.0.0.1:7011

nodata_failover_delay: 1.0
nodata_recover_delay: 10.0
noaudio_failover_delay: 20
noaudio_recover_delay: 20
audio_threshold: -90

socket: ./thesocket

log_level: debug
log_format: '%(asctime)s [%(levelname)s] %(name)s: %(message)s'

Run with file-based config

odroute run -c ./config.yml

'Hot-reloading' config

When running odroute with a file-based config you have the possibility to 'hot-reload' the settings, if you have configured a control-interface via socket or telnet.

To reload the configuration invoke a 'reload' command via any suitable control-interface. Assuming you have a socket interface on ./thesocket:

echo reload | nc -U ./thesocket

This will re-read the config file and update the inputs and outputs as well as updating the values for 'no-data' / 'no-audio' failover settings.

Please note: You cannot change the control-interface on-the-fly! To change the socket or telnet interface you have to restart the odroute process.

Testing

Run the ./test.sh script to run a few automated tests.

Features and relevant tests:

  • Routing ZMQ to ZMQ, ZMQ to EDI, EDI to EDI, EDI to ZMQ: ediinput and edioutput
  • Multiple outputs: ediinput
  • Failover no data, no audio (with different delays): cli and ediinput
  • Recovery with different delays: cli
  • Force input: cli
  • Configuration reload: configfile
  • Hot add / remove of inputs: hotaddremove
  • Hot add / remove of outputs: edioutput

Remarks

MPEG EDI inputs to ZMQ outputs won't work (see odroute/output.py)

Removed features

The stream socket based command interfaces (telnet and UNIX stream socket) have been removed in favour of a UNIX datagram socket

Telnet Interface

Version 0.0.2 provides a telnet interface that can list the configured inputs and outputs and the currently active input. Further it provides functionality fo force an input to be used (instead of relying on the fallback behaviour).

use option --telnet resp. -t with either port to listen on or in ip:port to bind. See odroute run --help

odroute run -s 5001 -s 5002 -o tcp://localhost:9001 -t 127.0.0.1:4001

Connect with telnet and run help to see the available commands

telnet 127.0.0.1 4001

Or use netcat:

echo help             | nc 127.0.0.1 4001
echo input.list       | nc 127.0.0.1 4001
echo input.force 5002 | nc 127.0.0.1 4001
echo input.current    | nc 127.0.0.1 4001

UNIX Socket interface

Version 0.0.17 provides a UNIX socket interface, with the same commands as the telnet one. Example client in python, with thesocket as path:

import socket
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
s.connect("./thesocket")
s.send("help\n".encode())
print(s.recv(1024).decode())

Using netcat is also possible

echo input.list | nc -U ./thesocket