tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

decision_logic.cc (13670B)


      1 /*
      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 
     11 #include "modules/audio_coding/neteq/decision_logic.h"
     12 
     13 #include <cstdint>
     14 #include <cstdio>
     15 #include <memory>
     16 #include <optional>
     17 #include <utility>
     18 
     19 #include "api/environment/environment.h"
     20 #include "api/neteq/delay_manager_interface.h"
     21 #include "api/neteq/neteq.h"
     22 #include "api/neteq/neteq_controller.h"
     23 #include "modules/audio_coding/neteq/buffer_level_filter.h"
     24 #include "modules/audio_coding/neteq/packet_arrival_history.h"
     25 #include "modules/audio_coding/neteq/packet_buffer.h"
     26 #include "rtc_base/checks.h"
     27 #include "rtc_base/numerics/safe_conversions.h"
     28 
     29 namespace webrtc {
     30 
     31 namespace {
     32 
     33 constexpr int kPostponeDecodingLevel = 50;
     34 constexpr int kTargetLevelWindowMs = 100;
     35 // The granularity of delay adjustments (accelerate/preemptive expand) is 15ms,
     36 // but round up since the clock has a granularity of 10ms.
     37 constexpr int kDelayAdjustmentGranularityMs = 20;
     38 constexpr int kPacketHistorySizeMs = 2000;
     39 constexpr size_t kCngTimeoutMs = 1000;
     40 
     41 bool IsTimestretch(NetEq::Mode mode) {
     42  return mode == NetEq::Mode::kAccelerateSuccess ||
     43         mode == NetEq::Mode::kAccelerateLowEnergy ||
     44         mode == NetEq::Mode::kPreemptiveExpandSuccess ||
     45         mode == NetEq::Mode::kPreemptiveExpandLowEnergy;
     46 }
     47 
     48 bool IsCng(NetEq::Mode mode) {
     49  return mode == NetEq::Mode::kRfc3389Cng ||
     50         mode == NetEq::Mode::kCodecInternalCng;
     51 }
     52 
     53 bool IsExpand(NetEq::Mode mode) {
     54  return mode == NetEq::Mode::kExpand || mode == NetEq::Mode::kCodecPlc;
     55 }
     56 
     57 }  // namespace
     58 
     59 DecisionLogic::DecisionLogic(
     60    const Environment& env,
     61    NetEqController::Config config,
     62    std::unique_ptr<DelayManagerInterface> delay_manager)
     63    : DecisionLogic(config,
     64                    std::move(delay_manager),
     65                    std::make_unique<BufferLevelFilter>()) {}
     66 
     67 DecisionLogic::DecisionLogic(
     68    NetEqController::Config config,
     69    std::unique_ptr<DelayManagerInterface> delay_manager,
     70    std::unique_ptr<BufferLevelFilter> buffer_level_filter,
     71    std::unique_ptr<PacketArrivalHistory> packet_arrival_history)
     72    : delay_manager_(std::move(delay_manager)),
     73      delay_constraints_(config.max_packets_in_buffer,
     74                         config.base_min_delay_ms),
     75      buffer_level_filter_(std::move(buffer_level_filter)),
     76      packet_arrival_history_(
     77          packet_arrival_history
     78              ? std::move(packet_arrival_history)
     79              : std::make_unique<PacketArrivalHistory>(config.tick_timer,
     80                                                       kPacketHistorySizeMs)),
     81      tick_timer_(config.tick_timer),
     82      disallow_time_stretching_(!config.allow_time_stretching),
     83      timescale_countdown_(
     84          tick_timer_->GetNewCountdown(kMinTimescaleInterval + 1)) {}
     85 
     86 DecisionLogic::~DecisionLogic() = default;
     87 
     88 void DecisionLogic::SoftReset() {
     89  packet_length_samples_ = 0;
     90  sample_memory_ = 0;
     91  prev_time_scale_ = false;
     92  timescale_countdown_ =
     93      tick_timer_->GetNewCountdown(kMinTimescaleInterval + 1);
     94  time_stretched_cn_samples_ = 0;
     95  delay_manager_->Reset();
     96  buffer_level_filter_->Reset();
     97  packet_arrival_history_->Reset();
     98 }
     99 
    100 void DecisionLogic::SetSampleRate(int fs_hz, size_t output_size_samples) {
    101  // TODO(hlundin): Change to an enumerator and skip assert.
    102  RTC_DCHECK(fs_hz == 8000 || fs_hz == 16000 || fs_hz == 32000 ||
    103             fs_hz == 48000);
    104  sample_rate_khz_ = fs_hz / 1000;
    105  output_size_samples_ = output_size_samples;
    106  packet_arrival_history_->set_sample_rate(fs_hz);
    107 }
    108 
    109 NetEq::Operation DecisionLogic::GetDecision(const NetEqStatus& status,
    110                                            bool* /* reset_decoder */) {
    111  prev_time_scale_ = prev_time_scale_ && IsTimestretch(status.last_mode);
    112  if (prev_time_scale_) {
    113    timescale_countdown_ = tick_timer_->GetNewCountdown(kMinTimescaleInterval);
    114  }
    115  if (!IsCng(status.last_mode) && !IsExpand(status.last_mode)) {
    116    FilterBufferLevel(status.packet_buffer_info.span_samples);
    117  }
    118 
    119  // Guard for errors, to avoid getting stuck in error mode.
    120  if (status.last_mode == NetEq::Mode::kError) {
    121    if (!status.next_packet) {
    122      return NetEq::Operation::kExpand;
    123    } else {
    124      // Use kUndefined to flag for a reset.
    125      return NetEq::Operation::kUndefined;
    126    }
    127  }
    128 
    129  if (status.next_packet && status.next_packet->is_cng) {
    130    return CngOperation(status);
    131  }
    132 
    133  // Handle the case with no packet at all available (except maybe DTMF).
    134  if (!status.next_packet) {
    135    return NoPacket(status);
    136  }
    137 
    138  if (PostponeDecode(status)) {
    139    return NoPacket(status);
    140  }
    141 
    142  const uint32_t five_seconds_samples =
    143      static_cast<uint32_t>(5000 * sample_rate_khz_);
    144  // Check if the required packet is available.
    145  if (status.target_timestamp == status.next_packet->timestamp) {
    146    return ExpectedPacketAvailable(status);
    147  }
    148  if (!PacketBuffer::IsObsoleteTimestamp(status.next_packet->timestamp,
    149                                         status.target_timestamp,
    150                                         five_seconds_samples)) {
    151    return FuturePacketAvailable(status);
    152  }
    153  // This implies that available_timestamp < target_timestamp, which can
    154  // happen when a new stream or codec is received. Signal for a reset.
    155  return NetEq::Operation::kUndefined;
    156 }
    157 
    158 int DecisionLogic::TargetLevelMs() const {
    159  return delay_constraints_.Clamp(UnlimitedTargetLevelMs());
    160 }
    161 
    162 int DecisionLogic::UnlimitedTargetLevelMs() const {
    163  return delay_manager_->TargetDelayMs();
    164 }
    165 
    166 int DecisionLogic::GetFilteredBufferLevel() const {
    167  return buffer_level_filter_->filtered_current_level();
    168 }
    169 
    170 std::optional<int> DecisionLogic::PacketArrived(int fs_hz,
    171                                                bool should_update_stats,
    172                                                const PacketArrivedInfo& info) {
    173  buffer_flush_ = buffer_flush_ || info.buffer_flush;
    174  if (!should_update_stats || info.is_cng_or_dtmf) {
    175    return std::nullopt;
    176  }
    177  if (info.packet_length_samples > 0 && fs_hz > 0 &&
    178      info.packet_length_samples != packet_length_samples_) {
    179    packet_length_samples_ = info.packet_length_samples;
    180    delay_constraints_.SetPacketAudioLength(packet_length_samples_ * 1000 /
    181                                            fs_hz);
    182  }
    183  bool inserted = packet_arrival_history_->Insert(info.main_timestamp,
    184                                                  info.packet_length_samples);
    185  if (!inserted || packet_arrival_history_->size() < 2) {
    186    // No meaningful delay estimate unless at least 2 packets have arrived.
    187    return std::nullopt;
    188  }
    189  int arrival_delay_ms =
    190      packet_arrival_history_->GetDelayMs(info.main_timestamp);
    191  bool reordered =
    192      !packet_arrival_history_->IsNewestRtpTimestamp(info.main_timestamp);
    193  delay_manager_->Update(arrival_delay_ms, reordered, info);
    194  return arrival_delay_ms;
    195 }
    196 
    197 void DecisionLogic::FilterBufferLevel(size_t buffer_size_samples) {
    198  buffer_level_filter_->SetTargetBufferLevel(TargetLevelMs());
    199 
    200  int time_stretched_samples = time_stretched_cn_samples_;
    201  if (prev_time_scale_) {
    202    time_stretched_samples += sample_memory_;
    203  }
    204 
    205  if (buffer_flush_) {
    206    buffer_level_filter_->SetFilteredBufferLevel(buffer_size_samples);
    207    buffer_flush_ = false;
    208  } else {
    209    buffer_level_filter_->Update(buffer_size_samples, time_stretched_samples);
    210  }
    211  prev_time_scale_ = false;
    212  time_stretched_cn_samples_ = 0;
    213 }
    214 
    215 NetEq::Operation DecisionLogic::CngOperation(
    216    NetEqController::NetEqStatus status) {
    217  // Signed difference between target and available timestamp.
    218  int32_t timestamp_diff = static_cast<int32_t>(
    219      static_cast<uint32_t>(status.generated_noise_samples +
    220                            status.target_timestamp) -
    221      status.next_packet->timestamp);
    222  int optimal_level_samp = TargetLevelMs() * sample_rate_khz_;
    223  const int64_t excess_waiting_time_samp =
    224      -static_cast<int64_t>(timestamp_diff) - optimal_level_samp;
    225 
    226  if (excess_waiting_time_samp > optimal_level_samp / 2) {
    227    // The waiting time for this packet will be longer than 1.5
    228    // times the wanted buffer delay. Apply fast-forward to cut the
    229    // waiting time down to the optimal.
    230    noise_fast_forward_ =
    231        saturated_cast<size_t>(noise_fast_forward_ + excess_waiting_time_samp);
    232    timestamp_diff =
    233        saturated_cast<int32_t>(timestamp_diff + excess_waiting_time_samp);
    234  }
    235 
    236  if (timestamp_diff < 0 && status.last_mode == NetEq::Mode::kRfc3389Cng) {
    237    // Not time to play this packet yet. Wait another round before using this
    238    // packet. Keep on playing CNG from previous CNG parameters.
    239    return NetEq::Operation::kRfc3389CngNoPacket;
    240  } else {
    241    // Otherwise, go for the CNG packet now.
    242    noise_fast_forward_ = 0;
    243    return NetEq::Operation::kRfc3389Cng;
    244  }
    245 }
    246 
    247 NetEq::Operation DecisionLogic::NoPacket(NetEqController::NetEqStatus status) {
    248  switch (status.last_mode) {
    249    case NetEq::Mode::kRfc3389Cng:
    250      return NetEq::Operation::kRfc3389CngNoPacket;
    251    case NetEq::Mode::kCodecInternalCng: {
    252      // Stop CNG after a timeout.
    253      if (status.generated_noise_samples > kCngTimeoutMs * sample_rate_khz_) {
    254        return NetEq::Operation::kExpand;
    255      }
    256      return NetEq::Operation::kCodecInternalCng;
    257    }
    258    default:
    259      return status.play_dtmf ? NetEq::Operation::kDtmf
    260                              : NetEq::Operation::kExpand;
    261  }
    262 }
    263 
    264 NetEq::Operation DecisionLogic::ExpectedPacketAvailable(
    265    NetEqController::NetEqStatus status) {
    266  if (!disallow_time_stretching_ && status.last_mode != NetEq::Mode::kExpand &&
    267      !status.play_dtmf) {
    268    const int playout_delay_ms = GetPlayoutDelayMs(status);
    269    const int64_t low_limit = TargetLevelMs();
    270    const int64_t high_limit = low_limit +
    271                               packet_arrival_history_->GetMaxDelayMs() +
    272                               kDelayAdjustmentGranularityMs;
    273    if (playout_delay_ms >= high_limit * 4) {
    274      return NetEq::Operation::kFastAccelerate;
    275    }
    276    if (TimescaleAllowed()) {
    277      if (playout_delay_ms >= high_limit) {
    278        return NetEq::Operation::kAccelerate;
    279      }
    280      if (playout_delay_ms < low_limit) {
    281        return NetEq::Operation::kPreemptiveExpand;
    282      }
    283    }
    284  }
    285  return NetEq::Operation::kNormal;
    286 }
    287 
    288 NetEq::Operation DecisionLogic::FuturePacketAvailable(
    289    NetEqController::NetEqStatus status) {
    290  // Required packet is not available, but a future packet is.
    291  // Check if we should continue with an ongoing concealment because the new
    292  // packet is too far into the future.
    293  const int buffer_delay_samples =
    294      status.packet_buffer_info.span_samples_wait_time;
    295  const int buffer_delay_ms = buffer_delay_samples / sample_rate_khz_;
    296  const int high_limit = TargetLevelMs() + kTargetLevelWindowMs / 2;
    297  const bool above_target_delay = buffer_delay_ms > high_limit;
    298  if ((PacketTooEarly(status) && !above_target_delay)) {
    299    return NoPacket(status);
    300  }
    301  uint32_t timestamp_leap =
    302      status.next_packet->timestamp - status.target_timestamp;
    303  if (timestamp_leap != status.generated_noise_samples) {
    304    // The delay was adjusted, reinitialize the buffer level filter.
    305    buffer_level_filter_->SetFilteredBufferLevel(buffer_delay_samples);
    306  }
    307 
    308  // Time to play the next packet.
    309  switch (status.last_mode) {
    310    case NetEq::Mode::kExpand:
    311      return NetEq::Operation::kMerge;
    312    case NetEq::Mode::kCodecPlc:
    313    case NetEq::Mode::kRfc3389Cng:
    314    case NetEq::Mode::kCodecInternalCng:
    315      return NetEq::Operation::kNormal;
    316    default:
    317      return status.play_dtmf ? NetEq::Operation::kDtmf
    318                              : NetEq::Operation::kExpand;
    319  }
    320 }
    321 
    322 bool DecisionLogic::UnderTargetLevel() const {
    323  return buffer_level_filter_->filtered_current_level() <
    324         TargetLevelMs() * sample_rate_khz_;
    325 }
    326 
    327 bool DecisionLogic::PostponeDecode(NetEqController::NetEqStatus status) const {
    328  // Make sure we don't restart audio too soon after CNG or expand to avoid
    329  // running out of data right away again.
    330  const size_t min_buffer_level_samples =
    331      TargetLevelMs() * sample_rate_khz_ * kPostponeDecodingLevel / 100;
    332  const size_t buffer_level_samples =
    333      status.packet_buffer_info.span_samples_wait_time;
    334  if (buffer_level_samples >= min_buffer_level_samples) {
    335    return false;
    336  }
    337  // Don't postpone decoding if there is a future DTX packet in the packet
    338  // buffer.
    339  if (status.packet_buffer_info.dtx_or_cng) {
    340    return false;
    341  }
    342  // Continue CNG until the buffer is at least at the minimum level.
    343  if (IsCng(status.last_mode)) {
    344    return true;
    345  }
    346  // Only continue expand if the mute factor is low enough (otherwise the
    347  // expansion was short enough to not be noticable). Note that the MuteFactor
    348  // is in Q14, so a value of 16384 corresponds to 1.
    349  if (IsExpand(status.last_mode) && status.expand_mutefactor < 16384 / 2) {
    350    return true;
    351  }
    352  return false;
    353 }
    354 
    355 bool DecisionLogic::PacketTooEarly(NetEqController::NetEqStatus status) const {
    356  const uint32_t timestamp_leap =
    357      status.next_packet->timestamp - status.target_timestamp;
    358  return timestamp_leap > status.generated_noise_samples;
    359 }
    360 
    361 int DecisionLogic::GetPlayoutDelayMs(
    362    NetEqController::NetEqStatus status) const {
    363  uint32_t playout_timestamp =
    364      status.target_timestamp - status.sync_buffer_samples;
    365  return packet_arrival_history_->GetDelayMs(playout_timestamp);
    366 }
    367 
    368 }  // namespace webrtc