1 /*
2 * Copyright 2004 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "pc/media_session.h"
12
13 #include <stddef.h>
14
15 #include <algorithm>
16 #include <cstdint>
17 #include <map>
18 #include <memory>
19 #include <string>
20 #include <tuple>
21 #include <vector>
22
23 #include "absl/algorithm/container.h"
24 #include "absl/strings/match.h"
25 #include "absl/strings/string_view.h"
26 #include "api/candidate.h"
27 #include "api/crypto_params.h"
28 #include "media/base/codec.h"
29 #include "media/base/media_constants.h"
30 #include "media/base/test_utils.h"
31 #include "media/sctp/sctp_transport_internal.h"
32 #include "p2p/base/p2p_constants.h"
33 #include "p2p/base/transport_description.h"
34 #include "p2p/base/transport_info.h"
35 #include "pc/media_protocol_names.h"
36 #include "pc/rtp_media_utils.h"
37 #include "rtc_base/arraysize.h"
38 #include "rtc_base/checks.h"
39 #include "rtc_base/fake_ssl_identity.h"
40 #include "rtc_base/rtc_certificate.h"
41 #include "rtc_base/ssl_identity.h"
42 #include "rtc_base/ssl_stream_adapter.h"
43 #include "rtc_base/string_encode.h"
44 #include "rtc_base/strings/string_builder.h"
45 #include "rtc_base/unique_id_generator.h"
46 #include "test/gmock.h"
47 #include "test/gtest.h"
48 #include "test/scoped_key_value_config.h"
49
50 #define ASSERT_CRYPTO(cd, s, cs) \
51 ASSERT_EQ(s, cd->cryptos().size()); \
52 ASSERT_EQ(cs, cd->cryptos()[0].cipher_suite)
53
54 typedef std::vector<cricket::Candidate> Candidates;
55
56 using cricket::AudioCodec;
57 using cricket::AudioContentDescription;
58 using cricket::ContentInfo;
59 using cricket::CryptoParamsVec;
60 using cricket::GetFirstAudioContent;
61 using cricket::GetFirstAudioContentDescription;
62 using cricket::GetFirstDataContent;
63 using cricket::GetFirstVideoContent;
64 using cricket::GetFirstVideoContentDescription;
65 using cricket::kAutoBandwidth;
66 using cricket::MEDIA_TYPE_AUDIO;
67 using cricket::MEDIA_TYPE_DATA;
68 using cricket::MEDIA_TYPE_VIDEO;
69 using cricket::MediaContentDescription;
70 using cricket::MediaDescriptionOptions;
71 using cricket::MediaProtocolType;
72 using cricket::MediaSessionDescriptionFactory;
73 using cricket::MediaSessionOptions;
74 using cricket::MediaType;
75 using cricket::RidDescription;
76 using cricket::RidDirection;
77 using cricket::SctpDataContentDescription;
78 using cricket::SEC_DISABLED;
79 using cricket::SEC_ENABLED;
80 using cricket::SEC_REQUIRED;
81 using cricket::SessionDescription;
82 using cricket::SimulcastDescription;
83 using cricket::SimulcastLayer;
84 using cricket::SimulcastLayerList;
85 using cricket::SsrcGroup;
86 using cricket::StreamParams;
87 using cricket::StreamParamsVec;
88 using cricket::TransportDescription;
89 using cricket::TransportDescriptionFactory;
90 using cricket::TransportInfo;
91 using cricket::VideoCodec;
92 using cricket::VideoContentDescription;
93 using rtc::kCsAeadAes128Gcm;
94 using rtc::kCsAeadAes256Gcm;
95 using rtc::kCsAesCm128HmacSha1_32;
96 using rtc::kCsAesCm128HmacSha1_80;
97 using rtc::UniqueRandomIdGenerator;
98 using ::testing::Contains;
99 using ::testing::Each;
100 using ::testing::ElementsAre;
101 using ::testing::ElementsAreArray;
102 using ::testing::Eq;
103 using ::testing::Field;
104 using ::testing::IsEmpty;
105 using ::testing::IsFalse;
106 using ::testing::Ne;
107 using ::testing::Not;
108 using ::testing::Pointwise;
109 using ::testing::SizeIs;
110 using webrtc::RtpExtension;
111 using webrtc::RtpTransceiverDirection;
112
113 static const AudioCodec kAudioCodecs1[] = {
114 AudioCodec(103, "ISAC", 16000, -1, 1),
115 AudioCodec(102, "iLBC", 8000, 13300, 1),
116 AudioCodec(0, "PCMU", 8000, 64000, 1),
117 AudioCodec(8, "PCMA", 8000, 64000, 1),
118 AudioCodec(117, "red", 8000, 0, 1),
119 AudioCodec(107, "CN", 48000, 0, 1)};
120
121 static const AudioCodec kAudioCodecs2[] = {
122 AudioCodec(126, "foo", 16000, 22000, 1),
123 AudioCodec(0, "PCMU", 8000, 64000, 1),
124 AudioCodec(127, "iLBC", 8000, 13300, 1),
125 };
126
127 static const AudioCodec kAudioCodecsAnswer[] = {
128 AudioCodec(102, "iLBC", 8000, 13300, 1),
129 AudioCodec(0, "PCMU", 8000, 64000, 1),
130 };
131
132 static const VideoCodec kVideoCodecs1[] = {VideoCodec(96, "H264-SVC"),
133 VideoCodec(97, "H264")};
134
135 static const VideoCodec kVideoCodecs1Reverse[] = {VideoCodec(97, "H264"),
136 VideoCodec(96, "H264-SVC")};
137
138 static const VideoCodec kVideoCodecs2[] = {VideoCodec(126, "H264"),
139 VideoCodec(127, "H263")};
140
141 static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")};
142
143 static const RtpExtension kAudioRtpExtension1[] = {
144 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
145 RtpExtension("http://google.com/testing/audio_something", 10),
146 };
147
148 static const RtpExtension kAudioRtpExtensionEncrypted1[] = {
149 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
150 RtpExtension("http://google.com/testing/audio_something", 10),
151 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
152 RtpExtension("http://google.com/testing/audio_something", 11, true),
153 };
154
155 static const RtpExtension kAudioRtpExtension2[] = {
156 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
157 RtpExtension("http://google.com/testing/audio_something_else", 8),
158 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
159 };
160
161 static const RtpExtension kAudioRtpExtension3[] = {
162 RtpExtension("http://google.com/testing/audio_something", 2),
163 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
164 };
165
166 static const RtpExtension kAudioRtpExtension3ForEncryption[] = {
167 RtpExtension("http://google.com/testing/audio_something", 2),
168 // Use RTP extension that supports encryption.
169 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
170 };
171
172 static const RtpExtension kAudioRtpExtension3ForEncryptionOffer[] = {
173 RtpExtension("http://google.com/testing/audio_something", 2),
174 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
175 RtpExtension("http://google.com/testing/audio_something", 14, true),
176 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 13, true),
177 };
178
179 static const RtpExtension kVideoRtpExtension3ForEncryptionOffer[] = {
180 RtpExtension("http://google.com/testing/video_something", 4),
181 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
182 RtpExtension("http://google.com/testing/video_something", 12, true),
183 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 13, true),
184 };
185
186 static const RtpExtension kAudioRtpExtensionAnswer[] = {
187 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
188 };
189
190 static const RtpExtension kAudioRtpExtensionEncryptedAnswer[] = {
191 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
192 };
193
194 static const RtpExtension kVideoRtpExtension1[] = {
195 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
196 RtpExtension("http://google.com/testing/video_something", 13),
197 };
198
199 static const RtpExtension kVideoRtpExtensionEncrypted1[] = {
200 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
201 RtpExtension("http://google.com/testing/video_something", 13),
202 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 9, true),
203 RtpExtension("http://google.com/testing/video_something", 7, true),
204 };
205
206 static const RtpExtension kVideoRtpExtension2[] = {
207 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
208 RtpExtension("http://google.com/testing/video_something_else", 14),
209 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
210 };
211
212 static const RtpExtension kVideoRtpExtension3[] = {
213 RtpExtension("http://google.com/testing/video_something", 4),
214 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
215 };
216
217 static const RtpExtension kVideoRtpExtension3ForEncryption[] = {
218 RtpExtension("http://google.com/testing/video_something", 4),
219 // Use RTP extension that supports encryption.
220 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 5),
221 };
222
223 static const RtpExtension kVideoRtpExtensionAnswer[] = {
224 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
225 };
226
227 static const RtpExtension kVideoRtpExtensionEncryptedAnswer[] = {
228 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 9, true),
229 };
230
231 static const RtpExtension kRtpExtensionTransportSequenceNumber01[] = {
232 RtpExtension("http://www.ietf.org/id/"
233 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
234 1),
235 };
236
237 static const RtpExtension kRtpExtensionTransportSequenceNumber01And02[] = {
238 RtpExtension("http://www.ietf.org/id/"
239 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
240 1),
241 RtpExtension(
242 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
243 2),
244 };
245
246 static const RtpExtension kRtpExtensionTransportSequenceNumber02[] = {
247 RtpExtension(
248 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
249 2),
250 };
251
252 static const RtpExtension kRtpExtensionGenericFrameDescriptorUri00[] = {
253 RtpExtension("http://www.webrtc.org/experiments/rtp-hdrext/"
254 "generic-frame-descriptor-00",
255 3),
256 };
257
258 static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
259 static const uint32_t kSimSsrc[] = {10, 20, 30};
260 static const uint32_t kFec1Ssrc[] = {10, 11};
261 static const uint32_t kFec2Ssrc[] = {20, 21};
262 static const uint32_t kFec3Ssrc[] = {30, 31};
263
264 static const char kMediaStream1[] = "stream_1";
265 static const char kMediaStream2[] = "stream_2";
266 static const char kVideoTrack1[] = "video_1";
267 static const char kVideoTrack2[] = "video_2";
268 static const char kAudioTrack1[] = "audio_1";
269 static const char kAudioTrack2[] = "audio_2";
270 static const char kAudioTrack3[] = "audio_3";
271
272 static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
273 "RTP/SAVPF"};
274 static const char* kMediaProtocolsDtls[] = {
275 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
276 "UDP/TLS/RTP/SAVP"};
277
278 // SRTP cipher name negotiated by the tests. This must be updated if the
279 // default changes.
280 static const char* kDefaultSrtpCryptoSuite = kCsAesCm128HmacSha1_80;
281 static const char* kDefaultSrtpCryptoSuiteGcm = kCsAeadAes256Gcm;
282
283 // These constants are used to make the code using "AddMediaDescriptionOptions"
284 // more readable.
285 static constexpr bool kStopped = true;
286 static constexpr bool kActive = false;
287
IsMediaContentOfType(const ContentInfo * content,MediaType media_type)288 static bool IsMediaContentOfType(const ContentInfo* content,
289 MediaType media_type) {
290 RTC_DCHECK(content);
291 return content->media_description()->type() == media_type;
292 }
293
GetMediaDirection(const ContentInfo * content)294 static RtpTransceiverDirection GetMediaDirection(const ContentInfo* content) {
295 RTC_DCHECK(content);
296 return content->media_description()->direction();
297 }
298
AddRtxCodec(const VideoCodec & rtx_codec,std::vector<VideoCodec> * codecs)299 static void AddRtxCodec(const VideoCodec& rtx_codec,
300 std::vector<VideoCodec>* codecs) {
301 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id));
302 codecs->push_back(rtx_codec);
303 }
304
305 template <class T>
GetCodecNames(const std::vector<T> & codecs)306 static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
307 std::vector<std::string> codec_names;
308 codec_names.reserve(codecs.size());
309 for (const auto& codec : codecs) {
310 codec_names.push_back(codec.name);
311 }
312 return codec_names;
313 }
314
315 // This is used for test only. MIDs are not the identification of the
316 // MediaDescriptionOptions since some end points may not support MID and the SDP
317 // may not contain 'mid'.
FindFirstMediaDescriptionByMid(const std::string & mid,MediaSessionOptions * opts)318 std::vector<MediaDescriptionOptions>::iterator FindFirstMediaDescriptionByMid(
319 const std::string& mid,
320 MediaSessionOptions* opts) {
321 return absl::c_find_if(
322 opts->media_description_options,
323 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
324 }
325
326 std::vector<MediaDescriptionOptions>::const_iterator
FindFirstMediaDescriptionByMid(const std::string & mid,const MediaSessionOptions & opts)327 FindFirstMediaDescriptionByMid(const std::string& mid,
328 const MediaSessionOptions& opts) {
329 return absl::c_find_if(
330 opts.media_description_options,
331 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
332 }
333
334 // Add a media section to the `session_options`.
AddMediaDescriptionOptions(MediaType type,const std::string & mid,RtpTransceiverDirection direction,bool stopped,MediaSessionOptions * opts)335 static void AddMediaDescriptionOptions(MediaType type,
336 const std::string& mid,
337 RtpTransceiverDirection direction,
338 bool stopped,
339 MediaSessionOptions* opts) {
340 opts->media_description_options.push_back(
341 MediaDescriptionOptions(type, mid, direction, stopped));
342 }
343
AddAudioVideoSections(RtpTransceiverDirection direction,MediaSessionOptions * opts)344 static void AddAudioVideoSections(RtpTransceiverDirection direction,
345 MediaSessionOptions* opts) {
346 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
347 opts);
348 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video", direction, kActive,
349 opts);
350 }
351
AddDataSection(RtpTransceiverDirection direction,MediaSessionOptions * opts)352 static void AddDataSection(RtpTransceiverDirection direction,
353 MediaSessionOptions* opts) {
354 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
355 }
356
AttachSenderToMediaDescriptionOptions(const std::string & mid,MediaType type,const std::string & track_id,const std::vector<std::string> & stream_ids,const std::vector<RidDescription> & rids,const SimulcastLayerList & simulcast_layers,int num_sim_layer,MediaSessionOptions * session_options)357 static void AttachSenderToMediaDescriptionOptions(
358 const std::string& mid,
359 MediaType type,
360 const std::string& track_id,
361 const std::vector<std::string>& stream_ids,
362 const std::vector<RidDescription>& rids,
363 const SimulcastLayerList& simulcast_layers,
364 int num_sim_layer,
365 MediaSessionOptions* session_options) {
366 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
367 switch (type) {
368 case MEDIA_TYPE_AUDIO:
369 it->AddAudioSender(track_id, stream_ids);
370 break;
371 case MEDIA_TYPE_VIDEO:
372 it->AddVideoSender(track_id, stream_ids, rids, simulcast_layers,
373 num_sim_layer);
374 break;
375 default:
376 RTC_DCHECK_NOTREACHED();
377 }
378 }
379
AttachSenderToMediaDescriptionOptions(const std::string & mid,MediaType type,const std::string & track_id,const std::vector<std::string> & stream_ids,int num_sim_layer,MediaSessionOptions * session_options)380 static void AttachSenderToMediaDescriptionOptions(
381 const std::string& mid,
382 MediaType type,
383 const std::string& track_id,
384 const std::vector<std::string>& stream_ids,
385 int num_sim_layer,
386 MediaSessionOptions* session_options) {
387 AttachSenderToMediaDescriptionOptions(mid, type, track_id, stream_ids, {},
388 SimulcastLayerList(), num_sim_layer,
389 session_options);
390 }
391
DetachSenderFromMediaSection(const std::string & mid,const std::string & track_id,MediaSessionOptions * session_options)392 static void DetachSenderFromMediaSection(const std::string& mid,
393 const std::string& track_id,
394 MediaSessionOptions* session_options) {
395 std::vector<cricket::SenderOptions>& sender_options_list =
396 FindFirstMediaDescriptionByMid(mid, session_options)->sender_options;
397 auto sender_it =
398 absl::c_find_if(sender_options_list,
399 [track_id](const cricket::SenderOptions& sender_options) {
400 return sender_options.track_id == track_id;
401 });
402 RTC_DCHECK(sender_it != sender_options_list.end());
403 sender_options_list.erase(sender_it);
404 }
405
406 // Helper function used to create a default MediaSessionOptions for Plan B SDP.
407 // (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
CreatePlanBMediaSessionOptions()408 static MediaSessionOptions CreatePlanBMediaSessionOptions() {
409 MediaSessionOptions session_options;
410 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
411 RtpTransceiverDirection::kRecvOnly, kActive,
412 &session_options);
413 return session_options;
414 }
415
416 // prefers GCM SDES crypto suites by removing non-GCM defaults.
PreferGcmCryptoParameters(CryptoParamsVec * cryptos)417 void PreferGcmCryptoParameters(CryptoParamsVec* cryptos) {
418 cryptos->erase(
419 std::remove_if(cryptos->begin(), cryptos->end(),
420 [](const cricket::CryptoParams& crypto) {
421 return crypto.cipher_suite != kCsAeadAes256Gcm &&
422 crypto.cipher_suite != kCsAeadAes128Gcm;
423 }),
424 cryptos->end());
425 }
426
427 // TODO(zhihuang): Most of these tests were written while MediaSessionOptions
428 // was designed for Plan B SDP, where only one audio "m=" section and one video
429 // "m=" section could be generated, and ordering couldn't be controlled. Many of
430 // these tests may be obsolete as a result, and should be refactored or removed.
431 class MediaSessionDescriptionFactoryTest : public ::testing::Test {
432 public:
MediaSessionDescriptionFactoryTest()433 MediaSessionDescriptionFactoryTest()
434 : tdf1_(field_trials),
435 tdf2_(field_trials),
436 f1_(&tdf1_, &ssrc_generator1),
437 f2_(&tdf2_, &ssrc_generator2) {
438 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
439 MAKE_VECTOR(kAudioCodecs1));
440 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1),
441 MAKE_VECTOR(kVideoCodecs1));
442 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
443 MAKE_VECTOR(kAudioCodecs2));
444 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2),
445 MAKE_VECTOR(kVideoCodecs2));
446 tdf1_.set_certificate(rtc::RTCCertificate::Create(
447 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
448 tdf2_.set_certificate(rtc::RTCCertificate::Create(
449 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
450 }
451
452 // Create a video StreamParamsVec object with:
453 // - one video stream with 3 simulcast streams and FEC,
CreateComplexVideoStreamParamsVec()454 StreamParamsVec CreateComplexVideoStreamParamsVec() {
455 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
456 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
457 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
458 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
459
460 std::vector<SsrcGroup> ssrc_groups;
461 ssrc_groups.push_back(sim_group);
462 ssrc_groups.push_back(fec_group1);
463 ssrc_groups.push_back(fec_group2);
464 ssrc_groups.push_back(fec_group3);
465
466 StreamParams simulcast_params;
467 simulcast_params.id = kVideoTrack1;
468 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
469 simulcast_params.ssrc_groups = ssrc_groups;
470 simulcast_params.cname = "Video_SIM_FEC";
471 simulcast_params.set_stream_ids({kMediaStream1});
472
473 StreamParamsVec video_streams;
474 video_streams.push_back(simulcast_params);
475
476 return video_streams;
477 }
478
CompareCryptoParams(const CryptoParamsVec & c1,const CryptoParamsVec & c2)479 bool CompareCryptoParams(const CryptoParamsVec& c1,
480 const CryptoParamsVec& c2) {
481 if (c1.size() != c2.size())
482 return false;
483 for (size_t i = 0; i < c1.size(); ++i)
484 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
485 c1[i].key_params != c2[i].key_params ||
486 c1[i].session_params != c2[i].session_params)
487 return false;
488 return true;
489 }
490
491 // Returns true if the transport info contains "renomination" as an
492 // ICE option.
GetIceRenomination(const TransportInfo * transport_info)493 bool GetIceRenomination(const TransportInfo* transport_info) {
494 return absl::c_linear_search(transport_info->description.transport_options,
495 "renomination");
496 }
497
TestTransportInfo(bool offer,const MediaSessionOptions & options,bool has_current_desc)498 void TestTransportInfo(bool offer,
499 const MediaSessionOptions& options,
500 bool has_current_desc) {
501 const std::string current_audio_ufrag = "current_audio_ufrag";
502 const std::string current_audio_pwd = "current_audio_pwd";
503 const std::string current_video_ufrag = "current_video_ufrag";
504 const std::string current_video_pwd = "current_video_pwd";
505 const std::string current_data_ufrag = "current_data_ufrag";
506 const std::string current_data_pwd = "current_data_pwd";
507 std::unique_ptr<SessionDescription> current_desc;
508 std::unique_ptr<SessionDescription> desc;
509 if (has_current_desc) {
510 current_desc = std::make_unique<SessionDescription>();
511 current_desc->AddTransportInfo(TransportInfo(
512 "audio",
513 TransportDescription(current_audio_ufrag, current_audio_pwd)));
514 current_desc->AddTransportInfo(TransportInfo(
515 "video",
516 TransportDescription(current_video_ufrag, current_video_pwd)));
517 current_desc->AddTransportInfo(TransportInfo(
518 "data", TransportDescription(current_data_ufrag, current_data_pwd)));
519 }
520 if (offer) {
521 desc = f1_.CreateOffer(options, current_desc.get());
522 } else {
523 std::unique_ptr<SessionDescription> offer;
524 offer = f1_.CreateOffer(options, NULL);
525 desc = f1_.CreateAnswer(offer.get(), options, current_desc.get());
526 }
527 ASSERT_TRUE(desc.get() != NULL);
528 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
529 if (options.has_audio()) {
530 EXPECT_TRUE(ti_audio != NULL);
531 if (has_current_desc) {
532 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
533 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
534 } else {
535 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
536 ti_audio->description.ice_ufrag.size());
537 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
538 ti_audio->description.ice_pwd.size());
539 }
540 auto media_desc_options_it =
541 FindFirstMediaDescriptionByMid("audio", options);
542 EXPECT_EQ(
543 media_desc_options_it->transport_options.enable_ice_renomination,
544 GetIceRenomination(ti_audio));
545 } else {
546 EXPECT_TRUE(ti_audio == NULL);
547 }
548 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
549 if (options.has_video()) {
550 EXPECT_TRUE(ti_video != NULL);
551 auto media_desc_options_it =
552 FindFirstMediaDescriptionByMid("video", options);
553 if (options.bundle_enabled) {
554 EXPECT_EQ(ti_audio->description.ice_ufrag,
555 ti_video->description.ice_ufrag);
556 EXPECT_EQ(ti_audio->description.ice_pwd, ti_video->description.ice_pwd);
557 } else {
558 if (has_current_desc) {
559 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
560 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
561 } else {
562 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
563 ti_video->description.ice_ufrag.size());
564 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
565 ti_video->description.ice_pwd.size());
566 }
567 }
568 EXPECT_EQ(
569 media_desc_options_it->transport_options.enable_ice_renomination,
570 GetIceRenomination(ti_video));
571 } else {
572 EXPECT_TRUE(ti_video == NULL);
573 }
574 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
575 if (options.has_data()) {
576 EXPECT_TRUE(ti_data != NULL);
577 if (options.bundle_enabled) {
578 EXPECT_EQ(ti_audio->description.ice_ufrag,
579 ti_data->description.ice_ufrag);
580 EXPECT_EQ(ti_audio->description.ice_pwd, ti_data->description.ice_pwd);
581 } else {
582 if (has_current_desc) {
583 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
584 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
585 } else {
586 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
587 ti_data->description.ice_ufrag.size());
588 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
589 ti_data->description.ice_pwd.size());
590 }
591 }
592 auto media_desc_options_it =
593 FindFirstMediaDescriptionByMid("data", options);
594 EXPECT_EQ(
595 media_desc_options_it->transport_options.enable_ice_renomination,
596 GetIceRenomination(ti_data));
597
598 } else {
599 EXPECT_TRUE(ti_data == NULL);
600 }
601 }
602
TestCryptoWithBundle(bool offer)603 void TestCryptoWithBundle(bool offer) {
604 f1_.set_secure(SEC_ENABLED);
605 MediaSessionOptions options;
606 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
607 std::unique_ptr<SessionDescription> ref_desc;
608 std::unique_ptr<SessionDescription> desc;
609 if (offer) {
610 options.bundle_enabled = false;
611 ref_desc = f1_.CreateOffer(options, NULL);
612 options.bundle_enabled = true;
613 desc = f1_.CreateOffer(options, ref_desc.get());
614 } else {
615 options.bundle_enabled = true;
616 ref_desc = f1_.CreateOffer(options, NULL);
617 desc = f1_.CreateAnswer(ref_desc.get(), options, NULL);
618 }
619 ASSERT_TRUE(desc);
620 const cricket::MediaContentDescription* audio_media_desc =
621 desc->GetContentDescriptionByName("audio");
622 ASSERT_TRUE(audio_media_desc);
623 const cricket::MediaContentDescription* video_media_desc =
624 desc->GetContentDescriptionByName("video");
625 ASSERT_TRUE(video_media_desc);
626 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
627 video_media_desc->cryptos()));
628 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
629 EXPECT_EQ(kDefaultSrtpCryptoSuite,
630 audio_media_desc->cryptos()[0].cipher_suite);
631
632 // Verify the selected crypto is one from the reference audio
633 // media content.
634 const cricket::MediaContentDescription* ref_audio_media_desc =
635 ref_desc->GetContentDescriptionByName("audio");
636 bool found = false;
637 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
638 if (ref_audio_media_desc->cryptos()[i].Matches(
639 audio_media_desc->cryptos()[0])) {
640 found = true;
641 break;
642 }
643 }
644 EXPECT_TRUE(found);
645 }
646
647 // This test that the audio and video media direction is set to
648 // `expected_direction_in_answer` in an answer if the offer direction is set
649 // to `direction_in_offer` and the answer is willing to both send and receive.
TestMediaDirectionInAnswer(RtpTransceiverDirection direction_in_offer,RtpTransceiverDirection expected_direction_in_answer)650 void TestMediaDirectionInAnswer(
651 RtpTransceiverDirection direction_in_offer,
652 RtpTransceiverDirection expected_direction_in_answer) {
653 MediaSessionOptions offer_opts;
654 AddAudioVideoSections(direction_in_offer, &offer_opts);
655
656 std::unique_ptr<SessionDescription> offer =
657 f1_.CreateOffer(offer_opts, NULL);
658 ASSERT_TRUE(offer.get() != NULL);
659 ContentInfo* ac_offer = offer->GetContentByName("audio");
660 ASSERT_TRUE(ac_offer != NULL);
661 ContentInfo* vc_offer = offer->GetContentByName("video");
662 ASSERT_TRUE(vc_offer != NULL);
663
664 MediaSessionOptions answer_opts;
665 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
666 std::unique_ptr<SessionDescription> answer =
667 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
668 const AudioContentDescription* acd_answer =
669 GetFirstAudioContentDescription(answer.get());
670 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
671 const VideoContentDescription* vcd_answer =
672 GetFirstVideoContentDescription(answer.get());
673 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
674 }
675
VerifyNoCNCodecs(const cricket::ContentInfo * content)676 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
677 RTC_DCHECK(content);
678 RTC_CHECK(content->media_description());
679 const cricket::AudioContentDescription* audio_desc =
680 content->media_description()->as_audio();
681 RTC_CHECK(audio_desc);
682 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
683 if (codec.name == "CN") {
684 return false;
685 }
686 }
687 return true;
688 }
689
TestVideoGcmCipher(bool gcm_offer,bool gcm_answer)690 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
691 MediaSessionOptions offer_opts;
692 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
693 offer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_offer;
694
695 MediaSessionOptions answer_opts;
696 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
697 answer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_answer;
698
699 f1_.set_secure(SEC_ENABLED);
700 f2_.set_secure(SEC_ENABLED);
701 std::unique_ptr<SessionDescription> offer =
702 f1_.CreateOffer(offer_opts, NULL);
703 ASSERT_TRUE(offer.get() != NULL);
704 if (gcm_offer && gcm_answer) {
705 for (cricket::ContentInfo& content : offer->contents()) {
706 auto cryptos = content.media_description()->cryptos();
707 PreferGcmCryptoParameters(&cryptos);
708 content.media_description()->set_cryptos(cryptos);
709 }
710 }
711 std::unique_ptr<SessionDescription> answer =
712 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
713 const ContentInfo* ac = answer->GetContentByName("audio");
714 const ContentInfo* vc = answer->GetContentByName("video");
715 ASSERT_TRUE(ac != NULL);
716 ASSERT_TRUE(vc != NULL);
717 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
718 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
719 const AudioContentDescription* acd = ac->media_description()->as_audio();
720 const VideoContentDescription* vcd = vc->media_description()->as_video();
721 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
722 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
723 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
724 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
725 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
726 if (gcm_offer && gcm_answer) {
727 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
728 } else {
729 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
730 }
731 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
732 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
733 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
734 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
735 if (gcm_offer && gcm_answer) {
736 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuiteGcm);
737 } else {
738 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
739 }
740 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
741 }
742
TestTransportSequenceNumberNegotiation(const cricket::RtpHeaderExtensions & local,const cricket::RtpHeaderExtensions & offered,const cricket::RtpHeaderExtensions & expectedAnswer)743 void TestTransportSequenceNumberNegotiation(
744 const cricket::RtpHeaderExtensions& local,
745 const cricket::RtpHeaderExtensions& offered,
746 const cricket::RtpHeaderExtensions& expectedAnswer) {
747 MediaSessionOptions opts;
748 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
749 SetAudioVideoRtpHeaderExtensions(offered, offered, &opts);
750 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
751 ASSERT_TRUE(offer.get() != NULL);
752 SetAudioVideoRtpHeaderExtensions(local, local, &opts);
753 std::unique_ptr<SessionDescription> answer =
754 f2_.CreateAnswer(offer.get(), opts, NULL);
755
756 EXPECT_EQ(
757 expectedAnswer,
758 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
759 EXPECT_EQ(
760 expectedAnswer,
761 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
762 }
763
764 std::vector<webrtc::RtpHeaderExtensionCapability>
HeaderExtensionCapabilitiesFromRtpExtensions(cricket::RtpHeaderExtensions extensions)765 HeaderExtensionCapabilitiesFromRtpExtensions(
766 cricket::RtpHeaderExtensions extensions) {
767 std::vector<webrtc::RtpHeaderExtensionCapability> capabilities;
768 for (const auto& extension : extensions) {
769 webrtc::RtpHeaderExtensionCapability capability(
770 extension.uri, extension.id,
771 webrtc::RtpTransceiverDirection::kSendRecv);
772 capabilities.push_back(capability);
773 }
774 return capabilities;
775 }
776
SetAudioVideoRtpHeaderExtensions(cricket::RtpHeaderExtensions audio_exts,cricket::RtpHeaderExtensions video_exts,MediaSessionOptions * opts)777 void SetAudioVideoRtpHeaderExtensions(cricket::RtpHeaderExtensions audio_exts,
778 cricket::RtpHeaderExtensions video_exts,
779 MediaSessionOptions* opts) {
780 auto audio_caps = HeaderExtensionCapabilitiesFromRtpExtensions(audio_exts);
781 auto video_caps = HeaderExtensionCapabilitiesFromRtpExtensions(video_exts);
782 for (auto& entry : opts->media_description_options) {
783 switch (entry.type) {
784 case MEDIA_TYPE_AUDIO:
785 entry.header_extensions = audio_caps;
786 break;
787 case MEDIA_TYPE_VIDEO:
788 entry.header_extensions = video_caps;
789 break;
790 default:
791 break;
792 }
793 }
794 }
795
796 protected:
797 webrtc::test::ScopedKeyValueConfig field_trials;
798 UniqueRandomIdGenerator ssrc_generator1;
799 UniqueRandomIdGenerator ssrc_generator2;
800 TransportDescriptionFactory tdf1_;
801 TransportDescriptionFactory tdf2_;
802 MediaSessionDescriptionFactory f1_;
803 MediaSessionDescriptionFactory f2_;
804 };
805
806 // Create a typical audio offer, and ensure it matches what we expect.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateAudioOffer)807 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
808 f1_.set_secure(SEC_ENABLED);
809 std::unique_ptr<SessionDescription> offer =
810 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
811 ASSERT_TRUE(offer.get() != NULL);
812 const ContentInfo* ac = offer->GetContentByName("audio");
813 const ContentInfo* vc = offer->GetContentByName("video");
814 ASSERT_TRUE(ac != NULL);
815 ASSERT_TRUE(vc == NULL);
816 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
817 const AudioContentDescription* acd = ac->media_description()->as_audio();
818 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
819 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
820 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
821 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
822 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
823 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
824 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
825 }
826
827 // Create a typical video offer, and ensure it matches what we expect.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateVideoOffer)828 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
829 MediaSessionOptions opts;
830 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
831 f1_.set_secure(SEC_ENABLED);
832 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
833 ASSERT_TRUE(offer.get() != NULL);
834 const ContentInfo* ac = offer->GetContentByName("audio");
835 const ContentInfo* vc = offer->GetContentByName("video");
836 ASSERT_TRUE(ac != NULL);
837 ASSERT_TRUE(vc != NULL);
838 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
839 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
840 const AudioContentDescription* acd = ac->media_description()->as_audio();
841 const VideoContentDescription* vcd = vc->media_description()->as_video();
842 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
843 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
844 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
845 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
846 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
847 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
848 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
849 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
850 EXPECT_EQ(f1_.video_sendrecv_codecs(), vcd->codecs());
851 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
852 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
853 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
854 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
855 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
856 }
857
858 // Test creating an offer with bundle where the Codecs have the same dynamic
859 // RTP playlod type. The test verifies that the offer don't contain the
860 // duplicate RTP payload types.
TEST_F(MediaSessionDescriptionFactoryTest,TestBundleOfferWithSameCodecPlType)861 TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
862 const VideoCodec& offered_video_codec = f2_.video_sendrecv_codecs()[0];
863 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
864 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
865
866 MediaSessionOptions opts;
867 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
868 opts.bundle_enabled = true;
869 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, NULL);
870 const VideoContentDescription* vcd =
871 GetFirstVideoContentDescription(offer.get());
872 const AudioContentDescription* acd =
873 GetFirstAudioContentDescription(offer.get());
874 ASSERT_TRUE(NULL != vcd);
875 ASSERT_TRUE(NULL != acd);
876 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
877 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
878 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
879 }
880
881 // Test creating an updated offer with bundle, audio, video and data
882 // after an audio only session has been negotiated.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateUpdatedVideoOfferWithBundle)883 TEST_F(MediaSessionDescriptionFactoryTest,
884 TestCreateUpdatedVideoOfferWithBundle) {
885 f1_.set_secure(SEC_ENABLED);
886 f2_.set_secure(SEC_ENABLED);
887 MediaSessionOptions opts;
888 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
889 RtpTransceiverDirection::kRecvOnly, kActive,
890 &opts);
891 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
892 RtpTransceiverDirection::kInactive, kStopped,
893 &opts);
894 opts.bundle_enabled = true;
895 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
896 std::unique_ptr<SessionDescription> answer =
897 f2_.CreateAnswer(offer.get(), opts, NULL);
898
899 MediaSessionOptions updated_opts;
900 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
901 updated_opts.bundle_enabled = true;
902 std::unique_ptr<SessionDescription> updated_offer(
903 f1_.CreateOffer(updated_opts, answer.get()));
904
905 const AudioContentDescription* acd =
906 GetFirstAudioContentDescription(updated_offer.get());
907 const VideoContentDescription* vcd =
908 GetFirstVideoContentDescription(updated_offer.get());
909 EXPECT_TRUE(NULL != vcd);
910 EXPECT_TRUE(NULL != acd);
911
912 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
913 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
914 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
915 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
916 }
917
918 // Create an SCTP data offer with bundle without error.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateSctpDataOffer)919 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
920 MediaSessionOptions opts;
921 opts.bundle_enabled = true;
922 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
923 f1_.set_secure(SEC_ENABLED);
924 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
925 EXPECT_TRUE(offer.get() != NULL);
926 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
927 auto dcd = GetFirstSctpDataContentDescription(offer.get());
928 ASSERT_TRUE(dcd);
929 // Since this transport is insecure, the protocol should be "SCTP".
930 EXPECT_EQ(cricket::kMediaProtocolSctp, dcd->protocol());
931 }
932
933 // Create an SCTP data offer with bundle without error.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateSecureSctpDataOffer)934 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSecureSctpDataOffer) {
935 MediaSessionOptions opts;
936 opts.bundle_enabled = true;
937 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
938 f1_.set_secure(SEC_ENABLED);
939 tdf1_.set_secure(SEC_ENABLED);
940 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
941 EXPECT_TRUE(offer.get() != NULL);
942 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
943 auto dcd = GetFirstSctpDataContentDescription(offer.get());
944 ASSERT_TRUE(dcd);
945 // The protocol should now be "UDP/DTLS/SCTP"
946 EXPECT_EQ(cricket::kMediaProtocolUdpDtlsSctp, dcd->protocol());
947 }
948
949 // Test creating an sctp data channel from an already generated offer.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateImplicitSctpDataOffer)950 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
951 MediaSessionOptions opts;
952 opts.bundle_enabled = true;
953 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
954 f1_.set_secure(SEC_ENABLED);
955 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
956 ASSERT_TRUE(offer1.get() != NULL);
957 const ContentInfo* data = offer1->GetContentByName("data");
958 ASSERT_TRUE(data != NULL);
959 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
960
961 std::unique_ptr<SessionDescription> offer2(
962 f1_.CreateOffer(opts, offer1.get()));
963 data = offer2->GetContentByName("data");
964 ASSERT_TRUE(data != NULL);
965 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
966 }
967
968 // Test that if BUNDLE is enabled and all media sections are rejected then the
969 // BUNDLE group is not present in the re-offer.
TEST_F(MediaSessionDescriptionFactoryTest,ReOfferNoBundleGroupIfAllRejected)970 TEST_F(MediaSessionDescriptionFactoryTest, ReOfferNoBundleGroupIfAllRejected) {
971 MediaSessionOptions opts;
972 opts.bundle_enabled = true;
973 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
974 RtpTransceiverDirection::kSendRecv, kActive,
975 &opts);
976 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
977
978 opts.media_description_options[0].stopped = true;
979 std::unique_ptr<SessionDescription> reoffer =
980 f1_.CreateOffer(opts, offer.get());
981
982 EXPECT_FALSE(reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
983 }
984
985 // Test that if BUNDLE is enabled and the remote re-offer does not include a
986 // BUNDLE group since all media sections are rejected, then the re-answer also
987 // does not include a BUNDLE group.
TEST_F(MediaSessionDescriptionFactoryTest,ReAnswerNoBundleGroupIfAllRejected)988 TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerNoBundleGroupIfAllRejected) {
989 MediaSessionOptions opts;
990 opts.bundle_enabled = true;
991 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
992 RtpTransceiverDirection::kSendRecv, kActive,
993 &opts);
994 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
995 std::unique_ptr<SessionDescription> answer =
996 f2_.CreateAnswer(offer.get(), opts, nullptr);
997
998 opts.media_description_options[0].stopped = true;
999 std::unique_ptr<SessionDescription> reoffer =
1000 f1_.CreateOffer(opts, offer.get());
1001 std::unique_ptr<SessionDescription> reanswer =
1002 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1003
1004 EXPECT_FALSE(reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
1005 }
1006
1007 // Test that if BUNDLE is enabled and the previous offerer-tagged media section
1008 // was rejected then the new offerer-tagged media section is the non-rejected
1009 // media section.
TEST_F(MediaSessionDescriptionFactoryTest,ReOfferChangeBundleOffererTagged)1010 TEST_F(MediaSessionDescriptionFactoryTest, ReOfferChangeBundleOffererTagged) {
1011 MediaSessionOptions opts;
1012 opts.bundle_enabled = true;
1013 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1014 RtpTransceiverDirection::kSendRecv, kActive,
1015 &opts);
1016 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1017
1018 // Reject the audio m= section and add a video m= section.
1019 opts.media_description_options[0].stopped = true;
1020 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1021 RtpTransceiverDirection::kSendRecv, kActive,
1022 &opts);
1023 std::unique_ptr<SessionDescription> reoffer =
1024 f1_.CreateOffer(opts, offer.get());
1025
1026 const cricket::ContentGroup* bundle_group =
1027 reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1028 ASSERT_TRUE(bundle_group);
1029 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1030 EXPECT_TRUE(bundle_group->HasContentName("video"));
1031 }
1032
1033 // Test that if BUNDLE is enabled and the previous offerer-tagged media section
1034 // was rejected and a new media section is added, then the re-answer BUNDLE
1035 // group will contain only the non-rejected media section.
TEST_F(MediaSessionDescriptionFactoryTest,ReAnswerChangedBundleOffererTagged)1036 TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerChangedBundleOffererTagged) {
1037 MediaSessionOptions opts;
1038 opts.bundle_enabled = true;
1039 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1040 RtpTransceiverDirection::kSendRecv, kActive,
1041 &opts);
1042 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1043 std::unique_ptr<SessionDescription> answer =
1044 f2_.CreateAnswer(offer.get(), opts, nullptr);
1045
1046 // Reject the audio m= section and add a video m= section.
1047 opts.media_description_options[0].stopped = true;
1048 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1049 RtpTransceiverDirection::kSendRecv, kActive,
1050 &opts);
1051 std::unique_ptr<SessionDescription> reoffer =
1052 f1_.CreateOffer(opts, offer.get());
1053 std::unique_ptr<SessionDescription> reanswer =
1054 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1055
1056 const cricket::ContentGroup* bundle_group =
1057 reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1058 ASSERT_TRUE(bundle_group);
1059 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1060 EXPECT_TRUE(bundle_group->HasContentName("video"));
1061 }
1062
TEST_F(MediaSessionDescriptionFactoryTest,CreateAnswerForOfferWithMultipleBundleGroups)1063 TEST_F(MediaSessionDescriptionFactoryTest,
1064 CreateAnswerForOfferWithMultipleBundleGroups) {
1065 // Create an offer with 4 m= sections, initially without BUNDLE groups.
1066 MediaSessionOptions opts;
1067 opts.bundle_enabled = false;
1068 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "1",
1069 RtpTransceiverDirection::kSendRecv, kActive,
1070 &opts);
1071 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "2",
1072 RtpTransceiverDirection::kSendRecv, kActive,
1073 &opts);
1074 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "3",
1075 RtpTransceiverDirection::kSendRecv, kActive,
1076 &opts);
1077 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "4",
1078 RtpTransceiverDirection::kSendRecv, kActive,
1079 &opts);
1080 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1081 ASSERT_TRUE(offer->groups().empty());
1082
1083 // Munge the offer to have two groups. Offers like these cannot be generated
1084 // without munging, but it is valid to receive such offers from remote
1085 // endpoints.
1086 cricket::ContentGroup bundle_group1(cricket::GROUP_TYPE_BUNDLE);
1087 bundle_group1.AddContentName("1");
1088 bundle_group1.AddContentName("2");
1089 cricket::ContentGroup bundle_group2(cricket::GROUP_TYPE_BUNDLE);
1090 bundle_group2.AddContentName("3");
1091 bundle_group2.AddContentName("4");
1092 offer->AddGroup(bundle_group1);
1093 offer->AddGroup(bundle_group2);
1094
1095 // If BUNDLE is enabled, the answer to this offer should accept both BUNDLE
1096 // groups.
1097 opts.bundle_enabled = true;
1098 std::unique_ptr<SessionDescription> answer =
1099 f2_.CreateAnswer(offer.get(), opts, nullptr);
1100
1101 std::vector<const cricket::ContentGroup*> answer_groups =
1102 answer->GetGroupsByName(cricket::GROUP_TYPE_BUNDLE);
1103 ASSERT_EQ(answer_groups.size(), 2u);
1104 EXPECT_EQ(answer_groups[0]->content_names().size(), 2u);
1105 EXPECT_TRUE(answer_groups[0]->HasContentName("1"));
1106 EXPECT_TRUE(answer_groups[0]->HasContentName("2"));
1107 EXPECT_EQ(answer_groups[1]->content_names().size(), 2u);
1108 EXPECT_TRUE(answer_groups[1]->HasContentName("3"));
1109 EXPECT_TRUE(answer_groups[1]->HasContentName("4"));
1110
1111 // If BUNDLE is disabled, the answer to this offer should reject both BUNDLE
1112 // groups.
1113 opts.bundle_enabled = false;
1114 answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
1115
1116 answer_groups = answer->GetGroupsByName(cricket::GROUP_TYPE_BUNDLE);
1117 // Rejected groups are still listed, but they are empty.
1118 ASSERT_EQ(answer_groups.size(), 2u);
1119 EXPECT_TRUE(answer_groups[0]->content_names().empty());
1120 EXPECT_TRUE(answer_groups[1]->content_names().empty());
1121 }
1122
1123 // Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1124 // and there is still a non-rejected media section that was in the initial
1125 // offer, then the ICE credentials do not change in the reoffer offerer-tagged
1126 // media section.
TEST_F(MediaSessionDescriptionFactoryTest,ReOfferChangeBundleOffererTaggedKeepsIceCredentials)1127 TEST_F(MediaSessionDescriptionFactoryTest,
1128 ReOfferChangeBundleOffererTaggedKeepsIceCredentials) {
1129 MediaSessionOptions opts;
1130 opts.bundle_enabled = true;
1131 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1132 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1133 std::unique_ptr<SessionDescription> answer =
1134 f2_.CreateAnswer(offer.get(), opts, nullptr);
1135
1136 // Reject the audio m= section.
1137 opts.media_description_options[0].stopped = true;
1138 std::unique_ptr<SessionDescription> reoffer =
1139 f1_.CreateOffer(opts, offer.get());
1140
1141 const TransportDescription* offer_tagged =
1142 offer->GetTransportDescriptionByName("audio");
1143 ASSERT_TRUE(offer_tagged);
1144 const TransportDescription* reoffer_tagged =
1145 reoffer->GetTransportDescriptionByName("video");
1146 ASSERT_TRUE(reoffer_tagged);
1147 EXPECT_EQ(offer_tagged->ice_ufrag, reoffer_tagged->ice_ufrag);
1148 EXPECT_EQ(offer_tagged->ice_pwd, reoffer_tagged->ice_pwd);
1149 }
1150
1151 // Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1152 // and there is still a non-rejected media section that was in the initial
1153 // offer, then the ICE credentials do not change in the reanswer answerer-tagged
1154 // media section.
TEST_F(MediaSessionDescriptionFactoryTest,ReAnswerChangeBundleOffererTaggedKeepsIceCredentials)1155 TEST_F(MediaSessionDescriptionFactoryTest,
1156 ReAnswerChangeBundleOffererTaggedKeepsIceCredentials) {
1157 MediaSessionOptions opts;
1158 opts.bundle_enabled = true;
1159 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1160 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1161 std::unique_ptr<SessionDescription> answer =
1162 f2_.CreateAnswer(offer.get(), opts, nullptr);
1163
1164 // Reject the audio m= section.
1165 opts.media_description_options[0].stopped = true;
1166 std::unique_ptr<SessionDescription> reoffer =
1167 f1_.CreateOffer(opts, offer.get());
1168 std::unique_ptr<SessionDescription> reanswer =
1169 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1170
1171 const TransportDescription* answer_tagged =
1172 answer->GetTransportDescriptionByName("audio");
1173 ASSERT_TRUE(answer_tagged);
1174 const TransportDescription* reanswer_tagged =
1175 reanswer->GetTransportDescriptionByName("video");
1176 ASSERT_TRUE(reanswer_tagged);
1177 EXPECT_EQ(answer_tagged->ice_ufrag, reanswer_tagged->ice_ufrag);
1178 EXPECT_EQ(answer_tagged->ice_pwd, reanswer_tagged->ice_pwd);
1179 }
1180
1181 // Create an audio, video offer without legacy StreamParams.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateOfferWithoutLegacyStreams)1182 TEST_F(MediaSessionDescriptionFactoryTest,
1183 TestCreateOfferWithoutLegacyStreams) {
1184 MediaSessionOptions opts;
1185 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1186 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
1187 ASSERT_TRUE(offer.get() != NULL);
1188 const ContentInfo* ac = offer->GetContentByName("audio");
1189 const ContentInfo* vc = offer->GetContentByName("video");
1190 ASSERT_TRUE(ac != NULL);
1191 ASSERT_TRUE(vc != NULL);
1192 const AudioContentDescription* acd = ac->media_description()->as_audio();
1193 const VideoContentDescription* vcd = vc->media_description()->as_video();
1194
1195 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1196 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1197 }
1198
1199 // Creates an audio+video sendonly offer.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateSendOnlyOffer)1200 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
1201 MediaSessionOptions opts;
1202 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
1203 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1204 {kMediaStream1}, 1, &opts);
1205 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1206 {kMediaStream1}, 1, &opts);
1207
1208 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
1209 ASSERT_TRUE(offer.get() != NULL);
1210 EXPECT_EQ(2u, offer->contents().size());
1211 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
1212 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
1213
1214 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1215 GetMediaDirection(&offer->contents()[0]));
1216 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1217 GetMediaDirection(&offer->contents()[1]));
1218 }
1219
1220 // Verifies that the order of the media contents in the current
1221 // SessionDescription is preserved in the new SessionDescription.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateOfferContentOrder)1222 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
1223 MediaSessionOptions opts;
1224 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
1225
1226 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
1227 ASSERT_TRUE(offer1.get() != NULL);
1228 EXPECT_EQ(1u, offer1->contents().size());
1229 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
1230
1231 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1232 RtpTransceiverDirection::kRecvOnly, kActive,
1233 &opts);
1234 std::unique_ptr<SessionDescription> offer2(
1235 f1_.CreateOffer(opts, offer1.get()));
1236 ASSERT_TRUE(offer2.get() != NULL);
1237 EXPECT_EQ(2u, offer2->contents().size());
1238 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
1239 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
1240
1241 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1242 RtpTransceiverDirection::kRecvOnly, kActive,
1243 &opts);
1244 std::unique_ptr<SessionDescription> offer3(
1245 f1_.CreateOffer(opts, offer2.get()));
1246 ASSERT_TRUE(offer3.get() != NULL);
1247 EXPECT_EQ(3u, offer3->contents().size());
1248 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
1249 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
1250 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
1251 }
1252
1253 // Create a typical audio answer, and ensure it matches what we expect.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateAudioAnswer)1254 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
1255 f1_.set_secure(SEC_ENABLED);
1256 f2_.set_secure(SEC_ENABLED);
1257 std::unique_ptr<SessionDescription> offer =
1258 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
1259 ASSERT_TRUE(offer.get() != NULL);
1260 std::unique_ptr<SessionDescription> answer =
1261 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
1262 const ContentInfo* ac = answer->GetContentByName("audio");
1263 const ContentInfo* vc = answer->GetContentByName("video");
1264 ASSERT_TRUE(ac != NULL);
1265 ASSERT_TRUE(vc == NULL);
1266 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1267 const AudioContentDescription* acd = ac->media_description()->as_audio();
1268 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1269 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
1270 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
1271 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1272 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
1273 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
1274 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
1275 }
1276
1277 // Create a typical audio answer with GCM ciphers enabled, and ensure it
1278 // matches what we expect.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateAudioAnswerGcm)1279 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
1280 f1_.set_secure(SEC_ENABLED);
1281 f2_.set_secure(SEC_ENABLED);
1282 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
1283 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
1284 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
1285 ASSERT_TRUE(offer.get() != NULL);
1286 for (cricket::ContentInfo& content : offer->contents()) {
1287 auto cryptos = content.media_description()->cryptos();
1288 PreferGcmCryptoParameters(&cryptos);
1289 content.media_description()->set_cryptos(cryptos);
1290 }
1291 std::unique_ptr<SessionDescription> answer =
1292 f2_.CreateAnswer(offer.get(), opts, NULL);
1293 const ContentInfo* ac = answer->GetContentByName("audio");
1294 const ContentInfo* vc = answer->GetContentByName("video");
1295 ASSERT_TRUE(ac != NULL);
1296 ASSERT_TRUE(vc == NULL);
1297 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1298 const AudioContentDescription* acd = ac->media_description()->as_audio();
1299 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1300 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
1301 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
1302 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1303 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
1304 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
1305 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
1306 }
1307
1308 // Create an audio answer with no common codecs, and ensure it is rejected.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateAudioAnswerWithNoCommonCodecs)1309 TEST_F(MediaSessionDescriptionFactoryTest,
1310 TestCreateAudioAnswerWithNoCommonCodecs) {
1311 MediaSessionOptions opts;
1312 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1313 RtpTransceiverDirection::kSendRecv, kActive,
1314 &opts);
1315 std::vector f1_codecs = {AudioCodec(96, "opus", 48000, -1, 1)};
1316 f1_.set_audio_codecs(f1_codecs, f1_codecs);
1317
1318 std::vector f2_codecs = {AudioCodec(0, "PCMU", 8000, -1, 1)};
1319 f2_.set_audio_codecs(f2_codecs, f2_codecs);
1320
1321 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1322 std::unique_ptr<SessionDescription> answer =
1323 f2_.CreateAnswer(offer.get(), opts, NULL);
1324 const ContentInfo* ac = answer->GetContentByName("audio");
1325 ASSERT_TRUE(ac != NULL);
1326 EXPECT_TRUE(ac->rejected);
1327 }
1328
1329 // Create a typical video answer, and ensure it matches what we expect.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateVideoAnswer)1330 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
1331 MediaSessionOptions opts;
1332 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1333 f1_.set_secure(SEC_ENABLED);
1334 f2_.set_secure(SEC_ENABLED);
1335 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
1336 ASSERT_TRUE(offer.get() != NULL);
1337 std::unique_ptr<SessionDescription> answer =
1338 f2_.CreateAnswer(offer.get(), opts, NULL);
1339 const ContentInfo* ac = answer->GetContentByName("audio");
1340 const ContentInfo* vc = answer->GetContentByName("video");
1341 ASSERT_TRUE(ac != NULL);
1342 ASSERT_TRUE(vc != NULL);
1343 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1344 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
1345 const AudioContentDescription* acd = ac->media_description()->as_audio();
1346 const VideoContentDescription* vcd = vc->media_description()->as_video();
1347 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1348 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
1349 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1350 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
1351 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
1352 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
1353 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1354 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
1355 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
1356 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
1357 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
1358 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
1359 }
1360
1361 // Create a typical video answer with GCM ciphers enabled, and ensure it
1362 // matches what we expect.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateVideoAnswerGcm)1363 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1364 TestVideoGcmCipher(true, true);
1365 }
1366
1367 // Create a typical video answer with GCM ciphers enabled for the offer only,
1368 // and ensure it matches what we expect.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateVideoAnswerGcmOffer)1369 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1370 TestVideoGcmCipher(true, false);
1371 }
1372
1373 // Create a typical video answer with GCM ciphers enabled for the answer only,
1374 // and ensure it matches what we expect.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateVideoAnswerGcmAnswer)1375 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1376 TestVideoGcmCipher(false, true);
1377 }
1378
1379 // Create a video answer with no common codecs, and ensure it is rejected.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateVideoAnswerWithNoCommonCodecs)1380 TEST_F(MediaSessionDescriptionFactoryTest,
1381 TestCreateVideoAnswerWithNoCommonCodecs) {
1382 MediaSessionOptions opts;
1383 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1384 RtpTransceiverDirection::kSendRecv, kActive,
1385 &opts);
1386 std::vector f1_codecs = {VideoCodec(96, "H264")};
1387 f1_.set_video_codecs(f1_codecs, f1_codecs);
1388
1389 std::vector f2_codecs = {VideoCodec(97, "VP8")};
1390 f2_.set_video_codecs(f2_codecs, f2_codecs);
1391
1392 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1393 std::unique_ptr<SessionDescription> answer =
1394 f2_.CreateAnswer(offer.get(), opts, NULL);
1395 const ContentInfo* vc = answer->GetContentByName("video");
1396 ASSERT_TRUE(vc != NULL);
1397 EXPECT_TRUE(vc->rejected);
1398 }
1399
1400 // Create a video answer with no common codecs (but a common FEC codec), and
1401 // ensure it is rejected.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateVideoAnswerWithOnlyFecCodecsCommon)1402 TEST_F(MediaSessionDescriptionFactoryTest,
1403 TestCreateVideoAnswerWithOnlyFecCodecsCommon) {
1404 MediaSessionOptions opts;
1405 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1406 RtpTransceiverDirection::kSendRecv, kActive,
1407 &opts);
1408 std::vector f1_codecs = {VideoCodec(96, "H264"),
1409 VideoCodec(118, "flexfec-03")};
1410 f1_.set_video_codecs(f1_codecs, f1_codecs);
1411
1412 std::vector f2_codecs = {VideoCodec(97, "VP8"),
1413 VideoCodec(118, "flexfec-03")};
1414 f2_.set_video_codecs(f2_codecs, f2_codecs);
1415
1416 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1417 std::unique_ptr<SessionDescription> answer =
1418 f2_.CreateAnswer(offer.get(), opts, NULL);
1419 const ContentInfo* vc = answer->GetContentByName("video");
1420 ASSERT_TRUE(vc != NULL);
1421 EXPECT_TRUE(vc->rejected);
1422 }
1423
1424 // The use_sctpmap flag should be set in an Sctp DataContentDescription by
1425 // default. The answer's use_sctpmap flag should match the offer's.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateDataAnswerUsesSctpmap)1426 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1427 MediaSessionOptions opts;
1428 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
1429 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
1430 ASSERT_TRUE(offer.get() != NULL);
1431 ContentInfo* dc_offer = offer->GetContentByName("data");
1432 ASSERT_TRUE(dc_offer != NULL);
1433 SctpDataContentDescription* dcd_offer =
1434 dc_offer->media_description()->as_sctp();
1435 EXPECT_TRUE(dcd_offer->use_sctpmap());
1436
1437 std::unique_ptr<SessionDescription> answer =
1438 f2_.CreateAnswer(offer.get(), opts, NULL);
1439 const ContentInfo* dc_answer = answer->GetContentByName("data");
1440 ASSERT_TRUE(dc_answer != NULL);
1441 const SctpDataContentDescription* dcd_answer =
1442 dc_answer->media_description()->as_sctp();
1443 EXPECT_TRUE(dcd_answer->use_sctpmap());
1444 }
1445
1446 // The answer's use_sctpmap flag should match the offer's.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateDataAnswerWithoutSctpmap)1447 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1448 MediaSessionOptions opts;
1449 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
1450 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
1451 ASSERT_TRUE(offer.get() != NULL);
1452 ContentInfo* dc_offer = offer->GetContentByName("data");
1453 ASSERT_TRUE(dc_offer != NULL);
1454 SctpDataContentDescription* dcd_offer =
1455 dc_offer->media_description()->as_sctp();
1456 dcd_offer->set_use_sctpmap(false);
1457
1458 std::unique_ptr<SessionDescription> answer =
1459 f2_.CreateAnswer(offer.get(), opts, NULL);
1460 const ContentInfo* dc_answer = answer->GetContentByName("data");
1461 ASSERT_TRUE(dc_answer != NULL);
1462 const SctpDataContentDescription* dcd_answer =
1463 dc_answer->media_description()->as_sctp();
1464 EXPECT_FALSE(dcd_answer->use_sctpmap());
1465 }
1466
1467 // Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1468 // and "TCP/DTLS/SCTP" offers.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateDataAnswerToDifferentOfferedProtos)1469 TEST_F(MediaSessionDescriptionFactoryTest,
1470 TestCreateDataAnswerToDifferentOfferedProtos) {
1471 // Need to enable DTLS offer/answer generation (disabled by default in this
1472 // test).
1473 f1_.set_secure(SEC_ENABLED);
1474 f2_.set_secure(SEC_ENABLED);
1475 tdf1_.set_secure(SEC_ENABLED);
1476 tdf2_.set_secure(SEC_ENABLED);
1477
1478 MediaSessionOptions opts;
1479 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
1480 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1481 ASSERT_TRUE(offer.get() != nullptr);
1482 ContentInfo* dc_offer = offer->GetContentByName("data");
1483 ASSERT_TRUE(dc_offer != nullptr);
1484 SctpDataContentDescription* dcd_offer =
1485 dc_offer->media_description()->as_sctp();
1486 ASSERT_TRUE(dcd_offer);
1487
1488 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1489 "TCP/DTLS/SCTP"};
1490 for (const std::string& proto : protos) {
1491 dcd_offer->set_protocol(proto);
1492 std::unique_ptr<SessionDescription> answer =
1493 f2_.CreateAnswer(offer.get(), opts, nullptr);
1494 const ContentInfo* dc_answer = answer->GetContentByName("data");
1495 ASSERT_TRUE(dc_answer != nullptr);
1496 const SctpDataContentDescription* dcd_answer =
1497 dc_answer->media_description()->as_sctp();
1498 EXPECT_FALSE(dc_answer->rejected);
1499 EXPECT_EQ(proto, dcd_answer->protocol());
1500 }
1501 }
1502
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateDataAnswerToOfferWithDefinedMessageSize)1503 TEST_F(MediaSessionDescriptionFactoryTest,
1504 TestCreateDataAnswerToOfferWithDefinedMessageSize) {
1505 // Need to enable DTLS offer/answer generation (disabled by default in this
1506 // test).
1507 f1_.set_secure(SEC_ENABLED);
1508 f2_.set_secure(SEC_ENABLED);
1509 tdf1_.set_secure(SEC_ENABLED);
1510 tdf2_.set_secure(SEC_ENABLED);
1511
1512 MediaSessionOptions opts;
1513 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
1514 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1515 ASSERT_TRUE(offer.get() != nullptr);
1516 ContentInfo* dc_offer = offer->GetContentByName("data");
1517 ASSERT_TRUE(dc_offer != nullptr);
1518 SctpDataContentDescription* dcd_offer =
1519 dc_offer->media_description()->as_sctp();
1520 ASSERT_TRUE(dcd_offer);
1521 dcd_offer->set_max_message_size(1234);
1522 std::unique_ptr<SessionDescription> answer =
1523 f2_.CreateAnswer(offer.get(), opts, nullptr);
1524 const ContentInfo* dc_answer = answer->GetContentByName("data");
1525 ASSERT_TRUE(dc_answer != nullptr);
1526 const SctpDataContentDescription* dcd_answer =
1527 dc_answer->media_description()->as_sctp();
1528 EXPECT_FALSE(dc_answer->rejected);
1529 EXPECT_EQ(1234, dcd_answer->max_message_size());
1530 }
1531
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateDataAnswerToOfferWithZeroMessageSize)1532 TEST_F(MediaSessionDescriptionFactoryTest,
1533 TestCreateDataAnswerToOfferWithZeroMessageSize) {
1534 // Need to enable DTLS offer/answer generation (disabled by default in this
1535 // test).
1536 f1_.set_secure(SEC_ENABLED);
1537 f2_.set_secure(SEC_ENABLED);
1538 tdf1_.set_secure(SEC_ENABLED);
1539 tdf2_.set_secure(SEC_ENABLED);
1540
1541 MediaSessionOptions opts;
1542 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
1543 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1544 ASSERT_TRUE(offer.get() != nullptr);
1545 ContentInfo* dc_offer = offer->GetContentByName("data");
1546 ASSERT_TRUE(dc_offer != nullptr);
1547 SctpDataContentDescription* dcd_offer =
1548 dc_offer->media_description()->as_sctp();
1549 ASSERT_TRUE(dcd_offer);
1550 dcd_offer->set_max_message_size(0);
1551 std::unique_ptr<SessionDescription> answer =
1552 f2_.CreateAnswer(offer.get(), opts, nullptr);
1553 const ContentInfo* dc_answer = answer->GetContentByName("data");
1554 ASSERT_TRUE(dc_answer != nullptr);
1555 const SctpDataContentDescription* dcd_answer =
1556 dc_answer->media_description()->as_sctp();
1557 EXPECT_FALSE(dc_answer->rejected);
1558 EXPECT_EQ(cricket::kSctpSendBufferSize, dcd_answer->max_message_size());
1559 }
1560
1561 // Verifies that the order of the media contents in the offer is preserved in
1562 // the answer.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateAnswerContentOrder)1563 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1564 MediaSessionOptions opts;
1565
1566 // Creates a data only offer.
1567 AddDataSection(RtpTransceiverDirection::kSendRecv, &opts);
1568 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
1569 ASSERT_TRUE(offer1.get() != NULL);
1570
1571 // Appends audio to the offer.
1572 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1573 RtpTransceiverDirection::kRecvOnly, kActive,
1574 &opts);
1575 std::unique_ptr<SessionDescription> offer2(
1576 f1_.CreateOffer(opts, offer1.get()));
1577 ASSERT_TRUE(offer2.get() != NULL);
1578
1579 // Appends video to the offer.
1580 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1581 RtpTransceiverDirection::kRecvOnly, kActive,
1582 &opts);
1583 std::unique_ptr<SessionDescription> offer3(
1584 f1_.CreateOffer(opts, offer2.get()));
1585 ASSERT_TRUE(offer3.get() != NULL);
1586
1587 std::unique_ptr<SessionDescription> answer =
1588 f2_.CreateAnswer(offer3.get(), opts, NULL);
1589 ASSERT_TRUE(answer.get() != NULL);
1590 EXPECT_EQ(3u, answer->contents().size());
1591 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1592 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1593 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1594 }
1595
1596 // TODO(deadbeef): Extend these tests to ensure the correct direction with other
1597 // answerer settings.
1598
1599 // This test that the media direction is set to send/receive in an answer if
1600 // the offer is send receive.
TEST_F(MediaSessionDescriptionFactoryTest,CreateAnswerToSendReceiveOffer)1601 TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
1602 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1603 RtpTransceiverDirection::kSendRecv);
1604 }
1605
1606 // This test that the media direction is set to receive only in an answer if
1607 // the offer is send only.
TEST_F(MediaSessionDescriptionFactoryTest,CreateAnswerToSendOnlyOffer)1608 TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
1609 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1610 RtpTransceiverDirection::kRecvOnly);
1611 }
1612
1613 // This test that the media direction is set to send only in an answer if
1614 // the offer is recv only.
TEST_F(MediaSessionDescriptionFactoryTest,CreateAnswerToRecvOnlyOffer)1615 TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
1616 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1617 RtpTransceiverDirection::kSendOnly);
1618 }
1619
1620 // This test that the media direction is set to inactive in an answer if
1621 // the offer is inactive.
TEST_F(MediaSessionDescriptionFactoryTest,CreateAnswerToInactiveOffer)1622 TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
1623 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1624 RtpTransceiverDirection::kInactive);
1625 }
1626
1627 // Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
TEST_F(MediaSessionDescriptionFactoryTest,AudioOfferAnswerWithCryptoDisabled)1628 TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
1629 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
1630 f1_.set_secure(SEC_DISABLED);
1631 f2_.set_secure(SEC_DISABLED);
1632 tdf1_.set_secure(SEC_DISABLED);
1633 tdf2_.set_secure(SEC_DISABLED);
1634
1635 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
1636 const AudioContentDescription* offer_acd =
1637 GetFirstAudioContentDescription(offer.get());
1638 ASSERT_TRUE(offer_acd != NULL);
1639 EXPECT_EQ(cricket::kMediaProtocolAvpf, offer_acd->protocol());
1640
1641 std::unique_ptr<SessionDescription> answer =
1642 f2_.CreateAnswer(offer.get(), opts, NULL);
1643
1644 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1645 ASSERT_TRUE(ac_answer != NULL);
1646 EXPECT_FALSE(ac_answer->rejected);
1647
1648 const AudioContentDescription* answer_acd =
1649 GetFirstAudioContentDescription(answer.get());
1650 ASSERT_TRUE(answer_acd != NULL);
1651 EXPECT_EQ(cricket::kMediaProtocolAvpf, answer_acd->protocol());
1652 }
1653
1654 // Create a video offer and answer and ensure the RTP header extensions
1655 // matches what we expect.
TEST_F(MediaSessionDescriptionFactoryTest,TestOfferAnswerWithRtpExtensions)1656 TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1657 MediaSessionOptions opts;
1658 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1659 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
1660 MAKE_VECTOR(kVideoRtpExtension1), &opts);
1661
1662 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
1663 ASSERT_TRUE(offer.get() != NULL);
1664 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
1665 MAKE_VECTOR(kVideoRtpExtension2), &opts);
1666 std::unique_ptr<SessionDescription> answer =
1667 f2_.CreateAnswer(offer.get(), opts, NULL);
1668
1669 EXPECT_EQ(
1670 MAKE_VECTOR(kAudioRtpExtension1),
1671 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1672 EXPECT_EQ(
1673 MAKE_VECTOR(kVideoRtpExtension1),
1674 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1675 EXPECT_EQ(
1676 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1677 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1678 EXPECT_EQ(
1679 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1680 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
1681 }
1682
1683 // Create a audio/video offer and answer and ensure that the
1684 // TransportSequenceNumber RTP header extensions are handled correctly. 02 is
1685 // supported and should take precedence even though not listed among locally
1686 // supported extensions.
TEST_F(MediaSessionDescriptionFactoryTest,TestOfferAnswerWithTransportSequenceNumberInOffer)1687 TEST_F(MediaSessionDescriptionFactoryTest,
1688 TestOfferAnswerWithTransportSequenceNumberInOffer) {
1689 TestTransportSequenceNumberNegotiation(
1690 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1691 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Offer.
1692 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01)); // Expected answer.
1693 }
TEST_F(MediaSessionDescriptionFactoryTest,TestOfferAnswerWithTransportSequenceNumber01And02InOffer)1694 TEST_F(MediaSessionDescriptionFactoryTest,
1695 TestOfferAnswerWithTransportSequenceNumber01And02InOffer) {
1696 TestTransportSequenceNumberNegotiation(
1697 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1698 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01And02), // Offer.
1699 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1700 }
TEST_F(MediaSessionDescriptionFactoryTest,TestOfferAnswerWithTransportSequenceNumber02InOffer)1701 TEST_F(MediaSessionDescriptionFactoryTest,
1702 TestOfferAnswerWithTransportSequenceNumber02InOffer) {
1703 TestTransportSequenceNumberNegotiation(
1704 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1705 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02), // Offer.
1706 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1707 }
1708
TEST_F(MediaSessionDescriptionFactoryTest,TestNegotiateFrameDescriptorWhenUnexposedLocally)1709 TEST_F(MediaSessionDescriptionFactoryTest,
1710 TestNegotiateFrameDescriptorWhenUnexposedLocally) {
1711 MediaSessionOptions opts;
1712 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1713
1714 SetAudioVideoRtpHeaderExtensions(
1715 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00),
1716 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00), &opts);
1717 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1718 SetAudioVideoRtpHeaderExtensions(
1719 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01),
1720 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), &opts);
1721 std::unique_ptr<SessionDescription> answer =
1722 f2_.CreateAnswer(offer.get(), opts, nullptr);
1723 EXPECT_THAT(
1724 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1725 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
1726 EXPECT_THAT(
1727 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1728 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
1729 }
1730
TEST_F(MediaSessionDescriptionFactoryTest,TestNegotiateFrameDescriptorWhenExposedLocally)1731 TEST_F(MediaSessionDescriptionFactoryTest,
1732 TestNegotiateFrameDescriptorWhenExposedLocally) {
1733 MediaSessionOptions opts;
1734 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1735
1736 SetAudioVideoRtpHeaderExtensions(
1737 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00),
1738 MAKE_VECTOR(kRtpExtensionGenericFrameDescriptorUri00), &opts);
1739 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1740 std::unique_ptr<SessionDescription> answer =
1741 f2_.CreateAnswer(offer.get(), opts, nullptr);
1742 EXPECT_THAT(
1743 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1744 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
1745 EXPECT_THAT(
1746 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1747 ElementsAreArray(kRtpExtensionGenericFrameDescriptorUri00));
1748 }
1749
TEST_F(MediaSessionDescriptionFactoryTest,NegotiateDependencyDescriptorWhenUnexposedLocally)1750 TEST_F(MediaSessionDescriptionFactoryTest,
1751 NegotiateDependencyDescriptorWhenUnexposedLocally) {
1752 MediaSessionOptions opts;
1753 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1754
1755 RtpExtension offer_dd(RtpExtension::kDependencyDescriptorUri, 7);
1756 SetAudioVideoRtpHeaderExtensions({}, {offer_dd}, &opts);
1757 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1758 RtpExtension local_tsn(RtpExtension::kTransportSequenceNumberUri, 5);
1759 SetAudioVideoRtpHeaderExtensions({}, {local_tsn}, &opts);
1760 std::unique_ptr<SessionDescription> answer =
1761 f2_.CreateAnswer(offer.get(), opts, nullptr);
1762 EXPECT_THAT(
1763 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1764 ElementsAre(offer_dd));
1765 }
1766
TEST_F(MediaSessionDescriptionFactoryTest,NegotiateDependencyDescriptorWhenExposedLocally)1767 TEST_F(MediaSessionDescriptionFactoryTest,
1768 NegotiateDependencyDescriptorWhenExposedLocally) {
1769 MediaSessionOptions opts;
1770 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1771
1772 RtpExtension offer_dd(RtpExtension::kDependencyDescriptorUri, 7);
1773 RtpExtension local_dd(RtpExtension::kDependencyDescriptorUri, 5);
1774 SetAudioVideoRtpHeaderExtensions({}, {offer_dd}, &opts);
1775 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1776 SetAudioVideoRtpHeaderExtensions({}, {local_dd}, &opts);
1777 std::unique_ptr<SessionDescription> answer =
1778 f2_.CreateAnswer(offer.get(), opts, nullptr);
1779 EXPECT_THAT(
1780 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1781 ElementsAre(offer_dd));
1782 }
1783
TEST_F(MediaSessionDescriptionFactoryTest,NegotiateAbsoluteCaptureTimeWhenUnexposedLocally)1784 TEST_F(MediaSessionDescriptionFactoryTest,
1785 NegotiateAbsoluteCaptureTimeWhenUnexposedLocally) {
1786 MediaSessionOptions opts;
1787 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1788
1789 const cricket::RtpHeaderExtensions offered_extensions = {
1790 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 7)};
1791 const cricket::RtpHeaderExtensions local_extensions = {
1792 RtpExtension(RtpExtension::kTransportSequenceNumberUri, 5)};
1793 SetAudioVideoRtpHeaderExtensions(offered_extensions, offered_extensions,
1794 &opts);
1795 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1796 SetAudioVideoRtpHeaderExtensions(local_extensions, local_extensions, &opts);
1797 std::unique_ptr<SessionDescription> answer =
1798 f2_.CreateAnswer(offer.get(), opts, nullptr);
1799 EXPECT_THAT(
1800 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1801 ElementsAreArray(offered_extensions));
1802 EXPECT_THAT(
1803 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1804 ElementsAreArray(offered_extensions));
1805 }
1806
TEST_F(MediaSessionDescriptionFactoryTest,NegotiateAbsoluteCaptureTimeWhenExposedLocally)1807 TEST_F(MediaSessionDescriptionFactoryTest,
1808 NegotiateAbsoluteCaptureTimeWhenExposedLocally) {
1809 MediaSessionOptions opts;
1810 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1811
1812 const cricket::RtpHeaderExtensions offered_extensions = {
1813 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 7)};
1814 const cricket::RtpHeaderExtensions local_extensions = {
1815 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 5)};
1816 SetAudioVideoRtpHeaderExtensions(offered_extensions, offered_extensions,
1817 &opts);
1818 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1819 SetAudioVideoRtpHeaderExtensions(local_extensions, local_extensions, &opts);
1820 std::unique_ptr<SessionDescription> answer =
1821 f2_.CreateAnswer(offer.get(), opts, nullptr);
1822 EXPECT_THAT(
1823 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1824 ElementsAreArray(offered_extensions));
1825 EXPECT_THAT(
1826 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1827 ElementsAreArray(offered_extensions));
1828 }
1829
TEST_F(MediaSessionDescriptionFactoryTest,DoNotNegotiateAbsoluteCaptureTimeWhenNotOffered)1830 TEST_F(MediaSessionDescriptionFactoryTest,
1831 DoNotNegotiateAbsoluteCaptureTimeWhenNotOffered) {
1832 MediaSessionOptions opts;
1833 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1834
1835 const cricket::RtpHeaderExtensions offered_extensions = {
1836 RtpExtension(RtpExtension::kTransportSequenceNumberUri, 7)};
1837 const cricket::RtpHeaderExtensions local_extensions = {
1838 RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 5)};
1839 SetAudioVideoRtpHeaderExtensions(offered_extensions, offered_extensions,
1840 &opts);
1841 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1842 SetAudioVideoRtpHeaderExtensions(local_extensions, local_extensions, &opts);
1843 std::unique_ptr<SessionDescription> answer =
1844 f2_.CreateAnswer(offer.get(), opts, nullptr);
1845 EXPECT_THAT(
1846 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
1847 IsEmpty());
1848 EXPECT_THAT(
1849 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
1850 IsEmpty());
1851 }
1852
TEST_F(MediaSessionDescriptionFactoryTest,OffersUnstoppedExtensionsWithAudioVideoExtensionStopped)1853 TEST_F(MediaSessionDescriptionFactoryTest,
1854 OffersUnstoppedExtensionsWithAudioVideoExtensionStopped) {
1855 MediaSessionOptions opts;
1856 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1857 RtpTransceiverDirection::kSendRecv, kActive,
1858 &opts);
1859 opts.media_description_options.back().header_extensions = {
1860 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1861 RtpTransceiverDirection::kStopped),
1862 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1863 RtpTransceiverDirection::kSendOnly)};
1864 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
1865 RtpTransceiverDirection::kSendRecv, kActive,
1866 &opts);
1867 opts.media_description_options.back().header_extensions = {
1868 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1869 RtpTransceiverDirection::kStopped),
1870 webrtc::RtpHeaderExtensionCapability("uri3", 7,
1871 RtpTransceiverDirection::kSendOnly)};
1872 auto offer = f1_.CreateOffer(opts, nullptr);
1873 EXPECT_THAT(
1874 offer->contents(),
1875 ElementsAre(
1876 Property(&ContentInfo::media_description,
1877 Pointee(Property(
1878 &MediaContentDescription::rtp_header_extensions,
1879 ElementsAre(Field(&RtpExtension::uri, "uri2"))))),
1880 Property(&ContentInfo::media_description,
1881 Pointee(Property(
1882 &MediaContentDescription::rtp_header_extensions,
1883 ElementsAre(Field(&RtpExtension::uri, "uri3")))))));
1884 }
1885
TEST_F(MediaSessionDescriptionFactoryTest,OffersUnstoppedExtensionsWithAudioExtensionStopped)1886 TEST_F(MediaSessionDescriptionFactoryTest,
1887 OffersUnstoppedExtensionsWithAudioExtensionStopped) {
1888 MediaSessionOptions opts;
1889 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1890 RtpTransceiverDirection::kSendRecv, kActive,
1891 &opts);
1892 opts.media_description_options.back().header_extensions = {
1893 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1894 RtpTransceiverDirection::kSendOnly),
1895 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1896 RtpTransceiverDirection::kStopped)};
1897 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
1898 RtpTransceiverDirection::kSendRecv, kActive,
1899 &opts);
1900 opts.media_description_options.back().header_extensions = {
1901 webrtc::RtpHeaderExtensionCapability("uri42", 42,
1902 RtpTransceiverDirection::kSendRecv),
1903 webrtc::RtpHeaderExtensionCapability("uri3", 7,
1904 RtpTransceiverDirection::kSendOnly)};
1905 auto offer = f1_.CreateOffer(opts, nullptr);
1906 EXPECT_THAT(
1907 offer->contents(),
1908 ElementsAre(
1909 Property(&ContentInfo::media_description,
1910 Pointee(Property(
1911 &MediaContentDescription::rtp_header_extensions,
1912 ElementsAre(Field(&RtpExtension::uri, "uri1"))))),
1913 Property(
1914 &ContentInfo::media_description,
1915 Pointee(Property(
1916 &MediaContentDescription::rtp_header_extensions,
1917 UnorderedElementsAre(Field(&RtpExtension::uri, "uri3"),
1918 Field(&RtpExtension::uri, "uri42")))))));
1919 }
1920
TEST_F(MediaSessionDescriptionFactoryTest,OffersUnstoppedExtensionsWithVideoExtensionStopped)1921 TEST_F(MediaSessionDescriptionFactoryTest,
1922 OffersUnstoppedExtensionsWithVideoExtensionStopped) {
1923 MediaSessionOptions opts;
1924 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1925 RtpTransceiverDirection::kSendRecv, kActive,
1926 &opts);
1927 opts.media_description_options.back().header_extensions = {
1928 webrtc::RtpHeaderExtensionCapability("uri1", 5,
1929 RtpTransceiverDirection::kSendOnly),
1930 webrtc::RtpHeaderExtensionCapability("uri2", 7,
1931 RtpTransceiverDirection::kSendRecv)};
1932 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
1933 RtpTransceiverDirection::kSendRecv, kActive,
1934 &opts);
1935 opts.media_description_options.back().header_extensions = {
1936 webrtc::RtpHeaderExtensionCapability("uri42", 42,
1937 RtpTransceiverDirection::kSendRecv),
1938 webrtc::RtpHeaderExtensionCapability("uri3", 7,
1939 RtpTransceiverDirection::kStopped)};
1940 auto offer = f1_.CreateOffer(opts, nullptr);
1941 EXPECT_THAT(
1942 offer->contents(),
1943 ElementsAre(
1944 Property(
1945 &ContentInfo::media_description,
1946 Pointee(Property(
1947 &MediaContentDescription::rtp_header_extensions,
1948 UnorderedElementsAre(Field(&RtpExtension::uri, "uri1"),
1949 Field(&RtpExtension::uri, "uri2"))))),
1950 Property(&ContentInfo::media_description,
1951 Pointee(Property(
1952 &MediaContentDescription::rtp_header_extensions,
1953 ElementsAre(Field(&RtpExtension::uri, "uri42")))))));
1954 }
1955
TEST_F(MediaSessionDescriptionFactoryTest,AnswersUnstoppedExtensions)1956 TEST_F(MediaSessionDescriptionFactoryTest, AnswersUnstoppedExtensions) {
1957 MediaSessionOptions opts;
1958 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1959 RtpTransceiverDirection::kSendRecv, kActive,
1960 &opts);
1961 opts.media_description_options.back().header_extensions = {
1962 webrtc::RtpHeaderExtensionCapability("uri1", 4,
1963 RtpTransceiverDirection::kStopped),
1964 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1965 RtpTransceiverDirection::kSendOnly),
1966 webrtc::RtpHeaderExtensionCapability("uri3", 2,
1967 RtpTransceiverDirection::kRecvOnly),
1968 webrtc::RtpHeaderExtensionCapability("uri4", 1,
1969 RtpTransceiverDirection::kSendRecv)};
1970 auto offer = f1_.CreateOffer(opts, nullptr);
1971 opts.media_description_options.back().header_extensions = {
1972 webrtc::RtpHeaderExtensionCapability("uri1", 4,
1973 RtpTransceiverDirection::kSendOnly),
1974 webrtc::RtpHeaderExtensionCapability("uri2", 3,
1975 RtpTransceiverDirection::kRecvOnly),
1976 webrtc::RtpHeaderExtensionCapability("uri3", 2,
1977 RtpTransceiverDirection::kStopped),
1978 webrtc::RtpHeaderExtensionCapability("uri4", 1,
1979 RtpTransceiverDirection::kSendRecv)};
1980 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
1981 EXPECT_THAT(
1982 answer->contents(),
1983 ElementsAre(Property(
1984 &ContentInfo::media_description,
1985 Pointee(Property(&MediaContentDescription::rtp_header_extensions,
1986 ElementsAre(Field(&RtpExtension::uri, "uri2"),
1987 Field(&RtpExtension::uri, "uri4")))))));
1988 }
1989
TEST_F(MediaSessionDescriptionFactoryTest,AppendsUnstoppedExtensionsToCurrentDescription)1990 TEST_F(MediaSessionDescriptionFactoryTest,
1991 AppendsUnstoppedExtensionsToCurrentDescription) {
1992 MediaSessionOptions opts;
1993 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1994 RtpTransceiverDirection::kSendRecv, kActive,
1995 &opts);
1996 opts.media_description_options.back().header_extensions = {
1997 webrtc::RtpHeaderExtensionCapability("uri1", 1,
1998 RtpTransceiverDirection::kSendRecv)};
1999 auto offer = f1_.CreateOffer(opts, nullptr);
2000 opts.media_description_options.back().header_extensions = {
2001 webrtc::RtpHeaderExtensionCapability("uri1", 2,
2002 RtpTransceiverDirection::kSendRecv),
2003 webrtc::RtpHeaderExtensionCapability("uri2", 3,
2004 RtpTransceiverDirection::kRecvOnly),
2005 webrtc::RtpHeaderExtensionCapability("uri3", 5,
2006 RtpTransceiverDirection::kStopped),
2007 webrtc::RtpHeaderExtensionCapability("uri4", 6,
2008 RtpTransceiverDirection::kSendRecv)};
2009 auto offer2 = f1_.CreateOffer(opts, offer.get());
2010 EXPECT_THAT(
2011 offer2->contents(),
2012 ElementsAre(Property(
2013 &ContentInfo::media_description,
2014 Pointee(Property(&MediaContentDescription::rtp_header_extensions,
2015 ElementsAre(Field(&RtpExtension::uri, "uri1"),
2016 Field(&RtpExtension::uri, "uri2"),
2017 Field(&RtpExtension::uri, "uri4")))))));
2018 }
2019
TEST_F(MediaSessionDescriptionFactoryTest,AppendsStoppedExtensionIfKnownAndPresentInTheOffer)2020 TEST_F(MediaSessionDescriptionFactoryTest,
2021 AppendsStoppedExtensionIfKnownAndPresentInTheOffer) {
2022 MediaSessionOptions opts;
2023 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2024 RtpTransceiverDirection::kSendRecv, kActive,
2025 &opts);
2026 opts.media_description_options.back().header_extensions = {
2027 webrtc::RtpHeaderExtensionCapability("uri1", 1,
2028 RtpTransceiverDirection::kSendRecv),
2029 webrtc::RtpHeaderExtensionCapability("uri2", 1,
2030 RtpTransceiverDirection::kSendRecv)};
2031 auto offer = f1_.CreateOffer(opts, nullptr);
2032
2033 // Now add "uri2" as stopped to the options verify that the offer contains
2034 // uri2 since it's already present since before.
2035 opts.media_description_options.back().header_extensions = {
2036 webrtc::RtpHeaderExtensionCapability("uri1", 1,
2037 RtpTransceiverDirection::kSendRecv),
2038 webrtc::RtpHeaderExtensionCapability("uri2", 2,
2039 RtpTransceiverDirection::kStopped)};
2040 auto offer2 = f1_.CreateOffer(opts, offer.get());
2041 EXPECT_THAT(
2042 offer2->contents(),
2043 ElementsAre(Property(
2044 &ContentInfo::media_description,
2045 Pointee(Property(&MediaContentDescription::rtp_header_extensions,
2046 ElementsAre(Field(&RtpExtension::uri, "uri1"),
2047 Field(&RtpExtension::uri, "uri2")))))));
2048 }
2049
TEST_F(MediaSessionDescriptionFactoryTest,TestOfferAnswerWithEncryptedRtpExtensionsBoth)2050 TEST_F(MediaSessionDescriptionFactoryTest,
2051 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
2052 MediaSessionOptions opts;
2053 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
2054
2055 f1_.set_enable_encrypted_rtp_header_extensions(true);
2056 f2_.set_enable_encrypted_rtp_header_extensions(true);
2057
2058 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
2059 MAKE_VECTOR(kVideoRtpExtension1), &opts);
2060 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2061 ASSERT_TRUE(offer.get() != NULL);
2062 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
2063 MAKE_VECTOR(kVideoRtpExtension2), &opts);
2064 std::unique_ptr<SessionDescription> answer =
2065 f2_.CreateAnswer(offer.get(), opts, NULL);
2066
2067 EXPECT_EQ(
2068 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
2069 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2070 EXPECT_EQ(
2071 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
2072 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
2073 EXPECT_EQ(
2074 MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
2075 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2076 EXPECT_EQ(
2077 MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
2078 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
2079 }
2080
TEST_F(MediaSessionDescriptionFactoryTest,TestOfferAnswerWithEncryptedRtpExtensionsOffer)2081 TEST_F(MediaSessionDescriptionFactoryTest,
2082 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
2083 MediaSessionOptions opts;
2084 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
2085
2086 f1_.set_enable_encrypted_rtp_header_extensions(true);
2087
2088 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
2089 MAKE_VECTOR(kVideoRtpExtension1), &opts);
2090 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2091 ASSERT_TRUE(offer.get() != NULL);
2092 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
2093 MAKE_VECTOR(kVideoRtpExtension2), &opts);
2094 std::unique_ptr<SessionDescription> answer =
2095 f2_.CreateAnswer(offer.get(), opts, NULL);
2096
2097 EXPECT_EQ(
2098 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
2099 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2100 EXPECT_EQ(
2101 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
2102 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
2103 EXPECT_EQ(
2104 MAKE_VECTOR(kAudioRtpExtensionAnswer),
2105 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2106 EXPECT_EQ(
2107 MAKE_VECTOR(kVideoRtpExtensionAnswer),
2108 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
2109 }
2110
TEST_F(MediaSessionDescriptionFactoryTest,TestOfferAnswerWithEncryptedRtpExtensionsAnswer)2111 TEST_F(MediaSessionDescriptionFactoryTest,
2112 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
2113 MediaSessionOptions opts;
2114 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
2115
2116 f2_.set_enable_encrypted_rtp_header_extensions(true);
2117
2118 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
2119 MAKE_VECTOR(kVideoRtpExtension1), &opts);
2120 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2121 ASSERT_TRUE(offer.get() != NULL);
2122 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
2123 MAKE_VECTOR(kVideoRtpExtension2), &opts);
2124 std::unique_ptr<SessionDescription> answer =
2125 f2_.CreateAnswer(offer.get(), opts, NULL);
2126
2127 EXPECT_EQ(
2128 MAKE_VECTOR(kAudioRtpExtension1),
2129 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2130 EXPECT_EQ(
2131 MAKE_VECTOR(kVideoRtpExtension1),
2132 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
2133 EXPECT_EQ(
2134 MAKE_VECTOR(kAudioRtpExtensionAnswer),
2135 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2136 EXPECT_EQ(
2137 MAKE_VECTOR(kVideoRtpExtensionAnswer),
2138 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
2139 }
2140
2141 // Create an audio, video, data answer without legacy StreamParams.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateAnswerWithoutLegacyStreams)2142 TEST_F(MediaSessionDescriptionFactoryTest,
2143 TestCreateAnswerWithoutLegacyStreams) {
2144 MediaSessionOptions opts;
2145 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
2146 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2147 ASSERT_TRUE(offer.get() != NULL);
2148 std::unique_ptr<SessionDescription> answer =
2149 f2_.CreateAnswer(offer.get(), opts, NULL);
2150 const ContentInfo* ac = answer->GetContentByName("audio");
2151 const ContentInfo* vc = answer->GetContentByName("video");
2152 ASSERT_TRUE(ac != NULL);
2153 ASSERT_TRUE(vc != NULL);
2154 const AudioContentDescription* acd = ac->media_description()->as_audio();
2155 const VideoContentDescription* vcd = vc->media_description()->as_video();
2156
2157 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
2158 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
2159 }
2160
2161 // Create a typical video answer, and ensure it matches what we expect.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateVideoAnswerRtcpMux)2162 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
2163 MediaSessionOptions offer_opts;
2164 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
2165
2166 MediaSessionOptions answer_opts;
2167 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
2168
2169 std::unique_ptr<SessionDescription> offer;
2170 std::unique_ptr<SessionDescription> answer;
2171
2172 offer_opts.rtcp_mux_enabled = true;
2173 answer_opts.rtcp_mux_enabled = true;
2174 offer = f1_.CreateOffer(offer_opts, NULL);
2175 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
2176 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2177 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
2178 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2179 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
2180 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2181 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
2182 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2183 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
2184
2185 offer_opts.rtcp_mux_enabled = true;
2186 answer_opts.rtcp_mux_enabled = false;
2187 offer = f1_.CreateOffer(offer_opts, NULL);
2188 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
2189 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2190 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
2191 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2192 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
2193 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2194 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
2195 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2196 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
2197
2198 offer_opts.rtcp_mux_enabled = false;
2199 answer_opts.rtcp_mux_enabled = true;
2200 offer = f1_.CreateOffer(offer_opts, NULL);
2201 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
2202 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2203 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
2204 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2205 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
2206 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2207 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
2208 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2209 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
2210
2211 offer_opts.rtcp_mux_enabled = false;
2212 answer_opts.rtcp_mux_enabled = false;
2213 offer = f1_.CreateOffer(offer_opts, NULL);
2214 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
2215 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
2216 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
2217 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
2218 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
2219 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
2220 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
2221 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
2222 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
2223 }
2224
2225 // Create an audio-only answer to a video offer.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateAudioAnswerToVideo)2226 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
2227 MediaSessionOptions opts;
2228 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2229 RtpTransceiverDirection::kRecvOnly, kActive,
2230 &opts);
2231 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2232 RtpTransceiverDirection::kRecvOnly, kActive,
2233 &opts);
2234 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2235 ASSERT_TRUE(offer.get() != NULL);
2236
2237 opts.media_description_options[1].stopped = true;
2238 std::unique_ptr<SessionDescription> answer =
2239 f2_.CreateAnswer(offer.get(), opts, NULL);
2240 const ContentInfo* ac = answer->GetContentByName("audio");
2241 const ContentInfo* vc = answer->GetContentByName("video");
2242 ASSERT_TRUE(ac != NULL);
2243 ASSERT_TRUE(vc != NULL);
2244 ASSERT_TRUE(vc->media_description() != NULL);
2245 EXPECT_TRUE(vc->rejected);
2246 }
2247
2248 // Create an answer that rejects the contents which are rejected in the offer.
TEST_F(MediaSessionDescriptionFactoryTest,CreateAnswerToOfferWithRejectedMedia)2249 TEST_F(MediaSessionDescriptionFactoryTest,
2250 CreateAnswerToOfferWithRejectedMedia) {
2251 MediaSessionOptions opts;
2252 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
2253 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2254 ASSERT_TRUE(offer.get() != NULL);
2255 ContentInfo* ac = offer->GetContentByName("audio");
2256 ContentInfo* vc = offer->GetContentByName("video");
2257 ASSERT_TRUE(ac != NULL);
2258 ASSERT_TRUE(vc != NULL);
2259 ac->rejected = true;
2260 vc->rejected = true;
2261 std::unique_ptr<SessionDescription> answer =
2262 f2_.CreateAnswer(offer.get(), opts, NULL);
2263 ac = answer->GetContentByName("audio");
2264 vc = answer->GetContentByName("video");
2265 ASSERT_TRUE(ac != NULL);
2266 ASSERT_TRUE(vc != NULL);
2267 EXPECT_TRUE(ac->rejected);
2268 EXPECT_TRUE(vc->rejected);
2269 }
2270
TEST_F(MediaSessionDescriptionFactoryTest,OfferAndAnswerDoesNotHaveMixedByteSessionAttribute)2271 TEST_F(MediaSessionDescriptionFactoryTest,
2272 OfferAndAnswerDoesNotHaveMixedByteSessionAttribute) {
2273 MediaSessionOptions opts;
2274 std::unique_ptr<SessionDescription> offer =
2275 f1_.CreateOffer(opts, /*current_description=*/nullptr);
2276 offer->set_extmap_allow_mixed(false);
2277
2278 std::unique_ptr<SessionDescription> answer(
2279 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
2280
2281 EXPECT_FALSE(answer->extmap_allow_mixed());
2282 }
2283
TEST_F(MediaSessionDescriptionFactoryTest,OfferAndAnswerHaveMixedByteSessionAttribute)2284 TEST_F(MediaSessionDescriptionFactoryTest,
2285 OfferAndAnswerHaveMixedByteSessionAttribute) {
2286 MediaSessionOptions opts;
2287 std::unique_ptr<SessionDescription> offer =
2288 f1_.CreateOffer(opts, /*current_description=*/nullptr);
2289 offer->set_extmap_allow_mixed(true);
2290
2291 std::unique_ptr<SessionDescription> answer_support(
2292 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
2293
2294 EXPECT_TRUE(answer_support->extmap_allow_mixed());
2295 }
2296
TEST_F(MediaSessionDescriptionFactoryTest,OfferAndAnswerDoesNotHaveMixedByteMediaAttributes)2297 TEST_F(MediaSessionDescriptionFactoryTest,
2298 OfferAndAnswerDoesNotHaveMixedByteMediaAttributes) {
2299 MediaSessionOptions opts;
2300 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
2301 std::unique_ptr<SessionDescription> offer =
2302 f1_.CreateOffer(opts, /*current_description=*/nullptr);
2303 offer->set_extmap_allow_mixed(false);
2304 MediaContentDescription* audio_offer =
2305 offer->GetContentDescriptionByName("audio");
2306 MediaContentDescription* video_offer =
2307 offer->GetContentDescriptionByName("video");
2308 ASSERT_EQ(MediaContentDescription::kNo,
2309 audio_offer->extmap_allow_mixed_enum());
2310 ASSERT_EQ(MediaContentDescription::kNo,
2311 video_offer->extmap_allow_mixed_enum());
2312
2313 std::unique_ptr<SessionDescription> answer(
2314 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
2315
2316 MediaContentDescription* audio_answer =
2317 answer->GetContentDescriptionByName("audio");
2318 MediaContentDescription* video_answer =
2319 answer->GetContentDescriptionByName("video");
2320 EXPECT_EQ(MediaContentDescription::kNo,
2321 audio_answer->extmap_allow_mixed_enum());
2322 EXPECT_EQ(MediaContentDescription::kNo,
2323 video_answer->extmap_allow_mixed_enum());
2324 }
2325
TEST_F(MediaSessionDescriptionFactoryTest,OfferAndAnswerHaveSameMixedByteMediaAttributes)2326 TEST_F(MediaSessionDescriptionFactoryTest,
2327 OfferAndAnswerHaveSameMixedByteMediaAttributes) {
2328 MediaSessionOptions opts;
2329 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
2330 std::unique_ptr<SessionDescription> offer =
2331 f1_.CreateOffer(opts, /*current_description=*/nullptr);
2332 offer->set_extmap_allow_mixed(false);
2333 MediaContentDescription* audio_offer =
2334 offer->GetContentDescriptionByName("audio");
2335 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
2336 MediaContentDescription* video_offer =
2337 offer->GetContentDescriptionByName("video");
2338 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
2339
2340 std::unique_ptr<SessionDescription> answer(
2341 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
2342
2343 MediaContentDescription* audio_answer =
2344 answer->GetContentDescriptionByName("audio");
2345 MediaContentDescription* video_answer =
2346 answer->GetContentDescriptionByName("video");
2347 EXPECT_EQ(MediaContentDescription::kMedia,
2348 audio_answer->extmap_allow_mixed_enum());
2349 EXPECT_EQ(MediaContentDescription::kMedia,
2350 video_answer->extmap_allow_mixed_enum());
2351 }
2352
TEST_F(MediaSessionDescriptionFactoryTest,OfferAndAnswerHaveDifferentMixedByteMediaAttributes)2353 TEST_F(MediaSessionDescriptionFactoryTest,
2354 OfferAndAnswerHaveDifferentMixedByteMediaAttributes) {
2355 MediaSessionOptions opts;
2356 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
2357 std::unique_ptr<SessionDescription> offer =
2358 f1_.CreateOffer(opts, /*current_description=*/nullptr);
2359 offer->set_extmap_allow_mixed(false);
2360 MediaContentDescription* audio_offer =
2361 offer->GetContentDescriptionByName("audio");
2362 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
2363 MediaContentDescription* video_offer =
2364 offer->GetContentDescriptionByName("video");
2365 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
2366
2367 std::unique_ptr<SessionDescription> answer(
2368 f2_.CreateAnswer(offer.get(), opts, /*current_description=*/nullptr));
2369
2370 MediaContentDescription* audio_answer =
2371 answer->GetContentDescriptionByName("audio");
2372 MediaContentDescription* video_answer =
2373 answer->GetContentDescriptionByName("video");
2374 EXPECT_EQ(MediaContentDescription::kNo,
2375 audio_answer->extmap_allow_mixed_enum());
2376 EXPECT_EQ(MediaContentDescription::kMedia,
2377 video_answer->extmap_allow_mixed_enum());
2378 }
2379
2380 // Create an audio and video offer with:
2381 // - one video track
2382 // - two audio tracks
2383 // and ensure it matches what we expect. Also updates the initial offer by
2384 // adding a new video track and replaces one of the audio tracks.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateMultiStreamVideoOffer)2385 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
2386 MediaSessionOptions opts;
2387 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
2388 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2389 {kMediaStream1}, 1, &opts);
2390 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2391 {kMediaStream1}, 1, &opts);
2392 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2393 {kMediaStream1}, 1, &opts);
2394
2395 f1_.set_secure(SEC_ENABLED);
2396 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2397
2398 ASSERT_TRUE(offer.get() != NULL);
2399 const ContentInfo* ac = offer->GetContentByName("audio");
2400 const ContentInfo* vc = offer->GetContentByName("video");
2401 ASSERT_TRUE(ac != NULL);
2402 ASSERT_TRUE(vc != NULL);
2403 const AudioContentDescription* acd = ac->media_description()->as_audio();
2404 const VideoContentDescription* vcd = vc->media_description()->as_video();
2405 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
2406 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
2407
2408 const StreamParamsVec& audio_streams = acd->streams();
2409 ASSERT_EQ(2U, audio_streams.size());
2410 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
2411 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2412 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2413 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2414 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2415 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2416 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2417
2418 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2419 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
2420 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
2421
2422 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
2423 EXPECT_EQ(f1_.video_sendrecv_codecs(), vcd->codecs());
2424 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
2425
2426 const StreamParamsVec& video_streams = vcd->streams();
2427 ASSERT_EQ(1U, video_streams.size());
2428 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2429 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2430 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2431 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2432
2433 // Update the offer. Add a new video track that is not synched to the
2434 // other tracks and replace audio track 2 with audio track 3.
2435 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2436 {kMediaStream2}, 1, &opts);
2437 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
2438 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
2439 {kMediaStream1}, 1, &opts);
2440 std::unique_ptr<SessionDescription> updated_offer(
2441 f1_.CreateOffer(opts, offer.get()));
2442
2443 ASSERT_TRUE(updated_offer.get() != NULL);
2444 ac = updated_offer->GetContentByName("audio");
2445 vc = updated_offer->GetContentByName("video");
2446 ASSERT_TRUE(ac != NULL);
2447 ASSERT_TRUE(vc != NULL);
2448 const AudioContentDescription* updated_acd =
2449 ac->media_description()->as_audio();
2450 const VideoContentDescription* updated_vcd =
2451 vc->media_description()->as_video();
2452
2453 EXPECT_EQ(acd->type(), updated_acd->type());
2454 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2455 EXPECT_EQ(vcd->type(), updated_vcd->type());
2456 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2457 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
2458 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
2459 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
2460 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
2461
2462 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2463 ASSERT_EQ(2U, updated_audio_streams.size());
2464 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
2465 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
2466 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
2467 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
2468 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
2469
2470 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2471 ASSERT_EQ(2U, updated_video_streams.size());
2472 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2473 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
2474 // All the media streams in one PeerConnection share one RTCP CNAME.
2475 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
2476 }
2477
2478 // Create an offer with simulcast video stream.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateSimulcastVideoOffer)2479 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
2480 MediaSessionOptions opts;
2481 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2482 RtpTransceiverDirection::kRecvOnly, kActive,
2483 &opts);
2484 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2485 RtpTransceiverDirection::kSendRecv, kActive,
2486 &opts);
2487 const int num_sim_layers = 3;
2488 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2489 {kMediaStream1}, num_sim_layers, &opts);
2490 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2491
2492 ASSERT_TRUE(offer.get() != NULL);
2493 const ContentInfo* vc = offer->GetContentByName("video");
2494 ASSERT_TRUE(vc != NULL);
2495 const VideoContentDescription* vcd = vc->media_description()->as_video();
2496
2497 const StreamParamsVec& video_streams = vcd->streams();
2498 ASSERT_EQ(1U, video_streams.size());
2499 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2500 const SsrcGroup* sim_ssrc_group =
2501 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
2502 ASSERT_TRUE(sim_ssrc_group != NULL);
2503 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
2504 }
2505
2506 MATCHER(RidDescriptionEquals, "Verifies that two RidDescriptions are equal.") {
2507 const RidDescription& rid1 = ::testing::get<0>(arg);
2508 const RidDescription& rid2 = ::testing::get<1>(arg);
2509 return rid1.rid == rid2.rid && rid1.direction == rid2.direction;
2510 }
2511
CheckSimulcastInSessionDescription(const SessionDescription * description,const std::string & content_name,const std::vector<RidDescription> & send_rids,const SimulcastLayerList & send_layers)2512 static void CheckSimulcastInSessionDescription(
2513 const SessionDescription* description,
2514 const std::string& content_name,
2515 const std::vector<RidDescription>& send_rids,
2516 const SimulcastLayerList& send_layers) {
2517 ASSERT_NE(description, nullptr);
2518 const ContentInfo* content = description->GetContentByName(content_name);
2519 ASSERT_NE(content, nullptr);
2520 const MediaContentDescription* cd = content->media_description();
2521 ASSERT_NE(cd, nullptr);
2522 const StreamParamsVec& streams = cd->streams();
2523 ASSERT_THAT(streams, SizeIs(1));
2524 const StreamParams& stream = streams[0];
2525 ASSERT_THAT(stream.ssrcs, IsEmpty());
2526 EXPECT_TRUE(stream.has_rids());
2527 const std::vector<RidDescription> rids = stream.rids();
2528
2529 EXPECT_THAT(rids, Pointwise(RidDescriptionEquals(), send_rids));
2530
2531 EXPECT_TRUE(cd->HasSimulcast());
2532 const SimulcastDescription& simulcast = cd->simulcast_description();
2533 EXPECT_THAT(simulcast.send_layers(), SizeIs(send_layers.size()));
2534 EXPECT_THAT(simulcast.send_layers(), Pointwise(Eq(), send_layers));
2535
2536 ASSERT_THAT(simulcast.receive_layers().GetAllLayers(), SizeIs(0));
2537 }
2538
2539 // Create an offer with spec-compliant simulcast video stream.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateCompliantSimulcastOffer)2540 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastOffer) {
2541 MediaSessionOptions opts;
2542 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2543 RtpTransceiverDirection::kSendRecv, kActive,
2544 &opts);
2545 std::vector<RidDescription> send_rids;
2546 send_rids.push_back(RidDescription("f", RidDirection::kSend));
2547 send_rids.push_back(RidDescription("h", RidDirection::kSend));
2548 send_rids.push_back(RidDescription("q", RidDirection::kSend));
2549 SimulcastLayerList simulcast_layers;
2550 simulcast_layers.AddLayer(SimulcastLayer(send_rids[0].rid, false));
2551 simulcast_layers.AddLayer(SimulcastLayer(send_rids[1].rid, true));
2552 simulcast_layers.AddLayer(SimulcastLayer(send_rids[2].rid, false));
2553 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2554 {kMediaStream1}, send_rids,
2555 simulcast_layers, 0, &opts);
2556 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2557
2558 CheckSimulcastInSessionDescription(offer.get(), "video", send_rids,
2559 simulcast_layers);
2560 }
2561
2562 // Create an offer that signals RIDs (not SSRCs) without Simulcast.
2563 // In this scenario, RIDs do not need to be negotiated (there is only one).
TEST_F(MediaSessionDescriptionFactoryTest,TestOfferWithRidsNoSimulcast)2564 TEST_F(MediaSessionDescriptionFactoryTest, TestOfferWithRidsNoSimulcast) {
2565 MediaSessionOptions opts;
2566 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2567 RtpTransceiverDirection::kSendRecv, kActive,
2568 &opts);
2569 RidDescription rid("f", RidDirection::kSend);
2570 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2571 {kMediaStream1}, {rid},
2572 SimulcastLayerList(), 0, &opts);
2573 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2574
2575 ASSERT_NE(offer.get(), nullptr);
2576 const ContentInfo* content = offer->GetContentByName("video");
2577 ASSERT_NE(content, nullptr);
2578 const MediaContentDescription* cd = content->media_description();
2579 ASSERT_NE(cd, nullptr);
2580 const StreamParamsVec& streams = cd->streams();
2581 ASSERT_THAT(streams, SizeIs(1));
2582 const StreamParams& stream = streams[0];
2583 ASSERT_THAT(stream.ssrcs, IsEmpty());
2584 EXPECT_FALSE(stream.has_rids());
2585 EXPECT_FALSE(cd->HasSimulcast());
2586 }
2587
2588 // Create an answer with spec-compliant simulcast video stream.
2589 // In this scenario, the SFU is the caller requesting that we send Simulcast.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateCompliantSimulcastAnswer)2590 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastAnswer) {
2591 MediaSessionOptions offer_opts;
2592 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2593 RtpTransceiverDirection::kSendRecv, kActive,
2594 &offer_opts);
2595 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2596 {kMediaStream1}, 1, &offer_opts);
2597 std::unique_ptr<SessionDescription> offer =
2598 f1_.CreateOffer(offer_opts, nullptr);
2599
2600 MediaSessionOptions answer_opts;
2601 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2602 RtpTransceiverDirection::kSendRecv, kActive,
2603 &answer_opts);
2604
2605 std::vector<RidDescription> rid_descriptions{
2606 RidDescription("f", RidDirection::kSend),
2607 RidDescription("h", RidDirection::kSend),
2608 RidDescription("q", RidDirection::kSend),
2609 };
2610 SimulcastLayerList simulcast_layers;
2611 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[0].rid, false));
2612 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[1].rid, true));
2613 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[2].rid, false));
2614 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2615 {kMediaStream1}, rid_descriptions,
2616 simulcast_layers, 0, &answer_opts);
2617 std::unique_ptr<SessionDescription> answer =
2618 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2619
2620 CheckSimulcastInSessionDescription(answer.get(), "video", rid_descriptions,
2621 simulcast_layers);
2622 }
2623
2624 // Create an answer that signals RIDs (not SSRCs) without Simulcast.
2625 // In this scenario, RIDs do not need to be negotiated (there is only one).
2626 // Note that RID Direction is not the same as the transceiver direction.
TEST_F(MediaSessionDescriptionFactoryTest,TestAnswerWithRidsNoSimulcast)2627 TEST_F(MediaSessionDescriptionFactoryTest, TestAnswerWithRidsNoSimulcast) {
2628 MediaSessionOptions offer_opts;
2629 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2630 RtpTransceiverDirection::kSendRecv, kActive,
2631 &offer_opts);
2632 RidDescription rid_offer("f", RidDirection::kSend);
2633 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2634 {kMediaStream1}, {rid_offer},
2635 SimulcastLayerList(), 0, &offer_opts);
2636 std::unique_ptr<SessionDescription> offer =
2637 f1_.CreateOffer(offer_opts, nullptr);
2638
2639 MediaSessionOptions answer_opts;
2640 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2641 RtpTransceiverDirection::kSendRecv, kActive,
2642 &answer_opts);
2643
2644 RidDescription rid_answer("f", RidDirection::kReceive);
2645 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2646 {kMediaStream1}, {rid_answer},
2647 SimulcastLayerList(), 0, &answer_opts);
2648 std::unique_ptr<SessionDescription> answer =
2649 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2650
2651 ASSERT_NE(answer.get(), nullptr);
2652 const ContentInfo* content = offer->GetContentByName("video");
2653 ASSERT_NE(content, nullptr);
2654 const MediaContentDescription* cd = content->media_description();
2655 ASSERT_NE(cd, nullptr);
2656 const StreamParamsVec& streams = cd->streams();
2657 ASSERT_THAT(streams, SizeIs(1));
2658 const StreamParams& stream = streams[0];
2659 ASSERT_THAT(stream.ssrcs, IsEmpty());
2660 EXPECT_FALSE(stream.has_rids());
2661 EXPECT_FALSE(cd->HasSimulcast());
2662 }
2663
2664 // Create an audio and video answer to a standard video offer with:
2665 // - one video track
2666 // - two audio tracks
2667 // - two data tracks
2668 // and ensure it matches what we expect. Also updates the initial answer by
2669 // adding a new video track and removes one of the audio tracks.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateMultiStreamVideoAnswer)2670 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
2671 MediaSessionOptions offer_opts;
2672 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2673 RtpTransceiverDirection::kRecvOnly, kActive,
2674 &offer_opts);
2675 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2676 RtpTransceiverDirection::kRecvOnly, kActive,
2677 &offer_opts);
2678 f1_.set_secure(SEC_ENABLED);
2679 f2_.set_secure(SEC_ENABLED);
2680 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
2681
2682 MediaSessionOptions answer_opts;
2683 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2684 RtpTransceiverDirection::kSendRecv, kActive,
2685 &answer_opts);
2686 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2687 RtpTransceiverDirection::kSendRecv, kActive,
2688 &answer_opts);
2689 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2690 {kMediaStream1}, 1, &answer_opts);
2691 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2692 {kMediaStream1}, 1, &answer_opts);
2693 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2694 {kMediaStream1}, 1, &answer_opts);
2695
2696 std::unique_ptr<SessionDescription> answer =
2697 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
2698
2699 ASSERT_TRUE(answer.get() != NULL);
2700 const ContentInfo* ac = answer->GetContentByName("audio");
2701 const ContentInfo* vc = answer->GetContentByName("video");
2702 ASSERT_TRUE(ac != NULL);
2703 ASSERT_TRUE(vc != NULL);
2704 const AudioContentDescription* acd = ac->media_description()->as_audio();
2705 const VideoContentDescription* vcd = vc->media_description()->as_video();
2706 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
2707 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
2708
2709 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
2710 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
2711
2712 const StreamParamsVec& audio_streams = acd->streams();
2713 ASSERT_EQ(2U, audio_streams.size());
2714 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
2715 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2716 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2717 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2718 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2719 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2720 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2721
2722 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2723 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
2724
2725 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
2726 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
2727
2728 const StreamParamsVec& video_streams = vcd->streams();
2729 ASSERT_EQ(1U, video_streams.size());
2730 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2731 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2732 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2733 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2734
2735 // Update the answer. Add a new video track that is not synched to the
2736 // other tracks and remove 1 audio track.
2737 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2738 {kMediaStream2}, 1, &answer_opts);
2739 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
2740 std::unique_ptr<SessionDescription> updated_answer(
2741 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
2742
2743 ASSERT_TRUE(updated_answer.get() != NULL);
2744 ac = updated_answer->GetContentByName("audio");
2745 vc = updated_answer->GetContentByName("video");
2746 ASSERT_TRUE(ac != NULL);
2747 ASSERT_TRUE(vc != NULL);
2748 const AudioContentDescription* updated_acd =
2749 ac->media_description()->as_audio();
2750 const VideoContentDescription* updated_vcd =
2751 vc->media_description()->as_video();
2752
2753 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
2754 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
2755 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
2756 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
2757
2758 EXPECT_EQ(acd->type(), updated_acd->type());
2759 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2760 EXPECT_EQ(vcd->type(), updated_vcd->type());
2761 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2762
2763 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2764 ASSERT_EQ(1U, updated_audio_streams.size());
2765 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
2766
2767 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2768 ASSERT_EQ(2U, updated_video_streams.size());
2769 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2770 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
2771 // All media streams in one PeerConnection share one CNAME.
2772 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
2773 }
2774
2775 // Create an updated offer after creating an answer to the original offer and
2776 // verify that the codecs that were part of the original answer are not changed
2777 // in the updated offer.
TEST_F(MediaSessionDescriptionFactoryTest,RespondentCreatesOfferAfterCreatingAnswer)2778 TEST_F(MediaSessionDescriptionFactoryTest,
2779 RespondentCreatesOfferAfterCreatingAnswer) {
2780 MediaSessionOptions opts;
2781 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
2782
2783 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2784 std::unique_ptr<SessionDescription> answer =
2785 f2_.CreateAnswer(offer.get(), opts, NULL);
2786
2787 const AudioContentDescription* acd =
2788 GetFirstAudioContentDescription(answer.get());
2789 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
2790
2791 const VideoContentDescription* vcd =
2792 GetFirstVideoContentDescription(answer.get());
2793 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
2794
2795 std::unique_ptr<SessionDescription> updated_offer(
2796 f2_.CreateOffer(opts, answer.get()));
2797
2798 // The expected audio codecs are the common audio codecs from the first
2799 // offer/answer exchange plus the audio codecs only `f2_` offer, sorted in
2800 // preference order.
2801 // TODO(wu): `updated_offer` should not include the codec
2802 // (i.e. `kAudioCodecs2[0]`) the other side doesn't support.
2803 const AudioCodec kUpdatedAudioCodecOffer[] = {
2804 kAudioCodecsAnswer[0],
2805 kAudioCodecsAnswer[1],
2806 kAudioCodecs2[0],
2807 };
2808
2809 // The expected video codecs are the common video codecs from the first
2810 // offer/answer exchange plus the video codecs only `f2_` offer, sorted in
2811 // preference order.
2812 const VideoCodec kUpdatedVideoCodecOffer[] = {
2813 kVideoCodecsAnswer[0],
2814 kVideoCodecs2[1],
2815 };
2816
2817 const AudioContentDescription* updated_acd =
2818 GetFirstAudioContentDescription(updated_offer.get());
2819 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kUpdatedAudioCodecOffer));
2820
2821 const VideoContentDescription* updated_vcd =
2822 GetFirstVideoContentDescription(updated_offer.get());
2823 EXPECT_THAT(updated_vcd->codecs(), ElementsAreArray(kUpdatedVideoCodecOffer));
2824 }
2825
2826 // Test that a reoffer does not reuse audio codecs from a previous media section
2827 // that is being recycled.
TEST_F(MediaSessionDescriptionFactoryTest,ReOfferDoesNotReUseRecycledAudioCodecs)2828 TEST_F(MediaSessionDescriptionFactoryTest,
2829 ReOfferDoesNotReUseRecycledAudioCodecs) {
2830 f1_.set_video_codecs({}, {});
2831 f2_.set_video_codecs({}, {});
2832
2833 MediaSessionOptions opts;
2834 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2835 RtpTransceiverDirection::kSendRecv, kActive,
2836 &opts);
2837 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2838 std::unique_ptr<SessionDescription> answer =
2839 f2_.CreateAnswer(offer.get(), opts, nullptr);
2840
2841 // Recycle the media section by changing its mid.
2842 opts.media_description_options[0].mid = "a1";
2843 std::unique_ptr<SessionDescription> reoffer =
2844 f2_.CreateOffer(opts, answer.get());
2845
2846 // Expect that the results of the first negotiation are ignored. If the m=
2847 // section was not recycled the payload types would match the initial offerer.
2848 const AudioContentDescription* acd =
2849 GetFirstAudioContentDescription(reoffer.get());
2850 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecs2));
2851 }
2852
2853 // Test that a reoffer does not reuse video codecs from a previous media section
2854 // that is being recycled.
TEST_F(MediaSessionDescriptionFactoryTest,ReOfferDoesNotReUseRecycledVideoCodecs)2855 TEST_F(MediaSessionDescriptionFactoryTest,
2856 ReOfferDoesNotReUseRecycledVideoCodecs) {
2857 f1_.set_audio_codecs({}, {});
2858 f2_.set_audio_codecs({}, {});
2859
2860 MediaSessionOptions opts;
2861 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2862 RtpTransceiverDirection::kSendRecv, kActive,
2863 &opts);
2864 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2865 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
2866
2867 // Recycle the media section by changing its mid.
2868 opts.media_description_options[0].mid = "v1";
2869 std::unique_ptr<SessionDescription> reoffer =
2870 f2_.CreateOffer(opts, answer.get());
2871
2872 // Expect that the results of the first negotiation are ignored. If the m=
2873 // section was not recycled the payload types would match the initial offerer.
2874 const VideoContentDescription* vcd =
2875 GetFirstVideoContentDescription(reoffer.get());
2876 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecs2));
2877 }
2878
2879 // Test that a reanswer does not reuse audio codecs from a previous media
2880 // section that is being recycled.
TEST_F(MediaSessionDescriptionFactoryTest,ReAnswerDoesNotReUseRecycledAudioCodecs)2881 TEST_F(MediaSessionDescriptionFactoryTest,
2882 ReAnswerDoesNotReUseRecycledAudioCodecs) {
2883 f1_.set_video_codecs({}, {});
2884 f2_.set_video_codecs({}, {});
2885
2886 // Perform initial offer/answer in reverse (`f2_` as offerer) so that the
2887 // second offer/answer is forward (`f1_` as offerer).
2888 MediaSessionOptions opts;
2889 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2890 RtpTransceiverDirection::kSendRecv, kActive,
2891 &opts);
2892 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2893 std::unique_ptr<SessionDescription> answer =
2894 f1_.CreateAnswer(offer.get(), opts, nullptr);
2895
2896 // Recycle the media section by changing its mid.
2897 opts.media_description_options[0].mid = "a1";
2898 std::unique_ptr<SessionDescription> reoffer =
2899 f1_.CreateOffer(opts, answer.get());
2900 std::unique_ptr<SessionDescription> reanswer =
2901 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
2902
2903 // Expect that the results of the first negotiation are ignored. If the m=
2904 // section was not recycled the payload types would match the initial offerer.
2905 const AudioContentDescription* acd =
2906 GetFirstAudioContentDescription(reanswer.get());
2907 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
2908 }
2909
2910 // Test that a reanswer does not reuse video codecs from a previous media
2911 // section that is being recycled.
TEST_F(MediaSessionDescriptionFactoryTest,ReAnswerDoesNotReUseRecycledVideoCodecs)2912 TEST_F(MediaSessionDescriptionFactoryTest,
2913 ReAnswerDoesNotReUseRecycledVideoCodecs) {
2914 f1_.set_audio_codecs({}, {});
2915 f2_.set_audio_codecs({}, {});
2916
2917 // Perform initial offer/answer in reverse (`f2_` as offerer) so that the
2918 // second offer/answer is forward (`f1_` as offerer).
2919 MediaSessionOptions opts;
2920 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2921 RtpTransceiverDirection::kSendRecv, kActive,
2922 &opts);
2923 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2924 std::unique_ptr<SessionDescription> answer =
2925 f1_.CreateAnswer(offer.get(), opts, nullptr);
2926
2927 // Recycle the media section by changing its mid.
2928 opts.media_description_options[0].mid = "v1";
2929 std::unique_ptr<SessionDescription> reoffer =
2930 f1_.CreateOffer(opts, answer.get());
2931 std::unique_ptr<SessionDescription> reanswer =
2932 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
2933
2934 // Expect that the results of the first negotiation are ignored. If the m=
2935 // section was not recycled the payload types would match the initial offerer.
2936 const VideoContentDescription* vcd =
2937 GetFirstVideoContentDescription(reanswer.get());
2938 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
2939 }
2940
2941 // Create an updated offer after creating an answer to the original offer and
2942 // verify that the codecs that were part of the original answer are not changed
2943 // in the updated offer. In this test Rtx is enabled.
TEST_F(MediaSessionDescriptionFactoryTest,RespondentCreatesOfferAfterCreatingAnswerWithRtx)2944 TEST_F(MediaSessionDescriptionFactoryTest,
2945 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2946 MediaSessionOptions opts;
2947 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2948 RtpTransceiverDirection::kRecvOnly, kActive,
2949 &opts);
2950 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2951 // This creates rtx for H264 with the payload type `f1_` uses.
2952 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2953 f1_.set_video_codecs(f1_codecs, f1_codecs);
2954
2955 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2956 // This creates rtx for H264 with the payload type `f2_` uses.
2957 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
2958 f2_.set_video_codecs(f2_codecs, f2_codecs);
2959
2960 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2961 ASSERT_TRUE(offer.get() != NULL);
2962 std::unique_ptr<SessionDescription> answer =
2963 f2_.CreateAnswer(offer.get(), opts, NULL);
2964
2965 const VideoContentDescription* vcd =
2966 GetFirstVideoContentDescription(answer.get());
2967
2968 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2969 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2970 &expected_codecs);
2971
2972 EXPECT_EQ(expected_codecs, vcd->codecs());
2973
2974 // Now, make sure we get same result (except for the order) if `f2_` creates
2975 // an updated offer even though the default payload types between `f1_` and
2976 // `f2_` are different.
2977 std::unique_ptr<SessionDescription> updated_offer(
2978 f2_.CreateOffer(opts, answer.get()));
2979 ASSERT_TRUE(updated_offer);
2980 std::unique_ptr<SessionDescription> updated_answer(
2981 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2982
2983 const VideoContentDescription* updated_vcd =
2984 GetFirstVideoContentDescription(updated_answer.get());
2985
2986 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2987 }
2988
2989 // Regression test for:
2990 // https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2991 // Existing codecs should always appear before new codecs in re-offers. But
2992 // under a specific set of circumstances, the existing RTX codec was ending up
2993 // added to the end of the list.
TEST_F(MediaSessionDescriptionFactoryTest,RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType)2994 TEST_F(MediaSessionDescriptionFactoryTest,
2995 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2996 MediaSessionOptions opts;
2997 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2998 RtpTransceiverDirection::kRecvOnly, kActive,
2999 &opts);
3000 // We specifically choose different preferred payload types for VP8 to
3001 // trigger the issue.
3002 cricket::VideoCodec vp8_offerer(100, "VP8");
3003 cricket::VideoCodec vp8_offerer_rtx =
3004 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
3005 cricket::VideoCodec vp8_answerer(110, "VP8");
3006 cricket::VideoCodec vp8_answerer_rtx =
3007 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
3008 cricket::VideoCodec vp9(120, "VP9");
3009 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
3010
3011 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
3012 // We also specifically cause the answerer to prefer VP9, such that if it
3013 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
3014 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
3015 vp8_answerer_rtx};
3016
3017 f1_.set_video_codecs(f1_codecs, f1_codecs);
3018 f2_.set_video_codecs(f2_codecs, f2_codecs);
3019 std::vector<AudioCodec> audio_codecs;
3020 f1_.set_audio_codecs(audio_codecs, audio_codecs);
3021 f2_.set_audio_codecs(audio_codecs, audio_codecs);
3022
3023 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
3024 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
3025 ASSERT_TRUE(offer.get() != NULL);
3026 std::unique_ptr<SessionDescription> answer =
3027 f2_.CreateAnswer(offer.get(), opts, NULL);
3028
3029 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
3030 // But if the bug is triggered, RTX for VP8 ends up last.
3031 std::unique_ptr<SessionDescription> updated_offer(
3032 f2_.CreateOffer(opts, answer.get()));
3033
3034 const VideoContentDescription* vcd =
3035 GetFirstVideoContentDescription(updated_offer.get());
3036 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
3037 ASSERT_EQ(4u, codecs.size());
3038 EXPECT_EQ(vp8_offerer, codecs[0]);
3039 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
3040 EXPECT_EQ(vp9, codecs[2]);
3041 EXPECT_EQ(vp9_rtx, codecs[3]);
3042 }
3043
3044 // Create an updated offer that adds video after creating an audio only answer
3045 // to the original offer. This test verifies that if a video codec and the RTX
3046 // codec have the same default payload type as an audio codec that is already in
3047 // use, the added codecs payload types are changed.
TEST_F(MediaSessionDescriptionFactoryTest,RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer)3048 TEST_F(MediaSessionDescriptionFactoryTest,
3049 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
3050 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3051 // This creates rtx for H264 with the payload type `f1_` uses.
3052 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
3053 f1_.set_video_codecs(f1_codecs, f1_codecs);
3054
3055 MediaSessionOptions opts;
3056 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3057 RtpTransceiverDirection::kRecvOnly, kActive,
3058 &opts);
3059
3060 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
3061 std::unique_ptr<SessionDescription> answer =
3062 f2_.CreateAnswer(offer.get(), opts, NULL);
3063
3064 const AudioContentDescription* acd =
3065 GetFirstAudioContentDescription(answer.get());
3066 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
3067
3068 // Now - let `f2_` add video with RTX and let the payload type the RTX codec
3069 // reference be the same as an audio codec that was negotiated in the
3070 // first offer/answer exchange.
3071 opts.media_description_options.clear();
3072 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
3073
3074 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3075 int used_pl_type = acd->codecs()[0].id;
3076 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
3077 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
3078 f2_.set_video_codecs(f2_codecs, f2_codecs);
3079
3080 std::unique_ptr<SessionDescription> updated_offer(
3081 f2_.CreateOffer(opts, answer.get()));
3082 ASSERT_TRUE(updated_offer);
3083 std::unique_ptr<SessionDescription> updated_answer(
3084 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
3085
3086 const AudioContentDescription* updated_acd =
3087 GetFirstAudioContentDescription(answer.get());
3088 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
3089
3090 const VideoContentDescription* updated_vcd =
3091 GetFirstVideoContentDescription(updated_answer.get());
3092
3093 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
3094 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
3095 int new_h264_pl_type = updated_vcd->codecs()[0].id;
3096 EXPECT_NE(used_pl_type, new_h264_pl_type);
3097 VideoCodec rtx = updated_vcd->codecs()[1];
3098 int pt_referenced_by_rtx = rtc::FromString<int>(
3099 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
3100 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
3101 }
3102
3103 // Create an updated offer with RTX after creating an answer to an offer
3104 // without RTX, and with different default payload types.
3105 // Verify that the added RTX codec references the correct payload type.
TEST_F(MediaSessionDescriptionFactoryTest,RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx)3106 TEST_F(MediaSessionDescriptionFactoryTest,
3107 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
3108 MediaSessionOptions opts;
3109 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
3110
3111 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3112 // This creates rtx for H264 with the payload type `f2_` uses.
3113 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
3114 f2_.set_video_codecs(f2_codecs, f2_codecs);
3115
3116 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
3117 ASSERT_TRUE(offer.get() != nullptr);
3118 std::unique_ptr<SessionDescription> answer =
3119 f2_.CreateAnswer(offer.get(), opts, nullptr);
3120
3121 const VideoContentDescription* vcd =
3122 GetFirstVideoContentDescription(answer.get());
3123
3124 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
3125 EXPECT_EQ(expected_codecs, vcd->codecs());
3126
3127 // Now, ensure that the RTX codec is created correctly when `f2_` creates an
3128 // updated offer, even though the default payload types are different from
3129 // those of `f1_`.
3130 std::unique_ptr<SessionDescription> updated_offer(
3131 f2_.CreateOffer(opts, answer.get()));
3132 ASSERT_TRUE(updated_offer);
3133
3134 const VideoContentDescription* updated_vcd =
3135 GetFirstVideoContentDescription(updated_offer.get());
3136
3137 // New offer should attempt to add H263, and RTX for H264.
3138 expected_codecs.push_back(kVideoCodecs2[1]);
3139 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
3140 &expected_codecs);
3141 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
3142 }
3143
3144 // Test that RTX is ignored when there is no associated payload type parameter.
TEST_F(MediaSessionDescriptionFactoryTest,RtxWithoutApt)3145 TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
3146 MediaSessionOptions opts;
3147 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3148 RtpTransceiverDirection::kRecvOnly, kActive,
3149 &opts);
3150 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3151 // This creates RTX without associated payload type parameter.
3152 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
3153 f1_.set_video_codecs(f1_codecs, f1_codecs);
3154
3155 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3156 // This creates RTX for H264 with the payload type `f2_` uses.
3157 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
3158 f2_.set_video_codecs(f2_codecs, f2_codecs);
3159
3160 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
3161 ASSERT_TRUE(offer.get() != NULL);
3162 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
3163 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
3164 // is possible to test that that RTX is dropped when
3165 // kCodecParamAssociatedPayloadType is missing in the offer.
3166 MediaContentDescription* media_desc =
3167 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3168 ASSERT_TRUE(media_desc);
3169 VideoContentDescription* desc = media_desc->as_video();
3170 std::vector<VideoCodec> codecs = desc->codecs();
3171 for (VideoCodec& codec : codecs) {
3172 if (absl::StartsWith(codec.name, cricket::kRtxCodecName)) {
3173 codec.params.clear();
3174 }
3175 }
3176 desc->set_codecs(codecs);
3177
3178 std::unique_ptr<SessionDescription> answer =
3179 f2_.CreateAnswer(offer.get(), opts, NULL);
3180
3181 EXPECT_THAT(
3182 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
3183 Not(Contains(cricket::kRtxCodecName)));
3184 }
3185
3186 // Test that RTX will be filtered out in the answer if its associated payload
3187 // type doesn't match the local value.
TEST_F(MediaSessionDescriptionFactoryTest,FilterOutRtxIfAptDoesntMatch)3188 TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
3189 MediaSessionOptions opts;
3190 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3191 RtpTransceiverDirection::kRecvOnly, kActive,
3192 &opts);
3193 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3194 // This creates RTX for H264 in sender.
3195 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
3196 f1_.set_video_codecs(f1_codecs, f1_codecs);
3197
3198 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3199 // This creates RTX for H263 in receiver.
3200 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
3201 f2_.set_video_codecs(f2_codecs, f2_codecs);
3202
3203 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
3204 ASSERT_TRUE(offer.get() != NULL);
3205 // Associated payload type doesn't match, therefore, RTX codec is removed in
3206 // the answer.
3207 std::unique_ptr<SessionDescription> answer =
3208 f2_.CreateAnswer(offer.get(), opts, NULL);
3209
3210 EXPECT_THAT(
3211 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
3212 Not(Contains(cricket::kRtxCodecName)));
3213 }
3214
3215 // Test that when multiple RTX codecs are offered, only the matched RTX codec
3216 // is added in the answer, and the unsupported RTX codec is filtered out.
TEST_F(MediaSessionDescriptionFactoryTest,FilterOutUnsupportedRtxWhenCreatingAnswer)3217 TEST_F(MediaSessionDescriptionFactoryTest,
3218 FilterOutUnsupportedRtxWhenCreatingAnswer) {
3219 MediaSessionOptions opts;
3220 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3221 RtpTransceiverDirection::kRecvOnly, kActive,
3222 &opts);
3223 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3224 // This creates RTX for H264-SVC in sender.
3225 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
3226 f1_.set_video_codecs(f1_codecs, f1_codecs);
3227
3228 // This creates RTX for H264 in sender.
3229 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
3230 f1_.set_video_codecs(f1_codecs, f1_codecs);
3231
3232 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
3233 // This creates RTX for H264 in receiver.
3234 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
3235 f2_.set_video_codecs(f2_codecs, f1_codecs);
3236
3237 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
3238 // for H264-SVC should also be removed.
3239 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
3240 ASSERT_TRUE(offer.get() != NULL);
3241 std::unique_ptr<SessionDescription> answer =
3242 f2_.CreateAnswer(offer.get(), opts, NULL);
3243 const VideoContentDescription* vcd =
3244 GetFirstVideoContentDescription(answer.get());
3245 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
3246 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3247 &expected_codecs);
3248
3249 EXPECT_EQ(expected_codecs, vcd->codecs());
3250 }
3251
3252 // Test that after one RTX codec has been negotiated, a new offer can attempt
3253 // to add another.
TEST_F(MediaSessionDescriptionFactoryTest,AddSecondRtxInNewOffer)3254 TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
3255 MediaSessionOptions opts;
3256 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3257 RtpTransceiverDirection::kRecvOnly, kActive,
3258 &opts);
3259 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
3260 // This creates RTX for H264 for the offerer.
3261 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
3262 f1_.set_video_codecs(f1_codecs, f1_codecs);
3263
3264 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
3265 ASSERT_TRUE(offer);
3266 const VideoContentDescription* vcd =
3267 GetFirstVideoContentDescription(offer.get());
3268
3269 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
3270 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3271 &expected_codecs);
3272 EXPECT_EQ(expected_codecs, vcd->codecs());
3273
3274 // Now, attempt to add RTX for H264-SVC.
3275 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
3276 f1_.set_video_codecs(f1_codecs, f1_codecs);
3277
3278 std::unique_ptr<SessionDescription> updated_offer(
3279 f1_.CreateOffer(opts, offer.get()));
3280 ASSERT_TRUE(updated_offer);
3281 vcd = GetFirstVideoContentDescription(updated_offer.get());
3282
3283 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
3284 &expected_codecs);
3285 EXPECT_EQ(expected_codecs, vcd->codecs());
3286 }
3287
3288 // Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
3289 // generated for each simulcast ssrc and correctly grouped.
TEST_F(MediaSessionDescriptionFactoryTest,SimSsrcsGenerateMultipleRtxSsrcs)3290 TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
3291 MediaSessionOptions opts;
3292 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3293 RtpTransceiverDirection::kSendRecv, kActive,
3294 &opts);
3295 // Add simulcast streams.
3296 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3297 {"stream1label"}, 3, &opts);
3298
3299 // Use a single real codec, and then add RTX for it.
3300 std::vector<VideoCodec> f1_codecs;
3301 f1_codecs.push_back(VideoCodec(97, "H264"));
3302 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
3303 f1_.set_video_codecs(f1_codecs, f1_codecs);
3304
3305 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
3306 // is a FID ssrc + grouping for each.
3307 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
3308 ASSERT_TRUE(offer.get() != NULL);
3309 MediaContentDescription* media_desc =
3310 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3311 ASSERT_TRUE(media_desc);
3312 VideoContentDescription* desc = media_desc->as_video();
3313 const StreamParamsVec& streams = desc->streams();
3314 // Single stream.
3315 ASSERT_EQ(1u, streams.size());
3316 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
3317 EXPECT_EQ(6u, streams[0].ssrcs.size());
3318 // And should have a SIM group for the simulcast.
3319 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3320 // And a FID group for RTX.
3321 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
3322 std::vector<uint32_t> primary_ssrcs;
3323 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3324 EXPECT_EQ(3u, primary_ssrcs.size());
3325 std::vector<uint32_t> fid_ssrcs;
3326 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
3327 EXPECT_EQ(3u, fid_ssrcs.size());
3328 }
3329
3330 // Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
3331 // together with a FEC-FR grouping. Guarded by WebRTC-FlexFEC-03 trial.
TEST_F(MediaSessionDescriptionFactoryTest,GenerateFlexfecSsrc)3332 TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
3333 webrtc::test::ScopedKeyValueConfig override_field_trials(
3334 field_trials, "WebRTC-FlexFEC-03/Enabled/");
3335 MediaSessionOptions opts;
3336 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3337 RtpTransceiverDirection::kSendRecv, kActive,
3338 &opts);
3339 // Add single stream.
3340 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3341 {"stream1label"}, 1, &opts);
3342
3343 // Use a single real codec, and then add FlexFEC for it.
3344 std::vector<VideoCodec> f1_codecs;
3345 f1_codecs.push_back(VideoCodec(97, "H264"));
3346 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
3347 f1_.set_video_codecs(f1_codecs, f1_codecs);
3348
3349 // Ensure that the offer has a single FlexFEC ssrc and that
3350 // there is no FEC-FR ssrc + grouping for each.
3351 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
3352 ASSERT_TRUE(offer.get() != nullptr);
3353 MediaContentDescription* media_desc =
3354 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3355 ASSERT_TRUE(media_desc);
3356 VideoContentDescription* desc = media_desc->as_video();
3357 const StreamParamsVec& streams = desc->streams();
3358 // Single stream.
3359 ASSERT_EQ(1u, streams.size());
3360 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
3361 EXPECT_EQ(2u, streams[0].ssrcs.size());
3362 // And should have a FEC-FR group for FlexFEC.
3363 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
3364 std::vector<uint32_t> primary_ssrcs;
3365 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3366 ASSERT_EQ(1u, primary_ssrcs.size());
3367 uint32_t flexfec_ssrc;
3368 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
3369 EXPECT_NE(flexfec_ssrc, 0u);
3370 }
3371
3372 // Test that FlexFEC is disabled for simulcast.
3373 // TODO(brandtr): Remove this test when we support simulcast, either through
3374 // multiple FlexfecSenders, or through multistream protection.
TEST_F(MediaSessionDescriptionFactoryTest,SimSsrcsGenerateNoFlexfecSsrcs)3375 TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
3376 webrtc::test::ScopedKeyValueConfig override_field_trials(
3377 field_trials, "WebRTC-FlexFEC-03/Enabled/");
3378 MediaSessionOptions opts;
3379 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3380 RtpTransceiverDirection::kSendRecv, kActive,
3381 &opts);
3382 // Add simulcast streams.
3383 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3384 {"stream1label"}, 3, &opts);
3385
3386 // Use a single real codec, and then add FlexFEC for it.
3387 std::vector<VideoCodec> f1_codecs;
3388 f1_codecs.push_back(VideoCodec(97, "H264"));
3389 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
3390 f1_.set_video_codecs(f1_codecs, f1_codecs);
3391
3392 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
3393 // there is no FEC-FR ssrc + grouping for each.
3394 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
3395 ASSERT_TRUE(offer.get() != nullptr);
3396 MediaContentDescription* media_desc =
3397 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3398 ASSERT_TRUE(media_desc);
3399 VideoContentDescription* desc = media_desc->as_video();
3400 const StreamParamsVec& streams = desc->streams();
3401 // Single stream.
3402 ASSERT_EQ(1u, streams.size());
3403 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
3404 EXPECT_EQ(3u, streams[0].ssrcs.size());
3405 // And should have a SIM group for the simulcast.
3406 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3407 // And not a FEC-FR group for FlexFEC.
3408 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
3409 std::vector<uint32_t> primary_ssrcs;
3410 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3411 EXPECT_EQ(3u, primary_ssrcs.size());
3412 for (uint32_t primary_ssrc : primary_ssrcs) {
3413 uint32_t flexfec_ssrc;
3414 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
3415 }
3416 }
3417
3418 // Create an updated offer after creating an answer to the original offer and
3419 // verify that the RTP header extensions that were part of the original answer
3420 // are not changed in the updated offer.
TEST_F(MediaSessionDescriptionFactoryTest,RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions)3421 TEST_F(MediaSessionDescriptionFactoryTest,
3422 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
3423 MediaSessionOptions opts;
3424 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
3425
3426 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension1),
3427 MAKE_VECTOR(kVideoRtpExtension1), &opts);
3428 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
3429 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension2),
3430 MAKE_VECTOR(kVideoRtpExtension2), &opts);
3431 std::unique_ptr<SessionDescription> answer =
3432 f2_.CreateAnswer(offer.get(), opts, NULL);
3433
3434 EXPECT_EQ(
3435 MAKE_VECTOR(kAudioRtpExtensionAnswer),
3436 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
3437 EXPECT_EQ(
3438 MAKE_VECTOR(kVideoRtpExtensionAnswer),
3439 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
3440
3441 std::unique_ptr<SessionDescription> updated_offer(
3442 f2_.CreateOffer(opts, answer.get()));
3443
3444 // The expected RTP header extensions in the new offer are the resulting
3445 // extensions from the first offer/answer exchange plus the extensions only
3446 // `f2_` offer.
3447 // Since the default local extension id `f2_` uses has already been used by
3448 // `f1_` for another extensions, it is changed to 13.
3449 const RtpExtension kUpdatedAudioRtpExtensions[] = {
3450 kAudioRtpExtensionAnswer[0],
3451 RtpExtension(kAudioRtpExtension2[1].uri, 13),
3452 kAudioRtpExtension2[2],
3453 };
3454
3455 // Since the default local extension id `f2_` uses has already been used by
3456 // `f1_` for another extensions, is is changed to 12.
3457 const RtpExtension kUpdatedVideoRtpExtensions[] = {
3458 kVideoRtpExtensionAnswer[0],
3459 RtpExtension(kVideoRtpExtension2[1].uri, 12),
3460 kVideoRtpExtension2[2],
3461 };
3462
3463 const AudioContentDescription* updated_acd =
3464 GetFirstAudioContentDescription(updated_offer.get());
3465 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
3466 updated_acd->rtp_header_extensions());
3467
3468 const VideoContentDescription* updated_vcd =
3469 GetFirstVideoContentDescription(updated_offer.get());
3470 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
3471 updated_vcd->rtp_header_extensions());
3472 }
3473
3474 // Verify that if the same RTP extension URI is used for audio and video, the
3475 // same ID is used. Also verify that the ID isn't changed when creating an
3476 // updated offer (this was previously a bug).
TEST_F(MediaSessionDescriptionFactoryTest,RtpExtensionIdReused)3477 TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
3478 MediaSessionOptions opts;
3479 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
3480
3481 SetAudioVideoRtpHeaderExtensions(MAKE_VECTOR(kAudioRtpExtension3),
3482 MAKE_VECTOR(kVideoRtpExtension3), &opts);
3483 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
3484
3485 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
3486 // the video extensions.
3487 const RtpExtension kExpectedVideoRtpExtension[] = {
3488 kVideoRtpExtension3[0],
3489 kAudioRtpExtension3[1],
3490 };
3491
3492 EXPECT_EQ(
3493 MAKE_VECTOR(kAudioRtpExtension3),
3494 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3495 EXPECT_EQ(
3496 MAKE_VECTOR(kExpectedVideoRtpExtension),
3497 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
3498
3499 // Nothing should change when creating a new offer
3500 std::unique_ptr<SessionDescription> updated_offer(
3501 f1_.CreateOffer(opts, offer.get()));
3502
3503 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
3504 GetFirstAudioContentDescription(updated_offer.get())
3505 ->rtp_header_extensions());
3506 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
3507 GetFirstVideoContentDescription(updated_offer.get())
3508 ->rtp_header_extensions());
3509 }
3510
3511 // Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
TEST_F(MediaSessionDescriptionFactoryTest,RtpExtensionIdReusedEncrypted)3512 TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
3513 MediaSessionOptions opts;
3514 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
3515
3516 f1_.set_enable_encrypted_rtp_header_extensions(true);
3517 f2_.set_enable_encrypted_rtp_header_extensions(true);
3518
3519 SetAudioVideoRtpHeaderExtensions(
3520 MAKE_VECTOR(kAudioRtpExtension3ForEncryption),
3521 MAKE_VECTOR(kVideoRtpExtension3ForEncryption), &opts);
3522 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
3523
3524 EXPECT_EQ(
3525 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
3526 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3527 EXPECT_EQ(
3528 MAKE_VECTOR(kVideoRtpExtension3ForEncryptionOffer),
3529 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
3530
3531 // Nothing should change when creating a new offer
3532 std::unique_ptr<SessionDescription> updated_offer(
3533 f1_.CreateOffer(opts, offer.get()));
3534
3535 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
3536 GetFirstAudioContentDescription(updated_offer.get())
3537 ->rtp_header_extensions());
3538 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtension3ForEncryptionOffer),
3539 GetFirstVideoContentDescription(updated_offer.get())
3540 ->rtp_header_extensions());
3541 }
3542
TEST(MediaSessionDescription,CopySessionDescription)3543 TEST(MediaSessionDescription, CopySessionDescription) {
3544 SessionDescription source;
3545 cricket::ContentGroup group(cricket::CN_AUDIO);
3546 source.AddGroup(group);
3547 std::unique_ptr<AudioContentDescription> acd =
3548 std::make_unique<AudioContentDescription>();
3549 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
3550 acd->AddLegacyStream(1);
3551 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp, acd->Clone());
3552 std::unique_ptr<VideoContentDescription> vcd =
3553 std::make_unique<VideoContentDescription>();
3554 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
3555 vcd->AddLegacyStream(2);
3556 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp, vcd->Clone());
3557
3558 std::unique_ptr<SessionDescription> copy = source.Clone();
3559 ASSERT_TRUE(copy.get() != NULL);
3560 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
3561 const ContentInfo* ac = copy->GetContentByName("audio");
3562 const ContentInfo* vc = copy->GetContentByName("video");
3563 ASSERT_TRUE(ac != NULL);
3564 ASSERT_TRUE(vc != NULL);
3565 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
3566 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
3567 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
3568 EXPECT_EQ(1u, acd->first_ssrc());
3569
3570 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
3571 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
3572 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
3573 EXPECT_EQ(2u, vcd->first_ssrc());
3574 }
3575
3576 // The below TestTransportInfoXXX tests create different offers/answers, and
3577 // ensure the TransportInfo in the SessionDescription matches what we expect.
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoOfferAudio)3578 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
3579 MediaSessionOptions options;
3580 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3581 RtpTransceiverDirection::kRecvOnly, kActive,
3582 &options);
3583 TestTransportInfo(true, options, false);
3584 }
3585
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoOfferIceRenomination)3586 TEST_F(MediaSessionDescriptionFactoryTest,
3587 TestTransportInfoOfferIceRenomination) {
3588 MediaSessionOptions options;
3589 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3590 RtpTransceiverDirection::kRecvOnly, kActive,
3591 &options);
3592 options.media_description_options[0]
3593 .transport_options.enable_ice_renomination = true;
3594 TestTransportInfo(true, options, false);
3595 }
3596
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoOfferAudioCurrent)3597 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
3598 MediaSessionOptions options;
3599 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3600 RtpTransceiverDirection::kRecvOnly, kActive,
3601 &options);
3602 TestTransportInfo(true, options, true);
3603 }
3604
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoOfferMultimedia)3605 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
3606 MediaSessionOptions options;
3607 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3608 TestTransportInfo(true, options, false);
3609 }
3610
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoOfferMultimediaCurrent)3611 TEST_F(MediaSessionDescriptionFactoryTest,
3612 TestTransportInfoOfferMultimediaCurrent) {
3613 MediaSessionOptions options;
3614 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3615 TestTransportInfo(true, options, true);
3616 }
3617
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoOfferBundle)3618 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
3619 MediaSessionOptions options;
3620 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3621 options.bundle_enabled = true;
3622 TestTransportInfo(true, options, false);
3623 }
3624
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoOfferBundleCurrent)3625 TEST_F(MediaSessionDescriptionFactoryTest,
3626 TestTransportInfoOfferBundleCurrent) {
3627 MediaSessionOptions options;
3628 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3629 options.bundle_enabled = true;
3630 TestTransportInfo(true, options, true);
3631 }
3632
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoAnswerAudio)3633 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
3634 MediaSessionOptions options;
3635 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3636 RtpTransceiverDirection::kRecvOnly, kActive,
3637 &options);
3638 TestTransportInfo(false, options, false);
3639 }
3640
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoAnswerIceRenomination)3641 TEST_F(MediaSessionDescriptionFactoryTest,
3642 TestTransportInfoAnswerIceRenomination) {
3643 MediaSessionOptions options;
3644 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3645 RtpTransceiverDirection::kRecvOnly, kActive,
3646 &options);
3647 options.media_description_options[0]
3648 .transport_options.enable_ice_renomination = true;
3649 TestTransportInfo(false, options, false);
3650 }
3651
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoAnswerAudioCurrent)3652 TEST_F(MediaSessionDescriptionFactoryTest,
3653 TestTransportInfoAnswerAudioCurrent) {
3654 MediaSessionOptions options;
3655 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3656 RtpTransceiverDirection::kRecvOnly, kActive,
3657 &options);
3658 TestTransportInfo(false, options, true);
3659 }
3660
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoAnswerMultimedia)3661 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
3662 MediaSessionOptions options;
3663 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3664 TestTransportInfo(false, options, false);
3665 }
3666
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoAnswerMultimediaCurrent)3667 TEST_F(MediaSessionDescriptionFactoryTest,
3668 TestTransportInfoAnswerMultimediaCurrent) {
3669 MediaSessionOptions options;
3670 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3671 TestTransportInfo(false, options, true);
3672 }
3673
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoAnswerBundle)3674 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
3675 MediaSessionOptions options;
3676 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3677 options.bundle_enabled = true;
3678 TestTransportInfo(false, options, false);
3679 }
3680
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoAnswerBundleCurrent)3681 TEST_F(MediaSessionDescriptionFactoryTest,
3682 TestTransportInfoAnswerBundleCurrent) {
3683 MediaSessionOptions options;
3684 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3685 options.bundle_enabled = true;
3686 TestTransportInfo(false, options, true);
3687 }
3688
3689 // Create an offer with bundle enabled and verify the crypto parameters are
3690 // the common set of the available cryptos.
TEST_F(MediaSessionDescriptionFactoryTest,TestCryptoWithOfferBundle)3691 TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
3692 TestCryptoWithBundle(true);
3693 }
3694
3695 // Create an answer with bundle enabled and verify the crypto parameters are
3696 // the common set of the available cryptos.
TEST_F(MediaSessionDescriptionFactoryTest,TestCryptoWithAnswerBundle)3697 TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
3698 TestCryptoWithBundle(false);
3699 }
3700
3701 // Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
3702 // DTLS is not enabled locally.
TEST_F(MediaSessionDescriptionFactoryTest,TestOfferDtlsSavpfWithoutDtlsFailed)3703 TEST_F(MediaSessionDescriptionFactoryTest,
3704 TestOfferDtlsSavpfWithoutDtlsFailed) {
3705 f1_.set_secure(SEC_ENABLED);
3706 f2_.set_secure(SEC_ENABLED);
3707 tdf1_.set_secure(SEC_DISABLED);
3708 tdf2_.set_secure(SEC_DISABLED);
3709
3710 std::unique_ptr<SessionDescription> offer =
3711 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
3712 ASSERT_TRUE(offer.get() != NULL);
3713 ContentInfo* offer_content = offer->GetContentByName("audio");
3714 ASSERT_TRUE(offer_content != NULL);
3715 AudioContentDescription* offer_audio_desc =
3716 offer_content->media_description()->as_audio();
3717 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3718
3719 std::unique_ptr<SessionDescription> answer =
3720 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
3721 ASSERT_TRUE(answer != NULL);
3722 ContentInfo* answer_content = answer->GetContentByName("audio");
3723 ASSERT_TRUE(answer_content != NULL);
3724
3725 ASSERT_TRUE(answer_content->rejected);
3726 }
3727
3728 // Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
3729 // UDP/TLS/RTP/SAVPF.
TEST_F(MediaSessionDescriptionFactoryTest,TestOfferDtlsSavpfCreateAnswer)3730 TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
3731 f1_.set_secure(SEC_ENABLED);
3732 f2_.set_secure(SEC_ENABLED);
3733 tdf1_.set_secure(SEC_ENABLED);
3734 tdf2_.set_secure(SEC_ENABLED);
3735
3736 std::unique_ptr<SessionDescription> offer =
3737 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
3738 ASSERT_TRUE(offer.get() != NULL);
3739 ContentInfo* offer_content = offer->GetContentByName("audio");
3740 ASSERT_TRUE(offer_content != NULL);
3741 AudioContentDescription* offer_audio_desc =
3742 offer_content->media_description()->as_audio();
3743 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3744
3745 std::unique_ptr<SessionDescription> answer =
3746 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
3747 ASSERT_TRUE(answer != NULL);
3748
3749 const ContentInfo* answer_content = answer->GetContentByName("audio");
3750 ASSERT_TRUE(answer_content != NULL);
3751 ASSERT_FALSE(answer_content->rejected);
3752
3753 const AudioContentDescription* answer_audio_desc =
3754 answer_content->media_description()->as_audio();
3755 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
3756 }
3757
3758 // Test that we include both SDES and DTLS in the offer, but only include SDES
3759 // in the answer if DTLS isn't negotiated.
TEST_F(MediaSessionDescriptionFactoryTest,TestCryptoDtls)3760 TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
3761 f1_.set_secure(SEC_ENABLED);
3762 f2_.set_secure(SEC_ENABLED);
3763 tdf1_.set_secure(SEC_ENABLED);
3764 tdf2_.set_secure(SEC_DISABLED);
3765 MediaSessionOptions options;
3766 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3767 std::unique_ptr<SessionDescription> offer, answer;
3768 const cricket::MediaContentDescription* audio_media_desc;
3769 const cricket::MediaContentDescription* video_media_desc;
3770 const cricket::TransportDescription* audio_trans_desc;
3771 const cricket::TransportDescription* video_trans_desc;
3772
3773 // Generate an offer with SDES and DTLS support.
3774 offer = f1_.CreateOffer(options, NULL);
3775 ASSERT_TRUE(offer.get() != NULL);
3776
3777 audio_media_desc = offer->GetContentDescriptionByName("audio");
3778 ASSERT_TRUE(audio_media_desc != NULL);
3779 video_media_desc = offer->GetContentDescriptionByName("video");
3780 ASSERT_TRUE(video_media_desc != NULL);
3781 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3782 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3783
3784 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3785 ASSERT_TRUE(audio_trans_desc != NULL);
3786 video_trans_desc = offer->GetTransportDescriptionByName("video");
3787 ASSERT_TRUE(video_trans_desc != NULL);
3788 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3789 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3790
3791 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
3792 answer = f2_.CreateAnswer(offer.get(), options, NULL);
3793 ASSERT_TRUE(answer.get() != NULL);
3794
3795 audio_media_desc = answer->GetContentDescriptionByName("audio");
3796 ASSERT_TRUE(audio_media_desc != NULL);
3797 video_media_desc = answer->GetContentDescriptionByName("video");
3798 ASSERT_TRUE(video_media_desc != NULL);
3799 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3800 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3801
3802 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3803 ASSERT_TRUE(audio_trans_desc != NULL);
3804 video_trans_desc = answer->GetTransportDescriptionByName("video");
3805 ASSERT_TRUE(video_trans_desc != NULL);
3806 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
3807 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
3808
3809 // Enable DTLS; the answer should now only have DTLS support.
3810 tdf2_.set_secure(SEC_ENABLED);
3811 answer = f2_.CreateAnswer(offer.get(), options, NULL);
3812 ASSERT_TRUE(answer.get() != NULL);
3813
3814 audio_media_desc = answer->GetContentDescriptionByName("audio");
3815 ASSERT_TRUE(audio_media_desc != NULL);
3816 video_media_desc = answer->GetContentDescriptionByName("video");
3817 ASSERT_TRUE(video_media_desc != NULL);
3818 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3819 EXPECT_TRUE(video_media_desc->cryptos().empty());
3820 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
3821 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
3822
3823 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3824 ASSERT_TRUE(audio_trans_desc != NULL);
3825 video_trans_desc = answer->GetTransportDescriptionByName("video");
3826 ASSERT_TRUE(video_trans_desc != NULL);
3827 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3828 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3829
3830 // Try creating offer again. DTLS enabled now, crypto's should be empty
3831 // in new offer.
3832 offer = f1_.CreateOffer(options, offer.get());
3833 ASSERT_TRUE(offer.get() != NULL);
3834 audio_media_desc = offer->GetContentDescriptionByName("audio");
3835 ASSERT_TRUE(audio_media_desc != NULL);
3836 video_media_desc = offer->GetContentDescriptionByName("video");
3837 ASSERT_TRUE(video_media_desc != NULL);
3838 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3839 EXPECT_TRUE(video_media_desc->cryptos().empty());
3840
3841 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3842 ASSERT_TRUE(audio_trans_desc != NULL);
3843 video_trans_desc = offer->GetTransportDescriptionByName("video");
3844 ASSERT_TRUE(video_trans_desc != NULL);
3845 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3846 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3847 }
3848
3849 // Test that an answer can't be created if cryptos are required but the offer is
3850 // unsecure.
TEST_F(MediaSessionDescriptionFactoryTest,TestSecureAnswerToUnsecureOffer)3851 TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
3852 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
3853 f1_.set_secure(SEC_DISABLED);
3854 tdf1_.set_secure(SEC_DISABLED);
3855 f2_.set_secure(SEC_REQUIRED);
3856 tdf1_.set_secure(SEC_ENABLED);
3857
3858 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
3859 ASSERT_TRUE(offer.get() != NULL);
3860 std::unique_ptr<SessionDescription> answer =
3861 f2_.CreateAnswer(offer.get(), options, NULL);
3862 EXPECT_TRUE(answer.get() == NULL);
3863 }
3864
3865 // Test that we accept a DTLS offer without SDES and create an appropriate
3866 // answer.
TEST_F(MediaSessionDescriptionFactoryTest,TestCryptoOfferDtlsButNotSdes)3867 TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
3868 f1_.set_secure(SEC_DISABLED);
3869 f2_.set_secure(SEC_ENABLED);
3870 tdf1_.set_secure(SEC_ENABLED);
3871 tdf2_.set_secure(SEC_ENABLED);
3872 MediaSessionOptions options;
3873 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3874
3875 // Generate an offer with DTLS but without SDES.
3876 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
3877 ASSERT_TRUE(offer.get() != NULL);
3878
3879 const AudioContentDescription* audio_offer =
3880 GetFirstAudioContentDescription(offer.get());
3881 ASSERT_TRUE(audio_offer->cryptos().empty());
3882 const VideoContentDescription* video_offer =
3883 GetFirstVideoContentDescription(offer.get());
3884 ASSERT_TRUE(video_offer->cryptos().empty());
3885
3886 const cricket::TransportDescription* audio_offer_trans_desc =
3887 offer->GetTransportDescriptionByName("audio");
3888 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
3889 const cricket::TransportDescription* video_offer_trans_desc =
3890 offer->GetTransportDescriptionByName("video");
3891 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
3892
3893 // Generate an answer with DTLS.
3894 std::unique_ptr<SessionDescription> answer =
3895 f2_.CreateAnswer(offer.get(), options, NULL);
3896 ASSERT_TRUE(answer.get() != NULL);
3897
3898 const cricket::TransportDescription* audio_answer_trans_desc =
3899 answer->GetTransportDescriptionByName("audio");
3900 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3901 const cricket::TransportDescription* video_answer_trans_desc =
3902 answer->GetTransportDescriptionByName("video");
3903 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
3904 }
3905
3906 // Verifies if vad_enabled option is set to false, CN codecs are not present in
3907 // offer or answer.
TEST_F(MediaSessionDescriptionFactoryTest,TestVADEnableOption)3908 TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3909 MediaSessionOptions options;
3910 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3911 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
3912 ASSERT_TRUE(offer.get() != NULL);
3913 const ContentInfo* audio_content = offer->GetContentByName("audio");
3914 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
3915
3916 options.vad_enabled = false;
3917 offer = f1_.CreateOffer(options, NULL);
3918 ASSERT_TRUE(offer.get() != NULL);
3919 audio_content = offer->GetContentByName("audio");
3920 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
3921 std::unique_ptr<SessionDescription> answer =
3922 f1_.CreateAnswer(offer.get(), options, NULL);
3923 ASSERT_TRUE(answer.get() != NULL);
3924 audio_content = answer->GetContentByName("audio");
3925 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
3926 }
3927
3928 // Test that the generated MIDs match the existing offer.
TEST_F(MediaSessionDescriptionFactoryTest,TestMIDsMatchesExistingOffer)3929 TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
3930 MediaSessionOptions opts;
3931 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_modified",
3932 RtpTransceiverDirection::kRecvOnly, kActive,
3933 &opts);
3934 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_modified",
3935 RtpTransceiverDirection::kRecvOnly, kActive,
3936 &opts);
3937 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data_modified",
3938 RtpTransceiverDirection::kSendRecv, kActive,
3939 &opts);
3940 // Create offer.
3941 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
3942 std::unique_ptr<SessionDescription> updated_offer(
3943 f1_.CreateOffer(opts, offer.get()));
3944
3945 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3946 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3947 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3948 ASSERT_TRUE(audio_content != nullptr);
3949 ASSERT_TRUE(video_content != nullptr);
3950 ASSERT_TRUE(data_content != nullptr);
3951 EXPECT_EQ("audio_modified", audio_content->name);
3952 EXPECT_EQ("video_modified", video_content->name);
3953 EXPECT_EQ("data_modified", data_content->name);
3954 }
3955
3956 // The following tests verify that the unified plan SDP is supported.
3957 // Test that we can create an offer with multiple media sections of same media
3958 // type.
TEST_F(MediaSessionDescriptionFactoryTest,CreateOfferWithMultipleAVMediaSections)3959 TEST_F(MediaSessionDescriptionFactoryTest,
3960 CreateOfferWithMultipleAVMediaSections) {
3961 MediaSessionOptions opts;
3962 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3963 RtpTransceiverDirection::kSendRecv, kActive,
3964 &opts);
3965 AttachSenderToMediaDescriptionOptions(
3966 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
3967
3968 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3969 RtpTransceiverDirection::kSendRecv, kActive,
3970 &opts);
3971 AttachSenderToMediaDescriptionOptions(
3972 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
3973
3974 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3975 RtpTransceiverDirection::kSendRecv, kActive,
3976 &opts);
3977 AttachSenderToMediaDescriptionOptions(
3978 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
3979
3980 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3981 RtpTransceiverDirection::kSendRecv, kActive,
3982 &opts);
3983 AttachSenderToMediaDescriptionOptions(
3984 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
3985 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
3986 ASSERT_TRUE(offer);
3987
3988 ASSERT_EQ(4u, offer->contents().size());
3989 EXPECT_FALSE(offer->contents()[0].rejected);
3990 const AudioContentDescription* acd =
3991 offer->contents()[0].media_description()->as_audio();
3992 ASSERT_EQ(1u, acd->streams().size());
3993 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
3994 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
3995
3996 EXPECT_FALSE(offer->contents()[1].rejected);
3997 const VideoContentDescription* vcd =
3998 offer->contents()[1].media_description()->as_video();
3999 ASSERT_EQ(1u, vcd->streams().size());
4000 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
4001 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
4002
4003 EXPECT_FALSE(offer->contents()[2].rejected);
4004 acd = offer->contents()[2].media_description()->as_audio();
4005 ASSERT_EQ(1u, acd->streams().size());
4006 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
4007 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
4008
4009 EXPECT_FALSE(offer->contents()[3].rejected);
4010 vcd = offer->contents()[3].media_description()->as_video();
4011 ASSERT_EQ(1u, vcd->streams().size());
4012 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
4013 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
4014 }
4015
4016 // Test that we can create an answer with multiple media sections of same media
4017 // type.
TEST_F(MediaSessionDescriptionFactoryTest,CreateAnswerWithMultipleAVMediaSections)4018 TEST_F(MediaSessionDescriptionFactoryTest,
4019 CreateAnswerWithMultipleAVMediaSections) {
4020 MediaSessionOptions opts;
4021 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
4022 RtpTransceiverDirection::kSendRecv, kActive,
4023 &opts);
4024 AttachSenderToMediaDescriptionOptions(
4025 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
4026
4027 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
4028 RtpTransceiverDirection::kSendRecv, kActive,
4029 &opts);
4030 AttachSenderToMediaDescriptionOptions(
4031 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
4032
4033 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
4034 RtpTransceiverDirection::kSendRecv, kActive,
4035 &opts);
4036 AttachSenderToMediaDescriptionOptions(
4037 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
4038
4039 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
4040 RtpTransceiverDirection::kSendRecv, kActive,
4041 &opts);
4042 AttachSenderToMediaDescriptionOptions(
4043 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
4044
4045 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
4046 ASSERT_TRUE(offer);
4047 std::unique_ptr<SessionDescription> answer =
4048 f2_.CreateAnswer(offer.get(), opts, nullptr);
4049
4050 ASSERT_EQ(4u, answer->contents().size());
4051 EXPECT_FALSE(answer->contents()[0].rejected);
4052 const AudioContentDescription* acd =
4053 answer->contents()[0].media_description()->as_audio();
4054 ASSERT_EQ(1u, acd->streams().size());
4055 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
4056 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
4057
4058 EXPECT_FALSE(answer->contents()[1].rejected);
4059 const VideoContentDescription* vcd =
4060 answer->contents()[1].media_description()->as_video();
4061 ASSERT_EQ(1u, vcd->streams().size());
4062 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
4063 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
4064
4065 EXPECT_FALSE(answer->contents()[2].rejected);
4066 acd = answer->contents()[2].media_description()->as_audio();
4067 ASSERT_EQ(1u, acd->streams().size());
4068 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
4069 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
4070
4071 EXPECT_FALSE(answer->contents()[3].rejected);
4072 vcd = answer->contents()[3].media_description()->as_video();
4073 ASSERT_EQ(1u, vcd->streams().size());
4074 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
4075 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
4076 }
4077
4078 // Test that the media section will be rejected in offer if the corresponding
4079 // MediaDescriptionOptions is stopped by the offerer.
TEST_F(MediaSessionDescriptionFactoryTest,CreateOfferWithMediaSectionStoppedByOfferer)4080 TEST_F(MediaSessionDescriptionFactoryTest,
4081 CreateOfferWithMediaSectionStoppedByOfferer) {
4082 // Create an offer with two audio sections and one of them is stopped.
4083 MediaSessionOptions offer_opts;
4084 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4085 RtpTransceiverDirection::kSendRecv, kActive,
4086 &offer_opts);
4087 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4088 RtpTransceiverDirection::kInactive, kStopped,
4089 &offer_opts);
4090 std::unique_ptr<SessionDescription> offer =
4091 f1_.CreateOffer(offer_opts, nullptr);
4092 ASSERT_TRUE(offer);
4093 ASSERT_EQ(2u, offer->contents().size());
4094 EXPECT_FALSE(offer->contents()[0].rejected);
4095 EXPECT_TRUE(offer->contents()[1].rejected);
4096 }
4097
4098 // Test that the media section will be rejected in answer if the corresponding
4099 // MediaDescriptionOptions is stopped by the offerer.
TEST_F(MediaSessionDescriptionFactoryTest,CreateAnswerWithMediaSectionStoppedByOfferer)4100 TEST_F(MediaSessionDescriptionFactoryTest,
4101 CreateAnswerWithMediaSectionStoppedByOfferer) {
4102 // Create an offer with two audio sections and one of them is stopped.
4103 MediaSessionOptions offer_opts;
4104 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4105 RtpTransceiverDirection::kSendRecv, kActive,
4106 &offer_opts);
4107 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4108 RtpTransceiverDirection::kInactive, kStopped,
4109 &offer_opts);
4110 std::unique_ptr<SessionDescription> offer =
4111 f1_.CreateOffer(offer_opts, nullptr);
4112 ASSERT_TRUE(offer);
4113 ASSERT_EQ(2u, offer->contents().size());
4114 EXPECT_FALSE(offer->contents()[0].rejected);
4115 EXPECT_TRUE(offer->contents()[1].rejected);
4116
4117 // Create an answer based on the offer.
4118 MediaSessionOptions answer_opts;
4119 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4120 RtpTransceiverDirection::kSendRecv, kActive,
4121 &answer_opts);
4122 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4123 RtpTransceiverDirection::kSendRecv, kActive,
4124 &answer_opts);
4125 std::unique_ptr<SessionDescription> answer =
4126 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
4127 ASSERT_EQ(2u, answer->contents().size());
4128 EXPECT_FALSE(answer->contents()[0].rejected);
4129 EXPECT_TRUE(answer->contents()[1].rejected);
4130 }
4131
4132 // Test that the media section will be rejected in answer if the corresponding
4133 // MediaDescriptionOptions is stopped by the answerer.
TEST_F(MediaSessionDescriptionFactoryTest,CreateAnswerWithMediaSectionRejectedByAnswerer)4134 TEST_F(MediaSessionDescriptionFactoryTest,
4135 CreateAnswerWithMediaSectionRejectedByAnswerer) {
4136 // Create an offer with two audio sections.
4137 MediaSessionOptions offer_opts;
4138 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4139 RtpTransceiverDirection::kSendRecv, kActive,
4140 &offer_opts);
4141 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4142 RtpTransceiverDirection::kSendRecv, kActive,
4143 &offer_opts);
4144 std::unique_ptr<SessionDescription> offer =
4145 f1_.CreateOffer(offer_opts, nullptr);
4146 ASSERT_TRUE(offer);
4147 ASSERT_EQ(2u, offer->contents().size());
4148 ASSERT_FALSE(offer->contents()[0].rejected);
4149 ASSERT_FALSE(offer->contents()[1].rejected);
4150
4151 // The answerer rejects one of the audio sections.
4152 MediaSessionOptions answer_opts;
4153 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4154 RtpTransceiverDirection::kSendRecv, kActive,
4155 &answer_opts);
4156 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4157 RtpTransceiverDirection::kInactive, kStopped,
4158 &answer_opts);
4159 std::unique_ptr<SessionDescription> answer =
4160 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
4161 ASSERT_EQ(2u, answer->contents().size());
4162 EXPECT_FALSE(answer->contents()[0].rejected);
4163 EXPECT_TRUE(answer->contents()[1].rejected);
4164
4165 // The TransportInfo of the rejected m= section is expected to be added in the
4166 // answer.
4167 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
4168 }
4169
4170 // Test the generated media sections has the same order of the
4171 // corresponding MediaDescriptionOptions.
TEST_F(MediaSessionDescriptionFactoryTest,CreateOfferRespectsMediaDescriptionOptionsOrder)4172 TEST_F(MediaSessionDescriptionFactoryTest,
4173 CreateOfferRespectsMediaDescriptionOptionsOrder) {
4174 MediaSessionOptions opts;
4175 // This tests put video section first because normally audio comes first by
4176 // default.
4177 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4178 RtpTransceiverDirection::kSendRecv, kActive,
4179 &opts);
4180 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4181 RtpTransceiverDirection::kSendRecv, kActive,
4182 &opts);
4183 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
4184
4185 ASSERT_TRUE(offer);
4186 ASSERT_EQ(2u, offer->contents().size());
4187 EXPECT_EQ("video", offer->contents()[0].name);
4188 EXPECT_EQ("audio", offer->contents()[1].name);
4189 }
4190
4191 // Test that different media sections using the same codec have same payload
4192 // type.
TEST_F(MediaSessionDescriptionFactoryTest,PayloadTypesSharedByMediaSectionsOfSameType)4193 TEST_F(MediaSessionDescriptionFactoryTest,
4194 PayloadTypesSharedByMediaSectionsOfSameType) {
4195 MediaSessionOptions opts;
4196 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4197 RtpTransceiverDirection::kSendRecv, kActive,
4198 &opts);
4199 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4200 RtpTransceiverDirection::kSendRecv, kActive,
4201 &opts);
4202 // Create an offer with two video sections using same codecs.
4203 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
4204 ASSERT_TRUE(offer);
4205 ASSERT_EQ(2u, offer->contents().size());
4206 const VideoContentDescription* vcd1 =
4207 offer->contents()[0].media_description()->as_video();
4208 const VideoContentDescription* vcd2 =
4209 offer->contents()[1].media_description()->as_video();
4210 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4211 ASSERT_EQ(2u, vcd1->codecs().size());
4212 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4213 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4214 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
4215 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
4216
4217 // Create answer and negotiate the codecs.
4218 std::unique_ptr<SessionDescription> answer =
4219 f2_.CreateAnswer(offer.get(), opts, nullptr);
4220 ASSERT_TRUE(answer);
4221 ASSERT_EQ(2u, answer->contents().size());
4222 vcd1 = answer->contents()[0].media_description()->as_video();
4223 vcd2 = answer->contents()[1].media_description()->as_video();
4224 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4225 ASSERT_EQ(1u, vcd1->codecs().size());
4226 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4227 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4228 }
4229
4230 // Test that the codec preference order per media section is respected in
4231 // subsequent offer.
TEST_F(MediaSessionDescriptionFactoryTest,CreateOfferRespectsCodecPreferenceOrder)4232 TEST_F(MediaSessionDescriptionFactoryTest,
4233 CreateOfferRespectsCodecPreferenceOrder) {
4234 MediaSessionOptions opts;
4235 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4236 RtpTransceiverDirection::kSendRecv, kActive,
4237 &opts);
4238 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4239 RtpTransceiverDirection::kSendRecv, kActive,
4240 &opts);
4241 // Create an offer with two video sections using same codecs.
4242 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
4243 ASSERT_TRUE(offer);
4244 ASSERT_EQ(2u, offer->contents().size());
4245 VideoContentDescription* vcd1 =
4246 offer->contents()[0].media_description()->as_video();
4247 const VideoContentDescription* vcd2 =
4248 offer->contents()[1].media_description()->as_video();
4249 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4250 EXPECT_EQ(video_codecs, vcd1->codecs());
4251 EXPECT_EQ(video_codecs, vcd2->codecs());
4252
4253 // Change the codec preference of the first video section and create a
4254 // follow-up offer.
4255 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4256 vcd1->set_codecs(video_codecs_reverse);
4257 std::unique_ptr<SessionDescription> updated_offer(
4258 f1_.CreateOffer(opts, offer.get()));
4259 vcd1 = updated_offer->contents()[0].media_description()->as_video();
4260 vcd2 = updated_offer->contents()[1].media_description()->as_video();
4261 // The video codec preference order should be respected.
4262 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4263 EXPECT_EQ(video_codecs, vcd2->codecs());
4264 }
4265
4266 // Test that the codec preference order per media section is respected in
4267 // the answer.
TEST_F(MediaSessionDescriptionFactoryTest,CreateAnswerRespectsCodecPreferenceOrder)4268 TEST_F(MediaSessionDescriptionFactoryTest,
4269 CreateAnswerRespectsCodecPreferenceOrder) {
4270 MediaSessionOptions opts;
4271 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4272 RtpTransceiverDirection::kSendRecv, kActive,
4273 &opts);
4274 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4275 RtpTransceiverDirection::kSendRecv, kActive,
4276 &opts);
4277 // Create an offer with two video sections using same codecs.
4278 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
4279 ASSERT_TRUE(offer);
4280 ASSERT_EQ(2u, offer->contents().size());
4281 VideoContentDescription* vcd1 =
4282 offer->contents()[0].media_description()->as_video();
4283 const VideoContentDescription* vcd2 =
4284 offer->contents()[1].media_description()->as_video();
4285 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4286 EXPECT_EQ(video_codecs, vcd1->codecs());
4287 EXPECT_EQ(video_codecs, vcd2->codecs());
4288
4289 // Change the codec preference of the first video section and create an
4290 // answer.
4291 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4292 vcd1->set_codecs(video_codecs_reverse);
4293 std::unique_ptr<SessionDescription> answer =
4294 f1_.CreateAnswer(offer.get(), opts, nullptr);
4295 vcd1 = answer->contents()[0].media_description()->as_video();
4296 vcd2 = answer->contents()[1].media_description()->as_video();
4297 // The video codec preference order should be respected.
4298 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4299 EXPECT_EQ(video_codecs, vcd2->codecs());
4300 }
4301
4302 // Test that when creating an answer, the codecs use local parameters instead of
4303 // the remote ones.
TEST_F(MediaSessionDescriptionFactoryTest,CreateAnswerWithLocalCodecParams)4304 TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
4305 const std::string audio_param_name = "audio_param";
4306 const std::string audio_value1 = "audio_v1";
4307 const std::string audio_value2 = "audio_v2";
4308 const std::string video_param_name = "video_param";
4309 const std::string video_value1 = "video_v1";
4310 const std::string video_value2 = "video_v2";
4311
4312 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
4313 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
4314 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
4315 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
4316
4317 // Set the parameters for codecs.
4318 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
4319 video_codecs1[0].SetParam(video_param_name, video_value1);
4320 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
4321 video_codecs2[0].SetParam(video_param_name, video_value2);
4322
4323 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
4324 f1_.set_video_codecs(video_codecs1, video_codecs1);
4325 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
4326 f2_.set_video_codecs(video_codecs2, video_codecs2);
4327
4328 MediaSessionOptions opts;
4329 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4330 RtpTransceiverDirection::kSendRecv, kActive,
4331 &opts);
4332 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4333 RtpTransceiverDirection::kSendRecv, kActive,
4334 &opts);
4335
4336 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
4337 ASSERT_TRUE(offer);
4338 auto offer_acd = offer->contents()[0].media_description()->as_audio();
4339 auto offer_vcd = offer->contents()[1].media_description()->as_video();
4340 std::string value;
4341 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
4342 EXPECT_EQ(audio_value1, value);
4343 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
4344 EXPECT_EQ(video_value1, value);
4345
4346 std::unique_ptr<SessionDescription> answer =
4347 f2_.CreateAnswer(offer.get(), opts, nullptr);
4348 ASSERT_TRUE(answer);
4349 auto answer_acd = answer->contents()[0].media_description()->as_audio();
4350 auto answer_vcd = answer->contents()[1].media_description()->as_video();
4351 // Use the parameters from the local codecs.
4352 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
4353 EXPECT_EQ(audio_value2, value);
4354 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
4355 EXPECT_EQ(video_value2, value);
4356 }
4357
4358 // Test that matching packetization-mode is part of the criteria for matching
4359 // H264 codecs (in addition to profile-level-id). Previously, this was not the
4360 // case, so the first H264 codec with the same profile-level-id would match and
4361 // the payload type in the answer would be incorrect.
4362 // This is a regression test for bugs.webrtc.org/8808
TEST_F(MediaSessionDescriptionFactoryTest,H264MatchCriteriaIncludesPacketizationMode)4363 TEST_F(MediaSessionDescriptionFactoryTest,
4364 H264MatchCriteriaIncludesPacketizationMode) {
4365 // Create two H264 codecs with the same profile level ID and different
4366 // packetization modes.
4367 VideoCodec h264_pm0(96, "H264");
4368 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4369 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
4370 VideoCodec h264_pm1(97, "H264");
4371 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4372 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
4373
4374 // Offerer will send both codecs, answerer should choose the one with matching
4375 // packetization mode (and not the first one it sees).
4376 f1_.set_video_codecs({h264_pm0, h264_pm1}, {h264_pm0, h264_pm1});
4377 f2_.set_video_codecs({h264_pm1}, {h264_pm1});
4378
4379 MediaSessionOptions opts;
4380 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4381 RtpTransceiverDirection::kSendRecv, kActive,
4382 &opts);
4383
4384 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
4385 ASSERT_TRUE(offer);
4386
4387 std::unique_ptr<SessionDescription> answer =
4388 f2_.CreateAnswer(offer.get(), opts, nullptr);
4389 ASSERT_TRUE(answer);
4390
4391 // Answer should have one negotiated codec with packetization-mode=1 using the
4392 // offered payload type.
4393 ASSERT_EQ(1u, answer->contents().size());
4394 auto answer_vcd = answer->contents()[0].media_description()->as_video();
4395 ASSERT_EQ(1u, answer_vcd->codecs().size());
4396 auto answer_codec = answer_vcd->codecs()[0];
4397 EXPECT_EQ(h264_pm1.id, answer_codec.id);
4398 }
4399
4400 class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
4401 public:
MediaProtocolTest()4402 MediaProtocolTest()
4403 : tdf1_(field_trials_),
4404 tdf2_(field_trials_),
4405 f1_(&tdf1_, &ssrc_generator1),
4406 f2_(&tdf2_, &ssrc_generator2) {
4407 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
4408 MAKE_VECTOR(kAudioCodecs1));
4409 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1),
4410 MAKE_VECTOR(kVideoCodecs1));
4411 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
4412 MAKE_VECTOR(kAudioCodecs2));
4413 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2),
4414 MAKE_VECTOR(kVideoCodecs2));
4415 f1_.set_secure(SEC_ENABLED);
4416 f2_.set_secure(SEC_ENABLED);
4417 tdf1_.set_certificate(rtc::RTCCertificate::Create(
4418 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
4419 tdf2_.set_certificate(rtc::RTCCertificate::Create(
4420 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
4421 tdf1_.set_secure(SEC_ENABLED);
4422 tdf2_.set_secure(SEC_ENABLED);
4423 }
4424
4425 protected:
4426 webrtc::test::ScopedKeyValueConfig field_trials_;
4427 TransportDescriptionFactory tdf1_;
4428 TransportDescriptionFactory tdf2_;
4429 MediaSessionDescriptionFactory f1_;
4430 MediaSessionDescriptionFactory f2_;
4431 UniqueRandomIdGenerator ssrc_generator1;
4432 UniqueRandomIdGenerator ssrc_generator2;
4433 };
4434
TEST_P(MediaProtocolTest,TestAudioVideoAcceptance)4435 TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
4436 MediaSessionOptions opts;
4437 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
4438 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
4439 ASSERT_TRUE(offer.get() != nullptr);
4440 // Set the protocol for all the contents.
4441 for (auto& content : offer.get()->contents()) {
4442 content.media_description()->set_protocol(GetParam());
4443 }
4444 std::unique_ptr<SessionDescription> answer =
4445 f2_.CreateAnswer(offer.get(), opts, nullptr);
4446 const ContentInfo* ac = answer->GetContentByName("audio");
4447 const ContentInfo* vc = answer->GetContentByName("video");
4448 ASSERT_TRUE(ac != nullptr);
4449 ASSERT_TRUE(vc != nullptr);
4450 EXPECT_FALSE(ac->rejected); // the offer is accepted
4451 EXPECT_FALSE(vc->rejected);
4452 const AudioContentDescription* acd = ac->media_description()->as_audio();
4453 const VideoContentDescription* vcd = vc->media_description()->as_video();
4454 EXPECT_EQ(GetParam(), acd->protocol());
4455 EXPECT_EQ(GetParam(), vcd->protocol());
4456 }
4457
4458 INSTANTIATE_TEST_SUITE_P(MediaProtocolPatternTest,
4459 MediaProtocolTest,
4460 ::testing::ValuesIn(kMediaProtocols));
4461 INSTANTIATE_TEST_SUITE_P(MediaProtocolDtlsPatternTest,
4462 MediaProtocolTest,
4463 ::testing::ValuesIn(kMediaProtocolsDtls));
4464
TEST_F(MediaSessionDescriptionFactoryTest,TestSetAudioCodecs)4465 TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
4466 webrtc::test::ScopedKeyValueConfig field_trials;
4467 TransportDescriptionFactory tdf(field_trials);
4468 UniqueRandomIdGenerator ssrc_generator;
4469 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
4470 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4471 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4472
4473 // The merged list of codecs should contain any send codecs that are also
4474 // nominally in the receive codecs list. Payload types should be picked from
4475 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
4476 // (set to 1). This equals what happens when the send codecs are used in an
4477 // offer and the receive codecs are used in the following answer.
4478 const std::vector<AudioCodec> sendrecv_codecs =
4479 MAKE_VECTOR(kAudioCodecsAnswer);
4480 const std::vector<AudioCodec> no_codecs;
4481
4482 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
4483 << "Please don't change shared test data!";
4484 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
4485 << "Please don't change shared test data!";
4486 // Alter iLBC send codec to have zero channels, to test that that is handled
4487 // properly.
4488 send_codecs[1].channels = 0;
4489
4490 // Alter iLBC receive codec to be lowercase, to test that case conversions
4491 // are handled properly.
4492 recv_codecs[2].name = "ilbc";
4493
4494 // Test proper merge
4495 sf.set_audio_codecs(send_codecs, recv_codecs);
4496 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4497 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4498 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
4499
4500 // Test empty send codecs list
4501 sf.set_audio_codecs(no_codecs, recv_codecs);
4502 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4503 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4504 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
4505
4506 // Test empty recv codecs list
4507 sf.set_audio_codecs(send_codecs, no_codecs);
4508 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4509 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4510 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
4511
4512 // Test all empty codec lists
4513 sf.set_audio_codecs(no_codecs, no_codecs);
4514 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4515 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4516 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
4517 }
4518
4519 namespace {
4520 // Compare the two vectors of codecs ignoring the payload type.
4521 template <class Codec>
CodecsMatch(const std::vector<Codec> & codecs1,const std::vector<Codec> & codecs2,const webrtc::FieldTrialsView * field_trials)4522 bool CodecsMatch(const std::vector<Codec>& codecs1,
4523 const std::vector<Codec>& codecs2,
4524 const webrtc::FieldTrialsView* field_trials) {
4525 if (codecs1.size() != codecs2.size()) {
4526 return false;
4527 }
4528
4529 for (size_t i = 0; i < codecs1.size(); ++i) {
4530 if (!codecs1[i].Matches(codecs2[i], field_trials)) {
4531 return false;
4532 }
4533 }
4534 return true;
4535 }
4536
TestAudioCodecsOffer(RtpTransceiverDirection direction)4537 void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
4538 webrtc::test::ScopedKeyValueConfig field_trials;
4539 TransportDescriptionFactory tdf(field_trials);
4540 UniqueRandomIdGenerator ssrc_generator;
4541 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
4542 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4543 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4544 const std::vector<AudioCodec> sendrecv_codecs =
4545 MAKE_VECTOR(kAudioCodecsAnswer);
4546 sf.set_audio_codecs(send_codecs, recv_codecs);
4547
4548 MediaSessionOptions opts;
4549 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
4550 &opts);
4551
4552 if (direction == RtpTransceiverDirection::kSendRecv ||
4553 direction == RtpTransceiverDirection::kSendOnly) {
4554 AttachSenderToMediaDescriptionOptions(
4555 "audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
4556 }
4557
4558 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
4559 ASSERT_TRUE(offer.get() != NULL);
4560 ContentInfo* ac = offer->GetContentByName("audio");
4561
4562 // If the factory didn't add any audio content to the offer, we cannot check
4563 // that the codecs put in are right. This happens when we neither want to
4564 // send nor receive audio. The checks are still in place if at some point
4565 // we'd instead create an inactive stream.
4566 if (ac) {
4567 AudioContentDescription* acd = ac->media_description()->as_audio();
4568 // sendrecv and inactive should both present lists as if the channel was
4569 // to be used for sending and receiving. Inactive essentially means it
4570 // might eventually be used anything, but we don't know more at this
4571 // moment.
4572 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
4573 EXPECT_TRUE(
4574 CodecsMatch<AudioCodec>(send_codecs, acd->codecs(), &field_trials));
4575 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
4576 EXPECT_TRUE(
4577 CodecsMatch<AudioCodec>(recv_codecs, acd->codecs(), &field_trials));
4578 } else {
4579 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs(),
4580 &field_trials));
4581 }
4582 }
4583 }
4584
4585 static const AudioCodec kOfferAnswerCodecs[] = {
4586 AudioCodec(0, "codec0", 16000, -1, 1),
4587 AudioCodec(1, "codec1", 8000, 13300, 1),
4588 AudioCodec(2, "codec2", 8000, 64000, 1),
4589 AudioCodec(3, "codec3", 8000, 64000, 1),
4590 AudioCodec(4, "codec4", 8000, 0, 2),
4591 AudioCodec(5, "codec5", 32000, 0, 1),
4592 AudioCodec(6, "codec6", 48000, 0, 1)};
4593
4594 /* The codecs groups below are chosen as per the matrix below. The objective
4595 * is to have different sets of codecs in the inputs, to get unique sets of
4596 * codecs after negotiation, depending on offer and answer communication
4597 * directions. One-way directions in the offer should either result in the
4598 * opposite direction in the answer, or an inactive answer. Regardless, the
4599 * choice of codecs should be as if the answer contained the opposite
4600 * direction. Inactive offers should be treated as sendrecv/sendrecv.
4601 *
4602 * | Offer | Answer | Result
4603 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
4604 * 0 | x - - | - x - | x - - - -
4605 * 1 | x x x | - x - | x - - x -
4606 * 2 | - x - | x - - | - x - - -
4607 * 3 | x x x | x - - | - x x - -
4608 * 4 | - x - | x x x | - x - - -
4609 * 5 | x - - | x x x | x - - - -
4610 * 6 | x x x | x x x | x x x x x
4611 */
4612 // Codecs used by offerer in the AudioCodecsAnswerTest
4613 static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
4614 static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
4615 // Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
4616 // jumbled to catch the answer not following the order in the offer.
4617 static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
4618 static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
4619 // The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
4620 static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
4621 static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
4622 static const int kResultSendrecv_SendCodecs[] = {3, 6};
4623 static const int kResultSendrecv_RecvCodecs[] = {1, 6};
4624 static const int kResultSendrecv_SendrecvCodecs[] = {6};
4625
4626 template <typename T, int IDXS>
VectorFromIndices(const T * array,const int (& indices)[IDXS])4627 std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
4628 std::vector<T> out;
4629 out.reserve(IDXS);
4630 for (int idx : indices)
4631 out.push_back(array[idx]);
4632
4633 return out;
4634 }
4635
TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,RtpTransceiverDirection answer_direction,bool add_legacy_stream)4636 void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
4637 RtpTransceiverDirection answer_direction,
4638 bool add_legacy_stream) {
4639 webrtc::test::ScopedKeyValueConfig field_trials;
4640 TransportDescriptionFactory offer_tdf(field_trials);
4641 TransportDescriptionFactory answer_tdf(field_trials);
4642 UniqueRandomIdGenerator ssrc_generator1, ssrc_generator2;
4643 MediaSessionDescriptionFactory offer_factory(&offer_tdf, &ssrc_generator1);
4644 MediaSessionDescriptionFactory answer_factory(&answer_tdf, &ssrc_generator2);
4645
4646 offer_factory.set_audio_codecs(
4647 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
4648 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
4649 answer_factory.set_audio_codecs(
4650 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
4651 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
4652
4653 MediaSessionOptions offer_opts;
4654 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", offer_direction,
4655 kActive, &offer_opts);
4656
4657 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
4658 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4659 kAudioTrack1, {kMediaStream1}, 1,
4660 &offer_opts);
4661 }
4662
4663 std::unique_ptr<SessionDescription> offer =
4664 offer_factory.CreateOffer(offer_opts, NULL);
4665 ASSERT_TRUE(offer.get() != NULL);
4666
4667 MediaSessionOptions answer_opts;
4668 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", answer_direction,
4669 kActive, &answer_opts);
4670
4671 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
4672 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4673 kAudioTrack1, {kMediaStream1}, 1,
4674 &answer_opts);
4675 }
4676 std::unique_ptr<SessionDescription> answer =
4677 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
4678 const ContentInfo* ac = answer->GetContentByName("audio");
4679
4680 // If the factory didn't add any audio content to the answer, we cannot
4681 // check that the codecs put in are right. This happens when we neither want
4682 // to send nor receive audio. The checks are still in place if at some point
4683 // we'd instead create an inactive stream.
4684 if (ac) {
4685 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
4686 const AudioContentDescription* acd = ac->media_description()->as_audio();
4687
4688 std::vector<AudioCodec> target_codecs;
4689 // For offers with sendrecv or inactive, we should never reply with more
4690 // codecs than offered, with these codec sets.
4691 switch (offer_direction) {
4692 case RtpTransceiverDirection::kInactive:
4693 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4694 kResultSendrecv_SendrecvCodecs);
4695 break;
4696 case RtpTransceiverDirection::kSendOnly:
4697 target_codecs =
4698 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
4699 break;
4700 case RtpTransceiverDirection::kRecvOnly:
4701 target_codecs =
4702 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
4703 break;
4704 case RtpTransceiverDirection::kSendRecv:
4705 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
4706 target_codecs =
4707 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
4708 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
4709 target_codecs =
4710 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
4711 } else {
4712 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4713 kResultSendrecv_SendrecvCodecs);
4714 }
4715 break;
4716 case RtpTransceiverDirection::kStopped:
4717 // This does not happen in any current test.
4718 RTC_DCHECK_NOTREACHED();
4719 }
4720
4721 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
4722 rtc::StringBuilder os;
4723 bool first = true;
4724 os << "{";
4725 for (const auto& c : codecs) {
4726 os << (first ? " " : ", ") << c.id;
4727 first = false;
4728 }
4729 os << " }";
4730 return os.Release();
4731 };
4732
4733 EXPECT_TRUE(acd->codecs() == target_codecs)
4734 << "Expected: " << format_codecs(target_codecs)
4735 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
4736 << webrtc::RtpTransceiverDirectionToString(offer_direction)
4737 << ", answerer wants: "
4738 << webrtc::RtpTransceiverDirectionToString(answer_direction)
4739 << "; got: "
4740 << webrtc::RtpTransceiverDirectionToString(acd->direction());
4741 } else {
4742 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
4743 << "Only inactive offers are allowed to not generate any audio "
4744 "content";
4745 }
4746 }
4747
4748 } // namespace
4749
4750 class AudioCodecsOfferTest
4751 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
4752
TEST_P(AudioCodecsOfferTest,TestCodecsInOffer)4753 TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
4754 TestAudioCodecsOffer(GetParam());
4755 }
4756
4757 INSTANTIATE_TEST_SUITE_P(MediaSessionDescriptionFactoryTest,
4758 AudioCodecsOfferTest,
4759 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4760 RtpTransceiverDirection::kRecvOnly,
4761 RtpTransceiverDirection::kSendRecv,
4762 RtpTransceiverDirection::kInactive));
4763
4764 class AudioCodecsAnswerTest
4765 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
4766 RtpTransceiverDirection,
4767 bool>> {};
4768
TEST_P(AudioCodecsAnswerTest,TestCodecsInAnswer)4769 TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
4770 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
4771 ::testing::get<1>(GetParam()),
4772 ::testing::get<2>(GetParam()));
4773 }
4774
4775 INSTANTIATE_TEST_SUITE_P(
4776 MediaSessionDescriptionFactoryTest,
4777 AudioCodecsAnswerTest,
4778 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
4779 RtpTransceiverDirection::kRecvOnly,
4780 RtpTransceiverDirection::kSendRecv,
4781 RtpTransceiverDirection::kInactive),
4782 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4783 RtpTransceiverDirection::kRecvOnly,
4784 RtpTransceiverDirection::kSendRecv,
4785 RtpTransceiverDirection::kInactive),
4786 ::testing::Bool()));
4787