Various enhancements and fixes:

- fixed handling of Max samples per packet Source parameter in the WebUI and added computation of the real frame duration
- fixed max number of channels configurable for a Sink in the WebUI
- fixed tic_frame_size_at_1fs daemon parameter documentation
- changed daemon default sample_rate parameter to 48000 Hz
This commit is contained in:
Andrea Bondavalli 2020-05-07 19:57:38 +02:00
parent 9c4913f7e4
commit 07c2b35777
9 changed files with 78 additions and 30 deletions

View File

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

View File

@ -65,7 +65,7 @@ std::shared_ptr<Config> 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) {

View File

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

View File

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

View File

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

View File

@ -140,12 +140,13 @@ class Config extends Component {
<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>
<option value="6">6 - 125&mu;s</option>
<option value="12">12 - 250&mu;s</option>
<option value="16">16 - 333&mu;s</option>
<option value="24">24 - 500&mu;s</option>
<option value="48">48 - 1ms</option>
<option value="96">96 - 2ms</option>
<option value="192">192 - 4ms</option>
</select>
</th>
</tr>

View File

@ -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 {
</tr>
<tr>
<th align="left"> <label>Channels</label> </th>
<th align="left"> <input type='number' min='1' max='8' className='input-number' value={this.state.channels} onChange={this.onChangeChannels} required/> </th>
<th align="left"> <input type='number' min='1' max='64' className='input-number' value={this.state.channels} onChange={this.onChangeChannels} required/> </th>
</tr>
<tr>
<th align="left">Audio Channels map</th>

View File

@ -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 {
<th align="left"> <label>Max samples per packet </label> </th>
<th align="left">
<select value={this.state.maxSamplesPerPacket} onChange={this.onChangeMaxSamplesPerPacket}>
<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>
<option value="6" disabled={this.checkMaxSamplesPerPacket(6) ? undefined : true}>6 - {this.getPacketDuration(6)}</option>
<option value="12" disabled={this.checkMaxSamplesPerPacket(12) ? undefined : true}>12 - {this.getPacketDuration(12)}</option>
<option value="16" disabled={this.checkMaxSamplesPerPacket(16) ? undefined : true}>16 - {this.getPacketDuration(16)}</option>
<option value="48" disabled={this.checkMaxSamplesPerPacket(48) ? undefined : true}>48 - {this.getPacketDuration(48)}</option>
<option value="96" disabled={this.checkMaxSamplesPerPacket(96) ? undefined : true}>96 - {this.getPacketDuration(96)}</option>
<option value="192" disabled={this.checkMaxSamplesPerPacket(192) ? undefined : true}>192 - {this.getPacketDuration(192)}</option>
</select>
</th>
</tr>

View File

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