1 /*
2 * libjingle
3 * Copyright 2004 Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include <string>
29 #include <vector>
30
31 #include "talk/media/base/codec.h"
32 #include "talk/media/base/testutils.h"
33 #include "webrtc/p2p/base/constants.h"
34 #include "webrtc/p2p/base/transportdescription.h"
35 #include "webrtc/p2p/base/transportinfo.h"
36 #include "talk/session/media/mediasession.h"
37 #include "talk/session/media/srtpfilter.h"
38 #include "webrtc/base/fakesslidentity.h"
39 #include "webrtc/base/gunit.h"
40 #include "webrtc/base/messagedigest.h"
41 #include "webrtc/base/ssladapter.h"
42
43 #ifdef HAVE_SRTP
44 #define ASSERT_CRYPTO(cd, s, cs) \
45 ASSERT_EQ(cricket::CT_NONE, cd->crypto_required()); \
46 ASSERT_EQ(s, cd->cryptos().size()); \
47 ASSERT_EQ(std::string(cs), cd->cryptos()[0].cipher_suite)
48 #else
49 #define ASSERT_CRYPTO(cd, s, cs) \
50 ASSERT_EQ(cricket::CT_NONE, cd->crypto_required()); \
51 ASSERT_EQ(0U, cd->cryptos().size());
52 #endif
53
54 typedef std::vector<cricket::Candidate> Candidates;
55
56 using cricket::MediaContentDescription;
57 using cricket::MediaSessionDescriptionFactory;
58 using cricket::MediaSessionOptions;
59 using cricket::MediaType;
60 using cricket::SessionDescription;
61 using cricket::SsrcGroup;
62 using cricket::StreamParams;
63 using cricket::StreamParamsVec;
64 using cricket::TransportDescription;
65 using cricket::TransportDescriptionFactory;
66 using cricket::TransportInfo;
67 using cricket::ContentInfo;
68 using cricket::CryptoParamsVec;
69 using cricket::AudioContentDescription;
70 using cricket::VideoContentDescription;
71 using cricket::DataContentDescription;
72 using cricket::GetFirstAudioContent;
73 using cricket::GetFirstVideoContent;
74 using cricket::GetFirstDataContent;
75 using cricket::GetFirstAudioContentDescription;
76 using cricket::GetFirstVideoContentDescription;
77 using cricket::GetFirstDataContentDescription;
78 using cricket::kAutoBandwidth;
79 using cricket::AudioCodec;
80 using cricket::VideoCodec;
81 using cricket::DataCodec;
82 using cricket::NS_JINGLE_RTP;
83 using cricket::MEDIA_TYPE_AUDIO;
84 using cricket::MEDIA_TYPE_VIDEO;
85 using cricket::MEDIA_TYPE_DATA;
86 using cricket::RtpHeaderExtension;
87 using cricket::SEC_DISABLED;
88 using cricket::SEC_ENABLED;
89 using cricket::SEC_REQUIRED;
90 using rtc::CS_AES_CM_128_HMAC_SHA1_32;
91 using rtc::CS_AES_CM_128_HMAC_SHA1_80;
92
93 static const AudioCodec kAudioCodecs1[] = {
94 AudioCodec(103, "ISAC", 16000, -1, 1, 6),
95 AudioCodec(102, "iLBC", 8000, 13300, 1, 5),
96 AudioCodec(0, "PCMU", 8000, 64000, 1, 4),
97 AudioCodec(8, "PCMA", 8000, 64000, 1, 3),
98 AudioCodec(117, "red", 8000, 0, 1, 2),
99 AudioCodec(107, "CN", 48000, 0, 1, 1)
100 };
101
102 static const AudioCodec kAudioCodecs2[] = {
103 AudioCodec(126, "speex", 16000, 22000, 1, 3),
104 AudioCodec(0, "PCMU", 8000, 64000, 1, 2),
105 AudioCodec(127, "iLBC", 8000, 13300, 1, 1),
106 };
107
108 static const AudioCodec kAudioCodecsAnswer[] = {
109 AudioCodec(102, "iLBC", 8000, 13300, 1, 5),
110 AudioCodec(0, "PCMU", 8000, 64000, 1, 4),
111 };
112
113 static const VideoCodec kVideoCodecs1[] = {
114 VideoCodec(96, "H264-SVC", 320, 200, 30, 2),
115 VideoCodec(97, "H264", 320, 200, 30, 1)
116 };
117
118 static const VideoCodec kVideoCodecs2[] = {
119 VideoCodec(126, "H264", 320, 200, 30, 2),
120 VideoCodec(127, "H263", 320, 200, 30, 1)
121 };
122
123 static const VideoCodec kVideoCodecsAnswer[] = {
124 VideoCodec(97, "H264", 320, 200, 30, 1)
125 };
126
127 static const DataCodec kDataCodecs1[] = {
128 DataCodec(98, "binary-data", 2),
129 DataCodec(99, "utf8-text", 1)
130 };
131
132 static const DataCodec kDataCodecs2[] = {
133 DataCodec(126, "binary-data", 2),
134 DataCodec(127, "utf8-text", 1)
135 };
136
137 static const DataCodec kDataCodecsAnswer[] = {
138 DataCodec(98, "binary-data", 2),
139 DataCodec(99, "utf8-text", 1)
140 };
141
142 static const RtpHeaderExtension kAudioRtpExtension1[] = {
143 RtpHeaderExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
144 RtpHeaderExtension("http://google.com/testing/audio_something", 10),
145 };
146
147 static const RtpHeaderExtension kAudioRtpExtension2[] = {
148 RtpHeaderExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
149 RtpHeaderExtension("http://google.com/testing/audio_something_else", 8),
150 RtpHeaderExtension("http://google.com/testing/both_audio_and_video", 7),
151 };
152
153 static const RtpHeaderExtension kAudioRtpExtension3[] = {
154 RtpHeaderExtension("http://google.com/testing/audio_something", 2),
155 RtpHeaderExtension("http://google.com/testing/both_audio_and_video", 3),
156 };
157
158 static const RtpHeaderExtension kAudioRtpExtensionAnswer[] = {
159 RtpHeaderExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
160 };
161
162 static const RtpHeaderExtension kVideoRtpExtension1[] = {
163 RtpHeaderExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
164 RtpHeaderExtension("http://google.com/testing/video_something", 13),
165 };
166
167 static const RtpHeaderExtension kVideoRtpExtension2[] = {
168 RtpHeaderExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
169 RtpHeaderExtension("http://google.com/testing/video_something_else", 14),
170 RtpHeaderExtension("http://google.com/testing/both_audio_and_video", 7),
171 };
172
173 static const RtpHeaderExtension kVideoRtpExtension3[] = {
174 RtpHeaderExtension("http://google.com/testing/video_something", 4),
175 RtpHeaderExtension("http://google.com/testing/both_audio_and_video", 5),
176 };
177
178 static const RtpHeaderExtension kVideoRtpExtensionAnswer[] = {
179 RtpHeaderExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
180 };
181
182 static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
183 static const uint32_t kSimSsrc[] = {10, 20, 30};
184 static const uint32_t kFec1Ssrc[] = {10, 11};
185 static const uint32_t kFec2Ssrc[] = {20, 21};
186 static const uint32_t kFec3Ssrc[] = {30, 31};
187
188 static const char kMediaStream1[] = "stream_1";
189 static const char kMediaStream2[] = "stream_2";
190 static const char kVideoTrack1[] = "video_1";
191 static const char kVideoTrack2[] = "video_2";
192 static const char kAudioTrack1[] = "audio_1";
193 static const char kAudioTrack2[] = "audio_2";
194 static const char kAudioTrack3[] = "audio_3";
195 static const char kDataTrack1[] = "data_1";
196 static const char kDataTrack2[] = "data_2";
197 static const char kDataTrack3[] = "data_3";
198
IsMediaContentOfType(const ContentInfo * content,MediaType media_type)199 static bool IsMediaContentOfType(const ContentInfo* content,
200 MediaType media_type) {
201 const MediaContentDescription* mdesc =
202 static_cast<const MediaContentDescription*>(content->description);
203 return mdesc && mdesc->type() == media_type;
204 }
205
206 static cricket::MediaContentDirection
GetMediaDirection(const ContentInfo * content)207 GetMediaDirection(const ContentInfo* content) {
208 cricket::MediaContentDescription* desc =
209 reinterpret_cast<cricket::MediaContentDescription*>(content->description);
210 return desc->direction();
211 }
212
AddRtxCodec(const VideoCodec & rtx_codec,std::vector<VideoCodec> * codecs)213 static void AddRtxCodec(const VideoCodec& rtx_codec,
214 std::vector<VideoCodec>* codecs) {
215 VideoCodec rtx;
216 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id, &rtx));
217 codecs->push_back(rtx_codec);
218 }
219
220 template <class T>
GetCodecNames(const std::vector<T> & codecs)221 static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
222 std::vector<std::string> codec_names;
223 for (const auto& codec : codecs) {
224 codec_names.push_back(codec.name);
225 }
226 return codec_names;
227 }
228
229 class MediaSessionDescriptionFactoryTest : public testing::Test {
230 public:
MediaSessionDescriptionFactoryTest()231 MediaSessionDescriptionFactoryTest()
232 : f1_(&tdf1_),
233 f2_(&tdf2_) {
234 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1));
235 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
236 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
237 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2));
238 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
239 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
240 tdf1_.set_certificate(rtc::RTCCertificate::Create(
241 rtc::scoped_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
242 tdf2_.set_certificate(rtc::RTCCertificate::Create(
243 rtc::scoped_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
244 }
245
246 // Create a video StreamParamsVec object with:
247 // - one video stream with 3 simulcast streams and FEC,
CreateComplexVideoStreamParamsVec()248 StreamParamsVec CreateComplexVideoStreamParamsVec() {
249 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
250 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
251 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
252 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
253
254 std::vector<SsrcGroup> ssrc_groups;
255 ssrc_groups.push_back(sim_group);
256 ssrc_groups.push_back(fec_group1);
257 ssrc_groups.push_back(fec_group2);
258 ssrc_groups.push_back(fec_group3);
259
260 StreamParams simulcast_params;
261 simulcast_params.id = kVideoTrack1;
262 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
263 simulcast_params.ssrc_groups = ssrc_groups;
264 simulcast_params.cname = "Video_SIM_FEC";
265 simulcast_params.sync_label = kMediaStream1;
266
267 StreamParamsVec video_streams;
268 video_streams.push_back(simulcast_params);
269
270 return video_streams;
271 }
272
CompareCryptoParams(const CryptoParamsVec & c1,const CryptoParamsVec & c2)273 bool CompareCryptoParams(const CryptoParamsVec& c1,
274 const CryptoParamsVec& c2) {
275 if (c1.size() != c2.size())
276 return false;
277 for (size_t i = 0; i < c1.size(); ++i)
278 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
279 c1[i].key_params != c2[i].key_params ||
280 c1[i].session_params != c2[i].session_params)
281 return false;
282 return true;
283 }
284
TestTransportInfo(bool offer,const MediaSessionOptions & options,bool has_current_desc)285 void TestTransportInfo(bool offer, const MediaSessionOptions& options,
286 bool has_current_desc) {
287 const std::string current_audio_ufrag = "current_audio_ufrag";
288 const std::string current_audio_pwd = "current_audio_pwd";
289 const std::string current_video_ufrag = "current_video_ufrag";
290 const std::string current_video_pwd = "current_video_pwd";
291 const std::string current_data_ufrag = "current_data_ufrag";
292 const std::string current_data_pwd = "current_data_pwd";
293 rtc::scoped_ptr<SessionDescription> current_desc;
294 rtc::scoped_ptr<SessionDescription> desc;
295 if (has_current_desc) {
296 current_desc.reset(new SessionDescription());
297 EXPECT_TRUE(current_desc->AddTransportInfo(
298 TransportInfo("audio",
299 TransportDescription(current_audio_ufrag,
300 current_audio_pwd))));
301 EXPECT_TRUE(current_desc->AddTransportInfo(
302 TransportInfo("video",
303 TransportDescription(current_video_ufrag,
304 current_video_pwd))));
305 EXPECT_TRUE(current_desc->AddTransportInfo(
306 TransportInfo("data",
307 TransportDescription(current_data_ufrag,
308 current_data_pwd))));
309 }
310 if (offer) {
311 desc.reset(f1_.CreateOffer(options, current_desc.get()));
312 } else {
313 rtc::scoped_ptr<SessionDescription> offer;
314 offer.reset(f1_.CreateOffer(options, NULL));
315 desc.reset(f1_.CreateAnswer(offer.get(), options, current_desc.get()));
316 }
317 ASSERT_TRUE(desc.get() != NULL);
318 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
319 if (options.has_audio()) {
320 EXPECT_TRUE(ti_audio != NULL);
321 if (has_current_desc) {
322 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
323 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
324 } else {
325 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
326 ti_audio->description.ice_ufrag.size());
327 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
328 ti_audio->description.ice_pwd.size());
329 }
330
331 } else {
332 EXPECT_TRUE(ti_audio == NULL);
333 }
334 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
335 if (options.has_video()) {
336 EXPECT_TRUE(ti_video != NULL);
337 if (options.bundle_enabled) {
338 EXPECT_EQ(ti_audio->description.ice_ufrag,
339 ti_video->description.ice_ufrag);
340 EXPECT_EQ(ti_audio->description.ice_pwd,
341 ti_video->description.ice_pwd);
342 } else {
343 if (has_current_desc) {
344 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
345 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
346 } else {
347 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
348 ti_video->description.ice_ufrag.size());
349 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
350 ti_video->description.ice_pwd.size());
351 }
352 }
353 } else {
354 EXPECT_TRUE(ti_video == NULL);
355 }
356 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
357 if (options.has_data()) {
358 EXPECT_TRUE(ti_data != NULL);
359 if (options.bundle_enabled) {
360 EXPECT_EQ(ti_audio->description.ice_ufrag,
361 ti_data->description.ice_ufrag);
362 EXPECT_EQ(ti_audio->description.ice_pwd,
363 ti_data->description.ice_pwd);
364 } else {
365 if (has_current_desc) {
366 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
367 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
368 } else {
369 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
370 ti_data->description.ice_ufrag.size());
371 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
372 ti_data->description.ice_pwd.size());
373 }
374 }
375 } else {
376 EXPECT_TRUE(ti_video == NULL);
377 }
378 }
379
TestCryptoWithBundle(bool offer)380 void TestCryptoWithBundle(bool offer) {
381 f1_.set_secure(SEC_ENABLED);
382 MediaSessionOptions options;
383 options.recv_audio = true;
384 options.recv_video = true;
385 options.data_channel_type = cricket::DCT_RTP;
386 rtc::scoped_ptr<SessionDescription> ref_desc;
387 rtc::scoped_ptr<SessionDescription> desc;
388 if (offer) {
389 options.bundle_enabled = false;
390 ref_desc.reset(f1_.CreateOffer(options, NULL));
391 options.bundle_enabled = true;
392 desc.reset(f1_.CreateOffer(options, ref_desc.get()));
393 } else {
394 options.bundle_enabled = true;
395 ref_desc.reset(f1_.CreateOffer(options, NULL));
396 desc.reset(f1_.CreateAnswer(ref_desc.get(), options, NULL));
397 }
398 ASSERT_TRUE(desc.get() != NULL);
399 const cricket::MediaContentDescription* audio_media_desc =
400 static_cast<const cricket::MediaContentDescription*>(
401 desc.get()->GetContentDescriptionByName("audio"));
402 ASSERT_TRUE(audio_media_desc != NULL);
403 const cricket::MediaContentDescription* video_media_desc =
404 static_cast<const cricket::MediaContentDescription*>(
405 desc.get()->GetContentDescriptionByName("video"));
406 ASSERT_TRUE(video_media_desc != NULL);
407 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
408 video_media_desc->cryptos()));
409 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
410 EXPECT_EQ(std::string(CS_AES_CM_128_HMAC_SHA1_80),
411 audio_media_desc->cryptos()[0].cipher_suite);
412
413 // Verify the selected crypto is one from the reference audio
414 // media content.
415 const cricket::MediaContentDescription* ref_audio_media_desc =
416 static_cast<const cricket::MediaContentDescription*>(
417 ref_desc.get()->GetContentDescriptionByName("audio"));
418 bool found = false;
419 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
420 if (ref_audio_media_desc->cryptos()[i].Matches(
421 audio_media_desc->cryptos()[0])) {
422 found = true;
423 break;
424 }
425 }
426 EXPECT_TRUE(found);
427 }
428
429 // This test that the audio and video media direction is set to
430 // |expected_direction_in_answer| in an answer if the offer direction is set
431 // to |direction_in_offer|.
TestMediaDirectionInAnswer(cricket::MediaContentDirection direction_in_offer,cricket::MediaContentDirection expected_direction_in_answer)432 void TestMediaDirectionInAnswer(
433 cricket::MediaContentDirection direction_in_offer,
434 cricket::MediaContentDirection expected_direction_in_answer) {
435 MediaSessionOptions opts;
436 opts.recv_video = true;
437 rtc::scoped_ptr<SessionDescription> offer(
438 f1_.CreateOffer(opts, NULL));
439 ASSERT_TRUE(offer.get() != NULL);
440 ContentInfo* ac_offer= offer->GetContentByName("audio");
441 ASSERT_TRUE(ac_offer != NULL);
442 AudioContentDescription* acd_offer =
443 static_cast<AudioContentDescription*>(ac_offer->description);
444 acd_offer->set_direction(direction_in_offer);
445 ContentInfo* vc_offer= offer->GetContentByName("video");
446 ASSERT_TRUE(vc_offer != NULL);
447 VideoContentDescription* vcd_offer =
448 static_cast<VideoContentDescription*>(vc_offer->description);
449 vcd_offer->set_direction(direction_in_offer);
450
451 rtc::scoped_ptr<SessionDescription> answer(
452 f2_.CreateAnswer(offer.get(), opts, NULL));
453 const AudioContentDescription* acd_answer =
454 GetFirstAudioContentDescription(answer.get());
455 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
456 const VideoContentDescription* vcd_answer =
457 GetFirstVideoContentDescription(answer.get());
458 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
459 }
460
VerifyNoCNCodecs(const cricket::ContentInfo * content)461 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
462 const cricket::ContentDescription* description = content->description;
463 ASSERT(description != NULL);
464 const cricket::AudioContentDescription* audio_content_desc =
465 static_cast<const cricket::AudioContentDescription*>(description);
466 ASSERT(audio_content_desc != NULL);
467 for (size_t i = 0; i < audio_content_desc->codecs().size(); ++i) {
468 if (audio_content_desc->codecs()[i].name == "CN")
469 return false;
470 }
471 return true;
472 }
473
474 protected:
475 MediaSessionDescriptionFactory f1_;
476 MediaSessionDescriptionFactory f2_;
477 TransportDescriptionFactory tdf1_;
478 TransportDescriptionFactory tdf2_;
479 };
480
481 // Create a typical audio offer, and ensure it matches what we expect.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateAudioOffer)482 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
483 f1_.set_secure(SEC_ENABLED);
484 rtc::scoped_ptr<SessionDescription> offer(
485 f1_.CreateOffer(MediaSessionOptions(), NULL));
486 ASSERT_TRUE(offer.get() != NULL);
487 const ContentInfo* ac = offer->GetContentByName("audio");
488 const ContentInfo* vc = offer->GetContentByName("video");
489 ASSERT_TRUE(ac != NULL);
490 ASSERT_TRUE(vc == NULL);
491 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
492 const AudioContentDescription* acd =
493 static_cast<const AudioContentDescription*>(ac->description);
494 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
495 EXPECT_EQ(f1_.audio_codecs(), acd->codecs());
496 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
497 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
498 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
499 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
500 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
501 }
502
503 // Create a typical video offer, and ensure it matches what we expect.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateVideoOffer)504 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
505 MediaSessionOptions opts;
506 opts.recv_video = true;
507 f1_.set_secure(SEC_ENABLED);
508 rtc::scoped_ptr<SessionDescription>
509 offer(f1_.CreateOffer(opts, NULL));
510 ASSERT_TRUE(offer.get() != NULL);
511 const ContentInfo* ac = offer->GetContentByName("audio");
512 const ContentInfo* vc = offer->GetContentByName("video");
513 ASSERT_TRUE(ac != NULL);
514 ASSERT_TRUE(vc != NULL);
515 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
516 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
517 const AudioContentDescription* acd =
518 static_cast<const AudioContentDescription*>(ac->description);
519 const VideoContentDescription* vcd =
520 static_cast<const VideoContentDescription*>(vc->description);
521 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
522 EXPECT_EQ(f1_.audio_codecs(), acd->codecs());
523 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
524 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
525 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
526 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
527 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
528 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
529 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
530 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
531 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
532 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
533 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
534 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
535 }
536
537 // Test creating an offer with bundle where the Codecs have the same dynamic
538 // RTP playlod type. The test verifies that the offer don't contain the
539 // duplicate RTP payload types.
TEST_F(MediaSessionDescriptionFactoryTest,TestBundleOfferWithSameCodecPlType)540 TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
541 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
542 const AudioCodec& offered_audio_codec = f2_.audio_codecs()[0];
543 const DataCodec& offered_data_codec = f2_.data_codecs()[0];
544 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
545 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
546
547 MediaSessionOptions opts;
548 opts.recv_audio = true;
549 opts.recv_video = true;
550 opts.data_channel_type = cricket::DCT_RTP;
551 opts.bundle_enabled = true;
552 rtc::scoped_ptr<SessionDescription>
553 offer(f2_.CreateOffer(opts, NULL));
554 const VideoContentDescription* vcd =
555 GetFirstVideoContentDescription(offer.get());
556 const AudioContentDescription* acd =
557 GetFirstAudioContentDescription(offer.get());
558 const DataContentDescription* dcd =
559 GetFirstDataContentDescription(offer.get());
560 ASSERT_TRUE(NULL != vcd);
561 ASSERT_TRUE(NULL != acd);
562 ASSERT_TRUE(NULL != dcd);
563 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
564 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
565 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
566 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
567 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
568 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
569 }
570
571 // Test creating an updated offer with with bundle, audio, video and data
572 // after an audio only session has been negotiated.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateUpdatedVideoOfferWithBundle)573 TEST_F(MediaSessionDescriptionFactoryTest,
574 TestCreateUpdatedVideoOfferWithBundle) {
575 f1_.set_secure(SEC_ENABLED);
576 f2_.set_secure(SEC_ENABLED);
577 MediaSessionOptions opts;
578 opts.recv_audio = true;
579 opts.recv_video = false;
580 opts.data_channel_type = cricket::DCT_NONE;
581 opts.bundle_enabled = true;
582 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
583 rtc::scoped_ptr<SessionDescription> answer(
584 f2_.CreateAnswer(offer.get(), opts, NULL));
585
586 MediaSessionOptions updated_opts;
587 updated_opts.recv_audio = true;
588 updated_opts.recv_video = true;
589 updated_opts.data_channel_type = cricket::DCT_RTP;
590 updated_opts.bundle_enabled = true;
591 rtc::scoped_ptr<SessionDescription> updated_offer(f1_.CreateOffer(
592 updated_opts, answer.get()));
593
594 const AudioContentDescription* acd =
595 GetFirstAudioContentDescription(updated_offer.get());
596 const VideoContentDescription* vcd =
597 GetFirstVideoContentDescription(updated_offer.get());
598 const DataContentDescription* dcd =
599 GetFirstDataContentDescription(updated_offer.get());
600 EXPECT_TRUE(NULL != vcd);
601 EXPECT_TRUE(NULL != acd);
602 EXPECT_TRUE(NULL != dcd);
603
604 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
605 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
606 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
607 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
608 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
609 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
610 }
611
612 // Create a RTP data offer, and ensure it matches what we expect.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateRtpDataOffer)613 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
614 MediaSessionOptions opts;
615 opts.data_channel_type = cricket::DCT_RTP;
616 f1_.set_secure(SEC_ENABLED);
617 rtc::scoped_ptr<SessionDescription>
618 offer(f1_.CreateOffer(opts, NULL));
619 ASSERT_TRUE(offer.get() != NULL);
620 const ContentInfo* ac = offer->GetContentByName("audio");
621 const ContentInfo* dc = offer->GetContentByName("data");
622 ASSERT_TRUE(ac != NULL);
623 ASSERT_TRUE(dc != NULL);
624 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
625 EXPECT_EQ(std::string(NS_JINGLE_RTP), dc->type);
626 const AudioContentDescription* acd =
627 static_cast<const AudioContentDescription*>(ac->description);
628 const DataContentDescription* dcd =
629 static_cast<const DataContentDescription*>(dc->description);
630 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
631 EXPECT_EQ(f1_.audio_codecs(), acd->codecs());
632 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
633 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
634 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
635 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
636 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
637 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
638 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
639 EXPECT_NE(0U, dcd->first_ssrc()); // a random nonzero ssrc
640 EXPECT_EQ(cricket::kDataMaxBandwidth,
641 dcd->bandwidth()); // default bandwidth (auto)
642 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
643 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
644 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
645 }
646
647 // Create an SCTP data offer with bundle without error.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateSctpDataOffer)648 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
649 MediaSessionOptions opts;
650 opts.recv_audio = false;
651 opts.bundle_enabled = true;
652 opts.data_channel_type = cricket::DCT_SCTP;
653 f1_.set_secure(SEC_ENABLED);
654 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
655 EXPECT_TRUE(offer.get() != NULL);
656 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
657 }
658
659 // Test creating an sctp data channel from an already generated offer.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateImplicitSctpDataOffer)660 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
661 MediaSessionOptions opts;
662 opts.recv_audio = false;
663 opts.bundle_enabled = true;
664 opts.data_channel_type = cricket::DCT_SCTP;
665 f1_.set_secure(SEC_ENABLED);
666 rtc::scoped_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
667 ASSERT_TRUE(offer1.get() != NULL);
668 const ContentInfo* data = offer1->GetContentByName("data");
669 ASSERT_TRUE(data != NULL);
670 const MediaContentDescription* mdesc =
671 static_cast<const MediaContentDescription*>(data->description);
672 ASSERT_EQ(cricket::kMediaProtocolSctp, mdesc->protocol());
673
674 // Now set data_channel_type to 'none' (default) and make sure that the
675 // datachannel type that gets generated from the previous offer, is of the
676 // same type.
677 opts.data_channel_type = cricket::DCT_NONE;
678 rtc::scoped_ptr<SessionDescription> offer2(
679 f1_.CreateOffer(opts, offer1.get()));
680 data = offer2->GetContentByName("data");
681 ASSERT_TRUE(data != NULL);
682 mdesc = static_cast<const MediaContentDescription*>(data->description);
683 EXPECT_EQ(cricket::kMediaProtocolSctp, mdesc->protocol());
684 }
685
686 // Create an audio, video offer without legacy StreamParams.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateOfferWithoutLegacyStreams)687 TEST_F(MediaSessionDescriptionFactoryTest,
688 TestCreateOfferWithoutLegacyStreams) {
689 MediaSessionOptions opts;
690 opts.recv_video = true;
691 f1_.set_add_legacy_streams(false);
692 rtc::scoped_ptr<SessionDescription>
693 offer(f1_.CreateOffer(opts, NULL));
694 ASSERT_TRUE(offer.get() != NULL);
695 const ContentInfo* ac = offer->GetContentByName("audio");
696 const ContentInfo* vc = offer->GetContentByName("video");
697 ASSERT_TRUE(ac != NULL);
698 ASSERT_TRUE(vc != NULL);
699 const AudioContentDescription* acd =
700 static_cast<const AudioContentDescription*>(ac->description);
701 const VideoContentDescription* vcd =
702 static_cast<const VideoContentDescription*>(vc->description);
703
704 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
705 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
706 }
707
708 // Creates an audio+video sendonly offer.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateSendOnlyOffer)709 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
710 MediaSessionOptions options;
711 options.recv_audio = false;
712 options.recv_video = false;
713 options.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack1, kMediaStream1);
714 options.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
715
716 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
717 ASSERT_TRUE(offer.get() != NULL);
718 EXPECT_EQ(2u, offer->contents().size());
719 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
720 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
721
722 EXPECT_EQ(cricket::MD_SENDONLY, GetMediaDirection(&offer->contents()[0]));
723 EXPECT_EQ(cricket::MD_SENDONLY, GetMediaDirection(&offer->contents()[1]));
724 }
725
726 // Verifies that the order of the media contents in the current
727 // SessionDescription is preserved in the new SessionDescription.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateOfferContentOrder)728 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
729 MediaSessionOptions opts;
730 opts.recv_audio = false;
731 opts.recv_video = false;
732 opts.data_channel_type = cricket::DCT_SCTP;
733
734 rtc::scoped_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
735 ASSERT_TRUE(offer1.get() != NULL);
736 EXPECT_EQ(1u, offer1->contents().size());
737 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
738
739 opts.recv_video = true;
740 rtc::scoped_ptr<SessionDescription> offer2(
741 f1_.CreateOffer(opts, offer1.get()));
742 ASSERT_TRUE(offer2.get() != NULL);
743 EXPECT_EQ(2u, offer2->contents().size());
744 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
745 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
746
747 opts.recv_audio = true;
748 rtc::scoped_ptr<SessionDescription> offer3(
749 f1_.CreateOffer(opts, offer2.get()));
750 ASSERT_TRUE(offer3.get() != NULL);
751 EXPECT_EQ(3u, offer3->contents().size());
752 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
753 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
754 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
755
756 // Verifies the default order is audio-video-data, so that the previous checks
757 // didn't pass by accident.
758 rtc::scoped_ptr<SessionDescription> offer4(f1_.CreateOffer(opts, NULL));
759 ASSERT_TRUE(offer4.get() != NULL);
760 EXPECT_EQ(3u, offer4->contents().size());
761 EXPECT_TRUE(IsMediaContentOfType(&offer4->contents()[0], MEDIA_TYPE_AUDIO));
762 EXPECT_TRUE(IsMediaContentOfType(&offer4->contents()[1], MEDIA_TYPE_VIDEO));
763 EXPECT_TRUE(IsMediaContentOfType(&offer4->contents()[2], MEDIA_TYPE_DATA));
764 }
765
766 // Create a typical audio answer, and ensure it matches what we expect.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateAudioAnswer)767 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
768 f1_.set_secure(SEC_ENABLED);
769 f2_.set_secure(SEC_ENABLED);
770 rtc::scoped_ptr<SessionDescription> offer(
771 f1_.CreateOffer(MediaSessionOptions(), NULL));
772 ASSERT_TRUE(offer.get() != NULL);
773 rtc::scoped_ptr<SessionDescription> answer(
774 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
775 const ContentInfo* ac = answer->GetContentByName("audio");
776 const ContentInfo* vc = answer->GetContentByName("video");
777 ASSERT_TRUE(ac != NULL);
778 ASSERT_TRUE(vc == NULL);
779 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
780 const AudioContentDescription* acd =
781 static_cast<const AudioContentDescription*>(ac->description);
782 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
783 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
784 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
785 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
786 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
787 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
788 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
789 }
790
791 // Create a typical video answer, and ensure it matches what we expect.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateVideoAnswer)792 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
793 MediaSessionOptions opts;
794 opts.recv_video = true;
795 f1_.set_secure(SEC_ENABLED);
796 f2_.set_secure(SEC_ENABLED);
797 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
798 ASSERT_TRUE(offer.get() != NULL);
799 rtc::scoped_ptr<SessionDescription> answer(
800 f2_.CreateAnswer(offer.get(), opts, NULL));
801 const ContentInfo* ac = answer->GetContentByName("audio");
802 const ContentInfo* vc = answer->GetContentByName("video");
803 ASSERT_TRUE(ac != NULL);
804 ASSERT_TRUE(vc != NULL);
805 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
806 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
807 const AudioContentDescription* acd =
808 static_cast<const AudioContentDescription*>(ac->description);
809 const VideoContentDescription* vcd =
810 static_cast<const VideoContentDescription*>(vc->description);
811 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
812 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
813 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
814 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
815 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
816 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
817 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
818 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
819 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
820 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
821 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
822 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
823 }
824
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateDataAnswer)825 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
826 MediaSessionOptions opts;
827 opts.data_channel_type = cricket::DCT_RTP;
828 f1_.set_secure(SEC_ENABLED);
829 f2_.set_secure(SEC_ENABLED);
830 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
831 ASSERT_TRUE(offer.get() != NULL);
832 rtc::scoped_ptr<SessionDescription> answer(
833 f2_.CreateAnswer(offer.get(), opts, NULL));
834 const ContentInfo* ac = answer->GetContentByName("audio");
835 const ContentInfo* vc = answer->GetContentByName("data");
836 ASSERT_TRUE(ac != NULL);
837 ASSERT_TRUE(vc != NULL);
838 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
839 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
840 const AudioContentDescription* acd =
841 static_cast<const AudioContentDescription*>(ac->description);
842 const DataContentDescription* vcd =
843 static_cast<const DataContentDescription*>(vc->description);
844 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
845 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
846 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
847 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
848 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
849 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
850 EXPECT_EQ(MEDIA_TYPE_DATA, vcd->type());
851 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), vcd->codecs());
852 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
853 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
854 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
855 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
856 }
857
858 // Verifies that the order of the media contents in the offer is preserved in
859 // the answer.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateAnswerContentOrder)860 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
861 MediaSessionOptions opts;
862
863 // Creates a data only offer.
864 opts.recv_audio = false;
865 opts.data_channel_type = cricket::DCT_SCTP;
866 rtc::scoped_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
867 ASSERT_TRUE(offer1.get() != NULL);
868
869 // Appends audio to the offer.
870 opts.recv_audio = true;
871 rtc::scoped_ptr<SessionDescription> offer2(
872 f1_.CreateOffer(opts, offer1.get()));
873 ASSERT_TRUE(offer2.get() != NULL);
874
875 // Appends video to the offer.
876 opts.recv_video = true;
877 rtc::scoped_ptr<SessionDescription> offer3(
878 f1_.CreateOffer(opts, offer2.get()));
879 ASSERT_TRUE(offer3.get() != NULL);
880
881 rtc::scoped_ptr<SessionDescription> answer(
882 f2_.CreateAnswer(offer3.get(), opts, NULL));
883 ASSERT_TRUE(answer.get() != NULL);
884 EXPECT_EQ(3u, answer->contents().size());
885 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
886 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
887 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
888 }
889
890 // This test that the media direction is set to send/receive in an answer if
891 // the offer is send receive.
TEST_F(MediaSessionDescriptionFactoryTest,CreateAnswerToSendReceiveOffer)892 TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
893 TestMediaDirectionInAnswer(cricket::MD_SENDRECV, cricket::MD_SENDRECV);
894 }
895
896 // This test that the media direction is set to receive only in an answer if
897 // the offer is send only.
TEST_F(MediaSessionDescriptionFactoryTest,CreateAnswerToSendOnlyOffer)898 TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
899 TestMediaDirectionInAnswer(cricket::MD_SENDONLY, cricket::MD_RECVONLY);
900 }
901
902 // This test that the media direction is set to send only in an answer if
903 // the offer is recv only.
TEST_F(MediaSessionDescriptionFactoryTest,CreateAnswerToRecvOnlyOffer)904 TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
905 TestMediaDirectionInAnswer(cricket::MD_RECVONLY, cricket::MD_SENDONLY);
906 }
907
908 // This test that the media direction is set to inactive in an answer if
909 // the offer is inactive.
TEST_F(MediaSessionDescriptionFactoryTest,CreateAnswerToInactiveOffer)910 TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
911 TestMediaDirectionInAnswer(cricket::MD_INACTIVE, cricket::MD_INACTIVE);
912 }
913
914 // Test that a data content with an unknown protocol is rejected in an answer.
TEST_F(MediaSessionDescriptionFactoryTest,CreateDataAnswerToOfferWithUnknownProtocol)915 TEST_F(MediaSessionDescriptionFactoryTest,
916 CreateDataAnswerToOfferWithUnknownProtocol) {
917 MediaSessionOptions opts;
918 opts.data_channel_type = cricket::DCT_RTP;
919 opts.recv_audio = false;
920 f1_.set_secure(SEC_ENABLED);
921 f2_.set_secure(SEC_ENABLED);
922 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
923 ContentInfo* dc_offer= offer->GetContentByName("data");
924 ASSERT_TRUE(dc_offer != NULL);
925 DataContentDescription* dcd_offer =
926 static_cast<DataContentDescription*>(dc_offer->description);
927 ASSERT_TRUE(dcd_offer != NULL);
928 std::string protocol = "a weird unknown protocol";
929 dcd_offer->set_protocol(protocol);
930
931 rtc::scoped_ptr<SessionDescription> answer(
932 f2_.CreateAnswer(offer.get(), opts, NULL));
933
934 const ContentInfo* dc_answer = answer->GetContentByName("data");
935 ASSERT_TRUE(dc_answer != NULL);
936 EXPECT_TRUE(dc_answer->rejected);
937 const DataContentDescription* dcd_answer =
938 static_cast<const DataContentDescription*>(dc_answer->description);
939 ASSERT_TRUE(dcd_answer != NULL);
940 EXPECT_EQ(protocol, dcd_answer->protocol());
941 }
942
943 // Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
TEST_F(MediaSessionDescriptionFactoryTest,AudioOfferAnswerWithCryptoDisabled)944 TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
945 MediaSessionOptions opts;
946 f1_.set_secure(SEC_DISABLED);
947 f2_.set_secure(SEC_DISABLED);
948 tdf1_.set_secure(SEC_DISABLED);
949 tdf2_.set_secure(SEC_DISABLED);
950
951 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
952 const AudioContentDescription* offer_acd =
953 GetFirstAudioContentDescription(offer.get());
954 ASSERT_TRUE(offer_acd != NULL);
955 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), offer_acd->protocol());
956
957 rtc::scoped_ptr<SessionDescription> answer(
958 f2_.CreateAnswer(offer.get(), opts, NULL));
959
960 const ContentInfo* ac_answer = answer->GetContentByName("audio");
961 ASSERT_TRUE(ac_answer != NULL);
962 EXPECT_FALSE(ac_answer->rejected);
963
964 const AudioContentDescription* answer_acd =
965 GetFirstAudioContentDescription(answer.get());
966 ASSERT_TRUE(answer_acd != NULL);
967 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), answer_acd->protocol());
968 }
969
970 // Create a video offer and answer and ensure the RTP header extensions
971 // matches what we expect.
TEST_F(MediaSessionDescriptionFactoryTest,TestOfferAnswerWithRtpExtensions)972 TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
973 MediaSessionOptions opts;
974 opts.recv_video = true;
975
976 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
977 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
978 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
979 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
980
981 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
982 ASSERT_TRUE(offer.get() != NULL);
983 rtc::scoped_ptr<SessionDescription> answer(
984 f2_.CreateAnswer(offer.get(), opts, NULL));
985
986 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension1),
987 GetFirstAudioContentDescription(
988 offer.get())->rtp_header_extensions());
989 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtension1),
990 GetFirstVideoContentDescription(
991 offer.get())->rtp_header_extensions());
992 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
993 GetFirstAudioContentDescription(
994 answer.get())->rtp_header_extensions());
995 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
996 GetFirstVideoContentDescription(
997 answer.get())->rtp_header_extensions());
998 }
999
1000 // Create an audio, video, data answer without legacy StreamParams.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateAnswerWithoutLegacyStreams)1001 TEST_F(MediaSessionDescriptionFactoryTest,
1002 TestCreateAnswerWithoutLegacyStreams) {
1003 MediaSessionOptions opts;
1004 opts.recv_video = true;
1005 opts.data_channel_type = cricket::DCT_RTP;
1006 f1_.set_add_legacy_streams(false);
1007 f2_.set_add_legacy_streams(false);
1008 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1009 ASSERT_TRUE(offer.get() != NULL);
1010 rtc::scoped_ptr<SessionDescription> answer(
1011 f2_.CreateAnswer(offer.get(), opts, NULL));
1012 const ContentInfo* ac = answer->GetContentByName("audio");
1013 const ContentInfo* vc = answer->GetContentByName("video");
1014 const ContentInfo* dc = answer->GetContentByName("data");
1015 ASSERT_TRUE(ac != NULL);
1016 ASSERT_TRUE(vc != NULL);
1017 const AudioContentDescription* acd =
1018 static_cast<const AudioContentDescription*>(ac->description);
1019 const VideoContentDescription* vcd =
1020 static_cast<const VideoContentDescription*>(vc->description);
1021 const DataContentDescription* dcd =
1022 static_cast<const DataContentDescription*>(dc->description);
1023
1024 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1025 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1026 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1027 }
1028
TEST_F(MediaSessionDescriptionFactoryTest,TestPartial)1029 TEST_F(MediaSessionDescriptionFactoryTest, TestPartial) {
1030 MediaSessionOptions opts;
1031 opts.recv_video = true;
1032 opts.data_channel_type = cricket::DCT_RTP;
1033 f1_.set_secure(SEC_ENABLED);
1034 rtc::scoped_ptr<SessionDescription>
1035 offer(f1_.CreateOffer(opts, NULL));
1036 ASSERT_TRUE(offer.get() != NULL);
1037 const ContentInfo* ac = offer->GetContentByName("audio");
1038 const ContentInfo* vc = offer->GetContentByName("video");
1039 const ContentInfo* dc = offer->GetContentByName("data");
1040 AudioContentDescription* acd = const_cast<AudioContentDescription*>(
1041 static_cast<const AudioContentDescription*>(ac->description));
1042 VideoContentDescription* vcd = const_cast<VideoContentDescription*>(
1043 static_cast<const VideoContentDescription*>(vc->description));
1044 DataContentDescription* dcd = const_cast<DataContentDescription*>(
1045 static_cast<const DataContentDescription*>(dc->description));
1046
1047 EXPECT_FALSE(acd->partial()); // default is false.
1048 acd->set_partial(true);
1049 EXPECT_TRUE(acd->partial());
1050 acd->set_partial(false);
1051 EXPECT_FALSE(acd->partial());
1052
1053 EXPECT_FALSE(vcd->partial()); // default is false.
1054 vcd->set_partial(true);
1055 EXPECT_TRUE(vcd->partial());
1056 vcd->set_partial(false);
1057 EXPECT_FALSE(vcd->partial());
1058
1059 EXPECT_FALSE(dcd->partial()); // default is false.
1060 dcd->set_partial(true);
1061 EXPECT_TRUE(dcd->partial());
1062 dcd->set_partial(false);
1063 EXPECT_FALSE(dcd->partial());
1064 }
1065
1066 // Create a typical video answer, and ensure it matches what we expect.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateVideoAnswerRtcpMux)1067 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1068 MediaSessionOptions offer_opts;
1069 MediaSessionOptions answer_opts;
1070 answer_opts.recv_video = true;
1071 offer_opts.recv_video = true;
1072 answer_opts.data_channel_type = cricket::DCT_RTP;
1073 offer_opts.data_channel_type = cricket::DCT_RTP;
1074
1075 rtc::scoped_ptr<SessionDescription> offer;
1076 rtc::scoped_ptr<SessionDescription> answer;
1077
1078 offer_opts.rtcp_mux_enabled = true;
1079 answer_opts.rtcp_mux_enabled = true;
1080
1081 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1082 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1083 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1084 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1085 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1086 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1087 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1088 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1089 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1090 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1091 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1092 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1093 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1094 EXPECT_TRUE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1095
1096 offer_opts.rtcp_mux_enabled = true;
1097 answer_opts.rtcp_mux_enabled = false;
1098
1099 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1100 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1101 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1102 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1103 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1104 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1105 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1106 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1107 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1108 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1109 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1110 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1111 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1112 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1113
1114 offer_opts.rtcp_mux_enabled = false;
1115 answer_opts.rtcp_mux_enabled = true;
1116
1117 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1118 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1119 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1120 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1121 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1122 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1123 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1124 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1125 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1126 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1127 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1128 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1129 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1130 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1131
1132 offer_opts.rtcp_mux_enabled = false;
1133 answer_opts.rtcp_mux_enabled = false;
1134
1135 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1136 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1137 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1138 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1139 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1140 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1141 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1142 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1143 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1144 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1145 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1146 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1147 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1148 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1149 }
1150
1151 // Create an audio-only answer to a video offer.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateAudioAnswerToVideo)1152 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1153 MediaSessionOptions opts;
1154 opts.recv_video = true;
1155 rtc::scoped_ptr<SessionDescription>
1156 offer(f1_.CreateOffer(opts, NULL));
1157 ASSERT_TRUE(offer.get() != NULL);
1158 rtc::scoped_ptr<SessionDescription> answer(
1159 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
1160 const ContentInfo* ac = answer->GetContentByName("audio");
1161 const ContentInfo* vc = answer->GetContentByName("video");
1162 ASSERT_TRUE(ac != NULL);
1163 ASSERT_TRUE(vc != NULL);
1164 ASSERT_TRUE(vc->description != NULL);
1165 EXPECT_TRUE(vc->rejected);
1166 }
1167
1168 // Create an audio-only answer to an offer with data.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateNoDataAnswerToDataOffer)1169 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
1170 MediaSessionOptions opts;
1171 opts.data_channel_type = cricket::DCT_RTP;
1172 rtc::scoped_ptr<SessionDescription>
1173 offer(f1_.CreateOffer(opts, NULL));
1174 ASSERT_TRUE(offer.get() != NULL);
1175 rtc::scoped_ptr<SessionDescription> answer(
1176 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
1177 const ContentInfo* ac = answer->GetContentByName("audio");
1178 const ContentInfo* dc = answer->GetContentByName("data");
1179 ASSERT_TRUE(ac != NULL);
1180 ASSERT_TRUE(dc != NULL);
1181 ASSERT_TRUE(dc->description != NULL);
1182 EXPECT_TRUE(dc->rejected);
1183 }
1184
1185 // Create an answer that rejects the contents which are rejected in the offer.
TEST_F(MediaSessionDescriptionFactoryTest,CreateAnswerToOfferWithRejectedMedia)1186 TEST_F(MediaSessionDescriptionFactoryTest,
1187 CreateAnswerToOfferWithRejectedMedia) {
1188 MediaSessionOptions opts;
1189 opts.recv_video = true;
1190 opts.data_channel_type = cricket::DCT_RTP;
1191 rtc::scoped_ptr<SessionDescription>
1192 offer(f1_.CreateOffer(opts, NULL));
1193 ASSERT_TRUE(offer.get() != NULL);
1194 ContentInfo* ac = offer->GetContentByName("audio");
1195 ContentInfo* vc = offer->GetContentByName("video");
1196 ContentInfo* dc = offer->GetContentByName("data");
1197 ASSERT_TRUE(ac != NULL);
1198 ASSERT_TRUE(vc != NULL);
1199 ASSERT_TRUE(dc != NULL);
1200 ac->rejected = true;
1201 vc->rejected = true;
1202 dc->rejected = true;
1203 rtc::scoped_ptr<SessionDescription> answer(
1204 f2_.CreateAnswer(offer.get(), opts, NULL));
1205 ac = answer->GetContentByName("audio");
1206 vc = answer->GetContentByName("video");
1207 dc = answer->GetContentByName("data");
1208 ASSERT_TRUE(ac != NULL);
1209 ASSERT_TRUE(vc != NULL);
1210 ASSERT_TRUE(dc != NULL);
1211 EXPECT_TRUE(ac->rejected);
1212 EXPECT_TRUE(vc->rejected);
1213 EXPECT_TRUE(dc->rejected);
1214 }
1215
1216 // Create an audio and video offer with:
1217 // - one video track
1218 // - two audio tracks
1219 // - two data tracks
1220 // and ensure it matches what we expect. Also updates the initial offer by
1221 // adding a new video track and replaces one of the audio tracks.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateMultiStreamVideoOffer)1222 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
1223 MediaSessionOptions opts;
1224 opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack1, kMediaStream1);
1225 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
1226 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2, kMediaStream1);
1227 opts.data_channel_type = cricket::DCT_RTP;
1228 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack1, kMediaStream1);
1229 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack2, kMediaStream1);
1230
1231 f1_.set_secure(SEC_ENABLED);
1232 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1233
1234 ASSERT_TRUE(offer.get() != NULL);
1235 const ContentInfo* ac = offer->GetContentByName("audio");
1236 const ContentInfo* vc = offer->GetContentByName("video");
1237 const ContentInfo* dc = offer->GetContentByName("data");
1238 ASSERT_TRUE(ac != NULL);
1239 ASSERT_TRUE(vc != NULL);
1240 ASSERT_TRUE(dc != NULL);
1241 const AudioContentDescription* acd =
1242 static_cast<const AudioContentDescription*>(ac->description);
1243 const VideoContentDescription* vcd =
1244 static_cast<const VideoContentDescription*>(vc->description);
1245 const DataContentDescription* dcd =
1246 static_cast<const DataContentDescription*>(dc->description);
1247 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1248 EXPECT_EQ(f1_.audio_codecs(), acd->codecs());
1249
1250 const StreamParamsVec& audio_streams = acd->streams();
1251 ASSERT_EQ(2U, audio_streams.size());
1252 EXPECT_EQ(audio_streams[0].cname , audio_streams[1].cname);
1253 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1254 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1255 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1256 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1257 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1258 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1259
1260 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1261 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1262 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
1263
1264 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1265 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
1266 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1267
1268 const StreamParamsVec& video_streams = vcd->streams();
1269 ASSERT_EQ(1U, video_streams.size());
1270 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1271 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1272 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1273 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1274
1275 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1276 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
1277 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1278
1279 const StreamParamsVec& data_streams = dcd->streams();
1280 ASSERT_EQ(2U, data_streams.size());
1281 EXPECT_EQ(data_streams[0].cname , data_streams[1].cname);
1282 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1283 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1284 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1285 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1286 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1287 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1288
1289 EXPECT_EQ(cricket::kDataMaxBandwidth,
1290 dcd->bandwidth()); // default bandwidth (auto)
1291 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
1292 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1293
1294
1295 // Update the offer. Add a new video track that is not synched to the
1296 // other tracks and replace audio track 2 with audio track 3.
1297 opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack2, kMediaStream2);
1298 opts.RemoveSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2);
1299 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack3, kMediaStream1);
1300 opts.RemoveSendStream(MEDIA_TYPE_DATA, kDataTrack2);
1301 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack3, kMediaStream1);
1302 rtc::scoped_ptr<SessionDescription>
1303 updated_offer(f1_.CreateOffer(opts, offer.get()));
1304
1305 ASSERT_TRUE(updated_offer.get() != NULL);
1306 ac = updated_offer->GetContentByName("audio");
1307 vc = updated_offer->GetContentByName("video");
1308 dc = updated_offer->GetContentByName("data");
1309 ASSERT_TRUE(ac != NULL);
1310 ASSERT_TRUE(vc != NULL);
1311 ASSERT_TRUE(dc != NULL);
1312 const AudioContentDescription* updated_acd =
1313 static_cast<const AudioContentDescription*>(ac->description);
1314 const VideoContentDescription* updated_vcd =
1315 static_cast<const VideoContentDescription*>(vc->description);
1316 const DataContentDescription* updated_dcd =
1317 static_cast<const DataContentDescription*>(dc->description);
1318
1319 EXPECT_EQ(acd->type(), updated_acd->type());
1320 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1321 EXPECT_EQ(vcd->type(), updated_vcd->type());
1322 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1323 EXPECT_EQ(dcd->type(), updated_dcd->type());
1324 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1325 ASSERT_CRYPTO(updated_acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
1326 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
1327 ASSERT_CRYPTO(updated_vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1328 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
1329 ASSERT_CRYPTO(updated_dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1330 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1331
1332 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1333 ASSERT_EQ(2U, updated_audio_streams.size());
1334 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
1335 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
1336 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
1337 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
1338 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
1339
1340 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1341 ASSERT_EQ(2U, updated_video_streams.size());
1342 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1343 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
1344 EXPECT_NE(updated_video_streams[1].cname, updated_video_streams[0].cname);
1345
1346 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1347 ASSERT_EQ(2U, updated_data_streams.size());
1348 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
1349 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
1350 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
1351 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
1352 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
1353 }
1354
1355 // Create an offer with simulcast video stream.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateSimulcastVideoOffer)1356 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
1357 MediaSessionOptions opts;
1358 const int num_sim_layers = 3;
1359 opts.AddSendVideoStream(kVideoTrack1, kMediaStream1, num_sim_layers);
1360 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1361
1362 ASSERT_TRUE(offer.get() != NULL);
1363 const ContentInfo* vc = offer->GetContentByName("video");
1364 ASSERT_TRUE(vc != NULL);
1365 const VideoContentDescription* vcd =
1366 static_cast<const VideoContentDescription*>(vc->description);
1367
1368 const StreamParamsVec& video_streams = vcd->streams();
1369 ASSERT_EQ(1U, video_streams.size());
1370 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1371 const SsrcGroup* sim_ssrc_group =
1372 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
1373 ASSERT_TRUE(sim_ssrc_group != NULL);
1374 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
1375 }
1376
1377 // Create an audio and video answer to a standard video offer with:
1378 // - one video track
1379 // - two audio tracks
1380 // - two data tracks
1381 // and ensure it matches what we expect. Also updates the initial answer by
1382 // adding a new video track and removes one of the audio tracks.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateMultiStreamVideoAnswer)1383 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
1384 MediaSessionOptions offer_opts;
1385 offer_opts.recv_video = true;
1386 offer_opts.data_channel_type = cricket::DCT_RTP;
1387 f1_.set_secure(SEC_ENABLED);
1388 f2_.set_secure(SEC_ENABLED);
1389 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(offer_opts,
1390 NULL));
1391
1392 MediaSessionOptions opts;
1393 opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack1, kMediaStream1);
1394 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
1395 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2, kMediaStream1);
1396 opts.data_channel_type = cricket::DCT_RTP;
1397 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack1, kMediaStream1);
1398 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack2, kMediaStream1);
1399
1400 rtc::scoped_ptr<SessionDescription>
1401 answer(f2_.CreateAnswer(offer.get(), opts, NULL));
1402
1403 ASSERT_TRUE(answer.get() != NULL);
1404 const ContentInfo* ac = answer->GetContentByName("audio");
1405 const ContentInfo* vc = answer->GetContentByName("video");
1406 const ContentInfo* dc = answer->GetContentByName("data");
1407 ASSERT_TRUE(ac != NULL);
1408 ASSERT_TRUE(vc != NULL);
1409 ASSERT_TRUE(dc != NULL);
1410 const AudioContentDescription* acd =
1411 static_cast<const AudioContentDescription*>(ac->description);
1412 const VideoContentDescription* vcd =
1413 static_cast<const VideoContentDescription*>(vc->description);
1414 const DataContentDescription* dcd =
1415 static_cast<const DataContentDescription*>(dc->description);
1416 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1417 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1418 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1419
1420 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1421 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1422
1423 const StreamParamsVec& audio_streams = acd->streams();
1424 ASSERT_EQ(2U, audio_streams.size());
1425 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
1426 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1427 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1428 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1429 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1430 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1431 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1432
1433 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1434 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1435
1436 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1437 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1438
1439 const StreamParamsVec& video_streams = vcd->streams();
1440 ASSERT_EQ(1U, video_streams.size());
1441 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1442 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1443 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1444 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1445
1446 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1447 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
1448
1449 const StreamParamsVec& data_streams = dcd->streams();
1450 ASSERT_EQ(2U, data_streams.size());
1451 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
1452 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1453 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1454 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1455 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1456 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1457 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1458
1459 EXPECT_EQ(cricket::kDataMaxBandwidth,
1460 dcd->bandwidth()); // default bandwidth (auto)
1461 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
1462
1463 // Update the answer. Add a new video track that is not synched to the
1464 // other traacks and remove 1 audio track.
1465 opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack2, kMediaStream2);
1466 opts.RemoveSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2);
1467 opts.RemoveSendStream(MEDIA_TYPE_DATA, kDataTrack2);
1468 rtc::scoped_ptr<SessionDescription>
1469 updated_answer(f2_.CreateAnswer(offer.get(), opts, answer.get()));
1470
1471 ASSERT_TRUE(updated_answer.get() != NULL);
1472 ac = updated_answer->GetContentByName("audio");
1473 vc = updated_answer->GetContentByName("video");
1474 dc = updated_answer->GetContentByName("data");
1475 ASSERT_TRUE(ac != NULL);
1476 ASSERT_TRUE(vc != NULL);
1477 ASSERT_TRUE(dc != NULL);
1478 const AudioContentDescription* updated_acd =
1479 static_cast<const AudioContentDescription*>(ac->description);
1480 const VideoContentDescription* updated_vcd =
1481 static_cast<const VideoContentDescription*>(vc->description);
1482 const DataContentDescription* updated_dcd =
1483 static_cast<const DataContentDescription*>(dc->description);
1484
1485 ASSERT_CRYPTO(updated_acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1486 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
1487 ASSERT_CRYPTO(updated_vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1488 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
1489 ASSERT_CRYPTO(updated_dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1490 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1491
1492 EXPECT_EQ(acd->type(), updated_acd->type());
1493 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1494 EXPECT_EQ(vcd->type(), updated_vcd->type());
1495 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1496 EXPECT_EQ(dcd->type(), updated_dcd->type());
1497 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1498
1499 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1500 ASSERT_EQ(1U, updated_audio_streams.size());
1501 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
1502
1503 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1504 ASSERT_EQ(2U, updated_video_streams.size());
1505 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1506 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
1507 EXPECT_NE(updated_video_streams[1].cname, updated_video_streams[0].cname);
1508
1509 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1510 ASSERT_EQ(1U, updated_data_streams.size());
1511 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
1512 }
1513
1514
1515 // Create an updated offer after creating an answer to the original offer and
1516 // verify that the codecs that were part of the original answer are not changed
1517 // in the updated offer.
TEST_F(MediaSessionDescriptionFactoryTest,RespondentCreatesOfferAfterCreatingAnswer)1518 TEST_F(MediaSessionDescriptionFactoryTest,
1519 RespondentCreatesOfferAfterCreatingAnswer) {
1520 MediaSessionOptions opts;
1521 opts.recv_audio = true;
1522 opts.recv_video = true;
1523
1524 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1525 rtc::scoped_ptr<SessionDescription> answer(
1526 f2_.CreateAnswer(offer.get(), opts, NULL));
1527
1528 const AudioContentDescription* acd =
1529 GetFirstAudioContentDescription(answer.get());
1530 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1531
1532 const VideoContentDescription* vcd =
1533 GetFirstVideoContentDescription(answer.get());
1534 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1535
1536 rtc::scoped_ptr<SessionDescription> updated_offer(
1537 f2_.CreateOffer(opts, answer.get()));
1538
1539 // The expected audio codecs are the common audio codecs from the first
1540 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
1541 // preference order.
1542 // TODO(wu): |updated_offer| should not include the codec
1543 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
1544 const AudioCodec kUpdatedAudioCodecOffer[] = {
1545 kAudioCodecsAnswer[0],
1546 kAudioCodecsAnswer[1],
1547 kAudioCodecs2[0],
1548 };
1549
1550 // The expected video codecs are the common video codecs from the first
1551 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
1552 // preference order.
1553 const VideoCodec kUpdatedVideoCodecOffer[] = {
1554 kVideoCodecsAnswer[0],
1555 kVideoCodecs2[1],
1556 };
1557
1558 const AudioContentDescription* updated_acd =
1559 GetFirstAudioContentDescription(updated_offer.get());
1560 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioCodecOffer), updated_acd->codecs());
1561
1562 const VideoContentDescription* updated_vcd =
1563 GetFirstVideoContentDescription(updated_offer.get());
1564 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoCodecOffer), updated_vcd->codecs());
1565 }
1566
1567 // Create an updated offer after creating an answer to the original offer and
1568 // verify that the codecs that were part of the original answer are not changed
1569 // in the updated offer. In this test Rtx is enabled.
TEST_F(MediaSessionDescriptionFactoryTest,RespondentCreatesOfferAfterCreatingAnswerWithRtx)1570 TEST_F(MediaSessionDescriptionFactoryTest,
1571 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
1572 MediaSessionOptions opts;
1573 opts.recv_video = true;
1574 opts.recv_audio = false;
1575 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1576 // This creates rtx for H264 with the payload type |f1_| uses.
1577 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
1578 f1_.set_video_codecs(f1_codecs);
1579
1580 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1581 // This creates rtx for H264 with the payload type |f2_| uses.
1582 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
1583 f2_.set_video_codecs(f2_codecs);
1584
1585 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1586 ASSERT_TRUE(offer.get() != NULL);
1587 rtc::scoped_ptr<SessionDescription> answer(
1588 f2_.CreateAnswer(offer.get(), opts, NULL));
1589
1590 const VideoContentDescription* vcd =
1591 GetFirstVideoContentDescription(answer.get());
1592
1593 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
1594 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
1595 &expected_codecs);
1596
1597 EXPECT_EQ(expected_codecs, vcd->codecs());
1598
1599 // Now, make sure we get same result, except for the preference order,
1600 // if |f2_| creates an updated offer even though the default payload types
1601 // are different from |f1_|.
1602 expected_codecs[0].preference = f1_codecs[1].preference;
1603
1604 rtc::scoped_ptr<SessionDescription> updated_offer(
1605 f2_.CreateOffer(opts, answer.get()));
1606 ASSERT_TRUE(updated_offer);
1607 rtc::scoped_ptr<SessionDescription> updated_answer(
1608 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
1609
1610 const VideoContentDescription* updated_vcd =
1611 GetFirstVideoContentDescription(updated_answer.get());
1612
1613 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
1614 }
1615
1616 // Create an updated offer that adds video after creating an audio only answer
1617 // to the original offer. This test verifies that if a video codec and the RTX
1618 // codec have the same default payload type as an audio codec that is already in
1619 // use, the added codecs payload types are changed.
TEST_F(MediaSessionDescriptionFactoryTest,RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer)1620 TEST_F(MediaSessionDescriptionFactoryTest,
1621 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
1622 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1623 // This creates rtx for H264 with the payload type |f1_| uses.
1624 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
1625 f1_.set_video_codecs(f1_codecs);
1626
1627 MediaSessionOptions opts;
1628 opts.recv_audio = true;
1629 opts.recv_video = false;
1630
1631 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1632 rtc::scoped_ptr<SessionDescription> answer(
1633 f2_.CreateAnswer(offer.get(), opts, NULL));
1634
1635 const AudioContentDescription* acd =
1636 GetFirstAudioContentDescription(answer.get());
1637 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1638
1639 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
1640 // reference be the same as an audio codec that was negotiated in the
1641 // first offer/answer exchange.
1642 opts.recv_audio = true;
1643 opts.recv_video = true;
1644
1645 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1646 int used_pl_type = acd->codecs()[0].id;
1647 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
1648 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
1649 f2_.set_video_codecs(f2_codecs);
1650
1651 rtc::scoped_ptr<SessionDescription> updated_offer(
1652 f2_.CreateOffer(opts, answer.get()));
1653 ASSERT_TRUE(updated_offer);
1654 rtc::scoped_ptr<SessionDescription> updated_answer(
1655 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
1656
1657 const AudioContentDescription* updated_acd =
1658 GetFirstAudioContentDescription(answer.get());
1659 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), updated_acd->codecs());
1660
1661 const VideoContentDescription* updated_vcd =
1662 GetFirstVideoContentDescription(updated_answer.get());
1663
1664 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
1665 ASSERT_EQ(std::string(cricket::kRtxCodecName), updated_vcd->codecs()[1].name);
1666 int new_h264_pl_type = updated_vcd->codecs()[0].id;
1667 EXPECT_NE(used_pl_type, new_h264_pl_type);
1668 VideoCodec rtx = updated_vcd->codecs()[1];
1669 int pt_referenced_by_rtx = rtc::FromString<int>(
1670 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
1671 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
1672 }
1673
1674 // Test that RTX is ignored when there is no associated payload type parameter.
TEST_F(MediaSessionDescriptionFactoryTest,RtxWithoutApt)1675 TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
1676 MediaSessionOptions opts;
1677 opts.recv_video = true;
1678 opts.recv_audio = false;
1679 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1680 // This creates RTX without associated payload type parameter.
1681 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName, 0, 0, 0, 0), &f1_codecs);
1682 f1_.set_video_codecs(f1_codecs);
1683
1684 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1685 // This creates RTX for H264 with the payload type |f2_| uses.
1686 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
1687 f2_.set_video_codecs(f2_codecs);
1688
1689 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1690 ASSERT_TRUE(offer.get() != NULL);
1691 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
1692 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
1693 // is possible to test that that RTX is dropped when
1694 // kCodecParamAssociatedPayloadType is missing in the offer.
1695 VideoContentDescription* desc =
1696 static_cast<cricket::VideoContentDescription*>(
1697 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
1698 ASSERT_TRUE(desc != NULL);
1699 std::vector<VideoCodec> codecs = desc->codecs();
1700 for (std::vector<VideoCodec>::iterator iter = codecs.begin();
1701 iter != codecs.end(); ++iter) {
1702 if (iter->name.find(cricket::kRtxCodecName) == 0) {
1703 iter->params.clear();
1704 }
1705 }
1706 desc->set_codecs(codecs);
1707
1708 rtc::scoped_ptr<SessionDescription> answer(
1709 f2_.CreateAnswer(offer.get(), opts, NULL));
1710
1711 std::vector<std::string> codec_names =
1712 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
1713 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
1714 cricket::kRtxCodecName));
1715 }
1716
1717 // Test that RTX will be filtered out in the answer if its associated payload
1718 // type doesn't match the local value.
TEST_F(MediaSessionDescriptionFactoryTest,FilterOutRtxIfAptDoesntMatch)1719 TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
1720 MediaSessionOptions opts;
1721 opts.recv_video = true;
1722 opts.recv_audio = false;
1723 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1724 // This creates RTX for H264 in sender.
1725 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
1726 f1_.set_video_codecs(f1_codecs);
1727
1728 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1729 // This creates RTX for H263 in receiver.
1730 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
1731 f2_.set_video_codecs(f2_codecs);
1732
1733 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1734 ASSERT_TRUE(offer.get() != NULL);
1735 // Associated payload type doesn't match, therefore, RTX codec is removed in
1736 // the answer.
1737 rtc::scoped_ptr<SessionDescription> answer(
1738 f2_.CreateAnswer(offer.get(), opts, NULL));
1739
1740 std::vector<std::string> codec_names =
1741 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
1742 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
1743 cricket::kRtxCodecName));
1744 }
1745
1746 // Test that when multiple RTX codecs are offered, only the matched RTX codec
1747 // is added in the answer, and the unsupported RTX codec is filtered out.
TEST_F(MediaSessionDescriptionFactoryTest,FilterOutUnsupportedRtxWhenCreatingAnswer)1748 TEST_F(MediaSessionDescriptionFactoryTest,
1749 FilterOutUnsupportedRtxWhenCreatingAnswer) {
1750 MediaSessionOptions opts;
1751 opts.recv_video = true;
1752 opts.recv_audio = false;
1753 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1754 // This creates RTX for H264-SVC in sender.
1755 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
1756 f1_.set_video_codecs(f1_codecs);
1757
1758 // This creates RTX for H264 in sender.
1759 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
1760 f1_.set_video_codecs(f1_codecs);
1761
1762 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1763 // This creates RTX for H264 in receiver.
1764 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
1765 f2_.set_video_codecs(f2_codecs);
1766
1767 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
1768 // for H264-SVC should also be removed.
1769 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1770 ASSERT_TRUE(offer.get() != NULL);
1771 rtc::scoped_ptr<SessionDescription> answer(
1772 f2_.CreateAnswer(offer.get(), opts, NULL));
1773 const VideoContentDescription* vcd =
1774 GetFirstVideoContentDescription(answer.get());
1775 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
1776 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
1777 &expected_codecs);
1778
1779 EXPECT_EQ(expected_codecs, vcd->codecs());
1780 }
1781
1782 // Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
1783 // generated for each simulcast ssrc and correctly grouped.
TEST_F(MediaSessionDescriptionFactoryTest,SimSsrcsGenerateMultipleRtxSsrcs)1784 TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
1785 MediaSessionOptions opts;
1786 opts.recv_video = true;
1787 opts.recv_audio = false;
1788
1789 // Add simulcast streams.
1790 opts.AddSendVideoStream("stream1", "stream1label", 3);
1791
1792 // Use a single real codec, and then add RTX for it.
1793 std::vector<VideoCodec> f1_codecs;
1794 f1_codecs.push_back(VideoCodec(97, "H264", 320, 200, 30, 1));
1795 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
1796 f1_.set_video_codecs(f1_codecs);
1797
1798 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
1799 // is a FID ssrc + grouping for each.
1800 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1801 ASSERT_TRUE(offer.get() != NULL);
1802 VideoContentDescription* desc = static_cast<VideoContentDescription*>(
1803 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
1804 ASSERT_TRUE(desc != NULL);
1805 EXPECT_TRUE(desc->multistream());
1806 const StreamParamsVec& streams = desc->streams();
1807 // Single stream.
1808 ASSERT_EQ(1u, streams.size());
1809 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
1810 EXPECT_EQ(6u, streams[0].ssrcs.size());
1811 // And should have a SIM group for the simulcast.
1812 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
1813 // And a FID group for RTX.
1814 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
1815 std::vector<uint32_t> primary_ssrcs;
1816 streams[0].GetPrimarySsrcs(&primary_ssrcs);
1817 EXPECT_EQ(3u, primary_ssrcs.size());
1818 std::vector<uint32_t> fid_ssrcs;
1819 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
1820 EXPECT_EQ(3u, fid_ssrcs.size());
1821 }
1822
1823 // Create an updated offer after creating an answer to the original offer and
1824 // verify that the RTP header extensions that were part of the original answer
1825 // are not changed in the updated offer.
TEST_F(MediaSessionDescriptionFactoryTest,RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions)1826 TEST_F(MediaSessionDescriptionFactoryTest,
1827 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
1828 MediaSessionOptions opts;
1829 opts.recv_audio = true;
1830 opts.recv_video = true;
1831
1832 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1833 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1834 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1835 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1836
1837 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1838 rtc::scoped_ptr<SessionDescription> answer(
1839 f2_.CreateAnswer(offer.get(), opts, NULL));
1840
1841 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
1842 GetFirstAudioContentDescription(
1843 answer.get())->rtp_header_extensions());
1844 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
1845 GetFirstVideoContentDescription(
1846 answer.get())->rtp_header_extensions());
1847
1848 rtc::scoped_ptr<SessionDescription> updated_offer(
1849 f2_.CreateOffer(opts, answer.get()));
1850
1851 // The expected RTP header extensions in the new offer are the resulting
1852 // extensions from the first offer/answer exchange plus the extensions only
1853 // |f2_| offer.
1854 // Since the default local extension id |f2_| uses has already been used by
1855 // |f1_| for another extensions, it is changed to 13.
1856 const RtpHeaderExtension kUpdatedAudioRtpExtensions[] = {
1857 kAudioRtpExtensionAnswer[0],
1858 RtpHeaderExtension(kAudioRtpExtension2[1].uri, 13),
1859 kAudioRtpExtension2[2],
1860 };
1861
1862 // Since the default local extension id |f2_| uses has already been used by
1863 // |f1_| for another extensions, is is changed to 12.
1864 const RtpHeaderExtension kUpdatedVideoRtpExtensions[] = {
1865 kVideoRtpExtensionAnswer[0],
1866 RtpHeaderExtension(kVideoRtpExtension2[1].uri, 12),
1867 kVideoRtpExtension2[2],
1868 };
1869
1870 const AudioContentDescription* updated_acd =
1871 GetFirstAudioContentDescription(updated_offer.get());
1872 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
1873 updated_acd->rtp_header_extensions());
1874
1875 const VideoContentDescription* updated_vcd =
1876 GetFirstVideoContentDescription(updated_offer.get());
1877 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
1878 updated_vcd->rtp_header_extensions());
1879 }
1880
1881 // Verify that if the same RTP extension URI is used for audio and video, the
1882 // same ID is used. Also verify that the ID isn't changed when creating an
1883 // updated offer (this was previously a bug).
TEST_F(MediaSessionDescriptionFactoryTest,RtpHeaderExtensionIdReused)1884 TEST_F(MediaSessionDescriptionFactoryTest,
1885 RtpHeaderExtensionIdReused) {
1886 MediaSessionOptions opts;
1887 opts.recv_audio = true;
1888 opts.recv_video = true;
1889
1890 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
1891 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
1892
1893 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1894
1895 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
1896 // the video extensions.
1897 const RtpHeaderExtension kExpectedVideoRtpExtension[] = {
1898 kVideoRtpExtension3[0],
1899 kAudioRtpExtension3[1],
1900 };
1901
1902 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
1903 GetFirstAudioContentDescription(
1904 offer.get())->rtp_header_extensions());
1905 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
1906 GetFirstVideoContentDescription(
1907 offer.get())->rtp_header_extensions());
1908
1909 // Nothing should change when creating a new offer
1910 rtc::scoped_ptr<SessionDescription> updated_offer(
1911 f1_.CreateOffer(opts, offer.get()));
1912
1913 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
1914 GetFirstAudioContentDescription(
1915 updated_offer.get())->rtp_header_extensions());
1916 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
1917 GetFirstVideoContentDescription(
1918 updated_offer.get())->rtp_header_extensions());
1919 }
1920
TEST(MediaSessionDescription,CopySessionDescription)1921 TEST(MediaSessionDescription, CopySessionDescription) {
1922 SessionDescription source;
1923 cricket::ContentGroup group(cricket::CN_AUDIO);
1924 source.AddGroup(group);
1925 AudioContentDescription* acd(new AudioContentDescription());
1926 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
1927 acd->AddLegacyStream(1);
1928 source.AddContent(cricket::CN_AUDIO, cricket::NS_JINGLE_RTP, acd);
1929 VideoContentDescription* vcd(new VideoContentDescription());
1930 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
1931 vcd->AddLegacyStream(2);
1932 source.AddContent(cricket::CN_VIDEO, cricket::NS_JINGLE_RTP, vcd);
1933
1934 rtc::scoped_ptr<SessionDescription> copy(source.Copy());
1935 ASSERT_TRUE(copy.get() != NULL);
1936 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
1937 const ContentInfo* ac = copy->GetContentByName("audio");
1938 const ContentInfo* vc = copy->GetContentByName("video");
1939 ASSERT_TRUE(ac != NULL);
1940 ASSERT_TRUE(vc != NULL);
1941 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
1942 const AudioContentDescription* acd_copy =
1943 static_cast<const AudioContentDescription*>(ac->description);
1944 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
1945 EXPECT_EQ(1u, acd->first_ssrc());
1946
1947 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
1948 const VideoContentDescription* vcd_copy =
1949 static_cast<const VideoContentDescription*>(vc->description);
1950 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
1951 EXPECT_EQ(2u, vcd->first_ssrc());
1952 }
1953
1954 // The below TestTransportInfoXXX tests create different offers/answers, and
1955 // ensure the TransportInfo in the SessionDescription matches what we expect.
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoOfferAudio)1956 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
1957 MediaSessionOptions options;
1958 options.recv_audio = true;
1959 TestTransportInfo(true, options, false);
1960 }
1961
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoOfferAudioCurrent)1962 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
1963 MediaSessionOptions options;
1964 options.recv_audio = true;
1965 TestTransportInfo(true, options, true);
1966 }
1967
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoOfferMultimedia)1968 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
1969 MediaSessionOptions options;
1970 options.recv_audio = true;
1971 options.recv_video = true;
1972 options.data_channel_type = cricket::DCT_RTP;
1973 TestTransportInfo(true, options, false);
1974 }
1975
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoOfferMultimediaCurrent)1976 TEST_F(MediaSessionDescriptionFactoryTest,
1977 TestTransportInfoOfferMultimediaCurrent) {
1978 MediaSessionOptions options;
1979 options.recv_audio = true;
1980 options.recv_video = true;
1981 options.data_channel_type = cricket::DCT_RTP;
1982 TestTransportInfo(true, options, true);
1983 }
1984
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoOfferBundle)1985 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
1986 MediaSessionOptions options;
1987 options.recv_audio = true;
1988 options.recv_video = true;
1989 options.data_channel_type = cricket::DCT_RTP;
1990 options.bundle_enabled = true;
1991 TestTransportInfo(true, options, false);
1992 }
1993
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoOfferBundleCurrent)1994 TEST_F(MediaSessionDescriptionFactoryTest,
1995 TestTransportInfoOfferBundleCurrent) {
1996 MediaSessionOptions options;
1997 options.recv_audio = true;
1998 options.recv_video = true;
1999 options.data_channel_type = cricket::DCT_RTP;
2000 options.bundle_enabled = true;
2001 TestTransportInfo(true, options, true);
2002 }
2003
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoAnswerAudio)2004 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
2005 MediaSessionOptions options;
2006 options.recv_audio = true;
2007 TestTransportInfo(false, options, false);
2008 }
2009
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoAnswerAudioCurrent)2010 TEST_F(MediaSessionDescriptionFactoryTest,
2011 TestTransportInfoAnswerAudioCurrent) {
2012 MediaSessionOptions options;
2013 options.recv_audio = true;
2014 TestTransportInfo(false, options, true);
2015 }
2016
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoAnswerMultimedia)2017 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
2018 MediaSessionOptions options;
2019 options.recv_audio = true;
2020 options.recv_video = true;
2021 options.data_channel_type = cricket::DCT_RTP;
2022 TestTransportInfo(false, options, false);
2023 }
2024
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoAnswerMultimediaCurrent)2025 TEST_F(MediaSessionDescriptionFactoryTest,
2026 TestTransportInfoAnswerMultimediaCurrent) {
2027 MediaSessionOptions options;
2028 options.recv_audio = true;
2029 options.recv_video = true;
2030 options.data_channel_type = cricket::DCT_RTP;
2031 TestTransportInfo(false, options, true);
2032 }
2033
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoAnswerBundle)2034 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
2035 MediaSessionOptions options;
2036 options.recv_audio = true;
2037 options.recv_video = true;
2038 options.data_channel_type = cricket::DCT_RTP;
2039 options.bundle_enabled = true;
2040 TestTransportInfo(false, options, false);
2041 }
2042
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoAnswerBundleCurrent)2043 TEST_F(MediaSessionDescriptionFactoryTest,
2044 TestTransportInfoAnswerBundleCurrent) {
2045 MediaSessionOptions options;
2046 options.recv_audio = true;
2047 options.recv_video = true;
2048 options.data_channel_type = cricket::DCT_RTP;
2049 options.bundle_enabled = true;
2050 TestTransportInfo(false, options, true);
2051 }
2052
2053 // Create an offer with bundle enabled and verify the crypto parameters are
2054 // the common set of the available cryptos.
TEST_F(MediaSessionDescriptionFactoryTest,TestCryptoWithOfferBundle)2055 TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
2056 TestCryptoWithBundle(true);
2057 }
2058
2059 // Create an answer with bundle enabled and verify the crypto parameters are
2060 // the common set of the available cryptos.
TEST_F(MediaSessionDescriptionFactoryTest,TestCryptoWithAnswerBundle)2061 TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
2062 TestCryptoWithBundle(false);
2063 }
2064
2065 // Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
2066 // DTLS is not enabled locally.
TEST_F(MediaSessionDescriptionFactoryTest,TestOfferDtlsSavpfWithoutDtlsFailed)2067 TEST_F(MediaSessionDescriptionFactoryTest,
2068 TestOfferDtlsSavpfWithoutDtlsFailed) {
2069 f1_.set_secure(SEC_ENABLED);
2070 f2_.set_secure(SEC_ENABLED);
2071 tdf1_.set_secure(SEC_DISABLED);
2072 tdf2_.set_secure(SEC_DISABLED);
2073
2074 rtc::scoped_ptr<SessionDescription> offer(
2075 f1_.CreateOffer(MediaSessionOptions(), NULL));
2076 ASSERT_TRUE(offer.get() != NULL);
2077 ContentInfo* offer_content = offer->GetContentByName("audio");
2078 ASSERT_TRUE(offer_content != NULL);
2079 AudioContentDescription* offer_audio_desc =
2080 static_cast<AudioContentDescription*>(offer_content->description);
2081 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2082
2083 rtc::scoped_ptr<SessionDescription> answer(
2084 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
2085 ASSERT_TRUE(answer != NULL);
2086 ContentInfo* answer_content = answer->GetContentByName("audio");
2087 ASSERT_TRUE(answer_content != NULL);
2088
2089 ASSERT_TRUE(answer_content->rejected);
2090 }
2091
2092 // Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
2093 // UDP/TLS/RTP/SAVPF.
TEST_F(MediaSessionDescriptionFactoryTest,TestOfferDtlsSavpfCreateAnswer)2094 TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
2095 f1_.set_secure(SEC_ENABLED);
2096 f2_.set_secure(SEC_ENABLED);
2097 tdf1_.set_secure(SEC_ENABLED);
2098 tdf2_.set_secure(SEC_ENABLED);
2099
2100 rtc::scoped_ptr<SessionDescription> offer(
2101 f1_.CreateOffer(MediaSessionOptions(), NULL));
2102 ASSERT_TRUE(offer.get() != NULL);
2103 ContentInfo* offer_content = offer->GetContentByName("audio");
2104 ASSERT_TRUE(offer_content != NULL);
2105 AudioContentDescription* offer_audio_desc =
2106 static_cast<AudioContentDescription*>(offer_content->description);
2107 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2108
2109 rtc::scoped_ptr<SessionDescription> answer(
2110 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
2111 ASSERT_TRUE(answer != NULL);
2112
2113 const ContentInfo* answer_content = answer->GetContentByName("audio");
2114 ASSERT_TRUE(answer_content != NULL);
2115 ASSERT_FALSE(answer_content->rejected);
2116
2117 const AudioContentDescription* answer_audio_desc =
2118 static_cast<const AudioContentDescription*>(answer_content->description);
2119 EXPECT_EQ(std::string(cricket::kMediaProtocolDtlsSavpf),
2120 answer_audio_desc->protocol());
2121 }
2122
2123 // Test that we include both SDES and DTLS in the offer, but only include SDES
2124 // in the answer if DTLS isn't negotiated.
TEST_F(MediaSessionDescriptionFactoryTest,TestCryptoDtls)2125 TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
2126 f1_.set_secure(SEC_ENABLED);
2127 f2_.set_secure(SEC_ENABLED);
2128 tdf1_.set_secure(SEC_ENABLED);
2129 tdf2_.set_secure(SEC_DISABLED);
2130 MediaSessionOptions options;
2131 options.recv_audio = true;
2132 options.recv_video = true;
2133 rtc::scoped_ptr<SessionDescription> offer, answer;
2134 const cricket::MediaContentDescription* audio_media_desc;
2135 const cricket::MediaContentDescription* video_media_desc;
2136 const cricket::TransportDescription* audio_trans_desc;
2137 const cricket::TransportDescription* video_trans_desc;
2138
2139 // Generate an offer with SDES and DTLS support.
2140 offer.reset(f1_.CreateOffer(options, NULL));
2141 ASSERT_TRUE(offer.get() != NULL);
2142
2143 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2144 offer->GetContentDescriptionByName("audio"));
2145 ASSERT_TRUE(audio_media_desc != NULL);
2146 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
2147 offer->GetContentDescriptionByName("video"));
2148 ASSERT_TRUE(video_media_desc != NULL);
2149 EXPECT_EQ(2u, audio_media_desc->cryptos().size());
2150 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2151
2152 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2153 ASSERT_TRUE(audio_trans_desc != NULL);
2154 video_trans_desc = offer->GetTransportDescriptionByName("video");
2155 ASSERT_TRUE(video_trans_desc != NULL);
2156 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2157 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
2158
2159 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
2160 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2161 ASSERT_TRUE(answer.get() != NULL);
2162
2163 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2164 answer->GetContentDescriptionByName("audio"));
2165 ASSERT_TRUE(audio_media_desc != NULL);
2166 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
2167 answer->GetContentDescriptionByName("video"));
2168 ASSERT_TRUE(video_media_desc != NULL);
2169 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
2170 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2171
2172 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2173 ASSERT_TRUE(audio_trans_desc != NULL);
2174 video_trans_desc = answer->GetTransportDescriptionByName("video");
2175 ASSERT_TRUE(video_trans_desc != NULL);
2176 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
2177 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
2178
2179 // Enable DTLS; the answer should now only have DTLS support.
2180 tdf2_.set_secure(SEC_ENABLED);
2181 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2182 ASSERT_TRUE(answer.get() != NULL);
2183
2184 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2185 answer->GetContentDescriptionByName("audio"));
2186 ASSERT_TRUE(audio_media_desc != NULL);
2187 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
2188 answer->GetContentDescriptionByName("video"));
2189 ASSERT_TRUE(video_media_desc != NULL);
2190 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2191 EXPECT_TRUE(video_media_desc->cryptos().empty());
2192 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2193 audio_media_desc->protocol());
2194 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2195 video_media_desc->protocol());
2196
2197 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2198 ASSERT_TRUE(audio_trans_desc != NULL);
2199 video_trans_desc = answer->GetTransportDescriptionByName("video");
2200 ASSERT_TRUE(video_trans_desc != NULL);
2201 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2202 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
2203
2204 // Try creating offer again. DTLS enabled now, crypto's should be empty
2205 // in new offer.
2206 offer.reset(f1_.CreateOffer(options, offer.get()));
2207 ASSERT_TRUE(offer.get() != NULL);
2208 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2209 offer->GetContentDescriptionByName("audio"));
2210 ASSERT_TRUE(audio_media_desc != NULL);
2211 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
2212 offer->GetContentDescriptionByName("video"));
2213 ASSERT_TRUE(video_media_desc != NULL);
2214 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2215 EXPECT_TRUE(video_media_desc->cryptos().empty());
2216
2217 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2218 ASSERT_TRUE(audio_trans_desc != NULL);
2219 video_trans_desc = offer->GetTransportDescriptionByName("video");
2220 ASSERT_TRUE(video_trans_desc != NULL);
2221 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2222 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
2223 }
2224
2225 // Test that an answer can't be created if cryptos are required but the offer is
2226 // unsecure.
TEST_F(MediaSessionDescriptionFactoryTest,TestSecureAnswerToUnsecureOffer)2227 TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
2228 MediaSessionOptions options;
2229 f1_.set_secure(SEC_DISABLED);
2230 tdf1_.set_secure(SEC_DISABLED);
2231 f2_.set_secure(SEC_REQUIRED);
2232 tdf1_.set_secure(SEC_ENABLED);
2233
2234 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(options,
2235 NULL));
2236 ASSERT_TRUE(offer.get() != NULL);
2237 rtc::scoped_ptr<SessionDescription> answer(
2238 f2_.CreateAnswer(offer.get(), options, NULL));
2239 EXPECT_TRUE(answer.get() == NULL);
2240 }
2241
2242 // Test that we accept a DTLS offer without SDES and create an appropriate
2243 // answer.
TEST_F(MediaSessionDescriptionFactoryTest,TestCryptoOfferDtlsButNotSdes)2244 TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
2245 f1_.set_secure(SEC_DISABLED);
2246 f2_.set_secure(SEC_ENABLED);
2247 tdf1_.set_secure(SEC_ENABLED);
2248 tdf2_.set_secure(SEC_ENABLED);
2249 MediaSessionOptions options;
2250 options.recv_audio = true;
2251 options.recv_video = true;
2252 options.data_channel_type = cricket::DCT_RTP;
2253
2254 rtc::scoped_ptr<SessionDescription> offer, answer;
2255
2256 // Generate an offer with DTLS but without SDES.
2257 offer.reset(f1_.CreateOffer(options, NULL));
2258 ASSERT_TRUE(offer.get() != NULL);
2259
2260 const AudioContentDescription* audio_offer =
2261 GetFirstAudioContentDescription(offer.get());
2262 ASSERT_TRUE(audio_offer->cryptos().empty());
2263 const VideoContentDescription* video_offer =
2264 GetFirstVideoContentDescription(offer.get());
2265 ASSERT_TRUE(video_offer->cryptos().empty());
2266 const DataContentDescription* data_offer =
2267 GetFirstDataContentDescription(offer.get());
2268 ASSERT_TRUE(data_offer->cryptos().empty());
2269
2270 const cricket::TransportDescription* audio_offer_trans_desc =
2271 offer->GetTransportDescriptionByName("audio");
2272 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
2273 const cricket::TransportDescription* video_offer_trans_desc =
2274 offer->GetTransportDescriptionByName("video");
2275 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
2276 const cricket::TransportDescription* data_offer_trans_desc =
2277 offer->GetTransportDescriptionByName("data");
2278 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
2279
2280 // Generate an answer with DTLS.
2281 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2282 ASSERT_TRUE(answer.get() != NULL);
2283
2284 const cricket::TransportDescription* audio_answer_trans_desc =
2285 answer->GetTransportDescriptionByName("audio");
2286 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
2287 const cricket::TransportDescription* video_answer_trans_desc =
2288 answer->GetTransportDescriptionByName("video");
2289 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
2290 const cricket::TransportDescription* data_answer_trans_desc =
2291 answer->GetTransportDescriptionByName("data");
2292 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
2293 }
2294
2295 // Verifies if vad_enabled option is set to false, CN codecs are not present in
2296 // offer or answer.
TEST_F(MediaSessionDescriptionFactoryTest,TestVADEnableOption)2297 TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
2298 MediaSessionOptions options;
2299 options.recv_audio = true;
2300 options.recv_video = true;
2301 rtc::scoped_ptr<SessionDescription> offer(
2302 f1_.CreateOffer(options, NULL));
2303 ASSERT_TRUE(offer.get() != NULL);
2304 const ContentInfo* audio_content = offer->GetContentByName("audio");
2305 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
2306
2307 options.vad_enabled = false;
2308 offer.reset(f1_.CreateOffer(options, NULL));
2309 ASSERT_TRUE(offer.get() != NULL);
2310 audio_content = offer->GetContentByName("audio");
2311 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
2312 rtc::scoped_ptr<SessionDescription> answer(
2313 f1_.CreateAnswer(offer.get(), options, NULL));
2314 ASSERT_TRUE(answer.get() != NULL);
2315 audio_content = answer->GetContentByName("audio");
2316 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
2317 }
2318
2319 // Test that the content name ("mid" in SDP) is unchanged when creating a
2320 // new offer.
TEST_F(MediaSessionDescriptionFactoryTest,TestContentNameNotChangedInSubsequentOffers)2321 TEST_F(MediaSessionDescriptionFactoryTest,
2322 TestContentNameNotChangedInSubsequentOffers) {
2323 MediaSessionOptions opts;
2324 opts.recv_audio = true;
2325 opts.recv_video = true;
2326 opts.data_channel_type = cricket::DCT_SCTP;
2327 // Create offer and modify the default content names.
2328 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
2329 for (ContentInfo& content : offer->contents()) {
2330 content.name.append("_modified");
2331 }
2332
2333 rtc::scoped_ptr<SessionDescription> updated_offer(
2334 f1_.CreateOffer(opts, offer.get()));
2335 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
2336 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
2337 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
2338 ASSERT_TRUE(audio_content != nullptr);
2339 ASSERT_TRUE(video_content != nullptr);
2340 ASSERT_TRUE(data_content != nullptr);
2341 EXPECT_EQ("audio_modified", audio_content->name);
2342 EXPECT_EQ("video_modified", video_content->name);
2343 EXPECT_EQ("data_modified", data_content->name);
2344 }
2345