diff options
-rw-r--r-- | doc/example.mux | 4 | ||||
-rw-r--r-- | lib/edi/common.cpp | 13 | ||||
-rw-r--r-- | lib/edi/common.hpp | 2 | ||||
-rw-r--r-- | src/ConfigParser.cpp | 8 | ||||
-rw-r--r-- | src/input/Edi.cpp | 14 | ||||
-rw-r--r-- | src/input/Edi.h | 2 | ||||
-rw-r--r-- | src/input/inputs.h | 2 |
7 files changed, 40 insertions, 5 deletions
diff --git a/doc/example.mux b/doc/example.mux index 83dbfbb..cf02467 100644 --- a/doc/example.mux +++ b/doc/example.mux @@ -228,6 +228,10 @@ subchannels { ; avoid runaway memory usage in case of issues. buffer 500 ; 500 * 24ms = 12 seconds + + ; Specify the additional delay in milliseconds to add to the TIST. Positive values + ; mean the content will be inserted later. + tist-delay 10 } } diff --git a/lib/edi/common.cpp b/lib/edi/common.cpp index d6ca89c..87a15ce 100644 --- a/lib/edi/common.cpp +++ b/lib/edi/common.cpp @@ -73,6 +73,19 @@ double frame_timestamp_t::diff_ms(const frame_timestamp_t& other) const return lhs - rhs; } +frame_timestamp_t& frame_timestamp_t::operator+=(const std::chrono::milliseconds& ms) +{ + tsta += (ms.count() % 1000) << 14; // Shift ms by 14 to Timestamp level 2 + if (tsta > 0xf9FFff) { + tsta -= 0xfa0000; // Substract 16384000, corresponding to one second + seconds += 1; + } + + seconds += (ms.count() / 1000); + + return *this; +} + frame_timestamp_t frame_timestamp_t::from_unix_epoch(std::time_t time, uint32_t tai_utc_offset, uint32_t tsta) { frame_timestamp_t ts; diff --git a/lib/edi/common.hpp b/lib/edi/common.hpp index 8252a7a..2a9c683 100644 --- a/lib/edi/common.hpp +++ b/lib/edi/common.hpp @@ -43,6 +43,8 @@ struct frame_timestamp_t { double diff_ms(const frame_timestamp_t& other) const; + frame_timestamp_t& operator+=(const std::chrono::milliseconds& ms); + static frame_timestamp_t from_unix_epoch(std::time_t time, uint32_t tai_utc_offset, uint32_t tsta); }; diff --git a/src/ConfigParser.cpp b/src/ConfigParser.cpp index 063e4ec..776ddc8 100644 --- a/src/ConfigParser.cpp +++ b/src/ConfigParser.cpp @@ -51,11 +51,12 @@ #include <boost/algorithm/string/split.hpp> #include <cstdint> #include <cstring> -#include <memory> +#include <chrono> #include <exception> #include <iostream> -#include <string> #include <map> +#include <memory> +#include <string> #include <vector> using namespace std; @@ -1037,6 +1038,9 @@ static void setup_subchannel_from_ptree(shared_ptr<DabSubchannel>& subchan, throw runtime_error("Subchannel with uid " + subchanuid + " has invalid buffer-management !"); } + const int32_t tist_delay = pt.get("tist-delay", 0); + subchan->input->setTistDelay(chrono::milliseconds(tist_delay)); + subchan->startAddress = 0; dabProtection* protection = &subchan->protection; diff --git a/src/input/Edi.cpp b/src/input/Edi.cpp index f4b5e25..b5301d2 100644 --- a/src/input/Edi.cpp +++ b/src/input/Edi.cpp @@ -62,6 +62,8 @@ Edi::Edi(const std::string& name, const dab_input_edi_config_t& config) : RC_ADD_PARAMETER(prebuffering, "Min buffer level before streaming starts [24ms frames]"); + + RC_ADD_PARAMETER(tistdelay, "TIST delay to add [ms]"); } Edi::~Edi() { @@ -209,7 +211,8 @@ size_t Edi::readFrame(uint8_t *buffer, size_t size, std::time_t seconds, int utc // difference between the input frame timestamp and the requested // timestamp. if (m_pending_sti_frame.timestamp.valid()) { - const auto ts_req = EdiDecoder::frame_timestamp_t::from_unix_epoch(seconds, utco, tsta); + auto ts_req = EdiDecoder::frame_timestamp_t::from_unix_epoch(seconds, utco, tsta); + ts_req += m_tist_delay; const double offset = m_pending_sti_frame.timestamp.diff_ms(ts_req); if (offset < 24e-3) { @@ -274,7 +277,8 @@ size_t Edi::readFrame(uint8_t *buffer, size_t size, std::time_t seconds, int utc return 0; } else { - const auto ts_req = EdiDecoder::frame_timestamp_t::from_unix_epoch(seconds, utco, tsta); + auto ts_req = EdiDecoder::frame_timestamp_t::from_unix_epoch(seconds, utco, tsta); + ts_req += m_tist_delay; const double offset = m_pending_sti_frame.timestamp.diff_ms(ts_req); if (offset > 24e-3) { @@ -384,6 +388,9 @@ void Edi::set_parameter(const std::string& parameter, const std::string& value) throw ParameterError("Invalid value for '" + parameter + "' in controllable " + get_rc_name()); } } + else if (parameter == "tistdelay") { + m_tist_delay = chrono::milliseconds(stoi(value)); + } else { throw ParameterError("Parameter '" + parameter + "' is not exported by controllable " + get_rc_name()); } @@ -408,6 +415,9 @@ const std::string Edi::get_parameter(const std::string& parameter) const break; } } + else if (parameter == "tistdelay") { + ss << m_tist_delay.count(); + } else { throw ParameterError("Parameter '" + parameter + "' is not exported by controllable " + get_rc_name()); } diff --git a/src/input/Edi.h b/src/input/Edi.h index ed4d7cf..a3b1d4d 100644 --- a/src/input/Edi.h +++ b/src/input/Edi.h @@ -97,7 +97,7 @@ class Edi : public InputBase, public RemoteControllable { std::atomic<bool> m_running = ATOMIC_VAR_INIT(false); ThreadsafeQueue<EdiDecoder::sti_frame_t> m_frames; - // InputBase defines bufferManagement + // InputBase defines bufferManagement and tist delay // Used in timestamp-based buffer management EdiDecoder::sti_frame_t m_pending_sti_frame; diff --git a/src/input/inputs.h b/src/input/inputs.h index 5d4fc60..83cdbf2 100644 --- a/src/input/inputs.h +++ b/src/input/inputs.h @@ -83,6 +83,7 @@ class InputBase { virtual ~InputBase() {} + void setTistDelay(const std::chrono::milliseconds& ms) { m_tist_delay = ms; } void setBufferManagement(BufferManagement bm) { m_bufferManagement = bm; } BufferManagement getBufferManagement() const { return m_bufferManagement; } @@ -90,6 +91,7 @@ class InputBase { InputBase() {} std::atomic<BufferManagement> m_bufferManagement = ATOMIC_VAR_INIT(BufferManagement::Prebuffering); + std::chrono::milliseconds m_tist_delay; }; }; |