19a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org/*
29a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org *  Copyright (c) 2011 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/rtcp.h"
129a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
139a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org#include <string.h>
149a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
15201049cd791b718821495a7951e1d3d9ea3bf1c1henrik.lundin@webrtc.org#include <algorithm>
16201049cd791b718821495a7951e1d3d9ea3bf1c1henrik.lundin@webrtc.org
179a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
189a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org#include "webrtc/modules/interface/module_common_types.h"
199a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
209a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgnamespace webrtc {
219a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
229a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid Rtcp::Init(uint16_t start_sequence_number) {
239a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  cycles_ = 0;
249a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  max_seq_no_ = start_sequence_number;
259a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  base_seq_no_ = start_sequence_number;
269a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  received_packets_ = 0;
279a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  received_packets_prior_ = 0;
289a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  expected_prior_ = 0;
299a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  jitter_ = 0;
309a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  transit_ = 0;
319a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
329a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
339a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid Rtcp::Update(const RTPHeader& rtp_header, uint32_t receive_timestamp) {
349a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Update number of received packets, and largest packet number received.
359a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  received_packets_++;
369a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int16_t sn_diff = rtp_header.sequenceNumber - max_seq_no_;
379a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  if (sn_diff >= 0) {
389a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    if (rtp_header.sequenceNumber < max_seq_no_) {
399a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      // Wrap-around detected.
409a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      cycles_++;
419a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    }
429a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    max_seq_no_ = rtp_header.sequenceNumber;
439a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
449a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
459a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Calculate jitter according to RFC 3550, and update previous timestamps.
469a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Note that the value in |jitter_| is in Q4.
479a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  if (received_packets_ > 1) {
489a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    int32_t ts_diff = receive_timestamp - (rtp_header.timestamp - transit_);
499a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    ts_diff = WEBRTC_SPL_ABS_W32(ts_diff);
509a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    int32_t jitter_diff = (ts_diff << 4) - jitter_;
519a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // Calculate 15 * jitter_ / 16 + jitter_diff / 16 (with proper rounding).
529a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    jitter_ = jitter_ + ((jitter_diff + 8) >> 4);
539a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
549a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  transit_ = rtp_header.timestamp - receive_timestamp;
559a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
569a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
579a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid Rtcp::GetStatistics(bool no_reset, RtcpStatistics* stats) {
589a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Extended highest sequence number received.
592714c796f7d474b58ae4eab18b6863d7988a3487sprang@webrtc.org  stats->extended_max_sequence_number =
602714c796f7d474b58ae4eab18b6863d7988a3487sprang@webrtc.org      (static_cast<int>(cycles_) << 16) + max_seq_no_;
619a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
629a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Calculate expected number of packets and compare it with the number of
639a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // packets that were actually received. The cumulative number of lost packets
649a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // can be extracted.
652714c796f7d474b58ae4eab18b6863d7988a3487sprang@webrtc.org  uint32_t expected_packets =
662714c796f7d474b58ae4eab18b6863d7988a3487sprang@webrtc.org      stats->extended_max_sequence_number - base_seq_no_ + 1;
679a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  if (received_packets_ == 0) {
689a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    // No packets received, assume none lost.
699a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    stats->cumulative_lost = 0;
709a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  } else if (expected_packets > received_packets_) {
719a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    stats->cumulative_lost = expected_packets - received_packets_;
729a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    if (stats->cumulative_lost > 0xFFFFFF) {
739a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org      stats->cumulative_lost = 0xFFFFFF;
749a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    }
759a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  } else {
769a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    stats->cumulative_lost = 0;
779a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
789a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
799a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  // Fraction lost since last report.
809a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  uint32_t expected_since_last = expected_packets - expected_prior_;
819a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  uint32_t received_since_last = received_packets_ - received_packets_prior_;
829a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  if (!no_reset) {
839a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    expected_prior_ = expected_packets;
849a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    received_packets_prior_ = received_packets_;
859a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
869a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  int32_t lost = expected_since_last - received_since_last;
879a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  if (expected_since_last == 0 || lost <= 0 || received_packets_ == 0) {
889a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org    stats->fraction_lost = 0;
899a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  } else {
902714c796f7d474b58ae4eab18b6863d7988a3487sprang@webrtc.org    stats->fraction_lost = std::min(0xFFU, (lost << 8) / expected_since_last);
919a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  }
929a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
939a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org  stats->jitter = jitter_ >> 4;  // Scaling from Q4.
949a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}
959a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org
969a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org}  // namespace webrtc
97