Simulcast work to enable RID mux.

Rids can now be sent using rtp_sender.
Hooking up the rid values in the voice and video engine is still WIP.

Bug: webrtc:10074
Change-Id: I245c7ecb23b67fc0ba65caaa5dbb4fcfd60c81bb
Reviewed-on: https://webrtc-review.googlesource.com/c/114505
Commit-Queue: Amit Hilbuch <amithi@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Reviewed-by: Seth Hampson <shampson@webrtc.org>
Reviewed-by: Fredrik Solenberg <solenberg@webrtc.org>
Reviewed-by: Sam Zackrisson <saza@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26092}
This commit is contained in:
Amit Hilbuch 2018-12-21 09:23:38 -08:00 committed by Commit Bot
parent 86079a4571
commit 77938e6409
26 changed files with 374 additions and 55 deletions

View File

@ -137,12 +137,20 @@ const char RtpExtension::kGenericFrameDescriptorUri[] =
"http://www.webrtc.org/experiments/rtp-hdrext/generic-frame-descriptor-00";
const int RtpExtension::kGenericFrameDescriptorDefaultId = 11;
const char RtpExtension::kEncryptHeaderExtensionsUri[] =
"urn:ietf:params:rtp-hdrext:encrypt";
const char RtpExtension::kColorSpaceUri[] =
"http://www.webrtc.org/experiments/rtp-hdrext/color-space";
const int RtpExtension::kColorSpaceDefaultId = 12;
const char RtpExtension::kEncryptHeaderExtensionsUri[] =
"urn:ietf:params:rtp-hdrext:encrypt";
const char RtpExtension::kRidUri[] =
"urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id";
const int RtpExtension::kRidDefaultId = 13;
const char RtpExtension::kRepairedRidUri[] =
"urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id";
const int RtpExtension::kRepairedRidDefaultId = 14;
constexpr int RtpExtension::kMinId;
constexpr int RtpExtension::kMaxId;
@ -153,7 +161,9 @@ constexpr int RtpExtension::kOneByteHeaderExtensionMaxValueSize;
bool RtpExtension::IsSupportedForAudio(const std::string& uri) {
return uri == webrtc::RtpExtension::kAudioLevelUri ||
uri == webrtc::RtpExtension::kTransportSequenceNumberUri ||
uri == webrtc::RtpExtension::kMidUri;
uri == webrtc::RtpExtension::kMidUri ||
uri == webrtc::RtpExtension::kRidUri ||
uri == webrtc::RtpExtension::kRepairedRidUri;
}
bool RtpExtension::IsSupportedForVideo(const std::string& uri) {
@ -167,7 +177,9 @@ bool RtpExtension::IsSupportedForVideo(const std::string& uri) {
uri == webrtc::RtpExtension::kMidUri ||
uri == webrtc::RtpExtension::kFrameMarkingUri ||
uri == webrtc::RtpExtension::kGenericFrameDescriptorUri ||
uri == webrtc::RtpExtension::kColorSpaceUri;
uri == webrtc::RtpExtension::kColorSpaceUri ||
uri == webrtc::RtpExtension::kRidUri ||
uri == webrtc::RtpExtension::kRepairedRidUri;
}
bool RtpExtension::IsEncryptionSupported(const std::string& uri) {
@ -185,7 +197,9 @@ bool RtpExtension::IsEncryptionSupported(const std::string& uri) {
uri == webrtc::RtpExtension::kTransportSequenceNumberUri ||
uri == webrtc::RtpExtension::kPlayoutDelayUri ||
uri == webrtc::RtpExtension::kVideoContentTypeUri ||
uri == webrtc::RtpExtension::kMidUri;
uri == webrtc::RtpExtension::kMidUri ||
uri == webrtc::RtpExtension::kRidUri ||
uri == webrtc::RtpExtension::kRepairedRidUri;
}
const RtpExtension* RtpExtension::FindHeaderExtensionByUri(

View File

@ -313,6 +313,14 @@ struct RtpExtension {
static const char kColorSpaceUri[];
static const int kColorSpaceDefaultId;
// Header extension for RIDs and Repaired RIDs
// https://tools.ietf.org/html/draft-ietf-avtext-rid-09
// https://tools.ietf.org/html/draft-ietf-mmusic-rid-15
static const char kRidUri[];
static const int kRidDefaultId;
static const char kRepairedRidUri[];
static const int kRepairedRidDefaultId;
// Inclusive min and max IDs for two-byte header extensions and one-byte
// header extensions, per RFC8285 Section 4.2-4.3.
static constexpr int kMinId = 1;

View File

@ -197,6 +197,10 @@ AudioSendStream::ExtensionIds AudioSendStream::FindExtensionIds(
ids.transport_sequence_number = extension.id;
} else if (extension.uri == RtpExtension::kMidUri) {
ids.mid = extension.id;
} else if (extension.uri == RtpExtension::kRidUri) {
ids.rid = extension.id;
} else if (extension.uri == RtpExtension::kRepairedRidUri) {
ids.repaired_rid = extension.id;
}
}
return ids;
@ -281,6 +285,13 @@ void AudioSendStream::ConfigureStream(
channel_send->SetMid(new_config.rtp.mid, new_ids.mid);
}
// RID RTP header extension
if ((first_time || new_ids.rid != old_ids.rid ||
new_ids.repaired_rid != old_ids.repaired_rid ||
new_config.rtp.rid != old_config.rtp.rid)) {
channel_send->SetRid(new_config.rtp.rid, new_ids.rid, new_ids.repaired_rid);
}
if (!ReconfigureSendCodec(stream, new_config)) {
RTC_LOG(LS_ERROR) << "Failed to set up send codec state.";
}

View File

@ -148,6 +148,8 @@ class AudioSendStream final : public webrtc::AudioSendStream,
int audio_level = 0;
int transport_sequence_number = 0;
int mid = 0;
int rid = 0;
int repaired_rid = 0;
};
static ExtensionIds FindExtensionIds(
const std::vector<RtpExtension>& extensions);

View File

@ -210,6 +210,7 @@ struct ConfigHelper {
.Times(1);
}
EXPECT_CALL(*channel_send_, ResetSenderCongestionControlObjects()).Times(1);
EXPECT_CALL(*channel_send_, SetRid(std::string(), 0, 0)).Times(1);
}
void SetupMockForSetupSendCodec(bool expect_set_encoder_call) {

View File

@ -133,6 +133,9 @@ class ChannelSend
// RTP+RTCP
void SetLocalSSRC(uint32_t ssrc) override;
void SetRid(const std::string& rid,
int extension_id,
int repaired_extension_id) override;
void SetMid(const std::string& mid, int extension_id) override;
void SetExtmapAllowMixed(bool extmap_allow_mixed) override;
void SetSendAudioLevelIndicationStatus(bool enable, int id) override;
@ -965,6 +968,23 @@ void ChannelSend::SetLocalSSRC(uint32_t ssrc) {
_rtpRtcpModule->SetSSRC(ssrc);
}
void ChannelSend::SetRid(const std::string& rid,
int extension_id,
int repaired_extension_id) {
RTC_DCHECK_RUN_ON(&worker_thread_checker_);
if (extension_id != 0) {
int ret = SetSendRtpHeaderExtension(!rid.empty(), kRtpExtensionRtpStreamId,
extension_id);
RTC_DCHECK_EQ(0, ret);
}
if (repaired_extension_id != 0) {
int ret = SetSendRtpHeaderExtension(!rid.empty(), kRtpExtensionRtpStreamId,
repaired_extension_id);
RTC_DCHECK_EQ(0, ret);
}
_rtpRtcpModule->SetRid(rid);
}
void ChannelSend::SetMid(const std::string& mid, int extension_id) {
RTC_DCHECK_RUN_ON(&worker_thread_checker_);
int ret = SetSendRtpHeaderExtension(true, kRtpExtensionMid, extension_id);

View File

@ -65,6 +65,10 @@ class ChannelSendInterface {
rtc::FunctionView<void(std::unique_ptr<AudioEncoder>*)> modifier) = 0;
virtual void SetLocalSSRC(uint32_t ssrc) = 0;
// Use 0 to indicate that the extension should not be registered.
virtual void SetRid(const std::string& rid,
int extension_id,
int repaired_extension_id) = 0;
virtual void SetMid(const std::string& mid, int extension_id) = 0;
virtual void SetRTCP_CNAME(absl::string_view c_name) = 0;
virtual void SetExtmapAllowMixed(bool extmap_allow_mixed) = 0;

View File

@ -74,6 +74,10 @@ class MockChannelSend : public voe::ChannelSendInterface {
MOCK_METHOD1(
ModifyEncoder,
void(rtc::FunctionView<void(std::unique_ptr<AudioEncoder>*)> modifier));
MOCK_METHOD3(SetRid,
void(const std::string& rid,
int extension_id,
int repaired_extension_id));
MOCK_METHOD2(SetMid, void(const std::string& mid, int extension_id));
MOCK_METHOD1(SetLocalSSRC, void(uint32_t ssrc));
MOCK_METHOD1(SetRTCP_CNAME, void(absl::string_view c_name));

View File

@ -79,6 +79,10 @@ class AudioSendStream {
// Sender SSRC.
uint32_t ssrc = 0;
// The value to send in the RID RTP header extension if the extension is
// included in the list of extensions.
std::string rid;
// The value to send in the MID RTP header extension if the extension is
// included in the list of extensions.
std::string mid;

View File

@ -66,6 +66,14 @@ struct RtpConfig {
std::vector<uint32_t> ssrcs;
// The Rtp Stream Ids (aka RIDs) to send in the RID RTP header extension
// if the extension is included in the list of extensions.
// If rids are specified, they should correspond to the |ssrcs| vector.
// This means that:
// 1. rids.size() == 0 || rids.size() == ssrcs.size().
// 2. If rids is not empty, then |rids[i]| should use |ssrcs[i]|.
std::vector<std::string> rids;
// The value to send in the MID RTP header extension if the extension is
// included in the list of extensions.
std::string mid;

View File

@ -225,6 +225,9 @@ RtpVideoSender::RtpVideoSender(
overhead_bytes_per_packet_(0),
encoder_target_rate_bps_(0) {
RTC_DCHECK_EQ(ssrcs.size(), rtp_modules_.size());
// The same argument for SSRCs is given to this method twice.
// The SSRCs are also accessed in this method through both variables.
RTC_DCHECK(ssrcs == rtp_config.ssrcs);
module_process_thread_checker_.DetachFromThread();
// SSRCs are assumed to be sorted in the same order as |rtp_modules|.
for (uint32_t ssrc : ssrcs) {
@ -263,6 +266,7 @@ RtpVideoSender::RtpVideoSender(
ConfigureProtection(rtp_config);
ConfigureSsrcs(rtp_config);
ConfigureRids(rtp_config);
if (!rtp_config.mid.empty()) {
for (auto& rtp_rtcp : rtp_modules_) {
@ -532,6 +536,18 @@ void RtpVideoSender::ConfigureSsrcs(const RtpConfig& rtp_config) {
}
}
void RtpVideoSender::ConfigureRids(const RtpConfig& rtp_config) {
RTC_DCHECK(rtp_config.rids.empty() ||
rtp_config.rids.size() == rtp_config.ssrcs.size());
RTC_DCHECK(rtp_config.rids.empty() ||
rtp_config.rids.size() == rtp_modules_.size());
for (size_t i = 0; i < rtp_config.rids.size(); ++i) {
const std::string& rid = rtp_config.rids[i];
RtpRtcp* const rtp_rtcp = rtp_modules_[i].get();
rtp_rtcp->SetRid(rid);
}
}
void RtpVideoSender::OnNetworkAvailability(bool network_available) {
for (auto& rtp_rtcp : rtp_modules_) {
rtp_rtcp->SetRTCPStatus(network_available ? rtp_config_.rtcp_mode

View File

@ -126,6 +126,7 @@ class RtpVideoSender : public RtpVideoSenderInterface,
void UpdateModuleSendingState() RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_);
void ConfigureProtection(const RtpConfig& rtp_config);
void ConfigureSsrcs(const RtpConfig& rtp_config);
void ConfigureRids(const RtpConfig& rtp_config);
bool FecEnabled() const;
bool NackEnabled() const;

View File

@ -514,10 +514,7 @@ RtpCapabilities WebRtcVideoEngine::GetCapabilities() const {
webrtc::RtpExtension::kGenericFrameDescriptorUri,
webrtc::RtpExtension::kGenericFrameDescriptorDefaultId));
}
// TODO(bugs.webrtc.org/4050): Add MID header extension as capability once MID
// demuxing is completed.
// capabilities.header_extensions.push_back(webrtc::RtpExtension(
// webrtc::RtpExtension::kMidUri, webrtc::RtpExtension::kMidDefaultId));
return capabilities;
}

View File

@ -564,10 +564,7 @@ RtpCapabilities WebRtcVoiceEngine::GetCapabilities() const {
webrtc::RtpExtension::kTransportSequenceNumberUri,
webrtc::RtpExtension::kTransportSequenceNumberDefaultId));
}
// TODO(bugs.webrtc.org/4050): Add MID header extension as capability once MID
// demuxing is completed.
// capabilities.header_extensions.push_back(webrtc::RtpExtension(
// webrtc::RtpExtension::kMidUri, webrtc::RtpExtension::kMidDefaultId));
return capabilities;
}

View File

@ -186,6 +186,12 @@ class RtpRtcp : public Module, public RtcpFeedbackSenderInterface {
// Sets SSRC, default is a random number.
virtual void SetSSRC(uint32_t ssrc) = 0;
// Sets the value for sending in the RID (and Repaired) RTP header extension.
// RIDs are used to identify an RTP stream if SSRCs are not negotiated.
// If the RID and Repaired RID extensions are not registered, the RID will
// not be sent.
virtual void SetRid(const std::string& rid) = 0;
// Sets the value for sending in the MID RTP header extension.
// The MID RTP header extension should be registered for this to do anything.
// Once set, this value can not be changed or removed.

View File

@ -64,6 +64,7 @@ class MockRtpRtcp : public RtpRtcp {
MOCK_CONST_METHOD0(GetRtxState, RtpState());
MOCK_CONST_METHOD0(SSRC, uint32_t());
MOCK_METHOD1(SetSSRC, void(uint32_t ssrc));
MOCK_METHOD1(SetRid, void(const std::string& rid));
MOCK_METHOD1(SetMid, void(const std::string& mid));
MOCK_CONST_METHOD1(CSRCs, int32_t(uint32_t csrcs[kRtpCsrcSize]));
MOCK_METHOD1(SetCsrcs, void(const std::vector<uint32_t>& csrcs));

View File

@ -569,4 +569,9 @@ rtc::ArrayView<uint8_t> RtpPacket::AllocateExtension(ExtensionType type,
return AllocateRawExtension(id, length);
}
bool RtpPacket::HasExtension(ExtensionType type) const {
// TODO(webrtc:7990): Add support for empty extensions (length==0).
return !FindExtension(type).empty();
}
} // namespace webrtc

View File

@ -95,6 +95,7 @@ class RtpPacket {
// Header extensions.
template <typename Extension>
bool HasExtension() const;
bool HasExtension(ExtensionType type) const;
template <typename Extension, typename FirstValue, typename... Values>
bool GetExtension(FirstValue, Values...) const;
@ -112,6 +113,14 @@ class RtpPacket {
template <typename Extension>
bool ReserveExtension();
// Find or allocate an extension |type|. Returns view of size |length|
// to write raw extension to or an empty view on failure.
rtc::ArrayView<uint8_t> AllocateExtension(ExtensionType type, size_t length);
// Find an extension |type|.
// Returns view of the raw extension or empty view on failure.
rtc::ArrayView<const uint8_t> FindExtension(ExtensionType type) const;
// Reserve size_bytes for payload. Returns nullptr on failure.
uint8_t* SetPayloadSize(size_t size_bytes);
// Same as SetPayloadSize but doesn't guarantee to keep current payload.
@ -145,10 +154,6 @@ class RtpPacket {
// with the specified id if not found.
ExtensionInfo& FindOrCreateExtensionInfo(int id);
// Find an extension |type|.
// Returns view of the raw extension or empty view on failure.
rtc::ArrayView<const uint8_t> FindExtension(ExtensionType type) const;
// Allocates and returns place to store rtp header extension.
// Returns empty arrayview on failure.
rtc::ArrayView<uint8_t> AllocateRawExtension(int id, size_t length);
@ -159,10 +164,6 @@ class RtpPacket {
uint16_t SetExtensionLengthMaybeAddZeroPadding(size_t extensions_offset);
// Find or allocate an extension |type|. Returns view of size |length|
// to write raw extension to or an empty view on failure.
rtc::ArrayView<uint8_t> AllocateExtension(ExtensionType type, size_t length);
uint8_t* WriteAt(size_t offset) { return buffer_.data() + offset; }
void WriteAt(size_t offset, uint8_t byte) { buffer_.data()[offset] = byte; }
@ -184,7 +185,7 @@ class RtpPacket {
template <typename Extension>
bool RtpPacket::HasExtension() const {
return !FindExtension(Extension::kId).empty();
return HasExtension(Extension::kId);
}
template <typename Extension, typename FirstValue, typename... Values>

View File

@ -335,6 +335,12 @@ void ModuleRtpRtcpImpl::SetSSRC(const uint32_t ssrc) {
SetRtcpReceiverSsrcs(ssrc);
}
void ModuleRtpRtcpImpl::SetRid(const std::string& rid) {
if (rtp_sender_) {
rtp_sender_->SetRid(rid);
}
}
void ModuleRtpRtcpImpl::SetMid(const std::string& mid) {
if (rtp_sender_) {
rtp_sender_->SetMid(mid);

View File

@ -105,6 +105,8 @@ class ModuleRtpRtcpImpl : public RtpRtcp, public RTCPReceiver::ModuleRtpRtcp {
// Configure SSRC, default is a random number.
void SetSSRC(uint32_t ssrc) override;
void SetRid(const std::string& rid) override;
void SetMid(const std::string& mid) override;
void SetCsrcs(const std::vector<uint32_t>& csrcs) override;

View File

@ -17,6 +17,7 @@
#include "absl/memory/memory.h"
#include "absl/strings/match.h"
#include "api/array_view.h"
#include "logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h"
#include "logging/rtc_event_log/rtc_event_log.h"
#include "modules/remote_bitrate_estimator/test/bwe_test_logging.h"
@ -57,13 +58,18 @@ constexpr RtpExtensionSize CreateExtensionSize() {
return {Extension::kId, Extension::kValueSizeBytes};
}
template <typename Extension>
constexpr RtpExtensionSize CreateMaxExtensionSize() {
return {Extension::kId, Extension::kMaxValueSizeBytes};
}
// Size info for header extensions that might be used in padding or FEC packets.
constexpr RtpExtensionSize kFecOrPaddingExtensionSizes[] = {
CreateExtensionSize<AbsoluteSendTime>(),
CreateExtensionSize<TransmissionOffset>(),
CreateExtensionSize<TransportSequenceNumber>(),
CreateExtensionSize<PlayoutDelayLimits>(),
{RtpMid::kId, RtpMid::kMaxValueSizeBytes},
CreateMaxExtensionSize<RtpMid>(),
};
// Size info for header extensions that might be used in video packets.
@ -75,7 +81,9 @@ constexpr RtpExtensionSize kVideoExtensionSizes[] = {
CreateExtensionSize<VideoOrientation>(),
CreateExtensionSize<VideoContentTypeExtension>(),
CreateExtensionSize<VideoTimingExtension>(),
{RtpMid::kId, RtpMid::kMaxValueSizeBytes},
CreateMaxExtensionSize<RtpStreamId>(),
CreateMaxExtensionSize<RepairedRtpStreamId>(),
CreateMaxExtensionSize<RtpMid>(),
{RtpGenericFrameDescriptorExtension::kId,
RtpGenericFrameDescriptorExtension::kMaxSizeBytes},
};
@ -1174,6 +1182,10 @@ std::unique_ptr<RtpPacketToSend> RTPSender::AllocatePacket() const {
// This is a no-op if the MID header extension is not registered.
packet->SetExtension<RtpMid>(mid_);
}
if (!rid_.empty()) {
// This is a no-op if the RID header extension is not registered.
packet->SetExtension<RtpStreamId>(rid_);
}
return packet;
}
@ -1258,6 +1270,13 @@ uint32_t RTPSender::SSRC() const {
return *ssrc_;
}
void RTPSender::SetRid(const std::string& rid) {
// RID is used in simulcast scenario when multiple layers share the same mid.
rtc::CritScope lock(&send_critsect_);
RTC_DCHECK_LE(rid.length(), RtpStreamId::kMaxValueSizeBytes);
rid_ = rid;
}
void RTPSender::SetMid(const std::string& mid) {
// This is configured via the API.
rtc::CritScope lock(&send_critsect_);
@ -1316,14 +1335,69 @@ bool RTPSender::SetFecParameters(const FecProtectionParams& delta_params,
return true;
}
std::unique_ptr<RtpPacketToSend> RTPSender::BuildRtxPacket(
const RtpPacketToSend& packet) {
static std::unique_ptr<RtpPacketToSend> CreateRtxPacket(
const RtpPacketToSend& packet,
RtpHeaderExtensionMap* extension_map) {
RTC_DCHECK(extension_map);
// TODO(danilchap): Create rtx packet with extra capacity for SRTP
// when transport interface would be updated to take buffer class.
std::unique_ptr<RtpPacketToSend> rtx_packet(new RtpPacketToSend(
&rtp_header_extension_map_, packet.size() + kRtxHeaderSize));
size_t packet_size = packet.size() + kRtxHeaderSize;
std::unique_ptr<RtpPacketToSend> rtx_packet =
absl::make_unique<RtpPacketToSend>(extension_map, packet_size);
// Set the relevant fixed packet headers. The following are not set:
// * Payload type - it is replaced in rtx packets.
// * Sequence number - RTX has a separate sequence numbering.
// * SSRC - RTX stream has its own SSRC.
rtx_packet->SetMarker(packet.Marker());
rtx_packet->SetTimestamp(packet.Timestamp());
// Set the variable fields in the packet header:
// * CSRCs - must be set before header extensions.
// * Header extensions - replace Rid header with RepairedRid header.
const std::vector<uint32_t> csrcs = packet.Csrcs();
rtx_packet->SetCsrcs(csrcs);
for (int extension = kRtpExtensionNone + 1;
extension < kRtpExtensionNumberOfExtensions; ++extension) {
RTPExtensionType source_extension =
static_cast<RTPExtensionType>(extension);
// Rid header should be replaced with RepairedRid header
RTPExtensionType destination_extension =
source_extension == kRtpExtensionRtpStreamId
? kRtpExtensionRepairedRtpStreamId
: source_extension;
// Empty extensions should be supported, so not checking |source.empty()|.
if (!packet.HasExtension(source_extension)) {
continue;
}
rtc::ArrayView<const uint8_t> source =
packet.FindExtension(source_extension);
rtc::ArrayView<uint8_t> destination =
rtx_packet->AllocateExtension(destination_extension, source.size());
// Could happen if any:
// 1. Extension has 0 length.
// 2. Extension is not registered in destination.
// 3. Allocating extension in destination failed.
if (destination.empty() || source.size() != destination.size()) {
continue;
}
std::memcpy(destination.begin(), source.begin(), destination.size());
}
return rtx_packet;
}
std::unique_ptr<RtpPacketToSend> RTPSender::BuildRtxPacket(
const RtpPacketToSend& packet) {
std::unique_ptr<RtpPacketToSend> rtx_packet =
CreateRtxPacket(packet, &rtp_header_extension_map_);
// Add original RTP header.
rtx_packet->CopyHeaderFrom(packet);
{
rtc::CritScope lock(&send_critsect_);
if (!sending_media_)
@ -1343,11 +1417,20 @@ std::unique_ptr<RtpPacketToSend> RTPSender::BuildRtxPacket(
// Replace SSRC.
rtx_packet->SetSsrc(*ssrc_rtx_);
// Possibly include the MID header extension.
// The spec indicates that it is possible for a sender to stop sending mids
// once the SSRCs have been bound on the receiver. As a result the source
// rtp packet might not have the MID header extension set.
// However, the SSRC of the RTX stream might not have been bound on the
// receiver. This means that we should include it here.
// The same argument goes for the Repaired RID extension.
if (!mid_.empty()) {
// This is a no-op if the MID header extension is not registered.
rtx_packet->SetExtension<RtpMid>(mid_);
}
if (!rid_.empty()) {
// This is a no-op if the Repaired-RID header extension is not registered.
// rtx_packet->SetExtension<RepairedRtpStreamId>(rid_);
}
}
uint8_t* rtx_payload =

View File

@ -100,6 +100,8 @@ class RTPSender {
void SetSSRC(uint32_t ssrc);
void SetRid(const std::string& rid);
void SetMid(const std::string& mid);
uint16_t SequenceNumber() const;
@ -330,6 +332,8 @@ class RTPSender {
// Must be explicitly set by the application, use of absl::optional
// only to keep track of correct use.
absl::optional<uint32_t> ssrc_ RTC_GUARDED_BY(send_critsect_);
// RID value to send in the RID or RepairedRID header extension.
std::string rid_ RTC_GUARDED_BY(send_critsect_);
// MID value to send in the MID header extension.
std::string mid_ RTC_GUARDED_BY(send_critsect_);
uint32_t last_rtp_timestamp_ RTC_GUARDED_BY(send_critsect_);

View File

@ -45,6 +45,11 @@ const int kAbsoluteSendTimeExtensionId = 14;
const int kTransportSequenceNumberExtensionId = 13;
const int kVideoTimingExtensionId = 12;
const int kMidExtensionId = 11;
const int kGenericDescriptorId = 10;
const int kAudioLevelExtensionId = 9;
const int kRidExtensionId = 8;
const int kRepairedRidExtensionId = 7;
const int kVideoRotationExtensionId = 5;
const int kPayload = 100;
const int kRtxPayload = 98;
const uint32_t kTimestamp = 10;
@ -53,15 +58,14 @@ const uint32_t kSsrc = 725242;
const int kMaxPacketLength = 1500;
const uint8_t kAudioLevel = 0x5a;
const uint16_t kTransportSequenceNumber = 0xaabbu;
const uint8_t kAudioLevelExtensionId = 9;
const int kAudioPayload = 103;
const uint64_t kStartTime = 123456789;
const size_t kMaxPaddingSize = 224u;
const int kVideoRotationExtensionId = 5;
const size_t kGenericHeaderLength = 1;
const uint8_t kPayloadData[] = {47, 11, 32, 93, 89};
const int64_t kDefaultExpectedRetransmissionTimeMs = 125;
const int kGenericDescriptorId = 10;
const char kNoRid[] = "";
const char kNoMid[] = "";
using ::testing::_;
using ::testing::ElementsAre;
@ -91,6 +95,9 @@ class LoopbackTransportTest : public webrtc::Transport {
receivers_extensions_.Register(kRtpExtensionMid, kMidExtensionId);
receivers_extensions_.Register(kRtpExtensionGenericFrameDescriptor,
kGenericDescriptorId);
receivers_extensions_.Register(kRtpExtensionRtpStreamId, kRidExtensionId);
receivers_extensions_.Register(kRtpExtensionRepairedRtpStreamId,
kRepairedRidExtensionId);
}
bool SendRtp(const uint8_t* data,
@ -1146,7 +1153,6 @@ TEST_P(RtpSenderTest, SendFlexfecPackets) {
constexpr int kFlexfecPayloadType = 118;
constexpr uint32_t kMediaSsrc = 1234;
constexpr uint32_t kFlexfecSsrc = 5678;
const char kNoMid[] = "";
const std::vector<RtpExtension> kNoRtpExtensions;
const std::vector<RtpExtensionSize> kNoRtpExtensionSizes;
FlexfecSender flexfec_sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
@ -1205,7 +1211,6 @@ TEST_P(RtpSenderTest, NoFlexfecForTimingFrames) {
constexpr int kFlexfecPayloadType = 118;
constexpr uint32_t kMediaSsrc = 1234;
constexpr uint32_t kFlexfecSsrc = 5678;
const char kNoMid[] = "";
const std::vector<RtpExtension> kNoRtpExtensions;
const std::vector<RtpExtensionSize> kNoRtpExtensionSizes;
@ -1305,7 +1310,6 @@ TEST_P(RtpSenderTestWithoutPacer, SendFlexfecPackets) {
constexpr int kFlexfecPayloadType = 118;
constexpr uint32_t kMediaSsrc = 1234;
constexpr uint32_t kFlexfecSsrc = 5678;
const char kNoMid[] = "";
const std::vector<RtpExtension> kNoRtpExtensions;
const std::vector<RtpExtensionSize> kNoRtpExtensionSizes;
FlexfecSender flexfec_sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
@ -1365,11 +1369,64 @@ TEST_P(RtpSenderTestWithoutPacer, MidIncludedOnSentPackets) {
}
}
TEST_P(RtpSenderTestWithoutPacer, RidIncludedOnSentPackets) {
const char kRid[] = "f";
rtp_sender_->SetSendingMediaStatus(false);
rtp_sender_->RegisterRtpHeaderExtension(kRtpExtensionRtpStreamId,
kRidExtensionId);
rtp_sender_->SetRid(kRid);
rtp_sender_->SetSendingMediaStatus(true);
SendGenericPayload();
ASSERT_EQ(1u, transport_.sent_packets_.size());
const RtpPacketReceived& packet = transport_.sent_packets_[0];
std::string rid;
ASSERT_TRUE(packet.GetExtension<RtpStreamId>(&rid));
EXPECT_EQ(kRid, rid);
}
TEST_P(RtpSenderTestWithoutPacer, RidIncludedOnRtxSentPackets) {
const char kRid[] = "f";
const uint8_t kPayloadType = 127;
rtp_sender_->SetSendingMediaStatus(false);
rtp_sender_->RegisterRtpHeaderExtension(kRtpExtensionRtpStreamId,
kRidExtensionId);
rtp_sender_->RegisterRtpHeaderExtension(kRtpExtensionRepairedRtpStreamId,
kRepairedRidExtensionId);
rtp_sender_->SetRid(kRid);
rtp_sender_->SetSendingMediaStatus(true);
rtp_sender_->SetRtxStatus(kRtxRetransmitted | kRtxRedundantPayloads);
rtp_sender_->SetRtxSsrc(1234);
rtp_sender_->SetRtxPayloadType(kRtxPayload, kPayloadType);
rtp_sender_->SetStorePacketsStatus(true, 10);
SendGenericPayload();
ASSERT_EQ(1u, transport_.sent_packets_.size());
const RtpPacketReceived& packet = transport_.sent_packets_[0];
std::string rid;
ASSERT_TRUE(packet.GetExtension<RtpStreamId>(&rid));
EXPECT_EQ(kRid, rid);
rid = kNoRid;
EXPECT_FALSE(packet.GetExtension<RepairedRtpStreamId>(&rid));
uint16_t packet_id = packet.SequenceNumber();
rtp_sender_->ReSendPacket(packet_id);
ASSERT_EQ(2u, transport_.sent_packets_.size());
const RtpPacketReceived& rtx_packet = transport_.sent_packets_[1];
ASSERT_TRUE(rtx_packet.GetExtension<RepairedRtpStreamId>(&rid));
EXPECT_EQ(kRid, rid);
EXPECT_FALSE(rtx_packet.HasExtension<RtpStreamId>());
}
TEST_P(RtpSenderTest, FecOverheadRate) {
constexpr int kFlexfecPayloadType = 118;
constexpr uint32_t kMediaSsrc = 1234;
constexpr uint32_t kFlexfecSsrc = 5678;
const char kNoMid[] = "";
const std::vector<RtpExtension> kNoRtpExtensions;
const std::vector<RtpExtensionSize> kNoRtpExtensionSizes;
FlexfecSender flexfec_sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,

View File

@ -1274,6 +1274,38 @@ void MediaSessionDescriptionFactory::set_audio_codecs(
ComputeAudioCodecsIntersectionAndUnion();
}
static void AddUnifiedPlanExtensions(RtpHeaderExtensions* extensions) {
RTC_DCHECK(extensions);
// Unified Plan also offers the MID and RID header extensions.
extensions->push_back(webrtc::RtpExtension(
webrtc::RtpExtension::kMidUri, webrtc::RtpExtension::kMidDefaultId));
extensions->push_back(webrtc::RtpExtension(
webrtc::RtpExtension::kRidUri, webrtc::RtpExtension::kRidDefaultId));
extensions->push_back(
webrtc::RtpExtension(webrtc::RtpExtension::kRepairedRidUri,
webrtc::RtpExtension::kRepairedRidDefaultId));
}
RtpHeaderExtensions
MediaSessionDescriptionFactory::audio_rtp_header_extensions() const {
RtpHeaderExtensions extensions = audio_rtp_extensions_;
if (is_unified_plan_) {
AddUnifiedPlanExtensions(&extensions);
}
return extensions;
}
RtpHeaderExtensions
MediaSessionDescriptionFactory::video_rtp_header_extensions() const {
RtpHeaderExtensions extensions = video_rtp_extensions_;
if (is_unified_plan_) {
AddUnifiedPlanExtensions(&extensions);
}
return extensions;
}
std::unique_ptr<SessionDescription> MediaSessionDescriptionFactory::CreateOffer(
const MediaSessionOptions& session_options,
const SessionDescription* current_description) const {

View File

@ -127,29 +127,13 @@ class MediaSessionDescriptionFactory {
void set_audio_rtp_header_extensions(const RtpHeaderExtensions& extensions) {
audio_rtp_extensions_ = extensions;
}
RtpHeaderExtensions audio_rtp_header_extensions() const {
RtpHeaderExtensions extensions = audio_rtp_extensions_;
// If we are Unified Plan, also offer the MID header extension.
if (is_unified_plan_) {
extensions.push_back(webrtc::RtpExtension(
webrtc::RtpExtension::kMidUri, webrtc::RtpExtension::kMidDefaultId));
}
return extensions;
}
RtpHeaderExtensions audio_rtp_header_extensions() const;
const VideoCodecs& video_codecs() const { return video_codecs_; }
void set_video_codecs(const VideoCodecs& codecs) { video_codecs_ = codecs; }
void set_video_rtp_header_extensions(const RtpHeaderExtensions& extensions) {
video_rtp_extensions_ = extensions;
}
RtpHeaderExtensions video_rtp_header_extensions() const {
RtpHeaderExtensions extensions = video_rtp_extensions_;
// If we are Unified Plan, also offer the MID header extension.
if (is_unified_plan_) {
extensions.push_back(webrtc::RtpExtension(
webrtc::RtpExtension::kMidUri, webrtc::RtpExtension::kMidDefaultId));
}
return extensions;
}
RtpHeaderExtensions video_rtp_header_extensions() const;
const DataCodecs& data_codecs() const { return data_codecs_; }
void set_data_codecs(const DataCodecs& codecs) { data_codecs_ = codecs; }
SecurePolicy secure() const { return secure_; }

View File

@ -8,6 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#include <algorithm>
#include <memory>
#include <string>
#include <vector>
@ -3686,6 +3687,56 @@ TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
}
// Checks that the RID extensions are added to the video RTP header extensions.
// Note: This test somewhat shows that |set_video_rtp_header_extensions()| is
// not very well defined, as calling set() and immediately get() will yield
// an object that is not semantically equivalent to the set object.
TEST_F(MediaSessionDescriptionFactoryTest, VideoHasRidExtensionsInUnifiedPlan) {
TransportDescriptionFactory tdf;
MediaSessionDescriptionFactory sf(&tdf);
sf.set_is_unified_plan(true);
cricket::RtpHeaderExtensions extensions;
sf.set_video_rtp_header_extensions(extensions);
cricket::RtpHeaderExtensions result = sf.video_rtp_header_extensions();
// Check to see that RID extensions were added to the extension list
EXPECT_GE(result.size(), 2u);
auto rid_extension = std::find_if(
result.begin(), result.end(), [](const RtpExtension& extension) {
return extension.uri == webrtc::RtpExtension::kRidUri;
});
EXPECT_NE(rid_extension, extensions.end());
auto repaired_rid_extension = std::find_if(
result.begin(), result.end(), [](const RtpExtension& extension) {
return extension.uri == webrtc::RtpExtension::kRepairedRidUri;
});
EXPECT_NE(repaired_rid_extension, extensions.end());
}
// Checks that the RID extensions are added to the audio RTP header extensions.
// Note: This test somewhat shows that |set_audio_rtp_header_extensions()| is
// not very well defined, as calling set() and immediately get() will yield
// an object that is not semantically equivalent to the set object.
TEST_F(MediaSessionDescriptionFactoryTest, AudioHasRidExtensionsInUnifiedPlan) {
TransportDescriptionFactory tdf;
MediaSessionDescriptionFactory sf(&tdf);
sf.set_is_unified_plan(true);
cricket::RtpHeaderExtensions extensions;
sf.set_audio_rtp_header_extensions(extensions);
cricket::RtpHeaderExtensions result = sf.audio_rtp_header_extensions();
// Check to see that RID extensions were added to the extension list
EXPECT_GE(result.size(), 2u);
auto rid_extension = std::find_if(
result.begin(), result.end(), [](const RtpExtension& extension) {
return extension.uri == webrtc::RtpExtension::kRidUri;
});
EXPECT_NE(rid_extension, extensions.end());
auto repaired_rid_extension = std::find_if(
result.begin(), result.end(), [](const RtpExtension& extension) {
return extension.uri == webrtc::RtpExtension::kRepairedRidUri;
});
EXPECT_NE(repaired_rid_extension, extensions.end());
}
namespace {
// Compare the two vectors of codecs ignoring the payload type.
template <class Codec>