Delete RtpReceiver and related code.

The RtpReceiver class is no longer used. Together with it, delete
RTPPayloadRegistry, RtpReceiverStrategy, and the tests under
modules/rtp_rtcp/test/testAPI/.

Bug: webrtc:8995
Change-Id: Ia9924d2f0f4315914a0dce6b7375ebb3601a6f96
Reviewed-on: https://webrtc-review.googlesource.com/c/103503
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Reviewed-by: Patrik Höglund <phoglund@webrtc.org>
Commit-Queue: Niels Moller <nisse@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#24968}
This commit is contained in:
Niels Möller 2018-10-03 16:02:09 +02:00 committed by Commit Bot
parent e9b74a77b1
commit 4a72ba99a7
21 changed files with 0 additions and 2659 deletions

View File

@ -30,7 +30,6 @@
#include "modules/pacing/packet_router.h"
#include "modules/rtp_rtcp/include/receive_statistics.h"
#include "modules/rtp_rtcp/source/rtp_packet_received.h"
#include "modules/rtp_rtcp/source/rtp_receiver_strategy.h"
#include "modules/utility/include/process_thread.h"
#include "rtc_base/checks.h"
#include "rtc_base/criticalsection.h"

View File

@ -111,8 +111,6 @@ rtc_static_library("rtp_rtcp") {
"include/receive_statistics.h",
"include/remote_ntp_time_estimator.h",
"include/rtp_header_parser.h",
"include/rtp_payload_registry.h",
"include/rtp_receiver.h",
"include/rtp_rtcp.h",
"include/ulpfec_receiver.h",
"source/contributing_sources.cc",
@ -159,15 +157,6 @@ rtc_static_library("rtp_rtcp") {
"source/rtp_header_parser.cc",
"source/rtp_packet_history.cc",
"source/rtp_packet_history.h",
"source/rtp_payload_registry.cc",
"source/rtp_receiver_audio.cc",
"source/rtp_receiver_audio.h",
"source/rtp_receiver_impl.cc",
"source/rtp_receiver_impl.h",
"source/rtp_receiver_strategy.cc",
"source/rtp_receiver_strategy.h",
"source/rtp_receiver_video.cc",
"source/rtp_receiver_video.h",
"source/rtp_rtcp_config.h",
"source/rtp_rtcp_impl.cc",
"source/rtp_rtcp_impl.h",
@ -410,8 +399,6 @@ if (rtc_include_tests) {
"source/rtp_header_extension_size_unittest.cc",
"source/rtp_packet_history_unittest.cc",
"source/rtp_packet_unittest.cc",
"source/rtp_payload_registry_unittest.cc",
"source/rtp_receiver_unittest.cc",
"source/rtp_rtcp_impl_unittest.cc",
"source/rtp_sender_unittest.cc",
"source/rtp_utility_unittest.cc",
@ -419,11 +406,6 @@ if (rtc_include_tests) {
"source/ulpfec_generator_unittest.cc",
"source/ulpfec_header_reader_writer_unittest.cc",
"source/ulpfec_receiver_unittest.cc",
"test/testAPI/test_api.cc",
"test/testAPI/test_api.h",
"test/testAPI/test_api_audio.cc",
"test/testAPI/test_api_rtcp.cc",
"test/testAPI/test_api_video.cc",
]
deps = [
":fec_test_helper",

View File

@ -1,66 +0,0 @@
/*
* Copyright (c) 2013 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_INCLUDE_RTP_PAYLOAD_REGISTRY_H_
#define MODULES_RTP_RTCP_INCLUDE_RTP_PAYLOAD_REGISTRY_H_
#include <map>
#include <set>
#include "absl/types/optional.h"
#include "api/audio_codecs/audio_format.h"
#include "api/video_codecs/video_codec.h"
#include "modules/rtp_rtcp/source/rtp_utility.h"
#include "rtc_base/criticalsection.h"
namespace webrtc {
class RTPPayloadRegistry {
public:
RTPPayloadRegistry();
~RTPPayloadRegistry();
// TODO(magjed): Split RTPPayloadRegistry into separate Audio and Video class
// and simplify the code. http://crbug/webrtc/6743.
// Replace all audio receive payload types with the given map.
void SetAudioReceivePayloads(std::map<int, SdpAudioFormat> codecs);
int32_t RegisterReceivePayload(int payload_type,
const SdpAudioFormat& audio_format,
bool* created_new_payload_type);
int32_t RegisterReceivePayload(const VideoCodec& video_codec);
int32_t DeRegisterReceivePayload(int8_t payload_type);
int GetPayloadTypeFrequency(uint8_t payload_type) const;
absl::optional<RtpUtility::Payload> PayloadTypeToPayload(
uint8_t payload_type) const;
private:
// Prunes the payload type map of the specific payload type, if it exists.
void DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType(
const SdpAudioFormat& audio_format);
rtc::CriticalSection crit_sect_;
std::map<int, RtpUtility::Payload> payload_type_map_;
// As a first step in splitting this class up in separate cases for audio and
// video, DCHECK that no instance is used for both audio and video.
#if RTC_DCHECK_IS_ON
bool used_for_audio_ RTC_GUARDED_BY(crit_sect_) = false;
bool used_for_video_ RTC_GUARDED_BY(crit_sect_) = false;
#endif
};
} // namespace webrtc
#endif // MODULES_RTP_RTCP_INCLUDE_RTP_PAYLOAD_REGISTRY_H_

View File

@ -1,86 +0,0 @@
/*
* Copyright (c) 2012 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_INCLUDE_RTP_RECEIVER_H_
#define MODULES_RTP_RTCP_INCLUDE_RTP_RECEIVER_H_
#include <vector>
#include "api/rtpreceiverinterface.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
namespace webrtc {
class RTPPayloadRegistry;
class VideoCodec;
class RtpReceiver {
public:
// Creates a video-enabled RTP receiver.
static RtpReceiver* CreateVideoReceiver(
Clock* clock,
RtpData* incoming_payload_callback,
RTPPayloadRegistry* rtp_payload_registry);
// Creates an audio-enabled RTP receiver.
static RtpReceiver* CreateAudioReceiver(
Clock* clock,
RtpData* incoming_payload_callback,
RTPPayloadRegistry* rtp_payload_registry);
virtual ~RtpReceiver() {}
// Registers a receive payload in the payload registry and notifies the media
// receiver strategy.
virtual int32_t RegisterReceivePayload(
int payload_type,
const SdpAudioFormat& audio_format) = 0;
// Deprecated version of the above.
int32_t RegisterReceivePayload(const CodecInst& audio_codec);
// Registers a receive payload in the payload registry.
virtual int32_t RegisterReceivePayload(const VideoCodec& video_codec) = 0;
// De-registers |payload_type| from the payload registry.
virtual int32_t DeRegisterReceivePayload(const int8_t payload_type) = 0;
// Parses the media specific parts of an RTP packet and updates the receiver
// state. This for instance means that any changes in SSRC and payload type is
// detected and acted upon.
virtual bool IncomingRtpPacket(const RTPHeader& rtp_header,
const uint8_t* payload,
size_t payload_length,
PayloadUnion payload_specific) = 0;
// TODO(nisse): Deprecated version, delete as soon as downstream
// applications are updated.
bool IncomingRtpPacket(const RTPHeader& rtp_header,
const uint8_t* payload,
size_t payload_length,
PayloadUnion payload_specific,
bool in_order /* Ignored */) {
return IncomingRtpPacket(rtp_header, payload, payload_length,
payload_specific);
}
// Gets the RTP timestamp and the corresponding monotonic system
// time for the most recent in-order packet. Returns true on
// success, false if no packet has been received.
virtual bool GetLatestTimestamps(uint32_t* timestamp,
int64_t* receive_time_ms) const = 0;
// Returns the remote SSRC of the currently received RTP stream.
virtual uint32_t SSRC() const = 0;
virtual std::vector<RtpSource> GetSources() const = 0;
};
} // namespace webrtc
#endif // MODULES_RTP_RTCP_INCLUDE_RTP_RECEIVER_H_

View File

@ -1,218 +0,0 @@
/*
* Copyright (c) 2013 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/include/rtp_payload_registry.h"
#include <algorithm>
#include "modules/audio_coding/codecs/audio_format_conversion.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
#include "rtc_base/stringutils.h"
namespace webrtc {
namespace {
bool PayloadIsCompatible(const RtpUtility::Payload& payload,
const SdpAudioFormat& audio_format) {
return payload.typeSpecific.is_audio() &&
audio_format.Matches(payload.typeSpecific.audio_payload().format);
}
bool PayloadIsCompatible(const RtpUtility::Payload& payload,
const VideoCodec& video_codec) {
if (!payload.typeSpecific.is_video() ||
_stricmp(payload.name, CodecTypeToPayloadString(video_codec.codecType)) !=
0)
return false;
// For H264, profiles must match as well.
if (video_codec.codecType == kVideoCodecH264) {
return video_codec.H264().profile ==
payload.typeSpecific.video_payload().h264_profile;
}
return true;
}
RtpUtility::Payload CreatePayloadType(const SdpAudioFormat& audio_format) {
RTC_DCHECK_GE(audio_format.clockrate_hz, 1000);
return {audio_format.name.c_str(),
PayloadUnion(AudioPayload{audio_format, 0})};
}
RtpUtility::Payload CreatePayloadType(const VideoCodec& video_codec) {
VideoPayload p;
p.videoCodecType = video_codec.codecType;
if (video_codec.codecType == kVideoCodecH264)
p.h264_profile = video_codec.H264().profile;
return {CodecTypeToPayloadString(video_codec.codecType), PayloadUnion(p)};
}
bool IsPayloadTypeValid(int8_t payload_type) {
assert(payload_type >= 0);
// Sanity check.
switch (payload_type) {
// Reserved payload types to avoid RTCP conflicts when marker bit is set.
case 64: // 192 Full INTRA-frame request.
case 72: // 200 Sender report.
case 73: // 201 Receiver report.
case 74: // 202 Source description.
case 75: // 203 Goodbye.
case 76: // 204 Application-defined.
case 77: // 205 Transport layer FB message.
case 78: // 206 Payload-specific FB message.
case 79: // 207 Extended report.
RTC_LOG(LS_ERROR) << "Can't register invalid receiver payload type: "
<< payload_type;
return false;
default:
return true;
}
}
} // namespace
RTPPayloadRegistry::RTPPayloadRegistry() = default;
RTPPayloadRegistry::~RTPPayloadRegistry() = default;
void RTPPayloadRegistry::SetAudioReceivePayloads(
std::map<int, SdpAudioFormat> codecs) {
rtc::CritScope cs(&crit_sect_);
#if RTC_DCHECK_IS_ON
RTC_DCHECK(!used_for_video_);
used_for_audio_ = true;
#endif
payload_type_map_.clear();
for (const auto& kv : codecs) {
const int& rtp_payload_type = kv.first;
const SdpAudioFormat& audio_format = kv.second;
RTC_DCHECK(IsPayloadTypeValid(rtp_payload_type));
payload_type_map_.emplace(rtp_payload_type,
CreatePayloadType(audio_format));
}
}
int32_t RTPPayloadRegistry::RegisterReceivePayload(
int payload_type,
const SdpAudioFormat& audio_format,
bool* created_new_payload) {
rtc::CritScope cs(&crit_sect_);
#if RTC_DCHECK_IS_ON
RTC_DCHECK(!used_for_video_);
used_for_audio_ = true;
#endif
*created_new_payload = false;
if (!IsPayloadTypeValid(payload_type))
return -1;
const auto it = payload_type_map_.find(payload_type);
if (it != payload_type_map_.end()) {
// We already use this payload type. Check if it's the same as we already
// have. If same, ignore sending an error.
if (PayloadIsCompatible(it->second, audio_format)) {
it->second.typeSpecific.audio_payload().rate = 0;
return 0;
}
RTC_LOG(LS_ERROR) << "Payload type already registered: " << payload_type;
return -1;
}
// Audio codecs must be unique.
DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType(audio_format);
const auto insert_status =
payload_type_map_.emplace(payload_type, CreatePayloadType(audio_format));
RTC_DCHECK(insert_status.second); // Insertion succeeded.
*created_new_payload = true;
// Successful set of payload type.
return 0;
}
int32_t RTPPayloadRegistry::RegisterReceivePayload(
const VideoCodec& video_codec) {
rtc::CritScope cs(&crit_sect_);
#if RTC_DCHECK_IS_ON
RTC_DCHECK(!used_for_audio_);
used_for_video_ = true;
#endif
if (!IsPayloadTypeValid(video_codec.plType))
return -1;
auto it = payload_type_map_.find(video_codec.plType);
if (it != payload_type_map_.end()) {
// We already use this payload type. Check if it's the same as we already
// have. If same, ignore sending an error.
if (PayloadIsCompatible(it->second, video_codec))
return 0;
RTC_LOG(LS_ERROR) << "Payload type already registered: "
<< static_cast<int>(video_codec.plType);
return -1;
}
const auto insert_status = payload_type_map_.emplace(
video_codec.plType, CreatePayloadType(video_codec));
RTC_DCHECK(insert_status.second); // Insertion succeeded.
// Successful set of payload type.
return 0;
}
int32_t RTPPayloadRegistry::DeRegisterReceivePayload(
const int8_t payload_type) {
rtc::CritScope cs(&crit_sect_);
payload_type_map_.erase(payload_type);
return 0;
}
// There can't be several codecs with the same rate, frequency and channels
// for audio codecs, but there can for video.
// Always called from within a critical section.
void RTPPayloadRegistry::DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType(
const SdpAudioFormat& audio_format) {
for (auto iterator = payload_type_map_.begin();
iterator != payload_type_map_.end(); ++iterator) {
if (PayloadIsCompatible(iterator->second, audio_format)) {
// Remove old setting.
payload_type_map_.erase(iterator);
break;
}
}
}
int RTPPayloadRegistry::GetPayloadTypeFrequency(uint8_t payload_type) const {
const auto payload = PayloadTypeToPayload(payload_type);
if (!payload) {
return -1;
}
rtc::CritScope cs(&crit_sect_);
return payload->typeSpecific.is_audio()
? payload->typeSpecific.audio_payload().format.clockrate_hz
: kVideoPayloadTypeFrequency;
}
absl::optional<RtpUtility::Payload> RTPPayloadRegistry::PayloadTypeToPayload(
uint8_t payload_type) const {
rtc::CritScope cs(&crit_sect_);
const auto it = payload_type_map_.find(payload_type);
return it == payload_type_map_.end()
? absl::nullopt
: absl::optional<RtpUtility::Payload>(it->second);
}
} // namespace webrtc

View File

@ -1,186 +0,0 @@
/*
* Copyright (c) 2013 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 <memory>
#include "common_types.h" // NOLINT(build/include)
#include "modules/rtp_rtcp/include/rtp_header_parser.h"
#include "modules/rtp_rtcp/include/rtp_payload_registry.h"
#include "modules/rtp_rtcp/source/rtp_utility.h"
#include "test/gmock.h"
#include "test/gtest.h"
namespace webrtc {
using ::testing::Eq;
using ::testing::Return;
using ::testing::StrEq;
using ::testing::_;
TEST(RtpPayloadRegistryTest,
RegistersAndRemembersVideoPayloadsUntilDeregistered) {
RTPPayloadRegistry rtp_payload_registry;
const uint8_t payload_type = 97;
VideoCodec video_codec;
video_codec.codecType = kVideoCodecVP8;
video_codec.plType = payload_type;
EXPECT_EQ(0, rtp_payload_registry.RegisterReceivePayload(video_codec));
const auto retrieved_payload =
rtp_payload_registry.PayloadTypeToPayload(payload_type);
EXPECT_TRUE(retrieved_payload);
// We should get back the corresponding payload that we registered.
EXPECT_STREQ("VP8", retrieved_payload->name);
EXPECT_TRUE(retrieved_payload->typeSpecific.is_video());
EXPECT_EQ(kVideoCodecVP8,
retrieved_payload->typeSpecific.video_payload().videoCodecType);
// Now forget about it and verify it's gone.
EXPECT_EQ(0, rtp_payload_registry.DeRegisterReceivePayload(payload_type));
EXPECT_FALSE(rtp_payload_registry.PayloadTypeToPayload(payload_type));
}
TEST(RtpPayloadRegistryTest,
RegistersAndRemembersAudioPayloadsUntilDeregistered) {
RTPPayloadRegistry rtp_payload_registry;
constexpr int payload_type = 97;
const SdpAudioFormat audio_format("name", 44000, 1);
bool new_payload_created = false;
EXPECT_EQ(0, rtp_payload_registry.RegisterReceivePayload(
payload_type, audio_format, &new_payload_created));
EXPECT_TRUE(new_payload_created) << "A new payload WAS created.";
const auto retrieved_payload =
rtp_payload_registry.PayloadTypeToPayload(payload_type);
EXPECT_TRUE(retrieved_payload);
// We should get back the corresponding payload that we registered.
EXPECT_STREQ("name", retrieved_payload->name);
EXPECT_TRUE(retrieved_payload->typeSpecific.is_audio());
EXPECT_EQ(audio_format,
retrieved_payload->typeSpecific.audio_payload().format);
// Now forget about it and verify it's gone.
EXPECT_EQ(0, rtp_payload_registry.DeRegisterReceivePayload(payload_type));
EXPECT_FALSE(rtp_payload_registry.PayloadTypeToPayload(payload_type));
}
TEST(RtpPayloadRegistryTest,
DoesNotAcceptSamePayloadTypeTwiceExceptIfPayloadIsCompatible) {
constexpr int payload_type = 97;
RTPPayloadRegistry rtp_payload_registry;
bool ignored = false;
const SdpAudioFormat audio_format("name", 44000, 1);
EXPECT_EQ(0, rtp_payload_registry.RegisterReceivePayload(
payload_type, audio_format, &ignored));
const SdpAudioFormat audio_format_2("name", 44001, 1); // Not compatible.
EXPECT_EQ(-1, rtp_payload_registry.RegisterReceivePayload(
payload_type, audio_format_2, &ignored))
<< "Adding incompatible codec with same payload type = bad.";
// Change payload type.
EXPECT_EQ(0, rtp_payload_registry.RegisterReceivePayload(
payload_type - 1, audio_format_2, &ignored))
<< "With a different payload type is fine though.";
// Ensure both payloads are preserved.
const auto retrieved_payload1 =
rtp_payload_registry.PayloadTypeToPayload(payload_type);
EXPECT_TRUE(retrieved_payload1);
EXPECT_STREQ("name", retrieved_payload1->name);
EXPECT_TRUE(retrieved_payload1->typeSpecific.is_audio());
EXPECT_EQ(audio_format,
retrieved_payload1->typeSpecific.audio_payload().format);
const auto retrieved_payload2 =
rtp_payload_registry.PayloadTypeToPayload(payload_type - 1);
EXPECT_TRUE(retrieved_payload2);
EXPECT_STREQ("name", retrieved_payload2->name);
EXPECT_TRUE(retrieved_payload2->typeSpecific.is_audio());
EXPECT_EQ(audio_format_2,
retrieved_payload2->typeSpecific.audio_payload().format);
// Ok, update the rate for one of the codecs. If either the incoming rate or
// the stored rate is zero it's not really an error to register the same
// codec twice, and in that case roughly the following happens.
EXPECT_EQ(0, rtp_payload_registry.RegisterReceivePayload(
payload_type, audio_format, &ignored));
}
TEST(RtpPayloadRegistryTest,
RemovesCompatibleCodecsOnRegistryIfCodecsMustBeUnique) {
constexpr int payload_type = 97;
RTPPayloadRegistry rtp_payload_registry;
bool ignored = false;
const SdpAudioFormat audio_format("name", 44000, 1);
EXPECT_EQ(0, rtp_payload_registry.RegisterReceivePayload(
payload_type, audio_format, &ignored));
EXPECT_EQ(0, rtp_payload_registry.RegisterReceivePayload(
payload_type - 1, audio_format, &ignored));
EXPECT_FALSE(rtp_payload_registry.PayloadTypeToPayload(payload_type))
<< "The first payload should be "
"deregistered because the only thing that differs is payload type.";
EXPECT_TRUE(rtp_payload_registry.PayloadTypeToPayload(payload_type - 1))
<< "The second payload should still be registered though.";
// Now ensure non-compatible codecs aren't removed. Make |audio_format_2|
// incompatible by changing the frequency.
const SdpAudioFormat audio_format_2("name", 44001, 1);
EXPECT_EQ(0, rtp_payload_registry.RegisterReceivePayload(
payload_type + 1, audio_format_2, &ignored));
EXPECT_TRUE(rtp_payload_registry.PayloadTypeToPayload(payload_type - 1))
<< "Not compatible; both payloads should be kept.";
EXPECT_TRUE(rtp_payload_registry.PayloadTypeToPayload(payload_type + 1))
<< "Not compatible; both payloads should be kept.";
}
class ParameterizedRtpPayloadRegistryTest
: public ::testing::TestWithParam<int> {};
TEST_P(ParameterizedRtpPayloadRegistryTest,
FailsToRegisterKnownPayloadsWeAreNotInterestedIn) {
RTPPayloadRegistry rtp_payload_registry;
bool ignored;
const int payload_type = GetParam();
const SdpAudioFormat audio_format("whatever", 1900, 1);
EXPECT_EQ(-1, rtp_payload_registry.RegisterReceivePayload(
payload_type, audio_format, &ignored));
}
INSTANTIATE_TEST_CASE_P(TestKnownBadPayloadTypes,
ParameterizedRtpPayloadRegistryTest,
testing::Values(64, 72, 73, 74, 75, 76, 77, 78, 79));
class RtpPayloadRegistryGenericTest : public ::testing::TestWithParam<int> {};
TEST_P(RtpPayloadRegistryGenericTest, RegisterGenericReceivePayloadType) {
RTPPayloadRegistry rtp_payload_registry;
bool ignored;
const int payload_type = GetParam();
const SdpAudioFormat audio_format("generic-codec", 1900, 1); // Dummy values.
EXPECT_EQ(0, rtp_payload_registry.RegisterReceivePayload(
payload_type, audio_format, &ignored));
}
INSTANTIATE_TEST_CASE_P(TestDynamicRange,
RtpPayloadRegistryGenericTest,
testing::Range(96, 127 + 1));
} // namespace webrtc

View File

@ -1,95 +0,0 @@
/*
* Copyright (c) 2012 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/rtp_receiver_audio.h"
#include <assert.h> // assert
#include <math.h> // pow()
#include <string.h> // memcpy()
#include "common_types.h" // NOLINT(build/include)
#include "rtc_base/logging.h"
#include "rtc_base/trace_event.h"
namespace webrtc {
RTPReceiverStrategy* RTPReceiverStrategy::CreateAudioStrategy(
RtpData* data_callback) {
return new RTPReceiverAudio(data_callback);
}
RTPReceiverAudio::RTPReceiverAudio(RtpData* data_callback)
: RTPReceiverStrategy(data_callback) {}
RTPReceiverAudio::~RTPReceiverAudio() = default;
// - Sample based or frame based codecs based on RFC 3551
// -
// - NOTE! There is one error in the RFC, stating G.722 uses 8 bits/samples.
// - The correct rate is 4 bits/sample.
// -
// - name of sampling default
// - encoding sample/frame bits/sample rate ms/frame ms/packet
// -
// - Sample based audio codecs
// - DVI4 sample 4 var. 20
// - G722 sample 4 16,000 20
// - G726-40 sample 5 8,000 20
// - G726-32 sample 4 8,000 20
// - G726-24 sample 3 8,000 20
// - G726-16 sample 2 8,000 20
// - L8 sample 8 var. 20
// - L16 sample 16 var. 20
// - PCMA sample 8 var. 20
// - PCMU sample 8 var. 20
// -
// - Frame based audio codecs
// - G723 frame N/A 8,000 30 30
// - G728 frame N/A 8,000 2.5 20
// - G729 frame N/A 8,000 10 20
// - G729D frame N/A 8,000 10 20
// - G729E frame N/A 8,000 10 20
// - GSM frame N/A 8,000 20 20
// - GSM-EFR frame N/A 8,000 20 20
// - LPC frame N/A 8,000 20 20
// - MPA frame N/A var. var.
// -
// - G7221 frame N/A
int32_t RTPReceiverAudio::ParseRtpPacket(WebRtcRTPHeader* rtp_header,
const PayloadUnion& specific_payload,
const uint8_t* payload,
size_t payload_length,
int64_t timestamp_ms) {
if (first_packet_received_()) {
RTC_LOG(LS_INFO) << "Received first audio RTP packet";
}
return ParseAudioCodecSpecific(rtp_header, payload, payload_length,
specific_payload.audio_payload());
}
// We are not allowed to have any critsects when calling data_callback.
int32_t RTPReceiverAudio::ParseAudioCodecSpecific(
WebRtcRTPHeader* rtp_header,
const uint8_t* payload_data,
size_t payload_length,
const AudioPayload& audio_specific) {
RTC_DCHECK_GE(payload_length, rtp_header->header.paddingLength);
const size_t payload_data_length =
payload_length - rtp_header->header.paddingLength;
if (payload_data_length == 0) {
rtp_header->frameType = kEmptyFrame;
return data_callback_->OnReceivedPayloadData(nullptr, 0, rtp_header);
}
return data_callback_->OnReceivedPayloadData(payload_data,
payload_data_length, rtp_header);
}
} // namespace webrtc

View File

@ -1,46 +0,0 @@
/*
* Copyright (c) 2012 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_RTP_RECEIVER_AUDIO_H_
#define MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_AUDIO_H_
#include <set>
#include "modules/rtp_rtcp/include/rtp_receiver.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/rtp_rtcp/source/rtp_receiver_strategy.h"
#include "modules/rtp_rtcp/source/rtp_utility.h"
#include "rtc_base/onetimeevent.h"
namespace webrtc {
// Handles audio RTP packets. This class is thread-safe.
class RTPReceiverAudio : public RTPReceiverStrategy {
public:
explicit RTPReceiverAudio(RtpData* data_callback);
~RTPReceiverAudio() override;
int32_t ParseRtpPacket(WebRtcRTPHeader* rtp_header,
const PayloadUnion& specific_payload,
const uint8_t* packet,
size_t payload_length,
int64_t timestamp_ms) override;
private:
int32_t ParseAudioCodecSpecific(WebRtcRTPHeader* rtp_header,
const uint8_t* payload_data,
size_t payload_length,
const AudioPayload& audio_specific);
ThreadUnsafeOneTimeEvent first_packet_received_;
};
} // namespace webrtc
#endif // MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_AUDIO_H_

View File

@ -1,246 +0,0 @@
/*
* Copyright (c) 2012 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/rtp_receiver_impl.h"
#include <assert.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <set>
#include <vector>
#include "common_types.h" // NOLINT(build/include)
#include "modules/audio_coding/codecs/audio_format_conversion.h"
#include "modules/include/module_common_types.h"
#include "modules/rtp_rtcp/include/rtp_payload_registry.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/rtp_rtcp/source/rtp_receiver_strategy.h"
#include "rtc_base/logging.h"
namespace webrtc {
namespace {
bool InOrderPacket(absl::optional<uint16_t> latest_sequence_number,
uint16_t current_sequence_number) {
if (!latest_sequence_number)
return true;
// We need to distinguish between a late or retransmitted packet,
// and a sequence number discontinuity.
if (IsNewerSequenceNumber(current_sequence_number, *latest_sequence_number)) {
return true;
} else {
// If we have a restart of the remote side this packet is still in order.
return !IsNewerSequenceNumber(
current_sequence_number,
*latest_sequence_number - kDefaultMaxReorderingThreshold);
}
}
} // namespace
using RtpUtility::Payload;
// Only return the sources in the last 10 seconds.
const int64_t kGetSourcesTimeoutMs = 10000;
RtpReceiver* RtpReceiver::CreateVideoReceiver(
Clock* clock,
RtpData* incoming_payload_callback,
RTPPayloadRegistry* rtp_payload_registry) {
RTC_DCHECK(incoming_payload_callback != nullptr);
return new RtpReceiverImpl(
clock, rtp_payload_registry,
RTPReceiverStrategy::CreateVideoStrategy(incoming_payload_callback));
}
RtpReceiver* RtpReceiver::CreateAudioReceiver(
Clock* clock,
RtpData* incoming_payload_callback,
RTPPayloadRegistry* rtp_payload_registry) {
RTC_DCHECK(incoming_payload_callback != nullptr);
return new RtpReceiverImpl(
clock, rtp_payload_registry,
RTPReceiverStrategy::CreateAudioStrategy(incoming_payload_callback));
}
int32_t RtpReceiver::RegisterReceivePayload(const CodecInst& audio_codec) {
return RegisterReceivePayload(audio_codec.pltype,
CodecInstToSdp(audio_codec));
}
RtpReceiverImpl::RtpReceiverImpl(Clock* clock,
RTPPayloadRegistry* rtp_payload_registry,
RTPReceiverStrategy* rtp_media_receiver)
: clock_(clock),
rtp_payload_registry_(rtp_payload_registry),
rtp_media_receiver_(rtp_media_receiver),
ssrc_(0),
last_received_timestamp_(0),
last_received_frame_time_ms_(-1) {}
RtpReceiverImpl::~RtpReceiverImpl() {}
int32_t RtpReceiverImpl::RegisterReceivePayload(
int payload_type,
const SdpAudioFormat& audio_format) {
rtc::CritScope lock(&critical_section_rtp_receiver_);
// TODO(phoglund): Try to streamline handling of the RED codec and some other
// cases which makes it necessary to keep track of whether we created a
// payload or not.
bool created_new_payload = false;
int32_t result = rtp_payload_registry_->RegisterReceivePayload(
payload_type, audio_format, &created_new_payload);
return result;
}
int32_t RtpReceiverImpl::RegisterReceivePayload(const VideoCodec& video_codec) {
rtc::CritScope lock(&critical_section_rtp_receiver_);
return rtp_payload_registry_->RegisterReceivePayload(video_codec);
}
int32_t RtpReceiverImpl::DeRegisterReceivePayload(const int8_t payload_type) {
rtc::CritScope lock(&critical_section_rtp_receiver_);
return rtp_payload_registry_->DeRegisterReceivePayload(payload_type);
}
uint32_t RtpReceiverImpl::SSRC() const {
rtc::CritScope lock(&critical_section_rtp_receiver_);
return ssrc_;
}
bool RtpReceiverImpl::IncomingRtpPacket(const RTPHeader& rtp_header,
const uint8_t* payload,
size_t payload_length,
PayloadUnion payload_specific) {
// Trigger our callbacks.
CheckSSRCChanged(rtp_header);
if (payload_length == 0) {
// OK, keep-alive packet.
return true;
}
int64_t now_ms = clock_->TimeInMilliseconds();
{
rtc::CritScope lock(&critical_section_rtp_receiver_);
csrcs_.Update(
now_ms, rtc::MakeArrayView(rtp_header.arrOfCSRCs, rtp_header.numCSRCs));
}
WebRtcRTPHeader webrtc_rtp_header{};
webrtc_rtp_header.header = rtp_header;
auto audio_level =
rtp_header.extension.hasAudioLevel
? absl::optional<uint8_t>(rtp_header.extension.audioLevel)
: absl::nullopt;
UpdateSources(audio_level);
int32_t ret_val = rtp_media_receiver_->ParseRtpPacket(
&webrtc_rtp_header, payload_specific, payload, payload_length, now_ms);
if (ret_val < 0) {
return false;
}
{
rtc::CritScope lock(&critical_section_rtp_receiver_);
// TODO(nisse): Do not rely on InOrderPacket for recovered packets, when
// packet is passed as RtpPacketReceived and that information is available.
// We should ideally never record timestamps for retransmitted or recovered
// packets.
if (InOrderPacket(last_received_sequence_number_,
rtp_header.sequenceNumber)) {
last_received_sequence_number_.emplace(rtp_header.sequenceNumber);
last_received_timestamp_ = rtp_header.timestamp;
last_received_frame_time_ms_ = clock_->TimeInMilliseconds();
}
}
return true;
}
std::vector<RtpSource> RtpReceiverImpl::GetSources() const {
rtc::CritScope lock(&critical_section_rtp_receiver_);
int64_t now_ms = clock_->TimeInMilliseconds();
RTC_DCHECK(std::is_sorted(ssrc_sources_.begin(), ssrc_sources_.end(),
[](const RtpSource& lhs, const RtpSource& rhs) {
return lhs.timestamp_ms() < rhs.timestamp_ms();
}));
std::vector<RtpSource> sources = csrcs_.GetSources(now_ms);
std::set<uint32_t> selected_ssrcs;
for (auto rit = ssrc_sources_.rbegin(); rit != ssrc_sources_.rend(); ++rit) {
if ((now_ms - rit->timestamp_ms()) > kGetSourcesTimeoutMs) {
break;
}
if (selected_ssrcs.insert(rit->source_id()).second) {
sources.push_back(*rit);
}
}
return sources;
}
bool RtpReceiverImpl::GetLatestTimestamps(uint32_t* timestamp,
int64_t* receive_time_ms) const {
rtc::CritScope lock(&critical_section_rtp_receiver_);
if (!last_received_sequence_number_)
return false;
*timestamp = last_received_timestamp_;
*receive_time_ms = last_received_frame_time_ms_;
return true;
}
// TODO(nisse): Delete.
// Implementation note: must not hold critsect when called.
void RtpReceiverImpl::CheckSSRCChanged(const RTPHeader& rtp_header) {
rtc::CritScope lock(&critical_section_rtp_receiver_);
ssrc_ = rtp_header.ssrc;
}
void RtpReceiverImpl::UpdateSources(
const absl::optional<uint8_t>& ssrc_audio_level) {
rtc::CritScope lock(&critical_section_rtp_receiver_);
int64_t now_ms = clock_->TimeInMilliseconds();
// If this is the first packet or the SSRC is changed, insert a new
// contributing source that uses the SSRC.
if (ssrc_sources_.empty() || ssrc_sources_.rbegin()->source_id() != ssrc_) {
ssrc_sources_.emplace_back(now_ms, ssrc_, RtpSourceType::SSRC);
} else {
ssrc_sources_.rbegin()->update_timestamp_ms(now_ms);
}
ssrc_sources_.back().set_audio_level(ssrc_audio_level);
RemoveOutdatedSources(now_ms);
}
void RtpReceiverImpl::RemoveOutdatedSources(int64_t now_ms) {
std::vector<RtpSource>::iterator vec_it;
for (vec_it = ssrc_sources_.begin(); vec_it != ssrc_sources_.end();
++vec_it) {
if ((now_ms - vec_it->timestamp_ms()) <= kGetSourcesTimeoutMs) {
break;
}
}
ssrc_sources_.erase(ssrc_sources_.begin(), vec_it);
}
} // namespace webrtc

View File

@ -1,86 +0,0 @@
/*
* Copyright (c) 2013 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_RTP_RECEIVER_IMPL_H_
#define MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_IMPL_H_
#include <memory>
#include <unordered_map>
#include <vector>
#include "absl/types/optional.h"
#include "modules/rtp_rtcp/include/rtp_receiver.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/rtp_rtcp/source/contributing_sources.h"
#include "modules/rtp_rtcp/source/rtp_receiver_strategy.h"
#include "rtc_base/criticalsection.h"
namespace webrtc {
class RtpReceiverImpl : public RtpReceiver {
public:
// Callbacks passed in here may not be NULL (use Null Object callbacks if you
// want callbacks to do nothing). This class takes ownership of the media
// receiver but nothing else.
RtpReceiverImpl(Clock* clock,
RTPPayloadRegistry* rtp_payload_registry,
RTPReceiverStrategy* rtp_media_receiver);
~RtpReceiverImpl() override;
int32_t RegisterReceivePayload(int payload_type,
const SdpAudioFormat& audio_format) override;
int32_t RegisterReceivePayload(const VideoCodec& video_codec) override;
int32_t DeRegisterReceivePayload(const int8_t payload_type) override;
bool IncomingRtpPacket(const RTPHeader& rtp_header,
const uint8_t* payload,
size_t payload_length,
PayloadUnion payload_specific) override;
bool GetLatestTimestamps(uint32_t* timestamp,
int64_t* receive_time_ms) const override;
uint32_t SSRC() const override;
std::vector<RtpSource> GetSources() const override;
private:
void CheckSSRCChanged(const RTPHeader& rtp_header);
void UpdateSources(const absl::optional<uint8_t>& ssrc_audio_level);
void RemoveOutdatedSources(int64_t now_ms);
Clock* clock_;
rtc::CriticalSection critical_section_rtp_receiver_;
RTPPayloadRegistry* const rtp_payload_registry_
RTC_PT_GUARDED_BY(critical_section_rtp_receiver_);
const std::unique_ptr<RTPReceiverStrategy> rtp_media_receiver_;
// SSRCs.
uint32_t ssrc_ RTC_GUARDED_BY(critical_section_rtp_receiver_);
ContributingSources csrcs_ RTC_GUARDED_BY(critical_section_rtp_receiver_);
// Sequence number and timestamps for the latest in-order packet.
absl::optional<uint16_t> last_received_sequence_number_
RTC_GUARDED_BY(critical_section_rtp_receiver_);
uint32_t last_received_timestamp_
RTC_GUARDED_BY(critical_section_rtp_receiver_);
int64_t last_received_frame_time_ms_
RTC_GUARDED_BY(critical_section_rtp_receiver_);
// The RtpSource objects are sorted chronologically.
std::vector<RtpSource> ssrc_sources_;
};
} // namespace webrtc
#endif // MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_IMPL_H_

View File

@ -1,22 +0,0 @@
/*
* Copyright (c) 2012 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/rtp_receiver_strategy.h"
#include <stdlib.h>
namespace webrtc {
RTPReceiverStrategy::RTPReceiverStrategy(RtpData* data_callback)
: data_callback_(data_callback) {}
RTPReceiverStrategy::~RTPReceiverStrategy() = default;
} // namespace webrtc

View File

@ -1,59 +0,0 @@
/*
* Copyright (c) 2012 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_RTP_RECEIVER_STRATEGY_H_
#define MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_STRATEGY_H_
#include "modules/rtp_rtcp/include/rtp_rtcp.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/rtp_rtcp/source/rtp_utility.h"
#include "rtc_base/criticalsection.h"
namespace webrtc {
struct CodecInst;
// This strategy deals with media-specific RTP packet processing.
// This class is not thread-safe and must be protected by its caller.
class RTPReceiverStrategy {
public:
static RTPReceiverStrategy* CreateVideoStrategy(RtpData* data_callback);
static RTPReceiverStrategy* CreateAudioStrategy(RtpData* data_callback);
virtual ~RTPReceiverStrategy();
// Parses the RTP packet and calls the data callback with the payload data.
// Implementations are encouraged to use the provided packet buffer and RTP
// header as arguments to the callback; implementations are also allowed to
// make changes in the data as necessary. The specific_payload argument
// provides audio or video-specific data.
virtual int32_t ParseRtpPacket(WebRtcRTPHeader* rtp_header,
const PayloadUnion& specific_payload,
const uint8_t* payload,
size_t payload_length,
int64_t timestamp_ms) = 0;
protected:
// The data callback is where we should send received payload data.
// See ParseRtpPacket. This class does not claim ownership of the callback.
// Implementations must NOT hold any critical sections while calling the
// callback.
//
// Note: Implementations may call the callback for other reasons than calls
// to ParseRtpPacket, for instance if the implementation somehow recovers a
// packet.
explicit RTPReceiverStrategy(RtpData* data_callback);
rtc::CriticalSection crit_sect_;
RtpData* data_callback_;
};
} // namespace webrtc
#endif // MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_STRATEGY_H_

View File

@ -1,461 +0,0 @@
/*
* Copyright (c) 2017 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 <memory>
#include "common_types.h" // NOLINT(build/include)
#include "modules/rtp_rtcp/include/rtp_header_parser.h"
#include "modules/rtp_rtcp/include/rtp_payload_registry.h"
#include "modules/rtp_rtcp/include/rtp_receiver.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/rtp_rtcp/mocks/mock_rtp_rtcp.h"
#include "test/gmock.h"
#include "test/gtest.h"
namespace webrtc {
namespace {
using ::testing::NiceMock;
using ::testing::UnorderedElementsAre;
const uint32_t kTestRate = 64000u;
const uint8_t kTestPayload[] = {'t', 'e', 's', 't'};
const uint8_t kPcmuPayloadType = 96;
const int64_t kGetSourcesTimeoutMs = 10000;
const uint32_t kSsrc1 = 123;
const uint32_t kSsrc2 = 124;
const uint32_t kCsrc1 = 111;
const uint32_t kCsrc2 = 222;
static uint32_t rtp_timestamp(int64_t time_ms) {
return static_cast<uint32_t>(time_ms * kTestRate / 1000);
}
} // namespace
class RtpReceiverTest : public ::testing::Test {
protected:
RtpReceiverTest()
: fake_clock_(123456),
rtp_receiver_(
RtpReceiver::CreateAudioReceiver(&fake_clock_,
&mock_rtp_data_,
&rtp_payload_registry_)) {
rtp_receiver_->RegisterReceivePayload(kPcmuPayloadType,
SdpAudioFormat("PCMU", 8000, 1));
}
~RtpReceiverTest() {}
bool FindSourceByIdAndType(const std::vector<RtpSource>& sources,
uint32_t source_id,
RtpSourceType type,
RtpSource* source) {
for (size_t i = 0; i < sources.size(); ++i) {
if (sources[i].source_id() == source_id &&
sources[i].source_type() == type) {
(*source) = sources[i];
return true;
}
}
return false;
}
SimulatedClock fake_clock_;
NiceMock<MockRtpData> mock_rtp_data_;
RTPPayloadRegistry rtp_payload_registry_;
std::unique_ptr<RtpReceiver> rtp_receiver_;
};
TEST_F(RtpReceiverTest, GetSources) {
int64_t now_ms = fake_clock_.TimeInMilliseconds();
RTPHeader header;
header.payloadType = kPcmuPayloadType;
header.ssrc = kSsrc1;
header.timestamp = rtp_timestamp(now_ms);
header.numCSRCs = 2;
header.arrOfCSRCs[0] = kCsrc1;
header.arrOfCSRCs[1] = kCsrc2;
const PayloadUnion payload_specific{
AudioPayload{SdpAudioFormat("foo", 8000, 1), 0}};
EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
header, kTestPayload, sizeof(kTestPayload), payload_specific));
auto sources = rtp_receiver_->GetSources();
// One SSRC source and two CSRC sources.
EXPECT_THAT(sources, UnorderedElementsAre(
RtpSource(now_ms, kSsrc1, RtpSourceType::SSRC),
RtpSource(now_ms, kCsrc1, RtpSourceType::CSRC),
RtpSource(now_ms, kCsrc2, RtpSourceType::CSRC)));
// Advance the fake clock and the method is expected to return the
// contributing source object with same source id and updated timestamp.
fake_clock_.AdvanceTimeMilliseconds(1);
EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
header, kTestPayload, sizeof(kTestPayload), payload_specific));
sources = rtp_receiver_->GetSources();
now_ms = fake_clock_.TimeInMilliseconds();
EXPECT_THAT(sources, UnorderedElementsAre(
RtpSource(now_ms, kSsrc1, RtpSourceType::SSRC),
RtpSource(now_ms, kCsrc1, RtpSourceType::CSRC),
RtpSource(now_ms, kCsrc2, RtpSourceType::CSRC)));
// Test the edge case that the sources are still there just before the
// timeout.
int64_t prev_time_ms = fake_clock_.TimeInMilliseconds();
fake_clock_.AdvanceTimeMilliseconds(kGetSourcesTimeoutMs);
sources = rtp_receiver_->GetSources();
EXPECT_THAT(sources,
UnorderedElementsAre(
RtpSource(prev_time_ms, kSsrc1, RtpSourceType::SSRC),
RtpSource(prev_time_ms, kCsrc1, RtpSourceType::CSRC),
RtpSource(prev_time_ms, kCsrc2, RtpSourceType::CSRC)));
// Time out.
fake_clock_.AdvanceTimeMilliseconds(1);
sources = rtp_receiver_->GetSources();
// All the sources should be out of date.
ASSERT_EQ(0u, sources.size());
}
// Test the case that the SSRC is changed.
TEST_F(RtpReceiverTest, GetSourcesChangeSSRC) {
int64_t prev_time_ms = -1;
int64_t now_ms = fake_clock_.TimeInMilliseconds();
RTPHeader header;
header.payloadType = kPcmuPayloadType;
header.ssrc = kSsrc1;
header.timestamp = rtp_timestamp(now_ms);
const PayloadUnion payload_specific{
AudioPayload{SdpAudioFormat("foo", 8000, 1), 0}};
EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
header, kTestPayload, sizeof(kTestPayload), payload_specific));
auto sources = rtp_receiver_->GetSources();
EXPECT_THAT(sources, UnorderedElementsAre(
RtpSource(now_ms, kSsrc1, RtpSourceType::SSRC)));
// The SSRC is changed and the old SSRC is expected to be returned.
fake_clock_.AdvanceTimeMilliseconds(100);
prev_time_ms = now_ms;
now_ms = fake_clock_.TimeInMilliseconds();
header.ssrc = kSsrc2;
header.timestamp = rtp_timestamp(now_ms);
EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
header, kTestPayload, sizeof(kTestPayload), payload_specific));
sources = rtp_receiver_->GetSources();
EXPECT_THAT(sources, UnorderedElementsAre(
RtpSource(prev_time_ms, kSsrc1, RtpSourceType::SSRC),
RtpSource(now_ms, kSsrc2, RtpSourceType::SSRC)));
// The SSRC is changed again and happen to be changed back to 1. No
// duplication is expected.
fake_clock_.AdvanceTimeMilliseconds(100);
header.ssrc = kSsrc1;
header.timestamp = rtp_timestamp(now_ms);
prev_time_ms = now_ms;
now_ms = fake_clock_.TimeInMilliseconds();
EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
header, kTestPayload, sizeof(kTestPayload), payload_specific));
sources = rtp_receiver_->GetSources();
EXPECT_THAT(sources, UnorderedElementsAre(
RtpSource(prev_time_ms, kSsrc2, RtpSourceType::SSRC),
RtpSource(now_ms, kSsrc1, RtpSourceType::SSRC)));
// Old SSRC source timeout.
fake_clock_.AdvanceTimeMilliseconds(kGetSourcesTimeoutMs);
now_ms = fake_clock_.TimeInMilliseconds();
EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
header, kTestPayload, sizeof(kTestPayload), payload_specific));
sources = rtp_receiver_->GetSources();
EXPECT_THAT(sources, UnorderedElementsAre(
RtpSource(now_ms, kSsrc1, RtpSourceType::SSRC)));
}
TEST_F(RtpReceiverTest, GetSourcesRemoveOutdatedSource) {
int64_t now_ms = fake_clock_.TimeInMilliseconds();
RTPHeader header;
header.payloadType = kPcmuPayloadType;
header.timestamp = rtp_timestamp(now_ms);
const PayloadUnion payload_specific{
AudioPayload{SdpAudioFormat("foo", 8000, 1), 0}};
header.numCSRCs = 1;
size_t kSourceListSize = 20;
for (size_t i = 0; i < kSourceListSize; ++i) {
header.ssrc = i;
header.arrOfCSRCs[0] = (i + 1);
EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
header, kTestPayload, sizeof(kTestPayload), payload_specific));
}
RtpSource source(0, 0, RtpSourceType::SSRC);
auto sources = rtp_receiver_->GetSources();
// Expect |kSourceListSize| SSRC sources and |kSourceListSize| CSRC sources.
ASSERT_EQ(2 * kSourceListSize, sources.size());
for (size_t i = 0; i < kSourceListSize; ++i) {
// The SSRC source IDs are expected to be 19, 18, 17 ... 0
ASSERT_TRUE(
FindSourceByIdAndType(sources, i, RtpSourceType::SSRC, &source));
EXPECT_EQ(now_ms, source.timestamp_ms());
// The CSRC source IDs are expected to be 20, 19, 18 ... 1
ASSERT_TRUE(
FindSourceByIdAndType(sources, (i + 1), RtpSourceType::CSRC, &source));
EXPECT_EQ(now_ms, source.timestamp_ms());
}
fake_clock_.AdvanceTimeMilliseconds(kGetSourcesTimeoutMs);
for (size_t i = 0; i < kSourceListSize; ++i) {
// The SSRC source IDs are expected to be 19, 18, 17 ... 0
ASSERT_TRUE(
FindSourceByIdAndType(sources, i, RtpSourceType::SSRC, &source));
EXPECT_EQ(now_ms, source.timestamp_ms());
// The CSRC source IDs are expected to be 20, 19, 18 ... 1
ASSERT_TRUE(
FindSourceByIdAndType(sources, (i + 1), RtpSourceType::CSRC, &source));
EXPECT_EQ(now_ms, source.timestamp_ms());
}
// Timeout. All the existing objects are out of date and are expected to be
// removed.
fake_clock_.AdvanceTimeMilliseconds(1);
header.ssrc = kSsrc1;
header.arrOfCSRCs[0] = kCsrc1;
EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
header, kTestPayload, sizeof(kTestPayload), payload_specific));
now_ms = fake_clock_.TimeInMilliseconds();
sources = rtp_receiver_->GetSources();
EXPECT_THAT(sources, UnorderedElementsAre(
RtpSource(now_ms, kSsrc1, RtpSourceType::SSRC),
RtpSource(now_ms, kCsrc1, RtpSourceType::CSRC)));
}
// The audio level from the RTPHeader extension should be stored in the
// RtpSource with the matching SSRC.
TEST_F(RtpReceiverTest, GetSourcesContainsAudioLevelExtension) {
RTPHeader header;
int64_t time1_ms = fake_clock_.TimeInMilliseconds();
header.payloadType = kPcmuPayloadType;
header.ssrc = kSsrc1;
header.timestamp = rtp_timestamp(time1_ms);
header.extension.hasAudioLevel = true;
header.extension.audioLevel = 10;
const PayloadUnion payload_specific{
AudioPayload{SdpAudioFormat("foo", 8000, 1), 0}};
EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
header, kTestPayload, sizeof(kTestPayload), payload_specific));
auto sources = rtp_receiver_->GetSources();
EXPECT_THAT(sources, UnorderedElementsAre(RtpSource(
time1_ms, kSsrc1, RtpSourceType::SSRC, 10)));
// Receive a packet from a different SSRC with a different level and check
// that they are both remembered.
fake_clock_.AdvanceTimeMilliseconds(1);
int64_t time2_ms = fake_clock_.TimeInMilliseconds();
header.ssrc = kSsrc2;
header.timestamp = rtp_timestamp(time2_ms);
header.extension.hasAudioLevel = true;
header.extension.audioLevel = 20;
EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
header, kTestPayload, sizeof(kTestPayload), payload_specific));
sources = rtp_receiver_->GetSources();
EXPECT_THAT(sources,
UnorderedElementsAre(
RtpSource(time1_ms, kSsrc1, RtpSourceType::SSRC, 10),
RtpSource(time2_ms, kSsrc2, RtpSourceType::SSRC, 20)));
// Receive a packet from the first SSRC again and check that the level is
// updated.
fake_clock_.AdvanceTimeMilliseconds(1);
int64_t time3_ms = fake_clock_.TimeInMilliseconds();
header.ssrc = kSsrc1;
header.timestamp = rtp_timestamp(time3_ms);
header.extension.hasAudioLevel = true;
header.extension.audioLevel = 30;
EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
header, kTestPayload, sizeof(kTestPayload), payload_specific));
sources = rtp_receiver_->GetSources();
EXPECT_THAT(sources,
UnorderedElementsAre(
RtpSource(time3_ms, kSsrc1, RtpSourceType::SSRC, 30),
RtpSource(time2_ms, kSsrc2, RtpSourceType::SSRC, 20)));
}
TEST_F(RtpReceiverTest,
MissingAudioLevelHeaderExtensionClearsRtpSourceAudioLevel) {
RTPHeader header;
int64_t time1_ms = fake_clock_.TimeInMilliseconds();
header.payloadType = kPcmuPayloadType;
header.ssrc = kSsrc1;
header.timestamp = rtp_timestamp(time1_ms);
header.extension.hasAudioLevel = true;
header.extension.audioLevel = 10;
const PayloadUnion payload_specific{
AudioPayload{SdpAudioFormat("foo", 8000, 1), 0}};
EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
header, kTestPayload, sizeof(kTestPayload), payload_specific));
auto sources = rtp_receiver_->GetSources();
EXPECT_THAT(sources, UnorderedElementsAre(RtpSource(
time1_ms, kSsrc1, RtpSourceType::SSRC, 10)));
// Receive a second packet without the audio level header extension and check
// that the audio level is cleared.
fake_clock_.AdvanceTimeMilliseconds(1);
int64_t time2_ms = fake_clock_.TimeInMilliseconds();
header.timestamp = rtp_timestamp(time2_ms);
header.extension.hasAudioLevel = false;
EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
header, kTestPayload, sizeof(kTestPayload), payload_specific));
sources = rtp_receiver_->GetSources();
EXPECT_THAT(sources, UnorderedElementsAre(
RtpSource(time2_ms, kSsrc1, RtpSourceType::SSRC)));
}
TEST_F(RtpReceiverTest, UpdatesTimestampsIfAndOnlyIfPacketArrivesInOrder) {
RTPHeader header;
int64_t time1_ms = fake_clock_.TimeInMilliseconds();
header.payloadType = kPcmuPayloadType;
header.ssrc = kSsrc1;
header.timestamp = rtp_timestamp(time1_ms);
header.extension.hasAudioLevel = true;
header.extension.audioLevel = 10;
header.sequenceNumber = 0xfff0;
const PayloadUnion payload_specific{
AudioPayload{SdpAudioFormat("foo", 8000, 1), 0}};
uint32_t latest_timestamp;
int64_t latest_receive_time_ms;
// No packet received yet.
EXPECT_FALSE(rtp_receiver_->GetLatestTimestamps(&latest_timestamp,
&latest_receive_time_ms));
// Initial packet
const uint32_t timestamp_1 = header.timestamp;
const int64_t receive_time_1 = fake_clock_.TimeInMilliseconds();
EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
header, kTestPayload, sizeof(kTestPayload), payload_specific));
EXPECT_TRUE(rtp_receiver_->GetLatestTimestamps(&latest_timestamp,
&latest_receive_time_ms));
EXPECT_EQ(latest_timestamp, timestamp_1);
EXPECT_EQ(latest_receive_time_ms, receive_time_1);
// Late packet, timestamp not recorded.
fake_clock_.AdvanceTimeMilliseconds(10);
header.timestamp -= 900;
header.sequenceNumber -= 2;
EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
header, kTestPayload, sizeof(kTestPayload), payload_specific));
EXPECT_TRUE(rtp_receiver_->GetLatestTimestamps(&latest_timestamp,
&latest_receive_time_ms));
EXPECT_EQ(latest_timestamp, timestamp_1);
EXPECT_EQ(latest_receive_time_ms, receive_time_1);
// New packet, still late, no wraparound.
fake_clock_.AdvanceTimeMilliseconds(10);
header.timestamp += 1800;
header.sequenceNumber += 1;
EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
header, kTestPayload, sizeof(kTestPayload), payload_specific));
EXPECT_TRUE(rtp_receiver_->GetLatestTimestamps(&latest_timestamp,
&latest_receive_time_ms));
EXPECT_EQ(latest_timestamp, timestamp_1);
EXPECT_EQ(latest_receive_time_ms, receive_time_1);
// New packet, new timestamp recorded
fake_clock_.AdvanceTimeMilliseconds(10);
header.timestamp += 900;
header.sequenceNumber += 2;
const uint32_t timestamp_2 = header.timestamp;
const int64_t receive_time_2 = fake_clock_.TimeInMilliseconds();
const uint16_t seqno_2 = header.sequenceNumber;
EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
header, kTestPayload, sizeof(kTestPayload), payload_specific));
EXPECT_TRUE(rtp_receiver_->GetLatestTimestamps(&latest_timestamp,
&latest_receive_time_ms));
EXPECT_EQ(latest_timestamp, timestamp_2);
EXPECT_EQ(latest_receive_time_ms, receive_time_2);
// New packet, timestamp wraps around
fake_clock_.AdvanceTimeMilliseconds(10);
header.timestamp += 900;
header.sequenceNumber += 20;
const uint32_t timestamp_3 = header.timestamp;
const int64_t receive_time_3 = fake_clock_.TimeInMilliseconds();
EXPECT_LT(header.sequenceNumber, seqno_2); // Wrap-around
EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
header, kTestPayload, sizeof(kTestPayload), payload_specific));
EXPECT_TRUE(rtp_receiver_->GetLatestTimestamps(&latest_timestamp,
&latest_receive_time_ms));
EXPECT_EQ(latest_timestamp, timestamp_3);
EXPECT_EQ(latest_receive_time_ms, receive_time_3);
}
TEST_F(RtpReceiverTest, UpdatesTimestampsWhenStreamResets) {
RTPHeader header;
int64_t time1_ms = fake_clock_.TimeInMilliseconds();
header.payloadType = kPcmuPayloadType;
header.ssrc = kSsrc1;
header.timestamp = rtp_timestamp(time1_ms);
header.extension.hasAudioLevel = true;
header.extension.audioLevel = 10;
header.sequenceNumber = 0xfff0;
const PayloadUnion payload_specific{
AudioPayload{SdpAudioFormat("foo", 8000, 1), 0}};
uint32_t latest_timestamp;
int64_t latest_receive_time_ms;
// No packet received yet.
EXPECT_FALSE(rtp_receiver_->GetLatestTimestamps(&latest_timestamp,
&latest_receive_time_ms));
// Initial packet
const uint32_t timestamp_1 = header.timestamp;
const int64_t receive_time_1 = fake_clock_.TimeInMilliseconds();
const uint16_t seqno_1 = header.sequenceNumber;
EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
header, kTestPayload, sizeof(kTestPayload), payload_specific));
EXPECT_TRUE(rtp_receiver_->GetLatestTimestamps(&latest_timestamp,
&latest_receive_time_ms));
EXPECT_EQ(latest_timestamp, timestamp_1);
EXPECT_EQ(latest_receive_time_ms, receive_time_1);
// Packet with far in the past seqno, but unlikely to be a wrap-around.
// Treated as a seqno discontinuity, and timestamp is recorded.
fake_clock_.AdvanceTimeMilliseconds(10);
header.timestamp += 900;
header.sequenceNumber = 0x9000;
const uint32_t timestamp_2 = header.timestamp;
const int64_t receive_time_2 = fake_clock_.TimeInMilliseconds();
const uint16_t seqno_2 = header.sequenceNumber;
EXPECT_LT(seqno_1 - seqno_2, 0x8000); // In the past.
EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
header, kTestPayload, sizeof(kTestPayload), payload_specific));
EXPECT_TRUE(rtp_receiver_->GetLatestTimestamps(&latest_timestamp,
&latest_receive_time_ms));
EXPECT_EQ(latest_timestamp, timestamp_2);
EXPECT_EQ(latest_receive_time_ms, receive_time_2);
}
} // namespace webrtc

View File

@ -1,110 +0,0 @@
/*
* Copyright (c) 2012 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/rtp_receiver_video.h"
#include <assert.h>
#include <string.h>
#include <memory>
#include "modules/rtp_rtcp/include/rtp_cvo.h"
#include "modules/rtp_rtcp/include/rtp_payload_registry.h"
#include "modules/rtp_rtcp/source/rtp_format.h"
#include "modules/rtp_rtcp/source/rtp_format_video_generic.h"
#include "modules/rtp_rtcp/source/rtp_utility.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
#include "rtc_base/trace_event.h"
namespace webrtc {
RTPReceiverStrategy* RTPReceiverStrategy::CreateVideoStrategy(
RtpData* data_callback) {
return new RTPReceiverVideo(data_callback);
}
RTPReceiverVideo::RTPReceiverVideo(RtpData* data_callback)
: RTPReceiverStrategy(data_callback) {}
RTPReceiverVideo::~RTPReceiverVideo() {}
int32_t RTPReceiverVideo::ParseRtpPacket(WebRtcRTPHeader* rtp_header,
const PayloadUnion& specific_payload,
const uint8_t* payload,
size_t payload_length,
int64_t timestamp_ms) {
rtp_header->video_header().codec =
specific_payload.video_payload().videoCodecType;
RTC_DCHECK_GE(payload_length, rtp_header->header.paddingLength);
const size_t payload_data_length =
payload_length - rtp_header->header.paddingLength;
if (payload == NULL || payload_data_length == 0) {
return data_callback_->OnReceivedPayloadData(NULL, 0, rtp_header) == 0 ? 0
: -1;
}
if (first_packet_received_()) {
RTC_LOG(LS_INFO) << "Received first video RTP packet";
}
// We are not allowed to hold a critical section when calling below functions.
std::unique_ptr<RtpDepacketizer> depacketizer(
RtpDepacketizer::Create(rtp_header->video_header().codec));
if (depacketizer.get() == NULL) {
RTC_LOG(LS_ERROR) << "Failed to create depacketizer.";
return -1;
}
RtpDepacketizer::ParsedPayload parsed_payload;
if (!depacketizer->Parse(&parsed_payload, payload, payload_data_length))
return -1;
rtp_header->frameType = parsed_payload.frame_type;
rtp_header->video_header() = parsed_payload.video_header();
rtp_header->video_header().rotation = kVideoRotation_0;
rtp_header->video_header().content_type = VideoContentType::UNSPECIFIED;
rtp_header->video_header().video_timing.flags = VideoSendTiming::kInvalid;
rtp_header->video_header().frame_marking.temporal_id = kNoTemporalIdx;
// Retrieve the video rotation information.
if (rtp_header->header.extension.hasVideoRotation) {
rtp_header->video_header().rotation =
rtp_header->header.extension.videoRotation;
}
if (rtp_header->header.extension.hasVideoContentType) {
rtp_header->video_header().content_type =
rtp_header->header.extension.videoContentType;
}
if (rtp_header->header.extension.has_video_timing) {
rtp_header->video_header().video_timing =
rtp_header->header.extension.video_timing;
}
rtp_header->video_header().playout_delay =
rtp_header->header.extension.playout_delay;
if (rtp_header->header.extension.has_frame_marking) {
rtp_header->video_header().frame_marking =
rtp_header->header.extension.frame_marking;
}
return data_callback_->OnReceivedPayloadData(parsed_payload.payload,
parsed_payload.payload_length,
rtp_header) == 0
? 0
: -1;
}
} // namespace webrtc

View File

@ -1,40 +0,0 @@
/*
* Copyright (c) 2012 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_RTP_RECEIVER_VIDEO_H_
#define MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_VIDEO_H_
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/rtp_rtcp/source/rtp_receiver_strategy.h"
#include "modules/rtp_rtcp/source/rtp_utility.h"
#include "rtc_base/onetimeevent.h"
namespace webrtc {
class RTPReceiverVideo : public RTPReceiverStrategy {
public:
explicit RTPReceiverVideo(RtpData* data_callback);
~RTPReceiverVideo() override;
int32_t ParseRtpPacket(WebRtcRTPHeader* rtp_header,
const PayloadUnion& specific_payload,
const uint8_t* packet,
size_t packet_length,
int64_t timestamp) override;
void SetPacketOverHead(uint16_t packet_over_head);
private:
OneTimeEvent first_packet_received_;
};
} // namespace webrtc
#endif // MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_VIDEO_H_

View File

@ -14,7 +14,6 @@
#include <utility>
#include "modules/rtp_rtcp/source/byte_io.h"
#include "modules/rtp_rtcp/source/rtp_receiver_video.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
#include "system_wrappers/include/clock.h"

View File

@ -1,206 +0,0 @@
/*
* Copyright (c) 2012 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/test/testAPI/test_api.h"
#include <algorithm>
#include <memory>
#include <string>
#include "modules/rtp_rtcp/source/rtp_packet_received.h"
#include "rtc_base/checks.h"
#include "rtc_base/rate_limiter.h"
#include "test/null_transport.h"
namespace webrtc {
void LoopBackTransport::SetSendModule(RtpRtcp* rtp_rtcp_module,
RTPPayloadRegistry* payload_registry,
RtpReceiver* receiver,
ReceiveStatistics* receive_statistics) {
rtp_rtcp_module_ = rtp_rtcp_module;
rtp_payload_registry_ = payload_registry;
rtp_receiver_ = receiver;
receive_statistics_ = receive_statistics;
}
void LoopBackTransport::DropEveryNthPacket(int n) {
packet_loss_ = n;
}
bool LoopBackTransport::SendRtp(const uint8_t* data,
size_t len,
const PacketOptions& options) {
count_++;
if (packet_loss_ > 0) {
if ((count_ % packet_loss_) == 0) {
return true;
}
}
RtpPacketReceived parsed_packet;
if (!parsed_packet.Parse(data, len)) {
return false;
}
const auto pl =
rtp_payload_registry_->PayloadTypeToPayload(parsed_packet.PayloadType());
if (!pl) {
return false;
}
receive_statistics_->OnRtpPacket(parsed_packet);
RTPHeader header;
parsed_packet.GetHeader(&header);
return rtp_receiver_->IncomingRtpPacket(
header, parsed_packet.payload().data(),
// RtpReceiver expects length including padding.
parsed_packet.payload_size() + parsed_packet.padding_size(),
pl->typeSpecific);
}
bool LoopBackTransport::SendRtcp(const uint8_t* data, size_t len) {
rtp_rtcp_module_->IncomingRtcpPacket((const uint8_t*)data, len);
return true;
}
int32_t TestRtpReceiver::OnReceivedPayloadData(
const uint8_t* payload_data,
size_t payload_size,
const webrtc::WebRtcRTPHeader* rtp_header) {
EXPECT_LE(payload_size, sizeof(payload_data_));
memcpy(payload_data_, payload_data, payload_size);
memcpy(&rtp_header_, rtp_header, sizeof(rtp_header_));
payload_size_ = payload_size;
return 0;
}
class RtpRtcpAPITest : public ::testing::Test {
protected:
RtpRtcpAPITest()
: fake_clock_(123456), retransmission_rate_limiter_(&fake_clock_, 1000) {
}
~RtpRtcpAPITest() override = default;
void SetUp() override {
const uint32_t kInitialSsrc = 8888;
RtpRtcp::Configuration configuration;
configuration.audio = true;
configuration.clock = &fake_clock_;
configuration.outgoing_transport = &null_transport_;
configuration.retransmission_rate_limiter = &retransmission_rate_limiter_;
module_.reset(RtpRtcp::CreateRtpRtcp(configuration));
module_->SetSSRC(kInitialSsrc);
}
SimulatedClock fake_clock_;
test::NullTransport null_transport_;
RateLimiter retransmission_rate_limiter_;
std::unique_ptr<RtpRtcp> module_;
};
TEST_F(RtpRtcpAPITest, Basic) {
const uint16_t kSequenceNumber = 2345;
module_->SetSequenceNumber(kSequenceNumber);
EXPECT_EQ(kSequenceNumber, module_->SequenceNumber());
const uint32_t kTimestamp = 4567;
module_->SetStartTimestamp(kTimestamp);
EXPECT_EQ(kTimestamp, module_->StartTimestamp());
EXPECT_FALSE(module_->Sending());
EXPECT_EQ(0, module_->SetSendingStatus(true));
EXPECT_TRUE(module_->Sending());
}
TEST_F(RtpRtcpAPITest, PacketSize) {
module_->SetMaxRtpPacketSize(1234);
EXPECT_EQ(1234u, module_->MaxRtpPacketSize());
}
TEST_F(RtpRtcpAPITest, SSRC) {
const uint32_t kSsrc = 3456;
module_->SetSSRC(kSsrc);
EXPECT_EQ(kSsrc, module_->SSRC());
}
TEST_F(RtpRtcpAPITest, RTCP) {
EXPECT_EQ(RtcpMode::kOff, module_->RTCP());
module_->SetRTCPStatus(RtcpMode::kCompound);
EXPECT_EQ(RtcpMode::kCompound, module_->RTCP());
EXPECT_EQ(0, module_->SetCNAME("john.doe@test.test"));
EXPECT_FALSE(module_->TMMBR());
module_->SetTMMBRStatus(true);
EXPECT_TRUE(module_->TMMBR());
module_->SetTMMBRStatus(false);
EXPECT_FALSE(module_->TMMBR());
}
TEST_F(RtpRtcpAPITest, RtxSender) {
module_->SetRtxSendStatus(kRtxRetransmitted);
EXPECT_EQ(kRtxRetransmitted, module_->RtxSendStatus());
module_->SetRtxSendStatus(kRtxOff);
EXPECT_EQ(kRtxOff, module_->RtxSendStatus());
module_->SetRtxSendStatus(kRtxRetransmitted);
EXPECT_EQ(kRtxRetransmitted, module_->RtxSendStatus());
}
TEST_F(RtpRtcpAPITest, LegalMidName) {
static const std::string kLegalMidNames[] = {
// clang-format off
"audio",
"audio0",
"audio_0",
// clang-format on
};
for (const auto& name : kLegalMidNames) {
EXPECT_TRUE(StreamId::IsLegalMidName(name))
<< "Mid should be legal: " << name;
}
static const std::string kNonLegalMidNames[] = {
// clang-format off
"",
"(audio0)",
// clang-format on
};
for (const auto& name : kNonLegalMidNames) {
EXPECT_FALSE(StreamId::IsLegalMidName(name))
<< "Mid should not be legal: " << name;
}
}
TEST_F(RtpRtcpAPITest, LegalRsidName) {
static const std::string kLegalRsidNames[] = {
// clang-format off
"audio",
"audio0",
// clang-format on
};
for (const auto& name : kLegalRsidNames) {
EXPECT_TRUE(StreamId::IsLegalRsidName(name))
<< "Rsid should be legal: " << name;
}
static const std::string kNonLegalRsidNames[] = {
// clang-format off
"",
"audio_0",
"(audio0)",
// clang-format on
};
for (const auto& name : kNonLegalRsidNames) {
EXPECT_FALSE(StreamId::IsLegalRsidName(name))
<< "Rsid should not be legal: " << name;
}
}
} // namespace webrtc

View File

@ -1,72 +0,0 @@
/*
* Copyright (c) 2012 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_TEST_TESTAPI_TEST_API_H_
#define MODULES_RTP_RTCP_TEST_TESTAPI_TEST_API_H_
#include "api/call/transport.h"
#include "common_types.h" // NOLINT(build/include)
#include "modules/rtp_rtcp/include/receive_statistics.h"
#include "modules/rtp_rtcp/include/rtp_header_parser.h"
#include "modules/rtp_rtcp/include/rtp_payload_registry.h"
#include "modules/rtp_rtcp/include/rtp_receiver.h"
#include "modules/rtp_rtcp/include/rtp_rtcp.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "test/gtest.h"
namespace webrtc {
// This class sends all its packet straight to the provided RtpRtcp module.
// with optional packet loss.
class LoopBackTransport : public Transport {
public:
LoopBackTransport()
: count_(0),
packet_loss_(0),
rtp_payload_registry_(NULL),
rtp_receiver_(NULL),
rtp_rtcp_module_(NULL) {}
void SetSendModule(RtpRtcp* rtp_rtcp_module,
RTPPayloadRegistry* payload_registry,
RtpReceiver* receiver,
ReceiveStatistics* receive_statistics);
void DropEveryNthPacket(int n);
bool SendRtp(const uint8_t* data,
size_t len,
const PacketOptions& options) override;
bool SendRtcp(const uint8_t* data, size_t len) override;
private:
int count_;
int packet_loss_;
ReceiveStatistics* receive_statistics_;
RTPPayloadRegistry* rtp_payload_registry_;
RtpReceiver* rtp_receiver_;
RtpRtcp* rtp_rtcp_module_;
};
class TestRtpReceiver : public RtpData {
public:
int32_t OnReceivedPayloadData(
const uint8_t* payload_data,
size_t payload_size,
const webrtc::WebRtcRTPHeader* rtp_header) override;
const uint8_t* payload_data() const { return payload_data_; }
size_t payload_size() const { return payload_size_; }
webrtc::WebRtcRTPHeader rtp_header() const { return rtp_header_; }
private:
uint8_t payload_data_[1500];
size_t payload_size_;
webrtc::WebRtcRTPHeader rtp_header_;
};
} // namespace webrtc
#endif // MODULES_RTP_RTCP_TEST_TESTAPI_TEST_API_H_

View File

@ -1,288 +0,0 @@
/*
* Copyright (c) 2012 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 <algorithm>
#include <memory>
#include <vector>
#include "common_types.h" // NOLINT(build/include)
#include "modules/audio_coding/codecs/audio_format_conversion.h"
#include "modules/rtp_rtcp/include/rtp_rtcp.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/rtp_rtcp/source/rtp_receiver_audio.h"
#include "modules/rtp_rtcp/test/testAPI/test_api.h"
#include "rtc_base/rate_limiter.h"
#include "test/gtest.h"
namespace webrtc {
namespace {
const uint32_t kTestRate = 64000u;
const uint8_t kTestPayload[] = {'t', 'e', 's', 't'};
const uint8_t kPcmuPayloadType = 96;
const uint8_t kDtmfPayloadType = 97;
const uint32_t kSsrc = 3456;
const uint32_t kTimestamp = 4567;
struct CngCodecSpec {
int payload_type;
int clockrate_hz;
};
const CngCodecSpec kCngCodecs[] = {{13, 8000},
{103, 16000},
{104, 32000},
{105, 48000}};
// Rough sanity check of DTMF payload.
void VerifyDtmf(const uint8_t* payloadData,
size_t payloadSize) {
EXPECT_EQ(payloadSize, 4u);
uint8_t p0 = (payloadSize > 0) ? payloadData[0] : 0xff;
uint8_t p1 = (payloadSize > 1) ? payloadData[1] : 0xff;
uint8_t p2 = (payloadSize > 2) ? payloadData[2] : 0xff;
uint8_t p3 = (payloadSize > 3) ? payloadData[3] : 0xff;
uint8_t event = p0;
bool reserved = (p1 >> 6) & 1;
uint8_t volume = p1 & 63;
uint16_t duration = (p2 << 8) | p3;
// 0-15 are digits, #, *, A-D, 32 is answer tone (see rfc 4734)
EXPECT_LE(event, 32u);
EXPECT_TRUE(event < 16u || event == 32u);
EXPECT_FALSE(reserved);
EXPECT_EQ(volume, 10u);
// Long duration for answer tone events only
EXPECT_TRUE(duration <= 1280 || event == 32u);
}
class VerifyingAudioReceiver : public RtpData {
public:
int32_t OnReceivedPayloadData(
const uint8_t* payloadData,
size_t payloadSize,
const webrtc::WebRtcRTPHeader* rtpHeader) override {
const uint8_t payload_type = rtpHeader->header.payloadType;
if (payload_type == kPcmuPayloadType) {
EXPECT_EQ(sizeof(kTestPayload), payloadSize);
// All our test vectors for PCMU are equal to |kTestPayload|.
const size_t min_size = std::min(sizeof(kTestPayload), payloadSize);
EXPECT_EQ(0, memcmp(payloadData, kTestPayload, min_size));
} else if (payload_type == kDtmfPayloadType) {
VerifyDtmf(payloadData, payloadSize);
}
return 0;
}
};
} // namespace
class RtpRtcpAudioTest : public ::testing::Test {
protected:
RtpRtcpAudioTest()
: fake_clock_(123456),
retransmission_rate_limiter_(&fake_clock_, 1000),
receive_statistics1_(ReceiveStatistics::Create(&fake_clock_)),
receive_statistics2_(ReceiveStatistics::Create(&fake_clock_)),
rtp_receiver1_(
RtpReceiver::CreateAudioReceiver(&fake_clock_,
&data_receiver1_,
&rtp_payload_registry1_)),
rtp_receiver2_(
RtpReceiver::CreateAudioReceiver(&fake_clock_,
&data_receiver2_,
&rtp_payload_registry2_)) {
RtpRtcp::Configuration configuration;
configuration.audio = true;
configuration.clock = &fake_clock_;
configuration.receive_statistics = receive_statistics1_.get();
configuration.outgoing_transport = &transport1_;
configuration.retransmission_rate_limiter = &retransmission_rate_limiter_;
module1_.reset(RtpRtcp::CreateRtpRtcp(configuration));
configuration.receive_statistics = receive_statistics2_.get();
configuration.outgoing_transport = &transport2_;
module2_.reset(RtpRtcp::CreateRtpRtcp(configuration));
transport1_.SetSendModule(module2_.get(), &rtp_payload_registry2_,
rtp_receiver2_.get(), receive_statistics2_.get());
transport2_.SetSendModule(module1_.get(), &rtp_payload_registry1_,
rtp_receiver1_.get(), receive_statistics1_.get());
}
~RtpRtcpAudioTest() override = default;
void RegisterPayload(const CodecInst& codec) {
EXPECT_EQ(0, module1_->RegisterSendPayload(codec));
EXPECT_EQ(0, rtp_receiver1_->RegisterReceivePayload(codec.pltype,
CodecInstToSdp(codec)));
EXPECT_EQ(0, module2_->RegisterSendPayload(codec));
EXPECT_EQ(0, rtp_receiver2_->RegisterReceivePayload(codec.pltype,
CodecInstToSdp(codec)));
}
SimulatedClock fake_clock_;
RateLimiter retransmission_rate_limiter_;
VerifyingAudioReceiver data_receiver1_;
VerifyingAudioReceiver data_receiver2_;
std::unique_ptr<ReceiveStatistics> receive_statistics1_;
std::unique_ptr<ReceiveStatistics> receive_statistics2_;
RTPPayloadRegistry rtp_payload_registry1_;
RTPPayloadRegistry rtp_payload_registry2_;
std::unique_ptr<RtpReceiver> rtp_receiver1_;
std::unique_ptr<RtpReceiver> rtp_receiver2_;
std::unique_ptr<RtpRtcp> module1_;
std::unique_ptr<RtpRtcp> module2_;
LoopBackTransport transport1_;
LoopBackTransport transport2_;
};
TEST_F(RtpRtcpAudioTest, Basic) {
module1_->SetSSRC(kSsrc);
module1_->SetStartTimestamp(kTimestamp);
// Test detection at the end of a DTMF tone.
// EXPECT_EQ(0, module2_->SetTelephoneEventForwardToDecoder(true));
EXPECT_EQ(0, module1_->SetSendingStatus(true));
// Start basic RTP test.
// Send an empty RTP packet.
// Should fail since we have not registered the payload type.
EXPECT_FALSE(module1_->SendOutgoingData(webrtc::kAudioFrameSpeech,
kPcmuPayloadType, 0, -1, nullptr, 0,
nullptr, nullptr, nullptr));
CodecInst voice_codec = {};
voice_codec.pltype = kPcmuPayloadType;
voice_codec.plfreq = 8000;
voice_codec.rate = kTestRate;
memcpy(voice_codec.plname, "PCMU", 5);
RegisterPayload(voice_codec);
EXPECT_TRUE(module1_->SendOutgoingData(webrtc::kAudioFrameSpeech,
kPcmuPayloadType, 0, -1, kTestPayload,
4, nullptr, nullptr, nullptr));
EXPECT_EQ(kSsrc, rtp_receiver2_->SSRC());
uint32_t timestamp;
int64_t receive_time_ms;
EXPECT_TRUE(
rtp_receiver2_->GetLatestTimestamps(&timestamp, &receive_time_ms));
EXPECT_EQ(kTimestamp, timestamp);
EXPECT_EQ(fake_clock_.TimeInMilliseconds(), receive_time_ms);
}
TEST_F(RtpRtcpAudioTest, DTMF) {
CodecInst voice_codec = {};
voice_codec.pltype = kPcmuPayloadType;
voice_codec.plfreq = 8000;
voice_codec.rate = kTestRate;
memcpy(voice_codec.plname, "PCMU", 5);
RegisterPayload(voice_codec);
module1_->SetSSRC(kSsrc);
module1_->SetStartTimestamp(kTimestamp);
EXPECT_EQ(0, module1_->SetSendingStatus(true));
// Prepare for DTMF.
voice_codec.pltype = kDtmfPayloadType;
voice_codec.plfreq = 8000;
memcpy(voice_codec.plname, "telephone-event", 16);
EXPECT_EQ(0, module1_->RegisterSendPayload(voice_codec));
EXPECT_EQ(0, rtp_receiver2_->RegisterReceivePayload(
voice_codec.pltype, CodecInstToSdp(voice_codec)));
// Start DTMF test.
int timeStamp = 160;
// Send a DTMF tone using RFC 2833 (4733).
for (int i = 0; i < 16; i++) {
EXPECT_EQ(0, module1_->SendTelephoneEventOutband(i, timeStamp, 10));
}
timeStamp += 160; // Prepare for next packet.
// Send RTP packets for 16 tones a 160 ms 100ms
// pause between = 2560ms + 1600ms = 4160ms
for (; timeStamp <= 250 * 160; timeStamp += 160) {
EXPECT_TRUE(module1_->SendOutgoingData(
webrtc::kAudioFrameSpeech, kPcmuPayloadType, timeStamp, -1,
kTestPayload, 4, nullptr, nullptr, nullptr));
fake_clock_.AdvanceTimeMilliseconds(20);
module1_->Process();
}
EXPECT_EQ(0, module1_->SendTelephoneEventOutband(32, 9000, 10));
for (; timeStamp <= 740 * 160; timeStamp += 160) {
EXPECT_TRUE(module1_->SendOutgoingData(
webrtc::kAudioFrameSpeech, kPcmuPayloadType, timeStamp, -1,
kTestPayload, 4, nullptr, nullptr, nullptr));
fake_clock_.AdvanceTimeMilliseconds(20);
module1_->Process();
}
}
TEST_F(RtpRtcpAudioTest, ComfortNoise) {
module1_->SetSSRC(kSsrc);
module1_->SetStartTimestamp(kTimestamp);
EXPECT_EQ(0, module1_->SetSendingStatus(true));
// Register PCMU and all four comfort noise codecs.
CodecInst voice_codec = {};
voice_codec.pltype = kPcmuPayloadType;
voice_codec.plfreq = 8000;
voice_codec.rate = kTestRate;
memcpy(voice_codec.plname, "PCMU", 5);
RegisterPayload(voice_codec);
for (const auto& c : kCngCodecs) {
CodecInst cng_codec = {};
cng_codec.pltype = c.payload_type;
cng_codec.plfreq = c.clockrate_hz;
memcpy(cng_codec.plname, "CN", 3);
RegisterPayload(cng_codec);
}
// Transmit comfort noise packets interleaved by PCMU packets.
uint32_t in_timestamp = 0;
for (const auto& c : kCngCodecs) {
uint32_t timestamp;
int64_t receive_time_ms;
EXPECT_TRUE(module1_->SendOutgoingData(
webrtc::kAudioFrameSpeech, kPcmuPayloadType, in_timestamp, -1,
kTestPayload, 4, nullptr, nullptr, nullptr));
EXPECT_EQ(kSsrc, rtp_receiver2_->SSRC());
EXPECT_TRUE(
rtp_receiver2_->GetLatestTimestamps(&timestamp, &receive_time_ms));
EXPECT_EQ(kTimestamp + in_timestamp, timestamp);
EXPECT_EQ(fake_clock_.TimeInMilliseconds(), receive_time_ms);
in_timestamp += 10;
fake_clock_.AdvanceTimeMilliseconds(20);
EXPECT_TRUE(module1_->SendOutgoingData(
webrtc::kAudioFrameCN, c.payload_type, in_timestamp, -1, kTestPayload,
1, nullptr, nullptr, nullptr));
EXPECT_EQ(kSsrc, rtp_receiver2_->SSRC());
EXPECT_TRUE(
rtp_receiver2_->GetLatestTimestamps(&timestamp, &receive_time_ms));
EXPECT_EQ(kTimestamp + in_timestamp, timestamp);
EXPECT_EQ(fake_clock_.TimeInMilliseconds(), receive_time_ms);
in_timestamp += 10;
fake_clock_.AdvanceTimeMilliseconds(20);
}
}
} // namespace webrtc

View File

@ -1,186 +0,0 @@
/*
* Copyright (c) 2012 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 <algorithm>
#include <memory>
#include <vector>
#include "common_types.h" // NOLINT(build/include)
#include "modules/audio_coding/codecs/audio_format_conversion.h"
#include "modules/rtp_rtcp/include/receive_statistics.h"
#include "modules/rtp_rtcp/include/rtp_rtcp.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/rtp_rtcp/source/rtp_receiver_audio.h"
#include "modules/rtp_rtcp/test/testAPI/test_api.h"
#include "rtc_base/rate_limiter.h"
#include "test/gtest.h"
namespace webrtc {
namespace {
const uint16_t kSequenceNumber = 2345;
const uint32_t kSsrc = 3456;
const uint32_t kTimestamp = 4567;
class RtcpCallback : public RtcpIntraFrameObserver {
public:
void OnReceivedIntraFrameRequest(uint32_t ssrc) override {}
};
class RtpRtcpRtcpTest : public ::testing::Test {
protected:
RtpRtcpRtcpTest()
: fake_clock_(123456),
retransmission_rate_limiter_(&fake_clock_, 1000),
receive_statistics1_(ReceiveStatistics::Create(&fake_clock_)),
receive_statistics2_(ReceiveStatistics::Create(&fake_clock_)),
rtp_receiver1_(
RtpReceiver::CreateAudioReceiver(&fake_clock_,
&receiver_,
&rtp_payload_registry1_)),
rtp_receiver2_(
RtpReceiver::CreateAudioReceiver(&fake_clock_,
&receiver_,
&rtp_payload_registry2_)) {}
~RtpRtcpRtcpTest() override = default;
void SetUp() override {
RtpRtcp::Configuration configuration;
configuration.audio = true;
configuration.clock = &fake_clock_;
configuration.receive_statistics = receive_statistics1_.get();
configuration.outgoing_transport = &transport1_;
configuration.intra_frame_callback = &rtcp_callback1_;
configuration.retransmission_rate_limiter = &retransmission_rate_limiter_;
module1_.reset(RtpRtcp::CreateRtpRtcp(configuration));
configuration.receive_statistics = receive_statistics2_.get();
configuration.outgoing_transport = &transport2_;
configuration.intra_frame_callback = &rtcp_callback2_;
module2_.reset(RtpRtcp::CreateRtpRtcp(configuration));
transport1_.SetSendModule(module2_.get(), &rtp_payload_registry2_,
rtp_receiver2_.get(), receive_statistics2_.get());
transport2_.SetSendModule(module1_.get(), &rtp_payload_registry1_,
rtp_receiver1_.get(), receive_statistics1_.get());
module1_->SetRTCPStatus(RtcpMode::kCompound);
module2_->SetRTCPStatus(RtcpMode::kCompound);
module2_->SetSSRC(kSsrc + 1);
module2_->SetRemoteSSRC(kSsrc);
module1_->SetSSRC(kSsrc);
module1_->SetSequenceNumber(kSequenceNumber);
module1_->SetStartTimestamp(kTimestamp);
module1_->SetCsrcs(kCsrcs);
EXPECT_EQ(0, module1_->SetCNAME("john.doe@test.test"));
EXPECT_EQ(0, module1_->SetSendingStatus(true));
CodecInst voice_codec;
voice_codec.pltype = 96;
voice_codec.plfreq = 8000;
voice_codec.rate = 64000;
memcpy(voice_codec.plname, "PCMU", 5);
EXPECT_EQ(0, module1_->RegisterSendPayload(voice_codec));
EXPECT_EQ(0, rtp_receiver1_->RegisterReceivePayload(
voice_codec.pltype, CodecInstToSdp(voice_codec)));
EXPECT_EQ(0, module2_->RegisterSendPayload(voice_codec));
EXPECT_EQ(0, rtp_receiver2_->RegisterReceivePayload(
voice_codec.pltype, CodecInstToSdp(voice_codec)));
// We need to send one RTP packet to get the RTCP packet to be accepted by
// the receiving module.
// Send RTP packet with the data "testtest".
const uint8_t test[9] = "testtest";
EXPECT_EQ(true,
module1_->SendOutgoingData(webrtc::kAudioFrameSpeech, 96, 0, -1,
test, 8, nullptr, nullptr, nullptr));
}
const std::vector<uint32_t> kCsrcs = {1234, 2345};
SimulatedClock fake_clock_;
RateLimiter retransmission_rate_limiter_;
RtcpCallback rtcp_callback1_;
RtcpCallback rtcp_callback2_;
RTPPayloadRegistry rtp_payload_registry1_;
RTPPayloadRegistry rtp_payload_registry2_;
TestRtpReceiver receiver_;
std::unique_ptr<ReceiveStatistics> receive_statistics1_;
std::unique_ptr<ReceiveStatistics> receive_statistics2_;
std::unique_ptr<RtpReceiver> rtp_receiver1_;
std::unique_ptr<RtpReceiver> rtp_receiver2_;
std::unique_ptr<RtpRtcp> module1_;
std::unique_ptr<RtpRtcp> module2_;
LoopBackTransport transport1_;
LoopBackTransport transport2_;
};
TEST_F(RtpRtcpRtcpTest, RTCP_CNAME) {
// Set cname of mixed.
EXPECT_EQ(0, module1_->AddMixedCNAME(kCsrcs[0], "john@192.168.0.1"));
EXPECT_EQ(0, module1_->AddMixedCNAME(kCsrcs[1], "jane@192.168.0.2"));
EXPECT_EQ(-1, module1_->RemoveMixedCNAME(kCsrcs[0] + 1));
EXPECT_EQ(0, module1_->RemoveMixedCNAME(kCsrcs[1]));
EXPECT_EQ(0, module1_->AddMixedCNAME(kCsrcs[1], "jane@192.168.0.2"));
// Send RTCP packet, triggered by timer.
fake_clock_.AdvanceTimeMilliseconds(7500);
module1_->Process();
fake_clock_.AdvanceTimeMilliseconds(100);
module2_->Process();
char cName[RTCP_CNAME_SIZE];
EXPECT_EQ(-1, module2_->RemoteCNAME(rtp_receiver2_->SSRC() + 1, cName));
// Check multiple CNAME.
EXPECT_EQ(0, module2_->RemoteCNAME(rtp_receiver2_->SSRC(), cName));
EXPECT_EQ(0, strncmp(cName, "john.doe@test.test", RTCP_CNAME_SIZE));
EXPECT_EQ(0, module2_->RemoteCNAME(kCsrcs[0], cName));
EXPECT_EQ(0, strncmp(cName, "john@192.168.0.1", RTCP_CNAME_SIZE));
EXPECT_EQ(0, module2_->RemoteCNAME(kCsrcs[1], cName));
EXPECT_EQ(0, strncmp(cName, "jane@192.168.0.2", RTCP_CNAME_SIZE));
EXPECT_EQ(0, module1_->SetSendingStatus(false));
// Test that BYE clears the CNAME.
EXPECT_EQ(-1, module2_->RemoteCNAME(rtp_receiver2_->SSRC(), cName));
}
TEST_F(RtpRtcpRtcpTest, RemoteRTCPStatRemote) {
std::vector<RTCPReportBlock> report_blocks;
EXPECT_EQ(0, module1_->RemoteRTCPStat(&report_blocks));
EXPECT_EQ(0u, report_blocks.size());
// Send RTCP packet, triggered by timer.
fake_clock_.AdvanceTimeMilliseconds(7500);
module1_->Process();
fake_clock_.AdvanceTimeMilliseconds(100);
module2_->Process();
EXPECT_EQ(0, module1_->RemoteRTCPStat(&report_blocks));
ASSERT_EQ(1u, report_blocks.size());
// |kSsrc+1| is the SSRC of module2 that send the report.
EXPECT_EQ(kSsrc + 1, report_blocks[0].sender_ssrc);
EXPECT_EQ(kSsrc, report_blocks[0].source_ssrc);
EXPECT_EQ(0, report_blocks[0].packets_lost);
EXPECT_LT(0u, report_blocks[0].delay_since_last_sender_report);
EXPECT_EQ(kSequenceNumber, report_blocks[0].extended_highest_sequence_number);
EXPECT_EQ(0u, report_blocks[0].fraction_lost);
}
} // namespace
} // namespace webrtc

View File

@ -1,166 +0,0 @@
/*
* Copyright (c) 2012 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 <stdlib.h>
#include <algorithm>
#include <memory>
#include "api/video_codecs/video_codec.h"
#include "modules/rtp_rtcp/include/rtp_payload_registry.h"
#include "modules/rtp_rtcp/include/rtp_rtcp.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/rtp_rtcp/source/byte_io.h"
#include "modules/rtp_rtcp/source/rtp_receiver_video.h"
#include "modules/rtp_rtcp/test/testAPI/test_api.h"
#include "rtc_base/rate_limiter.h"
#include "test/gtest.h"
namespace {
const uint32_t kSsrc = 3456;
const unsigned char kPayloadType = 100;
};
namespace webrtc {
class RtpRtcpVideoTest : public ::testing::Test {
protected:
RtpRtcpVideoTest()
: fake_clock_(123456),
retransmission_rate_limiter_(&fake_clock_, 1000),
receive_statistics_(ReceiveStatistics::Create(&fake_clock_)),
rtp_receiver_(
RtpReceiver::CreateVideoReceiver(&fake_clock_,
&receiver_,
&rtp_payload_registry_)) {}
~RtpRtcpVideoTest() override = default;
void SetUp() override {
RtpRtcp::Configuration configuration;
configuration.audio = false;
configuration.clock = &fake_clock_;
configuration.outgoing_transport = &transport_;
configuration.retransmission_rate_limiter = &retransmission_rate_limiter_;
video_module_.reset(RtpRtcp::CreateRtpRtcp(configuration));
video_module_->SetRTCPStatus(RtcpMode::kCompound);
video_module_->SetSSRC(kSsrc);
video_module_->SetStorePacketsStatus(true, 600);
EXPECT_EQ(0, video_module_->SetSendingStatus(true));
transport_.SetSendModule(video_module_.get(), &rtp_payload_registry_,
rtp_receiver_.get(), receive_statistics_.get());
VideoCodec video_codec;
memset(&video_codec, 0, sizeof(video_codec));
video_codec.plType = 123;
video_codec.codecType = kVideoCodecI420;
video_module_->RegisterVideoSendPayload(123, "I420");
EXPECT_EQ(0, rtp_payload_registry_.RegisterReceivePayload(video_codec));
payload_data_length_ = sizeof(video_frame_);
for (size_t n = 0; n < payload_data_length_; n++) {
video_frame_[n] = n % 10;
}
}
size_t BuildRTPheader(uint8_t* buffer,
uint32_t timestamp,
uint32_t sequence_number) {
buffer[0] = static_cast<uint8_t>(0x80); // version 2
buffer[1] = static_cast<uint8_t>(kPayloadType);
ByteWriter<uint16_t>::WriteBigEndian(buffer + 2, sequence_number);
ByteWriter<uint32_t>::WriteBigEndian(buffer + 4, timestamp);
ByteWriter<uint32_t>::WriteBigEndian(buffer + 8, 0x1234); // SSRC.
size_t rtpHeaderLength = 12;
return rtpHeaderLength;
}
size_t PaddingPacket(uint8_t* buffer,
uint32_t timestamp,
uint32_t sequence_number,
size_t bytes) {
// Max in the RFC 3550 is 255 bytes, we limit it to be modulus 32 for SRTP.
size_t max_length = 224;
size_t padding_bytes_in_packet = max_length;
if (bytes < max_length) {
padding_bytes_in_packet = (bytes + 16) & 0xffe0; // Keep our modulus 32.
}
// Correct seq num, timestamp and payload type.
size_t header_length = BuildRTPheader(buffer, timestamp, sequence_number);
buffer[0] |= 0x20; // Set padding bit.
int32_t* data = reinterpret_cast<int32_t*>(&(buffer[header_length]));
// Fill data buffer with random data.
for (size_t j = 0; j < (padding_bytes_in_packet >> 2); j++) {
data[j] = rand(); // NOLINT
}
// Set number of padding bytes in the last byte of the packet.
buffer[header_length + padding_bytes_in_packet - 1] =
padding_bytes_in_packet;
return padding_bytes_in_packet + header_length;
}
uint8_t video_frame_[65000];
size_t payload_data_length_;
SimulatedClock fake_clock_;
RateLimiter retransmission_rate_limiter_;
std::unique_ptr<ReceiveStatistics> receive_statistics_;
RTPPayloadRegistry rtp_payload_registry_;
TestRtpReceiver receiver_;
std::unique_ptr<RtpReceiver> rtp_receiver_;
std::unique_ptr<RtpRtcp> video_module_;
LoopBackTransport transport_;
};
TEST_F(RtpRtcpVideoTest, BasicVideo) {
uint32_t timestamp = 3000;
RTPVideoHeader video_header;
EXPECT_TRUE(video_module_->SendOutgoingData(
kVideoFrameDelta, 123, timestamp, timestamp / 90, video_frame_,
payload_data_length_, nullptr, &video_header, nullptr));
}
TEST_F(RtpRtcpVideoTest, PaddingOnlyFrames) {
const size_t kPadSize = 255;
uint8_t padding_packet[kPadSize];
uint32_t seq_num = 0;
uint32_t timestamp = 3000;
VideoCodec codec;
codec.codecType = kVideoCodecVP8;
codec.plType = kPayloadType;
EXPECT_EQ(0, rtp_payload_registry_.RegisterReceivePayload(codec));
for (int frame_idx = 0; frame_idx < 10; ++frame_idx) {
for (int packet_idx = 0; packet_idx < 5; ++packet_idx) {
size_t packet_size =
PaddingPacket(padding_packet, timestamp, seq_num, kPadSize);
++seq_num;
RTPHeader header;
std::unique_ptr<RtpHeaderParser> parser(RtpHeaderParser::Create());
EXPECT_TRUE(parser->Parse(padding_packet, packet_size, &header));
const auto pl =
rtp_payload_registry_.PayloadTypeToPayload(header.payloadType);
EXPECT_TRUE(pl);
const uint8_t* payload = padding_packet + header.headerLength;
const size_t payload_length = packet_size - header.headerLength;
EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
header, payload, payload_length, pl->typeSpecific));
EXPECT_EQ(0u, receiver_.payload_size());
EXPECT_EQ(payload_length, receiver_.rtp_header().header.paddingLength);
}
timestamp += 3000;
fake_clock_.AdvanceTimeMilliseconds(33);
}
}
} // namespace webrtc