Improved handling of "tic_frame_size_at_1fs" daemon parameter, added the possibility to configure it with the WebUI and updated the documentation.

This commit is contained in:
Andrea Bondavalli 2020-05-02 20:20:21 +02:00
parent 37fa1de81b
commit 745fa05d0b
8 changed files with 49 additions and 31 deletions

View File

@ -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.

View File

@ -59,9 +59,10 @@ std::shared_ptr<Config> 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;

View File

@ -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"};

View File

@ -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",

View File

@ -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);

View File

@ -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 {
<th align="left"> <input type='number' min='0' max='4000' className='input-number' value={this.state.playoutDelay} onChange={e => this.setState({playoutDelay: e.target.value, playoutDelayErr: !e.currentTarget.checkValidity()})} required/> </th>
</tr>
<tr>
<th align="left"> <label>TIC Frame size at @1FS </label> </th>
<th align="left"> <input type='number' min='192' max='8192' className='input-number' value={this.state.ticFrameSizeAt1fs} onChange={e => this.setState({ticFrameSizeAt1fs: e.target.value, ticFrameSizeAt1fsErr: !e.currentTarget.checkValidity()})} disabled required/> </th>
<th align="left"> <label>TIC frame size @1FS (samples) </label> </th>
<th align="left">
<select value={this.state.ticFrameSizeAt1fs} onChange={e => this.setState({ticFrameSizeAt1fs: e.target.value})}>
<option value="6">6 - 125&mu;s@48Khz</option>
<option value="12">12 - 250&mu;s@48Khz</option>
<option value="16">16 - 333&mu;s@48Khz</option>
<option value="48">48 - 1ms@48Khz</option>
<option value="96">96 - 2ms@48Khz</option>
<option value="192">192 - 4ms@48Khz</option>
</select>
</th>
</tr>
<tr>
<th align="left"> <label>Max TIC frame size </label> </th>
<th align="left"> <label>Max TIC frame size (samples) </label> </th>
<th align="left"> <input type='number' min='192' max='8192' className='input-number' value={this.state.maxTicFrameSize} onChange={e => this.setState({maxTicFrameSize: e.target.value, maxTicFrameSizeErr: !e.currentTarget.checkValidity()})} disabled required/> </th>
</tr>
<tr>

View File

@ -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 {
<th align="left"> <label>Max samples per packet </label> </th>
<th align="left">
<select value={this.state.maxSamplesPerPacket} onChange={this.onChangeMaxSamplesPerPacket}>
<option value="6">6 - 125&mu;s@48Khz</option>
<option value="12">12 - 250&mu;s@48Khz</option>
<option value="16">16 - 333&mu;s@48Khz</option>
<option value="48">48 - 1ms@48Khz</option>
<option value="96">96 - 2ms@48Khz</option>
<option value="192">192 - 4ms@48Khz</option>
<option value="6" disabled={this.checkMaxSamplesPerPacket(6) ? undefined : true}>6 - 125&mu;s@48Khz</option>
<option value="12" disabled={this.checkMaxSamplesPerPacket(12) ? undefined : true}>12 - 250&mu;s@48Khz</option>
<option value="16" disabled={this.checkMaxSamplesPerPacket(16) ? undefined : true}>16 - 333&mu;s@48Khz</option>
<option value="48" disabled={this.checkMaxSamplesPerPacket(48) ? undefined : true}>48 - 1ms@48Khz</option>
<option value="96" disabled={this.checkMaxSamplesPerPacket(96) ? undefined : true}>96 - 2ms@48Khz</option>
<option value="192" disabled={this.checkMaxSamplesPerPacket(192) ? undefined : true}>192 - 4ms@48Khz</option>
</select>
</th>
</tr>

View File

@ -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 (
<div id='sources'>
{ this.state.isLoading ? <Loader/>
{ this.state.isLoading || this.state.isConfigLoading ? <Loader/>
: <SourceList onAddClick={this.onAddClick}
onReloadClick={this.onReloadClick}
sources={sources} /> }
@ -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 ?