Add support for enabling simulcast in "Plan B" using MediaConstraints.
BUG=webrtc:9655 Change-Id: Ieb5fe5d97b6d4381608a51593bca5423979d1b9f Reviewed-on: https://webrtc-review.googlesource.com/95481 Commit-Queue: Jonas Oreland <jonaso@webrtc.org> Reviewed-by: Rasmus Brandt <brandtr@webrtc.org> Reviewed-by: Seth Hampson <shampson@webrtc.org> Cr-Commit-Position: refs/heads/master@{#24424}
This commit is contained in:

committed by
Commit Bot

parent
d65e143801
commit
fc1acd2364
@ -146,6 +146,9 @@ const char MediaConstraintsInterface::kCpuOveruseDetection[] =
|
|||||||
"googCpuOveruseDetection";
|
"googCpuOveruseDetection";
|
||||||
const char MediaConstraintsInterface::kPayloadPadding[] = "googPayloadPadding";
|
const char MediaConstraintsInterface::kPayloadPadding[] = "googPayloadPadding";
|
||||||
|
|
||||||
|
const char MediaConstraintsInterface::kNumSimulcastLayers[] =
|
||||||
|
"googNumSimulcastLayers";
|
||||||
|
|
||||||
// Set |value| to the value associated with the first appearance of |key|, or
|
// Set |value| to the value associated with the first appearance of |key|, or
|
||||||
// return false if |key| is not found.
|
// return false if |key| is not found.
|
||||||
bool MediaConstraintsInterface::Constraints::FindFirst(
|
bool MediaConstraintsInterface::Constraints::FindFirst(
|
||||||
@ -301,6 +304,13 @@ bool CopyConstraintsIntoOfferAnswerOptions(
|
|||||||
offer_answer_options->ice_restart = value;
|
offer_answer_options->ice_restart = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int layers;
|
||||||
|
if (FindConstraint(constraints,
|
||||||
|
MediaConstraintsInterface::kNumSimulcastLayers,
|
||||||
|
&layers, &mandatory_constraints_satisfied)) {
|
||||||
|
offer_answer_options->num_simulcast_layers = layers;
|
||||||
|
}
|
||||||
|
|
||||||
return mandatory_constraints_satisfied == constraints->GetMandatory().size();
|
return mandatory_constraints_satisfied == constraints->GetMandatory().size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,6 +119,11 @@ class MediaConstraintsInterface {
|
|||||||
// stripped by Chrome before passed down to Libjingle.
|
// stripped by Chrome before passed down to Libjingle.
|
||||||
static const char kInternalConstraintPrefix[];
|
static const char kInternalConstraintPrefix[];
|
||||||
|
|
||||||
|
// Specifies number of simulcast layers for all video tracks
|
||||||
|
// with a Plan B offer/answer
|
||||||
|
// (see RTCOfferAnswerOptions::num_simulcast_layers).
|
||||||
|
static const char kNumSimulcastLayers[];
|
||||||
|
|
||||||
virtual ~MediaConstraintsInterface() = default;
|
virtual ~MediaConstraintsInterface() = default;
|
||||||
|
|
||||||
virtual const Constraints& GetMandatory() const = 0;
|
virtual const Constraints& GetMandatory() const = 0;
|
||||||
|
@ -596,6 +596,9 @@ class PeerConnectionInterface : public rtc::RefCountInterface {
|
|||||||
// confused with RTCP mux (multiplexing RTP and RTCP together).
|
// confused with RTCP mux (multiplexing RTP and RTCP together).
|
||||||
bool use_rtp_mux = true;
|
bool use_rtp_mux = true;
|
||||||
|
|
||||||
|
// This will apply to all video tracks with a Plan B SDP offer/answer.
|
||||||
|
int num_simulcast_layers = 1;
|
||||||
|
|
||||||
RTCOfferAnswerOptions() = default;
|
RTCOfferAnswerOptions() = default;
|
||||||
|
|
||||||
RTCOfferAnswerOptions(int offer_to_receive_video,
|
RTCOfferAnswerOptions(int offer_to_receive_video,
|
||||||
|
@ -173,7 +173,8 @@ void AddRtpSenderOptions(
|
|||||||
const std::vector<rtc::scoped_refptr<
|
const std::vector<rtc::scoped_refptr<
|
||||||
RtpSenderProxyWithInternal<RtpSenderInternal>>>& senders,
|
RtpSenderProxyWithInternal<RtpSenderInternal>>>& senders,
|
||||||
cricket::MediaDescriptionOptions* audio_media_description_options,
|
cricket::MediaDescriptionOptions* audio_media_description_options,
|
||||||
cricket::MediaDescriptionOptions* video_media_description_options) {
|
cricket::MediaDescriptionOptions* video_media_description_options,
|
||||||
|
int num_sim_layers) {
|
||||||
for (const auto& sender : senders) {
|
for (const auto& sender : senders) {
|
||||||
if (sender->media_type() == cricket::MEDIA_TYPE_AUDIO) {
|
if (sender->media_type() == cricket::MEDIA_TYPE_AUDIO) {
|
||||||
if (audio_media_description_options) {
|
if (audio_media_description_options) {
|
||||||
@ -184,7 +185,8 @@ void AddRtpSenderOptions(
|
|||||||
RTC_DCHECK(sender->media_type() == cricket::MEDIA_TYPE_VIDEO);
|
RTC_DCHECK(sender->media_type() == cricket::MEDIA_TYPE_VIDEO);
|
||||||
if (video_media_description_options) {
|
if (video_media_description_options) {
|
||||||
video_media_description_options->AddVideoSender(
|
video_media_description_options->AddVideoSender(
|
||||||
sender->id(), sender->internal()->stream_ids(), 1);
|
sender->id(), sender->internal()->stream_ids(),
|
||||||
|
num_sim_layers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3686,7 +3688,8 @@ void PeerConnection::GetOptionsForPlanBOffer(
|
|||||||
: &session_options->media_description_options[*video_index];
|
: &session_options->media_description_options[*video_index];
|
||||||
|
|
||||||
AddRtpSenderOptions(GetSendersInternal(), audio_media_description_options,
|
AddRtpSenderOptions(GetSendersInternal(), audio_media_description_options,
|
||||||
video_media_description_options);
|
video_media_description_options,
|
||||||
|
offer_answer_options.num_simulcast_layers);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find a new MID that is not already in |used_mids|, then add it to |used_mids|
|
// Find a new MID that is not already in |used_mids|, then add it to |used_mids|
|
||||||
@ -3910,7 +3913,8 @@ void PeerConnection::GetOptionsForPlanBAnswer(
|
|||||||
: &session_options->media_description_options[*video_index];
|
: &session_options->media_description_options[*video_index];
|
||||||
|
|
||||||
AddRtpSenderOptions(GetSendersInternal(), audio_media_description_options,
|
AddRtpSenderOptions(GetSendersInternal(), audio_media_description_options,
|
||||||
video_media_description_options);
|
video_media_description_options,
|
||||||
|
offer_answer_options.num_simulcast_layers);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PeerConnection::GetOptionsForUnifiedPlanAnswer(
|
void PeerConnection::GetOptionsForUnifiedPlanAnswer(
|
||||||
|
@ -273,6 +273,56 @@ TEST_F(PeerConnectionMediaTestPlanB, EmptyRemoteOfferRemovesRecvStreams) {
|
|||||||
EXPECT_EQ(0u, callee_video->recv_streams().size());
|
EXPECT_EQ(0u, callee_video->recv_streams().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test enabling of simulcast with Plan B semantics.
|
||||||
|
// This test creating an offer.
|
||||||
|
TEST_F(PeerConnectionMediaTestPlanB, SimulcastOffer) {
|
||||||
|
auto caller = CreatePeerConnection();
|
||||||
|
auto caller_video_track = caller->AddVideoTrack("v");
|
||||||
|
RTCOfferAnswerOptions options;
|
||||||
|
options.num_simulcast_layers = 3;
|
||||||
|
auto offer = caller->CreateOffer(options);
|
||||||
|
auto* description = cricket::GetFirstMediaContent(
|
||||||
|
offer->description(),
|
||||||
|
cricket::MEDIA_TYPE_VIDEO)->media_description();
|
||||||
|
ASSERT_EQ(1u, description->streams().size());
|
||||||
|
ASSERT_TRUE(description->streams()[0].get_ssrc_group("SIM"));
|
||||||
|
EXPECT_EQ(3u, description->streams()[0].get_ssrc_group("SIM")->ssrcs.size());
|
||||||
|
|
||||||
|
// Check that it actually creates simulcast aswell.
|
||||||
|
caller->SetLocalDescription(std::move(offer));
|
||||||
|
auto senders = caller->pc()->GetSenders();
|
||||||
|
ASSERT_EQ(1u, senders.size());
|
||||||
|
EXPECT_EQ(cricket::MediaType::MEDIA_TYPE_VIDEO, senders[0]->media_type());
|
||||||
|
EXPECT_EQ(3u, senders[0]->GetParameters().encodings.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test enabling of simulcast with Plan B semantics.
|
||||||
|
// This test creating an answer.
|
||||||
|
TEST_F(PeerConnectionMediaTestPlanB, SimulcastAnswer) {
|
||||||
|
auto caller = CreatePeerConnection();
|
||||||
|
caller->AddVideoTrack("v0");
|
||||||
|
auto offer = caller->CreateOffer();
|
||||||
|
auto callee = CreatePeerConnection();
|
||||||
|
auto callee_video_track = callee->AddVideoTrack("v1");
|
||||||
|
ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
|
||||||
|
RTCOfferAnswerOptions options;
|
||||||
|
options.num_simulcast_layers = 3;
|
||||||
|
auto answer = callee->CreateAnswer(options);
|
||||||
|
auto* description = cricket::GetFirstMediaContent(
|
||||||
|
answer->description(),
|
||||||
|
cricket::MEDIA_TYPE_VIDEO)->media_description();
|
||||||
|
ASSERT_EQ(1u, description->streams().size());
|
||||||
|
ASSERT_TRUE(description->streams()[0].get_ssrc_group("SIM"));
|
||||||
|
EXPECT_EQ(3u, description->streams()[0].get_ssrc_group("SIM")->ssrcs.size());
|
||||||
|
|
||||||
|
// Check that it actually creates simulcast aswell.
|
||||||
|
callee->SetLocalDescription(std::move(answer));
|
||||||
|
auto senders = callee->pc()->GetSenders();
|
||||||
|
ASSERT_EQ(1u, senders.size());
|
||||||
|
EXPECT_EQ(cricket::MediaType::MEDIA_TYPE_VIDEO, senders[0]->media_type());
|
||||||
|
EXPECT_EQ(3u, senders[0]->GetParameters().encodings.size());
|
||||||
|
}
|
||||||
|
|
||||||
// Test that stopping the callee transceivers causes the media channels to be
|
// Test that stopping the callee transceivers causes the media channels to be
|
||||||
// destroyed on the callee after calling SetLocalDescription on the local
|
// destroyed on the callee after calling SetLocalDescription on the local
|
||||||
// answer.
|
// answer.
|
||||||
|
Reference in New Issue
Block a user