RaspDAB/Use ODR-DabMux to generate the multiplex

From Opendigitalradio
Jump to: navigation, search

We now open a new terminal console window and start to work on generating an actual DAB multiplex. The invocation of the ODR-DabMux program doesn't provide you with many options, If you issue

   $ odr-dabmux -h

you simply get a message that you need to provide a configuration file and an short explanation how a DAB multiplex is constructed of services that are based on service components which together fit into subchannels in the Common Interleaved Frame.

So you run the program with

   $ odr-dabmux PATH_TO/NAME_OF_CONFIGURATION.mux

We need to provide all information the multiplexer needs in the multiplex definition file.

How to define your DAB multiplex

To help you understand how to define a DAB multiplex file some examples are included in the dab/ODR-DabMux/doc folder. Let's have a look at the example.mux file:

   ; This is an example configuration file that illustrates
   ; the structure of the configuration.
   ; It doesn't show all possible options. A more detailed example
   ; is available in doc/advanced.mux
   ;
   ; It contains two services, one DAB and one DAB+, and also shows
   ; both the file input useful for offline processing, and the
   ; ZeroMQ input useful in a 24/7 scenario.
   ; More information about the usage of the tools is available
   ; in the guide, which can be found on the
   ; www.opendigitalradio.org website.
   ; 

It's always clever to read the documentation. I hope you take the time to do it !

   ; As you can see, comments are defined by semicolons.
   ;
   ; It consists of six mandatory sections, whose relative order in this
   ; file are of no importance.
   ; The general section defines global multiplex parameters.
   general {
       ; the DAB Transmission mode (values 1-4 accepted)
       dabmode 1

Always use dabmode 1, it's the only one really used...

   ; the number of ETI frames to generate (set to 0 to get an unlimited number)
   nbframes 10

10 is fine for a first test, later on you will put this at 0 for continuous operation.

   ; boolean fields can accept either false or true as values:
   ; Set to true to enable logging to syslog
   syslog false
   ; Enable timestamp definition necessary for SFN
   ; This also enables time encoding using the MNSC.
   tist false

Set this to true later on.

   ; The management server is a simple TCP server that can present
   ; statistics data (buffers, overruns, underruns, etc)
   ; which can then be graphed a tool like Munin
   ; The doc/stats_dabmux_multi.py tool is a suitable
   ; plugin for that.
   ; If the port is zero, or the line commented, the server
   ; is not started.
   managementport 12720
   }

To be discussed later on

   remotecontrol {
   ; enable the telnet remote control server on the given port
   ; This server allows you to read and define parameters that
   ; some features export. It is only accessible from localhost.
   ; Set the port to 0 to disable the server
   telnetport 12721

To be discussed later on

   ; The remote control is also accessible through a ZMQ REQ/REP socket,
   ; and is useful for machine-triggered interactions. It supports the
   ; same commands as the telnet RC.
   ; The example code in doc/zmq_remote.py illustrates how to use this rc.
   ; To disable the zeromq endpoint, remove the zmqendpoint line.
   ; By specifying "lo" in the URL, we make the server only accessible
   ; from localhost. You can write tcp://*:12722 to make it accessible
   ; on all interfaces.
   zmqendpoint tcp://lo:12722

To be discussed later on

   ; the remote control server makes use of the unique identifiers
   ; for the subchannels, services and components. Make sure you
   ; chose them so that you can identify them.

}

Now it get's interesting...

   ; Some ensemble parameters
   ensemble {
       id 0x8d4b ; you can also use decimal if you want

Every Ensemble has its own hexadecimal identifier code, such that receivers can detect they are different. There doesn't seem to be a central entity that distributes these codes (at least not in the Netherlands), so please check what ID code might be appropriate by checking the Ensemble codes of other ensembles in your region, and select a different one. It does seem to be good practice to start all identity codes with the short country code as in http://www.etsi.org/deliver/etsi_ts/101700_101799/101756/02.01.01_60/ts_101756v020101p.pdf section 5.4 Country ID. For example: in the case of the Netherlands this is '8'.

       ecc 0xe3 ; Extended Country Code

From the same table we see that the extended country code is 'E3'

       local-time-offset auto  ; autmatically calculate from system local time
                               ; or
       ;local-time-offset 1    ; in hours, supports half-hour offsets

Keep this as is, but make sure the system clock of the Raspberry is synchronized with an NTP server. By the way, if the time display on the receivers is not correct, simply stop and restart the multiplexer. This may happen if the multiplexer started before the time was synchronized with the Raspberry Pi.

       ; all labels are maximum 16 characters in length
       label "OpenDigitalRadio"
       ; The short label is built from the label by erasing letters, and cannot
       ; be longer than 8 characters. If omitted, it will be truncated from the
       ; label
       shortlabel "ODR"
   }

Think carefully about the name for your multiplex. Some DAB receivers will use the longer label, but some with just an RDS like display will use the shortlabel of maximum 8 characters. It is not clear why the shortlabel has to be derived from the label as explained above... With all the complexity of the DAB system, why this strange restriction ? (e.g. I could think of a label 'Radio Four', but with this restriction one cannot make the short label 'Radio 4'...)

   ; Definition of DAB services
   services {
   ; Each service has it's own unique identifier, that is
   ; used throughout the configuration file and for the RC.
       srv-fu {
           id 0x8daa
           label "Funk"
       ; you can define a shortlabel too.
       }
       srv-ri {
           id 0x8dab
           label "Rick"
       }
   }

In this section you give every radio station ('service') a unique ID ( Just as the ensemble ID, start with the short country code followed by 3 hexadecimal characters you choose - check the labels of other stations first so you do not copy one by accident ! ) and label that will be visible on the display of the DAB receiver so the listener can select what to listen to. By the way: you can change the part after 'srv-' with something you derive from the label you give the service, as illustrated, and keep this consistent for the subchannels and component definitions below.

   subchannels {
       sub-fu {
       ; This is our DAB programme, using a file input
           type audio
           inputfile "funk.mp2"
           bitrate 128
           id 10
           protection 3
       }

Here subchannels are defined, which for this simple example are audio programs only. In this first example the input is an MPEG 1 Layer II encoded audio file, which is type 'audio' (as the audio encoding in the original DAB specification). See below for using a stream from ODR-AudioEnc. You have to supply the bitrate (which should match the one you have set in the ODR-AudioEnc command line). Also a unique ID (it is probably best to number them logically 1 to ...) and the error correction protection level.

For 'old fashioned DAB' there are 5 error protection levels, UEP 1 to 5. UEP 1 provides the best protection, but at the cost of Capacity Units: it requires more error protection bits to be calculated and sent together with the bits that carry the audio information. This ratio is called the 'code rate'. For UEP 1 this is about 0.35, meaning that of all the bits sent for this station, almost 2/3rd are error correction bit and just about 1/3rd are bits carrying the audio information. According to https://www.ofcom.org.uk/__data/assets/pdf_file/0027/55494/annex-g.pdf the code rates for UEP 2 to 5 are approximately 0.42, 0.5, 0.6 and 0.75. UEP means 'Unequal Error Protection': some bits in the MPEG2 audio stream are better protected than others, as an error in them has an impact for a longer time than just one sample. In DAB+ this has changed, and modern Reed-Solomon encoding is used, protecting all audio bits the same way. There are 8 protection levels, in 2 categories A and B. EEP (Equal Error Protection) A1 to A4 have code rates from 1/4th, 3/8th, 1/2nd and 3/4th, and EEP B1 to B4 have code rates 4/9th, 4/7th, 4/6th and 4/5th . The EEP A protection can be used for bitrates in 8 kbits/sec increments, whereas the EEP B protection levels are limited to bitrates in 32 kbits/sec increments. (Please note, that currently the EasyDAB doesn't seem to be able to encode EEP B rates. This restricts the options available to compile the multiplex).

       sub-ri {
       ; This is our DAB+ programme, using a ZeroMQ
           type dabplus
       ; Accepts connections to port 9000 from any interface.
       ; Use ODR-AudioEnc as encoder
           inputfile "tcp://*:9000"
           bitrate 96
           id 1
           protection 3

This is similar as the previous subchannel, but this is a DAB+ AAC encoded station. As inputfile a stream from the ODR-AudioEnc is defined. To establish the link, the audio encoder needs to be supplied the exact URL it needs to send the stream to. The multiplexer listens for the stream on the port and interface defined as above.

       ; ZMQ specific options, mandatory:
       ; Maximum size of input buffer, in AAC frames (24ms)
       ; when this buffer size is reached, some frames will be
       ; discarded to get the size again below this value.
       ; As the present implementation discards entire AAC superframes,
       ; (5 frames = 120ms) the effect will clearly be audible.
       zmq-buffer 40
       ; At startup or after an underrun, the buffer is filled to this
       ; amount of AAC frames before streaming starts.
       zmq-prebuffering 20
       ; In an ideal scenario, where the input rate exactly corresponds
       ; to the rate at which the frames are consumed by dabmux, you
       ; see the buffer level staying around the zmq-prebuffering value.
       ; Network latency jitter can make it temporarily go lower or higher.
       ; Encoder clock drift will make the buffer either slowly fill or
       ; empty, which will create intermittent glitches.
       }
   }

I guess from this explanation the need for a buffer when using a stream input is clear...

   ; In our simple example, each component links one service to one subchannel
   components {
   ; the component unique identifiers are used for the RC.
       comp-fu {
       ; According to specification, you should not define component labels if
       ; the service is only used in one component. The service label is sufficient
       ; in that case.
           service srv-fu
           subchannel sub-fu
       }
       comp-ri {
           service srv-ri
           subchannel sub-ri
       }
   }

If you are using slide show PAD later on, you need to insert an indication here. Check the OpenDigitalRadio Wiki for details.

   ; A list of outputs
   outputs {
   ; The unique-id can be used by the remote control or the statistics server
   ; to identify the output
   ; Output RAW ETI NI to standard output
       stdout "fifo:///dev/stdout?type=raw"

Use this if you want to use RAW ETI. However, in our case we use ZeroMQ. So comment out (put ; before 'stdout') the above line and enable the ZeroMQ output by removing the ';' before 'zmq' below:

   ; ZeroMQ output example 
   ; This output does not back-pressure the multiplexer.
   ; Listen on all interfaces, on port 9100
       ;zmq  "zmq+tcp://*:9100"
   ; Output ETI-over-TCP. This is like piping a RAW ETI NI data stream
   ; into a TCP socket, except that the output can handle simultaneous
   ; connections.
   ; 0.0.0.0 means "listen on all interfaces"
   ; This output does not back-pressure the multiplexer.
       ;tcp "tcp://0.0.0.0:9200"

Use this for modulators that can receive an ETI stream over TCP.

   ; Throttle output to real-time (one ETI frame every 24ms)
       ;throttle "simul://"

For real-time operation (transmitting) you need to enable this output, so remove the ';' .

   ; Important! For real-time operation, you need to have exactly one
   ; output that applies back-pressure to ODR-DabMux, otherwise it will run
   ; at the highest possible rate on your system!
   ;
   ; For an output to a pipe, the data consumer at the other end of the pipe
   ; will dictate the multiplexing rate to ODR-DabMux.
   ;
   ; If you use the zmq+tcp:// or the tcp:// output,
   ; you must also enable a simul:// output!
   }

And that's the end of the multiplex configuration file.

Starting the multiplexer

As mentioned above, once you have defined your multiplex configuration file, you can start the multiplexer with

   $ odr-dabmux PATH_TO/NAME_OF_CONFIGURATION.mux

If your configuration file is OK, you will see an overview of the settings you provided, and some messages indicating the multiplexer has started.

In the repository you can find a RaspDab.mux example that you can use to generate a multiplex with one or two audio programs. Create a new directory in the home directory with the name 'config' in which we will store all configuration files for the project. And in this directory make a subdirectory called 'mux' to store the multiplex configuration files. So let's store RaspDab.mux there.

Assuming you invoke the program from the home directory, you can now issue the command

   $ odr-dabmux ./config/mux/RaspDab.mux

Leave this also running, as it is time to get to the EasyDAB board...

Personal tools