aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--configure.ac5
-rw-r--r--doc/example.mux54
-rw-r--r--src/ConfigParser.cpp4
-rw-r--r--src/DabMultiplexer.cpp38
-rw-r--r--src/DabMultiplexer.h12
-rw-r--r--src/DabMux.cpp13
-rw-r--r--src/MuxElements.cpp16
-rw-r--r--src/MuxElements.h1
-rw-r--r--src/UdpSocket.cpp34
-rw-r--r--src/UdpSocket.h9
-rw-r--r--src/dabOutput/dabOutput.h4
-rw-r--r--src/fig/FIG0.h3
13 files changed, 159 insertions, 40 deletions
diff --git a/ChangeLog b/ChangeLog
index b9b9b88..cf70f3c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,12 @@
This file contains information about the changes done to
the ODR-DabMux in this repository
+2015-11-27: Matthias P. Braendli <matthias@mpb.li>
+ (v0.8.1):
+ Fix compilation with test input.
+ Add PTy to remote control.
+ Add EDI options to configuration file for multicast settings.
+
2015-09-13: Matthias P. Braendli <matthias@mpb.li>
(v0.8.0):
Pad labels with spaces instead of terminating them with NUL.
diff --git a/configure.ac b/configure.ac
index 265b853..f23df79 100644
--- a/configure.ac
+++ b/configure.ac
@@ -17,7 +17,7 @@
# along with ODR-DabMux. If not, see <http://www.gnu.org/licenses/>.
AC_PREREQ(2.61)
-AC_INIT([ODR-DabMux], [0.8.0], [matthias.braendli@mpb.li])
+AC_INIT([ODR-DabMux], [0.8.1], [matthias.braendli@mpb.li])
AC_CONFIG_AUX_DIR([build-aux])
AC_CANONICAL_SYSTEM
AM_INIT_AUTOMAKE([-Wall subdir-objects foreign])
@@ -198,7 +198,8 @@ AS_IF([test "x$enable_output_zeromq" = "xyes"],
AC_DEFINE(HAVE_OUTPUT_ZEROMQ, [1], [Define if ZeroMQ output is enabled]))
# EDI
AC_ARG_ENABLE([output_edi],
- AS_HELP_STRING([--enable-output-edi], [Enable EDI output]))
+ [AS_HELP_STRING([--disable-output-edi], [Disable EDI output])],
+ [], [enable_output_edi=yes])
AS_IF([test "x$enable_output_edi" = "xyes"],
[AC_DEFINE(HAVE_OUTPUT_EDI, [1], [Define if EDI output is enabled])])
diff --git a/doc/example.mux b/doc/example.mux
index 4f4a2bc..456e046 100644
--- a/doc/example.mux
+++ b/doc/example.mux
@@ -1,5 +1,8 @@
; This is the official configuration file example that
; serves as documentation for the config file reader.
+; More information about the usage of the tools is available
+; in the guide, which can be found on the
+; www.opendigitalradio.org website.
;
; As you can see, comments are defined by semicolons.
;
@@ -17,7 +20,6 @@ general {
; the number of ETI frames to generate (set to 0 to get an unlimited number)
nbframes 10
-
; boolean fileds can accept either false or true as values:
; Enable logging to syslog
@@ -62,15 +64,20 @@ ensemble {
id 0x4fff ; you can also use decimal if you want
ecc 0xec ; Extended Country Code
- local-time-offset 1 ; in hours, supports half-hour offsets
+ local-time-offset auto ; autmatically calculate from system local time
; or
- ;local-time-offset auto ; autmatically calculate from system local time
+ ;local-time-offset 1 ; in hours, supports half-hour offsets
international-table 1 ; See TS 101 756 clause 5.7
; 1 corresponds to the PTy used in RDS
; 2 corresponds to program types used in north america
+
+ ; all labels are maximum 16 characters in length
label "TuxMux"
- shortlabel "Tux"
+ ; 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 "TxMux"
; Announcement settings for FIG0/19
announcements {
@@ -121,7 +128,6 @@ services {
}
srv-ri {
label "rick"
- shortlabel "rick"
}
}
@@ -245,8 +251,11 @@ components {
; data: unspecified=0, TMC=1, EWS=2, ITTS=3, paging=4, TDC=5, IP=59, MOT=60, proprietary=61
type 0
- label "funk"
- shortlabel "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.
+ ;label "funk"
+ ;shortlabel "fu"
service srv-fu
subchannel sub-fu
@@ -276,12 +285,6 @@ components {
}
comp-lu {
- ; labels are maximum 16 characters in length
- label "luschtig"
-
- ; a shortlabel is created by dropping some letters from the
- ; label, max length 8
- shortlabel "lu"
service srv-lu
subchannel sub-lu
@@ -289,8 +292,6 @@ components {
}
comp-ri {
- label "rick"
- shortlabel "rick"
service srv-ri
subchannel sub-ri
@@ -320,17 +321,28 @@ outputs {
; The edi output has a different syntax
edi {
- destination "192.168.23.23"
- port 12000
- sourceport 13000
+ ; example for unicast EDI
+ ;destination "192.168.23.23"
+ ; for unicast EDI, do not set source
+
+ ; example for multicast EDI, the source IP is required
+ ; so that the data is sent on the correct ethernet interface
+ destination "232.20.10.1"
+ source "192.168.0.50"
+ ; The multicast TTL has to be adapted according to your network
+ ttl 1
+
+ ; The settings below apply to both unicast and multicast
; EDI uses the UDP protocol
+ port 12000
+ sourceport 13000
; Enable the PFT subsystem. If false, AFPackets are sent.
- enable_pft false
+ enable_pft true
; How many lost fragments can be recovered by Reed-Solomon
- fec 3
+ fec 2
; Length of a RS chunk, can be overriden
;default=207
@@ -340,7 +352,7 @@ outputs {
dump false
; show more debugging info
- verbose true
+ verbose false
; (optional) set the kind of alignment to use in TAG Packets
; 0: no padding
diff --git a/src/ConfigParser.cpp b/src/ConfigParser.cpp
index 7803ad5..db01769 100644
--- a/src/ConfigParser.cpp
+++ b/src/ConfigParser.cpp
@@ -778,7 +778,7 @@ void setup_subchannel_from_ptree(dabSubchannel* subchan,
subchan->bitrate = DEFAULT_DATA_BITRATE;
#if defined(HAVE_INPUT_TEST) && defined(HAVE_FORMAT_RAW)
} else if (type == "test") {
- subchan->type = DataDmb;
+ subchan->type = subchannel_type_t::DataDmb;
subchan->bitrate = DEFAULT_DATA_BITRATE;
operations = dabInputTestOperations;
#endif // defined(HAVE_INPUT_TEST)) && defined(HAVE_FORMAT_RAW)
@@ -794,7 +794,7 @@ void setup_subchannel_from_ptree(dabSubchannel* subchan,
# pragma error("Must define at least one packet input")
#endif // defined(HAVE_INPUT_FILE)
#ifdef HAVE_FORMAT_EPM
- } else if (type == "enhancedpacked") {
+ } else if (type == "enhancedpacket") {
subchan->type = subchannel_type_t::Packet;
subchan->bitrate = DEFAULT_PACKET_BITRATE;
operations = dabInputEnhancedPacketFileOperations;
diff --git a/src/DabMultiplexer.cpp b/src/DabMultiplexer.cpp
index 5defce7..399084a 100644
--- a/src/DabMultiplexer.cpp
+++ b/src/DabMultiplexer.cpp
@@ -151,7 +151,25 @@ void DabMultiplexer::set_edi_config(const edi_configuration_t& new_edi_conf)
}
if (edi_conf.enabled) {
- edi_output.create(edi_conf.source_port);
+ int err = edi_output.create(edi_conf.source_port);
+
+ if (err) {
+ etiLog.level(error) << "EDI socket creation failed!";
+ throw MuxInitException();
+ }
+
+ if (not edi_conf.source_addr.empty()) {
+ err = edi_output.setMulticastSource(edi_conf.source_addr.c_str());
+ if (err) {
+ etiLog.level(error) << "EDI socket set source failed!";
+ throw MuxInitException();
+ }
+ err = edi_output.setMulticastTTL(edi_conf.ttl);
+ if (err) {
+ etiLog.level(error) << "EDI socket set TTL failed!";
+ throw MuxInitException();
+ }
+ }
}
if (edi_conf.verbose) {
@@ -1734,10 +1752,22 @@ void DabMultiplexer::mux_frame(std::vector<boost::shared_ptr<DabOutput> >& outpu
edi_tagDETI.tsta = tist->TIST;
- timestamp += 3 << 17;
- if (timestamp > 0xf9ffff)
+ /* Coding of the TIST, according to ETS 300 799 Annex C
+
+ Bit number b0(MSb)..b6 b7..b9 b10..b17 b18..b20 b21..b23(LSb)
+ Bit number b23(MSb)..b17 b16..b14 b13..b6 b5..b3 b2..b0(LSb)
+ as uint32_t
+ Width 7 3 8 3 3
+ Timestamp level 1 2 3 4 5
+ Valid range [0..124], 127 [0..7] [0..255] [0..7] [0..7]
+ Approximate 8 ms 1 ms 3,91 us 488 ns 61 ns
+ time resolution
+ */
+
+ timestamp += 24 << 13; // Shift 24ms by 13 to Timestamp level 2
+ if (timestamp > 0xf9FFff)
{
- timestamp -= 0xfa0000;
+ timestamp -= 0xfa0000; // Substract 16384000, corresponding to one second
// Also update MNSC time for next frame
MNSC_increment_time = true;
diff --git a/src/DabMultiplexer.h b/src/DabMultiplexer.h
index f454d20..bafefff 100644
--- a/src/DabMultiplexer.h
+++ b/src/DabMultiplexer.h
@@ -381,10 +381,14 @@ struct FIGtype0_17_programme {
uint16_t SId;
uint8_t NFC:2;
uint8_t Rfa:2;
- uint8_t CC:1;
- uint8_t L:1;
- uint8_t PS:1;
- uint8_t SD:1;
+ uint8_t CC:1; // Complimentary code
+ uint8_t L:1; // Signals presence of language field
+ uint8_t PS:1; // Primary/Secondary
+ // PS==0: language refers to primary service component
+ // PS==1: language refers to secondary service component
+ uint8_t SD:1; // Static/Dynamic
+ // SD==0: PTy and language may not represent the current programme contents
+ // SD==1: PTy and language represent the current programme contents
} PACKED;
struct FIGtype0_18 {
diff --git a/src/DabMux.cpp b/src/DabMux.cpp
index 04aed2b..f3f0c95 100644
--- a/src/DabMux.cpp
+++ b/src/DabMux.cpp
@@ -325,7 +325,9 @@ int main(int argc, char *argv[])
edi_conf.dest_addr = pt_edi.get<string>("destination");
edi_conf.dest_port = pt_edi.get<unsigned int>("port");
+ edi_conf.source_addr = pt_edi.get<string>("source", "");
edi_conf.source_port = pt_edi.get<unsigned int>("sourceport");
+ edi_conf.ttl = pt_edi.get<unsigned int>("ttl", 1);
edi_conf.dump = pt_edi.get<bool>("dump");
edi_conf.enable_pft = pt_edi.get<bool>("enable_pft");
@@ -430,10 +432,13 @@ int main(int argc, char *argv[])
#if HAVE_OUTPUT_EDI
if (edi_conf.enabled) {
- etiLog.level(warn) << "EXPERIMENTAL EDI OUTPUT ENABLED!";
- etiLog.level(info) << "edi to " << edi_conf.dest_addr << ":" << edi_conf.dest_port;
- etiLog.level(info) << "source port " << edi_conf.source_port;
- etiLog.level(info) << "verbose " << edi_conf.verbose;
+ etiLog.level(info) << "EDI to " << edi_conf.dest_addr << ":" << edi_conf.dest_port;
+ if (not edi_conf.source_addr.empty()) {
+ etiLog.level(info) << " source " << edi_conf.source_addr;
+ etiLog.level(info) << " ttl " << edi_conf.ttl;
+ }
+ etiLog.level(info) << " source port " << edi_conf.source_port;
+ etiLog.level(info) << " verbose " << edi_conf.verbose;
}
#endif
diff --git a/src/MuxElements.cpp b/src/MuxElements.cpp
index be0906e..adc6a60 100644
--- a/src/MuxElements.cpp
+++ b/src/MuxElements.cpp
@@ -404,6 +404,19 @@ void DabService::set_parameter(const string& parameter,
throw ParameterError(ss.str());
}
}
+ else if (parameter == "pty") {
+ int newpty = std::stoi(value); // International code, 5 bits
+
+ if (newpty >= 0 and newpty < (1<<5)) {
+ pty = newpty;
+ }
+ else {
+ stringstream ss;
+ ss << m_name << " pty is out of bounds";
+ etiLog.level(warn) << ss.str();
+ throw ParameterError(ss.str());
+ }
+ }
else {
stringstream ss;
ss << "Parameter '" << parameter <<
@@ -418,6 +431,9 @@ const string DabService::get_parameter(const string& parameter) const
if (parameter == "label") {
ss << label.long_label() << "," << label.short_label();
}
+ else if (parameter == "pty") {
+ ss << (int)pty;
+ }
else {
ss << "Parameter '" << parameter <<
"' is not exported by controllable " << get_rc_name();
diff --git a/src/MuxElements.h b/src/MuxElements.h
index 9fe2aeb..dc84ccb 100644
--- a/src/MuxElements.h
+++ b/src/MuxElements.h
@@ -338,6 +338,7 @@ class DabService : public RemoteControllable
uid(uid)
{
RC_ADD_PARAMETER(label, "Label and shortlabel [label,short]");
+ RC_ADD_PARAMETER(pty, "Programme Type");
}
std::string uid;
diff --git a/src/UdpSocket.cpp b/src/UdpSocket.cpp
index a1a7935..af26430 100644
--- a/src/UdpSocket.cpp
+++ b/src/UdpSocket.cpp
@@ -1,6 +1,9 @@
/*
Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Her Majesty the
Queen in Right of Canada (Communications Research Center Canada)
+
+ Copyright (C) 2015 Matthias P. Braendli
+ http://www.opendigitalradio.org
*/
/*
This file is part of ODR-DabMux.
@@ -155,6 +158,7 @@ int UdpSocket::create(int port, char *name)
setInetError("Can't reuse address");
return -1;
}
+
if (bind(listenSocket, address.getAddress(), sizeof(sockaddr_in)) == SOCKET_ERROR) {
setInetError("Can't bind socket");
closesocket(listenSocket);
@@ -291,7 +295,35 @@ int UdpSocket::joinGroup(char* groupname)
return 0;
}
-
+int UdpSocket::setMulticastTTL(int ttl)
+{
+ if (setsockopt(listenSocket, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl))
+ == SOCKET_ERROR) {
+ setInetError("Can't set ttl");
+ return -1;
+ }
+
+ return 0;
+}
+
+int UdpSocket::setMulticastSource(const char* source_addr)
+{
+ struct in_addr addr;
+ if (inet_aton(source_addr, &addr) == 0) {
+ setInetError("Can't parse source address");
+ return -1;
+ }
+
+ if (setsockopt(listenSocket, IPPROTO_IP, IP_MULTICAST_IF, &addr, sizeof(addr))
+ == SOCKET_ERROR) {
+ setInetError("Can't set source address");
+ return -1;
+ }
+
+ return 0;
+}
+
+
/**
* Constructs an UDP packet.
* @param initSize The initial size of the data buffer
diff --git a/src/UdpSocket.h b/src/UdpSocket.h
index e23401c..07e9f0e 100644
--- a/src/UdpSocket.h
+++ b/src/UdpSocket.h
@@ -1,6 +1,9 @@
/*
Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Her Majesty the
Queen in Right of Canada (Communications Research Center Canada)
+
+ Copyright (C) 2015 Matthias P. Braendli
+ http://www.opendigitalradio.org
*/
/*
This file is part of ODR-DabMux.
@@ -58,7 +61,7 @@ class UdpPacket;
* A UDP socket is the sending or receiving point for a packet delivery service.
* Each packet sent or received on a datagram socket is individually
* addressed and routed. Multiple packets sent from one machine to another may
- * be routed differently, and may arrive in any order.
+ * be routed differently, and may arrive in any order.
* @author Pascal Charest pascal.charest@crc.ca
*/
class UdpSocket {
@@ -66,6 +69,8 @@ class UdpSocket {
UdpSocket();
UdpSocket(int port, char *name = NULL);
~UdpSocket();
+ UdpSocket(const UdpSocket& other) = delete;
+ const UdpSocket& operator=(const UdpSocket& other) = delete;
static int init();
static int clean();
@@ -77,6 +82,8 @@ class UdpSocket {
int send(std::vector<uint8_t> data, InetAddress destination);
int receive(UdpPacket &packet);
int joinGroup(char* groupname);
+ int setMulticastSource(const char* source_addr);
+ int setMulticastTTL(int ttl);
/**
* Connects the socket on a specific address. Only data from this address
* will be received.
diff --git a/src/dabOutput/dabOutput.h b/src/dabOutput/dabOutput.h
index 0ced9d3..b2100ab 100644
--- a/src/dabOutput/dabOutput.h
+++ b/src/dabOutput/dabOutput.h
@@ -61,12 +61,14 @@ struct edi_configuration_t {
unsigned chunk_len; // RSk, data length of each chunk
unsigned fec; // number of fragments that can be recovered
bool enabled;
- unsigned int source_port;
bool dump;
bool verbose;
bool enable_pft;
std::string dest_addr;
+ std::string source_addr;
+ unsigned int source_port;
unsigned int dest_port;
+ unsigned int ttl;
unsigned int tagpacket_alignment;
};
diff --git a/src/fig/FIG0.h b/src/fig/FIG0.h
index 9811eaf..2dc6483 100644
--- a/src/fig/FIG0.h
+++ b/src/fig/FIG0.h
@@ -27,6 +27,8 @@
#define __FIG0_H_
#include <cstdint>
+#include <map>
+#include <set>
#include "fig/FIG.h"
@@ -181,6 +183,7 @@ class FIG0_13 : public IFIG
};
// FIG type 0/17
+// Programme Type (PTy)
class FIG0_17 : public IFIG
{
public: