Add helper classes to send and receive abs-capture-time extensions.
This change adds helper classes to manipulate Absolute Capture Time header extensions. Both classes support the "timestamp interpolation" optimization. Bug: webrtc:10739 Change-Id: I08eff46eb8910842a6dbaa3288b976004fabe1c7 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/149801 Commit-Queue: Chen Xing <chxg@google.com> Reviewed-by: Erik Språng <sprang@webrtc.org> Cr-Commit-Position: refs/heads/master@{#28936}
This commit is contained in:
parent
9fd2908f2e
commit
05f8f1d273
@ -131,6 +131,10 @@ rtc_static_library("rtp_rtcp") {
|
||||
"include/rtp_header_parser.h",
|
||||
"include/rtp_rtcp.h",
|
||||
"include/ulpfec_receiver.h",
|
||||
"source/absolute_capture_time_receiver.cc",
|
||||
"source/absolute_capture_time_receiver.h",
|
||||
"source/absolute_capture_time_sender.cc",
|
||||
"source/absolute_capture_time_sender.h",
|
||||
"source/dtmf_queue.cc",
|
||||
"source/dtmf_queue.h",
|
||||
"source/fec_private_tables_bursty.cc",
|
||||
@ -224,6 +228,8 @@ rtc_static_library("rtp_rtcp") {
|
||||
"../../api/rtc_event_log",
|
||||
"../../api/transport:field_trial_based_config",
|
||||
"../../api/transport:webrtc_key_value_config",
|
||||
"../../api/units:time_delta",
|
||||
"../../api/units:timestamp",
|
||||
"../../api/video:video_bitrate_allocation",
|
||||
"../../api/video:video_bitrate_allocator",
|
||||
"../../api/video:video_frame",
|
||||
@ -385,6 +391,8 @@ if (rtc_include_tests) {
|
||||
testonly = true
|
||||
|
||||
sources = [
|
||||
"source/absolute_capture_time_receiver_unittest.cc",
|
||||
"source/absolute_capture_time_sender_unittest.cc",
|
||||
"source/byte_io_unittest.cc",
|
||||
"source/fec_private_tables_bursty_unittest.cc",
|
||||
"source/flexfec_header_reader_writer_unittest.cc",
|
||||
|
||||
150
modules/rtp_rtcp/source/absolute_capture_time_receiver.cc
Normal file
150
modules/rtp_rtcp/source/absolute_capture_time_receiver.cc
Normal file
@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "modules/rtp_rtcp/source/absolute_capture_time_receiver.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "rtc_base/checks.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
constexpr Timestamp kInvalidLastReceiveTime = Timestamp::MinusInfinity();
|
||||
} // namespace
|
||||
|
||||
constexpr TimeDelta AbsoluteCaptureTimeReceiver::kInterpolationMaxInterval;
|
||||
|
||||
AbsoluteCaptureTimeReceiver::AbsoluteCaptureTimeReceiver(Clock* clock)
|
||||
: clock_(clock),
|
||||
remote_to_local_clock_offset_(absl::nullopt),
|
||||
last_receive_time_(kInvalidLastReceiveTime) {}
|
||||
|
||||
uint32_t AbsoluteCaptureTimeReceiver::GetSource(
|
||||
uint32_t ssrc,
|
||||
rtc::ArrayView<const uint32_t> csrcs) {
|
||||
if (csrcs.empty()) {
|
||||
return ssrc;
|
||||
}
|
||||
|
||||
return csrcs[0];
|
||||
}
|
||||
|
||||
void AbsoluteCaptureTimeReceiver::SetRemoteToLocalClockOffset(
|
||||
absl::optional<int64_t> value_q32x32) {
|
||||
rtc::CritScope cs(&crit_);
|
||||
|
||||
remote_to_local_clock_offset_ = value_q32x32;
|
||||
}
|
||||
|
||||
absl::optional<AbsoluteCaptureTime>
|
||||
AbsoluteCaptureTimeReceiver::OnReceivePacket(
|
||||
uint32_t source,
|
||||
uint32_t rtp_timestamp,
|
||||
uint32_t rtp_clock_frequency,
|
||||
const absl::optional<AbsoluteCaptureTime>& received_extension) {
|
||||
const Timestamp receive_time = clock_->CurrentTime();
|
||||
|
||||
rtc::CritScope cs(&crit_);
|
||||
|
||||
AbsoluteCaptureTime extension;
|
||||
if (received_extension == absl::nullopt) {
|
||||
if (!ShouldInterpolateExtension(receive_time, source, rtp_timestamp,
|
||||
rtp_clock_frequency)) {
|
||||
last_receive_time_ = kInvalidLastReceiveTime;
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
extension.absolute_capture_timestamp = InterpolateAbsoluteCaptureTimestamp(
|
||||
rtp_timestamp, rtp_clock_frequency, last_rtp_timestamp_,
|
||||
last_absolute_capture_timestamp_);
|
||||
extension.estimated_capture_clock_offset =
|
||||
last_estimated_capture_clock_offset_;
|
||||
} else {
|
||||
last_source_ = source;
|
||||
last_rtp_timestamp_ = rtp_timestamp;
|
||||
last_rtp_clock_frequency_ = rtp_clock_frequency;
|
||||
last_absolute_capture_timestamp_ =
|
||||
received_extension->absolute_capture_timestamp;
|
||||
last_estimated_capture_clock_offset_ =
|
||||
received_extension->estimated_capture_clock_offset;
|
||||
|
||||
last_receive_time_ = receive_time;
|
||||
|
||||
extension = *received_extension;
|
||||
}
|
||||
|
||||
extension.estimated_capture_clock_offset = AdjustEstimatedCaptureClockOffset(
|
||||
extension.estimated_capture_clock_offset);
|
||||
|
||||
return extension;
|
||||
}
|
||||
|
||||
uint64_t AbsoluteCaptureTimeReceiver::InterpolateAbsoluteCaptureTimestamp(
|
||||
uint32_t rtp_timestamp,
|
||||
uint32_t rtp_clock_frequency,
|
||||
uint32_t last_rtp_timestamp,
|
||||
uint64_t last_absolute_capture_timestamp) {
|
||||
RTC_DCHECK_GT(rtp_clock_frequency, 0);
|
||||
|
||||
return last_absolute_capture_timestamp +
|
||||
static_cast<int64_t>(
|
||||
rtc::dchecked_cast<uint64_t>(rtp_timestamp - last_rtp_timestamp)
|
||||
<< 32) /
|
||||
rtp_clock_frequency;
|
||||
}
|
||||
|
||||
bool AbsoluteCaptureTimeReceiver::ShouldInterpolateExtension(
|
||||
Timestamp receive_time,
|
||||
uint32_t source,
|
||||
uint32_t rtp_timestamp,
|
||||
uint32_t rtp_clock_frequency) const {
|
||||
// Shouldn't if we don't have a previously received extension stored.
|
||||
if (last_receive_time_ == kInvalidLastReceiveTime) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Shouldn't if the last received extension is too old.
|
||||
if ((receive_time - last_receive_time_) > kInterpolationMaxInterval) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Shouldn't if the source has changed.
|
||||
if (last_source_ != source) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Shouldn't if the RTP clock frequency has changed.
|
||||
if (last_rtp_clock_frequency_ != rtp_clock_frequency) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Shouldn't if the RTP clock frequency is invalid.
|
||||
if (rtp_clock_frequency <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
absl::optional<int64_t>
|
||||
AbsoluteCaptureTimeReceiver::AdjustEstimatedCaptureClockOffset(
|
||||
absl::optional<int64_t> received_value) const {
|
||||
if (received_value == absl::nullopt ||
|
||||
remote_to_local_clock_offset_ == absl::nullopt) {
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
// Do calculations as "unsigned" to make overflows deterministic.
|
||||
return static_cast<uint64_t>(*received_value) +
|
||||
static_cast<uint64_t>(*remote_to_local_clock_offset_);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
100
modules/rtp_rtcp/source/absolute_capture_time_receiver.h
Normal file
100
modules/rtp_rtcp/source/absolute_capture_time_receiver.h
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef MODULES_RTP_RTCP_SOURCE_ABSOLUTE_CAPTURE_TIME_RECEIVER_H_
|
||||
#define MODULES_RTP_RTCP_SOURCE_ABSOLUTE_CAPTURE_TIME_RECEIVER_H_
|
||||
|
||||
#include "api/array_view.h"
|
||||
#include "api/rtp_headers.h"
|
||||
#include "api/units/time_delta.h"
|
||||
#include "api/units/timestamp.h"
|
||||
#include "rtc_base/critical_section.h"
|
||||
#include "rtc_base/thread_annotations.h"
|
||||
#include "system_wrappers/include/clock.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
//
|
||||
// Helper class for receiving the |AbsoluteCaptureTime| header extension.
|
||||
//
|
||||
// Supports the "timestamp interpolation" optimization:
|
||||
// A receiver SHOULD memorize the capture system (i.e. CSRC/SSRC), capture
|
||||
// timestamp, and RTP timestamp of the most recently received abs-capture-time
|
||||
// packet on each received stream. It can then use that information, in
|
||||
// combination with RTP timestamps of packets without abs-capture-time, to
|
||||
// extrapolate missing capture timestamps.
|
||||
//
|
||||
// See: https://webrtc.org/experiments/rtp-hdrext/abs-capture-time/
|
||||
//
|
||||
class AbsoluteCaptureTimeReceiver {
|
||||
public:
|
||||
static constexpr TimeDelta kInterpolationMaxInterval =
|
||||
TimeDelta::Millis<5000>();
|
||||
|
||||
explicit AbsoluteCaptureTimeReceiver(Clock* clock);
|
||||
|
||||
// Returns the source (i.e. SSRC or CSRC) of the capture system.
|
||||
static uint32_t GetSource(uint32_t ssrc,
|
||||
rtc::ArrayView<const uint32_t> csrcs);
|
||||
|
||||
// Sets the NTP clock offset between the sender system (which may be different
|
||||
// from the capture system) and the local system. This information is normally
|
||||
// provided by passing half the value of the Round-Trip Time estimation given
|
||||
// by RTCP sender reports (see DLSR/DLRR).
|
||||
//
|
||||
// Note that the value must be in Q32.32-formatted fixed-point seconds.
|
||||
void SetRemoteToLocalClockOffset(absl::optional<int64_t> value_q32x32);
|
||||
|
||||
// Returns a received header extension, an interpolated header extension, or
|
||||
// |absl::nullopt| if it's not possible to interpolate a header extension.
|
||||
absl::optional<AbsoluteCaptureTime> OnReceivePacket(
|
||||
uint32_t source,
|
||||
uint32_t rtp_timestamp,
|
||||
uint32_t rtp_clock_frequency,
|
||||
const absl::optional<AbsoluteCaptureTime>& received_extension);
|
||||
|
||||
private:
|
||||
friend class AbsoluteCaptureTimeSender;
|
||||
|
||||
static uint64_t InterpolateAbsoluteCaptureTimestamp(
|
||||
uint32_t rtp_timestamp,
|
||||
uint32_t rtp_clock_frequency,
|
||||
uint32_t last_rtp_timestamp,
|
||||
uint64_t last_absolute_capture_timestamp);
|
||||
|
||||
bool ShouldInterpolateExtension(Timestamp receive_time,
|
||||
uint32_t source,
|
||||
uint32_t rtp_timestamp,
|
||||
uint32_t rtp_clock_frequency) const
|
||||
RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_);
|
||||
|
||||
absl::optional<int64_t> AdjustEstimatedCaptureClockOffset(
|
||||
absl::optional<int64_t> received_value) const
|
||||
RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_);
|
||||
|
||||
Clock* const clock_;
|
||||
|
||||
rtc::CriticalSection crit_;
|
||||
|
||||
absl::optional<int64_t> remote_to_local_clock_offset_ RTC_GUARDED_BY(crit_);
|
||||
|
||||
Timestamp last_receive_time_ RTC_GUARDED_BY(crit_);
|
||||
|
||||
uint32_t last_source_ RTC_GUARDED_BY(crit_);
|
||||
uint32_t last_rtp_timestamp_ RTC_GUARDED_BY(crit_);
|
||||
uint32_t last_rtp_clock_frequency_ RTC_GUARDED_BY(crit_);
|
||||
uint64_t last_absolute_capture_timestamp_ RTC_GUARDED_BY(crit_);
|
||||
absl::optional<int64_t> last_estimated_capture_clock_offset_
|
||||
RTC_GUARDED_BY(crit_);
|
||||
}; // AbsoluteCaptureTimeReceiver
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // MODULES_RTP_RTCP_SOURCE_ABSOLUTE_CAPTURE_TIME_RECEIVER_H_
|
||||
@ -0,0 +1,416 @@
|
||||
/*
|
||||
* Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "modules/rtp_rtcp/source/absolute_capture_time_receiver.h"
|
||||
|
||||
#include "system_wrappers/include/ntp_time.h"
|
||||
#include "test/gmock.h"
|
||||
#include "test/gtest.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
TEST(AbsoluteCaptureTimeReceiverTest, GetSourceWithoutCsrcs) {
|
||||
constexpr uint32_t kSsrc = 12;
|
||||
|
||||
EXPECT_EQ(AbsoluteCaptureTimeReceiver::GetSource(kSsrc, nullptr), kSsrc);
|
||||
}
|
||||
|
||||
TEST(AbsoluteCaptureTimeReceiverTest, GetSourceWithCsrcs) {
|
||||
constexpr uint32_t kSsrc = 12;
|
||||
constexpr uint32_t kCsrcs[] = {34, 56, 78, 90};
|
||||
|
||||
EXPECT_EQ(AbsoluteCaptureTimeReceiver::GetSource(kSsrc, kCsrcs), kCsrcs[0]);
|
||||
}
|
||||
|
||||
TEST(AbsoluteCaptureTimeReceiverTest, ReceiveExtensionReturnsExtension) {
|
||||
constexpr uint32_t kSource = 1337;
|
||||
constexpr uint32_t kRtpClockFrequency = 64000;
|
||||
constexpr uint32_t kRtpTimestamp0 = 1020300000;
|
||||
constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280;
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension0 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension1 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9020), absl::nullopt};
|
||||
|
||||
SimulatedClock clock(0);
|
||||
AbsoluteCaptureTimeReceiver receiver(&clock);
|
||||
|
||||
receiver.SetRemoteToLocalClockOffset(0);
|
||||
|
||||
EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp0,
|
||||
kRtpClockFrequency, kExtension0),
|
||||
kExtension0);
|
||||
|
||||
EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp1,
|
||||
kRtpClockFrequency, kExtension1),
|
||||
kExtension1);
|
||||
}
|
||||
|
||||
TEST(AbsoluteCaptureTimeReceiverTest, ReceiveNoExtensionReturnsNoExtension) {
|
||||
constexpr uint32_t kSource = 1337;
|
||||
constexpr uint32_t kRtpClockFrequency = 64000;
|
||||
constexpr uint32_t kRtpTimestamp0 = 1020300000;
|
||||
constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280;
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension0 = absl::nullopt;
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension1 = absl::nullopt;
|
||||
|
||||
SimulatedClock clock(0);
|
||||
AbsoluteCaptureTimeReceiver receiver(&clock);
|
||||
|
||||
receiver.SetRemoteToLocalClockOffset(0);
|
||||
|
||||
EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp0,
|
||||
kRtpClockFrequency, kExtension0),
|
||||
absl::nullopt);
|
||||
|
||||
EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp1,
|
||||
kRtpClockFrequency, kExtension1),
|
||||
absl::nullopt);
|
||||
}
|
||||
|
||||
TEST(AbsoluteCaptureTimeReceiverTest, InterpolateLaterPacketArrivingLater) {
|
||||
constexpr uint32_t kSource = 1337;
|
||||
constexpr uint32_t kRtpClockFrequency = 64000;
|
||||
constexpr uint32_t kRtpTimestamp0 = 1020300000;
|
||||
constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280;
|
||||
constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 + 2560;
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension0 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension1 = absl::nullopt;
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension2 = absl::nullopt;
|
||||
|
||||
SimulatedClock clock(0);
|
||||
AbsoluteCaptureTimeReceiver receiver(&clock);
|
||||
|
||||
receiver.SetRemoteToLocalClockOffset(0);
|
||||
|
||||
EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp0,
|
||||
kRtpClockFrequency, kExtension0),
|
||||
kExtension0);
|
||||
|
||||
absl::optional<AbsoluteCaptureTime> extension = receiver.OnReceivePacket(
|
||||
kSource, kRtpTimestamp1, kRtpClockFrequency, kExtension1);
|
||||
EXPECT_TRUE(extension.has_value());
|
||||
EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp),
|
||||
UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) + 20);
|
||||
EXPECT_EQ(extension->estimated_capture_clock_offset,
|
||||
kExtension0->estimated_capture_clock_offset);
|
||||
|
||||
extension = receiver.OnReceivePacket(kSource, kRtpTimestamp2,
|
||||
kRtpClockFrequency, kExtension2);
|
||||
EXPECT_TRUE(extension.has_value());
|
||||
EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp),
|
||||
UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) + 40);
|
||||
EXPECT_EQ(extension->estimated_capture_clock_offset,
|
||||
kExtension0->estimated_capture_clock_offset);
|
||||
}
|
||||
|
||||
TEST(AbsoluteCaptureTimeReceiverTest, InterpolateEarlierPacketArrivingLater) {
|
||||
constexpr uint32_t kSource = 1337;
|
||||
constexpr uint32_t kRtpClockFrequency = 64000;
|
||||
constexpr uint32_t kRtpTimestamp0 = 1020300000;
|
||||
constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 - 1280;
|
||||
constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 - 2560;
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension0 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension1 = absl::nullopt;
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension2 = absl::nullopt;
|
||||
|
||||
SimulatedClock clock(0);
|
||||
AbsoluteCaptureTimeReceiver receiver(&clock);
|
||||
|
||||
receiver.SetRemoteToLocalClockOffset(0);
|
||||
|
||||
EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp0,
|
||||
kRtpClockFrequency, kExtension0),
|
||||
kExtension0);
|
||||
|
||||
absl::optional<AbsoluteCaptureTime> extension = receiver.OnReceivePacket(
|
||||
kSource, kRtpTimestamp1, kRtpClockFrequency, kExtension1);
|
||||
EXPECT_TRUE(extension.has_value());
|
||||
EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp),
|
||||
UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) - 20);
|
||||
EXPECT_EQ(extension->estimated_capture_clock_offset,
|
||||
kExtension0->estimated_capture_clock_offset);
|
||||
|
||||
extension = receiver.OnReceivePacket(kSource, kRtpTimestamp2,
|
||||
kRtpClockFrequency, kExtension2);
|
||||
EXPECT_TRUE(extension.has_value());
|
||||
EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp),
|
||||
UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) - 40);
|
||||
EXPECT_EQ(extension->estimated_capture_clock_offset,
|
||||
kExtension0->estimated_capture_clock_offset);
|
||||
}
|
||||
|
||||
TEST(AbsoluteCaptureTimeReceiverTest,
|
||||
InterpolateLaterPacketArrivingLaterWithRtpTimestampWrapAround) {
|
||||
constexpr uint32_t kSource = 1337;
|
||||
constexpr uint32_t kRtpClockFrequency = 64000;
|
||||
constexpr uint32_t kRtpTimestamp0 = ~uint32_t{0} - 79;
|
||||
constexpr uint32_t kRtpTimestamp1 = 1280 - 80;
|
||||
constexpr uint32_t kRtpTimestamp2 = 2560 - 80;
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension0 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension1 = absl::nullopt;
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension2 = absl::nullopt;
|
||||
|
||||
SimulatedClock clock(0);
|
||||
AbsoluteCaptureTimeReceiver receiver(&clock);
|
||||
|
||||
receiver.SetRemoteToLocalClockOffset(0);
|
||||
|
||||
EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp0,
|
||||
kRtpClockFrequency, kExtension0),
|
||||
kExtension0);
|
||||
|
||||
absl::optional<AbsoluteCaptureTime> extension = receiver.OnReceivePacket(
|
||||
kSource, kRtpTimestamp1, kRtpClockFrequency, kExtension1);
|
||||
EXPECT_TRUE(extension.has_value());
|
||||
EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp),
|
||||
UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) + 20);
|
||||
EXPECT_EQ(extension->estimated_capture_clock_offset,
|
||||
kExtension0->estimated_capture_clock_offset);
|
||||
|
||||
extension = receiver.OnReceivePacket(kSource, kRtpTimestamp2,
|
||||
kRtpClockFrequency, kExtension2);
|
||||
EXPECT_TRUE(extension.has_value());
|
||||
EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp),
|
||||
UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) + 40);
|
||||
EXPECT_EQ(extension->estimated_capture_clock_offset,
|
||||
kExtension0->estimated_capture_clock_offset);
|
||||
}
|
||||
|
||||
TEST(AbsoluteCaptureTimeReceiverTest,
|
||||
InterpolateEarlierPacketArrivingLaterWithRtpTimestampWrapAround) {
|
||||
constexpr uint32_t kSource = 1337;
|
||||
constexpr uint32_t kRtpClockFrequency = 64000;
|
||||
constexpr uint32_t kRtpTimestamp0 = 799;
|
||||
constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 - 1280;
|
||||
constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 - 2560;
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension0 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension1 = absl::nullopt;
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension2 = absl::nullopt;
|
||||
|
||||
SimulatedClock clock(0);
|
||||
AbsoluteCaptureTimeReceiver receiver(&clock);
|
||||
|
||||
receiver.SetRemoteToLocalClockOffset(0);
|
||||
|
||||
EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp0,
|
||||
kRtpClockFrequency, kExtension0),
|
||||
kExtension0);
|
||||
|
||||
absl::optional<AbsoluteCaptureTime> extension = receiver.OnReceivePacket(
|
||||
kSource, kRtpTimestamp1, kRtpClockFrequency, kExtension1);
|
||||
EXPECT_TRUE(extension.has_value());
|
||||
EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp),
|
||||
UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) - 20);
|
||||
EXPECT_EQ(extension->estimated_capture_clock_offset,
|
||||
kExtension0->estimated_capture_clock_offset);
|
||||
|
||||
extension = receiver.OnReceivePacket(kSource, kRtpTimestamp2,
|
||||
kRtpClockFrequency, kExtension2);
|
||||
EXPECT_TRUE(extension.has_value());
|
||||
EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp),
|
||||
UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) - 40);
|
||||
EXPECT_EQ(extension->estimated_capture_clock_offset,
|
||||
kExtension0->estimated_capture_clock_offset);
|
||||
}
|
||||
|
||||
TEST(AbsoluteCaptureTimeReceiverTest,
|
||||
SkipEstimatedCaptureClockOffsetIfRemoteToLocalClockOffsetIsUnknown) {
|
||||
constexpr uint32_t kSource = 1337;
|
||||
constexpr uint32_t kRtpClockFrequency = 64000;
|
||||
constexpr uint32_t kRtpTimestamp0 = 1020300000;
|
||||
constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280;
|
||||
constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 + 2560;
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension0 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension1 = absl::nullopt;
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension2 = absl::nullopt;
|
||||
static const absl::optional<int64_t> kRemoteToLocalClockOffset2 =
|
||||
Int64MsToQ32x32(-7000007);
|
||||
|
||||
SimulatedClock clock(0);
|
||||
AbsoluteCaptureTimeReceiver receiver(&clock);
|
||||
|
||||
receiver.SetRemoteToLocalClockOffset(0);
|
||||
|
||||
EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp0,
|
||||
kRtpClockFrequency, kExtension0),
|
||||
kExtension0);
|
||||
|
||||
receiver.SetRemoteToLocalClockOffset(absl::nullopt);
|
||||
|
||||
absl::optional<AbsoluteCaptureTime> extension = receiver.OnReceivePacket(
|
||||
kSource, kRtpTimestamp1, kRtpClockFrequency, kExtension1);
|
||||
EXPECT_TRUE(extension.has_value());
|
||||
EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp),
|
||||
UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) + 20);
|
||||
EXPECT_EQ(extension->estimated_capture_clock_offset, absl::nullopt);
|
||||
|
||||
receiver.SetRemoteToLocalClockOffset(kRemoteToLocalClockOffset2);
|
||||
|
||||
extension = receiver.OnReceivePacket(kSource, kRtpTimestamp2,
|
||||
kRtpClockFrequency, kExtension2);
|
||||
EXPECT_TRUE(extension.has_value());
|
||||
EXPECT_EQ(UQ32x32ToInt64Ms(extension->absolute_capture_timestamp),
|
||||
UQ32x32ToInt64Ms(kExtension0->absolute_capture_timestamp) + 40);
|
||||
EXPECT_EQ(extension->estimated_capture_clock_offset,
|
||||
*kExtension0->estimated_capture_clock_offset +
|
||||
*kRemoteToLocalClockOffset2);
|
||||
}
|
||||
|
||||
TEST(AbsoluteCaptureTimeReceiverTest, SkipInterpolateIfTooLate) {
|
||||
constexpr uint32_t kSource = 1337;
|
||||
constexpr uint32_t kRtpClockFrequency = 64000;
|
||||
constexpr uint32_t kRtpTimestamp0 = 1020300000;
|
||||
constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280;
|
||||
constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp1 + 1280;
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension0 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension1 = absl::nullopt;
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension2 = absl::nullopt;
|
||||
|
||||
SimulatedClock clock(0);
|
||||
AbsoluteCaptureTimeReceiver receiver(&clock);
|
||||
|
||||
receiver.SetRemoteToLocalClockOffset(0);
|
||||
|
||||
EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp0,
|
||||
kRtpClockFrequency, kExtension0),
|
||||
kExtension0);
|
||||
|
||||
clock.AdvanceTime(AbsoluteCaptureTimeReceiver::kInterpolationMaxInterval);
|
||||
|
||||
EXPECT_TRUE(receiver
|
||||
.OnReceivePacket(kSource, kRtpTimestamp1, kRtpClockFrequency,
|
||||
kExtension1)
|
||||
.has_value());
|
||||
|
||||
clock.AdvanceTimeMilliseconds(1);
|
||||
|
||||
EXPECT_FALSE(receiver
|
||||
.OnReceivePacket(kSource, kRtpTimestamp2, kRtpClockFrequency,
|
||||
kExtension2)
|
||||
.has_value());
|
||||
}
|
||||
|
||||
TEST(AbsoluteCaptureTimeReceiverTest, SkipInterpolateIfSourceChanged) {
|
||||
constexpr uint32_t kSource0 = 1337;
|
||||
constexpr uint32_t kSource1 = 1338;
|
||||
constexpr uint32_t kRtpClockFrequency = 64000;
|
||||
constexpr uint32_t kRtpTimestamp0 = 1020300000;
|
||||
constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280;
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension0 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension1 = absl::nullopt;
|
||||
|
||||
SimulatedClock clock(0);
|
||||
AbsoluteCaptureTimeReceiver receiver(&clock);
|
||||
|
||||
receiver.SetRemoteToLocalClockOffset(0);
|
||||
|
||||
EXPECT_EQ(receiver.OnReceivePacket(kSource0, kRtpTimestamp0,
|
||||
kRtpClockFrequency, kExtension0),
|
||||
kExtension0);
|
||||
|
||||
EXPECT_FALSE(receiver
|
||||
.OnReceivePacket(kSource1, kRtpTimestamp1,
|
||||
kRtpClockFrequency, kExtension1)
|
||||
.has_value());
|
||||
}
|
||||
|
||||
TEST(AbsoluteCaptureTimeReceiverTest,
|
||||
SkipInterpolateIfRtpClockFrequencyChanged) {
|
||||
constexpr uint32_t kSource = 1337;
|
||||
constexpr uint32_t kRtpClockFrequency0 = 64000;
|
||||
constexpr uint32_t kRtpClockFrequency1 = 32000;
|
||||
constexpr uint32_t kRtpTimestamp0 = 1020300000;
|
||||
constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 640;
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension0 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension1 = absl::nullopt;
|
||||
|
||||
SimulatedClock clock(0);
|
||||
AbsoluteCaptureTimeReceiver receiver(&clock);
|
||||
|
||||
receiver.SetRemoteToLocalClockOffset(0);
|
||||
|
||||
EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp0,
|
||||
kRtpClockFrequency0, kExtension0),
|
||||
kExtension0);
|
||||
|
||||
EXPECT_FALSE(receiver
|
||||
.OnReceivePacket(kSource, kRtpTimestamp1,
|
||||
kRtpClockFrequency1, kExtension1)
|
||||
.has_value());
|
||||
}
|
||||
|
||||
TEST(AbsoluteCaptureTimeReceiverTest,
|
||||
SkipInterpolateIfRtpClockFrequencyIsInvalid) {
|
||||
constexpr uint32_t kSource = 1337;
|
||||
constexpr uint32_t kRtpClockFrequency = 0;
|
||||
constexpr uint32_t kRtpTimestamp0 = 1020300000;
|
||||
constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 640;
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension0 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension1 = absl::nullopt;
|
||||
|
||||
SimulatedClock clock(0);
|
||||
AbsoluteCaptureTimeReceiver receiver(&clock);
|
||||
|
||||
receiver.SetRemoteToLocalClockOffset(0);
|
||||
|
||||
EXPECT_EQ(receiver.OnReceivePacket(kSource, kRtpTimestamp0,
|
||||
kRtpClockFrequency, kExtension0),
|
||||
kExtension0);
|
||||
|
||||
EXPECT_FALSE(receiver
|
||||
.OnReceivePacket(kSource, kRtpTimestamp1, kRtpClockFrequency,
|
||||
kExtension1)
|
||||
.has_value());
|
||||
}
|
||||
|
||||
TEST(AbsoluteCaptureTimeReceiverTest, SkipInterpolateIsSticky) {
|
||||
constexpr uint32_t kSource0 = 1337;
|
||||
constexpr uint32_t kSource1 = 1338;
|
||||
constexpr uint32_t kSource2 = 1337;
|
||||
constexpr uint32_t kRtpClockFrequency = 64000;
|
||||
constexpr uint32_t kRtpTimestamp0 = 1020300000;
|
||||
constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280;
|
||||
constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp1 + 1280;
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension0 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension1 = absl::nullopt;
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension2 = absl::nullopt;
|
||||
|
||||
SimulatedClock clock(0);
|
||||
AbsoluteCaptureTimeReceiver receiver(&clock);
|
||||
|
||||
receiver.SetRemoteToLocalClockOffset(0);
|
||||
|
||||
EXPECT_EQ(receiver.OnReceivePacket(kSource0, kRtpTimestamp0,
|
||||
kRtpClockFrequency, kExtension0),
|
||||
kExtension0);
|
||||
|
||||
EXPECT_FALSE(receiver
|
||||
.OnReceivePacket(kSource1, kRtpTimestamp1,
|
||||
kRtpClockFrequency, kExtension1)
|
||||
.has_value());
|
||||
|
||||
EXPECT_FALSE(receiver
|
||||
.OnReceivePacket(kSource2, kRtpTimestamp2,
|
||||
kRtpClockFrequency, kExtension2)
|
||||
.has_value());
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
124
modules/rtp_rtcp/source/absolute_capture_time_sender.cc
Normal file
124
modules/rtp_rtcp/source/absolute_capture_time_sender.cc
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "modules/rtp_rtcp/source/absolute_capture_time_sender.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "modules/rtp_rtcp/source/absolute_capture_time_receiver.h"
|
||||
#include "system_wrappers/include/ntp_time.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
constexpr Timestamp kInvalidLastSendTime = Timestamp::MinusInfinity();
|
||||
|
||||
} // namespace
|
||||
|
||||
constexpr TimeDelta AbsoluteCaptureTimeSender::kInterpolationMaxInterval;
|
||||
constexpr TimeDelta AbsoluteCaptureTimeSender::kInterpolationMaxError;
|
||||
|
||||
static_assert(
|
||||
AbsoluteCaptureTimeReceiver::kInterpolationMaxInterval >=
|
||||
AbsoluteCaptureTimeSender::kInterpolationMaxInterval,
|
||||
"Receivers should be as willing to interpolate timestamps as senders.");
|
||||
|
||||
AbsoluteCaptureTimeSender::AbsoluteCaptureTimeSender(Clock* clock)
|
||||
: clock_(clock), last_send_time_(kInvalidLastSendTime) {}
|
||||
|
||||
uint32_t AbsoluteCaptureTimeSender::GetSource(
|
||||
uint32_t ssrc,
|
||||
rtc::ArrayView<const uint32_t> csrcs) {
|
||||
return AbsoluteCaptureTimeReceiver::GetSource(ssrc, csrcs);
|
||||
}
|
||||
|
||||
absl::optional<AbsoluteCaptureTime> AbsoluteCaptureTimeSender::OnSendPacket(
|
||||
uint32_t source,
|
||||
uint32_t rtp_timestamp,
|
||||
uint32_t rtp_clock_frequency,
|
||||
uint64_t absolute_capture_timestamp,
|
||||
absl::optional<int64_t> estimated_capture_clock_offset) {
|
||||
const Timestamp send_time = clock_->CurrentTime();
|
||||
|
||||
rtc::CritScope cs(&crit_);
|
||||
|
||||
if (!ShouldSendExtension(send_time, source, rtp_timestamp,
|
||||
rtp_clock_frequency, absolute_capture_timestamp,
|
||||
estimated_capture_clock_offset)) {
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
last_source_ = source;
|
||||
last_rtp_timestamp_ = rtp_timestamp;
|
||||
last_rtp_clock_frequency_ = rtp_clock_frequency;
|
||||
last_absolute_capture_timestamp_ = absolute_capture_timestamp;
|
||||
last_estimated_capture_clock_offset_ = estimated_capture_clock_offset;
|
||||
|
||||
last_send_time_ = send_time;
|
||||
|
||||
AbsoluteCaptureTime extension;
|
||||
extension.absolute_capture_timestamp = absolute_capture_timestamp;
|
||||
extension.estimated_capture_clock_offset = estimated_capture_clock_offset;
|
||||
return extension;
|
||||
}
|
||||
|
||||
bool AbsoluteCaptureTimeSender::ShouldSendExtension(
|
||||
Timestamp send_time,
|
||||
uint32_t source,
|
||||
uint32_t rtp_timestamp,
|
||||
uint32_t rtp_clock_frequency,
|
||||
uint64_t absolute_capture_timestamp,
|
||||
absl::optional<int64_t> estimated_capture_clock_offset) const {
|
||||
// Should if we've never sent anything before.
|
||||
if (last_send_time_ == kInvalidLastSendTime) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Should if the last sent extension is too old.
|
||||
if ((send_time - last_send_time_) > kInterpolationMaxInterval) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Should if the source has changed.
|
||||
if (last_source_ != source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Should if the RTP clock frequency has changed.
|
||||
if (last_rtp_clock_frequency_ != rtp_clock_frequency) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Should if the RTP clock frequency is invalid.
|
||||
if (rtp_clock_frequency <= 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Should if the estimated capture clock offset has changed.
|
||||
if (last_estimated_capture_clock_offset_ != estimated_capture_clock_offset) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Should if interpolation would introduce too much error.
|
||||
const uint64_t interpolated_absolute_capture_timestamp =
|
||||
AbsoluteCaptureTimeReceiver::InterpolateAbsoluteCaptureTimestamp(
|
||||
rtp_timestamp, rtp_clock_frequency, last_rtp_timestamp_,
|
||||
last_absolute_capture_timestamp_);
|
||||
const int64_t interpolation_error_ms = UQ32x32ToInt64Ms(std::min(
|
||||
interpolated_absolute_capture_timestamp - absolute_capture_timestamp,
|
||||
absolute_capture_timestamp - interpolated_absolute_capture_timestamp));
|
||||
if (interpolation_error_ms > kInterpolationMaxError.ms()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
88
modules/rtp_rtcp/source/absolute_capture_time_sender.h
Normal file
88
modules/rtp_rtcp/source/absolute_capture_time_sender.h
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef MODULES_RTP_RTCP_SOURCE_ABSOLUTE_CAPTURE_TIME_SENDER_H_
|
||||
#define MODULES_RTP_RTCP_SOURCE_ABSOLUTE_CAPTURE_TIME_SENDER_H_
|
||||
|
||||
#include "api/array_view.h"
|
||||
#include "api/rtp_headers.h"
|
||||
#include "api/units/time_delta.h"
|
||||
#include "api/units/timestamp.h"
|
||||
#include "rtc_base/critical_section.h"
|
||||
#include "rtc_base/thread_annotations.h"
|
||||
#include "system_wrappers/include/clock.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
//
|
||||
// Helper class for sending the |AbsoluteCaptureTime| header extension.
|
||||
//
|
||||
// Supports the "timestamp interpolation" optimization:
|
||||
// A sender SHOULD save bandwidth by not sending abs-capture-time with every
|
||||
// RTP packet. It SHOULD still send them at regular intervals (e.g. every
|
||||
// second) to help mitigate the impact of clock drift and packet loss. Mixers
|
||||
// SHOULD always send abs-capture-time with the first RTP packet after
|
||||
// changing capture system.
|
||||
//
|
||||
// Timestamp interpolation works fine as long as there’s reasonably low
|
||||
// NTP/RTP clock drift. This is not always true. Senders that detect “jumps”
|
||||
// between its NTP and RTP clock mappings SHOULD send abs-capture-time with
|
||||
// the first RTP packet after such a thing happening.
|
||||
//
|
||||
// See: https://webrtc.org/experiments/rtp-hdrext/abs-capture-time/
|
||||
//
|
||||
class AbsoluteCaptureTimeSender {
|
||||
public:
|
||||
static constexpr TimeDelta kInterpolationMaxInterval =
|
||||
TimeDelta::Millis<1000>();
|
||||
static constexpr TimeDelta kInterpolationMaxError = TimeDelta::Millis<1>();
|
||||
|
||||
explicit AbsoluteCaptureTimeSender(Clock* clock);
|
||||
|
||||
// Returns the source (i.e. SSRC or CSRC) of the capture system.
|
||||
static uint32_t GetSource(uint32_t ssrc,
|
||||
rtc::ArrayView<const uint32_t> csrcs);
|
||||
|
||||
// Returns a header extension to be sent, or |absl::nullopt| if the header
|
||||
// extension shouldn't be sent.
|
||||
absl::optional<AbsoluteCaptureTime> OnSendPacket(
|
||||
uint32_t source,
|
||||
uint32_t rtp_timestamp,
|
||||
uint32_t rtp_clock_frequency,
|
||||
uint64_t absolute_capture_timestamp,
|
||||
absl::optional<int64_t> estimated_capture_clock_offset);
|
||||
|
||||
private:
|
||||
bool ShouldSendExtension(
|
||||
Timestamp send_time,
|
||||
uint32_t source,
|
||||
uint32_t rtp_timestamp,
|
||||
uint32_t rtp_clock_frequency,
|
||||
uint64_t absolute_capture_timestamp,
|
||||
absl::optional<int64_t> estimated_capture_clock_offset) const
|
||||
RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_);
|
||||
|
||||
Clock* const clock_;
|
||||
|
||||
rtc::CriticalSection crit_;
|
||||
|
||||
Timestamp last_send_time_ RTC_GUARDED_BY(crit_);
|
||||
|
||||
uint32_t last_source_ RTC_GUARDED_BY(crit_);
|
||||
uint32_t last_rtp_timestamp_ RTC_GUARDED_BY(crit_);
|
||||
uint32_t last_rtp_clock_frequency_ RTC_GUARDED_BY(crit_);
|
||||
uint64_t last_absolute_capture_timestamp_ RTC_GUARDED_BY(crit_);
|
||||
absl::optional<int64_t> last_estimated_capture_clock_offset_
|
||||
RTC_GUARDED_BY(crit_);
|
||||
}; // AbsoluteCaptureTimeSender
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // MODULES_RTP_RTCP_SOURCE_ABSOLUTE_CAPTURE_TIME_SENDER_H_
|
||||
374
modules/rtp_rtcp/source/absolute_capture_time_sender_unittest.cc
Normal file
374
modules/rtp_rtcp/source/absolute_capture_time_sender_unittest.cc
Normal file
@ -0,0 +1,374 @@
|
||||
/*
|
||||
* Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "modules/rtp_rtcp/source/absolute_capture_time_sender.h"
|
||||
|
||||
#include "system_wrappers/include/ntp_time.h"
|
||||
#include "test/gmock.h"
|
||||
#include "test/gtest.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
TEST(AbsoluteCaptureTimeSenderTest, GetSourceWithoutCsrcs) {
|
||||
constexpr uint32_t kSsrc = 12;
|
||||
|
||||
EXPECT_EQ(AbsoluteCaptureTimeSender::GetSource(kSsrc, nullptr), kSsrc);
|
||||
}
|
||||
|
||||
TEST(AbsoluteCaptureTimeSenderTest, GetSourceWithCsrcs) {
|
||||
constexpr uint32_t kSsrc = 12;
|
||||
constexpr uint32_t kCsrcs[] = {34, 56, 78, 90};
|
||||
|
||||
EXPECT_EQ(AbsoluteCaptureTimeSender::GetSource(kSsrc, kCsrcs), kCsrcs[0]);
|
||||
}
|
||||
|
||||
TEST(AbsoluteCaptureTimeSenderTest, InterpolateLaterPacketSentLater) {
|
||||
constexpr uint32_t kSource = 1337;
|
||||
constexpr uint32_t kRtpClockFrequency = 64000;
|
||||
constexpr uint32_t kRtpTimestamp0 = 1020300000;
|
||||
constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280;
|
||||
constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 + 2560;
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension0 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension1 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 20), Int64MsToQ32x32(-350)};
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension2 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 40), Int64MsToQ32x32(-350)};
|
||||
SimulatedClock clock(0);
|
||||
AbsoluteCaptureTimeSender sender(&clock);
|
||||
|
||||
EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency,
|
||||
kExtension0->absolute_capture_timestamp,
|
||||
kExtension0->estimated_capture_clock_offset),
|
||||
kExtension0);
|
||||
|
||||
EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency,
|
||||
kExtension1->absolute_capture_timestamp,
|
||||
kExtension1->estimated_capture_clock_offset),
|
||||
absl::nullopt);
|
||||
|
||||
EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency,
|
||||
kExtension2->absolute_capture_timestamp,
|
||||
kExtension2->estimated_capture_clock_offset),
|
||||
absl::nullopt);
|
||||
}
|
||||
|
||||
TEST(AbsoluteCaptureTimeSenderTest, InterpolateEarlierPacketSentLater) {
|
||||
constexpr uint32_t kSource = 1337;
|
||||
constexpr uint32_t kRtpClockFrequency = 64000;
|
||||
constexpr uint32_t kRtpTimestamp0 = 1020300000;
|
||||
constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 - 1280;
|
||||
constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 - 2560;
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension0 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension1 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000 - 20), Int64MsToQ32x32(-350)};
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension2 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000 - 40), Int64MsToQ32x32(-350)};
|
||||
|
||||
SimulatedClock clock(0);
|
||||
AbsoluteCaptureTimeSender sender(&clock);
|
||||
|
||||
EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency,
|
||||
kExtension0->absolute_capture_timestamp,
|
||||
kExtension0->estimated_capture_clock_offset),
|
||||
kExtension0);
|
||||
|
||||
EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency,
|
||||
kExtension1->absolute_capture_timestamp,
|
||||
kExtension1->estimated_capture_clock_offset),
|
||||
absl::nullopt);
|
||||
|
||||
EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency,
|
||||
kExtension2->absolute_capture_timestamp,
|
||||
kExtension2->estimated_capture_clock_offset),
|
||||
absl::nullopt);
|
||||
}
|
||||
|
||||
TEST(AbsoluteCaptureTimeSenderTest,
|
||||
InterpolateLaterPacketSentLaterWithRtpTimestampWrapAround) {
|
||||
constexpr uint32_t kSource = 1337;
|
||||
constexpr uint32_t kRtpClockFrequency = 64000;
|
||||
constexpr uint32_t kRtpTimestamp0 = ~uint32_t{0} - 79;
|
||||
constexpr uint32_t kRtpTimestamp1 = 1280 - 80;
|
||||
constexpr uint32_t kRtpTimestamp2 = 2560 - 80;
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension0 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension1 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 20), Int64MsToQ32x32(-350)};
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension2 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 40), Int64MsToQ32x32(-350)};
|
||||
|
||||
SimulatedClock clock(0);
|
||||
AbsoluteCaptureTimeSender sender(&clock);
|
||||
|
||||
EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency,
|
||||
kExtension0->absolute_capture_timestamp,
|
||||
kExtension0->estimated_capture_clock_offset),
|
||||
kExtension0);
|
||||
|
||||
EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency,
|
||||
kExtension1->absolute_capture_timestamp,
|
||||
kExtension1->estimated_capture_clock_offset),
|
||||
absl::nullopt);
|
||||
|
||||
EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency,
|
||||
kExtension2->absolute_capture_timestamp,
|
||||
kExtension2->estimated_capture_clock_offset),
|
||||
absl::nullopt);
|
||||
}
|
||||
|
||||
TEST(AbsoluteCaptureTimeSenderTest,
|
||||
InterpolateEarlierPacketSentLaterWithRtpTimestampWrapAround) {
|
||||
constexpr uint32_t kSource = 1337;
|
||||
constexpr uint32_t kRtpClockFrequency = 64000;
|
||||
constexpr uint32_t kRtpTimestamp0 = 799;
|
||||
constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 - 1280;
|
||||
constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 - 2560;
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension0 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension1 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000 - 20), Int64MsToQ32x32(-350)};
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension2 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000 - 40), Int64MsToQ32x32(-350)};
|
||||
|
||||
SimulatedClock clock(0);
|
||||
AbsoluteCaptureTimeSender sender(&clock);
|
||||
|
||||
EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency,
|
||||
kExtension0->absolute_capture_timestamp,
|
||||
kExtension0->estimated_capture_clock_offset),
|
||||
kExtension0);
|
||||
|
||||
EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency,
|
||||
kExtension1->absolute_capture_timestamp,
|
||||
kExtension1->estimated_capture_clock_offset),
|
||||
absl::nullopt);
|
||||
|
||||
EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency,
|
||||
kExtension2->absolute_capture_timestamp,
|
||||
kExtension2->estimated_capture_clock_offset),
|
||||
absl::nullopt);
|
||||
}
|
||||
|
||||
TEST(AbsoluteCaptureTimeSenderTest, SkipInterpolateIfTooLate) {
|
||||
constexpr uint32_t kSource = 1337;
|
||||
constexpr uint32_t kRtpClockFrequency = 64000;
|
||||
constexpr uint32_t kRtpTimestamp0 = 1020300000;
|
||||
constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280;
|
||||
constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 + 2560;
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension0 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension1 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 20), Int64MsToQ32x32(-350)};
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension2 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 40), Int64MsToQ32x32(-350)};
|
||||
|
||||
SimulatedClock clock(0);
|
||||
AbsoluteCaptureTimeSender sender(&clock);
|
||||
|
||||
EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency,
|
||||
kExtension0->absolute_capture_timestamp,
|
||||
kExtension0->estimated_capture_clock_offset),
|
||||
kExtension0);
|
||||
|
||||
clock.AdvanceTime(AbsoluteCaptureTimeSender::kInterpolationMaxInterval);
|
||||
|
||||
EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency,
|
||||
kExtension1->absolute_capture_timestamp,
|
||||
kExtension1->estimated_capture_clock_offset),
|
||||
absl::nullopt);
|
||||
|
||||
clock.AdvanceTimeMicroseconds(1);
|
||||
|
||||
EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency,
|
||||
kExtension2->absolute_capture_timestamp,
|
||||
kExtension2->estimated_capture_clock_offset),
|
||||
kExtension2);
|
||||
}
|
||||
|
||||
TEST(AbsoluteCaptureTimeSenderTest, SkipInterpolateIfSourceChanged) {
|
||||
constexpr uint32_t kSource0 = 1337;
|
||||
constexpr uint32_t kSource1 = 1338;
|
||||
constexpr uint32_t kSource2 = 1338;
|
||||
constexpr uint32_t kRtpClockFrequency = 64000;
|
||||
constexpr uint32_t kRtpTimestamp0 = 1020300000;
|
||||
constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280;
|
||||
constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 + 2560;
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension0 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension1 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 20), Int64MsToQ32x32(-350)};
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension2 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 40), Int64MsToQ32x32(-350)};
|
||||
|
||||
SimulatedClock clock(0);
|
||||
AbsoluteCaptureTimeSender sender(&clock);
|
||||
|
||||
EXPECT_EQ(sender.OnSendPacket(kSource0, kRtpTimestamp0, kRtpClockFrequency,
|
||||
kExtension0->absolute_capture_timestamp,
|
||||
kExtension0->estimated_capture_clock_offset),
|
||||
kExtension0);
|
||||
|
||||
EXPECT_EQ(sender.OnSendPacket(kSource1, kRtpTimestamp1, kRtpClockFrequency,
|
||||
kExtension1->absolute_capture_timestamp,
|
||||
kExtension1->estimated_capture_clock_offset),
|
||||
kExtension1);
|
||||
|
||||
EXPECT_EQ(sender.OnSendPacket(kSource2, kRtpTimestamp2, kRtpClockFrequency,
|
||||
kExtension2->absolute_capture_timestamp,
|
||||
kExtension2->estimated_capture_clock_offset),
|
||||
absl::nullopt);
|
||||
}
|
||||
|
||||
TEST(AbsoluteCaptureTimeSenderTest, SkipInterpolateIfRtpClockFrequencyChanged) {
|
||||
constexpr uint32_t kSource = 1337;
|
||||
constexpr uint32_t kRtpClockFrequency0 = 64000;
|
||||
constexpr uint32_t kRtpClockFrequency1 = 32000;
|
||||
constexpr uint32_t kRtpClockFrequency2 = 32000;
|
||||
constexpr uint32_t kRtpTimestamp0 = 1020300000;
|
||||
constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 640;
|
||||
constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 + 1280;
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension0 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension1 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 20), Int64MsToQ32x32(-350)};
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension2 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 40), Int64MsToQ32x32(-350)};
|
||||
|
||||
SimulatedClock clock(0);
|
||||
AbsoluteCaptureTimeSender sender(&clock);
|
||||
|
||||
EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency0,
|
||||
kExtension0->absolute_capture_timestamp,
|
||||
kExtension0->estimated_capture_clock_offset),
|
||||
kExtension0);
|
||||
|
||||
EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency1,
|
||||
kExtension1->absolute_capture_timestamp,
|
||||
kExtension1->estimated_capture_clock_offset),
|
||||
kExtension1);
|
||||
|
||||
EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency2,
|
||||
kExtension2->absolute_capture_timestamp,
|
||||
kExtension2->estimated_capture_clock_offset),
|
||||
absl::nullopt);
|
||||
}
|
||||
|
||||
TEST(AbsoluteCaptureTimeSenderTest,
|
||||
SkipInterpolateIfRtpClockFrequencyIsInvalid) {
|
||||
constexpr uint32_t kSource = 1337;
|
||||
constexpr uint32_t kRtpClockFrequency0 = 0;
|
||||
constexpr uint32_t kRtpClockFrequency1 = 0;
|
||||
constexpr uint32_t kRtpClockFrequency2 = 0;
|
||||
constexpr uint32_t kRtpTimestamp0 = 1020300000;
|
||||
constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0;
|
||||
constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0;
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension0 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension1 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 20), Int64MsToQ32x32(-350)};
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension2 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 40), Int64MsToQ32x32(-350)};
|
||||
|
||||
SimulatedClock clock(0);
|
||||
AbsoluteCaptureTimeSender sender(&clock);
|
||||
|
||||
EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency0,
|
||||
kExtension0->absolute_capture_timestamp,
|
||||
kExtension0->estimated_capture_clock_offset),
|
||||
kExtension0);
|
||||
|
||||
EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency1,
|
||||
kExtension1->absolute_capture_timestamp,
|
||||
kExtension1->estimated_capture_clock_offset),
|
||||
kExtension1);
|
||||
|
||||
EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency2,
|
||||
kExtension2->absolute_capture_timestamp,
|
||||
kExtension2->estimated_capture_clock_offset),
|
||||
kExtension2);
|
||||
}
|
||||
|
||||
TEST(AbsoluteCaptureTimeSenderTest,
|
||||
SkipInterpolateIfEstimatedCaptureClockOffsetChanged) {
|
||||
constexpr uint32_t kSource = 1337;
|
||||
constexpr uint32_t kRtpClockFrequency = 64000;
|
||||
constexpr uint32_t kRtpTimestamp0 = 1020300000;
|
||||
constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280;
|
||||
constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 + 2560;
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension0 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension1 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 20), Int64MsToQ32x32(370)};
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension2 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000 + 40), absl::nullopt};
|
||||
|
||||
SimulatedClock clock(0);
|
||||
AbsoluteCaptureTimeSender sender(&clock);
|
||||
|
||||
EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency,
|
||||
kExtension0->absolute_capture_timestamp,
|
||||
kExtension0->estimated_capture_clock_offset),
|
||||
kExtension0);
|
||||
|
||||
EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency,
|
||||
kExtension1->absolute_capture_timestamp,
|
||||
kExtension1->estimated_capture_clock_offset),
|
||||
kExtension1);
|
||||
|
||||
EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency,
|
||||
kExtension2->absolute_capture_timestamp,
|
||||
kExtension2->estimated_capture_clock_offset),
|
||||
kExtension2);
|
||||
}
|
||||
|
||||
TEST(AbsoluteCaptureTimeSenderTest,
|
||||
SkipInterpolateIfTooMuchInterpolationError) {
|
||||
constexpr uint32_t kSource = 1337;
|
||||
constexpr uint32_t kRtpClockFrequency = 64000;
|
||||
constexpr uint32_t kRtpTimestamp0 = 1020300000;
|
||||
constexpr uint32_t kRtpTimestamp1 = kRtpTimestamp0 + 1280;
|
||||
constexpr uint32_t kRtpTimestamp2 = kRtpTimestamp0 + 2560;
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension0 =
|
||||
AbsoluteCaptureTime{Int64MsToUQ32x32(9000), Int64MsToQ32x32(-350)};
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension1 =
|
||||
AbsoluteCaptureTime{
|
||||
Int64MsToUQ32x32(
|
||||
9000 + 20 +
|
||||
AbsoluteCaptureTimeSender::kInterpolationMaxError.ms()),
|
||||
Int64MsToQ32x32(-350)};
|
||||
static const absl::optional<AbsoluteCaptureTime> kExtension2 =
|
||||
AbsoluteCaptureTime{
|
||||
Int64MsToUQ32x32(
|
||||
9000 + 40 +
|
||||
AbsoluteCaptureTimeSender::kInterpolationMaxError.ms() + 1),
|
||||
Int64MsToQ32x32(-350)};
|
||||
|
||||
SimulatedClock clock(0);
|
||||
AbsoluteCaptureTimeSender sender(&clock);
|
||||
|
||||
EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp0, kRtpClockFrequency,
|
||||
kExtension0->absolute_capture_timestamp,
|
||||
kExtension0->estimated_capture_clock_offset),
|
||||
kExtension0);
|
||||
|
||||
EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp1, kRtpClockFrequency,
|
||||
kExtension1->absolute_capture_timestamp,
|
||||
kExtension1->estimated_capture_clock_offset),
|
||||
absl::nullopt);
|
||||
|
||||
EXPECT_EQ(sender.OnSendPacket(kSource, kRtpTimestamp2, kRtpClockFrequency,
|
||||
kExtension2->absolute_capture_timestamp,
|
||||
kExtension2->estimated_capture_clock_offset),
|
||||
kExtension2);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
Loading…
x
Reference in New Issue
Block a user