Add NetEq config flag that enables RTX handling.
When enabled, the delay manager is updated with reordered packets. It also makes the peak detector ignore the reordered packets. Change-Id: I2bdc99764cc76b15e613ed3dc75f83aaf66eee4e Bug: webrtc:10178 Reviewed-on: https://webrtc-review.googlesource.com/c/116481 Commit-Queue: Jakob Ivarsson <jakobi@webrtc.org> Reviewed-by: Minyue Li <minyue@webrtc.org> Cr-Commit-Position: refs/heads/master@{#26187}
This commit is contained in:

committed by
Commit Bot

parent
d8bd75079b
commit
39b934ba2e
@ -30,7 +30,7 @@ TEST(DecisionLogic, CreateAndDestroy) {
|
||||
new rtc::RefCountedObject<MockAudioDecoderFactory>, absl::nullopt);
|
||||
TickTimer tick_timer;
|
||||
PacketBuffer packet_buffer(10, &tick_timer);
|
||||
DelayPeakDetector delay_peak_detector(&tick_timer);
|
||||
DelayPeakDetector delay_peak_detector(&tick_timer, false);
|
||||
DelayManager delay_manager(240, 0, &delay_peak_detector, &tick_timer);
|
||||
BufferLevelFilter buffer_level_filter;
|
||||
DecisionLogic* logic = DecisionLogic::Create(
|
||||
@ -47,7 +47,7 @@ TEST(DecisionLogic, PostponeDecodingAfterExpansionSettings) {
|
||||
new rtc::RefCountedObject<MockAudioDecoderFactory>, absl::nullopt);
|
||||
TickTimer tick_timer;
|
||||
PacketBuffer packet_buffer(10, &tick_timer);
|
||||
DelayPeakDetector delay_peak_detector(&tick_timer);
|
||||
DelayPeakDetector delay_peak_detector(&tick_timer, false);
|
||||
DelayManager delay_manager(240, 0, &delay_peak_detector, &tick_timer);
|
||||
BufferLevelFilter buffer_level_filter;
|
||||
{
|
||||
|
@ -158,6 +158,7 @@ int DelayManager::Update(uint16_t sequence_number,
|
||||
}
|
||||
|
||||
// Check for discontinuous packet sequence and re-ordering.
|
||||
bool reordered = false;
|
||||
if (IsNewerSequenceNumber(sequence_number, last_seq_no_ + 1)) {
|
||||
// Compensate for gap in the sequence numbers. Reduce IAT with the
|
||||
// expected extra time due to lost packets, but ensure that the IAT is
|
||||
@ -166,6 +167,7 @@ int DelayManager::Update(uint16_t sequence_number,
|
||||
iat_packets = std::max(iat_packets, 0);
|
||||
} else if (!IsNewerSequenceNumber(sequence_number, last_seq_no_)) {
|
||||
iat_packets += static_cast<uint16_t>(last_seq_no_ + 1 - sequence_number);
|
||||
reordered = true;
|
||||
}
|
||||
|
||||
// Saturate IAT at maximum value.
|
||||
@ -173,7 +175,7 @@ int DelayManager::Update(uint16_t sequence_number,
|
||||
iat_packets = std::min(iat_packets, max_iat);
|
||||
UpdateHistogram(iat_packets);
|
||||
// Calculate new |target_level_| based on updated statistics.
|
||||
target_level_ = CalculateTargetLevel(iat_packets);
|
||||
target_level_ = CalculateTargetLevel(iat_packets, reordered);
|
||||
if (streaming_mode_) {
|
||||
target_level_ = std::max(target_level_, max_iat_cumulative_sum_);
|
||||
}
|
||||
@ -294,7 +296,7 @@ void DelayManager::LimitTargetLevel() {
|
||||
target_level_ = std::max(target_level_, 1 << 8);
|
||||
}
|
||||
|
||||
int DelayManager::CalculateTargetLevel(int iat_packets) {
|
||||
int DelayManager::CalculateTargetLevel(int iat_packets, bool reordered) {
|
||||
int limit_probability = forced_limit_probability_.value_or(kLimitProbability);
|
||||
if (streaming_mode_) {
|
||||
limit_probability = kLimitProbabilityStreaming;
|
||||
@ -325,7 +327,8 @@ int DelayManager::CalculateTargetLevel(int iat_packets) {
|
||||
base_target_level_ = static_cast<int>(index);
|
||||
|
||||
// Update detector for delay peaks.
|
||||
bool delay_peak_found = peak_detector_.Update(iat_packets, target_level);
|
||||
bool delay_peak_found =
|
||||
peak_detector_.Update(iat_packets, reordered, target_level);
|
||||
if (delay_peak_found) {
|
||||
target_level = std::max(target_level, peak_detector_.MaxPeakHeight());
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ class DelayManager {
|
||||
// Sets target_level_ (in Q8) and returns the same value. Also calculates
|
||||
// and updates base_target_level_, which is the target buffer level before
|
||||
// taking delay peaks into account.
|
||||
virtual int CalculateTargetLevel(int iat_packets);
|
||||
virtual int CalculateTargetLevel(int iat_packets, bool reordered);
|
||||
|
||||
// Notifies the DelayManager of how much audio data is carried in each packet.
|
||||
// The method updates the DelayPeakDetector too, and resets the inter-arrival
|
||||
|
@ -49,7 +49,10 @@ class DelayManagerTest : public ::testing::Test {
|
||||
};
|
||||
|
||||
DelayManagerTest::DelayManagerTest()
|
||||
: dm_(nullptr), detector_(&tick_timer_), seq_no_(0x1234), ts_(0x12345678) {}
|
||||
: dm_(nullptr),
|
||||
detector_(&tick_timer_, false),
|
||||
seq_no_(0x1234),
|
||||
ts_(0x12345678) {}
|
||||
|
||||
void DelayManagerTest::SetUp() {
|
||||
RecreateDelayManager();
|
||||
@ -126,7 +129,7 @@ TEST_F(DelayManagerTest, UpdateNormal) {
|
||||
// Expect detector update method to be called once with inter-arrival time
|
||||
// equal to 1 packet, and (base) target level equal to 1 as well.
|
||||
// Return false to indicate no peaks found.
|
||||
EXPECT_CALL(detector_, Update(1, 1)).WillOnce(Return(false));
|
||||
EXPECT_CALL(detector_, Update(1, false, 1)).WillOnce(Return(false));
|
||||
InsertNextPacket();
|
||||
EXPECT_EQ(1 << 8, dm_->TargetLevel()); // In Q8.
|
||||
EXPECT_EQ(1, dm_->base_target_level());
|
||||
@ -149,7 +152,7 @@ TEST_F(DelayManagerTest, UpdateLongInterArrivalTime) {
|
||||
// Expect detector update method to be called once with inter-arrival time
|
||||
// equal to 1 packet, and (base) target level equal to 1 as well.
|
||||
// Return false to indicate no peaks found.
|
||||
EXPECT_CALL(detector_, Update(2, 2)).WillOnce(Return(false));
|
||||
EXPECT_CALL(detector_, Update(2, false, 2)).WillOnce(Return(false));
|
||||
InsertNextPacket();
|
||||
EXPECT_EQ(2 << 8, dm_->TargetLevel()); // In Q8.
|
||||
EXPECT_EQ(2, dm_->base_target_level());
|
||||
@ -172,7 +175,7 @@ TEST_F(DelayManagerTest, UpdatePeakFound) {
|
||||
// Expect detector update method to be called once with inter-arrival time
|
||||
// equal to 1 packet, and (base) target level equal to 1 as well.
|
||||
// Return true to indicate that peaks are found. Let the peak height be 5.
|
||||
EXPECT_CALL(detector_, Update(1, 1)).WillOnce(Return(true));
|
||||
EXPECT_CALL(detector_, Update(1, false, 1)).WillOnce(Return(true));
|
||||
EXPECT_CALL(detector_, MaxPeakHeight()).WillOnce(Return(5));
|
||||
InsertNextPacket();
|
||||
EXPECT_EQ(5 << 8, dm_->TargetLevel());
|
||||
@ -194,7 +197,7 @@ TEST_F(DelayManagerTest, TargetDelay) {
|
||||
// Expect detector update method to be called once with inter-arrival time
|
||||
// equal to 1 packet, and (base) target level equal to 1 as well.
|
||||
// Return false to indicate no peaks found.
|
||||
EXPECT_CALL(detector_, Update(1, 1)).WillOnce(Return(false));
|
||||
EXPECT_CALL(detector_, Update(1, false, 1)).WillOnce(Return(false));
|
||||
InsertNextPacket();
|
||||
const int kExpectedTarget = 1;
|
||||
EXPECT_EQ(kExpectedTarget << 8, dm_->TargetLevel()); // In Q8.
|
||||
@ -216,7 +219,7 @@ TEST_F(DelayManagerTest, MaxDelay) {
|
||||
// Second packet arrival.
|
||||
// Expect detector update method to be called once with inter-arrival time
|
||||
// equal to |kExpectedTarget| packet. Return true to indicate peaks found.
|
||||
EXPECT_CALL(detector_, Update(kExpectedTarget, _))
|
||||
EXPECT_CALL(detector_, Update(kExpectedTarget, false, _))
|
||||
.WillRepeatedly(Return(true));
|
||||
EXPECT_CALL(detector_, MaxPeakHeight())
|
||||
.WillRepeatedly(Return(kExpectedTarget));
|
||||
@ -246,7 +249,7 @@ TEST_F(DelayManagerTest, MinDelay) {
|
||||
// Second packet arrival.
|
||||
// Expect detector update method to be called once with inter-arrival time
|
||||
// equal to |kExpectedTarget| packet. Return true to indicate peaks found.
|
||||
EXPECT_CALL(detector_, Update(kExpectedTarget, _))
|
||||
EXPECT_CALL(detector_, Update(kExpectedTarget, false, _))
|
||||
.WillRepeatedly(Return(true));
|
||||
EXPECT_CALL(detector_, MaxPeakHeight())
|
||||
.WillRepeatedly(Return(kExpectedTarget));
|
||||
@ -264,6 +267,15 @@ TEST_F(DelayManagerTest, MinDelay) {
|
||||
EXPECT_EQ(kMinDelayPackets << 8, dm_->TargetLevel());
|
||||
}
|
||||
|
||||
TEST_F(DelayManagerTest, UpdateReorderedPacket) {
|
||||
SetPacketAudioLength(kFrameSizeMs);
|
||||
InsertNextPacket();
|
||||
|
||||
// Insert packet that was sent before the previous packet.
|
||||
EXPECT_CALL(detector_, Update(_, true, _));
|
||||
EXPECT_EQ(0, dm_->Update(seq_no_ - 1, ts_ - kFrameSizeMs, kFs));
|
||||
}
|
||||
|
||||
// Tests that skipped sequence numbers (simulating empty packets) are handled
|
||||
// correctly.
|
||||
TEST_F(DelayManagerTest, EmptyPacketsReported) {
|
||||
@ -285,7 +297,7 @@ TEST_F(DelayManagerTest, EmptyPacketsReported) {
|
||||
// Expect detector update method to be called once with inter-arrival time
|
||||
// equal to 1 packet, and (base) target level equal to 1 as well.
|
||||
// Return false to indicate no peaks found.
|
||||
EXPECT_CALL(detector_, Update(1, 1)).WillOnce(Return(false));
|
||||
EXPECT_CALL(detector_, Update(1, false, 1)).WillOnce(Return(false));
|
||||
InsertNextPacket();
|
||||
|
||||
EXPECT_EQ(1 << 8, dm_->TargetLevel()); // In Q8.
|
||||
@ -309,7 +321,7 @@ TEST_F(DelayManagerTest, EmptyPacketsNotReported) {
|
||||
// Expect detector update method to be called once with inter-arrival time
|
||||
// equal to 1 packet, and (base) target level equal to 1 as well.
|
||||
// Return false to indicate no peaks found.
|
||||
EXPECT_CALL(detector_, Update(10, 10)).WillOnce(Return(false));
|
||||
EXPECT_CALL(detector_, Update(10, false, 10)).WillOnce(Return(false));
|
||||
InsertNextPacket();
|
||||
|
||||
// Note 10 times higher target value.
|
||||
@ -348,7 +360,7 @@ TEST_F(DelayManagerTest, TargetDelayGreaterThanOne) {
|
||||
// Second packet arrival.
|
||||
// Expect detector update method to be called once with inter-arrival time
|
||||
// equal to 1 packet.
|
||||
EXPECT_CALL(detector_, Update(1, 1)).WillOnce(Return(false));
|
||||
EXPECT_CALL(detector_, Update(1, false, 1)).WillOnce(Return(false));
|
||||
InsertNextPacket();
|
||||
constexpr int kExpectedTarget = 1;
|
||||
EXPECT_EQ(kExpectedTarget << 8, dm_->TargetLevel()); // In Q8.
|
||||
|
@ -26,10 +26,12 @@ namespace webrtc {
|
||||
|
||||
DelayPeakDetector::~DelayPeakDetector() = default;
|
||||
|
||||
DelayPeakDetector::DelayPeakDetector(const TickTimer* tick_timer)
|
||||
DelayPeakDetector::DelayPeakDetector(const TickTimer* tick_timer,
|
||||
bool ignore_reordered_packets)
|
||||
: peak_found_(false),
|
||||
peak_detection_threshold_(0),
|
||||
tick_timer_(tick_timer),
|
||||
ignore_reordered_packets_(ignore_reordered_packets),
|
||||
frame_length_change_experiment_(
|
||||
field_trial::IsEnabled("WebRTC-Audio-NetEqFramelengthExperiment")) {
|
||||
RTC_DCHECK(!peak_period_stopwatch_);
|
||||
@ -79,7 +81,12 @@ uint64_t DelayPeakDetector::MaxPeakPeriod() const {
|
||||
return max_period_element->period_ms;
|
||||
}
|
||||
|
||||
bool DelayPeakDetector::Update(int inter_arrival_time, int target_level) {
|
||||
bool DelayPeakDetector::Update(int inter_arrival_time,
|
||||
bool reordered,
|
||||
int target_level) {
|
||||
if (ignore_reordered_packets_ && reordered) {
|
||||
return CheckPeakConditions();
|
||||
}
|
||||
if (inter_arrival_time > target_level + peak_detection_threshold_ ||
|
||||
inter_arrival_time > 2 * target_level) {
|
||||
// A delay peak is observed.
|
||||
|
@ -23,7 +23,7 @@ namespace webrtc {
|
||||
|
||||
class DelayPeakDetector {
|
||||
public:
|
||||
DelayPeakDetector(const TickTimer* tick_timer);
|
||||
DelayPeakDetector(const TickTimer* tick_timer, bool ignore_reordered_packets);
|
||||
virtual ~DelayPeakDetector();
|
||||
virtual void Reset();
|
||||
|
||||
@ -43,10 +43,11 @@ class DelayPeakDetector {
|
||||
// larger than 0), or 0 if no delay peaks have been observed recently.
|
||||
virtual uint64_t MaxPeakPeriod() const;
|
||||
|
||||
// Updates the DelayPeakDetector with a new inter-arrival time (in packets)
|
||||
// and the current target buffer level (needed to decide if a peak is observed
|
||||
// or not). Returns true if peak-mode is active, false if not.
|
||||
virtual bool Update(int inter_arrival_time, int target_level);
|
||||
// Updates the DelayPeakDetector with a new inter-arrival time (in packets),
|
||||
// the current target buffer level (needed to decide if a peak is observed or
|
||||
// not) and if the new inter-arrival time includes a compensation for
|
||||
// reordering. Returns true if peak-mode is active, false if not.
|
||||
virtual bool Update(int inter_arrival_time, bool reordered, int target_level);
|
||||
|
||||
private:
|
||||
static const size_t kMaxNumPeaks = 8;
|
||||
@ -66,6 +67,7 @@ class DelayPeakDetector {
|
||||
int peak_detection_threshold_;
|
||||
const TickTimer* tick_timer_;
|
||||
std::unique_ptr<TickTimer::Stopwatch> peak_period_stopwatch_;
|
||||
const bool ignore_reordered_packets_;
|
||||
const bool frame_length_change_experiment_;
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(DelayPeakDetector);
|
||||
|
@ -18,14 +18,14 @@ namespace webrtc {
|
||||
|
||||
TEST(DelayPeakDetector, CreateAndDestroy) {
|
||||
TickTimer tick_timer;
|
||||
DelayPeakDetector* detector = new DelayPeakDetector(&tick_timer);
|
||||
DelayPeakDetector* detector = new DelayPeakDetector(&tick_timer, false);
|
||||
EXPECT_FALSE(detector->peak_found());
|
||||
delete detector;
|
||||
}
|
||||
|
||||
TEST(DelayPeakDetector, EmptyHistory) {
|
||||
TickTimer tick_timer;
|
||||
DelayPeakDetector detector(&tick_timer);
|
||||
DelayPeakDetector detector(&tick_timer, false);
|
||||
EXPECT_EQ(-1, detector.MaxPeakHeight());
|
||||
EXPECT_EQ(0u, detector.MaxPeakPeriod());
|
||||
}
|
||||
@ -35,7 +35,7 @@ TEST(DelayPeakDetector, EmptyHistory) {
|
||||
// start. This should then continue until it is disengaged due to lack of peaks.
|
||||
TEST(DelayPeakDetector, TriggerPeakMode) {
|
||||
TickTimer tick_timer;
|
||||
DelayPeakDetector detector(&tick_timer);
|
||||
DelayPeakDetector detector(&tick_timer, false);
|
||||
const int kPacketSizeMs = 30;
|
||||
detector.SetPacketAudioLength(kPacketSizeMs);
|
||||
|
||||
@ -69,9 +69,9 @@ TEST(DelayPeakDetector, TriggerPeakMode) {
|
||||
(arrival_times_ms[next] - arrival_times_ms[next - 1]) / kPacketSizeMs;
|
||||
const int kTargetBufferLevel = 1; // Define peaks to be iat > 2.
|
||||
if (time < peak_mode_start_ms || time > peak_mode_end_ms) {
|
||||
EXPECT_FALSE(detector.Update(iat_packets, kTargetBufferLevel));
|
||||
EXPECT_FALSE(detector.Update(iat_packets, false, kTargetBufferLevel));
|
||||
} else {
|
||||
EXPECT_TRUE(detector.Update(iat_packets, kTargetBufferLevel));
|
||||
EXPECT_TRUE(detector.Update(iat_packets, false, kTargetBufferLevel));
|
||||
EXPECT_EQ(kWorstPeakPeriod, detector.MaxPeakPeriod());
|
||||
EXPECT_EQ(kPeakDelayMs / kPacketSizeMs + 1, detector.MaxPeakHeight());
|
||||
}
|
||||
@ -87,7 +87,7 @@ TEST(DelayPeakDetector, TriggerPeakMode) {
|
||||
// The delay pattern has peaks with delay = 3, thus should not trigger.
|
||||
TEST(DelayPeakDetector, DoNotTriggerPeakMode) {
|
||||
TickTimer tick_timer;
|
||||
DelayPeakDetector detector(&tick_timer);
|
||||
DelayPeakDetector detector(&tick_timer, false);
|
||||
const int kPacketSizeMs = 30;
|
||||
detector.SetPacketAudioLength(kPacketSizeMs);
|
||||
|
||||
@ -115,7 +115,7 @@ TEST(DelayPeakDetector, DoNotTriggerPeakMode) {
|
||||
int iat_packets =
|
||||
(arrival_times_ms[next] - arrival_times_ms[next - 1]) / kPacketSizeMs;
|
||||
const int kTargetBufferLevel = 2; // Define peaks to be iat > 4.
|
||||
EXPECT_FALSE(detector.Update(iat_packets, kTargetBufferLevel));
|
||||
EXPECT_FALSE(detector.Update(iat_packets, false, kTargetBufferLevel));
|
||||
++next;
|
||||
}
|
||||
tick_timer.Increment();
|
||||
@ -129,15 +129,33 @@ TEST(DelayPeakDetector, DoNotTriggerPeakMode) {
|
||||
// problems.
|
||||
TEST(DelayPeakDetector, ZeroDistancePeaks) {
|
||||
TickTimer tick_timer;
|
||||
DelayPeakDetector detector(&tick_timer);
|
||||
DelayPeakDetector detector(&tick_timer, false);
|
||||
const int kPacketSizeMs = 30;
|
||||
detector.SetPacketAudioLength(kPacketSizeMs);
|
||||
|
||||
const int kTargetBufferLevel = 2; // Define peaks to be iat > 4.
|
||||
const int kInterArrivalTime = 3 * kTargetBufferLevel; // Will trigger a peak.
|
||||
EXPECT_FALSE(detector.Update(kInterArrivalTime, kTargetBufferLevel));
|
||||
EXPECT_FALSE(detector.Update(kInterArrivalTime, kTargetBufferLevel));
|
||||
EXPECT_FALSE(detector.Update(kInterArrivalTime, kTargetBufferLevel));
|
||||
const int kInterArrivalTime =
|
||||
3 * kTargetBufferLevel; // Above peak threshold.
|
||||
EXPECT_FALSE(detector.Update(kInterArrivalTime, false, kTargetBufferLevel));
|
||||
tick_timer.Increment();
|
||||
EXPECT_FALSE(detector.Update(kInterArrivalTime, false, kTargetBufferLevel));
|
||||
// The following would fail if there were non-zero time between the updates.
|
||||
EXPECT_FALSE(detector.Update(kInterArrivalTime, false, kTargetBufferLevel));
|
||||
}
|
||||
|
||||
TEST(DelayPeakDetector, IgnoreReorderedPacket) {
|
||||
TickTimer tick_timer;
|
||||
DelayPeakDetector detector(&tick_timer, true);
|
||||
|
||||
const int kTargetBufferLevel = 2; // Define peaks to be iat > 4.
|
||||
const int kInterArrivalTime =
|
||||
3 * kTargetBufferLevel; // Above peak threshold.
|
||||
EXPECT_FALSE(detector.Update(kInterArrivalTime, false, kTargetBufferLevel));
|
||||
tick_timer.Increment();
|
||||
EXPECT_FALSE(detector.Update(kInterArrivalTime, false, kTargetBufferLevel));
|
||||
tick_timer.Increment();
|
||||
// The following would fail if the packet was not reordered.
|
||||
EXPECT_FALSE(detector.Update(kInterArrivalTime, true, kTargetBufferLevel));
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
@ -117,6 +117,7 @@ class NetEq {
|
||||
int min_delay_ms = 0;
|
||||
bool enable_fast_accelerate = false;
|
||||
bool enable_muted_state = false;
|
||||
bool enable_rtx_handling = false;
|
||||
absl::optional<AudioCodecPairId> codec_pair_id;
|
||||
bool for_test_no_time_stretching = false; // Use only for testing.
|
||||
};
|
||||
|
@ -34,7 +34,7 @@ class MockDelayManager : public DelayManager {
|
||||
int(uint16_t sequence_number,
|
||||
uint32_t timestamp,
|
||||
int sample_rate_hz));
|
||||
MOCK_METHOD1(CalculateTargetLevel, int(int iat_packets));
|
||||
MOCK_METHOD2(CalculateTargetLevel, int(int iat_packets, bool reordered));
|
||||
MOCK_METHOD1(SetPacketAudioLength, int(int length_ms));
|
||||
MOCK_METHOD0(Reset, void());
|
||||
MOCK_CONST_METHOD0(PeakFound, bool());
|
||||
|
@ -19,8 +19,9 @@ namespace webrtc {
|
||||
|
||||
class MockDelayPeakDetector : public DelayPeakDetector {
|
||||
public:
|
||||
MockDelayPeakDetector(const TickTimer* tick_timer)
|
||||
: DelayPeakDetector(tick_timer) {}
|
||||
MockDelayPeakDetector(const TickTimer* tick_timer,
|
||||
bool ignore_reordered_packets)
|
||||
: DelayPeakDetector(tick_timer, ignore_reordered_packets) {}
|
||||
virtual ~MockDelayPeakDetector() { Die(); }
|
||||
MOCK_METHOD0(Die, void());
|
||||
MOCK_METHOD0(Reset, void());
|
||||
@ -28,7 +29,8 @@ class MockDelayPeakDetector : public DelayPeakDetector {
|
||||
MOCK_METHOD0(peak_found, bool());
|
||||
MOCK_CONST_METHOD0(MaxPeakHeight, int());
|
||||
MOCK_CONST_METHOD0(MaxPeakPeriod, uint64_t());
|
||||
MOCK_METHOD2(Update, bool(int inter_arrival_time, int target_level));
|
||||
MOCK_METHOD3(Update,
|
||||
bool(int inter_arrival_time, bool reordered, int target_level));
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
@ -28,9 +28,10 @@ std::string NetEq::Config::ToString() const {
|
||||
ss << "sample_rate_hz=" << sample_rate_hz << ", enable_post_decode_vad="
|
||||
<< (enable_post_decode_vad ? "true" : "false")
|
||||
<< ", max_packets_in_buffer=" << max_packets_in_buffer
|
||||
<< ", enable_fast_accelerate="
|
||||
<< (enable_fast_accelerate ? " true" : "false")
|
||||
<< ", enable_muted_state=" << (enable_muted_state ? " true" : "false");
|
||||
<< ", min_delay_ms=" << min_delay_ms << ", enable_fast_accelerate="
|
||||
<< (enable_fast_accelerate ? "true" : "false")
|
||||
<< ", enable_muted_state=" << (enable_muted_state ? "true" : "false")
|
||||
<< ", enable_rtx_handling=" << (enable_rtx_handling ? "true" : "false");
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,8 @@ NetEqImpl::Dependencies::Dependencies(
|
||||
buffer_level_filter(new BufferLevelFilter),
|
||||
decoder_database(
|
||||
new DecoderDatabase(decoder_factory, config.codec_pair_id)),
|
||||
delay_peak_detector(new DelayPeakDetector(tick_timer.get())),
|
||||
delay_peak_detector(
|
||||
new DelayPeakDetector(tick_timer.get(), config.enable_rtx_handling)),
|
||||
delay_manager(new DelayManager(config.max_packets_in_buffer,
|
||||
config.min_delay_ms,
|
||||
delay_peak_detector.get(),
|
||||
@ -112,7 +113,8 @@ NetEqImpl::NetEqImpl(const NetEq::Config& config,
|
||||
speech_expand_uma_logger_("WebRTC.Audio.SpeechExpandRatePercent",
|
||||
10, // Report once every 10 s.
|
||||
tick_timer_.get()),
|
||||
no_time_stretching_(config.for_test_no_time_stretching) {
|
||||
no_time_stretching_(config.for_test_no_time_stretching),
|
||||
enable_rtx_handling_(config.enable_rtx_handling) {
|
||||
RTC_LOG(LS_INFO) << "NetEq config: " << config.ToString();
|
||||
int fs = config.sample_rate_hz;
|
||||
if (fs != 8000 && fs != 16000 && fs != 32000 && fs != 48000) {
|
||||
@ -737,9 +739,11 @@ int NetEqImpl::InsertPacketInternal(const RTPHeader& rtp_header,
|
||||
}
|
||||
|
||||
// Update statistics.
|
||||
if ((int32_t)(main_timestamp - timestamp_) >= 0 && !new_codec_) {
|
||||
if ((enable_rtx_handling_ || (int32_t)(main_timestamp - timestamp_) >= 0) &&
|
||||
!new_codec_) {
|
||||
// Only update statistics if incoming packet is not older than last played
|
||||
// out packet, and if new codec flag is not set.
|
||||
// out packet or RTX handling is enabled, and if new codec flag is not
|
||||
// set.
|
||||
delay_manager_->Update(main_sequence_number, main_timestamp, fs_hz_);
|
||||
}
|
||||
} else if (delay_manager_->last_pack_cng_or_dtmf() == -1) {
|
||||
|
@ -408,6 +408,7 @@ class NetEqImpl : public webrtc::NetEq {
|
||||
ExpandUmaLogger speech_expand_uma_logger_ RTC_GUARDED_BY(crit_sect_);
|
||||
bool no_time_stretching_ RTC_GUARDED_BY(crit_sect_); // Only used for test.
|
||||
rtc::BufferT<int16_t> concealment_audio_ RTC_GUARDED_BY(crit_sect_);
|
||||
const bool enable_rtx_handling_ RTC_GUARDED_BY(crit_sect_);
|
||||
|
||||
private:
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(NetEqImpl);
|
||||
|
@ -87,7 +87,7 @@ class NetEqImplTest : public ::testing::Test {
|
||||
|
||||
if (use_mock_delay_peak_detector_) {
|
||||
std::unique_ptr<MockDelayPeakDetector> mock(
|
||||
new MockDelayPeakDetector(tick_timer_));
|
||||
new MockDelayPeakDetector(tick_timer_, config_.enable_rtx_handling));
|
||||
mock_delay_peak_detector_ = mock.get();
|
||||
EXPECT_CALL(*mock_delay_peak_detector_, Reset()).Times(1);
|
||||
deps.delay_peak_detector = std::move(mock);
|
||||
@ -1301,6 +1301,43 @@ TEST_F(NetEqImplTest, InsertEmptyPacket) {
|
||||
neteq_->InsertEmptyPacket(rtp_header);
|
||||
}
|
||||
|
||||
TEST_F(NetEqImplTest, EnableRtxHandling) {
|
||||
UseNoMocks();
|
||||
use_mock_delay_manager_ = true;
|
||||
config_.enable_rtx_handling = true;
|
||||
CreateInstance();
|
||||
EXPECT_CALL(*mock_delay_manager_, BufferLimits(_, _))
|
||||
.Times(1)
|
||||
.WillOnce(DoAll(SetArgPointee<0>(0), SetArgPointee<1>(0)));
|
||||
|
||||
const int kPayloadLengthSamples = 80;
|
||||
const size_t kPayloadLengthBytes = 2 * kPayloadLengthSamples; // PCM 16-bit.
|
||||
const uint8_t kPayloadType = 17; // Just an arbitrary number.
|
||||
const uint32_t kReceiveTime = 17;
|
||||
uint8_t payload[kPayloadLengthBytes] = {0};
|
||||
RTPHeader rtp_header;
|
||||
rtp_header.payloadType = kPayloadType;
|
||||
rtp_header.sequenceNumber = 0x1234;
|
||||
rtp_header.timestamp = 0x12345678;
|
||||
rtp_header.ssrc = 0x87654321;
|
||||
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->RegisterPayloadType(
|
||||
NetEqDecoder::kDecoderPCM16B, "", kPayloadType));
|
||||
EXPECT_EQ(NetEq::kOK,
|
||||
neteq_->InsertPacket(rtp_header, payload, kReceiveTime));
|
||||
AudioFrame output;
|
||||
bool muted;
|
||||
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output, &muted));
|
||||
|
||||
// Insert second packet that was sent before the first packet.
|
||||
rtp_header.sequenceNumber -= 1;
|
||||
rtp_header.timestamp -= kPayloadLengthSamples;
|
||||
EXPECT_CALL(*mock_delay_manager_,
|
||||
Update(rtp_header.sequenceNumber, rtp_header.timestamp, _));
|
||||
EXPECT_EQ(NetEq::kOK,
|
||||
neteq_->InsertPacket(rtp_header, payload, kReceiveTime));
|
||||
}
|
||||
|
||||
class Decoder120ms : public AudioDecoder {
|
||||
public:
|
||||
Decoder120ms(int sample_rate_hz, SpeechType speech_type)
|
||||
|
Reference in New Issue
Block a user