blob: 1a5aa26e023e22dc2c22b53289faade7f003507c [file] [log] [blame]
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +00001/*
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/audio_coding/neteq/decision_logic.h"
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000012
Yves Gerey988cc082018-10-23 12:03:01 +020013#include <stdio.h>
Jonas Olssona4d87372019-07-05 19:08:33 +020014
Jakob Ivarssonc782cf82022-05-16 15:28:22 +020015#include <memory>
Yves Gerey988cc082018-10-23 12:03:01 +020016#include <string>
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000017
Jakob Ivarsson46dda832019-07-03 16:00:30 +020018#include "absl/types/optional.h"
Jakob Ivarssonc782cf82022-05-16 15:28:22 +020019#include "api/neteq/neteq.h"
20#include "api/neteq/neteq_controller.h"
21#include "modules/audio_coding/neteq/packet_arrival_history.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "modules/audio_coding/neteq/packet_buffer.h"
Yves Gerey988cc082018-10-23 12:03:01 +020023#include "rtc_base/checks.h"
Jakob Ivarsson46dda832019-07-03 16:00:30 +020024#include "rtc_base/experiments/field_trial_parser.h"
Jakob Ivarssonc782cf82022-05-16 15:28:22 +020025#include "rtc_base/experiments/struct_parameters_parser.h"
Minyue Li7f6417f2018-10-03 21:19:08 +020026#include "rtc_base/logging.h"
Yves Gerey988cc082018-10-23 12:03:01 +020027#include "rtc_base/numerics/safe_conversions.h"
Jakob Ivarsson46dda832019-07-03 16:00:30 +020028#include "system_wrappers/include/field_trial.h"
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000029
Jakob Ivarsson74158ff2021-09-07 14:24:56 +020030namespace webrtc {
31
Minyue Li7f6417f2018-10-03 21:19:08 +020032namespace {
Minyue Li7f6417f2018-10-03 21:19:08 +020033
Jakob Ivarssond3a780b2019-02-28 14:30:21 +010034constexpr int kPostponeDecodingLevel = 50;
Jakob Ivarssonc782cf82022-05-16 15:28:22 +020035constexpr int kTargetLevelWindowMs = 100;
36constexpr int kMaxWaitForPacketTicks = 10;
37// The granularity of delay adjustments (accelerate/preemptive expand) is 15ms,
38// but round up since the clock has a granularity of 10ms.
39constexpr int kDelayAdjustmentGranularityMs = 20;
Minyue Li7f6417f2018-10-03 21:19:08 +020040
Jakob Ivarsson74158ff2021-09-07 14:24:56 +020041std::unique_ptr<DelayManager> CreateDelayManager(
42 const NetEqController::Config& neteq_config) {
43 DelayManager::Config config;
44 config.max_packets_in_buffer = neteq_config.max_packets_in_buffer;
45 config.base_minimum_delay_ms = neteq_config.base_min_delay_ms;
46 config.Log();
47 return std::make_unique<DelayManager>(config, neteq_config.tick_timer);
48}
Minyue Li7f6417f2018-10-03 21:19:08 +020049
Jakob Ivarssonc782cf82022-05-16 15:28:22 +020050bool IsTimestretch(NetEq::Mode mode) {
51 return mode == NetEq::Mode::kAccelerateSuccess ||
52 mode == NetEq::Mode::kAccelerateLowEnergy ||
53 mode == NetEq::Mode::kPreemptiveExpandSuccess ||
54 mode == NetEq::Mode::kPreemptiveExpandLowEnergy;
55}
56
57bool IsCng(NetEq::Mode mode) {
58 return mode == NetEq::Mode::kRfc3389Cng ||
59 mode == NetEq::Mode::kCodecInternalCng;
60}
61
Jakob Ivarssonca101e62022-04-04 21:42:55 +020062bool IsExpand(NetEq::Mode mode) {
63 return mode == NetEq::Mode::kExpand || mode == NetEq::Mode::kCodecPlc;
64}
65
Jakob Ivarsson74158ff2021-09-07 14:24:56 +020066} // namespace
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000067
Jakob Ivarssonc782cf82022-05-16 15:28:22 +020068DecisionLogic::Config::Config() {
69 StructParametersParser::Create(
70 "enable_stable_playout_delay", &enable_stable_playout_delay, //
71 "reinit_after_expands", &reinit_after_expands, //
72 "packet_history_size_ms", &packet_history_size_ms, //
73 "deceleration_target_level_offset_ms",
74 &deceleration_target_level_offset_ms)
75 ->Parse(webrtc::field_trial::FindFullName(
76 "WebRTC-Audio-NetEqDecisionLogicConfig"));
77 RTC_LOG(LS_INFO) << "NetEq decision logic config:"
78 << " enable_stable_playout_delay="
79 << enable_stable_playout_delay
80 << " reinit_after_expands=" << reinit_after_expands
81 << " packet_history_size_ms=" << packet_history_size_ms
82 << " deceleration_target_level_offset_ms="
83 << deceleration_target_level_offset_ms;
84}
85
Ivo Creusen53a31f72019-10-24 15:20:39 +020086DecisionLogic::DecisionLogic(NetEqController::Config config)
Jakob Ivarsson609b0472020-10-19 09:19:34 +020087 : DecisionLogic(config,
Jakob Ivarsson74158ff2021-09-07 14:24:56 +020088 CreateDelayManager(config),
Jakob Ivarsson609b0472020-10-19 09:19:34 +020089 std::make_unique<BufferLevelFilter>()) {}
90
91DecisionLogic::DecisionLogic(
92 NetEqController::Config config,
93 std::unique_ptr<DelayManager> delay_manager,
94 std::unique_ptr<BufferLevelFilter> buffer_level_filter)
95 : delay_manager_(std::move(delay_manager)),
96 buffer_level_filter_(std::move(buffer_level_filter)),
Jakob Ivarssonc782cf82022-05-16 15:28:22 +020097 packet_arrival_history_(config_.packet_history_size_ms),
Ivo Creusen53a31f72019-10-24 15:20:39 +020098 tick_timer_(config.tick_timer),
99 disallow_time_stretching_(!config.allow_time_stretching),
Henrik Lundin47b17dc2016-05-10 10:20:59 +0200100 timescale_countdown_(
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200101 tick_timer_->GetNewCountdown(kMinTimescaleInterval + 1)) {}
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000102
Henrik Lundin47b17dc2016-05-10 10:20:59 +0200103DecisionLogic::~DecisionLogic() = default;
104
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000105void DecisionLogic::SoftReset() {
106 packet_length_samples_ = 0;
107 sample_memory_ = 0;
108 prev_time_scale_ = false;
Jakob Ivarsson80fb9782020-10-09 13:41:06 +0200109 last_pack_cng_or_dtmf_ = true;
Henrik Lundin47b17dc2016-05-10 10:20:59 +0200110 timescale_countdown_ =
111 tick_timer_->GetNewCountdown(kMinTimescaleInterval + 1);
Jakob Ivarsson46dda832019-07-03 16:00:30 +0200112 time_stretched_cn_samples_ = 0;
Ivo Creusen53a31f72019-10-24 15:20:39 +0200113 delay_manager_->Reset();
Jakob Ivarsson609b0472020-10-19 09:19:34 +0200114 buffer_level_filter_->Reset();
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200115 packet_arrival_history_.Reset();
116 last_playout_delay_ms_ = 0;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000117}
118
Peter Kastingdce40cf2015-08-24 14:52:23 -0700119void DecisionLogic::SetSampleRate(int fs_hz, size_t output_size_samples) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000120 // TODO(hlundin): Change to an enumerator and skip assert.
Mirko Bonadei25ab3222021-07-08 20:08:20 +0200121 RTC_DCHECK(fs_hz == 8000 || fs_hz == 16000 || fs_hz == 32000 ||
122 fs_hz == 48000);
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200123 sample_rate_khz_ = fs_hz / 1000;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000124 output_size_samples_ = output_size_samples;
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200125 packet_arrival_history_.set_sample_rate(fs_hz);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000126}
127
Ivo Creusen3ce44a32019-10-31 14:38:11 +0100128NetEq::Operation DecisionLogic::GetDecision(const NetEqStatus& status,
129 bool* reset_decoder) {
ossu61a208b2016-09-20 01:38:00 -0700130 // If last mode was CNG (or Expand, since this could be covering up for
131 // a lost CNG packet), remember that CNG is on. This is needed if comfort
132 // noise is interrupted by DTMF.
Ivo Creusen3ce44a32019-10-31 14:38:11 +0100133 if (status.last_mode == NetEq::Mode::kRfc3389Cng) {
ossu61a208b2016-09-20 01:38:00 -0700134 cng_state_ = kCngRfc3389On;
Ivo Creusen3ce44a32019-10-31 14:38:11 +0100135 } else if (status.last_mode == NetEq::Mode::kCodecInternalCng) {
ossu61a208b2016-09-20 01:38:00 -0700136 cng_state_ = kCngInternalOn;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000137 }
138
Jakob Ivarssonca101e62022-04-04 21:42:55 +0200139 if (IsExpand(status.last_mode)) {
140 ++num_consecutive_expands_;
141 } else {
142 num_consecutive_expands_ = 0;
143 }
144
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200145 if (!IsExpand(status.last_mode) && !IsCng(status.last_mode)) {
146 last_playout_delay_ms_ = GetPlayoutDelayMs(status);
147 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000148
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200149 prev_time_scale_ = prev_time_scale_ && IsTimestretch(status.last_mode);
150 if (prev_time_scale_) {
151 timescale_countdown_ = tick_timer_->GetNewCountdown(kMinTimescaleInterval);
152 }
153 if (!IsCng(status.last_mode)) {
Jakob Ivarssone6aabd02022-03-28 16:06:37 +0200154 FilterBufferLevel(status.packet_buffer_info.span_samples);
Minyue Li7d204d52019-04-16 11:44:49 +0200155 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000156
Henrik Lundin7687ad52018-07-02 10:14:46 +0200157 // Guard for errors, to avoid getting stuck in error mode.
Ivo Creusen3ce44a32019-10-31 14:38:11 +0100158 if (status.last_mode == NetEq::Mode::kError) {
Ivo Creusen53a31f72019-10-24 15:20:39 +0200159 if (!status.next_packet) {
Ivo Creusen3ce44a32019-10-31 14:38:11 +0100160 return NetEq::Operation::kExpand;
Henrik Lundin7687ad52018-07-02 10:14:46 +0200161 } else {
Ivo Creusen3ce44a32019-10-31 14:38:11 +0100162 // Use kUndefined to flag for a reset.
163 return NetEq::Operation::kUndefined;
Henrik Lundin7687ad52018-07-02 10:14:46 +0200164 }
165 }
166
Ivo Creusen53a31f72019-10-24 15:20:39 +0200167 if (status.next_packet && status.next_packet->is_cng) {
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200168 return CngOperation(status);
Henrik Lundin7687ad52018-07-02 10:14:46 +0200169 }
170
171 // Handle the case with no packet at all available (except maybe DTMF).
Ivo Creusen53a31f72019-10-24 15:20:39 +0200172 if (!status.next_packet) {
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200173 return NoPacket(status);
Henrik Lundin7687ad52018-07-02 10:14:46 +0200174 }
175
176 // If the expand period was very long, reset NetEQ since it is likely that the
177 // sender was restarted.
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200178 if (num_consecutive_expands_ > config_.reinit_after_expands) {
Henrik Lundin7687ad52018-07-02 10:14:46 +0200179 *reset_decoder = true;
Ivo Creusen3ce44a32019-10-31 14:38:11 +0100180 return NetEq::Operation::kNormal;
Henrik Lundin7687ad52018-07-02 10:14:46 +0200181 }
182
183 // Make sure we don't restart audio too soon after an expansion to avoid
184 // running out of data right away again. We should only wait if there are no
185 // DTX or CNG packets in the buffer (otherwise we should just play out what we
186 // have, since we cannot know the exact duration of DTX or CNG packets), and
187 // if the mute factor is low enough (otherwise the expansion was short enough
188 // to not be noticable).
189 // Note that the MuteFactor is in Q14, so a value of 16384 corresponds to 1.
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200190 const int target_level_samples = TargetLevelMs() * sample_rate_khz_;
191 if (!config_.enable_stable_playout_delay && IsExpand(status.last_mode) &&
192 status.expand_mutefactor < 16384 / 2 &&
Jakob Ivarssone6aabd02022-03-28 16:06:37 +0200193 status.packet_buffer_info.span_samples <
194 static_cast<size_t>(target_level_samples * kPostponeDecodingLevel /
195 100) &&
Ivo Creusen53a31f72019-10-24 15:20:39 +0200196 !status.packet_buffer_info.dtx_or_cng) {
Ivo Creusen3ce44a32019-10-31 14:38:11 +0100197 return NetEq::Operation::kExpand;
Henrik Lundin7687ad52018-07-02 10:14:46 +0200198 }
199
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200200 const uint32_t five_seconds_samples =
201 static_cast<uint32_t>(5000 * sample_rate_khz_);
Henrik Lundin7687ad52018-07-02 10:14:46 +0200202 // Check if the required packet is available.
Ivo Creusen53a31f72019-10-24 15:20:39 +0200203 if (status.target_timestamp == status.next_packet->timestamp) {
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200204 return ExpectedPacketAvailable(status);
Henrik Lundin7687ad52018-07-02 10:14:46 +0200205 }
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200206 if (!PacketBuffer::IsObsoleteTimestamp(status.next_packet->timestamp,
207 status.target_timestamp,
208 five_seconds_samples)) {
209 return FuturePacketAvailable(status);
210 }
211 // This implies that available_timestamp < target_timestamp, which can
212 // happen when a new stream or codec is received. Signal for a reset.
213 return NetEq::Operation::kUndefined;
Henrik Lundin7687ad52018-07-02 10:14:46 +0200214}
215
Jakob Ivarssonca101e62022-04-04 21:42:55 +0200216void DecisionLogic::NotifyMutedState() {
217 ++num_consecutive_expands_;
Henrik Lundin5afa61c2018-07-02 14:53:24 +0200218}
219
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200220int DecisionLogic::TargetLevelMs() const {
221 int target_delay_ms = delay_manager_->TargetDelayMs();
222 if (!config_.enable_stable_playout_delay) {
223 target_delay_ms =
224 std::max(target_delay_ms,
225 static_cast<int>(packet_length_samples_ / sample_rate_khz_));
226 }
227 return target_delay_ms;
228}
229
230int DecisionLogic::GetFilteredBufferLevel() const {
231 if (config_.enable_stable_playout_delay) {
232 return last_playout_delay_ms_ * sample_rate_khz_;
233 }
234 return buffer_level_filter_->filtered_current_level();
235}
236
Ivo Creusena2b31c32020-10-14 17:54:22 +0200237absl::optional<int> DecisionLogic::PacketArrived(
238 int fs_hz,
239 bool should_update_stats,
240 const PacketArrivedInfo& info) {
Ivo Creusen7b463c52020-11-25 11:32:40 +0100241 buffer_flush_ = buffer_flush_ || info.buffer_flush;
Ivo Creusena2b31c32020-10-14 17:54:22 +0200242 if (info.is_cng_or_dtmf) {
Jakob Ivarsson80fb9782020-10-09 13:41:06 +0200243 last_pack_cng_or_dtmf_ = true;
244 return absl::nullopt;
Ivo Creusen53a31f72019-10-24 15:20:39 +0200245 }
Jakob Ivarsson80fb9782020-10-09 13:41:06 +0200246 if (!should_update_stats) {
247 return absl::nullopt;
248 }
Ivo Creusena2b31c32020-10-14 17:54:22 +0200249 if (info.packet_length_samples > 0 && fs_hz > 0 &&
250 info.packet_length_samples != packet_length_samples_) {
251 packet_length_samples_ = info.packet_length_samples;
Jakob Ivarsson80fb9782020-10-09 13:41:06 +0200252 delay_manager_->SetPacketAudioLength(packet_length_samples_ * 1000 / fs_hz);
253 }
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200254 packet_arrival_history_.Insert(
255 info.main_timestamp, tick_timer_->ticks() * tick_timer_->ms_per_tick());
Jakob Ivarsson80fb9782020-10-09 13:41:06 +0200256 auto relative_delay = delay_manager_->Update(
Ivo Creusena2b31c32020-10-14 17:54:22 +0200257 info.main_timestamp, fs_hz, /*reset=*/last_pack_cng_or_dtmf_);
Jakob Ivarsson80fb9782020-10-09 13:41:06 +0200258 last_pack_cng_or_dtmf_ = false;
Ivo Creusen53a31f72019-10-24 15:20:39 +0200259 return relative_delay;
260}
261
Minyue Li7d204d52019-04-16 11:44:49 +0200262void DecisionLogic::FilterBufferLevel(size_t buffer_size_samples) {
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200263 buffer_level_filter_->SetTargetBufferLevel(TargetLevelMs());
Henrik Lundin5afa61c2018-07-02 14:53:24 +0200264
Jakob Ivarsson46dda832019-07-03 16:00:30 +0200265 int time_stretched_samples = time_stretched_cn_samples_;
Minyue Li7d204d52019-04-16 11:44:49 +0200266 if (prev_time_scale_) {
Jakob Ivarsson46dda832019-07-03 16:00:30 +0200267 time_stretched_samples += sample_memory_;
Minyue Li7d204d52019-04-16 11:44:49 +0200268 }
269
Ivo Creusen7b463c52020-11-25 11:32:40 +0100270 if (buffer_flush_) {
271 buffer_level_filter_->SetFilteredBufferLevel(buffer_size_samples);
272 buffer_flush_ = false;
273 } else {
274 buffer_level_filter_->Update(buffer_size_samples, time_stretched_samples);
275 }
Minyue Li7d204d52019-04-16 11:44:49 +0200276 prev_time_scale_ = false;
Jakob Ivarsson46dda832019-07-03 16:00:30 +0200277 time_stretched_cn_samples_ = 0;
Henrik Lundin5afa61c2018-07-02 14:53:24 +0200278}
279
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200280NetEq::Operation DecisionLogic::CngOperation(
281 NetEqController::NetEqStatus status) {
Henrik Lundin7687ad52018-07-02 10:14:46 +0200282 // Signed difference between target and available timestamp.
283 int32_t timestamp_diff = static_cast<int32_t>(
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200284 static_cast<uint32_t>(status.generated_noise_samples +
285 status.target_timestamp) -
286 status.next_packet->timestamp);
287 int optimal_level_samp = TargetLevelMs() * sample_rate_khz_;
Henrik Lundin7687ad52018-07-02 10:14:46 +0200288 const int64_t excess_waiting_time_samp =
289 -static_cast<int64_t>(timestamp_diff) - optimal_level_samp;
290
291 if (excess_waiting_time_samp > optimal_level_samp / 2) {
292 // The waiting time for this packet will be longer than 1.5
293 // times the wanted buffer delay. Apply fast-forward to cut the
294 // waiting time down to the optimal.
Jakob Ivarsson42b6e2d2019-10-21 11:51:05 +0200295 noise_fast_forward_ = rtc::saturated_cast<size_t>(noise_fast_forward_ +
296 excess_waiting_time_samp);
Henrik Lundin7687ad52018-07-02 10:14:46 +0200297 timestamp_diff =
298 rtc::saturated_cast<int32_t>(timestamp_diff + excess_waiting_time_samp);
299 }
300
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200301 if (timestamp_diff < 0 && status.last_mode == NetEq::Mode::kRfc3389Cng) {
Henrik Lundin7687ad52018-07-02 10:14:46 +0200302 // Not time to play this packet yet. Wait another round before using this
303 // packet. Keep on playing CNG from previous CNG parameters.
Ivo Creusen3ce44a32019-10-31 14:38:11 +0100304 return NetEq::Operation::kRfc3389CngNoPacket;
Henrik Lundin7687ad52018-07-02 10:14:46 +0200305 } else {
306 // Otherwise, go for the CNG packet now.
307 noise_fast_forward_ = 0;
Ivo Creusen3ce44a32019-10-31 14:38:11 +0100308 return NetEq::Operation::kRfc3389Cng;
Henrik Lundin7687ad52018-07-02 10:14:46 +0200309 }
310}
311
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200312NetEq::Operation DecisionLogic::NoPacket(NetEqController::NetEqStatus status) {
Henrik Lundin7687ad52018-07-02 10:14:46 +0200313 if (cng_state_ == kCngRfc3389On) {
314 // Keep on playing comfort noise.
Ivo Creusen3ce44a32019-10-31 14:38:11 +0100315 return NetEq::Operation::kRfc3389CngNoPacket;
Henrik Lundin7687ad52018-07-02 10:14:46 +0200316 } else if (cng_state_ == kCngInternalOn) {
317 // Keep on playing codec internal comfort noise.
Ivo Creusen3ce44a32019-10-31 14:38:11 +0100318 return NetEq::Operation::kCodecInternalCng;
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200319 } else if (status.play_dtmf) {
Ivo Creusen3ce44a32019-10-31 14:38:11 +0100320 return NetEq::Operation::kDtmf;
Henrik Lundin7687ad52018-07-02 10:14:46 +0200321 } else {
322 // Nothing to play, do expand.
Ivo Creusen3ce44a32019-10-31 14:38:11 +0100323 return NetEq::Operation::kExpand;
Henrik Lundin7687ad52018-07-02 10:14:46 +0200324 }
325}
326
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200327NetEq::Operation DecisionLogic::ExpectedPacketAvailable(
328 NetEqController::NetEqStatus status) {
329 if (!disallow_time_stretching_ && status.last_mode != NetEq::Mode::kExpand &&
330 !status.play_dtmf) {
331 if (config_.enable_stable_playout_delay) {
332 const int playout_delay_ms = GetPlayoutDelayMs(status);
333 if (playout_delay_ms >= HighThreshold() << 2) {
334 return NetEq::Operation::kFastAccelerate;
335 }
336 if (TimescaleAllowed()) {
337 if (playout_delay_ms >= HighThreshold()) {
338 return NetEq::Operation::kAccelerate;
339 }
340 if (playout_delay_ms < LowThreshold()) {
341 return NetEq::Operation::kPreemptiveExpand;
342 }
343 }
344 } else {
345 const int target_level_samples = TargetLevelMs() * sample_rate_khz_;
346 const int low_limit = std::max(
347 target_level_samples * 3 / 4,
348 target_level_samples -
349 config_.deceleration_target_level_offset_ms * sample_rate_khz_);
350 const int high_limit = std::max(
351 target_level_samples,
352 low_limit + kDelayAdjustmentGranularityMs * sample_rate_khz_);
Jakob Ivarsson80fb9782020-10-09 13:41:06 +0200353
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200354 const int buffer_level_samples =
355 buffer_level_filter_->filtered_current_level();
356 if (buffer_level_samples >= high_limit << 2)
357 return NetEq::Operation::kFastAccelerate;
358 if (TimescaleAllowed()) {
359 if (buffer_level_samples >= high_limit)
360 return NetEq::Operation::kAccelerate;
361 if (buffer_level_samples < low_limit)
362 return NetEq::Operation::kPreemptiveExpand;
363 }
Henrik Lundin7687ad52018-07-02 10:14:46 +0200364 }
365 }
Ivo Creusen3ce44a32019-10-31 14:38:11 +0100366 return NetEq::Operation::kNormal;
Henrik Lundin7687ad52018-07-02 10:14:46 +0200367}
368
Ivo Creusen3ce44a32019-10-31 14:38:11 +0100369NetEq::Operation DecisionLogic::FuturePacketAvailable(
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200370 NetEqController::NetEqStatus status) {
Henrik Lundin7687ad52018-07-02 10:14:46 +0200371 // Required packet is not available, but a future packet is.
372 // Check if we should continue with an ongoing expand because the new packet
373 // is too far into the future.
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200374 if (IsExpand(status.last_mode) && ShouldContinueExpand(status)) {
375 if (status.play_dtmf) {
Henrik Lundin7687ad52018-07-02 10:14:46 +0200376 // Still have DTMF to play, so do not do expand.
Ivo Creusen3ce44a32019-10-31 14:38:11 +0100377 return NetEq::Operation::kDtmf;
Henrik Lundin7687ad52018-07-02 10:14:46 +0200378 } else {
379 // Nothing to play.
Ivo Creusen3ce44a32019-10-31 14:38:11 +0100380 return NetEq::Operation::kExpand;
Henrik Lundin7687ad52018-07-02 10:14:46 +0200381 }
382 }
383
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200384 if (status.last_mode == NetEq::Mode::kCodecPlc) {
Ivo Creusen3ce44a32019-10-31 14:38:11 +0100385 return NetEq::Operation::kNormal;
Henrik Lundin00eb12a2018-09-05 18:14:52 +0200386 }
387
Henrik Lundin7687ad52018-07-02 10:14:46 +0200388 // If previous was comfort noise, then no merge is needed.
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200389 if (IsCng(status.last_mode)) {
390 uint32_t timestamp_leap =
391 status.next_packet->timestamp - status.target_timestamp;
Jakob Ivarsson46dda832019-07-03 16:00:30 +0200392 const bool generated_enough_noise =
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200393 status.generated_noise_samples >= timestamp_leap;
394
395 int playout_delay_ms = GetNextPacketDelayMs(status);
396 const bool above_target_delay = playout_delay_ms > HighThresholdCng();
397 const bool below_target_delay = playout_delay_ms < LowThresholdCng();
Jakob Ivarssone6aabd02022-03-28 16:06:37 +0200398 // Keep the delay same as before CNG, but make sure that it is within the
399 // target window.
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200400 if ((generated_enough_noise && !below_target_delay) || above_target_delay) {
401 time_stretched_cn_samples_ =
402 timestamp_leap - status.generated_noise_samples;
Jakob Ivarssone6aabd02022-03-28 16:06:37 +0200403 return NetEq::Operation::kNormal;
Henrik Lundin7687ad52018-07-02 10:14:46 +0200404 }
Jakob Ivarsson46dda832019-07-03 16:00:30 +0200405
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200406 if (status.last_mode == NetEq::Mode::kRfc3389Cng) {
Ivo Creusen3ce44a32019-10-31 14:38:11 +0100407 return NetEq::Operation::kRfc3389CngNoPacket;
Jakob Ivarsson46dda832019-07-03 16:00:30 +0200408 }
Ivo Creusen3ce44a32019-10-31 14:38:11 +0100409 return NetEq::Operation::kCodecInternalCng;
Henrik Lundin7687ad52018-07-02 10:14:46 +0200410 }
Jakob Ivarsson46dda832019-07-03 16:00:30 +0200411
Henrik Lundin7687ad52018-07-02 10:14:46 +0200412 // Do not merge unless we have done an expand before.
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200413 if (status.last_mode == NetEq::Mode::kExpand) {
Ivo Creusen3ce44a32019-10-31 14:38:11 +0100414 return NetEq::Operation::kMerge;
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200415 } else if (status.play_dtmf) {
Henrik Lundin7687ad52018-07-02 10:14:46 +0200416 // Play DTMF instead of expand.
Ivo Creusen3ce44a32019-10-31 14:38:11 +0100417 return NetEq::Operation::kDtmf;
Henrik Lundin7687ad52018-07-02 10:14:46 +0200418 } else {
Ivo Creusen3ce44a32019-10-31 14:38:11 +0100419 return NetEq::Operation::kExpand;
Henrik Lundin7687ad52018-07-02 10:14:46 +0200420 }
421}
422
423bool DecisionLogic::UnderTargetLevel() const {
Jakob Ivarsson609b0472020-10-19 09:19:34 +0200424 return buffer_level_filter_->filtered_current_level() <
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200425 TargetLevelMs() * sample_rate_khz_;
Henrik Lundin7687ad52018-07-02 10:14:46 +0200426}
427
428bool DecisionLogic::ReinitAfterExpands(uint32_t timestamp_leap) const {
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200429 return timestamp_leap >= static_cast<uint32_t>(output_size_samples_ *
430 config_.reinit_after_expands);
Henrik Lundin7687ad52018-07-02 10:14:46 +0200431}
432
433bool DecisionLogic::PacketTooEarly(uint32_t timestamp_leap) const {
434 return timestamp_leap >
435 static_cast<uint32_t>(output_size_samples_ * num_consecutive_expands_);
436}
437
438bool DecisionLogic::MaxWaitForPacket() const {
Jakob Ivarssonc782cf82022-05-16 15:28:22 +0200439 return num_consecutive_expands_ >= kMaxWaitForPacketTicks;
440}
441
442bool DecisionLogic::ShouldContinueExpand(
443 NetEqController::NetEqStatus status) const {
444 uint32_t timestamp_leap =
445 status.next_packet->timestamp - status.target_timestamp;
446 if (config_.enable_stable_playout_delay) {
447 return GetNextPacketDelayMs(status) < HighThreshold() &&
448 PacketTooEarly(timestamp_leap);
449 }
450 return !ReinitAfterExpands(timestamp_leap) && !MaxWaitForPacket() &&
451 PacketTooEarly(timestamp_leap) && UnderTargetLevel();
452}
453
454int DecisionLogic::GetNextPacketDelayMs(
455 NetEqController::NetEqStatus status) const {
456 if (config_.enable_stable_playout_delay) {
457 return packet_arrival_history_.GetDelayMs(
458 status.next_packet->timestamp,
459 tick_timer_->ticks() * tick_timer_->ms_per_tick());
460 }
461 return status.packet_buffer_info.span_samples / sample_rate_khz_;
462}
463
464int DecisionLogic::GetPlayoutDelayMs(
465 NetEqController::NetEqStatus status) const {
466 uint32_t playout_timestamp =
467 status.target_timestamp - status.sync_buffer_samples;
468 return packet_arrival_history_.GetDelayMs(
469 playout_timestamp, tick_timer_->ticks() * tick_timer_->ms_per_tick());
470}
471
472int DecisionLogic::LowThreshold() const {
473 int target_delay_ms = TargetLevelMs();
474 return std::max(
475 target_delay_ms * 3 / 4,
476 target_delay_ms - config_.deceleration_target_level_offset_ms);
477}
478
479int DecisionLogic::HighThreshold() const {
480 if (config_.enable_stable_playout_delay) {
481 return std::max(TargetLevelMs(), packet_arrival_history_.GetMaxDelayMs()) +
482 kDelayAdjustmentGranularityMs;
483 }
484 return std::max(TargetLevelMs(),
485 LowThreshold() + kDelayAdjustmentGranularityMs);
486}
487
488int DecisionLogic::LowThresholdCng() const {
489 if (config_.enable_stable_playout_delay) {
490 return LowThreshold();
491 }
492 return std::max(0, TargetLevelMs() - kTargetLevelWindowMs / 2);
493}
494
495int DecisionLogic::HighThresholdCng() const {
496 if (config_.enable_stable_playout_delay) {
497 return HighThreshold();
498 }
499 return TargetLevelMs() + kTargetLevelWindowMs / 2;
Henrik Lundin7687ad52018-07-02 10:14:46 +0200500}
501
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000502} // namespace webrtc