From e36865985abf9c4f31d34a9542c790f5baf8fe60 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Wed, 8 Jul 2020 09:17:09 +0200 Subject: Replace PAD fifo by UNIX socket --- Makefile.am | 2 + src/odr-padenc.cpp | 242 +++++++++++++++++--------------------------------- src/odr-padenc.h | 102 +++++---------------- src/pad_common.cpp | 43 +++------ src/pad_common.h | 2 +- src/pad_interface.cpp | 144 ++++++++++++++++++++++++++++++ src/pad_interface.h | 53 +++++++++++ 7 files changed, 319 insertions(+), 269 deletions(-) create mode 100644 src/pad_interface.cpp create mode 100644 src/pad_interface.h diff --git a/Makefile.am b/Makefile.am index e61b436..8b31205 100644 --- a/Makefile.am +++ b/Makefile.am @@ -13,6 +13,8 @@ odr_padenc_LDFLAGS = -pie -z now odr_padenc_SOURCES = \ src/odr-padenc.cpp \ src/odr-padenc.h \ + src/pad_interface.cpp \ + src/pad_interface.h \ src/common.cpp \ src/common.h \ src/pad_common.cpp \ diff --git a/src/odr-padenc.cpp b/src/odr-padenc.cpp index 0a7629a..41a1ea1 100644 --- a/src/odr-padenc.cpp +++ b/src/odr-padenc.cpp @@ -1,7 +1,7 @@ /* Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://rd.csp.it/) - Copyright (C) 2014, 2015 Matthias P. Braendli (http://opendigitalradio.org) + Copyright (C) 2014-2020 Matthias P. Braendli (http://opendigitalradio.org) Copyright (C) 2015-2019 Stefan Pöschel (http://opendigitalradio.org) @@ -28,14 +28,13 @@ */ #include "odr-padenc.h" +#include - -static PadEncoder *pad_encoder = NULL; +std::atomic do_exit; static void break_handler(int) { fprintf(stderr, "...ODR-PadEnc exits...\n"); - if(pad_encoder) - pad_encoder->DoExit(); + do_exit.store(true); } static void header() { @@ -61,13 +60,9 @@ static void usage(const char* name) { " been encoded.\n" " -s, --sleep=DUR Wait DUR seconds between each slide\n" " Default: %d\n" - " -o, --output=FILENAME FIFO to write PAD data into.\n" - " Default: %s\n" + " -o, --output=IDENTIFIER Socket to communicate with audio encoder\n" " -t, --dls=FILENAME FIFO or file to read DLS text from.\n" - " If specified more than once, use next file after slide switch (for uniform PAD encoder, -l is used instead).\n" - " -p, --pad=LENGTH Set the PAD length in bytes.\n" - " Possible values: %s\n" - " Default: %zu\n" + " If specified more than once, use next file after -l delay.\n" " -c, --charset=ID ID of the character set encoding used for DLS text input.\n" " ID = 0: Complete EBU Latin based repertoire\n" " ID = 6: ISO/IEC 10646 using UCS-2 BE\n" @@ -85,24 +80,21 @@ static void usage(const char* name) { " -v, --verbose Print more information to the console (may be used more than once)\n" "\n" "Parameters for uniform PAD encoder only:\n" - " -f, --frame-dur=DUR Enable the uniform PAD encoder and set the duration of one frame/AU in milliseconds.\n" " -l, --label=DUR Wait DUR seconds between each label (if more than one file used)\n" " Default: %d\n" " -L, --label-ins=DUR Insert label every DUR milliseconds\n" " Default: %d\n" - " -i, --init-burst=COUNT Sets a PAD burst amount to initially fill the output FIFO\n" - " Default: %d\n" " -X, --xpad-interval=COUNT Output X-PAD every COUNT frames/AUs (otherwise: only F-PAD)\n" - " Default: %d\n", + " Default: %d\n" + "\n" + "The PAD length is configured on the audio encoder and communicated over the socket to ODR-PadEnc\n" + "Allowed PAD lengths are: %s\n", options_default.slide_interval, - options_default.output, - PADPacketizer::ALLOWED_PADLEN.c_str(), - options_default.padlen, options_default.max_slide_size, options_default.label_interval, options_default.label_insertion, - options_default.init_burst, - options_default.xpad_interval + options_default.xpad_interval, + PADPacketizer::ALLOWED_PADLEN.c_str() ); } @@ -133,22 +125,19 @@ int main(int argc, char *argv[]) { {"output", required_argument, 0, 'o'}, {"dls", required_argument, 0, 't'}, {"item-state", required_argument, 0, 'I'}, - {"pad", required_argument, 0, 'p'}, {"sleep", required_argument, 0, 's'}, {"max-slide-size", required_argument, 0, 'm'}, {"raw-slides", no_argument, 0, 'R'}, {"help", no_argument, 0, 'h'}, - {"frame-dur", required_argument, 0, 'f'}, {"label", required_argument, 0, 'l'}, {"label-ins", required_argument, 0, 'L'}, - {"init-burst", required_argument, 0, 'i'}, {"xpad-interval", required_argument, 0, 'X'}, {"verbose", no_argument, 0, 'v'}, {0,0,0,0}, }; int ch; - while((ch = getopt_long(argc, argv, "eChRrc:d:o:p:s:t:I:f:l:L:i:X:vm:", longopts, NULL)) != -1) { + while((ch = getopt_long(argc, argv, "eChRrc:d:o:s:t:I:l:L:X:vm:", longopts, NULL)) != -1) { switch (ch) { case 'c': options.dl_params.charset = (DABCharset) atoi(optarg); @@ -166,7 +155,7 @@ int main(int argc, char *argv[]) { options.erase_after_tx = true; break; case 'o': - options.output = optarg; + options.socket_ident = optarg; break; case 's': options.slide_interval = atoi(optarg); @@ -177,27 +166,18 @@ int main(int argc, char *argv[]) { case 'I': options.item_state_file = optarg; break; - case 'p': - options.padlen = atoi(optarg); - break; case 'm': options.max_slide_size = atoi(optarg); break; case 'R': options.raw_slides = true; break; - case 'f': - options.frame_dur = atoi(optarg); - break; case 'l': options.label_interval = atoi(optarg); break; case 'L': options.label_insertion = atoi(optarg); break; - case 'i': - options.init_burst = atoi(optarg); - break; case 'X': options.xpad_interval = atoi(optarg); break; @@ -211,11 +191,6 @@ int main(int argc, char *argv[]) { } } - if (!PADPacketizer::CheckPADLen(options.padlen)) { - fprintf(stderr, "ODR-PadEnc Error: PAD length %zu invalid: Possible values: %s\n", - options.padlen, PADPacketizer::ALLOWED_PADLEN.c_str()); - return 2; - } if (options.max_slide_size > SLSEncoder::MAXSLIDESIZE_SIMPLE) { fprintf(stderr, "ODR-PadEnc Error: max slide size %zu exceeds Simple Profile limit %zu\n", options.max_slide_size, SLSEncoder::MAXSLIDESIZE_SIMPLE); @@ -223,16 +198,16 @@ int main(int argc, char *argv[]) { } if (options.sls_dir && not options.dls_files.empty()) { - fprintf(stderr, "ODR-PadEnc encoding Slideshow from '%s' and DLS from %s to '%s' (PAD length: %zu)\n", - options.sls_dir, list_dls_files(options.dls_files).c_str(), options.output, options.padlen); + fprintf(stderr, "ODR-PadEnc encoding Slideshow from '%s' and DLS from %s to '%s'\n", + options.sls_dir, list_dls_files(options.dls_files).c_str(), options.socket_ident.c_str()); } else if (options.sls_dir) { - fprintf(stderr, "ODR-PadEnc encoding Slideshow from '%s' to '%s' (PAD length: %zu). No DLS.\n", - options.sls_dir, options.output, options.padlen); + fprintf(stderr, "ODR-PadEnc encoding Slideshow from '%s' to '%s'. No DLS.\n", + options.sls_dir, options.socket_ident.c_str()); } else if (not options.dls_files.empty()) { - fprintf(stderr, "ODR-PadEnc encoding DLS from %s to '%s' (PAD length: %zu). No Slideshow.\n", - list_dls_files(options.dls_files).c_str(), options.output, options.padlen); + fprintf(stderr, "ODR-PadEnc encoding DLS from %s to '%s'. No Slideshow.\n", + list_dls_files(options.dls_files).c_str(), options.socket_ident.c_str()); } else { fprintf(stderr, "ODR-PadEnc Error: Neither DLS nor Slideshow to encode !\n"); @@ -294,41 +269,6 @@ int main(int argc, char *argv[]) { return 1; } - - // invoke selected encoder - if (options.frame_dur) { - fprintf(stderr, "ODR-PadEnc using uniform PAD encoder\n"); - pad_encoder = new UniformPadEncoder(options); - } else { - fprintf(stderr, "ODR-PadEnc using burst PAD encoder\n"); - pad_encoder = new BurstPadEncoder(options); - } - int result = pad_encoder->Main(); - delete pad_encoder; - - return result; -} - - -// --- PadEncoder ----------------------------------------------------------------- -int PadEncoder::Main() { - output_fd = open(options.output, O_WRONLY); - if (output_fd == -1) { - perror("ODR-PadEnc Error: failed to open output"); - return 3; - } - - // check for FIFO - struct stat fifo_stat; - if (fstat(output_fd, &fifo_stat)) { - perror("ODR-PadEnc Error: could not retrieve output file stat"); - return 1; - } - if ((fifo_stat.st_mode & S_IFMT) != S_IFIFO) { - fprintf(stderr, "ODR-PadEnc Error: the output file must be a FIFO!\n"); - return 3; - } - #if HAVE_MAGICKWAND MagickWandGenesis(); if (verbose) @@ -349,23 +289,47 @@ int PadEncoder::Main() { return 1; } - // invoke actual encoder int result = 0; - while (!do_exit) { - result = Encode(); - // abort on error - if (result) - break; + PadInterface intf; + try { + intf.open(options.socket_ident); - // sleep until next run - std::this_thread::sleep_until(run_timeline); - } + uint8_t previous_padlen = 0; - // cleanup - if (close(output_fd)) { - perror("ODR-PadEnc Error: failed to close output"); - return 1; + std::shared_ptr pad_encoder; + + while (!do_exit) { + options.padlen = intf.receive_request(); + + if (previous_padlen != options.padlen) { + previous_padlen = options.padlen; + + if (options.padlen == 0) { + /* ignore */ + } + else if (!PADPacketizer::CheckPADLen(options.padlen)) { + fprintf(stderr, "ODR-PadEnc Error: PAD length %d invalid: Possible values: %s\n", + options.padlen, PADPacketizer::ALLOWED_PADLEN.c_str()); + result = 2; + break; + } + else { + fprintf(stderr, "ODR-PadEnc Reinitialise PAD length to %d\n", options.padlen); + pad_encoder = std::make_shared(options); + } + } + + if (options.padlen > 0) { + result = pad_encoder->Encode(intf); + if (result > 0) { + break; + } + } + } + } + catch (const std::runtime_error& e) { + fprintf(stderr, "ODR-PadEnc failure: %s\n", e.what()); } #if HAVE_MAGICKWAND @@ -375,6 +339,28 @@ int PadEncoder::Main() { return result; } + +// --- PadEncoder ----------------------------------------------------------------- +PadEncoder::PadEncoder(PadEncoderOptions options) : + options(options), + pad_packetizer(PADPacketizer(options.padlen)), + dls_encoder(DLSEncoder(&pad_packetizer)), + sls_encoder(SLSEncoder(&pad_packetizer)), + slides_success(false), + curr_dls_file(0) +{ + // PAD related timelines + next_slide = next_label = next_label_insertion = steady_clock::now(); + + // if multiple DLS files, ensure that initial increment leads to first one + if (options.dls_files.size() > 1) { + curr_dls_file = -1; + } + + xpad_interval_counter = 0; +} + + int PadEncoder::CheckRereadFile(const std::string& type, const std::string& path) { struct stat path_stat; if (stat(path.c_str(), &path_stat)) { @@ -460,69 +446,9 @@ int PadEncoder::EncodeLabel(bool skip_if_already_queued) { } -// --- BurstPadEncoder ----------------------------------------------------------------- -const int BurstPadEncoder::DLS_REPETITION_WHILE_SLS = 50; // PADs - -int BurstPadEncoder::Encode() { - int result = 0; - - // encode SLS - if (options.SLSEnabled()) { - result = EncodeSlide(false); - if (result) - return result; - - // while flushing, insert DLS (if present) after a certain PAD amout - while (pad_packetizer.QueueFilled()) { - if (options.DLSEnabled()) { - result = EncodeLabel(false); - if (result) - return result; - } - - pad_packetizer.WriteAllPADs(output_fd, DLS_REPETITION_WHILE_SLS); - } - } - - // encode (a last) DLS (if present) - if (options.DLSEnabled()) { - result = EncodeLabel(false); - if (result) - return result; - - // switch to next DLS file - curr_dls_file = (curr_dls_file + 1) % options.dls_files.size(); - } - - // flush all remaining PADs - pad_packetizer.WriteAllPADs(output_fd); - - // schedule next run at next slide interval - run_timeline += std::chrono::seconds(options.slide_interval); - - return 0; -} - - -// --- UniformPadEncoder ----------------------------------------------------------------- -UniformPadEncoder::UniformPadEncoder(PadEncoderOptions options) : PadEncoder(options) { - // PAD related timelines - pad_timeline = steady_clock::now(); - next_slide = pad_timeline; - next_label = pad_timeline; - next_label_insertion = pad_timeline; - - // consider initial burst - run_timeline -= std::chrono::milliseconds(options.init_burst * options.frame_dur); - - // if multiple DLS files, ensure that initial increment leads to first one - if (options.dls_files.size() > 1) - curr_dls_file = -1; - - xpad_interval_counter = 0; -} +int PadEncoder::Encode(PadInterface& intf) { + steady_clock::time_point pad_timeline = std::chrono::steady_clock::now(); -int UniformPadEncoder::Encode() { int result = 0; // handle SLS @@ -580,11 +506,9 @@ int UniformPadEncoder::Encode() { return result; // flush one PAD (considering X-PAD output interval) - pad_packetizer.WriteAllPADs(output_fd, 1, true, xpad_interval_counter == 0); - pad_timeline += std::chrono::milliseconds(options.frame_dur); + auto pad = pad_packetizer.GetNextPAD(xpad_interval_counter == 0); - // schedule next run at next frame/AU - run_timeline += std::chrono::milliseconds(options.frame_dur); + intf.send_pad_data(pad.data(), pad.size()); // update X-PAD output interval counter xpad_interval_counter = (xpad_interval_counter + 1) % options.xpad_interval; diff --git a/src/odr-padenc.h b/src/odr-padenc.h index 9ecf4a4..85dd11b 100644 --- a/src/odr-padenc.h +++ b/src/odr-padenc.h @@ -1,7 +1,7 @@ /* Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://rd.csp.it/) - Copyright (C) 2014, 2015 Matthias P. Braendli (http://opendigitalradio.org) + Copyright (C) 2014-2020 Matthias P. Braendli (http://opendigitalradio.org) Copyright (C) 2015-2019 Stefan Pöschel (http://opendigitalradio.org) @@ -41,6 +41,7 @@ #include #include +#include "pad_interface.h" #include "pad_common.h" #include "dls.h" #include "sls.h" @@ -50,41 +51,23 @@ using std::chrono::steady_clock; // --- PadEncoderOptions ----------------------------------------------------------------- struct PadEncoderOptions { - size_t padlen; - bool erase_after_tx; - int slide_interval; - int frame_dur; // uniform PAD encoder only - int label_interval; // uniform PAD encoder only - int label_insertion; // uniform PAD encoder only - int init_burst; // uniform PAD encoder only - int xpad_interval; // uniform PAD encoder only - size_t max_slide_size; - bool raw_slides; + uint8_t padlen = 0; + bool erase_after_tx = false; + int slide_interval = 10; + int label_interval = 12; // uniform PAD encoder only + int label_insertion = 1200; // uniform PAD encoder only + int xpad_interval = 1; // uniform PAD encoder only + size_t max_slide_size = SLSEncoder::MAXSLIDESIZE_SIMPLE; + bool raw_slides = false; DL_PARAMS dl_params; - const char* sls_dir; - const char* output; + const char *sls_dir = nullptr; + std::string socket_ident; std::vector dls_files; - const char* item_state_file; - - PadEncoderOptions() : - padlen(58), - erase_after_tx(false), - slide_interval(10), - frame_dur(0), - label_interval(12), - label_insertion(1200), - init_burst(12), - xpad_interval(1), - max_slide_size(SLSEncoder::MAXSLIDESIZE_SIMPLE), - raw_slides(false), - sls_dir(NULL), - output("/tmp/pad.fifo"), - item_state_file(NULL) - {} - - bool DLSEnabled() {return !dls_files.empty();} - bool SLSEnabled() {return sls_dir;} + const char *item_state_file = nullptr; + + bool DLSEnabled() const { return !dls_files.empty(); } + bool SLSEnabled() const { return sls_dir; } }; @@ -98,56 +81,19 @@ protected: SlideStore slides; bool slides_success; int curr_dls_file; - int output_fd; - steady_clock::time_point run_timeline; - - std::atomic do_exit; - - PadEncoder(PadEncoderOptions options) : - options(options), - pad_packetizer(PADPacketizer(options.padlen)), - dls_encoder(DLSEncoder(&pad_packetizer)), - sls_encoder(SLSEncoder(&pad_packetizer)), - slides_success(false), - curr_dls_file(0), - output_fd(-1), - run_timeline(steady_clock::now()), - do_exit(false) - {} - - virtual int Encode() = 0; + steady_clock::time_point next_slide; + steady_clock::time_point next_label; + steady_clock::time_point next_label_insertion; + size_t xpad_interval_counter; + int EncodeSlide(bool skip_if_already_queued); int EncodeLabel(bool skip_if_already_queued); static int CheckRereadFile(const std::string& type, const std::string& path); + public: + PadEncoder(PadEncoderOptions options); virtual ~PadEncoder() {} - int Main(); - void DoExit() {do_exit = true;} -}; - - -// --- BurstPadEncoder ----------------------------------------------------------------- -class BurstPadEncoder : public PadEncoder { -private: - static const int DLS_REPETITION_WHILE_SLS; - - int Encode(); -public: - BurstPadEncoder(PadEncoderOptions options) : PadEncoder(options) {} + int Encode(PadInterface& intf); }; - -// --- UniformPadEncoder ----------------------------------------------------------------- -class UniformPadEncoder : public PadEncoder { -private: - steady_clock::time_point pad_timeline; - steady_clock::time_point next_slide; - steady_clock::time_point next_label; - steady_clock::time_point next_label_insertion; - size_t xpad_interval_counter; - - int Encode(); -public: - UniformPadEncoder(PadEncoderOptions options); -}; diff --git a/src/pad_common.cpp b/src/pad_common.cpp index 0c3f0b3..8ee2cd8 100644 --- a/src/pad_common.cpp +++ b/src/pad_common.cpp @@ -139,40 +139,21 @@ pad_t* PADPacketizer::GetPAD() { return FlushPAD(); } - -void PADPacketizer::WriteAllPADs(int output_fd, int limit, bool output_sole_fpad, bool output_xpad) { - size_t error_count = 0; - size_t error_bytes = 0; - - // output a limited amount of PADs (-1 = no limit) - for (int i = 0; i != limit; i++) { - pad_t* pad = output_xpad ? GetPAD() : FlushPAD(); - - // if only F-PAD present, abort (if desired) - if (pad->back() == FPAD_LEN && !output_sole_fpad) { - delete pad; - break; - } - - if (verbose >= 2) { - fprintf(stderr, "ODR-PadEnc writing PAD (%zu bytes):", pad->size()); - for (size_t j = 0; j < pad->size(); j++) { - const char sep = (j == (pad->size() - 1) || j == (pad->size() - 1 - FPAD_LEN)) ? '|' : ' '; - fprintf(stderr, "%c%02X", sep , (*pad)[j]); - } - fprintf(stderr, "\n"); - } - - if (write(output_fd, &(*pad)[0], pad->size()) != (signed) pad->size()) { - error_count++; - error_bytes += pad->size(); +std::vector PADPacketizer::GetNextPAD(bool output_xpad) { + pad_t* pad = output_xpad ? GetPAD() : FlushPAD(); + + if (verbose >= 2) { + fprintf(stderr, "ODR-PadEnc writing PAD (%zu bytes):", pad->size()); + for (size_t j = 0; j < pad->size(); j++) { + const char sep = (j == (pad->size() - 1) || j == (pad->size() - 1 - FPAD_LEN)) ? '|' : ' '; + fprintf(stderr, "%c%02X", sep , (*pad)[j]); } - - delete pad; + fprintf(stderr, "\n"); } - if (error_count) - fprintf(stderr, "ODR-PadEnc Error: Could not write %zu PAD(s) with %zu Bytes\n", error_count, error_bytes); + std::vector p = *pad; + delete pad; + return p; } diff --git a/src/pad_common.h b/src/pad_common.h index 7568d8c..d0fec13 100644 --- a/src/pad_common.h +++ b/src/pad_common.h @@ -123,7 +123,7 @@ public: bool QueueFilled(); bool QueueContainsDG(int apptype_start); - void WriteAllPADs(int output_fd, int limit = -1, bool output_sole_fpad = false, bool output_xpad = true); + std::vector GetNextPAD(bool output_xpad); static DATA_GROUP* CreateDataGroupLengthIndicator(size_t len); static bool CheckPADLen(size_t len); diff --git a/src/pad_interface.cpp b/src/pad_interface.cpp new file mode 100644 index 0000000..3db5308 --- /dev/null +++ b/src/pad_interface.cpp @@ -0,0 +1,144 @@ +/* + Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://rd.csp.it/) + + Copyright (C) 2014-2020 Matthias P. Braendli (http://opendigitalradio.org) + + Copyright (C) 2015-2019 Stefan Pöschel (http://opendigitalradio.org) + + This program 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. + + This program 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 this program. If not, see . +*/ +#include "config.h" +#include "pad_interface.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MESSAGE_REQUEST 1 +#define MESSAGE_PAD_DATA 2 + +using namespace std; + +void PadInterface::open(const std::string &pad_ident) +{ + m_pad_ident = pad_ident; + + m_sock = socket(AF_UNIX, SOCK_DGRAM, 0); + if (m_sock == -1) { + throw runtime_error("PAD socket creation failed: " + string(strerror(errno))); + } + + struct sockaddr_un claddr; + memset(&claddr, 0, sizeof(struct sockaddr_un)); + claddr.sun_family = AF_UNIX; + snprintf(claddr.sun_path, sizeof(claddr.sun_path), "/tmp/%s.padenc", m_pad_ident.c_str()); + if (unlink(claddr.sun_path) == -1 and errno != ENOENT) { + fprintf(stderr, "Unlinking of socket %s failed: %s\n", claddr.sun_path, strerror(errno)); + } + + int ret = bind(m_sock, (const struct sockaddr *) &claddr, sizeof(struct sockaddr_un)); + if (ret == -1) { + throw runtime_error("PAD socket bind failed " + string(strerror(errno))); + } +} + +uint8_t PadInterface::receive_request() +{ + if (m_pad_ident.empty()) { + throw logic_error("Uninitialised PadInterface::request() called"); + } + + vector buffer(4); + + while (true) { + struct pollfd fds[1]; + fds[0].fd = m_sock; + fds[0].events = POLLIN; + int timeout_ms = 240; + + int retval = poll(fds, 1, timeout_ms); + + if (retval == -1) { + std::string errstr(strerror(errno)); + throw std::runtime_error("PAD socket poll error: " + errstr); + } + else if (retval > 0) { + ssize_t ret = recvfrom(m_sock, buffer.data(), buffer.size(), 0, nullptr, nullptr); + + if (ret == -1) { + throw runtime_error(string("Can't receive data: ") + strerror(errno)); + } + else { + buffer.resize(ret); + + // We could check where the data comes from, but since we're using UNIX sockets + // the source is anyway local to the machine. + + if (buffer[0] == MESSAGE_REQUEST) { + uint8_t padlen = buffer[1]; + return padlen; + } + else { + continue; + } + } + } + else { + return 0; + } + } +} + +void PadInterface::send_pad_data(const uint8_t *data, size_t len) +{ + struct sockaddr_un claddr; + memset(&claddr, 0, sizeof(struct sockaddr_un)); + claddr.sun_family = AF_UNIX; + snprintf(claddr.sun_path, sizeof(claddr.sun_path), "/tmp/%s.audioenc", m_pad_ident.c_str()); + + vector message(len + 1); + message[0] = MESSAGE_PAD_DATA; + copy(data, data + len, message.begin() + 1); + + ssize_t ret = sendto(m_sock, message.data(), message.size(), 0, (struct sockaddr*)&claddr, sizeof(struct sockaddr_un)); + if (ret == -1) { + // This suppresses the -Wlogical-op warning + if (errno == EAGAIN +#if EAGAIN != EWOULDBLOCK + or errno == EWOULDBLOCK +#endif + or errno == ECONNREFUSED + or errno == ENOENT) { + if (m_audioenc_reachable) { + fprintf(stderr, "ODR-PadEnc at %s not reachable\n", claddr.sun_path); + m_audioenc_reachable = false; + } + } + else { + fprintf(stderr, "PAD send failed: %s\n", strerror(errno)); + } + } + else if ((size_t)ret != message.size()) { + fprintf(stderr, "PAD incorrect length sent: %zu bytes of %zu transmitted\n", ret, len); + } + else if (not m_audioenc_reachable) { + fprintf(stderr, "Audio encoder is now reachable at %s\n", claddr.sun_path); + m_audioenc_reachable = true; + } +} diff --git a/src/pad_interface.h b/src/pad_interface.h new file mode 100644 index 0000000..f0307bd --- /dev/null +++ b/src/pad_interface.h @@ -0,0 +1,53 @@ +/* + Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://rd.csp.it/) + + Copyright (C) 2014-2020 Matthias P. Braendli (http://opendigitalradio.org) + + Copyright (C) 2015-2019 Stefan Pöschel (http://opendigitalradio.org) + + This program 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. + + This program 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 this program. If not, see . +*/ + +#pragma once +#include +#include +#include +#include +#include + +/*! \file PadInterface.h + * + * Handles communication with ODR-PadEnc using a socket + */ + +class PadInterface { + public: + /*! Create a new PAD data interface that binds to /tmp/pad_ident.padenc and + * communicates with ODR-AudioEnc at /tmp/pad_ident.audioenc + */ + void open(const std::string &pad_ident); + + /*! Receives a request from the audio encoder + * + * \return the desired padlen + */ + uint8_t receive_request(); + + void send_pad_data(const uint8_t *data, size_t len); + + private: + std::string m_pad_ident; + int m_sock = -1; + bool m_audioenc_reachable = true; +}; -- cgit v1.2.3