Skip to content

Commit

Permalink
roc-streaminggh-674 Refine packet_count and fract_loss calculations
Browse files Browse the repository at this point in the history
- packet_count: On receiver, derive it from packet_count in SR,
  and handle 32-bit wraps. On sender, derive it from ext_first_sn
  and ext_last_sn, and also handle 32-bit wraps

- fract_loss: automatically calculate loss ratio since last report
  based on packet_count and cum_loss
  • Loading branch information
gavv committed Feb 5, 2024
1 parent 7419dc9 commit e1909c6
Show file tree
Hide file tree
Showing 19 changed files with 370 additions and 61 deletions.
24 changes: 17 additions & 7 deletions src/internal_modules/roc_audio/feedback_monitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/

#include "roc_audio/feedback_monitor.h"
#include "roc_audio/packetizer.h"
#include "roc_core/log.h"
#include "roc_core/panic.h"
#include "roc_core/time.h"
Expand All @@ -15,15 +16,17 @@ namespace roc {
namespace audio {

FeedbackMonitor::FeedbackMonitor(IFrameWriter& writer,
Packetizer& packetizer,
ResamplerWriter* resampler,
const FeedbackConfig& feedback_config,
const LatencyConfig& latency_config,
const SampleSpec& sample_spec)
: tuner_(latency_config, sample_spec)
, latency_metrics_()
, use_packetizer_(false)
, has_feedback_(false)
, last_feedback_ts_(0)
, feedback_timeout_(feedback_config.source_timeout)
, packetizer_(packetizer)
, writer_(writer)
, resampler_(resampler)
, enable_scaling_(latency_config.tuner_profile != audio::LatencyTunerProfile_Intact)
Expand Down Expand Up @@ -100,6 +103,13 @@ void FeedbackMonitor::process_feedback(packet::stream_source_t source_id,
latency_metrics_ = latency_metrics;
link_metrics_ = link_metrics;

if (link_metrics_.total_packets == 0 || use_packetizer_) {
// If packet counter is not reported from receiver, fallback to
// counter from sender.
link_metrics_.total_packets = packetizer_.metrics().packet_count;
use_packetizer_ = true;
}

has_feedback_ = true;
last_feedback_ts_ = core::timestamp(core::ClockMonotonic);
}
Expand Down Expand Up @@ -128,21 +138,21 @@ size_t FeedbackMonitor::num_participants() const {
return has_feedback_ ? 1 : 0;
}

const LatencyMetrics& FeedbackMonitor::latency_metrics(size_t part_index) const {
roc_panic_if_msg(part_index >= num_participants(),
const LatencyMetrics& FeedbackMonitor::latency_metrics(size_t party_index) const {
roc_panic_if_msg(party_index >= num_participants(),
"feedback monitor: participant index out of bounds:"
" index=%lu max=%lu",
(unsigned long)part_index, (unsigned long)num_participants());
(unsigned long)party_index, (unsigned long)num_participants());

// TODO(gh-674): collect per-session metrics
return latency_metrics_;
}

const packet::LinkMetrics& FeedbackMonitor::link_metrics(size_t part_index) const {
roc_panic_if_msg(part_index >= num_participants(),
const packet::LinkMetrics& FeedbackMonitor::link_metrics(size_t party_index) const {
roc_panic_if_msg(party_index >= num_participants(),
"feedback monitor: participant index out of bounds:"
" index=%lu max=%lu",
(unsigned long)part_index, (unsigned long)num_participants());
(unsigned long)party_index, (unsigned long)num_participants());

// TODO(gh-674): collect per-session metrics
return link_metrics_;
Expand Down
12 changes: 8 additions & 4 deletions src/internal_modules/roc_audio/feedback_monitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include "roc_audio/iframe_writer.h"
#include "roc_audio/latency_tuner.h"
#include "roc_audio/packetizer.h"
#include "roc_audio/resampler_writer.h"
#include "roc_audio/sample_spec.h"
#include "roc_core/noncopyable.h"
Expand Down Expand Up @@ -63,6 +64,7 @@ class FeedbackMonitor : public IFrameWriter, public core::NonCopyable<> {
public:
//! Constructor.
FeedbackMonitor(IFrameWriter& writer,
Packetizer& packetizer,
ResamplerWriter* resampler,
const FeedbackConfig& feedback_config,
const LatencyConfig& latency_config,
Expand Down Expand Up @@ -91,12 +93,12 @@ class FeedbackMonitor : public IFrameWriter, public core::NonCopyable<> {
size_t num_participants() const;

//! Get latest latency metrics for session.
//! @p part_index should be in range [0; num_participants()-1].
const LatencyMetrics& latency_metrics(size_t part_index) const;
//! @p party_index should be in range [0; num_participants()-1].
const LatencyMetrics& latency_metrics(size_t party_index) const;

//! Get latest link metrics for session.
//! @p part_index should be in range [0; num_participants()-1].
const packet::LinkMetrics& link_metrics(size_t part_index) const;
//! @p party_index should be in range [0; num_participants()-1].
const packet::LinkMetrics& link_metrics(size_t party_index) const;

private:
bool update_tuner_(packet::stream_timestamp_t duration);
Expand All @@ -108,11 +110,13 @@ class FeedbackMonitor : public IFrameWriter, public core::NonCopyable<> {

LatencyMetrics latency_metrics_;
packet::LinkMetrics link_metrics_;
bool use_packetizer_;

bool has_feedback_;
core::nanoseconds_t last_feedback_ts_;
const core::nanoseconds_t feedback_timeout_;

Packetizer& packetizer_;
IFrameWriter& writer_;

ResamplerWriter* resampler_;
Expand Down
11 changes: 0 additions & 11 deletions src/internal_modules/roc_audio/latency_monitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,17 +60,6 @@ namespace audio {
class LatencyMonitor : public IFrameReader, public core::NonCopyable<> {
public:
//! Constructor.
//!
//! @b Parameters
//! - @p frame_reader is inner frame reader for E2E latency calculation
//! - @p incoming_queue and @p depacketizer are used to NIQ latency calculation
//! - @p link_meter is used to obtain link metrics
//! - @p resampler is used to set the scaling factor to compensate clock
//! drift according to calculated latency
//! - @p config defines calculation parameters
//! - @p packet_sample_spec is the sample spec of the input packets
//! - @p frame_sample_spec is the sample spec of the output frames (after
//! resampling)
LatencyMonitor(IFrameReader& frame_reader,
const packet::SortedQueue& incoming_queue,
const Depacketizer& depacketizer,
Expand Down
11 changes: 2 additions & 9 deletions src/internal_modules/roc_packet/ilink_meter.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,7 @@ struct LinkMetrics {
//! packets actually received, where the number of packets received includes any
//! which are late or duplicates. Packets that arrive late are not counted as lost,
//! and the loss may be negative if there are duplicates.
int64_t cum_lost_packets;

//! Fraction of lost packets from 0 to 1.
//! The fraction of RTP data packets lost since the previous report was sent.
//! Defined to be the number of packets lost divided by the number of packets
//! expected. If the loss is negative due to duplicates, set to zero.
float fract_lost_packets;
int64_t lost_packets;

//! Estimated interarrival jitter.
//! An estimate of the statistical variance of the RTP data packet
Expand All @@ -67,8 +61,7 @@ struct LinkMetrics {
: ext_first_seqnum(0)
, ext_last_seqnum(0)
, total_packets(0)
, cum_lost_packets(0)
, fract_lost_packets(0)
, lost_packets(0)
, jitter(0)
, rtt(0) {
}
Expand Down
20 changes: 20 additions & 0 deletions src/internal_modules/roc_packet/units.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,26 @@ inline bool seqnum_le(const seqnum_t a, const seqnum_t b) {
//! Sequence number extended to 32 bits.
typedef uint32_t ext_seqnum_t;

//! Extended sequence number delta.
//! @remarks
//! Signed version of ext_seqnum_t.
typedef int32_t ext_seqnum_diff_t;

//! Compute difference between two extended seqnums.
inline ext_seqnum_diff_t ext_seqnum_diff(const ext_seqnum_t a, const ext_seqnum_t b) {
return ext_seqnum_diff_t(a - b);
}

//! Check if `a` is before `b`, taking possible wrap into account.
inline bool ext_seqnum_lt(const ext_seqnum_t a, const ext_seqnum_t b) {
return ext_seqnum_diff(a, b) < 0;
}

//! Check if `a` is before or equal to `b`, taking possible wrap into account.
inline bool ext_seqnum_le(const ext_seqnum_t a, const ext_seqnum_t b) {
return ext_seqnum_diff(a, b) <= 0;
}

//! FEC packet block number.
//! @remarks
//! Defines position of FEC packet block within stream.
Expand Down
8 changes: 4 additions & 4 deletions src/internal_modules/roc_pipeline/receiver_session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -318,8 +318,8 @@ void ReceiverSession::generate_reports(const char* report_cname,
report.sample_rate = source_meter_->encoding().sample_spec.sample_rate();
report.ext_first_seqnum = link_metrics.ext_first_seqnum;
report.ext_last_seqnum = link_metrics.ext_last_seqnum;
report.cum_loss = link_metrics.cum_lost_packets;
report.fract_loss = link_metrics.fract_lost_packets;
report.packet_count = link_metrics.total_packets;
report.cum_loss = link_metrics.lost_packets;
report.jitter = link_metrics.jitter;
report.niq_latency = latency_metrics.niq_latency;
report.niq_stalling = latency_metrics.niq_stalling;
Expand All @@ -343,8 +343,8 @@ void ReceiverSession::generate_reports(const char* report_cname,
report.sample_rate = repair_meter_->encoding().sample_spec.sample_rate();
report.ext_first_seqnum = link_metrics.ext_first_seqnum;
report.ext_last_seqnum = link_metrics.ext_last_seqnum;
report.cum_loss = link_metrics.cum_lost_packets;
report.fract_loss = link_metrics.fract_lost_packets;
report.packet_count = link_metrics.total_packets;
report.cum_loss = link_metrics.lost_packets;
report.jitter = link_metrics.jitter;

reports++;
Expand Down
12 changes: 6 additions & 6 deletions src/internal_modules/roc_pipeline/sender_session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,8 @@ bool SenderSession::create_transport_pipeline(SenderEndpoint* source_endpoint,
}

feedback_monitor_.reset(new (feedback_monitor_) audio::FeedbackMonitor(
*frm_writer, resampler_writer_.get(), config_.feedback, config_.latency,
config_.input_sample_spec));
*frm_writer, *packetizer_, resampler_writer_.get(), config_.feedback,
config_.latency, config_.input_sample_spec));
if (!feedback_monitor_ || !feedback_monitor_->is_valid()) {
return false;
}
Expand Down Expand Up @@ -322,8 +322,8 @@ rtcp::SendReport SenderSession::query_send_stream(core::nanoseconds_t report_tim
report.report_timestamp = report_time;
report.stream_timestamp = timestamp_extractor_->get_mapping(report_time);
report.sample_rate = packetizer_->sample_rate();
report.packet_count = (uint32_t)packet_metrics.packet_count;
report.byte_count = (uint32_t)packet_metrics.payload_count;
report.packet_count = packet_metrics.packet_count;
report.byte_count = packet_metrics.payload_count;

return report;
}
Expand All @@ -342,8 +342,8 @@ SenderSession::notify_send_stream(packet::stream_source_t recv_source_id,
packet::LinkMetrics link_metrics;
link_metrics.ext_first_seqnum = recv_report.ext_first_seqnum;
link_metrics.ext_last_seqnum = recv_report.ext_last_seqnum;
link_metrics.cum_lost_packets = recv_report.cum_loss;
link_metrics.fract_lost_packets = recv_report.fract_loss;
link_metrics.total_packets = recv_report.packet_count;
link_metrics.lost_packets = recv_report.cum_loss;
link_metrics.jitter = recv_report.jitter;
link_metrics.rtt = recv_report.rtt;

Expand Down
1 change: 1 addition & 0 deletions src/internal_modules/roc_rtcp/communicator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,7 @@ bool Communicator::next_send_stream_(size_t new_stream_index) {
}

bool Communicator::next_recv_stream_(size_t new_stream_index) {
// See comment in next_send_stream_().
const size_t next_pkt_recv_stream =
std::max(cur_pkt_recv_stream_, new_stream_index - recv_stream_index_ + 1);

Expand Down
38 changes: 38 additions & 0 deletions src/internal_modules/roc_rtcp/loss_estimator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2024 Roc Streaming authors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

#include "roc_rtcp/loss_estimator.h"

namespace roc {
namespace rtcp {

LossEstimator::LossEstimator()
: prev_total_(0)
, prev_lost_(0) {
}

float LossEstimator::update(const uint64_t total_packets, const int64_t lost_packets) {
float fract_loss = 0;

if (total_packets > prev_total_) {
fract_loss =
float(lost_packets - prev_lost_) / float(total_packets - prev_total_);
}

if (fract_loss < 0) {
fract_loss = 0;
}

prev_total_ = total_packets;
prev_lost_ = lost_packets;

return fract_loss;
}

} // namespace rtcp
} // namespace roc
40 changes: 40 additions & 0 deletions src/internal_modules/roc_rtcp/loss_estimator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright (c) 2024 Roc Streaming authors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

//! @file roc_rtcp/loss_estimator.h
//! @brief Loss estimator.

#ifndef ROC_RTCP_LOSS_ESTIMATOR_H_
#define ROC_RTCP_LOSS_ESTIMATOR_H_

#include "roc_core/stddefs.h"

namespace roc {
namespace rtcp {

//! Computes fractions loss ration since last report.
class LossEstimator {
public:
//! Initialize.
LossEstimator();

//! Update and return fractional loss ration since previous update.
//! @p total_packets defines total count of packets expected.
//! @p lost_packets defines count of packets not received,
//! probably negative dues to duplicates.
float update(uint64_t total_packets, int64_t lost_packets);

private:
uint64_t prev_total_;
int64_t prev_lost_;
};

} // namespace rtcp
} // namespace roc

#endif // ROC_RTCP_LOSS_ESTIMATOR_H_
48 changes: 48 additions & 0 deletions src/internal_modules/roc_rtcp/packet_counter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2024 Roc Streaming authors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

#include "roc_rtcp/packet_counter.h"

namespace roc {
namespace rtcp {

PacketCounter::PacketCounter()
: first_update_(true)
, begin64_(0)
, end64_hi_(0)
, end64_lo_(0)
, counter_(0) {
}

uint64_t PacketCounter::update(const uint32_t begin, const uint32_t end) {
// If this is first update, or begin was changed, reset state.
if (first_update_ || begin != begin64_) {
begin64_ = begin;
end64_hi_ = 0;
end64_lo_ = end;
first_update_ = false;
}

// Update end.
if (int32_t(end - end64_lo_) > 0) {
if (end < end64_lo_) {
end64_hi_ += (uint32_t)-1;
}
end64_lo_ = end;
}

// Update counter.
if (begin64_ <= (end64_hi_ + end64_lo_)) {
counter_ = (end64_hi_ + end64_lo_) - begin64_;
}

return counter_;
}

} // namespace rtcp
} // namespace roc
Loading

0 comments on commit e1909c6

Please sign in to comment.