aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2016-11-07 21:37:47 +0100
committerMatthias P. Braendli <matthias.braendli@mpb.li>2016-11-07 21:37:47 +0100
commit95b197a53c8314a68fd8cf73e495018844e7d708 (patch)
treed7a1f48c0c7f04bea34c9e19dc219195469df563 /src
parent33e51f5996c02c6a6aee27b57d91d90e3f1db5a2 (diff)
parent21d8cacffc1201514b0e1143f8de60e754262291 (diff)
downloaddabmux-95b197a53c8314a68fd8cf73e495018844e7d708.tar.gz
dabmux-95b197a53c8314a68fd8cf73e495018844e7d708.tar.bz2
dabmux-95b197a53c8314a68fd8cf73e495018844e7d708.zip
Merge rework of inputs into 'next'
This breaks the non-blocking fifo inputs, as it seems nobody is using them. It restores some UDP functionality, not necessarily in the same way as before.
Diffstat (limited to 'src')
-rw-r--r--src/ConfigParser.cpp216
-rw-r--r--src/DabMux.cpp18
-rw-r--r--src/DabMux.h7
-rw-r--r--src/Makefile.am22
-rw-r--r--src/MuxElements.h4
-rw-r--r--src/UdpSocket.cpp18
-rw-r--r--src/UdpSocket.h10
-rw-r--r--src/dabInput.h17
-rw-r--r--src/dabInputMpegFile.cpp31
-rw-r--r--src/input/File.cpp443
-rw-r--r--src/input/File.h91
-rw-r--r--src/input/Prbs.cpp (renamed from src/dabInputPrbs.cpp)35
-rw-r--r--src/input/Prbs.h (renamed from src/dabInputPrbs.h)14
-rw-r--r--src/input/Udp.cpp134
-rw-r--r--src/input/Udp.h52
-rw-r--r--src/input/Zmq.cpp (renamed from src/dabInputZmq.cpp)53
-rw-r--r--src/input/Zmq.h (renamed from src/dabInputZmq.h)48
-rw-r--r--src/input/inputs.h52
-rw-r--r--src/mpeg.c26
-rw-r--r--src/mpeg.h7
-rw-r--r--src/utils.cpp20
21 files changed, 1107 insertions, 211 deletions
diff --git a/src/ConfigParser.cpp b/src/ConfigParser.cpp
index 770daa6..1ed1bac 100644
--- a/src/ConfigParser.cpp
+++ b/src/ConfigParser.cpp
@@ -48,27 +48,16 @@
#include <map>
#include <cstring>
#include "dabOutput/dabOutput.h"
-#include "dabInput.h"
+#include "input/inputs.h"
#include "utils.h"
-#include "dabInputFile.h"
-#include "dabInputFifo.h"
-#include "dabInputMpegFile.h"
-#include "dabInputMpegFifo.h"
-#include "dabInputDabplusFile.h"
-#include "dabInputDabplusFifo.h"
-#include "dabInputPacketFile.h"
-#include "dabInputEnhancedPacketFile.h"
-#include "dabInputEnhancedFifo.h"
-#include "dabInputUdp.h"
-#include "dabInputPrbs.h"
-#include "dabInputRawFile.h"
-#include "dabInputRawFifo.h"
-#include "dabInputDmbFile.h"
-#include "dabInputDmbUdp.h"
-#include "dabInputZmq.h"
#include "DabMux.h"
#include "ManagementServer.h"
+#include "input/Prbs.h"
+#include "input/Zmq.h"
+#include "input/File.h"
+#include "input/Udp.h"
+
#ifdef _WIN32
# pragma warning ( disable : 4103 )
@@ -541,13 +530,13 @@ void parse_ptree(
}
}
-static dab_input_zmq_config_t setup_zmq_input(
+static Inputs::dab_input_zmq_config_t setup_zmq_input(
const boost::property_tree::ptree &pt,
const std::string& subchanuid)
{
using boost::property_tree::ptree_error;
- dab_input_zmq_config_t zmqconfig;
+ Inputs::dab_input_zmq_config_t zmqconfig;
try {
zmqconfig.buffer_size = pt.get<int>("zmq-buffer");
@@ -621,6 +610,7 @@ static void setup_subchannel_from_ptree(DabSubchannel* subchan,
subchan->inputUri = inputUri;
+#if OLD_INPUTS // {{{
/* The input is of the old_style type,
* with the struct of function pointers,
* and needs to be a DabInputCompatible
@@ -714,7 +704,7 @@ static void setup_subchannel_from_ptree(DabSubchannel* subchan,
} else if (type == "data" and proto == "prbs") {
input_is_old_style = false;
- subchan->input = new DabInputPrbs();
+ subchan->input = make_shared<Inputs::Prbs>();
subchan->type = subchannel_type_t::DataDmb;
subchan->bitrate = DEFAULT_DATA_BITRATE;
} else if (type == "data") {
@@ -928,5 +918,191 @@ static void setup_subchannel_from_ptree(DabSubchannel* subchan,
subchan->input = new DabInputCompatible(operations);
}
// else { it's already been created! }
+#endif // 0 }}}
+
+ dabProtection* protection = &subchan->protection;
+
+ const bool nonblock = pt.get("nonblock", false);
+ if (nonblock) {
+ etiLog.level(warn) << "The nonblock option is not supported";
+ }
+
+ if (type == "dabplus" or type == "audio") {
+ subchan->type = subchannel_type_t::Audio;
+ subchan->bitrate = 0;
+
+ if (proto == "file") {
+ if (type == "audio") {
+ subchan->input = make_shared<Inputs::MPEGFile>();
+ }
+ else if (type == "dabplus") {
+ subchan->input = make_shared<Inputs::RawFile>();
+ }
+ else {
+ throw logic_error("Incomplete handling of file input");
+ }
+ }
+ else if (proto == "tcp" ||
+ proto == "epgm" ||
+ proto == "ipc") {
+
+ auto zmqconfig = setup_zmq_input(pt, subchanuid);
+
+ if (type == "audio") {
+ auto inzmq = make_shared<Inputs::ZmqMPEG>(subchanuid, zmqconfig);
+ rcs.enrol(inzmq.get());
+ subchan->input = inzmq;
+ }
+ else if (type == "dabplus") {
+ auto inzmq = make_shared<Inputs::ZmqAAC>(subchanuid, zmqconfig);
+ rcs.enrol(inzmq.get());
+ subchan->input = inzmq;
+ }
+
+ if (proto == "epgm") {
+ etiLog.level(warn) << "Using untested epgm:// zeromq input";
+ }
+ else if (proto == "ipc") {
+ etiLog.level(warn) << "Using untested ipc:// zeromq input";
+ }
+ }
+ else {
+ stringstream ss;
+ ss << "Subchannel with uid " << subchanuid <<
+ ": Invalid protocol for " << type << " input (" <<
+ proto << ")" << endl;
+ throw runtime_error(ss.str());
+ }
+ }
+ else if (type == "data" and proto == "prbs") {
+ subchan->input = make_shared<Inputs::Prbs>();
+ subchan->type = subchannel_type_t::DataDmb;
+ subchan->bitrate = DEFAULT_DATA_BITRATE;
+ }
+ else if (type == "data" or type == "dmb") {
+ if (proto == "udp") {
+ subchan->input = make_shared<Inputs::Udp>();
+ } else if (proto == "file" or proto == "fifo") {
+ subchan->input = make_shared<Inputs::RawFile>();
+ } else {
+ stringstream ss;
+ ss << "Subchannel with uid " << subchanuid <<
+ ": Invalid protocol for data input (" <<
+ proto << ")" << endl;
+ throw runtime_error(ss.str());
+ }
+
+ subchan->type = subchannel_type_t::DataDmb;
+ subchan->bitrate = DEFAULT_DATA_BITRATE;
+
+ if (type == "dmb") {
+ /* The old dmb input took care of interleaving and Reed-Solomon encoding. This
+ * code is unported.
+ * See dabInputDmbFile.cpp
+ */
+ etiLog.level(warn) << "uid " << subchanuid << " of type Dmb uses RAW input";
+ }
+ }
+ else if (type == "packet" or type == "enhancedpacket") {
+ subchan->type = subchannel_type_t::Packet;
+ subchan->bitrate = DEFAULT_PACKET_BITRATE;
+
+ bool enhanced = (type == "enhancedpacket");
+ subchan->input = make_shared<Inputs::PacketFile>(enhanced);
+ }
+ else {
+ stringstream ss;
+ ss << "Subchannel with uid " << subchanuid << " has unknown type!";
+ throw runtime_error(ss.str());
+ }
+ subchan->startAddress = 0;
+
+ if (type == "audio") {
+ protection->form = UEP;
+ protection->level = 2;
+ protection->uep.tableIndex = 0;
+ }
+ else {
+ protection->level = 2;
+ protection->form = EEP;
+ protection->eep.profile = EEP_A;
+ }
+
+ /* Get bitrate */
+ try {
+ subchan->bitrate = pt.get<int>("bitrate");
+ if ((subchan->bitrate & 0x7) != 0) {
+ stringstream ss;
+ ss << "Subchannel with uid " << subchanuid <<
+ ": Bitrate (" << subchan->bitrate << " not a multiple of 8!";
+ throw runtime_error(ss.str());
+ }
+ }
+ catch (ptree_error &e) {
+ stringstream ss;
+ ss << "Error, no bitrate defined for subchannel " << subchanuid;
+ throw runtime_error(ss.str());
+ }
+
+ /* Get id */
+ try {
+ subchan->id = hexparse(pt.get<std::string>("id"));
+ }
+ catch (ptree_error &e) {
+ for (int i = 0; i < 64; ++i) { // Find first free subchannel
+ vector<DabSubchannel*>::iterator subchannel = getSubchannel(ensemble->subchannels, i);
+ if (subchannel == ensemble->subchannels.end()) {
+ subchannel = ensemble->subchannels.end() - 1;
+ subchan->id = i;
+ break;
+ }
+ }
+ }
+
+ /* Get optional protection profile */
+ string profile = pt.get("protection-profile", "");
+
+ if (profile == "EEP_A") {
+ protection->form = EEP;
+ protection->eep.profile = EEP_A;
+ }
+ else if (profile == "EEP_B") {
+ protection->form = EEP;
+ protection->eep.profile = EEP_B;
+ }
+ else if (profile == "UEP") {
+ protection->form = UEP;
+ }
+
+ /* Get protection level */
+ try {
+ int level = pt.get<int>("protection");
+
+ if (protection->form == UEP) {
+ if ((level < 1) || (level > 5)) {
+ stringstream ss;
+ ss << "Subchannel with uid " << subchanuid <<
+ ": protection level must be between "
+ "1 to 5 inclusively (current = " << level << " )";
+ throw runtime_error(ss.str());
+ }
+ }
+ else if (protection->form == EEP) {
+ if ((level < 1) || (level > 4)) {
+ stringstream ss;
+ ss << "Subchannel with uid " << subchanuid <<
+ ": protection level must be between "
+ "1 to 4 inclusively (current = " << level << " )";
+ throw runtime_error(ss.str());
+ }
+ }
+ protection->level = level - 1;
+ }
+ catch (ptree_error &e) {
+ stringstream ss;
+ ss << "Subchannel with uid " << subchanuid <<
+ ": protection level undefined!";
+ throw runtime_error(ss.str());
+ }
}
diff --git a/src/DabMux.cpp b/src/DabMux.cpp
index 32ddb39..3927420 100644
--- a/src/DabMux.cpp
+++ b/src/DabMux.cpp
@@ -94,22 +94,8 @@ typedef DWORD32 uint32_t;
# include "Eti.h"
#endif
-#include "dabInputFile.h"
-#include "dabInputFifo.h"
-#include "dabInputMpegFile.h"
-#include "dabInputMpegFifo.h"
-#include "dabInputDabplusFile.h"
-#include "dabInputDabplusFifo.h"
-#include "dabInputPacketFile.h"
-#include "dabInputEnhancedPacketFile.h"
-#include "dabInputEnhancedFifo.h"
-#include "dabInputUdp.h"
-#include "dabInputPrbs.h"
-#include "dabInputRawFile.h"
-#include "dabInputRawFifo.h"
-#include "dabInputDmbFile.h"
-#include "dabInputDmbUdp.h"
-
+#include "input/Prbs.h"
+#include "input/Zmq.h"
#include "dabOutput/dabOutput.h"
#include "dabOutput/edi/TagItems.h"
diff --git a/src/DabMux.h b/src/DabMux.h
index 5dda759..80b4881 100644
--- a/src/DabMux.h
+++ b/src/DabMux.h
@@ -25,8 +25,7 @@
You should have received a copy of the GNU General Public License
along with ODR-DabMux. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef _DABMUX_H
-#define _DABMUX_H
+#pragma once
#include <stdint.h>
#include <string>
@@ -34,7 +33,7 @@
#include "DabMultiplexer.h"
#include "RemoteControl.h"
#include "dabOutput/dabOutput.h"
-#include "dabInput.h"
+#include "input/inputs.h"
#include "Eti.h"
#include "MuxElements.h"
@@ -44,5 +43,3 @@
# include <sys/time.h>
#endif
-#endif
-
diff --git a/src/Makefile.am b/src/Makefile.am
index 408c86e..084cf7b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -47,23 +47,11 @@ odr_dabmux_LDADD =$(ZMQ_LIBS) $(CURL_LIBS) \
odr_dabmux_SOURCES =DabMux.cpp DabMux.h \
DabMultiplexer.cpp DabMultiplexer.h \
- dabInput.h dabInput.cpp \
- dabInputDabplusFifo.h dabInputDabplusFifo.cpp \
- dabInputDabplusFile.h dabInputDabplusFile.cpp \
- dabInputDmbFile.h dabInputDmbFile.cpp \
- dabInputDmbUdp.h dabInputDmbUdp.cpp \
- dabInputEnhancedFifo.h dabInputEnhancedFifo.cpp \
- dabInputEnhancedPacketFile.h dabInputEnhancedPacketFile.cpp \
- dabInputFifo.h dabInputFifo.cpp \
- dabInputFile.h dabInputFile.cpp \
- dabInputMpegFifo.h dabInputMpegFifo.cpp \
- dabInputMpegFile.h dabInputMpegFile.cpp \
- dabInputPacketFile.h dabInputPacketFile.cpp \
- dabInputPrbs.h dabInputPrbs.cpp \
- dabInputRawFile.h dabInputRawFile.cpp \
- dabInputRawFifo.h dabInputRawFifo.cpp \
- dabInputUdp.h dabInputUdp.cpp \
- dabInputZmq.h dabInputZmq.cpp \
+ input/inputs.h \
+ input/Prbs.cpp input/Prbs.h \
+ input/Zmq.cpp input/Zmq.h \
+ input/File.cpp input/File.h \
+ input/Udp.cpp input/Udp.h \
dabOutput/dabOutput.h \
dabOutput/dabOutputFile.cpp \
dabOutput/dabOutputFifo.cpp \
diff --git a/src/MuxElements.h b/src/MuxElements.h
index 7056121..7324cdc 100644
--- a/src/MuxElements.h
+++ b/src/MuxElements.h
@@ -40,7 +40,7 @@
#include <boost/optional.hpp>
#include <stdint.h>
#include "dabOutput/dabOutput.h"
-#include "dabInput.h"
+#include "input/inputs.h"
#include "RemoteControl.h"
#include "Eti.h"
@@ -295,7 +295,7 @@ public:
std::string uid;
std::string inputUri;
- DabInputBase* input;
+ std::shared_ptr<Inputs::InputBase> input;
unsigned char id;
subchannel_type_t type;
uint16_t startAddress;
diff --git a/src/UdpSocket.cpp b/src/UdpSocket.cpp
index 020e3f5..ccdd7ed 100644
--- a/src/UdpSocket.cpp
+++ b/src/UdpSocket.cpp
@@ -37,19 +37,19 @@ using namespace std;
UdpSocket::UdpSocket() :
listenSocket(INVALID_SOCKET)
{
- init_sock(0, "");
+ reinit(0, "");
}
UdpSocket::UdpSocket(int port) :
listenSocket(INVALID_SOCKET)
{
- init_sock(port, "");
+ reinit(port, "");
}
UdpSocket::UdpSocket(int port, const std::string& name) :
listenSocket(INVALID_SOCKET)
{
- init_sock(port, name);
+ reinit(port, name);
}
@@ -67,7 +67,7 @@ int UdpSocket::setBlocking(bool block)
return 0;
}
-int UdpSocket::init_sock(int port, const std::string& name)
+int UdpSocket::reinit(int port, const std::string& name)
{
if (listenSocket != INVALID_SOCKET) {
::close(listenSocket);
@@ -98,6 +98,16 @@ int UdpSocket::init_sock(int port, const std::string& name)
return 0;
}
+int UdpSocket::close()
+{
+ if (listenSocket != INVALID_SOCKET) {
+ ::close(listenSocket);
+ }
+
+ listenSocket = INVALID_SOCKET;
+
+ return 0;
+}
UdpSocket::~UdpSocket()
{
diff --git a/src/UdpSocket.h b/src/UdpSocket.h
index 535499e..dfeaac1 100644
--- a/src/UdpSocket.h
+++ b/src/UdpSocket.h
@@ -80,6 +80,15 @@ class UdpSocket
UdpSocket(const UdpSocket& other) = delete;
const UdpSocket& operator=(const UdpSocket& other) = delete;
+ /** reinitialise socket. Close the already open socket, and
+ * create a new one
+ */
+ int reinit(int port, const std::string& name);
+
+ /** Close the socket
+ */
+ int close(void);
+
/** Send an UDP packet.
* @param packet The UDP packet to be sent. It includes the data and the
* destination address
@@ -111,7 +120,6 @@ class UdpSocket
int setBlocking(bool block);
protected:
- int init_sock(int port, const std::string& name);
/// The address on which the socket is bound.
InetAddress address;
diff --git a/src/dabInput.h b/src/dabInput.h
index d5444cd..d2c5f49 100644
--- a/src/dabInput.h
+++ b/src/dabInput.h
@@ -29,8 +29,6 @@
#include "RemoteControl.h"
#include <string>
-extern Logger etiLog;
-
// TODO replace usage of dabInputOperations by a
// class hierarchy
struct dabInputOperations {
@@ -48,19 +46,6 @@ struct dabInputOperations {
bool operator==(const dabInputOperations&);
};
-/* New input object base */
-class DabInputBase {
- public:
- virtual int open(const std::string& name) = 0;
- virtual int readFrame(void* buffer, int size) = 0;
- virtual int setBitrate(int bitrate) = 0;
- virtual int close() = 0;
-
- virtual ~DabInputBase() {}
- protected:
- DabInputBase() {}
-};
-
/* Wrapper class for old-style dabInputOperations inputs */
class DabInputCompatible : public DabInputBase {
public:
@@ -77,7 +62,7 @@ class DabInputCompatible : public DabInputBase {
virtual int setbuf(int size)
{ return m_ops.setbuf(args, size); }
- virtual int readFrame(void* buffer, int size)
+ virtual int readFrame(uint8_t* buffer, size_t size)
{
if (m_ops.lock) {
m_ops.lock(args);
diff --git a/src/dabInputMpegFile.cpp b/src/dabInputMpegFile.cpp
index 804ea29..6f24f32 100644
--- a/src/dabInputMpegFile.cpp
+++ b/src/dabInputMpegFile.cpp
@@ -47,37 +47,6 @@ struct dabInputOperations dabInputMpegFileOperations = {
};
-#define MPEG_FREQUENCY -2
-#define MPEG_PADDING -3
-#define MPEG_COPYRIGHT -4
-#define MPEG_ORIGINAL -5
-#define MPEG_EMPHASIS -6
-int checkDabMpegFrame(void* data) {
- mpegHeader* header = (mpegHeader*)data;
- unsigned long* headerData = (unsigned long*)data;
- if ((*headerData & 0x0f0ffcff) == 0x0004fcff) return 0;
- if ((*headerData & 0x0f0ffcff) == 0x0004f4ff) return 0;
- if (getMpegFrequency(header) != 48000) {
- if (getMpegFrequency(header) != 24000) {
- return MPEG_FREQUENCY;
- }
- }
- if (header->padding != 0) {
- return MPEG_PADDING;
- }
- if (header->copyright != 0) {
- return MPEG_COPYRIGHT;
- }
- if (header->original != 0) {
- return MPEG_ORIGINAL;
- }
- if (header->emphasis != 0) {
- return MPEG_EMPHASIS;
- }
- return -1;
-}
-
-
int dabInputMpegFileRead(dabInputOperations* ops, void* args, void* buffer, int size)
{
dabInputFileData* data = (dabInputFileData*)args;
diff --git a/src/input/File.cpp b/src/input/File.cpp
new file mode 100644
index 0000000..5c61fd4
--- /dev/null
+++ b/src/input/File.cpp
@@ -0,0 +1,443 @@
+/*
+ Copyright (C) 2009 Her Majesty the Queen in Right of Canada (Communications
+ Research Center Canada)
+
+ Copyright (C) 2016 Matthias P. Braendli
+ http://www.opendigitalradio.org
+
+ */
+/*
+ This file is part of ODR-DabMux.
+
+ ODR-DabMux is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ ODR-DabMux is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with ODR-DabMux. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sstream>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#ifndef _WIN32
+# define O_BINARY 0
+#endif
+
+#include "input/File.h"
+#include "mpeg.h"
+#include "ReedSolomon.h"
+
+namespace Inputs {
+
+#ifdef _WIN32
+# pragma pack(push, 1)
+#endif
+struct packetHeader {
+ unsigned char addressHigh:2;
+ unsigned char last:1;
+ unsigned char first:1;
+ unsigned char continuityIndex:2;
+ unsigned char packetLength:2;
+ unsigned char addressLow;
+ unsigned char dataLength:7;
+ unsigned char command;
+}
+#ifdef _WIN32
+# pragma pack(pop)
+#else
+__attribute((packed))
+#endif
+;
+
+
+int FileBase::open(const std::string& name)
+{
+ m_fd = ::open(name.c_str(), O_RDONLY | O_BINARY);
+ if (m_fd == -1) {
+ std::stringstream ss;
+ ss << "Could not open input file " << name << ": " <<
+ strerror(errno);
+ throw std::runtime_error(ss.str());
+ }
+ return 0;
+}
+
+int FileBase::setBitrate(int bitrate)
+{
+ if (bitrate <= 0) {
+ etiLog.log(error, "Invalid bitrate (%i)\n", bitrate);
+ return -1;
+ }
+
+ return bitrate;
+}
+
+
+int FileBase::close()
+{
+ if (m_fd != -1) {
+ ::close(m_fd);
+ m_fd = -1;
+ }
+ return 0;
+}
+
+int FileBase::rewind()
+{
+ return ::lseek(m_fd, 0, SEEK_SET);
+}
+
+ssize_t FileBase::readFromFile(uint8_t* buffer, size_t size)
+{
+ ssize_t ret = read(m_fd, buffer, size);
+
+ if (ret == -1) {
+ etiLog.log(alert, "ERROR: Can't read file\n");
+ perror("");
+ return -1;
+ }
+
+ if (ret < (ssize_t)size) {
+ ssize_t sizeOut = ret;
+ etiLog.log(info, "reach end of file -> rewinding\n");
+ if (rewind() == -1) {
+ etiLog.log(alert, "ERROR: Can't rewind file\n");
+ return -1;
+ }
+
+ ret = read(m_fd, buffer + sizeOut, size - sizeOut);
+ if (ret == -1) {
+ etiLog.log(alert, "ERROR: Can't read file\n");
+ perror("");
+ return -1;
+ }
+
+ if (ret < (ssize_t)size) {
+ etiLog.log(alert, "ERROR: Not enough data in file\n");
+ return -1;
+ }
+ }
+
+ return size;
+}
+
+int MPEGFile::readFrame(uint8_t* buffer, size_t size)
+{
+ int result;
+ bool do_rewind = false;
+READ_SUBCHANNEL:
+ if (m_parity) {
+ result = readData(m_fd, buffer, size, 2);
+ m_parity = false;
+ return 0;
+ } else {
+ result = readMpegHeader(m_fd, buffer, size);
+ if (result > 0) {
+ result = readMpegFrame(m_fd, buffer, size);
+ if (result < 0 && getMpegFrequency(buffer) == 24000) {
+ m_parity = true;
+ result = size;
+ }
+ }
+ }
+ switch (result) {
+ case MPEG_BUFFER_UNDERFLOW:
+ etiLog.log(warn, "data underflow -> frame muted\n");
+ goto MUTE_SUBCHANNEL;
+ case MPEG_BUFFER_OVERFLOW:
+ etiLog.log(warn, "bitrate too high -> frame muted\n");
+ goto MUTE_SUBCHANNEL;
+ case MPEG_FILE_EMPTY:
+ if (do_rewind) {
+ etiLog.log(error, "file rewinded and still empty "
+ "-> frame muted\n");
+ goto MUTE_SUBCHANNEL;
+ }
+ else {
+ etiLog.log(info, "reach end of file -> rewinding\n");
+ rewind();
+ goto READ_SUBCHANNEL;
+ }
+ case MPEG_FILE_ERROR:
+ etiLog.log(alert, "can't read file (%i) -> frame muted\n", errno);
+ perror("");
+ goto MUTE_SUBCHANNEL;
+ case MPEG_SYNC_NOT_FOUND:
+ etiLog.log(alert, "mpeg sync not found, maybe is not a valid file "
+ "-> frame muted\n");
+ goto MUTE_SUBCHANNEL;
+ case MPEG_INVALID_FRAME:
+ etiLog.log(alert, "file is not a valid mpeg file "
+ "-> frame muted\n");
+ goto MUTE_SUBCHANNEL;
+ default:
+ if (result < 0) {
+ etiLog.log(alert,
+ "unknown error (code = %i) -> frame muted\n",
+ result);
+MUTE_SUBCHANNEL:
+ memset(buffer, 0, size);
+ }
+ else {
+ if (result < (ssize_t)size) {
+ etiLog.log(warn, "bitrate too low from file "
+ "-> frame padded\n");
+ memset((char*)buffer + result, 0, size - result);
+ }
+
+ result = checkDabMpegFrame(buffer);
+ switch (result) {
+ case MPEG_FREQUENCY:
+ etiLog.log(error, "file has a frame with an invalid "
+ "frequency: %i, should be 48000 or 24000\n",
+ getMpegFrequency(buffer));
+ break;
+ case MPEG_PADDING:
+ etiLog.log(warn,
+ "file has a frame with padding bit set\n");
+ break;
+ case MPEG_COPYRIGHT:
+ result = 0;
+ break;
+ case MPEG_ORIGINAL:
+ result = 0;
+ break;
+ case MPEG_EMPHASIS:
+ etiLog.log(warn,
+ "file has a frame with emphasis bits set\n");
+ break;
+ default:
+ if (result < 0) {
+ etiLog.log(alert, "mpeg file has an invalid DAB "
+ "mpeg frame (unknown reason: %i)\n", result);
+ }
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+int MPEGFile::setBitrate(int bitrate)
+{
+ if (bitrate == 0) {
+ uint8_t buffer[4];
+
+ if (readFrame(buffer, 4) == 0) {
+ bitrate = getMpegBitrate(buffer);
+ }
+ else {
+ bitrate = -1;
+ }
+ rewind();
+ }
+ return bitrate;
+}
+
+int RawFile::readFrame(uint8_t* buffer, size_t size)
+{
+ return readFromFile(buffer, size);
+}
+
+PacketFile::PacketFile(bool enhancedPacketMode)
+{
+ m_enhancedPacketEnabled = enhancedPacketMode;
+}
+
+int PacketFile::readFrame(uint8_t* buffer, size_t size)
+{
+ size_t written = 0;
+ int length;
+ packetHeader* header;
+ int indexRow;
+ int indexCol;
+
+ while (written < size) {
+ if (m_enhancedPacketWaiting > 0) {
+ *buffer = 192 - m_enhancedPacketWaiting;
+ *buffer /= 22;
+ *buffer <<= 2;
+ *(buffer++) |= 0x03;
+ *(buffer++) = 0xfe;
+ indexCol = 188;
+ indexCol += (192 - m_enhancedPacketWaiting) / 12;
+ indexRow = 0;
+ indexRow += (192 - m_enhancedPacketWaiting) % 12;
+ for (int j = 0; j < 22; ++j) {
+ if (m_enhancedPacketWaiting == 0) {
+ *(buffer++) = 0;
+ }
+ else {
+ *(buffer++) = m_enhancedPacketData[indexRow][indexCol];
+ if (++indexRow == 12) {
+ indexRow = 0;
+ ++indexCol;
+ }
+ --m_enhancedPacketWaiting;
+ }
+ }
+ written += 24;
+ if (m_enhancedPacketWaiting == 0) {
+ m_enhancedPacketLength = 0;
+ }
+ }
+ else if (m_packetLength != 0) {
+ header = (packetHeader*)(&m_packetData[0]);
+ if (written + m_packetLength > (unsigned)size) {
+ memset(buffer, 0, 22);
+ buffer[22] = 0x60;
+ buffer[23] = 0x4b;
+ length = 24;
+ }
+ else if (m_enhancedPacketEnabled) {
+ if (m_enhancedPacketLength + m_packetLength > (12 * 188)) {
+ memset(buffer, 0, 22);
+ buffer[22] = 0x60;
+ buffer[23] = 0x4b;
+ length = 24;
+ }
+ else {
+ std::copy(m_packetData.begin(),
+ m_packetData.begin() + m_packetLength,
+ buffer);
+ length = m_packetLength;
+ m_packetLength = 0;
+ }
+ }
+ else {
+ std::copy(m_packetData.begin(),
+ m_packetData.begin() + m_packetLength,
+ buffer);
+ length = m_packetLength;
+ m_packetLength = 0;
+ }
+
+ if (m_enhancedPacketEnabled) {
+ indexCol = m_enhancedPacketLength / 12;
+ indexRow = m_enhancedPacketLength % 12; // TODO Check if always 0
+ for (int j = 0; j < length; ++j) {
+ m_enhancedPacketData[indexRow][indexCol] = buffer[j];
+ if (++indexRow == 12) {
+ indexRow = 0;
+ ++indexCol;
+ }
+ }
+ m_enhancedPacketLength += length;
+ if (m_enhancedPacketLength >= (12 * 188)) {
+ m_enhancedPacketLength = (12 * 188);
+ ReedSolomon encoder(204, 188);
+ for (int j = 0; j < 12; ++j) {
+ encoder.encode(&m_enhancedPacketData[j][0], 188);
+ }
+ m_enhancedPacketWaiting = 192;
+ }
+ }
+ written += length;
+ buffer += length;
+ }
+ else {
+ int nbBytes = readFromFile(buffer, 3);
+ header = (packetHeader*)buffer;
+ if (nbBytes == -1) {
+ if (errno == EAGAIN) goto END_PACKET;
+ perror("Packet file");
+ return -1;
+ }
+ else if (nbBytes == 0) {
+ if (rewind() == -1) {
+ goto END_PACKET;
+ }
+ continue;
+ }
+ else if (nbBytes < 3) {
+ etiLog.log(error,
+ "Error while reading file for packet header; "
+ "read %i out of 3 bytes\n", nbBytes);
+ break;
+ }
+
+ length = header->packetLength * 24 + 24;
+ if (written + length > size) {
+ memcpy(&m_packetData[0], header, 3);
+ readFromFile(&m_packetData[3], length - 3);
+ m_packetLength = length;
+ continue;
+ }
+
+ if (m_enhancedPacketEnabled) {
+ if (m_enhancedPacketLength + length > (12 * 188)) {
+ memcpy(&m_packetData[0], header, 3);
+ readFromFile(&m_packetData[3], length - 3);
+ m_packetLength = length;
+ continue;
+ }
+ }
+
+ nbBytes = readFromFile(buffer + 3, length - 3);
+ if (nbBytes == -1) {
+ perror("Packet file");
+ return -1;
+ }
+ else if (nbBytes == 0) {
+ etiLog.log(info,
+ "Packet header read, but no data!\n");
+ if (rewind() == -1) {
+ goto END_PACKET;
+ }
+ continue;
+ }
+ else if (nbBytes < length - 3) {
+ etiLog.log(error, "Error while reading packet file; "
+ "read %i out of %i bytes\n", nbBytes, length - 3);
+ break;
+ }
+
+ if (m_enhancedPacketEnabled) {
+ indexCol = m_enhancedPacketLength / 12;
+ indexRow = m_enhancedPacketLength % 12; // TODO Check if always 0
+ for (int j = 0; j < length; ++j) {
+ m_enhancedPacketData[indexRow][indexCol] = buffer[j];
+ if (++indexRow == 12) {
+ indexRow = 0;
+ ++indexCol;
+ }
+ }
+ m_enhancedPacketLength += length;
+ if (m_enhancedPacketLength >= (12 * 188)) {
+ if (m_enhancedPacketLength > (12 * 188)) {
+ etiLog.log(error,
+ "Error, too much enhanced packet data!\n");
+ }
+ ReedSolomon encoder(204, 188);
+ for (int j = 0; j < 12; ++j) {
+ encoder.encode(&m_enhancedPacketData[j][0], 188);
+ }
+ m_enhancedPacketWaiting = 192;
+ }
+ }
+ written += length;
+ buffer += length;
+ }
+ }
+END_PACKET:
+ while (written < size) {
+ memset(buffer, 0, 22);
+ buffer[22] = 0x60;
+ buffer[23] = 0x4b;
+ buffer += 24;
+ written += 24;
+ }
+ return written;
+}
+
+};
diff --git a/src/input/File.h b/src/input/File.h
new file mode 100644
index 0000000..080d6b5
--- /dev/null
+++ b/src/input/File.h
@@ -0,0 +1,91 @@
+/*
+ Copyright (C) 2009 Her Majesty the Queen in Right of Canada (Communications
+ Research Center Canada)
+
+ Copyright (C) 2016 Matthias P. Braendli
+ http://www.opendigitalradio.org
+
+ */
+/*
+ This file is part of ODR-DabMux.
+
+ ODR-DabMux is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ ODR-DabMux is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with ODR-DabMux. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <vector>
+#include <array>
+#include <string>
+#include <stdint.h>
+#include "input/inputs.h"
+#include "ManagementServer.h"
+
+namespace Inputs {
+
+class FileBase : public InputBase {
+ public:
+ virtual int open(const std::string& name);
+ virtual int readFrame(uint8_t* buffer, size_t size) = 0;
+ virtual int setBitrate(int bitrate);
+ virtual int close();
+
+ /* Rewind the file
+ * Returns -1 on failure, 0 on success
+ */
+ virtual int rewind();
+ protected:
+ /* Read len bytes from the file into buf, and return
+ * the number of bytes read, or -1 in case of error.
+ */
+ virtual ssize_t readFromFile(uint8_t* buf, size_t len);
+
+ // We use unix open() instead of fopen() because
+ // we might want to do non-blocking I/O in the future
+ int m_fd = -1;
+};
+
+class MPEGFile : public FileBase {
+ public:
+ virtual int readFrame(uint8_t* buffer, size_t size);
+ virtual int setBitrate(int bitrate);
+
+ private:
+ bool m_parity = false;
+};
+
+class RawFile : public FileBase {
+ public:
+ virtual int readFrame(uint8_t* buffer, size_t size);
+};
+
+class PacketFile : public FileBase {
+ public:
+ PacketFile(bool enhancedPacketMode);
+ virtual int readFrame(uint8_t* buffer, size_t size);
+
+ protected:
+ std::array<uint8_t,96> m_packetData;
+ size_t m_packetLength;
+
+ /* Enhanced packet mode enables FEC for MSC packet mode
+ * as described in EN 300 401 Clause 5.3.5
+ */
+ bool m_enhancedPacketEnabled = false;
+ std::array<std::array<uint8_t, 204>,12> m_enhancedPacketData;
+ size_t m_enhancedPacketWaiting;
+ size_t m_enhancedPacketLength;
+};
+
+};
diff --git a/src/dabInputPrbs.cpp b/src/input/Prbs.cpp
index 2678668..7856a46 100644
--- a/src/dabInputPrbs.cpp
+++ b/src/input/Prbs.cpp
@@ -26,7 +26,7 @@
along with ODR-DabMux. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "dabInputPrbs.h"
+#include "input/Prbs.h"
#include <stdexcept>
#include <sstream>
@@ -38,23 +38,31 @@
using namespace std;
+namespace Inputs {
+
// ETS 300 799 Clause G.2.1
// Preferred polynomial is G(x) = x^20 + x^17 + 1
-const uint32_t PRBS_DEFAULT_POLY = (1 << 19) | (1 << 16) | 1;
+const uint32_t PRBS_DEFAULT_POLY = (1 << 20) | (1 << 17) | (1 << 0);
-int DabInputPrbs::open(const string& name)
+int Prbs::open(const string& name)
{
- if (name.empty()) {
+ if (name.substr(0, 7) != "prbs://") {
+ throw logic_error("Invalid PRBS name");
+ }
+
+ const string& url_polynomial = name.substr(7);
+
+ if (url_polynomial.empty()) {
m_prbs.setup(PRBS_DEFAULT_POLY);
}
else {
- if (name[0] != ':') {
+ if (url_polynomial[0] != ':') {
throw invalid_argument(
"Invalid PRBS address format. "
"Must be prbs://:polynomial.");
}
- const string poly_str = name.substr(1);
+ const string poly_str = url_polynomial.substr(1);
long polynomial = hexparse(poly_str);
@@ -69,30 +77,29 @@ int DabInputPrbs::open(const string& name)
return 0;
}
-int DabInputPrbs::readFrame(void* buffer, int size)
+int Prbs::readFrame(uint8_t* buffer, size_t size)
{
- unsigned char* cbuffer = reinterpret_cast<unsigned char*>(buffer);
-
- for (int i = 0; i < size; ++i) {
- cbuffer[i] = m_prbs.step();
+ for (size_t i = 0; i < size; ++i) {
+ buffer[i] = m_prbs.step();
}
return size;
}
-int DabInputPrbs::setBitrate(int bitrate)
+int Prbs::setBitrate(int bitrate)
{
return bitrate;
}
-int DabInputPrbs::close()
+int Prbs::close()
{
return 0;
}
-int DabInputPrbs::rewind()
+int Prbs::rewind()
{
m_prbs.rewind();
return 0;
}
+};
diff --git a/src/dabInputPrbs.h b/src/input/Prbs.h
index 95c5e25..3b2b7d4 100644
--- a/src/dabInputPrbs.h
+++ b/src/input/Prbs.h
@@ -28,19 +28,17 @@
#pragma once
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
#include <string>
-#include "dabInput.h"
+#include "input/inputs.h"
#include "prbs.h"
-class DabInputPrbs : public DabInputBase {
+namespace Inputs {
+
+class Prbs : public InputBase {
public:
virtual int open(const std::string& name);
- virtual int readFrame(void* buffer, int size);
+ virtual int readFrame(uint8_t* buffer, size_t size);
virtual int setBitrate(int bitrate);
virtual int close();
@@ -50,3 +48,5 @@ class DabInputPrbs : public DabInputBase {
PrbsGenerator m_prbs;
};
+};
+
diff --git a/src/input/Udp.cpp b/src/input/Udp.cpp
new file mode 100644
index 0000000..a238d9b
--- /dev/null
+++ b/src/input/Udp.cpp
@@ -0,0 +1,134 @@
+/*
+ Copyright (C) 2009 Her Majesty the Queen in Right of Canada (Communications
+ Research Center Canada)
+
+ Copyright (C) 2016
+ Matthias P. Braendli, matthias.braendli@mpb.li
+
+ http://www.opendigitalradio.org
+ */
+/*
+ This file is part of ODR-DabMux.
+
+ ODR-DabMux is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ ODR-DabMux is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with ODR-DabMux. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "input/Udp.h"
+
+#include <stdexcept>
+#include <sstream>
+#include <string.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "utils.h"
+
+using namespace std;
+
+namespace Inputs {
+
+int Udp::open(const std::string& name)
+{
+ // Skip the udp:// part if it is present
+ const string endpoint = (name.substr(0, 6) == "udp://") ?
+ name.substr(6) : name;
+
+ // The endpoint should be address:port
+ const auto colon_pos = endpoint.find_first_of(":");
+ if (colon_pos == string::npos) {
+ stringstream ss;
+ ss << "'" << name <<
+ " is an invalid format for udp address: "
+ "expected [udp://]address:port";
+ throw invalid_argument(ss.str());
+ }
+
+ const auto address = endpoint.substr(0, colon_pos);
+ const auto port_str = endpoint.substr(colon_pos + 1);
+
+ const long port = strtol(port_str.c_str(), nullptr, 10);
+
+ if ((port == LONG_MIN or port == LONG_MAX) and errno == ERANGE) {
+ throw out_of_range("udp input: port out of range");
+ }
+ else if (port == 0 and errno != 0) {
+ stringstream ss;
+ ss << "udp input port parse error: " << strerror(errno);
+ throw invalid_argument(ss.str());
+ }
+
+ if (port == 0) {
+ throw out_of_range("can't use port number 0 in udp address");
+ }
+
+ if (m_sock.reinit(port, address) == -1) {
+ stringstream ss;
+ ss << "Could not init UDP socket: " << inetErrMsg;
+ throw runtime_error(ss.str());
+ }
+
+ if (m_sock.setBlocking(false) == -1) {
+ stringstream ss;
+ ss << "Could not set non-blocking UDP socket: " << inetErrMsg;
+ throw runtime_error(ss.str());
+ }
+
+ return 0;
+}
+
+int Udp::readFrame(uint8_t* buffer, size_t size)
+{
+ uint8_t* data = reinterpret_cast<uint8_t*>(buffer);
+
+ // Regardless of buffer contents, try receiving data.
+ UdpPacket packet;
+ int ret = m_sock.receive(packet);
+
+ if (ret == -1) {
+ stringstream ss;
+ ss << "Could not read from UDP socket: " << inetErrMsg;
+ throw runtime_error(ss.str());
+ }
+
+ std::copy(packet.getData(), packet.getData() + packet.getSize(),
+ back_inserter(m_buffer));
+
+ // Take data from the buffer if it contains enough data,
+ // in any case write the buffer
+ if (m_buffer.size() >= (size_t)size) {
+ std::copy(m_buffer.begin(), m_buffer.begin() + size, data);
+ }
+ else {
+ memset(data, 0x0, size);
+ }
+
+ return size;
+}
+
+int Udp::setBitrate(int bitrate)
+{
+ if (bitrate <= 0) {
+ etiLog.log(error, "Invalid bitrate (%i)\n", bitrate);
+ return -1;
+ }
+
+ return bitrate;
+}
+
+int Udp::close()
+{
+ return m_sock.close();
+}
+
+};
diff --git a/src/input/Udp.h b/src/input/Udp.h
new file mode 100644
index 0000000..379dbf3
--- /dev/null
+++ b/src/input/Udp.h
@@ -0,0 +1,52 @@
+/*
+ Copyright (C) 2009 Her Majesty the Queen in Right of Canada (Communications
+ Research Center Canada)
+
+ Copyright (C) 2016
+ Matthias P. Braendli, matthias.braendli@mpb.li
+
+ http://www.opendigitalradio.org
+ */
+/*
+ This file is part of ODR-DabMux.
+
+ ODR-DabMux is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ ODR-DabMux is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with ODR-DabMux. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+#include "input/inputs.h"
+#include "UdpSocket.h"
+
+namespace Inputs {
+
+class Udp : public InputBase {
+ public:
+ virtual int open(const std::string& name);
+ virtual int readFrame(uint8_t* buffer, size_t size);
+ virtual int setBitrate(int bitrate);
+ virtual int close();
+
+ private:
+ UdpSocket m_sock;
+
+ // The content of the UDP packets gets written into the
+ // buffer, and the UDP packet boundaries disappear there.
+ std::vector<uint8_t> m_buffer;
+};
+
+};
+
diff --git a/src/dabInputZmq.cpp b/src/input/Zmq.cpp
index 93f1ea3..a5601fa 100644
--- a/src/dabInputZmq.cpp
+++ b/src/input/Zmq.cpp
@@ -2,7 +2,7 @@
Copyright (C) 2009 Her Majesty the Queen in Right of Canada (Communications
Research Center Canada)
- Copyright (C) 2013, 2014 Matthias P. Braendli
+ Copyright (C) 2016 Matthias P. Braendli
http://www.opendigitalradio.org
ZeroMQ input. see www.zeromq.org for more info
@@ -39,17 +39,8 @@
along with ODR-DabMux. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "dabInput.h"
-#include "dabInputZmq.h"
-#include "PcDebug.h"
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
+#include "input/Zmq.h"
-#ifdef HAVE_INPUT_ZEROMQ
-
-#include "zmq.hpp"
#include <cstdio>
#include <cstdlib>
#include <list>
@@ -58,22 +49,28 @@
#include <string>
#include <sstream>
#include <limits.h>
+#include "PcDebug.h"
+#include "Log.h"
#ifdef __MINGW32__
# define bzero(s, n) memset(s, 0, n)
#endif
+namespace Inputs {
+
using namespace std;
int readkey(string& keyfile, char* key)
{
- int fd = open(keyfile.c_str(), O_RDONLY);
- if (fd < 0)
- return fd;
- int ret = read(fd, key, CURVE_KEYLEN);
- close(fd);
- if (ret < 0) {
- return ret;
+ FILE* fd = fopen(keyfile.c_str(), "r");
+ if (fd == nullptr) {
+ return -1;
+ }
+
+ int ret = fread(key, CURVE_KEYLEN, 1, fd);
+ fclose(fd);
+ if (ret == 0) {
+ return -1;
}
/* It needs to be zero-terminated */
@@ -89,7 +86,7 @@ int readkey(string& keyfile, char* key)
* keys to the socket, and finally bind the socket
* to the new address
*/
-void DabInputZmqBase::rebind()
+void ZmqBase::rebind()
{
if (! m_zmq_sock_bound_to.empty()) {
try {
@@ -223,7 +220,7 @@ void DabInputZmqBase::rebind()
}
}
-int DabInputZmqBase::open(const std::string& inputUri)
+int ZmqBase::open(const std::string& inputUri)
{
m_inputUri = inputUri;
@@ -236,20 +233,20 @@ int DabInputZmqBase::open(const std::string& inputUri)
return 0;
}
-int DabInputZmqBase::close()
+int ZmqBase::close()
{
m_zmq_sock.close();
return 0;
}
-int DabInputZmqBase::setBitrate(int bitrate)
+int ZmqBase::setBitrate(int bitrate)
{
m_bitrate = bitrate;
return bitrate; // TODO do a nice check here
}
// size corresponds to a frame size. It is constant for a given bitrate
-int DabInputZmqBase::readFrame(void* buffer, int size)
+int ZmqBase::readFrame(uint8_t* buffer, size_t size)
{
int rc;
@@ -340,7 +337,7 @@ int DabInputZmqBase::readFrame(void* buffer, int size)
/******** MPEG input *******/
// Read a MPEG frame from the socket, and push to list
-int DabInputZmqMPEG::readFromSocket(size_t framesize)
+int ZmqMPEG::readFromSocket(size_t framesize)
{
bool messageReceived = false;
zmq::message_t msg;
@@ -410,7 +407,7 @@ int DabInputZmqMPEG::readFromSocket(size_t framesize)
// Read a AAC+ superframe from the socket, cut it into five frames,
// and push to list
-int DabInputZmqAAC::readFromSocket(size_t framesize)
+int ZmqAAC::readFromSocket(size_t framesize)
{
bool messageReceived;
zmq::message_t msg;
@@ -496,7 +493,7 @@ int DabInputZmqAAC::readFromSocket(size_t framesize)
/********* REMOTE CONTROL ***********/
-void DabInputZmqBase::set_parameter(const string& parameter,
+void ZmqBase::set_parameter(const string& parameter,
const string& value)
{
if (parameter == "buffer") {
@@ -576,7 +573,7 @@ void DabInputZmqBase::set_parameter(const string& parameter,
}
}
-const string DabInputZmqBase::get_parameter(const string& parameter) const
+const string ZmqBase::get_parameter(const string& parameter) const
{
stringstream ss;
if (parameter == "buffer") {
@@ -615,5 +612,5 @@ const string DabInputZmqBase::get_parameter(const string& parameter) const
}
-#endif
+};
diff --git a/src/dabInputZmq.h b/src/input/Zmq.h
index 351fb07..8d729e0 100644
--- a/src/dabInputZmq.h
+++ b/src/input/Zmq.h
@@ -2,7 +2,7 @@
Copyright (C) 2009 Her Majesty the Queen in Right of Canada (Communications
Research Center Canada)
- Copyright (C) 2013, 2014 Matthias P. Braendli
+ Copyright (C) 2016 Matthias P. Braendli
http://www.opendigitalradio.org
ZeroMQ input. see www.zeromq.org for more info
@@ -41,48 +41,37 @@
along with ODR-DabMux. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef DAB_INPUT_ZMQ_H
-#define DAB_INPUT_ZMQ_H
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#ifdef HAVE_INPUT_ZEROMQ
+#pragma once
#include <list>
#include <string>
#include <stdint.h>
#include "zmq.hpp"
-#include "dabInput.h"
+#include "input/inputs.h"
#include "ManagementServer.h"
+namespace Inputs {
+
/* The frame_buffer contains DAB logical frames as defined in
* TS 102 563, section 6.
* Five elements of this buffer make one AAC superframe (120ms audio)
*/
-// Number of elements to prebuffer before starting the pipeline
-#define INPUT_ZMQ_DEF_PREBUFFERING (5*4) // 480ms
-
-// Default frame_buffer size in number of elements
-#define INPUT_ZMQ_DEF_BUFFER_SIZE (5*8) // 960ms
-
// Minimum frame_buffer size in number of elements
// This is one AAC superframe, but you probably don't want to
// go that low anyway.
-#define INPUT_ZMQ_MIN_BUFFER_SIZE (5*1) // 120ms
+const size_t INPUT_ZMQ_MIN_BUFFER_SIZE = 5*1; // 120ms
// Maximum frame_buffer size in number of elements
// One minute is clearly way over what everybody would
// want.
-#define INPUT_ZMQ_MAX_BUFFER_SIZE (5*500) // 60s
+const size_t INPUT_ZMQ_MAX_BUFFER_SIZE = 5*500; // 60s
/* The ZeroMQ Curve key is 40 bytes long in Z85 representation
*
* But we need to store it as zero-terminated string.
*/
-#define CURVE_KEYLEN 40
+const size_t CURVE_KEYLEN = 40;
/* helper to invalidate a key */
#define INVALIDATE_KEY(k) memset(k, 0, CURVE_KEYLEN+1)
@@ -156,9 +145,9 @@ struct zmq_frame_header_t
#define ZMQ_FRAME_DATA(f) ( ((uint8_t*)f)+sizeof(zmq_frame_header_t) )
-class DabInputZmqBase : public DabInputBase, public RemoteControllable {
+class ZmqBase : public InputBase, public RemoteControllable {
public:
- DabInputZmqBase(const std::string name,
+ ZmqBase(const std::string name,
dab_input_zmq_config_t config)
: RemoteControllable(name),
m_zmq_context(1),
@@ -192,7 +181,7 @@ class DabInputZmqBase : public DabInputBase, public RemoteControllable {
}
virtual int open(const std::string& inputUri);
- virtual int readFrame(void* buffer, int size);
+ virtual int readFrame(uint8_t* buffer, size_t size);
virtual int setBitrate(int bitrate);
virtual int close();
@@ -238,11 +227,11 @@ class DabInputZmqBase : public DabInputBase, public RemoteControllable {
size_t m_prebuf_current;
};
-class DabInputZmqMPEG : public DabInputZmqBase {
+class ZmqMPEG : public ZmqBase {
public:
- DabInputZmqMPEG(const std::string name,
+ ZmqMPEG(const std::string name,
dab_input_zmq_config_t config)
- : DabInputZmqBase(name, config) {
+ : ZmqBase(name, config) {
RC_ADD_PARAMETER(buffer,
"Size of the input buffer [mpeg frames]");
@@ -254,11 +243,11 @@ class DabInputZmqMPEG : public DabInputZmqBase {
virtual int readFromSocket(size_t framesize);
};
-class DabInputZmqAAC : public DabInputZmqBase {
+class ZmqAAC : public ZmqBase {
public:
- DabInputZmqAAC(const std::string name,
+ ZmqAAC(const std::string name,
dab_input_zmq_config_t config)
- : DabInputZmqBase(name, config) {
+ : ZmqBase(name, config) {
RC_ADD_PARAMETER(buffer,
"Size of the input buffer [aac superframes]");
@@ -270,7 +259,6 @@ class DabInputZmqAAC : public DabInputZmqBase {
virtual int readFromSocket(size_t framesize);
};
-#endif // HAVE_INPUT_ZMQ
+};
-#endif // DAB_INPUT_ZMQ_H
diff --git a/src/input/inputs.h b/src/input/inputs.h
new file mode 100644
index 0000000..bfb1fb6
--- /dev/null
+++ b/src/input/inputs.h
@@ -0,0 +1,52 @@
+/*
+ Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Her Majesty the Queen in
+ Right of Canada (Communications Research Center Canada)
+
+ Copyright (C) 2016
+ Matthias P. Braendli, matthias.braendli@mpb.li
+
+ http://www.opendigitalradio.org
+ */
+/*
+ This file is part of ODR-DabMux.
+
+ ODR-DabMux is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ ODR-DabMux is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with ODR-DabMux. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include "Log.h"
+#include "RemoteControl.h"
+#include <string>
+
+namespace Inputs {
+
+/* New input object base */
+class InputBase {
+ public:
+ virtual int open(const std::string& name) = 0;
+ virtual int readFrame(uint8_t* buffer, size_t size) = 0;
+ virtual int setBitrate(int bitrate) = 0;
+ virtual int close() = 0;
+
+ virtual ~InputBase() {}
+ protected:
+ InputBase() {}
+};
+
+};
+
diff --git a/src/mpeg.c b/src/mpeg.c
index f7aed34..a48f5bb 100644
--- a/src/mpeg.c
+++ b/src/mpeg.c
@@ -219,3 +219,29 @@ int readMpegFrame(int file, void* data, int size)
}
return framelength;
}
+
+int checkDabMpegFrame(void* data) {
+ mpegHeader* header = (mpegHeader*)data;
+ unsigned long* headerData = (unsigned long*)data;
+ if ((*headerData & 0x0f0ffcff) == 0x0004fcff) return 0;
+ if ((*headerData & 0x0f0ffcff) == 0x0004f4ff) return 0;
+ if (getMpegFrequency(header) != 48000) {
+ if (getMpegFrequency(header) != 24000) {
+ return MPEG_FREQUENCY;
+ }
+ }
+ if (header->padding != 0) {
+ return MPEG_PADDING;
+ }
+ if (header->emphasis != 0) {
+ return MPEG_EMPHASIS;
+ }
+ if (header->copyright != 0) {
+ return MPEG_COPYRIGHT;
+ }
+ if (header->original != 0) {
+ return MPEG_ORIGINAL;
+ }
+ return -1;
+}
+
diff --git a/src/mpeg.h b/src/mpeg.h
index aa7cfb6..15b9b80 100644
--- a/src/mpeg.h
+++ b/src/mpeg.h
@@ -75,6 +75,13 @@ ssize_t readData(int file, void* data, size_t size, unsigned int tries);
int readMpegHeader(int file, void* data, int size);
int readMpegFrame(int file, void* data, int size);
+#define MPEG_FREQUENCY -2
+#define MPEG_PADDING -3
+#define MPEG_COPYRIGHT -4
+#define MPEG_ORIGINAL -5
+#define MPEG_EMPHASIS -6
+int checkDabMpegFrame(void* data);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/utils.cpp b/src/utils.cpp
index e26389d..cf57170 100644
--- a/src/utils.cpp
+++ b/src/utils.cpp
@@ -103,36 +103,16 @@ void header_message()
std::cerr << "Input URLs supported:" << std::endl <<
" prbs" <<
-#if defined(HAVE_INPUT_UDP)
" udp" <<
-#endif
-#if defined(HAVE_INPUT_FIFO)
- " fifo" <<
-#endif
-#if defined(HAVE_INPUT_FILE)
" file" <<
-#endif
-#if defined(HAVE_INPUT_ZEROMQ)
" zmq" <<
-#endif
std::endl;
std::cerr << "Inputs format supported:" << std::endl <<
-#if defined(HAVE_FORMAT_RAW)
" raw" <<
-#endif
-#if defined(HAVE_FORMAT_MPEG)
" mpeg" <<
-#endif
-#if defined(HAVE_FORMAT_PACKET)
" packet" <<
-#endif
-#if defined(HAVE_FORMAT_DMB)
- " dmb" <<
-#endif
-#if defined(HAVE_FORMAT_EPM)
" epm" <<
-#endif
std::endl;
std::cerr << "Output URLs supported:" << std::endl <<