19a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org/*
29a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org *  Copyright (c) 2013 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/statistics_calculator.h"
129a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
139a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org#include <assert.h>
143f45c2e0ac4cb280f941efa3a3476895795e3dd6pbos@webrtc.org#include <string.h>  // memset
159a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
16e5abc854f3dc47de16067c2a41476c39b7626722henrik.lundin@webrtc.org#include "webrtc/modules/audio_coding/neteq/decision_logic.h"
17e5abc854f3dc47de16067c2a41476c39b7626722henrik.lundin@webrtc.org#include "webrtc/modules/audio_coding/neteq/delay_manager.h"
189a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
199a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgnamespace webrtc {
209a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
219a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgStatisticsCalculator::StatisticsCalculator()
229a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    : preemptive_samples_(0),
239a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      accelerate_samples_(0),
249a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      added_zero_samples_(0),
259a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      expanded_voice_samples_(0),
269a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      expanded_noise_samples_(0),
279a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      discarded_packets_(0),
289a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      lost_timestamps_(0),
299a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      last_report_timestamp_(0),
309a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      len_waiting_times_(0),
319a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      next_waiting_time_index_(0) {
329a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  memset(waiting_times_, 0, kLenWaitingTimes * sizeof(waiting_times_[0]));
339a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
349a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
359a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid StatisticsCalculator::Reset() {
369a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  preemptive_samples_ = 0;
379a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  accelerate_samples_ = 0;
389a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  added_zero_samples_ = 0;
399a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  expanded_voice_samples_ = 0;
409a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  expanded_noise_samples_ = 0;
419a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
429a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
439a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid StatisticsCalculator::ResetMcu() {
449a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  discarded_packets_ = 0;
459a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  lost_timestamps_ = 0;
469a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  last_report_timestamp_ = 0;
479a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
489a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
499a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid StatisticsCalculator::ResetWaitingTimeStatistics() {
509a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  memset(waiting_times_, 0, kLenWaitingTimes * sizeof(waiting_times_[0]));
519a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  len_waiting_times_ = 0;
529a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  next_waiting_time_index_ = 0;
539a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
549a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
559a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid StatisticsCalculator::ExpandedVoiceSamples(int num_samples) {
569a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  expanded_voice_samples_ += num_samples;
579a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
589a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
599a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid StatisticsCalculator::ExpandedNoiseSamples(int num_samples) {
609a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  expanded_noise_samples_ += num_samples;
619a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
629a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
639a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid StatisticsCalculator::PreemptiveExpandedSamples(int num_samples) {
649a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  preemptive_samples_ += num_samples;
659a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
669a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
679a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid StatisticsCalculator::AcceleratedSamples(int num_samples) {
689a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  accelerate_samples_ += num_samples;
699a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
709a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
719a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid StatisticsCalculator::AddZeros(int num_samples) {
729a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  added_zero_samples_ += num_samples;
739a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
749a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
759a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid StatisticsCalculator::PacketsDiscarded(int num_packets) {
769a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  discarded_packets_ += num_packets;
779a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
789a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
799a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid StatisticsCalculator::LostSamples(int num_samples) {
809a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  lost_timestamps_ += num_samples;
819a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
829a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
839a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid StatisticsCalculator::IncreaseCounter(int num_samples, int fs_hz) {
849a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  last_report_timestamp_ += num_samples;
859a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  if (last_report_timestamp_ >
869a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      static_cast<uint32_t>(fs_hz * kMaxReportPeriod)) {
879a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    lost_timestamps_ = 0;
889a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    last_report_timestamp_ = 0;
899a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    discarded_packets_ = 0;
909a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
919a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
929a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
939a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid StatisticsCalculator::StoreWaitingTime(int waiting_time_ms) {
949a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  assert(next_waiting_time_index_ < kLenWaitingTimes);
959a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  waiting_times_[next_waiting_time_index_] = waiting_time_ms;
969a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  next_waiting_time_index_++;
979a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  if (next_waiting_time_index_ >= kLenWaitingTimes) {
989a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    next_waiting_time_index_ = 0;
999a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
1009a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  if (len_waiting_times_ < kLenWaitingTimes) {
1019a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    len_waiting_times_++;
1029a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
1039a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
1049a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1059a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid StatisticsCalculator::GetNetworkStatistics(
1069a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    int fs_hz,
1079a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    int num_samples_in_buffers,
1089a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    int samples_per_packet,
1099a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    const DelayManager& delay_manager,
1109a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    const DecisionLogic& decision_logic,
1119a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    NetEqNetworkStatistics *stats) {
1129a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  if (fs_hz <= 0 || !stats) {
1139a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    assert(false);
1149a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    return;
1159a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
1169a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1179a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  stats->added_zero_samples = added_zero_samples_;
1189a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  stats->current_buffer_size_ms = num_samples_in_buffers * 1000 / fs_hz;
1199a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  const int ms_per_packet = decision_logic.packet_length_samples() /
1209a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      (fs_hz / 1000);
1219a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  stats->preferred_buffer_size_ms = (delay_manager.TargetLevel() >> 8) *
1229a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      ms_per_packet;
1239a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  stats->jitter_peaks_found = delay_manager.PeakFound();
1249a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  stats->clockdrift_ppm = delay_manager.AverageIAT();
1259a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1269a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  stats->packet_loss_rate = CalculateQ14Ratio(lost_timestamps_,
1279a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                              last_report_timestamp_);
1289a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1299a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  const unsigned discarded_samples = discarded_packets_ * samples_per_packet;
1309a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  stats->packet_discard_rate = CalculateQ14Ratio(discarded_samples,
1319a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                                 last_report_timestamp_);
1329a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1339a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  stats->accelerate_rate = CalculateQ14Ratio(accelerate_samples_,
1349a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                             last_report_timestamp_);
1359a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1369a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  stats->preemptive_rate = CalculateQ14Ratio(preemptive_samples_,
1379a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                             last_report_timestamp_);
1389a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1399a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  stats->expand_rate = CalculateQ14Ratio(expanded_voice_samples_ +
1409a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                         expanded_noise_samples_,
1419a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                         last_report_timestamp_);
1429a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1439a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Reset counters.
1449a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  ResetMcu();
1459a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  Reset();
1469a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
1479a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1489a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid StatisticsCalculator::WaitingTimes(std::vector<int>* waiting_times) {
1499a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  if (!waiting_times) {
1509a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    return;
1519a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
1529a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  waiting_times->assign(waiting_times_, waiting_times_ + len_waiting_times_);
1539a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  ResetWaitingTimeStatistics();
1549a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
1559a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1569a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgint StatisticsCalculator::CalculateQ14Ratio(uint32_t numerator,
1579a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org                                            uint32_t denominator) {
1589a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  if (numerator == 0) {
1599a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    return 0;
1609a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  } else if (numerator < denominator) {
1619a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Ratio must be smaller than 1 in Q14.
1629a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    assert((numerator << 14) / denominator < (1 << 14));
1639a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    return (numerator << 14) / denominator;
1649a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  } else {
1659a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Will not produce a ratio larger than 1, since this is probably an error.
1669a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    return 1 << 14;
1679a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
1689a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
1699a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
1709a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}  // namespace webrtc
171