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