aboutsummaryrefslogtreecommitdiffstats
path: root/src/odr-padenc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/odr-padenc.cpp')
-rw-r--r--src/odr-padenc.cpp242
1 files changed, 83 insertions, 159 deletions
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 <memory>
-
-static PadEncoder *pad_encoder = NULL;
+std::atomic<bool> 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<PadEncoder> 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<PadEncoder>(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;