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:
Jonas Oreland
2018-08-24 10:58:37 +02:00
committed by Commit Bot
parent d65e143801
commit fc1acd2364
5 changed files with 76 additions and 4 deletions

View File

@ -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();
} }

View File

@ -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;

View File

@ -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,

View File

@ -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(

View File

@ -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.