diff options
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | configure.ac | 5 | ||||
-rw-r--r-- | doc/example.mux | 54 | ||||
-rw-r--r-- | src/ConfigParser.cpp | 4 | ||||
-rw-r--r-- | src/DabMultiplexer.cpp | 38 | ||||
-rw-r--r-- | src/DabMultiplexer.h | 12 | ||||
-rw-r--r-- | src/DabMux.cpp | 13 | ||||
-rw-r--r-- | src/MuxElements.cpp | 16 | ||||
-rw-r--r-- | src/MuxElements.h | 1 | ||||
-rw-r--r-- | src/UdpSocket.cpp | 34 | ||||
-rw-r--r-- | src/UdpSocket.h | 9 | ||||
-rw-r--r-- | src/dabOutput/dabOutput.h | 4 | ||||
-rw-r--r-- | src/fig/FIG0.h | 3 |
13 files changed, 159 insertions, 40 deletions
@@ -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: |