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:
parent
86079a4571
commit
77938e6409
@ -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(
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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.";
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 =
|
||||
|
||||
@ -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_);
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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_; }
|
||||
|
||||
@ -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>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user