diff --git a/daemon/README.md b/daemon/README.md index c8de7d6..456b4db 100644 --- a/daemon/README.md +++ b/daemon/README.md @@ -221,8 +221,7 @@ where: > **tic\_frame\_size\_at\_1fs** > JSON number specifying the TIC frame size at 1FS in samples, valid range is from 6 to 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 every 4ms causing an average latency greater than 4ms. -> A user is able to configure Sources 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 packets will be affected by a 1ms latency. +> 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 every 4ms resulting on an average latency greater than 4ms. > **max\_tic\_frame\_size** > JSON number specifying the max tick frame size. This is currently set to 1024. diff --git a/daemon/config.cpp b/daemon/config.cpp index 0a0f163..8f4f316 100644 --- a/daemon/config.cpp +++ b/daemon/config.cpp @@ -65,7 +65,7 @@ std::shared_ptr Config::parse(const std::string& filename) { config.max_tic_frame_size_ > 1024) config.max_tic_frame_size_ = 1024; if (config.sample_rate_ == 0) - config.sample_rate_ = 44100; + config.sample_rate_ = 48000; boost::system::error_code ec; ip::address_v4::from_string(config.rtp_mcast_base_.c_str(), ec); if (ec) { diff --git a/daemon/config.hpp b/daemon/config.hpp index 4092340..fc77c72 100644 --- a/daemon/config.hpp +++ b/daemon/config.hpp @@ -119,7 +119,7 @@ class Config { uint32_t playout_delay_{0}; uint32_t tic_frame_size_at_1fs_{48}; uint32_t max_tic_frame_size_{1024}; - uint32_t sample_rate_{44100}; + uint32_t sample_rate_{48000}; std::string rtp_mcast_base_{"239.1.0.1"}; std::string sap_mcast_addr_{"224.2.127.254"}; uint16_t rtp_port_{5004}; diff --git a/daemon/daemon.conf b/daemon/daemon.conf index aba9cef..8204681 100644 --- a/daemon/daemon.conf +++ b/daemon/daemon.conf @@ -6,7 +6,7 @@ "playout_delay": 0, "tic_frame_size_at_1fs": 48, "max_tic_frame_size": 1024, - "sample_rate": 44100, + "sample_rate": 48000, "rtp_mcast_base": "239.1.0.1", "rtp_port": 5004, "ptp_domain": 0, diff --git a/daemon/session_manager.cpp b/daemon/session_manager.cpp index 6ca4fd6..31ae8d6 100644 --- a/daemon/session_manager.cpp +++ b/daemon/session_manager.cpp @@ -455,9 +455,7 @@ 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 > config_->get_tic_frame_size_at_1fs() ? - config_->get_tic_frame_size_at_1fs() : source.max_samples_per_packet; + info.stream.m_ui32MaxSamplesPerPacket = 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(); diff --git a/webui/src/Config.js b/webui/src/Config.js index c856ad5..0115f45 100644 --- a/webui/src/Config.js +++ b/webui/src/Config.js @@ -140,12 +140,13 @@ class Config extends Component { diff --git a/webui/src/SinkEdit.js b/webui/src/SinkEdit.js index ded465c..23103c9 100644 --- a/webui/src/SinkEdit.js +++ b/webui/src/SinkEdit.js @@ -117,7 +117,7 @@ class SinkEdit extends Component { onCancel() { this.props.closeEdit(); } - + onChangeChannels(e) { if (e.currentTarget.checkValidity()) { let channels = parseInt(e.target.value, 10); @@ -213,7 +213,7 @@ class SinkEdit extends Component { - + Audio Channels map diff --git a/webui/src/SourceEdit.js b/webui/src/SourceEdit.js index 88351de..c1929ad 100644 --- a/webui/src/SourceEdit.js +++ b/webui/src/SourceEdit.js @@ -44,6 +44,7 @@ class SourceEdit extends Component { static propTypes = { source: PropTypes.object.isRequired, ticFrameSizeAt1fs: PropTypes.number.isRequired, + sampleRate: PropTypes.number.isRequired, applyEdit: PropTypes.func.isRequired, closeEdit: PropTypes.func.isRequired, editIsOpen: PropTypes.bool.isRequired, @@ -59,8 +60,6 @@ class SourceEdit extends Component { name: this.props.source.name, nameErr: false, io: this.props.source.io, - 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, @@ -70,8 +69,9 @@ class SourceEdit extends Component { refclkPtpTraceable: this.props.source.refclk_ptp_traceable, channels: this.props.source.map.length, channelsErr: false, - maxChannels: Math.floor(max_packet_size / (this.props.source.max_samples_per_packet * (this.props.source.codec === 'L16' ? 2 : 3))), map: this.props.source.map, + maxSamplesPerPacket: this.getMaxSamplesPerPacket(), + maxChannels: this.getMaxChannels(this.props.source.codec, this.getMaxSamplesPerPacket()), audioMap: [] } let v; @@ -87,6 +87,10 @@ class SourceEdit extends Component { this.onChangeCodec = this.onChangeCodec.bind(this); this.inputIsValid = this.inputIsValid.bind(this); this.checkMaxSamplesPerPacket = this.checkMaxSamplesPerPacket.bind(this); + this.getMaxSamplesPerPacket = this.getMaxSamplesPerPacket.bind(this); + this.getnFS = this.getnFS.bind(this); + this.getPacketDuration = this.getPacketDuration.bind(this); + this.getMaxChannels = this.getMaxChannels.bind(this); } componentDidMount() { @@ -120,16 +124,21 @@ class SourceEdit extends Component { onCancel() { this.props.closeEdit(); } + + getMaxChannels(codec, samples) { + let maxChannels = Math.floor(max_packet_size / (samples * (codec === 'L16' ? 2 : 3))); + return maxChannels > 64 ? 64 : maxChannels; + } onChangeMaxSamplesPerPacket(e) { let samples = parseInt(e.target.value, 10); - let maxChannels = Math.floor(max_packet_size / (samples * (this.state.codec === 'L16' ? 2 : 3))); + let maxChannels = this.getMaxChannels(this.state.codec, samples); this.setState({ maxSamplesPerPacket: samples, maxChannels: maxChannels, channelsErr: this.state.channels > maxChannels }); } onChangeCodec(e) { let codec = e.target.value; - let maxChannels = Math.floor(max_packet_size / (this.state.maxSamplesPerPacket * (codec === 'L16' ? 2 : 3))); + let maxChannels = this.getMaxChannels(this.state.codec, this.state.maxSamplesPerPacket); this.setState({ codec: codec, maxChannels: maxChannels, channelsErr: this.state.channels > maxChannels }); } @@ -156,8 +165,47 @@ class SourceEdit extends Component { this.setState({ map: map }); } - checkMaxSamplesPerPacket(value) { - return this.props.ticFrameSizeAt1fs >= value; + getnFS() { + switch(this.props.sampleRate) { + case 384000: + case 352800: + return 8; + break; + case 192000: + case 176400: + return 4; + break; + case 96000: + case 88200: + return 2; + break; + case 48000: + case 44100: + default: + return 1; + } + } + + checkMaxSamplesPerPacket(samples) { + return (samples <= (this.props.ticFrameSizeAt1fs * this.getnFS())); + } + + getMaxSamplesPerPacket() { + return (this.props.source.max_samples_per_packet > (this.props.ticFrameSizeAt1fs * this.getnFS())) ? + (this.props.ticFrameSizeAt1fs * this.getnFS()) : this.props.source.max_samples_per_packet; + } + + getPacketDuration(samples) { + let duration = (samples * 1000000) / this.props.sampleRate; + if (duration >= 1000) { + duration /= 1000; + if (duration == Math.round(duration)) + return Math.round(duration).toString() + 'ms'; + else + return (Math.round(duration * 1000) / 1000).toString() + 'ms'; + } + else + return Math.round(duration).toString() + 'μs'; } inputIsValid() { @@ -193,12 +241,12 @@ class SourceEdit extends Component { diff --git a/webui/src/Sources.js b/webui/src/Sources.js index d638eda..62b1d55 100644 --- a/webui/src/Sources.js +++ b/webui/src/Sources.js @@ -146,6 +146,7 @@ class Sources extends Component { infoIsOpen: false, removeIsOpen: false, ticFrameSizeAt1fs: '', + sampleRate: '', editTitle: '' }; this.onInfoClick = this.onInfoClick.bind(this); @@ -171,7 +172,7 @@ class Sources extends Component { RestAPI.getConfig() .then(response => response.json()) .then( - data => this.setState( { isConfigLoading: false, ticFrameSizeAt1fs: data.tic_frame_size_at_1fs })) + data => this.setState( { isConfigLoading: false, ticFrameSizeAt1fs: data.tic_frame_size_at_1fs, sampleRate: data.sample_rate })) .catch(err => this.setState({ isConfigLoading: false })); } @@ -281,6 +282,7 @@ class Sources extends Component { editTitle={this.state.editTitle} isEdit={this.state.isEdit} ticFrameSizeAt1fs={this.state.ticFrameSizeAt1fs} + sampleRate={this.state.sampleRate} source={this.state.source} /> : undefined } { this.state.removeIsOpen ?