diff options
-rw-r--r-- | .gitignore | 18 | ||||
-rw-r--r-- | b100-2048.ini | 25 | ||||
-rw-r--r-- | b200-2048-zmq.ini | 20 | ||||
-rw-r--r-- | b200-2048.ini | 6 | ||||
-rw-r--r-- | b200-30.72.ini | 25 | ||||
-rw-r--r-- | b200-resample.ini | 6 | ||||
-rw-r--r-- | b200-sync-zmq.ini | 75 | ||||
-rw-r--r-- | b200-sync.ini | 6 | ||||
-rw-r--r-- | edi-test.mux | 163 | ||||
-rwxr-xr-x | edi/edidebug.py | 3 | ||||
-rwxr-xr-x | edi/edisend.py | 193 | ||||
-rwxr-xr-x | encode-alsa32.sh | 17 | ||||
-rwxr-xr-x | encode-alsasrc-gst-dabplus.sh | 39 | ||||
-rwxr-xr-x | encode-alsasrc-sox-mpeg.sh | 22 | ||||
-rwxr-xr-x | encode-fb.sh | 3 | ||||
-rwxr-xr-x | encode-fbplus.sh | 36 | ||||
-rwxr-xr-x | encode-jack.sh | 154 | ||||
-rwxr-xr-x | encode-stdin.sh | 3 | ||||
-rwxr-xr-x | encode-url-gst-dabplus.sh | 44 | ||||
-rwxr-xr-x | histogram.py | 28 | ||||
-rw-r--r-- | minimal.ini | 11 | ||||
-rw-r--r-- | modulatoroffset | 2 | ||||
-rwxr-xr-x | mpeg_analyse.py | 117 | ||||
-rw-r--r-- | rdsparse/decoder_impl.cc | 21 | ||||
-rw-r--r-- | test.ini | 31 | ||||
-rw-r--r-- | zmq-simul.mux | 94 |
26 files changed, 768 insertions, 394 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fce88b8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +zmqtest +eti +*.sub +*.pub +*.raw +*.wav +*.mp2 +*.dab +*.dabp +*.dabplus +keys +filter +rdsparse/CMakeCache.txt +rdsparse/CMakeFiles/ +rdsparse/Makefile +rdsparse/cmake_install.cmake +rdsparse/cmake_uninstall.cmake +rdsparse/rdsparse diff --git a/b100-2048.ini b/b100-2048.ini index 7d4b94c..f990a2d 100644 --- a/b100-2048.ini +++ b/b100-2048.ini @@ -10,11 +10,12 @@ filelog=1 filename=/dev/stderr [input] -transport=file -source=/dev/stdin -;transport=zeromq -;source=tcp://mpb.li:9100 -loop=0 +;transport=file +;source=/dev/stdin +;loop=0 +transport=zeromq +source=tcp://core.mpb.li:9100 +max_frames_queued=400 [modulator] ; Gain mode: 0=FIX, 1=MAX, 2=VAR @@ -33,8 +34,8 @@ digital_gain=1.0 rate=2048000 [firfilter] -enabled=0 -filtertapsfile=filter/simplefiltertaps.txt +enabled=1 +filtertapsfile=filter/filtertaps.txt [output] ; choose output: possible values: uhd, file @@ -48,7 +49,7 @@ filename=/dev/null device= master_clock_rate=20480000 type=b100 -txgain=4 +txgain=12 ;frequency=234208000 channel=13C @@ -64,10 +65,6 @@ behaviour_refclk_lock_lost=crash ; Used for SFN with the UHD output [delaymanagement] -synchronous=0 +synchronous=1 -; choose between fixed and dynamic offset definition -management=dynamic - -fixedoffset=0.002 -dynamicoffsetfile=modulatoroffset +offset=2.0 diff --git a/b200-2048-zmq.ini b/b200-2048-zmq.ini index 905454f..f79f0c3 100644 --- a/b200-2048-zmq.ini +++ b/b200-2048-zmq.ini @@ -1,4 +1,5 @@ -; Sample configuration file for CRC-DABMOD +; Sample configuration file for ODR-DabMod +; using a zeromq input [remotecontrol] telnet=1 @@ -6,7 +7,7 @@ telnetport=2121 [log] syslog=0 -filelog=1 +filelog=0 filename=/dev/stderr [input] @@ -15,6 +16,7 @@ filename=/dev/stderr transport=zeromq source=tcp://localhost:9100 loop=0 +max_frames_queued=400 [modulator] ; Gain mode: 0=FIX, 1=MAX, 2=VAR @@ -22,12 +24,12 @@ gainmode=2 ; Transmission mode ; If not defined, take the mode from ETI -;mode=2 +mode=1 ; Set to 0 to disable CicEqualiser dac_clk_rate=0 -digital_gain=1.0 +digital_gain=0.8 ; Output sample rate rate=2048000 @@ -49,7 +51,7 @@ filename=/dev/null device= master_clock_rate=32768000 type=b200 -txgain=45 +txgain=50 ;frequency=234208000 channel=13C @@ -63,12 +65,10 @@ pps_source=none ; possible values: ignore, crash behaviour_refclk_lock_lost=crash +max_gps_holdover_time=300 + ; Used for SFN with the UHD output [delaymanagement] synchronous=0 -; choose between fixed and dynamic offset definition -management=dynamic - -fixedoffset=0.002 -dynamicoffsetfile=modulatoroffset +offset=2.0 diff --git a/b200-2048.ini b/b200-2048.ini index 7742a1d..92fe43e 100644 --- a/b200-2048.ini +++ b/b200-2048.ini @@ -67,8 +67,4 @@ behaviour_refclk_lock_lost=crash [delaymanagement] synchronous=0 -; choose between fixed and dynamic offset definition -management=dynamic - -fixedoffset=0.002 -dynamicoffsetfile=modulatoroffset +offset=0.002 diff --git a/b200-30.72.ini b/b200-30.72.ini index a66fbfe..be0e204 100644 --- a/b200-30.72.ini +++ b/b200-30.72.ini @@ -12,13 +12,13 @@ filename=/dev/stderr [input] ;transport=file -;source=/dev/stdin -loop=0 +;source=/home/bram/dab/mmbtools-aux/eti/AnnouncementTest-FraunhoferIIS-2013-11-25.eti +;loop=1 transport=zeromq ;source=tcp://localhost:9100 source=tcp://core.mpb.li:9100 -max_frames_queued=400 +max_frames_queued=800 [modulator] ; Gain mode: 0=FIX, 1=MAX, 2=VAR @@ -26,12 +26,12 @@ gainmode=2 ; Transmission mode ; If not defined, take the mode from ETI -;mode=2 +mode=1 ; Set to 0 to disable CicEqualiser dac_clk_rate=0 -digital_gain=1.0 +digital_gain=0.8 ; Output sample rate rate=2048000 @@ -53,12 +53,12 @@ filename=/dev/null device= master_clock_rate=32768000 type=b200 -txgain=50 +txgain=40 ;frequency=234208000 channel=13C ; possible values : internal, external, MIMO -refclk_source=gpsdo +refclk_source=gpsdo-ettus ; possible values : none, external, MIMO pps_source=gpsdo @@ -67,12 +67,15 @@ pps_source=gpsdo ; possible values: ignore, crash behaviour_refclk_lock_lost=crash +max_gps_holdover_time=600 + ; Used for SFN with the UHD output [delaymanagement] synchronous=1 -; choose between fixed and dynamic offset definition -management=dynamic +offset=2.0 -fixedoffset=0.002 -dynamicoffsetfile=modulatoroffset +[tii] +enable = 0 +comb = 16 +pattern = 5 diff --git a/b200-resample.ini b/b200-resample.ini index ad72801..c537f1c 100644 --- a/b200-resample.ini +++ b/b200-resample.ini @@ -67,8 +67,4 @@ behaviour_refclk_lock_lost=crash [delaymanagement] synchronous=0 -; choose between fixed and dynamic offset definition -management=dynamic - -fixedoffset=0.002 -dynamicoffsetfile=modulatoroffset +offset=2.0 diff --git a/b200-sync-zmq.ini b/b200-sync-zmq.ini new file mode 100644 index 0000000..60f6611 --- /dev/null +++ b/b200-sync-zmq.ini @@ -0,0 +1,75 @@ +; Sample configuration file for ODR-DabMod + +[remotecontrol] +telnet=1 +telnetport=2121 + +[log] +syslog=0 +filelog=0 +filename=/dev/stderr + +[input] +;transport=file +;source=/dev/stdin +transport=zeromq +source=tcp://core.mpb.li:9100 +loop=0 + +[modulator] +; Gain mode: 0=FIX, 1=MAX, 2=VAR +gainmode=2 + +; Transmission mode +; If not defined, take the mode from ETI +mode=1 + +; Set to 0 to disable CicEqualiser +dac_clk_rate=0 + +digital_gain=0.8 + +; Output sample rate +rate=2048000 + +[firfilter] +enabled=1 +filtertapsfile=filter/simplefiltertaps.txt + +[output] +; choose output: possible values: uhd, file +output=uhd + +[fileoutput] +filename=/dev/null + +[uhdoutput] +;device=master_clock_rate=32768000,type=b100 +;txgain=2 +device= +master_clock_rate=32768000 +type=b200 +txgain=45 +;frequency=234208000 +channel=13C + +; possible values : internal, external, MIMO +refclk_source=internal + +; possible values : none, external, MIMO +pps_source=none + +; behaviour when external clock reference lock lost +; possible values: ignore, crash +behaviour_refclk_lock_lost=crash + +; Used for SFN with the UHD output +[delaymanagement] +synchronous=1 + +offset=2.0 + +[tii] +enable = 1 +comb = 16 +pattern = 6 diff --git a/b200-sync.ini b/b200-sync.ini index 6a996d5..b232f36 100644 --- a/b200-sync.ini +++ b/b200-sync.ini @@ -67,8 +67,4 @@ behaviour_refclk_lock_lost=crash [delaymanagement] synchronous=1 -; choose between fixed and dynamic offset definition -management=dynamic - -fixedoffset=0.002 -dynamicoffsetfile=modulatoroffset +offset=2.0 diff --git a/edi-test.mux b/edi-test.mux new file mode 100644 index 0000000..6d835b7 --- /dev/null +++ b/edi-test.mux @@ -0,0 +1,163 @@ +general { + ; the DAB Transmission mode (values 1-4 accepted) + dabmode 1 + + ; the number of ETI frames to generate (set to 0 to get an unlimited number) + nbframes 0 + + ; The statsserver for extracting statistics + statsserverport 12720 + + syslog false + writescca false + tist false + + new_fig_carousel true +} + +remotecontrol { + ; enable the remote control server + telnetport 12721 +} + +; Some ensemble parameters +ensemble { + id 20479 + ; Extended Country Code (decimal) + ecc 225 + + local-time-offset 2 + international-table 1 + label "TuxMux" + shortlabel "Tux" +} + +services { + funk { + label "funk" + shortlabel "funk" + pty 0 + language 0 + id 10 + } + + funk2 { + label "funk2" + shortlabel "funk2" + pty 0 + language 0 + id 11 + } + funk3 { + label "funk3" + shortlabel "funk3" + pty 1 + language 0 + id 12 + } + +} + +subchannels { + funk { + type audio + inputfile "funk.mp2" + nonblock false + bitrate 128 + id 10 + protection 5 + } + + funk2 { + type dabplus + inputfile "funk2.dabp" + nonblock false + bitrate 96 + id 11 + protection 3 + } + + funk3 { + type audio + inputfile "funk.mp2" + nonblock false + bitrate 128 + id 12 + protection 3 + } +} + +; For now, each component links one service to one subchannel +components { + ; the component unique identifiers are not used anywhere, but + ; are useful to disambiguate different components. + funky { + label funk + shortlabel fu + service funk + subchannel funk + } + + funky2 { + label funk2 + shortlabel funk2 + service funk2 + subchannel funk2 + } + + funky3 { + label funk3 + shortlabel funk3 + service funk3 + subchannel funk3 + } +} + +; A list of outputs, in the format +; unique_id "uri" +outputs { + ;foobar "fifo:///home/bram/dab/mmbtools-aux/eti/funk2.10000.eti?type=raw" + simul "simul://" + null "fifo:///dev/null" + + ; ZeroMQ output example + ; zmq "zmq+tcp://*:8080" + + edi { + + fec 2 + ;chunk_len 140 + + destinations { + unicast { + destination "10.31.0.120" + ;destination "239.20.64.1" + ;source "192.168.2.10" + sourceport 15321 + } + un_autre { + destination "239.20.64.1" + source "10.31.0.121" + sourceport 15322 + ttl 2 + } + } + + port 12002 + + ; EDI uses the UDP protocol + + ; Enable the PFT subsystem. If false, AFPackets are sent. + enable_pft true + + ; Save the packets sent over ethernet to the file ./edi.debug + dump false + + ; show more debugging info + verbose false + + ; optional: what kind of alignment to do in the tagpacket + ;tagpacket_alignment 16 + } + +} diff --git a/edi/edidebug.py b/edi/edidebug.py index 64d605d..c41d9a6 100755 --- a/edi/edidebug.py +++ b/edi/edidebug.py @@ -482,7 +482,8 @@ def tagitems(tagpacket): name, length = struct.unpack(tag_item_head_struct, tagpacket[i:i+8]) # length is in bits, because it's more annoying this way - assert(length % 8 == 0) + if length % 8 != 0: + print("ASSERTION ERROR: length of tagpacket is not multiple of 8: {}".format(length)) length /= 8 tag_value = tagpacket[i+8:i+8+length] diff --git a/edi/edisend.py b/edi/edisend.py new file mode 100755 index 0000000..2bd6bc1 --- /dev/null +++ b/edi/edisend.py @@ -0,0 +1,193 @@ +#!/usr/bin/env python2 +# +# Read an EDI dump file and transmit over UDP +# +# The MIT License (MIT) +# +# Copyright (c) 2015 Matthias P. Braendli +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +import sys +import struct + +from crc import crc16 +from reedsolo import RSCodec + +import socket +import time + +UDP_IP = "239.20.64.1" +UDP_PORT = 12002 + +class BufferedFile: + def __init__(self, fname): + self.buf = [] + + if fname == "-": + self.fd = sys.stdin + else: + self.fd = open(fname, "rb") + + def read(self, n): + if not self.buf: + return self.fd.read(n) + else: + if len(self.buf) < n: + self.buf.extend(self.fd.read(n - len(self.buf))) + + if len(self.buf) == n: + ret = b"".join(self.buf) + self.buf = [] + else: + ret = b"".join(self.buf[:n]) + del self.buf[:n] + + return ret + + def peek(self, n): + dat = self.fd.read(n) + self.buf.extend(dat) + return dat + + +pft_head_struct = "!2sH3B3BH" +pft_rs_head_struct = "!2B" +pft_addr_head_struct = "!2H" +af_head_struct = "!2sLHBc" +class EDI: + def __init__(self): + self.last_send_time = time.time() + self.sock = socket.socket(socket.AF_INET, # Internet + socket.SOCK_DGRAM) # UDP + + def send_udp(self, message): + self.sock.sendto(message, (UDP_IP, UDP_PORT)) + + + def decode(self, stream): + sync = stream.peek(2) + + if len(sync) < 2: + return False + + if sync == "PF": + return self.decode_pft(stream) + elif sync == "AF": + return self.decode_af(stream, is_stream=True) + + + + def decode_pft(self, stream): + headerdata = stream.read(12) + header = struct.unpack(pft_head_struct, headerdata) + + psync, pseq, findex1, findex2, findex3, fcount1, fcount2, fcount3, fec_ad_plen = header + + findex = (findex1 << 16) | (findex2 << 8) | findex3 + fcount = (fcount1 << 16) | (fcount2 << 8) | fcount3 + + fec = (fec_ad_plen & 0x8000) != 0x00 + addr = (fec_ad_plen & 0x4000) != 0x00 + plen = fec_ad_plen & 0x3FFF + + rs_k = 0 + rs_z = 0 + if fec: + rs_head = stream.read(2) + rs_k, rs_z = struct.unpack(pft_rs_head_struct, rs_head) + headerdata += rs_head + + addr_source = 0 + addr_dest = 0 + if addr: + addr_head = stream.read(4) + addr_source, addr_dest = struct.unpack(pft_addr_head_struct, addr_head) + headerdata += addr_head + + # read CRC + crc_data = stream.read(2) + crc = struct.unpack("!H", crc_data)[0] + + crc_calc = crc16(headerdata) + crc_calc ^= 0xFFFF + + crc_ok = crc_calc == crc + + time_now = time.time() + if findex == 0: + if self.last_send_time + 24e-3 > time_now: + delay = self.last_send_time + 24e-3 - time_now + print("Sleeping for {} ms".format(1000 * delay)) + time.sleep(delay) + self.last_send_time = time_now + + + if crc_ok: + payload = stream.read(plen) + self.send_udp(headerdata + crc_data + payload) + + return crc_ok + + + def decode_af(self, in_data, is_stream=False): + if is_stream: + headerdata = in_data.read(10) + else: + headerdata = in_data[:10] + + sync, plen, seq, ar, pt = struct.unpack(af_head_struct, headerdata) + + if sync != "AF": + return False + + crc_flag = (ar & 0x80) != 0x00 + revision = ar & 0x7F + + if is_stream: + payload = in_data.read(plen) + crc_data = in_data.read(2) + crc = struct.unpack("!H", crc_data)[0] + else: + payload = in_data[10:10+plen] + crc_data = in_data[10+plen:10+plen+2] + crc = struct.unpack("!H", crc_data)[0] + + crc_calc = crc16(headerdata) + crc_calc = crc16(payload, crc_calc) + crc_calc ^= 0xFFFF + + crc_ok = crc_calc == crc + + if crc_ok: + self.send_udp(headerdata + payload + crc_data) + + return crc_ok + +if len(sys.argv) > 1: + filename = sys.argv[1] + + edi_fd = BufferedFile(filename) +else: + edi_fd = BufferedFile("-") + +edi = EDI() +while edi.decode(edi_fd): + pass + diff --git a/encode-alsa32.sh b/encode-alsa32.sh deleted file mode 100755 index 750ecc5..0000000 --- a/encode-alsa32.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash -# -# Read audio from ALSA input using sox, and encode with fdk-aac-dabplus-zmq -# -BITRATE=$1 -DST=$2 -ALSASRC="default" - -if [ "$DST" == "" ] -then - echo "Usage:" - echo " $0 <bitrate> <zmq destination>" - exit 1 -fi - -dabplus-enc -d $ALSASRC -c 2 -r 32000 -b $BITRATE -o $DST -p 48 - diff --git a/encode-alsasrc-gst-dabplus.sh b/encode-alsasrc-gst-dabplus.sh deleted file mode 100755 index 7ec5d9e..0000000 --- a/encode-alsasrc-gst-dabplus.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash -# -# Read audio from ALSA input using gstreamer, and encode with fdk-aac-dabplus-zmq -# -BITRATE=$1 -DST=$2 -QUEUEDELAY=400000 #400ms - -GSTREAMER_VERSION="0" - -if [ "$DST" == "" ] -then - echo "Usage:" - echo " $0 <bitrate> <zmq destination>" - exit 1 -fi - - -if [ "$GSTREAMER_VERSION" == "1" ] -then - gst-launch-1.0 -q \ - alsasrc "device=default" ! \ - audio/x-raw, 'rate=48000,format=S16LE,channels=2' ! \ - queue "max-size-time=$QUEUEDELAY" ! \ - filesink location="/dev/stdout" | \ - dabplus-enc \ - -i /dev/stdin -b $BITRATE -f raw -a -o "${DST}" - -elif [ "$GSTREAMER_VERSION" == "0" ] -then - gst-launch -q \ - alsasrc "device=default" ! \ - audio/x-raw-int, 'rate=48000,format=S16LE,channels=2' ! \ - queue "max-size-time=$QUEUEDELAY" ! \ - filesink location="/dev/stdout" | \ - dabplus-enc \ - -i /dev/stdin -b $BITRATE -f raw -a -o "${DST}" -fi - diff --git a/encode-alsasrc-sox-mpeg.sh b/encode-alsasrc-sox-mpeg.sh deleted file mode 100755 index 3de71b5..0000000 --- a/encode-alsasrc-sox-mpeg.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash -# -# Read audio from ALSA input using sox, and encode with toolame, -# send to ZMQ -# -# This needs toolame-dab from -# https://github.com/Opendigitalradio/toolame-dab -# -BITRATE=$1 -DST=$2 -ALSASRC="default" - -if [ "$DST" == "" ] -then - echo "Usage:" - echo " $0 <bitrate> <zmq destination>" - exit 1 -fi - -sox -t alsa $ALSASRC -b 16 -t raw - rate 48k channels 2 | \ - toolame -s 48 -D 4 -b $BITRATE /dev/stdin $DST - diff --git a/encode-fb.sh b/encode-fb.sh deleted file mode 100755 index f97f3a3..0000000 --- a/encode-fb.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -echo "Encoding FB to 1.ff" -mpg123 -r 48000 -s http://fbpc5.epfl.ch:8001 |toolame -s 48 -D 4 -b 128 /dev/stdin ./1.ff diff --git a/encode-fbplus.sh b/encode-fbplus.sh deleted file mode 100755 index 1e1bfc8..0000000 --- a/encode-fbplus.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash -# -# Encode Frequence Banane to ZMQ -# -# Remarks: it's probably better to use the -# snd-aloop scenario now. - -WITH_GSTREAMER=0 -URL=http://fbpc5.epfl.ch:8000/fb_192 -BITRATE=$1 -DST=$2 - -if [ "$DST" == "" ] -then - echo "Usage:" - echo " $0 <bitrate> <zmq destination>" - exit 1 -fi - -if [ "$WITH_GSTREAMER" == "1" ] -then - gst-launch-0.10 -q \ - uridecodebin uri=$URL ! \ - queue ! \ - audioresample quality=8 ! \ - audioconvert ! \ - audio/x-raw-int, 'rate=48000,format=S16LE,channels=2' ! \ - filesink location="/dev/stdout" | \ - dabplus-enc \ - -i /dev/stdin -b $BITRATE -f raw -a -o $DST -else - mpg123 -s $URL |\ - sox -t raw -r 44100 -e signed -b 16 -c 2 - -t raw - rate 32k |\ - dabplus-enc \ - -i /dev/stdin -r 32000 -b $BITRATE -f raw -a -o $DST -fi diff --git a/encode-jack.sh b/encode-jack.sh deleted file mode 100755 index ab7e9aa..0000000 --- a/encode-jack.sh +++ /dev/null @@ -1,154 +0,0 @@ -#!/bin/bash -# -# mplayer - jack - jack-stdout - dabplus-enc -# encoder script. -# -# Used to encode webstreams for DAB+, requires -# jackd -d dummy -r 32000 -# to be running - -printerr() { - echo -e "\033[01;31m$1\033[0m" -} - -printmsg() { - echo -e "\033[01;32m$1\033[0m" -} - -set -u - -# check number of arguments -if [[ "$#" < 3 ]] ; then - echo "Usage $0 url jack-id destination [volume]" - echo "The volume setting is optional" - exit 1 -fi - -if [[ "$#" > 2 ]] ; then - URL=$1 - ID=$2 - DST=$3 -fi - -if [[ "$#" == 4 ]] ; then - VOL=$4 -else - VOL="" -fi - -BITRATE=80 -RATE=32000 - -encoderalive=0 -mplayerpid=0 -encoderpid=0 - -# The trap for Ctrl-C -sigint_trap() { - printerr "Got Ctrl-C, killing mplayer and encoder" - - if [[ "$mplayerpid" != "0" ]] ; then - kill -TERM $mplayerpid - sleep 2 - kill -KILL $mplayerpid - fi - - if [[ "$encoderpid" != "0" ]] ; then - kill -TERM $encoderpid - sleep 2 - kill -KILL $encoderpid - fi - - printmsg "Goodbye" - exit -} - -trap sigint_trap SIGINT - -while true -do - mplayer_ok=0 - - if [[ "$mplayerpid" == "0" ]] ; then - if [[ "$VOL" == "" ]] ; then - mplayer -quiet -af resample=$RATE:0:2 -ao jack:name=$ID $URL & - mplayerpid=$! - else - mplayer -quiet -af resample=$RATE:0:2 -af volume=$VOL -ao jack:name=$ID $URL & - mplayerpid=$! - fi - - printmsg "Started mplayer with pid $mplayerpid" - - # give some time to mplayer to set up and - # wait until port becomes visible - timeout=10 - - while [[ "$mplayer_ok" == "0" ]] - do - printmsg "Waiting for mplayer to connect to jack ($timeout)" - sleep 1 - mplayer_ok=$(jack_lsp $ID:out_0 | wc -l) - - timeout=$(( $timeout - 1)) - - if [[ "$timeout" == "0" ]] ; then - printerr "mplayer doesn't connect to jack !" - kill $mplayerpid - break - fi - done - else - printmsg "No need to start mplayer: $mplayerpid" - fi - - if [[ "$mplayer_ok" == "1" ]] ; then - jack-stdout $ID:out_0 $ID:out_1 | \ - dabplus-enc -i /dev/stdin -l \ - -b $BITRATE -r $RATE -f raw -a -o $DST & - encoderpid=$! - fi - - printmsg "Started encoder with pid $encoderpid" - - sleep 5 - - checkloop=1 - while [[ "$checkloop" == "1" ]] - do - sleep 2 - - kill -s 0 $mplayerpid - if [[ "$?" != "0" ]] ; then - # mplayer died - # we must kill jack-stdout, because we cannot reconnect it - # to a new mplayer, since we do not know the jack-stdout name. - # And it has no cmdline option to set one, Rrrrongntudtjuuu! - if [[ "$encoderpid" != "0" ]] ; then - kill -TERM $encoderpid - fi - checkloop=0 - - # mark as dead - mplayerpid=0 - - printerr "Mplayer died" - fi - - if [[ "$encoderpid" != "0" ]] ; then - kill -s 0 $encoderpid - if [[ "$?" != "0" ]] ; then - # the encoder died, - # no need to kill the mplayer, we can reconnect to it - - checkloop=0 - - printerr "Encoder died" - fi - fi - done - - sleep 5 - -done - diff --git a/encode-stdin.sh b/encode-stdin.sh deleted file mode 100755 index c97a5ce..0000000 --- a/encode-stdin.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -toolame -s 48 -D 4 -b 128 /dev/stdin /dev/stdout > 1.ff diff --git a/encode-url-gst-dabplus.sh b/encode-url-gst-dabplus.sh deleted file mode 100755 index b05d7bb..0000000 --- a/encode-url-gst-dabplus.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/bash -# -# Read a URL using gstreamer, and encode with fdk-aac-dabplus-enc -# -URL=$1 -BITRATE=$2 -DST=$3 -QUEUEDELAY=400000 #400ms - -GSTREAMER_VERSION="1" - -if [ "$DST" == "" ] -then - echo "Usage:" - echo " $0 <url> <bitrate> <zmq destination>" - exit 1 -fi - - -if [ "$GSTREAMER_VERSION" == "1" ] -then - gst-launch-1.0 -q \ - uridecodebin uri=$URL ! \ - queue "max-size-time=$QUEUEDELAY" ! \ - audioresample quality=8 ! \ - audioconvert ! \ - audio/x-raw, 'rate=48000,format=S16LE,channels=2' ! \ - filesink location="/dev/stdout" | \ - dabplus-enc \ - -i /dev/stdin -b $BITRATE -f raw -a -o "${DST}" - -elif [ "$GSTREAMER_VERSION" == "0" ] -then - gst-launch -q \ - uridecodebin uri=$URL ! \ - queue "max-size-time=$QUEUEDELAY" ! \ - audioresample quality=8 ! \ - audioconvert ! \ - audio/x-raw-int, 'rate=48000,format=S16LE,channels=2' ! \ - filesink location="/dev/stdout" | \ - dabplus-enc \ - -i /dev/stdin -b $BITRATE -f raw -a -o "${DST}" -fi - diff --git a/histogram.py b/histogram.py new file mode 100755 index 0000000..c17a255 --- /dev/null +++ b/histogram.py @@ -0,0 +1,28 @@ +#!/usr/bin/python2 +# +# Print sample histograms from dabmod I/Q file + +import sys + +import pylab as P +import numpy + + +fd = open('test.iq', 'rb') + +read_data = numpy.fromfile(file=fd, dtype=numpy.float32, count=-1) + +print("MAX absolute value: {}".format(numpy.max(numpy.abs(read_data)))) + +if 0: + P.plot(read_data) + +if 1: + P.figure() + + # the histogram of the data with histtype='step' + n, bins, patches = P.hist(read_data, 50, normed=1, histtype='stepfilled') + P.setp(patches, 'facecolor', 'g', 'alpha', 0.75) + +P.show() + diff --git a/minimal.ini b/minimal.ini new file mode 100644 index 0000000..8f98890 --- /dev/null +++ b/minimal.ini @@ -0,0 +1,11 @@ +[input] +transport=zeromq +source=tcp://core.mpb.li:9100 +max_frames_queued=400 + +[output] +output=file + +[fileoutput] +filename=/dev/null + diff --git a/modulatoroffset b/modulatoroffset index 2348025..5186d07 100644 --- a/modulatoroffset +++ b/modulatoroffset @@ -1 +1 @@ -1.200151 +4.0 diff --git a/mpeg_analyse.py b/mpeg_analyse.py new file mode 100755 index 0000000..495e808 --- /dev/null +++ b/mpeg_analyse.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python2 +# +# Analyse an mp2 file for debugging +# +# The MIT License (MIT) +# +# Copyright (c) 2016 Matthias P. Braendli +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +from pprint import pprint +import sys +import struct + +# Header: +# AAAAAAAA AAABBCCD EEEEFFGH IIJJKLMM +# see http://mpgedit.org/mpgedit/mpeg_format/mpeghdr.htm + +audio_version_ids = ["MPEG version 2.5", "reserved", "MPEG Version 2 (ISO/IEC 13818-3)", "MPEG Version 1 (ISO/IEC 11172-3)"] +layer_descriptions = ["reserved", "Layer III", "Layer II", "Layer I"] + +# bitrate index: +# bits V1,L1 V1,L2 V1,L3 V2,L1 V2, L2 & L3 +# 0000 free free free free free +# 0001 32 32 32 32 8 +# 0010 64 48 40 48 16 +# 0011 96 56 48 56 24 +# 0100 128 64 56 64 32 +# 0101 160 80 64 80 40 +# 0110 192 96 80 96 48 +# 0111 224 112 96 112 56 +# 1000 256 128 112 128 64 +# 1001 288 160 128 144 80 +# 1010 320 192 160 160 96 +# 1011 352 224 192 176 112 +# 1100 384 256 224 192 128 +# 1101 416 320 256 224 144 +# 1110 448 384 320 256 160 +# 1111 bad bad bad bad bad + +def analyse(fd): + headerdata = struct.unpack("!BBBB", fd.read(4)) + + sync = (headerdata[0] << 3) | (headerdata[1] >> 5) + print("Sync: {:x}".format(sync)) + + audio_version_id = (headerdata[1] >> 3) & 0x3 + print("audio_version_id {}".format(audio_version_ids[audio_version_id])) + + layer_description = (headerdata[1] >> 1) & 0x3 + print("layer_description {}".format(layer_descriptions[layer_description])) + + protection_bit = headerdata[1] & 0x1 + if protection_bit: + print("Without protection") + else: + print("With protection") + + bitrate_index = headerdata[2] >> 4 + print("bitrate_index {}".format(bitrate_index)) + + sampling_rate = (headerdata[2] >> 2) & 0x3 + print("sampling_rate {}".format(sampling_rate)) + + padding_bit = (headerdata[2] >> 1) & 0x1 + if padding_bit: + print("With padding") + else: + print("Without padding") + + private_bit = headerdata[2] & 0x1 + if private_bit: + print("Private bit set") + else: + print("Private bit unset") + + channel_mode = headerdata[3] >> 6 + print("channel_mode {}".format(channel_mode)) + + mode_extension = (headerdata[3] >> 4) & 0x3 + print("mode_extension {}".format(mode_extension)) + + copyright = (headerdata[3] >> 3) & 0x1 + if copyright: + print("With copyright") + else: + print("Without copyright") + + original = (headerdata[3] >> 2) & 0x1 + if original: + print("With original") + else: + print("Without original") + + emphasis = headerdata[3] & 0x3 + print("emphasis {}".format(emphasis)) + + + +fd = open(sys.argv[1], "rb") +analyse(fd) diff --git a/rdsparse/decoder_impl.cc b/rdsparse/decoder_impl.cc index 2bfa5a4..625a520 100644 --- a/rdsparse/decoder_impl.cc +++ b/rdsparse/decoder_impl.cc @@ -101,14 +101,24 @@ int decoder_impl::work (int noutput_items, lastseen_offset=j; lastseen_offset_counter=bit_counter; presync=true; + lout << "@@@@@ presync" << std::endl; } else { bit_distance=bit_counter-lastseen_offset_counter; - if (offset_pos[lastseen_offset]>=offset_pos[j]) + if (offset_pos[lastseen_offset]>=offset_pos[j]) { block_distance=offset_pos[j]+4-offset_pos[lastseen_offset]; - else + } + else { block_distance=offset_pos[j]-offset_pos[lastseen_offset]; - if ((block_distance*26)!=bit_distance) presync=false; + } + + if ((block_distance*26)!=bit_distance) { + presync=false; + lout << "@@@@@ presync lost " << j << " " << + block_distance*26 << " " << + bit_distance << " " << + std::endl; + } else { lout << "@@@@@ Sync State Detected" << std::endl; enter_sync(j); @@ -148,6 +158,11 @@ int decoder_impl::work (int noutput_items, else { wrong_blocks_counter++; good_block=false; + lout << "@@@@@ CRC " << + std::hex << std::setfill('0') << std::setw(4) << + block_received_crc << " " << + std::hex << std::setfill('0') << std::setw(4) << + block_calculated_crc << std::dec << std::endl; } } /* done checking CRC */ @@ -1,7 +1,7 @@ ; Sample configuration file for CRC-DABMOD [remotecontrol] -telnet=1 +telnet=0 telnetport=2121 [log] @@ -11,12 +11,13 @@ filename=/dev/stderr [input] transport=file -;source=/home/bram/dab/mmbtools-aux/eti/csp.eti -source=/dev/stdin +source=/home/bram/dab/mmbtools-aux/eti/funk2.100.eti +;source=/dev/stdin +loop=0 ;transport=zeromq -;source=tcp://localhost:8080 -loop=0 +;source=tcp://localhost:9100 +;max_frames_queued=400 [modulator] ; Gain mode: 0=FIX, 1=MAX, 2=VAR @@ -24,7 +25,7 @@ gainmode=2 ; Transmission mode ; If not defined, take the mode from ETI -mode=1 +;mode=0 ; Set to 0 to disable CicEqualiser dac_clk_rate=0 @@ -32,25 +33,30 @@ dac_clk_rate=0 digital_gain=1.0 ; Output sample rate -rate=8000000 +rate=2048000 [firfilter] -enabled=1 +enabled=0 filtertapsfile=filter/simplefiltertaps.txt [output] ; choose output: possible values: uhd, file output=file +[zmqoutput] +listen=tcp://*:9200 +socket_type=rep + [fileoutput] -filename=/dev/stdout +filename=ofdm.iq +;filename=/dev/null [uhdoutput] ;frequency=234208000 channel=13C ; For the B200 -master_clock_rate=32000000 +master_clock_rate=32768000 type=b200 txgain=35 @@ -73,7 +79,4 @@ behaviour_refclk_lock_lost=crash synchronous=0 ; choose between fixed and dynamic offset definition -management=dynamic - -fixedoffset=0.002 -dynamicoffsetfile=modulatoroffset +offset=0.002 diff --git a/zmq-simul.mux b/zmq-simul.mux index 5689f31..6a599dc 100644 --- a/zmq-simul.mux +++ b/zmq-simul.mux @@ -8,9 +8,11 @@ general { ; The statsserver for extracting statistics statsserverport 12720 - syslog false + syslog true writescca false tist true + + new_fig_carousel true } remotecontrol { @@ -29,6 +31,26 @@ ensemble { international-table 1 label "TuxMux" shortlabel "Tux" + + ; Announcement settings for FIG0/19 + announcements { + alarm { + cluster 0xFF + flags { + Alarm true + } + + subchannel sub-fb + } + test_announcement { + cluster 1 + flags { + Traffic true + } + + subchannel sub-fb + } + } } services { @@ -39,11 +61,23 @@ services { language 0 id 0x4060 ; also supports id + + announcements { + Traffic true + Alarm true + clusters "1,255" + } } srv-label { label "label" id 0x4040 ; also supports id + + announcements { + Traffic true + Alarm true + clusters "1,255" + } } } @@ -54,10 +88,11 @@ subchannels { sub-fb { type dabplus ; use ZeroMQ: - inputfile "tcp://*:9001" + ;inputfile "tcp://*:9001" + inputfile "./stream-0.msc" zmq-buffer 40 zmq-prebuffering 20 - bitrate 80 + bitrate 128 id 24 protection 3 @@ -68,13 +103,21 @@ subchannels { } sub-label { type audio - inputfile "tcp://*:9002" + inputfile "/home/bram/dab/mmbtools-aux/fip-j-ok.mp2" + ;inputfile "tcp://*:9002" zmq-buffer 40 zmq-prebuffering 20 bitrate 128 id 4 protection 3 } +; sub-data { +; type data +; inputfile "udp://:9003" +; bitrate 16 +; id 5 +; protection 3 +; } } ; For now, each component links one service to one subchannel @@ -91,7 +134,6 @@ components { } comp-label { - label "label" service srv-label subchannel sub-label } @@ -100,10 +142,48 @@ components { ; A list of outputs, in the format ; unique-id "uri" outputs { - stdout "fifo:///dev/stdout?type=raw" - zmq "zmq+tcp://*:9100" + ;stdout "fifo:///dev/stdout?type=raw" + ;thefile "file://./zmq-simul.eti?type=raw" + ;zmq "zmq+tcp://*:9100" ; This throttles muxing down to nominal rate throttle "simul://" + + ;net_udp "udp://shack.local:31000" + net_tcp "tcp://0.0.0.0:31000" + + edi { + fec 0 + chunk_len 200 + + destinations { + multicast { + destination "239.20.64.1" + ;source "192.168.2.10" + source "192.168.0.100" + sourceport 52321 + ttl 1 + } + ;unicast { + ;destination "192.168.2.2" + ;} + } + + port 52002 + + ; EDI uses the UDP protocol + + ; Enable the PFT subsystem. If false, AFPackets are sent. + enable_pft true + + ; Save the packets sent over ethernet to the file ./edi.debug + dump false + + ; show more debugging info + verbose false + + ; optional: what kind of alignment to do in the tagpacket + tagpacket_alignment 16 + } } |