19a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org/*
29a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
39a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org *
49a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org *  Use of this source code is governed by a BSD-style license
59a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org *  that can be found in the LICENSE file in the root of the source
69a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org *  tree. An additional intellectual property rights grant can be found
79a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org *  in the file PATENTS.  All contributing project authors may
89a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
99a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org */
109a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
11e5abc854f3dc47de16067c2a41476c39b7626722henrik.lundin@webrtc.org#include "webrtc/modules/audio_coding/neteq/delay_peak_detector.h"
129a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
139a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org#include <algorithm>  // max
149a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
159a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgnamespace webrtc {
169a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
179a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org// The DelayPeakDetector keeps track of severe inter-arrival times, called
189a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org// delay peaks. When a peak is observed, the "height" (the time elapsed since
199a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org// the previous packet arrival) and the peak "period" (the time since the last
209a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org// observed peak) is recorded in a vector. When enough peaks have been observed,
219a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org// peak-mode is engaged and the DelayManager asks the DelayPeakDetector for
229a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org// the worst peak height.
239a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
249a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgDelayPeakDetector::DelayPeakDetector()
259a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  : peak_found_(false),
269a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    peak_detection_threshold_(0),
279a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    peak_period_counter_ms_(-1) {
289a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
299a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
309a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid DelayPeakDetector::Reset() {
319a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  peak_period_counter_ms_ = -1;  // Indicate that next peak is the first.
329a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  peak_found_ = false;
339a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  peak_history_.clear();
349a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
359a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
369a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org// Calculates the threshold in number of packets.
379a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid DelayPeakDetector::SetPacketAudioLength(int length_ms) {
389a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  if (length_ms > 0) {
399a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    peak_detection_threshold_ = kPeakHeightMs / length_ms;
409a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
419a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
429a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
439a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgint DelayPeakDetector::MaxPeakHeight() const {
449a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int max_height = -1;  // Returns -1 for an empty history.
459a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  std::list<Peak>::const_iterator it;
469a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  for (it = peak_history_.begin(); it != peak_history_.end(); ++it) {
479a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    max_height = std::max(max_height, it->peak_height_packets);
489a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
499a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  return max_height;
509a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
519a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
529a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgint DelayPeakDetector::MaxPeakPeriod() const {
539a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int max_period = -1;  // Returns -1 for an empty history.
549a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  std::list<Peak>::const_iterator it;
559a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  for (it = peak_history_.begin(); it != peak_history_.end(); ++it) {
569a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    max_period = std::max(max_period, it->period_ms);
579a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
589a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  return max_period;
599a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
609a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
619a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgbool DelayPeakDetector::Update(int inter_arrival_time, int target_level) {
629a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  if (inter_arrival_time > target_level + peak_detection_threshold_ ||
639a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      inter_arrival_time > 2 * target_level) {
649a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // A delay peak is observed.
659a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    if (peak_period_counter_ms_ == -1) {
669a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // This is the first peak. Reset the period counter.
679a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      peak_period_counter_ms_ = 0;
689a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    } else if (peak_period_counter_ms_ <= kMaxPeakPeriodMs) {
699a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // This is not the first peak, and the period is valid.
709a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // Store peak data in the vector.
719a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      Peak peak_data;
729a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      peak_data.period_ms = peak_period_counter_ms_;
739a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      peak_data.peak_height_packets = inter_arrival_time;
749a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      peak_history_.push_back(peak_data);
759a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      while (peak_history_.size() > kMaxNumPeaks) {
769a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        // Delete the oldest data point.
779a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org        peak_history_.pop_front();
789a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      }
799a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      peak_period_counter_ms_ = 0;
809a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    } else if (peak_period_counter_ms_ <= 2 * kMaxPeakPeriodMs) {
819a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // Invalid peak due to too long period. Reset period counter and start
829a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // looking for next peak.
839a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      peak_period_counter_ms_ = 0;
849a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    } else {
859a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // More than 2 times the maximum period has elapsed since the last peak
869a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // was registered. It seams that the network conditions have changed.
879a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // Reset the peak statistics.
889a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      Reset();
899a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    }
909a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
919a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  return CheckPeakConditions();
929a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
939a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
949a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid DelayPeakDetector::IncrementCounter(int inc_ms) {
959a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  if (peak_period_counter_ms_ >= 0) {
969a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    peak_period_counter_ms_ += inc_ms;
979a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
989a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
999a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1009a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgbool DelayPeakDetector::CheckPeakConditions() {
1019a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  size_t s = peak_history_.size();
1029a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  if (s >= kMinPeaksToTrigger &&
1039a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      peak_period_counter_ms_ <= 2 * MaxPeakPeriod()) {
1049a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    peak_found_ = true;
1059a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  } else {
1069a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    peak_found_ = false;
1079a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
1089a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  return peak_found_;
1099a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
1109a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}  // namespace webrtc
111