From 745fa05d0b6f2ddd50190e4023632f0a2eecc4e6 Mon Sep 17 00:00:00 2001 From: Andrea Bondavalli Date: Sat, 2 May 2020 20:20:21 +0200 Subject: [PATCH] Improved handling of "tic_frame_size_at_1fs" daemon parameter, added the possibility to configure it with the WebUI and updated the documentation. --- daemon/README.md | 7 ++++--- daemon/config.cpp | 5 +++-- daemon/config.hpp | 2 +- daemon/daemon.conf | 2 +- daemon/session_manager.cpp | 12 +++--------- webui/src/Config.js | 17 ++++++++++++----- webui/src/SourceEdit.js | 21 ++++++++++++++------- webui/src/Sources.js | 14 +++++++++++--- 8 files changed, 49 insertions(+), 31 deletions(-) diff --git a/daemon/README.md b/daemon/README.md index 68f03eb..0e7ac55 100644 --- a/daemon/README.md +++ b/daemon/README.md @@ -220,11 +220,12 @@ where: > JSON number specifying the default safety playout delay at 1FS in samples. > **tic\_frame\_size\_at\_1fs** -> JSON number specifying the RTP frame size at 1FS in samples. +> JSON number specifying the TIC frame size at 1FS in samples, valid range is between 6 and 192 samples. +> This global setting is used to determine the driver base timer period. For example with a value of 192 samples this period is set to 4ms and the outgoing RTP packets are scheduled for being sent to the network interface every 4ms causing an average latency grater than 4ms. +> A user is able to configure Source whose max number of samples range from 125μs (6 samples) to the value of this parameter. For example with a value of 48 samples a user is able to configure sources with a max number of samples ranging from 125μs (6 samples) to 1ms (48 samples) and these will be affected by a 1ms latency. > **max\_tic\_frame\_size** -> JSON number specifying the max tick frame size. -> In case of a high value of *tic_frame_size_at_1fs*, this must be set to 8192. +> JSON number specifying the max tick frame size. This is currently set to 1024. > **sap\_mcast\_addr** > JSON string specifying the SAP multicast address used for both announcing local sources and browsing remote sources. diff --git a/daemon/config.cpp b/daemon/config.cpp index d8f3af1..0a0f163 100644 --- a/daemon/config.cpp +++ b/daemon/config.cpp @@ -59,9 +59,10 @@ std::shared_ptr Config::parse(const std::string& filename) { if (config.playout_delay_ > 4000) config.playout_delay_ = 4000; if (config.tic_frame_size_at_1fs_ == 0 || - config.tic_frame_size_at_1fs_ > 8192) + config.tic_frame_size_at_1fs_ > 192) config.tic_frame_size_at_1fs_ = 192; - if (config.max_tic_frame_size_ == 0 || config.max_tic_frame_size_ > 8192) + if (config.max_tic_frame_size_ < config.tic_frame_size_at_1fs_ || + config.max_tic_frame_size_ > 1024) config.max_tic_frame_size_ = 1024; if (config.sample_rate_ == 0) config.sample_rate_ = 44100; diff --git a/daemon/config.hpp b/daemon/config.hpp index 24d8b7e..4092340 100644 --- a/daemon/config.hpp +++ b/daemon/config.hpp @@ -117,7 +117,7 @@ class Config { std::string http_base_dir_{"../webui/build"}; int log_severity_{2}; uint32_t playout_delay_{0}; - uint32_t tic_frame_size_at_1fs_{512}; + uint32_t tic_frame_size_at_1fs_{48}; uint32_t max_tic_frame_size_{1024}; uint32_t sample_rate_{44100}; std::string rtp_mcast_base_{"239.1.0.1"}; diff --git a/daemon/daemon.conf b/daemon/daemon.conf index f0258bf..aba9cef 100644 --- a/daemon/daemon.conf +++ b/daemon/daemon.conf @@ -4,7 +4,7 @@ "http_base_dir": "../webui/build", "log_severity": 2, "playout_delay": 0, - "tic_frame_size_at_1fs": 192, + "tic_frame_size_at_1fs": 48, "max_tic_frame_size": 1024, "sample_rate": 44100, "rtp_mcast_base": "239.1.0.1", diff --git a/daemon/session_manager.cpp b/daemon/session_manager.cpp index 592091c..6ca4fd6 100644 --- a/daemon/session_manager.cpp +++ b/daemon/session_manager.cpp @@ -455,7 +455,9 @@ std::error_code SessionManager::add_source(const StreamSource& source) { info.stream.m_byNbOfChannels = source.map.size(); strncpy(info.stream.m_cCodec, source.codec.c_str(), sizeof(info.stream.m_cCodec) - 1); - info.stream.m_ui32MaxSamplesPerPacket = source.max_samples_per_packet; // only for Source + info.stream.m_ui32MaxSamplesPerPacket = + source.max_samples_per_packet > config_->get_tic_frame_size_at_1fs() ? + config_->get_tic_frame_size_at_1fs() : source.max_samples_per_packet; info.stream.m_ui32SamplingRate = driver_->get_current_sample_rate(); // last set from driver or config info.stream.m_uiId = source.id; info.stream.m_ui32RTCPSrcIP = config_->get_ip_addr(); @@ -717,19 +719,11 @@ std::error_code SessionManager::add_sink(const StreamSink& sink) { info.stream.m_ui32FrameSize = config_->get_max_tic_frame_size(); } - BOOST_LOG_TRIVIAL(info) << "session_manager:: sink samples per packet " << - info.stream.m_ui32MaxSamplesPerPacket; BOOST_LOG_TRIVIAL(info) << "session_manager:: sink frame size " << info.stream.m_ui32FrameSize; BOOST_LOG_TRIVIAL(info) << "session_manager:: playout delay " << info.stream.m_ui32PlayOutDelay; - // info.m_ui32SrcIP = addr; // only for Source - // info.m_usSrcPort = 5004; - // info.m_ui32MaxSamplesPerPacket = 48; - // info.m_ui32SSRC = 65544; - // info.m_ucDSCP = source.dscp; - // info.m_byTTL = source.ttl; auto mcast_mac_addr = get_mcast_mac_addr(info.stream.m_ui32DestIP); std::copy(std::begin(mcast_mac_addr), std::end(mcast_mac_addr), info.stream.m_ui8DestMAC); diff --git a/webui/src/Config.js b/webui/src/Config.js index db1b000..c856ad5 100644 --- a/webui/src/Config.js +++ b/webui/src/Config.js @@ -37,7 +37,6 @@ class Config extends Component { playoutDelay: '', playoutDelayErr: false, ticFrameSizeAt1fs: '', - ticFrameSizeAt1fsErr: false, maxTicFrameSize: '', maxTicFrameSizeErr: false, sampleRate: '', @@ -99,7 +98,6 @@ class Config extends Component { inputIsValid() { return !this.state.playoutDelayErr && - !this.state.ticFrameSizeAt1fsErr && !this.state.maxTicFrameSizeErr && !this.state.rtpMcastBaseErr && !this.state.sapMcastAddrErr && @@ -139,11 +137,20 @@ class Config extends Component { this.setState({playoutDelay: e.target.value, playoutDelayErr: !e.currentTarget.checkValidity()})} required/> - - this.setState({ticFrameSizeAt1fs: e.target.value, ticFrameSizeAt1fsErr: !e.currentTarget.checkValidity()})} disabled required/> + + + + - + this.setState({maxTicFrameSize: e.target.value, maxTicFrameSizeErr: !e.currentTarget.checkValidity()})} disabled required/> diff --git a/webui/src/SourceEdit.js b/webui/src/SourceEdit.js index 24f99d8..88351de 100644 --- a/webui/src/SourceEdit.js +++ b/webui/src/SourceEdit.js @@ -43,6 +43,7 @@ const max_packet_size = 1440; //bytes class SourceEdit extends Component { static propTypes = { source: PropTypes.object.isRequired, + ticFrameSizeAt1fs: PropTypes.number.isRequired, applyEdit: PropTypes.func.isRequired, closeEdit: PropTypes.func.isRequired, editIsOpen: PropTypes.bool.isRequired, @@ -58,7 +59,8 @@ class SourceEdit extends Component { name: this.props.source.name, nameErr: false, io: this.props.source.io, - maxSamplesPerPacket: this.props.source.max_samples_per_packet, + maxSamplesPerPacket: (this.props.source.max_samples_per_packet > this.props.ticFrameSizeAt1fs) ? + this.props.ticFrameSizeAt1fs : this.props.source.max_samples_per_packet, codec: this.props.source.codec, ttl: this.props.source.ttl, ttlErr: false, @@ -84,6 +86,7 @@ class SourceEdit extends Component { this.onChangeMaxSamplesPerPacket = this.onChangeMaxSamplesPerPacket.bind(this); this.onChangeCodec = this.onChangeCodec.bind(this); this.inputIsValid = this.inputIsValid.bind(this); + this.checkMaxSamplesPerPacket = this.checkMaxSamplesPerPacket.bind(this); } componentDidMount() { @@ -153,6 +156,10 @@ class SourceEdit extends Component { this.setState({ map: map }); } + checkMaxSamplesPerPacket(value) { + return this.props.ticFrameSizeAt1fs >= value; + } + inputIsValid() { return !this.state.nameErr && !this.state.ttlErr && @@ -186,12 +193,12 @@ class SourceEdit extends Component { diff --git a/webui/src/Sources.js b/webui/src/Sources.js index 779b899..d638eda 100644 --- a/webui/src/Sources.js +++ b/webui/src/Sources.js @@ -139,11 +139,13 @@ class Sources extends Component { sources: [], source: {}, isLoading: false, + isConfigLoading: false, isEdit: false, isInfo: false, editIsOpen: false, infoIsOpen: false, - removeIsOpen: false, + removeIsOpen: false, + ticFrameSizeAt1fs: '', editTitle: '' }; this.onInfoClick = this.onInfoClick.bind(this); @@ -160,12 +162,17 @@ class Sources extends Component { } fetchSources() { - this.setState({isLoading: true}); + this.setState({isLoading: true, isConfigLoading: true}); RestAPI.getSources() .then(response => response.json()) .then( data => this.setState( { sources: data.sources, isLoading: false })) .catch(err => this.setState( { isLoading: false } )); + RestAPI.getConfig() + .then(response => response.json()) + .then( + data => this.setState( { isConfigLoading: false, ticFrameSizeAt1fs: data.tic_frame_size_at_1fs })) + .catch(err => this.setState({ isConfigLoading: false })); } componentDidMount() { @@ -253,7 +260,7 @@ class Sources extends Component { )); return (
- { this.state.isLoading ? + { this.state.isLoading || this.state.isConfigLoading ? : } @@ -273,6 +280,7 @@ class Sources extends Component { applyEdit={this.applyEdit} editTitle={this.state.editTitle} isEdit={this.state.isEdit} + ticFrameSizeAt1fs={this.state.ticFrameSizeAt1fs} source={this.state.source} /> : undefined } { this.state.removeIsOpen ?