Add relative_packet_arrival_delay and jitter_buffer_packets_received statistics.
Bug: webrtc:10333 Change-Id: I415e2286b426cbca940fe3a187957531847272ec Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/124780 Commit-Queue: Jakob Ivarsson <jakobi@webrtc.org> Reviewed-by: Minyue Li <minyue@webrtc.org> Cr-Commit-Position: refs/heads/master@{#26976}
This commit is contained in:

committed by
Commit Bot

parent
1aa7581701
commit
445070818c
@ -16,6 +16,7 @@
|
|||||||
#include "modules/audio_coding/neteq/delay_manager.h"
|
#include "modules/audio_coding/neteq/delay_manager.h"
|
||||||
#include "modules/audio_coding/neteq/delay_peak_detector.h"
|
#include "modules/audio_coding/neteq/delay_peak_detector.h"
|
||||||
#include "modules/audio_coding/neteq/packet_buffer.h"
|
#include "modules/audio_coding/neteq/packet_buffer.h"
|
||||||
|
#include "modules/audio_coding/neteq/statistics_calculator.h"
|
||||||
#include "modules/audio_coding/neteq/tick_timer.h"
|
#include "modules/audio_coding/neteq/tick_timer.h"
|
||||||
#include "test/field_trial.h"
|
#include "test/field_trial.h"
|
||||||
#include "test/gtest.h"
|
#include "test/gtest.h"
|
||||||
@ -29,10 +30,11 @@ TEST(DecisionLogic, CreateAndDestroy) {
|
|||||||
DecoderDatabase decoder_database(
|
DecoderDatabase decoder_database(
|
||||||
new rtc::RefCountedObject<MockAudioDecoderFactory>, absl::nullopt);
|
new rtc::RefCountedObject<MockAudioDecoderFactory>, absl::nullopt);
|
||||||
TickTimer tick_timer;
|
TickTimer tick_timer;
|
||||||
|
StatisticsCalculator stats;
|
||||||
PacketBuffer packet_buffer(10, &tick_timer);
|
PacketBuffer packet_buffer(10, &tick_timer);
|
||||||
DelayPeakDetector delay_peak_detector(&tick_timer, false);
|
DelayPeakDetector delay_peak_detector(&tick_timer, false);
|
||||||
auto delay_manager =
|
auto delay_manager = DelayManager::Create(240, 0, false, &delay_peak_detector,
|
||||||
DelayManager::Create(240, 0, false, &delay_peak_detector, &tick_timer);
|
&tick_timer, &stats);
|
||||||
BufferLevelFilter buffer_level_filter;
|
BufferLevelFilter buffer_level_filter;
|
||||||
DecisionLogic* logic = DecisionLogic::Create(
|
DecisionLogic* logic = DecisionLogic::Create(
|
||||||
fs_hz, output_size_samples, false, &decoder_database, packet_buffer,
|
fs_hz, output_size_samples, false, &decoder_database, packet_buffer,
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "absl/memory/memory.h"
|
#include "absl/memory/memory.h"
|
||||||
#include "modules/audio_coding/neteq/delay_peak_detector.h"
|
#include "modules/audio_coding/neteq/delay_peak_detector.h"
|
||||||
#include "modules/audio_coding/neteq/histogram.h"
|
#include "modules/audio_coding/neteq/histogram.h"
|
||||||
|
#include "modules/audio_coding/neteq/statistics_calculator.h"
|
||||||
#include "modules/include/module_common_types_public.h"
|
#include "modules/include/module_common_types_public.h"
|
||||||
#include "rtc_base/checks.h"
|
#include "rtc_base/checks.h"
|
||||||
#include "rtc_base/logging.h"
|
#include "rtc_base/logging.h"
|
||||||
@ -114,6 +115,7 @@ DelayManager::DelayManager(size_t max_packets_in_buffer,
|
|||||||
bool enable_rtx_handling,
|
bool enable_rtx_handling,
|
||||||
DelayPeakDetector* peak_detector,
|
DelayPeakDetector* peak_detector,
|
||||||
const TickTimer* tick_timer,
|
const TickTimer* tick_timer,
|
||||||
|
StatisticsCalculator* statistics,
|
||||||
std::unique_ptr<Histogram> histogram)
|
std::unique_ptr<Histogram> histogram)
|
||||||
: first_packet_received_(false),
|
: first_packet_received_(false),
|
||||||
max_packets_in_buffer_(max_packets_in_buffer),
|
max_packets_in_buffer_(max_packets_in_buffer),
|
||||||
@ -121,6 +123,7 @@ DelayManager::DelayManager(size_t max_packets_in_buffer,
|
|||||||
histogram_quantile_(histogram_quantile),
|
histogram_quantile_(histogram_quantile),
|
||||||
histogram_mode_(histogram_mode),
|
histogram_mode_(histogram_mode),
|
||||||
tick_timer_(tick_timer),
|
tick_timer_(tick_timer),
|
||||||
|
statistics_(statistics),
|
||||||
base_minimum_delay_ms_(base_minimum_delay_ms),
|
base_minimum_delay_ms_(base_minimum_delay_ms),
|
||||||
effective_minimum_delay_ms_(base_minimum_delay_ms),
|
effective_minimum_delay_ms_(base_minimum_delay_ms),
|
||||||
base_target_level_(4), // In Q0 domain.
|
base_target_level_(4), // In Q0 domain.
|
||||||
@ -150,7 +153,8 @@ std::unique_ptr<DelayManager> DelayManager::Create(
|
|||||||
int base_minimum_delay_ms,
|
int base_minimum_delay_ms,
|
||||||
bool enable_rtx_handling,
|
bool enable_rtx_handling,
|
||||||
DelayPeakDetector* peak_detector,
|
DelayPeakDetector* peak_detector,
|
||||||
const TickTimer* tick_timer) {
|
const TickTimer* tick_timer,
|
||||||
|
StatisticsCalculator* statistics) {
|
||||||
int quantile;
|
int quantile;
|
||||||
std::unique_ptr<Histogram> histogram;
|
std::unique_ptr<Histogram> histogram;
|
||||||
HistogramMode mode;
|
HistogramMode mode;
|
||||||
@ -168,7 +172,8 @@ std::unique_ptr<DelayManager> DelayManager::Create(
|
|||||||
}
|
}
|
||||||
return absl::make_unique<DelayManager>(
|
return absl::make_unique<DelayManager>(
|
||||||
max_packets_in_buffer, base_minimum_delay_ms, quantile, mode,
|
max_packets_in_buffer, base_minimum_delay_ms, quantile, mode,
|
||||||
enable_rtx_handling, peak_detector, tick_timer, std::move(histogram));
|
enable_rtx_handling, peak_detector, tick_timer, statistics,
|
||||||
|
std::move(histogram));
|
||||||
}
|
}
|
||||||
|
|
||||||
DelayManager::~DelayManager() {}
|
DelayManager::~DelayManager() {}
|
||||||
@ -234,8 +239,6 @@ int DelayManager::Update(uint16_t sequence_number,
|
|||||||
reordered = true;
|
reordered = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (histogram_mode_) {
|
|
||||||
case RELATIVE_ARRIVAL_DELAY: {
|
|
||||||
int iat_delay = iat_ms - packet_len_ms;
|
int iat_delay = iat_ms - packet_len_ms;
|
||||||
int relative_delay;
|
int relative_delay;
|
||||||
if (reordered) {
|
if (reordered) {
|
||||||
@ -244,6 +247,10 @@ int DelayManager::Update(uint16_t sequence_number,
|
|||||||
UpdateDelayHistory(iat_delay);
|
UpdateDelayHistory(iat_delay);
|
||||||
relative_delay = CalculateRelativePacketArrivalDelay();
|
relative_delay = CalculateRelativePacketArrivalDelay();
|
||||||
}
|
}
|
||||||
|
statistics_->RelativePacketArrivalDelay(relative_delay);
|
||||||
|
|
||||||
|
switch (histogram_mode_) {
|
||||||
|
case RELATIVE_ARRIVAL_DELAY: {
|
||||||
const int index = relative_delay / kBucketSizeMs;
|
const int index = relative_delay / kBucketSizeMs;
|
||||||
if (index < histogram_->NumBuckets()) {
|
if (index < histogram_->NumBuckets()) {
|
||||||
// Maximum delay to register is 2000 ms.
|
// Maximum delay to register is 2000 ms.
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include "absl/types/optional.h"
|
#include "absl/types/optional.h"
|
||||||
#include "modules/audio_coding/neteq/histogram.h"
|
#include "modules/audio_coding/neteq/histogram.h"
|
||||||
|
#include "modules/audio_coding/neteq/statistics_calculator.h"
|
||||||
#include "modules/audio_coding/neteq/tick_timer.h"
|
#include "modules/audio_coding/neteq/tick_timer.h"
|
||||||
#include "rtc_base/constructor_magic.h"
|
#include "rtc_base/constructor_magic.h"
|
||||||
|
|
||||||
@ -40,6 +41,7 @@ class DelayManager {
|
|||||||
bool enable_rtx_handling,
|
bool enable_rtx_handling,
|
||||||
DelayPeakDetector* peak_detector,
|
DelayPeakDetector* peak_detector,
|
||||||
const TickTimer* tick_timer,
|
const TickTimer* tick_timer,
|
||||||
|
StatisticsCalculator* statistics,
|
||||||
std::unique_ptr<Histogram> histogram);
|
std::unique_ptr<Histogram> histogram);
|
||||||
|
|
||||||
// Create a DelayManager object. Notify the delay manager that the packet
|
// Create a DelayManager object. Notify the delay manager that the packet
|
||||||
@ -51,7 +53,8 @@ class DelayManager {
|
|||||||
int base_minimum_delay_ms,
|
int base_minimum_delay_ms,
|
||||||
bool enable_rtx_handling,
|
bool enable_rtx_handling,
|
||||||
DelayPeakDetector* peak_detector,
|
DelayPeakDetector* peak_detector,
|
||||||
const TickTimer* tick_timer);
|
const TickTimer* tick_timer,
|
||||||
|
StatisticsCalculator* statistics);
|
||||||
|
|
||||||
virtual ~DelayManager();
|
virtual ~DelayManager();
|
||||||
|
|
||||||
@ -174,6 +177,7 @@ class DelayManager {
|
|||||||
const int histogram_quantile_;
|
const int histogram_quantile_;
|
||||||
const HistogramMode histogram_mode_;
|
const HistogramMode histogram_mode_;
|
||||||
const TickTimer* tick_timer_;
|
const TickTimer* tick_timer_;
|
||||||
|
StatisticsCalculator* statistics_;
|
||||||
int base_minimum_delay_ms_;
|
int base_minimum_delay_ms_;
|
||||||
// Provides delay which is used by LimitTargetLevel as lower bound on target
|
// Provides delay which is used by LimitTargetLevel as lower bound on target
|
||||||
// delay.
|
// delay.
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include "modules/audio_coding/neteq/histogram.h"
|
#include "modules/audio_coding/neteq/histogram.h"
|
||||||
#include "modules/audio_coding/neteq/mock/mock_delay_peak_detector.h"
|
#include "modules/audio_coding/neteq/mock/mock_delay_peak_detector.h"
|
||||||
#include "modules/audio_coding/neteq/mock/mock_histogram.h"
|
#include "modules/audio_coding/neteq/mock/mock_histogram.h"
|
||||||
|
#include "modules/audio_coding/neteq/mock/mock_statistics_calculator.h"
|
||||||
#include "rtc_base/checks.h"
|
#include "rtc_base/checks.h"
|
||||||
#include "test/field_trial.h"
|
#include "test/field_trial.h"
|
||||||
#include "test/gmock.h"
|
#include "test/gmock.h"
|
||||||
@ -53,6 +54,7 @@ class DelayManagerTest : public ::testing::Test {
|
|||||||
|
|
||||||
std::unique_ptr<DelayManager> dm_;
|
std::unique_ptr<DelayManager> dm_;
|
||||||
TickTimer tick_timer_;
|
TickTimer tick_timer_;
|
||||||
|
MockStatisticsCalculator stats_;
|
||||||
MockDelayPeakDetector detector_;
|
MockDelayPeakDetector detector_;
|
||||||
MockHistogram* mock_histogram_;
|
MockHistogram* mock_histogram_;
|
||||||
uint16_t seq_no_;
|
uint16_t seq_no_;
|
||||||
@ -81,10 +83,11 @@ void DelayManagerTest::RecreateDelayManager() {
|
|||||||
dm_ = absl::make_unique<DelayManager>(
|
dm_ = absl::make_unique<DelayManager>(
|
||||||
kMaxNumberOfPackets, kMinDelayMs, kDefaultHistogramQuantile,
|
kMaxNumberOfPackets, kMinDelayMs, kDefaultHistogramQuantile,
|
||||||
histogram_mode_, enable_rtx_handling_, &detector_, &tick_timer_,
|
histogram_mode_, enable_rtx_handling_, &detector_, &tick_timer_,
|
||||||
std::move(histogram));
|
&stats_, std::move(histogram));
|
||||||
} else {
|
} else {
|
||||||
dm_ = DelayManager::Create(kMaxNumberOfPackets, kMinDelayMs,
|
dm_ = DelayManager::Create(kMaxNumberOfPackets, kMinDelayMs,
|
||||||
enable_rtx_handling_, &detector_, &tick_timer_);
|
enable_rtx_handling_, &detector_, &tick_timer_,
|
||||||
|
&stats_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -709,4 +712,17 @@ TEST_F(DelayManagerTest, RelativeArrivalDelayMode) {
|
|||||||
EXPECT_EQ(0, dm_->Update(seq_no_, ts_, kFs));
|
EXPECT_EQ(0, dm_->Update(seq_no_, ts_, kFs));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(DelayManagerTest, RelativeArrivalDelayStatistic) {
|
||||||
|
SetPacketAudioLength(kFrameSizeMs);
|
||||||
|
InsertNextPacket();
|
||||||
|
|
||||||
|
IncreaseTime(kFrameSizeMs);
|
||||||
|
EXPECT_CALL(stats_, RelativePacketArrivalDelay(0));
|
||||||
|
InsertNextPacket();
|
||||||
|
|
||||||
|
IncreaseTime(2 * kFrameSizeMs);
|
||||||
|
EXPECT_CALL(stats_, RelativePacketArrivalDelay(20));
|
||||||
|
InsertNextPacket();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
@ -71,9 +71,18 @@ struct NetEqLifetimeStatistics {
|
|||||||
uint64_t concealment_events = 0;
|
uint64_t concealment_events = 0;
|
||||||
uint64_t jitter_buffer_delay_ms = 0;
|
uint64_t jitter_buffer_delay_ms = 0;
|
||||||
uint64_t jitter_buffer_emitted_count = 0;
|
uint64_t jitter_buffer_emitted_count = 0;
|
||||||
// Below stat is not part of the spec.
|
// Below stats are not part of the spec.
|
||||||
uint64_t voice_concealed_samples = 0;
|
uint64_t voice_concealed_samples = 0;
|
||||||
uint64_t delayed_packet_outage_samples = 0;
|
uint64_t delayed_packet_outage_samples = 0;
|
||||||
|
// This is sum of relative packet arrival delays of received packets so far.
|
||||||
|
// Since end-to-end delay of a packet is difficult to measure and is not
|
||||||
|
// necessarily useful for measuring jitter buffer performance, we report a
|
||||||
|
// relative packet arrival delay. The relative packet arrival delay of a
|
||||||
|
// packet is defined as the arrival delay compared to the first packet
|
||||||
|
// received, given that it had zero delay. To avoid clock drift, the "first"
|
||||||
|
// packet can be made dynamic.
|
||||||
|
uint64_t relative_packet_arrival_delay_ms = 0;
|
||||||
|
uint64_t jitter_buffer_packets_received = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Metrics that describe the operations performed in NetEq, and the internal
|
// Metrics that describe the operations performed in NetEq, and the internal
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
#include "modules/audio_coding/neteq/delay_manager.h"
|
#include "modules/audio_coding/neteq/delay_manager.h"
|
||||||
#include "modules/audio_coding/neteq/histogram.h"
|
#include "modules/audio_coding/neteq/histogram.h"
|
||||||
|
#include "modules/audio_coding/neteq/statistics_calculator.h"
|
||||||
#include "test/gmock.h"
|
#include "test/gmock.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
@ -28,6 +29,7 @@ class MockDelayManager : public DelayManager {
|
|||||||
bool enable_rtx_handling,
|
bool enable_rtx_handling,
|
||||||
DelayPeakDetector* peak_detector,
|
DelayPeakDetector* peak_detector,
|
||||||
const TickTimer* tick_timer,
|
const TickTimer* tick_timer,
|
||||||
|
StatisticsCalculator* stats,
|
||||||
std::unique_ptr<Histogram> histogram)
|
std::unique_ptr<Histogram> histogram)
|
||||||
: DelayManager(max_packets_in_buffer,
|
: DelayManager(max_packets_in_buffer,
|
||||||
base_min_target_delay_ms,
|
base_min_target_delay_ms,
|
||||||
@ -36,6 +38,7 @@ class MockDelayManager : public DelayManager {
|
|||||||
enable_rtx_handling,
|
enable_rtx_handling,
|
||||||
peak_detector,
|
peak_detector,
|
||||||
tick_timer,
|
tick_timer,
|
||||||
|
stats,
|
||||||
std::move(histogram)) {}
|
std::move(histogram)) {}
|
||||||
virtual ~MockDelayManager() { Die(); }
|
virtual ~MockDelayManager() { Die(); }
|
||||||
MOCK_METHOD0(Die, void());
|
MOCK_METHOD0(Die, void());
|
||||||
|
@ -21,6 +21,7 @@ class MockStatisticsCalculator : public StatisticsCalculator {
|
|||||||
public:
|
public:
|
||||||
MOCK_METHOD1(PacketsDiscarded, void(size_t num_packets));
|
MOCK_METHOD1(PacketsDiscarded, void(size_t num_packets));
|
||||||
MOCK_METHOD1(SecondaryPacketsDiscarded, void(size_t num_packets));
|
MOCK_METHOD1(SecondaryPacketsDiscarded, void(size_t num_packets));
|
||||||
|
MOCK_METHOD1(RelativePacketArrivalDelay, void(size_t delay_ms));
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
#include "modules/audio_coding/neteq/post_decode_vad.h"
|
#include "modules/audio_coding/neteq/post_decode_vad.h"
|
||||||
#include "modules/audio_coding/neteq/preemptive_expand.h"
|
#include "modules/audio_coding/neteq/preemptive_expand.h"
|
||||||
#include "modules/audio_coding/neteq/red_payload_splitter.h"
|
#include "modules/audio_coding/neteq/red_payload_splitter.h"
|
||||||
|
#include "modules/audio_coding/neteq/statistics_calculator.h"
|
||||||
#include "modules/audio_coding/neteq/sync_buffer.h"
|
#include "modules/audio_coding/neteq/sync_buffer.h"
|
||||||
#include "modules/audio_coding/neteq/tick_timer.h"
|
#include "modules/audio_coding/neteq/tick_timer.h"
|
||||||
#include "modules/audio_coding/neteq/time_stretch.h"
|
#include "modules/audio_coding/neteq/time_stretch.h"
|
||||||
@ -58,6 +59,7 @@ NetEqImpl::Dependencies::Dependencies(
|
|||||||
const NetEq::Config& config,
|
const NetEq::Config& config,
|
||||||
const rtc::scoped_refptr<AudioDecoderFactory>& decoder_factory)
|
const rtc::scoped_refptr<AudioDecoderFactory>& decoder_factory)
|
||||||
: tick_timer(new TickTimer),
|
: tick_timer(new TickTimer),
|
||||||
|
stats(new StatisticsCalculator),
|
||||||
buffer_level_filter(new BufferLevelFilter),
|
buffer_level_filter(new BufferLevelFilter),
|
||||||
decoder_database(
|
decoder_database(
|
||||||
new DecoderDatabase(decoder_factory, config.codec_pair_id)),
|
new DecoderDatabase(decoder_factory, config.codec_pair_id)),
|
||||||
@ -67,7 +69,8 @@ NetEqImpl::Dependencies::Dependencies(
|
|||||||
config.min_delay_ms,
|
config.min_delay_ms,
|
||||||
config.enable_rtx_handling,
|
config.enable_rtx_handling,
|
||||||
delay_peak_detector.get(),
|
delay_peak_detector.get(),
|
||||||
tick_timer.get())),
|
tick_timer.get(),
|
||||||
|
stats.get())),
|
||||||
dtmf_buffer(new DtmfBuffer(config.sample_rate_hz)),
|
dtmf_buffer(new DtmfBuffer(config.sample_rate_hz)),
|
||||||
dtmf_tone_generator(new DtmfToneGenerator),
|
dtmf_tone_generator(new DtmfToneGenerator),
|
||||||
packet_buffer(
|
packet_buffer(
|
||||||
@ -97,6 +100,7 @@ NetEqImpl::NetEqImpl(const NetEq::Config& config,
|
|||||||
expand_factory_(std::move(deps.expand_factory)),
|
expand_factory_(std::move(deps.expand_factory)),
|
||||||
accelerate_factory_(std::move(deps.accelerate_factory)),
|
accelerate_factory_(std::move(deps.accelerate_factory)),
|
||||||
preemptive_expand_factory_(std::move(deps.preemptive_expand_factory)),
|
preemptive_expand_factory_(std::move(deps.preemptive_expand_factory)),
|
||||||
|
stats_(std::move(deps.stats)),
|
||||||
last_mode_(kModeNormal),
|
last_mode_(kModeNormal),
|
||||||
decoded_buffer_length_(kMaxFrameSize),
|
decoded_buffer_length_(kMaxFrameSize),
|
||||||
decoded_buffer_(new int16_t[decoded_buffer_length_]),
|
decoded_buffer_(new int16_t[decoded_buffer_length_]),
|
||||||
@ -233,7 +237,7 @@ void NetEqImpl::SetCodecs(const std::map<int, SdpAudioFormat>& codecs) {
|
|||||||
const std::vector<int> changed_payload_types =
|
const std::vector<int> changed_payload_types =
|
||||||
decoder_database_->SetCodecs(codecs);
|
decoder_database_->SetCodecs(codecs);
|
||||||
for (const int pt : changed_payload_types) {
|
for (const int pt : changed_payload_types) {
|
||||||
packet_buffer_->DiscardPacketsWithPayloadType(pt, &stats_);
|
packet_buffer_->DiscardPacketsWithPayloadType(pt, stats_.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,7 +255,8 @@ int NetEqImpl::RemovePayloadType(uint8_t rtp_payload_type) {
|
|||||||
rtc::CritScope lock(&crit_sect_);
|
rtc::CritScope lock(&crit_sect_);
|
||||||
int ret = decoder_database_->Remove(rtp_payload_type);
|
int ret = decoder_database_->Remove(rtp_payload_type);
|
||||||
if (ret == DecoderDatabase::kOK || ret == DecoderDatabase::kDecoderNotFound) {
|
if (ret == DecoderDatabase::kOK || ret == DecoderDatabase::kDecoderNotFound) {
|
||||||
packet_buffer_->DiscardPacketsWithPayloadType(rtp_payload_type, &stats_);
|
packet_buffer_->DiscardPacketsWithPayloadType(rtp_payload_type,
|
||||||
|
stats_.get());
|
||||||
return kOK;
|
return kOK;
|
||||||
}
|
}
|
||||||
return kFail;
|
return kFail;
|
||||||
@ -329,20 +334,21 @@ int NetEqImpl::NetworkStatistics(NetEqNetworkStatistics* stats) {
|
|||||||
assert(decision_logic_.get());
|
assert(decision_logic_.get());
|
||||||
const int ms_per_packet = rtc::dchecked_cast<int>(
|
const int ms_per_packet = rtc::dchecked_cast<int>(
|
||||||
decision_logic_->packet_length_samples() / (fs_hz_ / 1000));
|
decision_logic_->packet_length_samples() / (fs_hz_ / 1000));
|
||||||
stats_.PopulateDelayManagerStats(ms_per_packet, *delay_manager_.get(), stats);
|
stats_->PopulateDelayManagerStats(ms_per_packet, *delay_manager_.get(),
|
||||||
stats_.GetNetworkStatistics(fs_hz_, total_samples_in_buffers,
|
stats);
|
||||||
|
stats_->GetNetworkStatistics(fs_hz_, total_samples_in_buffers,
|
||||||
decoder_frame_length_, stats);
|
decoder_frame_length_, stats);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetEqLifetimeStatistics NetEqImpl::GetLifetimeStatistics() const {
|
NetEqLifetimeStatistics NetEqImpl::GetLifetimeStatistics() const {
|
||||||
rtc::CritScope lock(&crit_sect_);
|
rtc::CritScope lock(&crit_sect_);
|
||||||
return stats_.GetLifetimeStatistics();
|
return stats_->GetLifetimeStatistics();
|
||||||
}
|
}
|
||||||
|
|
||||||
NetEqOperationsAndState NetEqImpl::GetOperationsAndState() const {
|
NetEqOperationsAndState NetEqImpl::GetOperationsAndState() const {
|
||||||
rtc::CritScope lock(&crit_sect_);
|
rtc::CritScope lock(&crit_sect_);
|
||||||
auto result = stats_.GetOperationsAndState();
|
auto result = stats_->GetOperationsAndState();
|
||||||
result.current_buffer_size_ms =
|
result.current_buffer_size_ms =
|
||||||
(packet_buffer_->NumSamplesInBuffer(decoder_frame_length_) +
|
(packet_buffer_->NumSamplesInBuffer(decoder_frame_length_) +
|
||||||
sync_buffer_->FutureLength()) *
|
sync_buffer_->FutureLength()) *
|
||||||
@ -469,6 +475,7 @@ int NetEqImpl::InsertPacketInternal(const RTPHeader& rtp_header,
|
|||||||
RTC_LOG_F(LS_ERROR) << "payload is empty";
|
RTC_LOG_F(LS_ERROR) << "payload is empty";
|
||||||
return kInvalidPointer;
|
return kInvalidPointer;
|
||||||
}
|
}
|
||||||
|
stats_->ReceivedPacket();
|
||||||
|
|
||||||
PacketList packet_list;
|
PacketList packet_list;
|
||||||
// Insert packet in a packet list.
|
// Insert packet in a packet list.
|
||||||
@ -654,7 +661,7 @@ int NetEqImpl::InsertPacketInternal(const RTPHeader& rtp_header,
|
|||||||
// Insert packets in buffer.
|
// Insert packets in buffer.
|
||||||
const int ret = packet_buffer_->InsertPacketList(
|
const int ret = packet_buffer_->InsertPacketList(
|
||||||
&parsed_packet_list, *decoder_database_, ¤t_rtp_payload_type_,
|
&parsed_packet_list, *decoder_database_, ¤t_rtp_payload_type_,
|
||||||
¤t_cng_rtp_payload_type_, &stats_);
|
¤t_cng_rtp_payload_type_, stats_.get());
|
||||||
if (ret == PacketBuffer::kFlushed) {
|
if (ret == PacketBuffer::kFlushed) {
|
||||||
// Reset DSP timestamp etc. if packet buffer flushed.
|
// Reset DSP timestamp etc. if packet buffer flushed.
|
||||||
new_codec_ = true;
|
new_codec_ = true;
|
||||||
@ -751,8 +758,8 @@ int NetEqImpl::GetAudioInternal(AudioFrame* audio_frame,
|
|||||||
*muted = false;
|
*muted = false;
|
||||||
last_decoded_timestamps_.clear();
|
last_decoded_timestamps_.clear();
|
||||||
tick_timer_->Increment();
|
tick_timer_->Increment();
|
||||||
stats_.IncreaseCounter(output_size_samples_, fs_hz_);
|
stats_->IncreaseCounter(output_size_samples_, fs_hz_);
|
||||||
const auto lifetime_stats = stats_.GetLifetimeStatistics();
|
const auto lifetime_stats = stats_->GetLifetimeStatistics();
|
||||||
expand_uma_logger_.UpdateSampleCounter(lifetime_stats.concealed_samples,
|
expand_uma_logger_.UpdateSampleCounter(lifetime_stats.concealed_samples,
|
||||||
fs_hz_);
|
fs_hz_);
|
||||||
speech_expand_uma_logger_.UpdateSampleCounter(
|
speech_expand_uma_logger_.UpdateSampleCounter(
|
||||||
@ -772,7 +779,7 @@ int NetEqImpl::GetAudioInternal(AudioFrame* audio_frame,
|
|||||||
: timestamp_scaler_->ToExternal(playout_timestamp_) -
|
: timestamp_scaler_->ToExternal(playout_timestamp_) -
|
||||||
static_cast<uint32_t>(audio_frame->samples_per_channel_);
|
static_cast<uint32_t>(audio_frame->samples_per_channel_);
|
||||||
audio_frame->num_channels_ = sync_buffer_->Channels();
|
audio_frame->num_channels_ = sync_buffer_->Channels();
|
||||||
stats_.ExpandedNoiseSamples(output_size_samples_, false);
|
stats_->ExpandedNoiseSamples(output_size_samples_, false);
|
||||||
*muted = true;
|
*muted = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -981,7 +988,7 @@ int NetEqImpl::GetDecision(Operations* operation,
|
|||||||
if (!new_codec_) {
|
if (!new_codec_) {
|
||||||
const uint32_t five_seconds_samples = 5 * fs_hz_;
|
const uint32_t five_seconds_samples = 5 * fs_hz_;
|
||||||
packet_buffer_->DiscardOldPackets(end_timestamp, five_seconds_samples,
|
packet_buffer_->DiscardOldPackets(end_timestamp, five_seconds_samples,
|
||||||
&stats_);
|
stats_.get());
|
||||||
}
|
}
|
||||||
const Packet* packet = packet_buffer_->PeekNextPacket();
|
const Packet* packet = packet_buffer_->PeekNextPacket();
|
||||||
|
|
||||||
@ -1001,12 +1008,14 @@ int NetEqImpl::GetDecision(Operations* operation,
|
|||||||
(end_timestamp >= packet->timestamp ||
|
(end_timestamp >= packet->timestamp ||
|
||||||
end_timestamp + generated_noise_samples > packet->timestamp)) {
|
end_timestamp + generated_noise_samples > packet->timestamp)) {
|
||||||
// Don't use this packet, discard it.
|
// Don't use this packet, discard it.
|
||||||
if (packet_buffer_->DiscardNextPacket(&stats_) != PacketBuffer::kOK) {
|
if (packet_buffer_->DiscardNextPacket(stats_.get()) !=
|
||||||
|
PacketBuffer::kOK) {
|
||||||
assert(false); // Must be ok by design.
|
assert(false); // Must be ok by design.
|
||||||
}
|
}
|
||||||
// Check buffer again.
|
// Check buffer again.
|
||||||
if (!new_codec_) {
|
if (!new_codec_) {
|
||||||
packet_buffer_->DiscardOldPackets(end_timestamp, 5 * fs_hz_, &stats_);
|
packet_buffer_->DiscardOldPackets(end_timestamp, 5 * fs_hz_,
|
||||||
|
stats_.get());
|
||||||
}
|
}
|
||||||
packet = packet_buffer_->PeekNextPacket();
|
packet = packet_buffer_->PeekNextPacket();
|
||||||
}
|
}
|
||||||
@ -1088,7 +1097,7 @@ int NetEqImpl::GetDecision(Operations* operation,
|
|||||||
decision_logic_->SoftReset();
|
decision_logic_->SoftReset();
|
||||||
buffer_level_filter_->Reset();
|
buffer_level_filter_->Reset();
|
||||||
delay_manager_->Reset();
|
delay_manager_->Reset();
|
||||||
stats_.ResetMcu();
|
stats_->ResetMcu();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t required_samples = output_size_samples_;
|
size_t required_samples = output_size_samples_;
|
||||||
@ -1193,7 +1202,7 @@ int NetEqImpl::GetDecision(Operations* operation,
|
|||||||
// if comfort noise is not played. If comfort noise was just played,
|
// if comfort noise is not played. If comfort noise was just played,
|
||||||
// this adjustment of timestamp is only done to get back in sync with the
|
// this adjustment of timestamp is only done to get back in sync with the
|
||||||
// stream timestamp; no loss to report.
|
// stream timestamp; no loss to report.
|
||||||
stats_.LostSamples(packet->timestamp - end_timestamp);
|
stats_->LostSamples(packet->timestamp - end_timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*operation != kRfc3389Cng) {
|
if (*operation != kRfc3389Cng) {
|
||||||
@ -1460,10 +1469,10 @@ void NetEqImpl::DoMerge(int16_t* decoded_buffer,
|
|||||||
// Update in-call and post-call statistics.
|
// Update in-call and post-call statistics.
|
||||||
if (expand_->MuteFactor(0) == 0) {
|
if (expand_->MuteFactor(0) == 0) {
|
||||||
// Expand generates only noise.
|
// Expand generates only noise.
|
||||||
stats_.ExpandedNoiseSamplesCorrection(expand_length_correction);
|
stats_->ExpandedNoiseSamplesCorrection(expand_length_correction);
|
||||||
} else {
|
} else {
|
||||||
// Expansion generates more than only noise.
|
// Expansion generates more than only noise.
|
||||||
stats_.ExpandedVoiceSamplesCorrection(expand_length_correction);
|
stats_->ExpandedVoiceSamplesCorrection(expand_length_correction);
|
||||||
}
|
}
|
||||||
|
|
||||||
last_mode_ = kModeMerge;
|
last_mode_ = kModeMerge;
|
||||||
@ -1504,11 +1513,11 @@ bool NetEqImpl::DoCodecPlc() {
|
|||||||
if (std::all_of(concealment_audio_.cbegin(), concealment_audio_.cend(),
|
if (std::all_of(concealment_audio_.cbegin(), concealment_audio_.cend(),
|
||||||
[](int16_t i) { return i == 0; })) {
|
[](int16_t i) { return i == 0; })) {
|
||||||
// Expand operation generates only noise.
|
// Expand operation generates only noise.
|
||||||
stats_.ExpandedNoiseSamples(concealed_samples_per_channel,
|
stats_->ExpandedNoiseSamples(concealed_samples_per_channel,
|
||||||
is_new_concealment_event);
|
is_new_concealment_event);
|
||||||
} else {
|
} else {
|
||||||
// Expand operation generates more than only noise.
|
// Expand operation generates more than only noise.
|
||||||
stats_.ExpandedVoiceSamples(concealed_samples_per_channel,
|
stats_->ExpandedVoiceSamples(concealed_samples_per_channel,
|
||||||
is_new_concealment_event);
|
is_new_concealment_event);
|
||||||
}
|
}
|
||||||
last_mode_ = kModeCodecPlc;
|
last_mode_ = kModeCodecPlc;
|
||||||
@ -1530,10 +1539,10 @@ int NetEqImpl::DoExpand(bool play_dtmf) {
|
|||||||
// Update in-call and post-call statistics.
|
// Update in-call and post-call statistics.
|
||||||
if (expand_->MuteFactor(0) == 0) {
|
if (expand_->MuteFactor(0) == 0) {
|
||||||
// Expand operation generates only noise.
|
// Expand operation generates only noise.
|
||||||
stats_.ExpandedNoiseSamples(length, is_new_concealment_event);
|
stats_->ExpandedNoiseSamples(length, is_new_concealment_event);
|
||||||
} else {
|
} else {
|
||||||
// Expand operation generates more than only noise.
|
// Expand operation generates more than only noise.
|
||||||
stats_.ExpandedVoiceSamples(length, is_new_concealment_event);
|
stats_->ExpandedVoiceSamples(length, is_new_concealment_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
last_mode_ = kModeExpand;
|
last_mode_ = kModeExpand;
|
||||||
@ -1582,7 +1591,7 @@ int NetEqImpl::DoAccelerate(int16_t* decoded_buffer,
|
|||||||
Accelerate::ReturnCodes return_code =
|
Accelerate::ReturnCodes return_code =
|
||||||
accelerate_->Process(decoded_buffer, decoded_length, fast_accelerate,
|
accelerate_->Process(decoded_buffer, decoded_length, fast_accelerate,
|
||||||
algorithm_buffer_.get(), &samples_removed);
|
algorithm_buffer_.get(), &samples_removed);
|
||||||
stats_.AcceleratedSamples(samples_removed);
|
stats_->AcceleratedSamples(samples_removed);
|
||||||
switch (return_code) {
|
switch (return_code) {
|
||||||
case Accelerate::kSuccess:
|
case Accelerate::kSuccess:
|
||||||
last_mode_ = kModeAccelerateSuccess;
|
last_mode_ = kModeAccelerateSuccess;
|
||||||
@ -1660,7 +1669,7 @@ int NetEqImpl::DoPreemptiveExpand(int16_t* decoded_buffer,
|
|||||||
PreemptiveExpand::ReturnCodes return_code = preemptive_expand_->Process(
|
PreemptiveExpand::ReturnCodes return_code = preemptive_expand_->Process(
|
||||||
decoded_buffer, decoded_length, old_borrowed_samples_per_channel,
|
decoded_buffer, decoded_length, old_borrowed_samples_per_channel,
|
||||||
algorithm_buffer_.get(), &samples_added);
|
algorithm_buffer_.get(), &samples_added);
|
||||||
stats_.PreemptiveExpandedSamples(samples_added);
|
stats_->PreemptiveExpandedSamples(samples_added);
|
||||||
switch (return_code) {
|
switch (return_code) {
|
||||||
case PreemptiveExpand::kSuccess:
|
case PreemptiveExpand::kSuccess:
|
||||||
last_mode_ = kModePreemptiveExpandSuccess;
|
last_mode_ = kModePreemptiveExpandSuccess;
|
||||||
@ -1875,7 +1884,7 @@ int NetEqImpl::ExtractPackets(size_t required_samples,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
const uint64_t waiting_time_ms = packet->waiting_time->ElapsedMs();
|
const uint64_t waiting_time_ms = packet->waiting_time->ElapsedMs();
|
||||||
stats_.StoreWaitingTime(waiting_time_ms);
|
stats_->StoreWaitingTime(waiting_time_ms);
|
||||||
RTC_DCHECK(!packet->empty());
|
RTC_DCHECK(!packet->empty());
|
||||||
|
|
||||||
if (first_packet) {
|
if (first_packet) {
|
||||||
@ -1899,7 +1908,7 @@ int NetEqImpl::ExtractPackets(size_t required_samples,
|
|||||||
packet_duration = packet->frame->Duration();
|
packet_duration = packet->frame->Duration();
|
||||||
// TODO(ossu): Is this the correct way to track Opus FEC packets?
|
// TODO(ossu): Is this the correct way to track Opus FEC packets?
|
||||||
if (packet->priority.codec_level > 0) {
|
if (packet->priority.codec_level > 0) {
|
||||||
stats_.SecondaryDecodedSamples(
|
stats_->SecondaryDecodedSamples(
|
||||||
rtc::dchecked_cast<int>(packet_duration));
|
rtc::dchecked_cast<int>(packet_duration));
|
||||||
}
|
}
|
||||||
} else if (!has_cng_packet) {
|
} else if (!has_cng_packet) {
|
||||||
@ -1915,7 +1924,7 @@ int NetEqImpl::ExtractPackets(size_t required_samples,
|
|||||||
}
|
}
|
||||||
extracted_samples = packet->timestamp - first_timestamp + packet_duration;
|
extracted_samples = packet->timestamp - first_timestamp + packet_duration;
|
||||||
|
|
||||||
stats_.JitterBufferDelay(packet_duration, waiting_time_ms);
|
stats_->JitterBufferDelay(packet_duration, waiting_time_ms);
|
||||||
|
|
||||||
packet_list->push_back(std::move(*packet)); // Store packet in list.
|
packet_list->push_back(std::move(*packet)); // Store packet in list.
|
||||||
packet = absl::nullopt; // Ensure it's never used after the move.
|
packet = absl::nullopt; // Ensure it's never used after the move.
|
||||||
@ -1943,7 +1952,7 @@ int NetEqImpl::ExtractPackets(size_t required_samples,
|
|||||||
// we could end up in the situation where we never decode anything, since
|
// we could end up in the situation where we never decode anything, since
|
||||||
// all incoming packets are considered too old but the buffer will also
|
// all incoming packets are considered too old but the buffer will also
|
||||||
// never be flooded and flushed.
|
// never be flooded and flushed.
|
||||||
packet_buffer_->DiscardAllOldPackets(timestamp_, &stats_);
|
packet_buffer_->DiscardAllOldPackets(timestamp_, stats_.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
return rtc::dchecked_cast<int>(extracted_samples);
|
return rtc::dchecked_cast<int>(extracted_samples);
|
||||||
@ -1953,7 +1962,7 @@ void NetEqImpl::UpdatePlcComponents(int fs_hz, size_t channels) {
|
|||||||
// Delete objects and create new ones.
|
// Delete objects and create new ones.
|
||||||
expand_.reset(expand_factory_->Create(background_noise_.get(),
|
expand_.reset(expand_factory_->Create(background_noise_.get(),
|
||||||
sync_buffer_.get(), &random_vector_,
|
sync_buffer_.get(), &random_vector_,
|
||||||
&stats_, fs_hz, channels));
|
stats_.get(), fs_hz, channels));
|
||||||
merge_.reset(new Merge(fs_hz, channels, expand_.get(), sync_buffer_.get()));
|
merge_.reset(new Merge(fs_hz, channels, expand_.get(), sync_buffer_.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,6 +99,7 @@ class NetEqImpl : public webrtc::NetEq {
|
|||||||
~Dependencies();
|
~Dependencies();
|
||||||
|
|
||||||
std::unique_ptr<TickTimer> tick_timer;
|
std::unique_ptr<TickTimer> tick_timer;
|
||||||
|
std::unique_ptr<StatisticsCalculator> stats;
|
||||||
std::unique_ptr<BufferLevelFilter> buffer_level_filter;
|
std::unique_ptr<BufferLevelFilter> buffer_level_filter;
|
||||||
std::unique_ptr<DecoderDatabase> decoder_database;
|
std::unique_ptr<DecoderDatabase> decoder_database;
|
||||||
std::unique_ptr<DelayPeakDetector> delay_peak_detector;
|
std::unique_ptr<DelayPeakDetector> delay_peak_detector;
|
||||||
@ -361,6 +362,7 @@ class NetEqImpl : public webrtc::NetEq {
|
|||||||
RTC_GUARDED_BY(crit_sect_);
|
RTC_GUARDED_BY(crit_sect_);
|
||||||
const std::unique_ptr<PreemptiveExpandFactory> preemptive_expand_factory_
|
const std::unique_ptr<PreemptiveExpandFactory> preemptive_expand_factory_
|
||||||
RTC_GUARDED_BY(crit_sect_);
|
RTC_GUARDED_BY(crit_sect_);
|
||||||
|
const std::unique_ptr<StatisticsCalculator> stats_ RTC_GUARDED_BY(crit_sect_);
|
||||||
|
|
||||||
std::unique_ptr<BackgroundNoise> background_noise_ RTC_GUARDED_BY(crit_sect_);
|
std::unique_ptr<BackgroundNoise> background_noise_ RTC_GUARDED_BY(crit_sect_);
|
||||||
std::unique_ptr<DecisionLogic> decision_logic_ RTC_GUARDED_BY(crit_sect_);
|
std::unique_ptr<DecisionLogic> decision_logic_ RTC_GUARDED_BY(crit_sect_);
|
||||||
@ -375,7 +377,6 @@ class NetEqImpl : public webrtc::NetEq {
|
|||||||
RTC_GUARDED_BY(crit_sect_);
|
RTC_GUARDED_BY(crit_sect_);
|
||||||
RandomVector random_vector_ RTC_GUARDED_BY(crit_sect_);
|
RandomVector random_vector_ RTC_GUARDED_BY(crit_sect_);
|
||||||
std::unique_ptr<ComfortNoise> comfort_noise_ RTC_GUARDED_BY(crit_sect_);
|
std::unique_ptr<ComfortNoise> comfort_noise_ RTC_GUARDED_BY(crit_sect_);
|
||||||
StatisticsCalculator stats_ RTC_GUARDED_BY(crit_sect_);
|
|
||||||
int fs_hz_ RTC_GUARDED_BY(crit_sect_);
|
int fs_hz_ RTC_GUARDED_BY(crit_sect_);
|
||||||
int fs_mult_ RTC_GUARDED_BY(crit_sect_);
|
int fs_mult_ RTC_GUARDED_BY(crit_sect_);
|
||||||
int last_output_sample_rate_hz_ RTC_GUARDED_BY(crit_sect_);
|
int last_output_sample_rate_hz_ RTC_GUARDED_BY(crit_sect_);
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "modules/audio_coding/neteq/mock/mock_red_payload_splitter.h"
|
#include "modules/audio_coding/neteq/mock/mock_red_payload_splitter.h"
|
||||||
#include "modules/audio_coding/neteq/neteq_impl.h"
|
#include "modules/audio_coding/neteq/neteq_impl.h"
|
||||||
#include "modules/audio_coding/neteq/preemptive_expand.h"
|
#include "modules/audio_coding/neteq/preemptive_expand.h"
|
||||||
|
#include "modules/audio_coding/neteq/statistics_calculator.h"
|
||||||
#include "modules/audio_coding/neteq/sync_buffer.h"
|
#include "modules/audio_coding/neteq/sync_buffer.h"
|
||||||
#include "modules/audio_coding/neteq/timestamp_scaler.h"
|
#include "modules/audio_coding/neteq/timestamp_scaler.h"
|
||||||
#include "rtc_base/numerics/safe_conversions.h"
|
#include "rtc_base/numerics/safe_conversions.h"
|
||||||
@ -100,7 +101,7 @@ class NetEqImplTest : public ::testing::Test {
|
|||||||
config_.max_packets_in_buffer, config_.min_delay_ms, 1020054733,
|
config_.max_packets_in_buffer, config_.min_delay_ms, 1020054733,
|
||||||
DelayManager::HistogramMode::INTER_ARRIVAL_TIME,
|
DelayManager::HistogramMode::INTER_ARRIVAL_TIME,
|
||||||
config_.enable_rtx_handling, delay_peak_detector_, tick_timer_,
|
config_.enable_rtx_handling, delay_peak_detector_, tick_timer_,
|
||||||
absl::make_unique<Histogram>(50, 32745)));
|
deps.stats.get(), absl::make_unique<Histogram>(50, 32745)));
|
||||||
mock_delay_manager_ = mock.get();
|
mock_delay_manager_ = mock.get();
|
||||||
EXPECT_CALL(*mock_delay_manager_, set_streaming_mode(false)).Times(1);
|
EXPECT_CALL(*mock_delay_manager_, set_streaming_mode(false)).Times(1);
|
||||||
deps.delay_manager = std::move(mock);
|
deps.delay_manager = std::move(mock);
|
||||||
|
@ -258,6 +258,14 @@ void StatisticsCalculator::FlushedPacketBuffer() {
|
|||||||
buffer_full_counter_.RegisterSample();
|
buffer_full_counter_.RegisterSample();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StatisticsCalculator::ReceivedPacket() {
|
||||||
|
++lifetime_stats_.jitter_buffer_packets_received;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatisticsCalculator::RelativePacketArrivalDelay(size_t delay_ms) {
|
||||||
|
lifetime_stats_.relative_packet_arrival_delay_ms += delay_ms;
|
||||||
|
}
|
||||||
|
|
||||||
void StatisticsCalculator::LogDelayedPacketOutageEvent(int num_samples,
|
void StatisticsCalculator::LogDelayedPacketOutageEvent(int num_samples,
|
||||||
int fs_hz) {
|
int fs_hz) {
|
||||||
int outage_duration_ms = num_samples / (fs_hz / 1000);
|
int outage_duration_ms = num_samples / (fs_hz / 1000);
|
||||||
|
@ -83,9 +83,15 @@ class StatisticsCalculator {
|
|||||||
// Reports that |num_samples| samples were decoded from secondary packets.
|
// Reports that |num_samples| samples were decoded from secondary packets.
|
||||||
void SecondaryDecodedSamples(int num_samples);
|
void SecondaryDecodedSamples(int num_samples);
|
||||||
|
|
||||||
// Rerport that the packet buffer was flushed.
|
// Reports that the packet buffer was flushed.
|
||||||
void FlushedPacketBuffer();
|
void FlushedPacketBuffer();
|
||||||
|
|
||||||
|
// Reports that the jitter buffer received a packet.
|
||||||
|
void ReceivedPacket();
|
||||||
|
|
||||||
|
// Reports that a received packet was delayed by |delay_ms| milliseconds.
|
||||||
|
virtual void RelativePacketArrivalDelay(size_t delay_ms);
|
||||||
|
|
||||||
// Logs a delayed packet outage event of |num_samples| expanded at a sample
|
// Logs a delayed packet outage event of |num_samples| expanded at a sample
|
||||||
// rate of |fs_hz|. A delayed packet outage event is defined as an expand
|
// rate of |fs_hz|. A delayed packet outage event is defined as an expand
|
||||||
// period caused not by an actual packet loss, but by a delayed packet.
|
// period caused not by an actual packet loss, but by a delayed packet.
|
||||||
|
@ -104,4 +104,28 @@ TEST(StatisticsCalculator, ExpandedSamplesCorrection) {
|
|||||||
EXPECT_EQ((50u << 14) / k10MsSamples, stats_output.speech_expand_rate);
|
EXPECT_EQ((50u << 14) / k10MsSamples, stats_output.speech_expand_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(StatisticsCalculator, RelativePacketArrivalDelay) {
|
||||||
|
StatisticsCalculator stats;
|
||||||
|
|
||||||
|
stats.RelativePacketArrivalDelay(50);
|
||||||
|
NetEqLifetimeStatistics stats_output = stats.GetLifetimeStatistics();
|
||||||
|
EXPECT_EQ(50u, stats_output.relative_packet_arrival_delay_ms);
|
||||||
|
|
||||||
|
stats.RelativePacketArrivalDelay(20);
|
||||||
|
stats_output = stats.GetLifetimeStatistics();
|
||||||
|
EXPECT_EQ(70u, stats_output.relative_packet_arrival_delay_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StatisticsCalculator, ReceivedPacket) {
|
||||||
|
StatisticsCalculator stats;
|
||||||
|
|
||||||
|
stats.ReceivedPacket();
|
||||||
|
NetEqLifetimeStatistics stats_output = stats.GetLifetimeStatistics();
|
||||||
|
EXPECT_EQ(1u, stats_output.jitter_buffer_packets_received);
|
||||||
|
|
||||||
|
stats.ReceivedPacket();
|
||||||
|
stats_output = stats.GetLifetimeStatistics();
|
||||||
|
EXPECT_EQ(2u, stats_output.jitter_buffer_packets_received);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
Reference in New Issue
Block a user