3 * Copyright 2004 Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
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.
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.
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"
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)
49 #define ASSERT_CRYPTO(cd, s, cs) \
50 ASSERT_EQ(cricket::CT_NONE, cd->crypto_required()); \
51 ASSERT_EQ(0U, cd->cryptos().size());
54 typedef std::vector<cricket::Candidate> Candidates;
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::GetFirstAudioContentDescription;
73 using cricket::GetFirstVideoContentDescription;
74 using cricket::GetFirstDataContentDescription;
75 using cricket::kAutoBandwidth;
76 using cricket::AudioCodec;
77 using cricket::VideoCodec;
78 using cricket::DataCodec;
79 using cricket::NS_JINGLE_RTP;
80 using cricket::MEDIA_TYPE_AUDIO;
81 using cricket::MEDIA_TYPE_VIDEO;
82 using cricket::MEDIA_TYPE_DATA;
83 using cricket::RtpHeaderExtension;
84 using cricket::SEC_DISABLED;
85 using cricket::SEC_ENABLED;
86 using cricket::SEC_REQUIRED;
87 using cricket::CS_AES_CM_128_HMAC_SHA1_32;
88 using cricket::CS_AES_CM_128_HMAC_SHA1_80;
90 static const AudioCodec kAudioCodecs1[] = {
91 AudioCodec(103, "ISAC", 16000, -1, 1, 6),
92 AudioCodec(102, "iLBC", 8000, 13300, 1, 5),
93 AudioCodec(0, "PCMU", 8000, 64000, 1, 4),
94 AudioCodec(8, "PCMA", 8000, 64000, 1, 3),
95 AudioCodec(117, "red", 8000, 0, 1, 2),
96 AudioCodec(107, "CN", 48000, 0, 1, 1)
99 static const AudioCodec kAudioCodecs2[] = {
100 AudioCodec(126, "speex", 16000, 22000, 1, 3),
101 AudioCodec(0, "PCMU", 8000, 64000, 1, 2),
102 AudioCodec(127, "iLBC", 8000, 13300, 1, 1),
105 static const AudioCodec kAudioCodecsAnswer[] = {
106 AudioCodec(102, "iLBC", 8000, 13300, 1, 5),
107 AudioCodec(0, "PCMU", 8000, 64000, 1, 4),
110 static const VideoCodec kVideoCodecs1[] = {
111 VideoCodec(96, "H264-SVC", 320, 200, 30, 2),
112 VideoCodec(97, "H264", 320, 200, 30, 1)
115 static const VideoCodec kVideoCodecs2[] = {
116 VideoCodec(126, "H264", 320, 200, 30, 2),
117 VideoCodec(127, "H263", 320, 200, 30, 1)
120 static const VideoCodec kVideoCodecsAnswer[] = {
121 VideoCodec(97, "H264", 320, 200, 30, 1)
124 static const DataCodec kDataCodecs1[] = {
125 DataCodec(98, "binary-data", 2),
126 DataCodec(99, "utf8-text", 1)
129 static const DataCodec kDataCodecs2[] = {
130 DataCodec(126, "binary-data", 2),
131 DataCodec(127, "utf8-text", 1)
134 static const DataCodec kDataCodecsAnswer[] = {
135 DataCodec(98, "binary-data", 2),
136 DataCodec(99, "utf8-text", 1)
139 static const RtpHeaderExtension kAudioRtpExtension1[] = {
140 RtpHeaderExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
141 RtpHeaderExtension("http://google.com/testing/audio_something", 10),
144 static const RtpHeaderExtension kAudioRtpExtension2[] = {
145 RtpHeaderExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
146 RtpHeaderExtension("http://google.com/testing/audio_something_else", 8),
147 RtpHeaderExtension("http://google.com/testing/both_audio_and_video", 7),
150 static const RtpHeaderExtension kAudioRtpExtensionAnswer[] = {
151 RtpHeaderExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
154 static const RtpHeaderExtension kVideoRtpExtension1[] = {
155 RtpHeaderExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
156 RtpHeaderExtension("http://google.com/testing/video_something", 13),
159 static const RtpHeaderExtension kVideoRtpExtension2[] = {
160 RtpHeaderExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
161 RtpHeaderExtension("http://google.com/testing/video_something_else", 14),
162 RtpHeaderExtension("http://google.com/testing/both_audio_and_video", 7),
165 static const RtpHeaderExtension kVideoRtpExtensionAnswer[] = {
166 RtpHeaderExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
169 static const uint32 kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
170 static const uint32 kSimSsrc[] = {10, 20, 30};
171 static const uint32 kFec1Ssrc[] = {10, 11};
172 static const uint32 kFec2Ssrc[] = {20, 21};
173 static const uint32 kFec3Ssrc[] = {30, 31};
175 static const char kMediaStream1[] = "stream_1";
176 static const char kMediaStream2[] = "stream_2";
177 static const char kVideoTrack1[] = "video_1";
178 static const char kVideoTrack2[] = "video_2";
179 static const char kAudioTrack1[] = "audio_1";
180 static const char kAudioTrack2[] = "audio_2";
181 static const char kAudioTrack3[] = "audio_3";
182 static const char kDataTrack1[] = "data_1";
183 static const char kDataTrack2[] = "data_2";
184 static const char kDataTrack3[] = "data_3";
186 static bool IsMediaContentOfType(const ContentInfo* content,
187 MediaType media_type) {
188 const MediaContentDescription* mdesc =
189 static_cast<const MediaContentDescription*>(content->description);
190 return mdesc && mdesc->type() == media_type;
193 static cricket::MediaContentDirection
194 GetMediaDirection(const ContentInfo* content) {
195 cricket::MediaContentDescription* desc =
196 reinterpret_cast<cricket::MediaContentDescription*>(content->description);
197 return desc->direction();
200 class MediaSessionDescriptionFactoryTest : public testing::Test {
202 MediaSessionDescriptionFactoryTest()
203 : f1_(&tdf1_), f2_(&tdf2_), id1_("id1"), id2_("id2") {
204 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1));
205 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
206 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
207 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2));
208 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
209 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
210 tdf1_.set_identity(&id1_);
211 tdf2_.set_identity(&id2_);
214 // Create a video StreamParamsVec object with:
215 // - one video stream with 3 simulcast streams and FEC,
216 StreamParamsVec CreateComplexVideoStreamParamsVec() {
217 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
218 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
219 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
220 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
222 std::vector<SsrcGroup> ssrc_groups;
223 ssrc_groups.push_back(sim_group);
224 ssrc_groups.push_back(fec_group1);
225 ssrc_groups.push_back(fec_group2);
226 ssrc_groups.push_back(fec_group3);
228 StreamParams simulcast_params;
229 simulcast_params.id = kVideoTrack1;
230 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
231 simulcast_params.ssrc_groups = ssrc_groups;
232 simulcast_params.cname = "Video_SIM_FEC";
233 simulcast_params.sync_label = kMediaStream1;
235 StreamParamsVec video_streams;
236 video_streams.push_back(simulcast_params);
238 return video_streams;
241 bool CompareCryptoParams(const CryptoParamsVec& c1,
242 const CryptoParamsVec& c2) {
243 if (c1.size() != c2.size())
245 for (size_t i = 0; i < c1.size(); ++i)
246 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
247 c1[i].key_params != c2[i].key_params ||
248 c1[i].session_params != c2[i].session_params)
253 void TestTransportInfo(bool offer, const MediaSessionOptions& options,
254 bool has_current_desc) {
255 const std::string current_audio_ufrag = "current_audio_ufrag";
256 const std::string current_audio_pwd = "current_audio_pwd";
257 const std::string current_video_ufrag = "current_video_ufrag";
258 const std::string current_video_pwd = "current_video_pwd";
259 const std::string current_data_ufrag = "current_data_ufrag";
260 const std::string current_data_pwd = "current_data_pwd";
261 rtc::scoped_ptr<SessionDescription> current_desc;
262 rtc::scoped_ptr<SessionDescription> desc;
263 if (has_current_desc) {
264 current_desc.reset(new SessionDescription());
265 EXPECT_TRUE(current_desc->AddTransportInfo(
266 TransportInfo("audio",
267 TransportDescription("",
269 current_audio_pwd))));
270 EXPECT_TRUE(current_desc->AddTransportInfo(
271 TransportInfo("video",
272 TransportDescription("",
274 current_video_pwd))));
275 EXPECT_TRUE(current_desc->AddTransportInfo(
276 TransportInfo("data",
277 TransportDescription("",
279 current_data_pwd))));
282 desc.reset(f1_.CreateOffer(options, current_desc.get()));
284 rtc::scoped_ptr<SessionDescription> offer;
285 offer.reset(f1_.CreateOffer(options, NULL));
286 desc.reset(f1_.CreateAnswer(offer.get(), options, current_desc.get()));
288 ASSERT_TRUE(desc.get() != NULL);
289 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
290 if (options.has_audio()) {
291 EXPECT_TRUE(ti_audio != NULL);
292 if (has_current_desc) {
293 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
294 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
296 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
297 ti_audio->description.ice_ufrag.size());
298 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
299 ti_audio->description.ice_pwd.size());
303 EXPECT_TRUE(ti_audio == NULL);
305 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
306 if (options.has_video()) {
307 EXPECT_TRUE(ti_video != NULL);
308 if (options.bundle_enabled) {
309 EXPECT_EQ(ti_audio->description.ice_ufrag,
310 ti_video->description.ice_ufrag);
311 EXPECT_EQ(ti_audio->description.ice_pwd,
312 ti_video->description.ice_pwd);
314 if (has_current_desc) {
315 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
316 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
318 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
319 ti_video->description.ice_ufrag.size());
320 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
321 ti_video->description.ice_pwd.size());
325 EXPECT_TRUE(ti_video == NULL);
327 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
328 if (options.has_data()) {
329 EXPECT_TRUE(ti_data != NULL);
330 if (options.bundle_enabled) {
331 EXPECT_EQ(ti_audio->description.ice_ufrag,
332 ti_data->description.ice_ufrag);
333 EXPECT_EQ(ti_audio->description.ice_pwd,
334 ti_data->description.ice_pwd);
336 if (has_current_desc) {
337 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
338 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
340 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
341 ti_data->description.ice_ufrag.size());
342 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
343 ti_data->description.ice_pwd.size());
347 EXPECT_TRUE(ti_video == NULL);
351 void TestCryptoWithBundle(bool offer) {
352 f1_.set_secure(SEC_ENABLED);
353 MediaSessionOptions options;
354 options.recv_audio = true;
355 options.recv_video = true;
356 options.data_channel_type = cricket::DCT_RTP;
357 rtc::scoped_ptr<SessionDescription> ref_desc;
358 rtc::scoped_ptr<SessionDescription> desc;
360 options.bundle_enabled = false;
361 ref_desc.reset(f1_.CreateOffer(options, NULL));
362 options.bundle_enabled = true;
363 desc.reset(f1_.CreateOffer(options, ref_desc.get()));
365 options.bundle_enabled = true;
366 ref_desc.reset(f1_.CreateOffer(options, NULL));
367 desc.reset(f1_.CreateAnswer(ref_desc.get(), options, NULL));
369 ASSERT_TRUE(desc.get() != NULL);
370 const cricket::MediaContentDescription* audio_media_desc =
371 static_cast<const cricket::MediaContentDescription*>(
372 desc.get()->GetContentDescriptionByName("audio"));
373 ASSERT_TRUE(audio_media_desc != NULL);
374 const cricket::MediaContentDescription* video_media_desc =
375 static_cast<const cricket::MediaContentDescription*>(
376 desc.get()->GetContentDescriptionByName("video"));
377 ASSERT_TRUE(video_media_desc != NULL);
378 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
379 video_media_desc->cryptos()));
380 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
381 EXPECT_EQ(std::string(CS_AES_CM_128_HMAC_SHA1_80),
382 audio_media_desc->cryptos()[0].cipher_suite);
384 // Verify the selected crypto is one from the reference audio
386 const cricket::MediaContentDescription* ref_audio_media_desc =
387 static_cast<const cricket::MediaContentDescription*>(
388 ref_desc.get()->GetContentDescriptionByName("audio"));
390 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
391 if (ref_audio_media_desc->cryptos()[i].Matches(
392 audio_media_desc->cryptos()[0])) {
400 // This test that the audio and video media direction is set to
401 // |expected_direction_in_answer| in an answer if the offer direction is set
402 // to |direction_in_offer|.
403 void TestMediaDirectionInAnswer(
404 cricket::MediaContentDirection direction_in_offer,
405 cricket::MediaContentDirection expected_direction_in_answer) {
406 MediaSessionOptions opts;
407 opts.recv_video = true;
408 rtc::scoped_ptr<SessionDescription> offer(
409 f1_.CreateOffer(opts, NULL));
410 ASSERT_TRUE(offer.get() != NULL);
411 ContentInfo* ac_offer= offer->GetContentByName("audio");
412 ASSERT_TRUE(ac_offer != NULL);
413 AudioContentDescription* acd_offer =
414 static_cast<AudioContentDescription*>(ac_offer->description);
415 acd_offer->set_direction(direction_in_offer);
416 ContentInfo* vc_offer= offer->GetContentByName("video");
417 ASSERT_TRUE(vc_offer != NULL);
418 VideoContentDescription* vcd_offer =
419 static_cast<VideoContentDescription*>(vc_offer->description);
420 vcd_offer->set_direction(direction_in_offer);
422 rtc::scoped_ptr<SessionDescription> answer(
423 f2_.CreateAnswer(offer.get(), opts, NULL));
424 const AudioContentDescription* acd_answer =
425 GetFirstAudioContentDescription(answer.get());
426 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
427 const VideoContentDescription* vcd_answer =
428 GetFirstVideoContentDescription(answer.get());
429 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
432 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
433 const cricket::ContentDescription* description = content->description;
434 ASSERT(description != NULL);
435 const cricket::AudioContentDescription* audio_content_desc =
436 static_cast<const cricket::AudioContentDescription*>(description);
437 ASSERT(audio_content_desc != NULL);
438 for (size_t i = 0; i < audio_content_desc->codecs().size(); ++i) {
439 if (audio_content_desc->codecs()[i].name == "CN")
446 MediaSessionDescriptionFactory f1_;
447 MediaSessionDescriptionFactory f2_;
448 TransportDescriptionFactory tdf1_;
449 TransportDescriptionFactory tdf2_;
450 rtc::FakeSSLIdentity id1_;
451 rtc::FakeSSLIdentity id2_;
454 // Create a typical audio offer, and ensure it matches what we expect.
455 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
456 f1_.set_secure(SEC_ENABLED);
457 rtc::scoped_ptr<SessionDescription> offer(
458 f1_.CreateOffer(MediaSessionOptions(), NULL));
459 ASSERT_TRUE(offer.get() != NULL);
460 const ContentInfo* ac = offer->GetContentByName("audio");
461 const ContentInfo* vc = offer->GetContentByName("video");
462 ASSERT_TRUE(ac != NULL);
463 ASSERT_TRUE(vc == NULL);
464 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
465 const AudioContentDescription* acd =
466 static_cast<const AudioContentDescription*>(ac->description);
467 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
468 EXPECT_EQ(f1_.audio_codecs(), acd->codecs());
469 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
470 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
471 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
472 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
473 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
476 // Create a typical video offer, and ensure it matches what we expect.
477 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
478 MediaSessionOptions opts;
479 opts.recv_video = true;
480 f1_.set_secure(SEC_ENABLED);
481 rtc::scoped_ptr<SessionDescription>
482 offer(f1_.CreateOffer(opts, NULL));
483 ASSERT_TRUE(offer.get() != NULL);
484 const ContentInfo* ac = offer->GetContentByName("audio");
485 const ContentInfo* vc = offer->GetContentByName("video");
486 ASSERT_TRUE(ac != NULL);
487 ASSERT_TRUE(vc != NULL);
488 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
489 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
490 const AudioContentDescription* acd =
491 static_cast<const AudioContentDescription*>(ac->description);
492 const VideoContentDescription* vcd =
493 static_cast<const VideoContentDescription*>(vc->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 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
502 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
503 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
504 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
505 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
506 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
507 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
510 // Test creating an offer with bundle where the Codecs have the same dynamic
511 // RTP playlod type. The test verifies that the offer don't contain the
512 // duplicate RTP payload types.
513 TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
514 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
515 const AudioCodec& offered_audio_codec = f2_.audio_codecs()[0];
516 const DataCodec& offered_data_codec = f2_.data_codecs()[0];
517 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
518 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
520 MediaSessionOptions opts;
521 opts.recv_audio = true;
522 opts.recv_video = true;
523 opts.data_channel_type = cricket::DCT_RTP;
524 opts.bundle_enabled = true;
525 rtc::scoped_ptr<SessionDescription>
526 offer(f2_.CreateOffer(opts, NULL));
527 const VideoContentDescription* vcd =
528 GetFirstVideoContentDescription(offer.get());
529 const AudioContentDescription* acd =
530 GetFirstAudioContentDescription(offer.get());
531 const DataContentDescription* dcd =
532 GetFirstDataContentDescription(offer.get());
533 ASSERT_TRUE(NULL != vcd);
534 ASSERT_TRUE(NULL != acd);
535 ASSERT_TRUE(NULL != dcd);
536 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
537 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
538 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
539 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
540 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
541 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
544 // Test creating an updated offer with with bundle, audio, video and data
545 // after an audio only session has been negotiated.
546 TEST_F(MediaSessionDescriptionFactoryTest,
547 TestCreateUpdatedVideoOfferWithBundle) {
548 f1_.set_secure(SEC_ENABLED);
549 f2_.set_secure(SEC_ENABLED);
550 MediaSessionOptions opts;
551 opts.recv_audio = true;
552 opts.recv_video = false;
553 opts.data_channel_type = cricket::DCT_NONE;
554 opts.bundle_enabled = true;
555 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
556 rtc::scoped_ptr<SessionDescription> answer(
557 f2_.CreateAnswer(offer.get(), opts, NULL));
559 MediaSessionOptions updated_opts;
560 updated_opts.recv_audio = true;
561 updated_opts.recv_video = true;
562 updated_opts.data_channel_type = cricket::DCT_RTP;
563 updated_opts.bundle_enabled = true;
564 rtc::scoped_ptr<SessionDescription> updated_offer(f1_.CreateOffer(
565 updated_opts, answer.get()));
567 const AudioContentDescription* acd =
568 GetFirstAudioContentDescription(updated_offer.get());
569 const VideoContentDescription* vcd =
570 GetFirstVideoContentDescription(updated_offer.get());
571 const DataContentDescription* dcd =
572 GetFirstDataContentDescription(updated_offer.get());
573 EXPECT_TRUE(NULL != vcd);
574 EXPECT_TRUE(NULL != acd);
575 EXPECT_TRUE(NULL != dcd);
577 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
578 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
579 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
580 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
581 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
582 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
584 // Create a RTP data offer, and ensure it matches what we expect.
585 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
586 MediaSessionOptions opts;
587 opts.data_channel_type = cricket::DCT_RTP;
588 f1_.set_secure(SEC_ENABLED);
589 rtc::scoped_ptr<SessionDescription>
590 offer(f1_.CreateOffer(opts, NULL));
591 ASSERT_TRUE(offer.get() != NULL);
592 const ContentInfo* ac = offer->GetContentByName("audio");
593 const ContentInfo* dc = offer->GetContentByName("data");
594 ASSERT_TRUE(ac != NULL);
595 ASSERT_TRUE(dc != NULL);
596 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
597 EXPECT_EQ(std::string(NS_JINGLE_RTP), dc->type);
598 const AudioContentDescription* acd =
599 static_cast<const AudioContentDescription*>(ac->description);
600 const DataContentDescription* dcd =
601 static_cast<const DataContentDescription*>(dc->description);
602 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
603 EXPECT_EQ(f1_.audio_codecs(), acd->codecs());
604 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
605 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
606 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
607 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
608 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
609 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
610 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
611 EXPECT_NE(0U, dcd->first_ssrc()); // a random nonzero ssrc
612 EXPECT_EQ(cricket::kDataMaxBandwidth,
613 dcd->bandwidth()); // default bandwidth (auto)
614 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
615 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
616 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
619 // Create an SCTP data offer with bundle without error.
620 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
621 MediaSessionOptions opts;
622 opts.recv_audio = false;
623 opts.bundle_enabled = true;
624 opts.data_channel_type = cricket::DCT_SCTP;
625 f1_.set_secure(SEC_ENABLED);
626 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
627 EXPECT_TRUE(offer.get() != NULL);
628 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
631 // Test creating an sctp data channel from an already generated offer.
632 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
633 MediaSessionOptions opts;
634 opts.recv_audio = false;
635 opts.bundle_enabled = true;
636 opts.data_channel_type = cricket::DCT_SCTP;
637 f1_.set_secure(SEC_ENABLED);
638 rtc::scoped_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
639 ASSERT_TRUE(offer1.get() != NULL);
640 const ContentInfo* data = offer1->GetContentByName("data");
641 ASSERT_TRUE(data != NULL);
642 const MediaContentDescription* mdesc =
643 static_cast<const MediaContentDescription*>(data->description);
644 ASSERT_EQ(cricket::kMediaProtocolSctp, mdesc->protocol());
646 // Now set data_channel_type to 'none' (default) and make sure that the
647 // datachannel type that gets generated from the previous offer, is of the
649 opts.data_channel_type = cricket::DCT_NONE;
650 rtc::scoped_ptr<SessionDescription> offer2(
651 f1_.CreateOffer(opts, offer1.get()));
652 data = offer2->GetContentByName("data");
653 ASSERT_TRUE(data != NULL);
654 mdesc = static_cast<const MediaContentDescription*>(data->description);
655 EXPECT_EQ(cricket::kMediaProtocolSctp, mdesc->protocol());
658 // Create an audio, video offer without legacy StreamParams.
659 TEST_F(MediaSessionDescriptionFactoryTest,
660 TestCreateOfferWithoutLegacyStreams) {
661 MediaSessionOptions opts;
662 opts.recv_video = true;
663 f1_.set_add_legacy_streams(false);
664 rtc::scoped_ptr<SessionDescription>
665 offer(f1_.CreateOffer(opts, NULL));
666 ASSERT_TRUE(offer.get() != NULL);
667 const ContentInfo* ac = offer->GetContentByName("audio");
668 const ContentInfo* vc = offer->GetContentByName("video");
669 ASSERT_TRUE(ac != NULL);
670 ASSERT_TRUE(vc != NULL);
671 const AudioContentDescription* acd =
672 static_cast<const AudioContentDescription*>(ac->description);
673 const VideoContentDescription* vcd =
674 static_cast<const VideoContentDescription*>(vc->description);
676 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
677 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
680 // Creates an audio+video sendonly offer.
681 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
682 MediaSessionOptions options;
683 options.recv_audio = false;
684 options.recv_video = false;
685 options.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack1, kMediaStream1);
686 options.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
688 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
689 ASSERT_TRUE(offer.get() != NULL);
690 EXPECT_EQ(2u, offer->contents().size());
691 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
692 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
694 EXPECT_EQ(cricket::MD_SENDONLY, GetMediaDirection(&offer->contents()[0]));
695 EXPECT_EQ(cricket::MD_SENDONLY, GetMediaDirection(&offer->contents()[1]));
698 // Verifies that the order of the media contents in the current
699 // SessionDescription is preserved in the new SessionDescription.
700 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
701 MediaSessionOptions opts;
702 opts.recv_audio = false;
703 opts.recv_video = false;
704 opts.data_channel_type = cricket::DCT_SCTP;
706 rtc::scoped_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
707 ASSERT_TRUE(offer1.get() != NULL);
708 EXPECT_EQ(1u, offer1->contents().size());
709 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
711 opts.recv_video = true;
712 rtc::scoped_ptr<SessionDescription> offer2(
713 f1_.CreateOffer(opts, offer1.get()));
714 ASSERT_TRUE(offer2.get() != NULL);
715 EXPECT_EQ(2u, offer2->contents().size());
716 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
717 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
719 opts.recv_audio = true;
720 rtc::scoped_ptr<SessionDescription> offer3(
721 f1_.CreateOffer(opts, offer2.get()));
722 ASSERT_TRUE(offer3.get() != NULL);
723 EXPECT_EQ(3u, offer3->contents().size());
724 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
725 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
726 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
728 // Verifies the default order is audio-video-data, so that the previous checks
729 // didn't pass by accident.
730 rtc::scoped_ptr<SessionDescription> offer4(f1_.CreateOffer(opts, NULL));
731 ASSERT_TRUE(offer4.get() != NULL);
732 EXPECT_EQ(3u, offer4->contents().size());
733 EXPECT_TRUE(IsMediaContentOfType(&offer4->contents()[0], MEDIA_TYPE_AUDIO));
734 EXPECT_TRUE(IsMediaContentOfType(&offer4->contents()[1], MEDIA_TYPE_VIDEO));
735 EXPECT_TRUE(IsMediaContentOfType(&offer4->contents()[2], MEDIA_TYPE_DATA));
738 // Create a typical audio answer, and ensure it matches what we expect.
739 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
740 f1_.set_secure(SEC_ENABLED);
741 f2_.set_secure(SEC_ENABLED);
742 rtc::scoped_ptr<SessionDescription> offer(
743 f1_.CreateOffer(MediaSessionOptions(), NULL));
744 ASSERT_TRUE(offer.get() != NULL);
745 rtc::scoped_ptr<SessionDescription> answer(
746 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
747 const ContentInfo* ac = answer->GetContentByName("audio");
748 const ContentInfo* vc = answer->GetContentByName("video");
749 ASSERT_TRUE(ac != NULL);
750 ASSERT_TRUE(vc == NULL);
751 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
752 const AudioContentDescription* acd =
753 static_cast<const AudioContentDescription*>(ac->description);
754 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
755 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
756 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
757 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
758 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
759 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
760 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
763 // Create a typical video answer, and ensure it matches what we expect.
764 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
765 MediaSessionOptions opts;
766 opts.recv_video = true;
767 f1_.set_secure(SEC_ENABLED);
768 f2_.set_secure(SEC_ENABLED);
769 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
770 ASSERT_TRUE(offer.get() != NULL);
771 rtc::scoped_ptr<SessionDescription> answer(
772 f2_.CreateAnswer(offer.get(), opts, NULL));
773 const ContentInfo* ac = answer->GetContentByName("audio");
774 const ContentInfo* vc = answer->GetContentByName("video");
775 ASSERT_TRUE(ac != NULL);
776 ASSERT_TRUE(vc != NULL);
777 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
778 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
779 const AudioContentDescription* acd =
780 static_cast<const AudioContentDescription*>(ac->description);
781 const VideoContentDescription* vcd =
782 static_cast<const VideoContentDescription*>(vc->description);
783 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
784 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
785 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
786 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
787 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
788 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
789 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
790 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
791 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
792 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
793 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
794 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
797 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
798 MediaSessionOptions opts;
799 opts.data_channel_type = cricket::DCT_RTP;
800 f1_.set_secure(SEC_ENABLED);
801 f2_.set_secure(SEC_ENABLED);
802 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
803 ASSERT_TRUE(offer.get() != NULL);
804 rtc::scoped_ptr<SessionDescription> answer(
805 f2_.CreateAnswer(offer.get(), opts, NULL));
806 const ContentInfo* ac = answer->GetContentByName("audio");
807 const ContentInfo* vc = answer->GetContentByName("data");
808 ASSERT_TRUE(ac != NULL);
809 ASSERT_TRUE(vc != NULL);
810 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
811 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
812 const AudioContentDescription* acd =
813 static_cast<const AudioContentDescription*>(ac->description);
814 const DataContentDescription* vcd =
815 static_cast<const DataContentDescription*>(vc->description);
816 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
817 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
818 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
819 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
820 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
821 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
822 EXPECT_EQ(MEDIA_TYPE_DATA, vcd->type());
823 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), vcd->codecs());
824 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
825 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
826 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
827 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
830 // Verifies that the order of the media contents in the offer is preserved in
832 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
833 MediaSessionOptions opts;
835 // Creates a data only offer.
836 opts.recv_audio = false;
837 opts.data_channel_type = cricket::DCT_SCTP;
838 rtc::scoped_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
839 ASSERT_TRUE(offer1.get() != NULL);
841 // Appends audio to the offer.
842 opts.recv_audio = true;
843 rtc::scoped_ptr<SessionDescription> offer2(
844 f1_.CreateOffer(opts, offer1.get()));
845 ASSERT_TRUE(offer2.get() != NULL);
847 // Appends video to the offer.
848 opts.recv_video = true;
849 rtc::scoped_ptr<SessionDescription> offer3(
850 f1_.CreateOffer(opts, offer2.get()));
851 ASSERT_TRUE(offer3.get() != NULL);
853 rtc::scoped_ptr<SessionDescription> answer(
854 f2_.CreateAnswer(offer3.get(), opts, NULL));
855 ASSERT_TRUE(answer.get() != NULL);
856 EXPECT_EQ(3u, answer->contents().size());
857 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
858 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
859 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
862 // This test that the media direction is set to send/receive in an answer if
863 // the offer is send receive.
864 TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
865 TestMediaDirectionInAnswer(cricket::MD_SENDRECV, cricket::MD_SENDRECV);
868 // This test that the media direction is set to receive only in an answer if
869 // the offer is send only.
870 TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
871 TestMediaDirectionInAnswer(cricket::MD_SENDONLY, cricket::MD_RECVONLY);
874 // This test that the media direction is set to send only in an answer if
875 // the offer is recv only.
876 TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
877 TestMediaDirectionInAnswer(cricket::MD_RECVONLY, cricket::MD_SENDONLY);
880 // This test that the media direction is set to inactive in an answer if
881 // the offer is inactive.
882 TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
883 TestMediaDirectionInAnswer(cricket::MD_INACTIVE, cricket::MD_INACTIVE);
886 // Test that a data content with an unknown protocol is rejected in an answer.
887 TEST_F(MediaSessionDescriptionFactoryTest,
888 CreateDataAnswerToOfferWithUnknownProtocol) {
889 MediaSessionOptions opts;
890 opts.data_channel_type = cricket::DCT_RTP;
891 opts.recv_audio = false;
892 f1_.set_secure(SEC_ENABLED);
893 f2_.set_secure(SEC_ENABLED);
894 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
895 ContentInfo* dc_offer= offer->GetContentByName("data");
896 ASSERT_TRUE(dc_offer != NULL);
897 DataContentDescription* dcd_offer =
898 static_cast<DataContentDescription*>(dc_offer->description);
899 ASSERT_TRUE(dcd_offer != NULL);
900 std::string protocol = "a weird unknown protocol";
901 dcd_offer->set_protocol(protocol);
903 rtc::scoped_ptr<SessionDescription> answer(
904 f2_.CreateAnswer(offer.get(), opts, NULL));
906 const ContentInfo* dc_answer = answer->GetContentByName("data");
907 ASSERT_TRUE(dc_answer != NULL);
908 EXPECT_TRUE(dc_answer->rejected);
909 const DataContentDescription* dcd_answer =
910 static_cast<const DataContentDescription*>(dc_answer->description);
911 ASSERT_TRUE(dcd_answer != NULL);
912 EXPECT_EQ(protocol, dcd_answer->protocol());
915 // Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
916 TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
917 MediaSessionOptions opts;
918 f1_.set_secure(SEC_DISABLED);
919 f2_.set_secure(SEC_DISABLED);
920 tdf1_.set_secure(SEC_DISABLED);
921 tdf2_.set_secure(SEC_DISABLED);
923 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
924 const AudioContentDescription* offer_acd =
925 GetFirstAudioContentDescription(offer.get());
926 ASSERT_TRUE(offer_acd != NULL);
927 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), offer_acd->protocol());
929 rtc::scoped_ptr<SessionDescription> answer(
930 f2_.CreateAnswer(offer.get(), opts, NULL));
932 const ContentInfo* ac_answer = answer->GetContentByName("audio");
933 ASSERT_TRUE(ac_answer != NULL);
934 EXPECT_FALSE(ac_answer->rejected);
936 const AudioContentDescription* answer_acd =
937 GetFirstAudioContentDescription(answer.get());
938 ASSERT_TRUE(answer_acd != NULL);
939 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), answer_acd->protocol());
942 // Create a video offer and answer and ensure the RTP header extensions
943 // matches what we expect.
944 TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
945 MediaSessionOptions opts;
946 opts.recv_video = true;
948 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
949 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
950 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
951 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
953 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
954 ASSERT_TRUE(offer.get() != NULL);
955 rtc::scoped_ptr<SessionDescription> answer(
956 f2_.CreateAnswer(offer.get(), opts, NULL));
958 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension1),
959 GetFirstAudioContentDescription(
960 offer.get())->rtp_header_extensions());
961 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtension1),
962 GetFirstVideoContentDescription(
963 offer.get())->rtp_header_extensions());
964 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
965 GetFirstAudioContentDescription(
966 answer.get())->rtp_header_extensions());
967 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
968 GetFirstVideoContentDescription(
969 answer.get())->rtp_header_extensions());
972 // Create an audio, video, data answer without legacy StreamParams.
973 TEST_F(MediaSessionDescriptionFactoryTest,
974 TestCreateAnswerWithoutLegacyStreams) {
975 MediaSessionOptions opts;
976 opts.recv_video = true;
977 opts.data_channel_type = cricket::DCT_RTP;
978 f1_.set_add_legacy_streams(false);
979 f2_.set_add_legacy_streams(false);
980 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
981 ASSERT_TRUE(offer.get() != NULL);
982 rtc::scoped_ptr<SessionDescription> answer(
983 f2_.CreateAnswer(offer.get(), opts, NULL));
984 const ContentInfo* ac = answer->GetContentByName("audio");
985 const ContentInfo* vc = answer->GetContentByName("video");
986 const ContentInfo* dc = answer->GetContentByName("data");
987 ASSERT_TRUE(ac != NULL);
988 ASSERT_TRUE(vc != NULL);
989 const AudioContentDescription* acd =
990 static_cast<const AudioContentDescription*>(ac->description);
991 const VideoContentDescription* vcd =
992 static_cast<const VideoContentDescription*>(vc->description);
993 const DataContentDescription* dcd =
994 static_cast<const DataContentDescription*>(dc->description);
996 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
997 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
998 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1001 TEST_F(MediaSessionDescriptionFactoryTest, TestPartial) {
1002 MediaSessionOptions opts;
1003 opts.recv_video = true;
1004 opts.data_channel_type = cricket::DCT_RTP;
1005 f1_.set_secure(SEC_ENABLED);
1006 rtc::scoped_ptr<SessionDescription>
1007 offer(f1_.CreateOffer(opts, NULL));
1008 ASSERT_TRUE(offer.get() != NULL);
1009 const ContentInfo* ac = offer->GetContentByName("audio");
1010 const ContentInfo* vc = offer->GetContentByName("video");
1011 const ContentInfo* dc = offer->GetContentByName("data");
1012 AudioContentDescription* acd = const_cast<AudioContentDescription*>(
1013 static_cast<const AudioContentDescription*>(ac->description));
1014 VideoContentDescription* vcd = const_cast<VideoContentDescription*>(
1015 static_cast<const VideoContentDescription*>(vc->description));
1016 DataContentDescription* dcd = const_cast<DataContentDescription*>(
1017 static_cast<const DataContentDescription*>(dc->description));
1019 EXPECT_FALSE(acd->partial()); // default is false.
1020 acd->set_partial(true);
1021 EXPECT_TRUE(acd->partial());
1022 acd->set_partial(false);
1023 EXPECT_FALSE(acd->partial());
1025 EXPECT_FALSE(vcd->partial()); // default is false.
1026 vcd->set_partial(true);
1027 EXPECT_TRUE(vcd->partial());
1028 vcd->set_partial(false);
1029 EXPECT_FALSE(vcd->partial());
1031 EXPECT_FALSE(dcd->partial()); // default is false.
1032 dcd->set_partial(true);
1033 EXPECT_TRUE(dcd->partial());
1034 dcd->set_partial(false);
1035 EXPECT_FALSE(dcd->partial());
1038 // Create a typical video answer, and ensure it matches what we expect.
1039 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1040 MediaSessionOptions offer_opts;
1041 MediaSessionOptions answer_opts;
1042 answer_opts.recv_video = true;
1043 offer_opts.recv_video = true;
1044 answer_opts.data_channel_type = cricket::DCT_RTP;
1045 offer_opts.data_channel_type = cricket::DCT_RTP;
1047 rtc::scoped_ptr<SessionDescription> offer;
1048 rtc::scoped_ptr<SessionDescription> answer;
1050 offer_opts.rtcp_mux_enabled = true;
1051 answer_opts.rtcp_mux_enabled = true;
1053 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1054 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1055 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1056 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1057 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1058 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1059 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1060 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1061 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1062 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1063 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1064 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1065 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1066 EXPECT_TRUE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1068 offer_opts.rtcp_mux_enabled = true;
1069 answer_opts.rtcp_mux_enabled = false;
1071 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1072 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1073 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1074 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1075 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1076 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1077 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1078 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1079 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1080 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1081 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1082 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1083 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1084 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1086 offer_opts.rtcp_mux_enabled = false;
1087 answer_opts.rtcp_mux_enabled = true;
1089 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1090 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1091 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1092 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1093 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1094 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1095 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1096 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1097 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1098 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1099 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1100 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1101 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1102 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1104 offer_opts.rtcp_mux_enabled = false;
1105 answer_opts.rtcp_mux_enabled = false;
1107 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1108 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1109 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1110 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1111 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1112 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1113 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1114 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1115 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1116 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1117 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1118 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1119 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1120 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1123 // Create an audio-only answer to a video offer.
1124 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1125 MediaSessionOptions opts;
1126 opts.recv_video = true;
1127 rtc::scoped_ptr<SessionDescription>
1128 offer(f1_.CreateOffer(opts, NULL));
1129 ASSERT_TRUE(offer.get() != NULL);
1130 rtc::scoped_ptr<SessionDescription> answer(
1131 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
1132 const ContentInfo* ac = answer->GetContentByName("audio");
1133 const ContentInfo* vc = answer->GetContentByName("video");
1134 ASSERT_TRUE(ac != NULL);
1135 ASSERT_TRUE(vc != NULL);
1136 ASSERT_TRUE(vc->description != NULL);
1137 EXPECT_TRUE(vc->rejected);
1140 // Create an audio-only answer to an offer with data.
1141 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
1142 MediaSessionOptions opts;
1143 opts.data_channel_type = cricket::DCT_RTP;
1144 rtc::scoped_ptr<SessionDescription>
1145 offer(f1_.CreateOffer(opts, NULL));
1146 ASSERT_TRUE(offer.get() != NULL);
1147 rtc::scoped_ptr<SessionDescription> answer(
1148 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
1149 const ContentInfo* ac = answer->GetContentByName("audio");
1150 const ContentInfo* dc = answer->GetContentByName("data");
1151 ASSERT_TRUE(ac != NULL);
1152 ASSERT_TRUE(dc != NULL);
1153 ASSERT_TRUE(dc->description != NULL);
1154 EXPECT_TRUE(dc->rejected);
1157 // Create an answer that rejects the contents which are rejected in the offer.
1158 TEST_F(MediaSessionDescriptionFactoryTest,
1159 CreateAnswerToOfferWithRejectedMedia) {
1160 MediaSessionOptions opts;
1161 opts.recv_video = true;
1162 opts.data_channel_type = cricket::DCT_RTP;
1163 rtc::scoped_ptr<SessionDescription>
1164 offer(f1_.CreateOffer(opts, NULL));
1165 ASSERT_TRUE(offer.get() != NULL);
1166 ContentInfo* ac = offer->GetContentByName("audio");
1167 ContentInfo* vc = offer->GetContentByName("video");
1168 ContentInfo* dc = offer->GetContentByName("data");
1169 ASSERT_TRUE(ac != NULL);
1170 ASSERT_TRUE(vc != NULL);
1171 ASSERT_TRUE(dc != NULL);
1172 ac->rejected = true;
1173 vc->rejected = true;
1174 dc->rejected = true;
1175 rtc::scoped_ptr<SessionDescription> answer(
1176 f2_.CreateAnswer(offer.get(), opts, NULL));
1177 ac = answer->GetContentByName("audio");
1178 vc = answer->GetContentByName("video");
1179 dc = answer->GetContentByName("data");
1180 ASSERT_TRUE(ac != NULL);
1181 ASSERT_TRUE(vc != NULL);
1182 ASSERT_TRUE(dc != NULL);
1183 EXPECT_TRUE(ac->rejected);
1184 EXPECT_TRUE(vc->rejected);
1185 EXPECT_TRUE(dc->rejected);
1188 // Create an audio and video offer with:
1189 // - one video track
1190 // - two audio tracks
1191 // - two data tracks
1192 // and ensure it matches what we expect. Also updates the initial offer by
1193 // adding a new video track and replaces one of the audio tracks.
1194 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
1195 MediaSessionOptions opts;
1196 opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack1, kMediaStream1);
1197 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
1198 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2, kMediaStream1);
1199 opts.data_channel_type = cricket::DCT_RTP;
1200 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack1, kMediaStream1);
1201 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack2, kMediaStream1);
1203 f1_.set_secure(SEC_ENABLED);
1204 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1206 ASSERT_TRUE(offer.get() != NULL);
1207 const ContentInfo* ac = offer->GetContentByName("audio");
1208 const ContentInfo* vc = offer->GetContentByName("video");
1209 const ContentInfo* dc = offer->GetContentByName("data");
1210 ASSERT_TRUE(ac != NULL);
1211 ASSERT_TRUE(vc != NULL);
1212 ASSERT_TRUE(dc != NULL);
1213 const AudioContentDescription* acd =
1214 static_cast<const AudioContentDescription*>(ac->description);
1215 const VideoContentDescription* vcd =
1216 static_cast<const VideoContentDescription*>(vc->description);
1217 const DataContentDescription* dcd =
1218 static_cast<const DataContentDescription*>(dc->description);
1219 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1220 EXPECT_EQ(f1_.audio_codecs(), acd->codecs());
1222 const StreamParamsVec& audio_streams = acd->streams();
1223 ASSERT_EQ(2U, audio_streams.size());
1224 EXPECT_EQ(audio_streams[0].cname , audio_streams[1].cname);
1225 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1226 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1227 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1228 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1229 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1230 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1232 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1233 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1234 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
1236 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1237 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
1238 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1240 const StreamParamsVec& video_streams = vcd->streams();
1241 ASSERT_EQ(1U, video_streams.size());
1242 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1243 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1244 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1245 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1247 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1248 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
1249 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1251 const StreamParamsVec& data_streams = dcd->streams();
1252 ASSERT_EQ(2U, data_streams.size());
1253 EXPECT_EQ(data_streams[0].cname , data_streams[1].cname);
1254 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1255 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1256 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1257 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1258 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1259 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1261 EXPECT_EQ(cricket::kDataMaxBandwidth,
1262 dcd->bandwidth()); // default bandwidth (auto)
1263 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
1264 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1267 // Update the offer. Add a new video track that is not synched to the
1268 // other tracks and replace audio track 2 with audio track 3.
1269 opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack2, kMediaStream2);
1270 opts.RemoveSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2);
1271 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack3, kMediaStream1);
1272 opts.RemoveSendStream(MEDIA_TYPE_DATA, kDataTrack2);
1273 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack3, kMediaStream1);
1274 rtc::scoped_ptr<SessionDescription>
1275 updated_offer(f1_.CreateOffer(opts, offer.get()));
1277 ASSERT_TRUE(updated_offer.get() != NULL);
1278 ac = updated_offer->GetContentByName("audio");
1279 vc = updated_offer->GetContentByName("video");
1280 dc = updated_offer->GetContentByName("data");
1281 ASSERT_TRUE(ac != NULL);
1282 ASSERT_TRUE(vc != NULL);
1283 ASSERT_TRUE(dc != NULL);
1284 const AudioContentDescription* updated_acd =
1285 static_cast<const AudioContentDescription*>(ac->description);
1286 const VideoContentDescription* updated_vcd =
1287 static_cast<const VideoContentDescription*>(vc->description);
1288 const DataContentDescription* updated_dcd =
1289 static_cast<const DataContentDescription*>(dc->description);
1291 EXPECT_EQ(acd->type(), updated_acd->type());
1292 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1293 EXPECT_EQ(vcd->type(), updated_vcd->type());
1294 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1295 EXPECT_EQ(dcd->type(), updated_dcd->type());
1296 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1297 ASSERT_CRYPTO(updated_acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
1298 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
1299 ASSERT_CRYPTO(updated_vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1300 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
1301 ASSERT_CRYPTO(updated_dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1302 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1304 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1305 ASSERT_EQ(2U, updated_audio_streams.size());
1306 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
1307 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
1308 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
1309 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
1310 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
1312 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1313 ASSERT_EQ(2U, updated_video_streams.size());
1314 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1315 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
1316 EXPECT_NE(updated_video_streams[1].cname, updated_video_streams[0].cname);
1318 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1319 ASSERT_EQ(2U, updated_data_streams.size());
1320 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
1321 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
1322 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
1323 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
1324 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
1327 // Create an offer with simulcast video stream.
1328 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
1329 MediaSessionOptions opts;
1330 const int num_sim_layers = 3;
1331 opts.AddSendVideoStream(kVideoTrack1, kMediaStream1, num_sim_layers);
1332 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1334 ASSERT_TRUE(offer.get() != NULL);
1335 const ContentInfo* vc = offer->GetContentByName("video");
1336 ASSERT_TRUE(vc != NULL);
1337 const VideoContentDescription* vcd =
1338 static_cast<const VideoContentDescription*>(vc->description);
1340 const StreamParamsVec& video_streams = vcd->streams();
1341 ASSERT_EQ(1U, video_streams.size());
1342 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1343 const SsrcGroup* sim_ssrc_group =
1344 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
1345 ASSERT_TRUE(sim_ssrc_group != NULL);
1346 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
1349 // Create an audio and video answer to a standard video offer with:
1350 // - one video track
1351 // - two audio tracks
1352 // - two data tracks
1353 // and ensure it matches what we expect. Also updates the initial answer by
1354 // adding a new video track and removes one of the audio tracks.
1355 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
1356 MediaSessionOptions offer_opts;
1357 offer_opts.recv_video = true;
1358 offer_opts.data_channel_type = cricket::DCT_RTP;
1359 f1_.set_secure(SEC_ENABLED);
1360 f2_.set_secure(SEC_ENABLED);
1361 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(offer_opts,
1364 MediaSessionOptions opts;
1365 opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack1, kMediaStream1);
1366 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
1367 opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2, kMediaStream1);
1368 opts.data_channel_type = cricket::DCT_RTP;
1369 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack1, kMediaStream1);
1370 opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack2, kMediaStream1);
1372 rtc::scoped_ptr<SessionDescription>
1373 answer(f2_.CreateAnswer(offer.get(), opts, NULL));
1375 ASSERT_TRUE(answer.get() != NULL);
1376 const ContentInfo* ac = answer->GetContentByName("audio");
1377 const ContentInfo* vc = answer->GetContentByName("video");
1378 const ContentInfo* dc = answer->GetContentByName("data");
1379 ASSERT_TRUE(ac != NULL);
1380 ASSERT_TRUE(vc != NULL);
1381 ASSERT_TRUE(dc != NULL);
1382 const AudioContentDescription* acd =
1383 static_cast<const AudioContentDescription*>(ac->description);
1384 const VideoContentDescription* vcd =
1385 static_cast<const VideoContentDescription*>(vc->description);
1386 const DataContentDescription* dcd =
1387 static_cast<const DataContentDescription*>(dc->description);
1388 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1389 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1390 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1392 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1393 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1395 const StreamParamsVec& audio_streams = acd->streams();
1396 ASSERT_EQ(2U, audio_streams.size());
1397 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
1398 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1399 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1400 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1401 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1402 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1403 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1405 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1406 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1408 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1409 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1411 const StreamParamsVec& video_streams = vcd->streams();
1412 ASSERT_EQ(1U, video_streams.size());
1413 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1414 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1415 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1416 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1418 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1419 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
1421 const StreamParamsVec& data_streams = dcd->streams();
1422 ASSERT_EQ(2U, data_streams.size());
1423 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
1424 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1425 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1426 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1427 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1428 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1429 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1431 EXPECT_EQ(cricket::kDataMaxBandwidth,
1432 dcd->bandwidth()); // default bandwidth (auto)
1433 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
1435 // Update the answer. Add a new video track that is not synched to the
1436 // other traacks and remove 1 audio track.
1437 opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack2, kMediaStream2);
1438 opts.RemoveSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2);
1439 opts.RemoveSendStream(MEDIA_TYPE_DATA, kDataTrack2);
1440 rtc::scoped_ptr<SessionDescription>
1441 updated_answer(f2_.CreateAnswer(offer.get(), opts, answer.get()));
1443 ASSERT_TRUE(updated_answer.get() != NULL);
1444 ac = updated_answer->GetContentByName("audio");
1445 vc = updated_answer->GetContentByName("video");
1446 dc = updated_answer->GetContentByName("data");
1447 ASSERT_TRUE(ac != NULL);
1448 ASSERT_TRUE(vc != NULL);
1449 ASSERT_TRUE(dc != NULL);
1450 const AudioContentDescription* updated_acd =
1451 static_cast<const AudioContentDescription*>(ac->description);
1452 const VideoContentDescription* updated_vcd =
1453 static_cast<const VideoContentDescription*>(vc->description);
1454 const DataContentDescription* updated_dcd =
1455 static_cast<const DataContentDescription*>(dc->description);
1457 ASSERT_CRYPTO(updated_acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1458 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
1459 ASSERT_CRYPTO(updated_vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1460 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
1461 ASSERT_CRYPTO(updated_dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1462 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1464 EXPECT_EQ(acd->type(), updated_acd->type());
1465 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1466 EXPECT_EQ(vcd->type(), updated_vcd->type());
1467 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1468 EXPECT_EQ(dcd->type(), updated_dcd->type());
1469 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1471 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1472 ASSERT_EQ(1U, updated_audio_streams.size());
1473 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
1475 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1476 ASSERT_EQ(2U, updated_video_streams.size());
1477 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1478 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
1479 EXPECT_NE(updated_video_streams[1].cname, updated_video_streams[0].cname);
1481 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1482 ASSERT_EQ(1U, updated_data_streams.size());
1483 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
1487 // Create an updated offer after creating an answer to the original offer and
1488 // verify that the codecs that were part of the original answer are not changed
1489 // in the updated offer.
1490 TEST_F(MediaSessionDescriptionFactoryTest,
1491 RespondentCreatesOfferAfterCreatingAnswer) {
1492 MediaSessionOptions opts;
1493 opts.recv_audio = true;
1494 opts.recv_video = true;
1496 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1497 rtc::scoped_ptr<SessionDescription> answer(
1498 f2_.CreateAnswer(offer.get(), opts, NULL));
1500 const AudioContentDescription* acd =
1501 GetFirstAudioContentDescription(answer.get());
1502 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1504 const VideoContentDescription* vcd =
1505 GetFirstVideoContentDescription(answer.get());
1506 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1508 rtc::scoped_ptr<SessionDescription> updated_offer(
1509 f2_.CreateOffer(opts, answer.get()));
1511 // The expected audio codecs are the common audio codecs from the first
1512 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
1513 // preference order.
1514 // TODO(wu): |updated_offer| should not include the codec
1515 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
1516 const AudioCodec kUpdatedAudioCodecOffer[] = {
1517 kAudioCodecsAnswer[0],
1518 kAudioCodecsAnswer[1],
1522 // The expected video codecs are the common video codecs from the first
1523 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
1524 // preference order.
1525 const VideoCodec kUpdatedVideoCodecOffer[] = {
1526 kVideoCodecsAnswer[0],
1530 const AudioContentDescription* updated_acd =
1531 GetFirstAudioContentDescription(updated_offer.get());
1532 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioCodecOffer), updated_acd->codecs());
1534 const VideoContentDescription* updated_vcd =
1535 GetFirstVideoContentDescription(updated_offer.get());
1536 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoCodecOffer), updated_vcd->codecs());
1539 // Create an updated offer after creating an answer to the original offer and
1540 // verify that the codecs that were part of the original answer are not changed
1541 // in the updated offer. In this test Rtx is enabled.
1542 TEST_F(MediaSessionDescriptionFactoryTest,
1543 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
1544 MediaSessionOptions opts;
1545 opts.recv_video = true;
1546 opts.recv_audio = false;
1547 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1550 rtx_f1.name = cricket::kRtxCodecName;
1552 // This creates rtx for H264 with the payload type |f1_| uses.
1553 rtx_f1.params[cricket::kCodecParamAssociatedPayloadType] =
1554 rtc::ToString<int>(kVideoCodecs1[1].id);
1555 f1_codecs.push_back(rtx_f1);
1556 f1_.set_video_codecs(f1_codecs);
1558 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1561 rtx_f2.name = cricket::kRtxCodecName;
1563 // This creates rtx for H264 with the payload type |f2_| uses.
1564 rtx_f2.params[cricket::kCodecParamAssociatedPayloadType] =
1565 rtc::ToString<int>(kVideoCodecs2[0].id);
1566 f2_codecs.push_back(rtx_f2);
1567 f2_.set_video_codecs(f2_codecs);
1569 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1570 ASSERT_TRUE(offer.get() != NULL);
1571 rtc::scoped_ptr<SessionDescription> answer(
1572 f2_.CreateAnswer(offer.get(), opts, NULL));
1574 const VideoContentDescription* vcd =
1575 GetFirstVideoContentDescription(answer.get());
1577 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
1578 expected_codecs.push_back(rtx_f1);
1580 EXPECT_EQ(expected_codecs, vcd->codecs());
1582 // Now, make sure we get same result, except for the preference order,
1583 // if |f2_| creates an updated offer even though the default payload types
1584 // are different from |f1_|.
1585 expected_codecs[0].preference = f1_codecs[1].preference;
1587 rtc::scoped_ptr<SessionDescription> updated_offer(
1588 f2_.CreateOffer(opts, answer.get()));
1589 ASSERT_TRUE(updated_offer);
1590 rtc::scoped_ptr<SessionDescription> updated_answer(
1591 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
1593 const VideoContentDescription* updated_vcd =
1594 GetFirstVideoContentDescription(updated_answer.get());
1596 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
1599 // Create an updated offer that adds video after creating an audio only answer
1600 // to the original offer. This test verifies that if a video codec and the RTX
1601 // codec have the same default payload type as an audio codec that is already in
1602 // use, the added codecs payload types are changed.
1603 TEST_F(MediaSessionDescriptionFactoryTest,
1604 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
1605 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1608 rtx_f1.name = cricket::kRtxCodecName;
1610 // This creates rtx for H264 with the payload type |f1_| uses.
1611 rtx_f1.params[cricket::kCodecParamAssociatedPayloadType] =
1612 rtc::ToString<int>(kVideoCodecs1[1].id);
1613 f1_codecs.push_back(rtx_f1);
1614 f1_.set_video_codecs(f1_codecs);
1616 MediaSessionOptions opts;
1617 opts.recv_audio = true;
1618 opts.recv_video = false;
1620 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1621 rtc::scoped_ptr<SessionDescription> answer(
1622 f2_.CreateAnswer(offer.get(), opts, NULL));
1624 const AudioContentDescription* acd =
1625 GetFirstAudioContentDescription(answer.get());
1626 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1628 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
1629 // reference be the same as an audio codec that was negotiated in the
1630 // first offer/answer exchange.
1631 opts.recv_audio = true;
1632 opts.recv_video = true;
1634 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1635 int used_pl_type = acd->codecs()[0].id;
1636 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
1639 rtx_f2.name = cricket::kRtxCodecName;
1640 rtx_f2.params[cricket::kCodecParamAssociatedPayloadType] =
1641 rtc::ToString<int>(used_pl_type);
1642 f2_codecs.push_back(rtx_f2);
1643 f2_.set_video_codecs(f2_codecs);
1645 rtc::scoped_ptr<SessionDescription> updated_offer(
1646 f2_.CreateOffer(opts, answer.get()));
1647 ASSERT_TRUE(updated_offer);
1648 rtc::scoped_ptr<SessionDescription> updated_answer(
1649 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
1651 const AudioContentDescription* updated_acd =
1652 GetFirstAudioContentDescription(answer.get());
1653 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), updated_acd->codecs());
1655 const VideoContentDescription* updated_vcd =
1656 GetFirstVideoContentDescription(updated_answer.get());
1658 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
1659 ASSERT_EQ(std::string(cricket::kRtxCodecName), updated_vcd->codecs()[1].name);
1660 int new_h264_pl_type = updated_vcd->codecs()[0].id;
1661 EXPECT_NE(used_pl_type, new_h264_pl_type);
1662 VideoCodec rtx = updated_vcd->codecs()[1];
1663 int pt_referenced_by_rtx = rtc::FromString<int>(
1664 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
1665 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
1668 // Test that RTX is ignored when there is no associated payload type parameter.
1669 TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
1670 MediaSessionOptions opts;
1671 opts.recv_video = true;
1672 opts.recv_audio = false;
1673 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1676 rtx_f1.name = cricket::kRtxCodecName;
1678 f1_codecs.push_back(rtx_f1);
1679 f1_.set_video_codecs(f1_codecs);
1681 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1684 rtx_f2.name = cricket::kRtxCodecName;
1686 // This creates rtx for H264 with the payload type |f2_| uses.
1687 rtx_f2.SetParam(cricket::kCodecParamAssociatedPayloadType,
1688 rtc::ToString<int>(kVideoCodecs2[0].id));
1689 f2_codecs.push_back(rtx_f2);
1690 f2_.set_video_codecs(f2_codecs);
1692 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1693 ASSERT_TRUE(offer.get() != NULL);
1694 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
1695 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
1696 // is possible to test that that RTX is dropped when
1697 // kCodecParamAssociatedPayloadType is missing in the offer.
1698 VideoContentDescription* desc =
1699 static_cast<cricket::VideoContentDescription*>(
1700 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
1701 ASSERT_TRUE(desc != NULL);
1702 std::vector<VideoCodec> codecs = desc->codecs();
1703 for (std::vector<VideoCodec>::iterator iter = codecs.begin();
1704 iter != codecs.end(); ++iter) {
1705 if (iter->name.find(cricket::kRtxCodecName) == 0) {
1706 iter->params.clear();
1709 desc->set_codecs(codecs);
1711 rtc::scoped_ptr<SessionDescription> answer(
1712 f2_.CreateAnswer(offer.get(), opts, NULL));
1714 const VideoContentDescription* vcd =
1715 GetFirstVideoContentDescription(answer.get());
1717 for (std::vector<VideoCodec>::const_iterator iter = vcd->codecs().begin();
1718 iter != vcd->codecs().end(); ++iter) {
1719 ASSERT_STRNE(iter->name.c_str(), cricket::kRtxCodecName);
1723 // Create an updated offer after creating an answer to the original offer and
1724 // verify that the RTP header extensions that were part of the original answer
1725 // are not changed in the updated offer.
1726 TEST_F(MediaSessionDescriptionFactoryTest,
1727 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
1728 MediaSessionOptions opts;
1729 opts.recv_audio = true;
1730 opts.recv_video = true;
1732 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1733 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1734 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1735 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1737 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1738 rtc::scoped_ptr<SessionDescription> answer(
1739 f2_.CreateAnswer(offer.get(), opts, NULL));
1741 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
1742 GetFirstAudioContentDescription(
1743 answer.get())->rtp_header_extensions());
1744 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
1745 GetFirstVideoContentDescription(
1746 answer.get())->rtp_header_extensions());
1748 rtc::scoped_ptr<SessionDescription> updated_offer(
1749 f2_.CreateOffer(opts, answer.get()));
1751 // The expected RTP header extensions in the new offer are the resulting
1752 // extensions from the first offer/answer exchange plus the extensions only
1754 // Since the default local extension id |f2_| uses has already been used by
1755 // |f1_| for another extensions, it is changed to 13.
1756 const RtpHeaderExtension kUpdatedAudioRtpExtensions[] = {
1757 kAudioRtpExtensionAnswer[0],
1758 RtpHeaderExtension(kAudioRtpExtension2[1].uri, 13),
1759 kAudioRtpExtension2[2],
1762 // Since the default local extension id |f2_| uses has already been used by
1763 // |f1_| for another extensions, is is changed to 12.
1764 const RtpHeaderExtension kUpdatedVideoRtpExtensions[] = {
1765 kVideoRtpExtensionAnswer[0],
1766 RtpHeaderExtension(kVideoRtpExtension2[1].uri, 12),
1767 kVideoRtpExtension2[2],
1770 const AudioContentDescription* updated_acd =
1771 GetFirstAudioContentDescription(updated_offer.get());
1772 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
1773 updated_acd->rtp_header_extensions());
1775 const VideoContentDescription* updated_vcd =
1776 GetFirstVideoContentDescription(updated_offer.get());
1777 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
1778 updated_vcd->rtp_header_extensions());
1781 TEST(MediaSessionDescription, CopySessionDescription) {
1782 SessionDescription source;
1783 cricket::ContentGroup group(cricket::CN_AUDIO);
1784 source.AddGroup(group);
1785 AudioContentDescription* acd(new AudioContentDescription());
1786 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
1787 acd->AddLegacyStream(1);
1788 source.AddContent(cricket::CN_AUDIO, cricket::NS_JINGLE_RTP, acd);
1789 VideoContentDescription* vcd(new VideoContentDescription());
1790 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
1791 vcd->AddLegacyStream(2);
1792 source.AddContent(cricket::CN_VIDEO, cricket::NS_JINGLE_RTP, vcd);
1794 rtc::scoped_ptr<SessionDescription> copy(source.Copy());
1795 ASSERT_TRUE(copy.get() != NULL);
1796 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
1797 const ContentInfo* ac = copy->GetContentByName("audio");
1798 const ContentInfo* vc = copy->GetContentByName("video");
1799 ASSERT_TRUE(ac != NULL);
1800 ASSERT_TRUE(vc != NULL);
1801 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
1802 const AudioContentDescription* acd_copy =
1803 static_cast<const AudioContentDescription*>(ac->description);
1804 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
1805 EXPECT_EQ(1u, acd->first_ssrc());
1807 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
1808 const VideoContentDescription* vcd_copy =
1809 static_cast<const VideoContentDescription*>(vc->description);
1810 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
1811 EXPECT_EQ(2u, vcd->first_ssrc());
1814 // The below TestTransportInfoXXX tests create different offers/answers, and
1815 // ensure the TransportInfo in the SessionDescription matches what we expect.
1816 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
1817 MediaSessionOptions options;
1818 options.recv_audio = true;
1819 TestTransportInfo(true, options, false);
1822 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
1823 MediaSessionOptions options;
1824 options.recv_audio = true;
1825 TestTransportInfo(true, options, true);
1828 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
1829 MediaSessionOptions options;
1830 options.recv_audio = true;
1831 options.recv_video = true;
1832 options.data_channel_type = cricket::DCT_RTP;
1833 TestTransportInfo(true, options, false);
1836 TEST_F(MediaSessionDescriptionFactoryTest,
1837 TestTransportInfoOfferMultimediaCurrent) {
1838 MediaSessionOptions options;
1839 options.recv_audio = true;
1840 options.recv_video = true;
1841 options.data_channel_type = cricket::DCT_RTP;
1842 TestTransportInfo(true, options, true);
1845 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
1846 MediaSessionOptions options;
1847 options.recv_audio = true;
1848 options.recv_video = true;
1849 options.data_channel_type = cricket::DCT_RTP;
1850 options.bundle_enabled = true;
1851 TestTransportInfo(true, options, false);
1854 TEST_F(MediaSessionDescriptionFactoryTest,
1855 TestTransportInfoOfferBundleCurrent) {
1856 MediaSessionOptions options;
1857 options.recv_audio = true;
1858 options.recv_video = true;
1859 options.data_channel_type = cricket::DCT_RTP;
1860 options.bundle_enabled = true;
1861 TestTransportInfo(true, options, true);
1864 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
1865 MediaSessionOptions options;
1866 options.recv_audio = true;
1867 TestTransportInfo(false, options, false);
1870 TEST_F(MediaSessionDescriptionFactoryTest,
1871 TestTransportInfoAnswerAudioCurrent) {
1872 MediaSessionOptions options;
1873 options.recv_audio = true;
1874 TestTransportInfo(false, options, true);
1877 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
1878 MediaSessionOptions options;
1879 options.recv_audio = true;
1880 options.recv_video = true;
1881 options.data_channel_type = cricket::DCT_RTP;
1882 TestTransportInfo(false, options, false);
1885 TEST_F(MediaSessionDescriptionFactoryTest,
1886 TestTransportInfoAnswerMultimediaCurrent) {
1887 MediaSessionOptions options;
1888 options.recv_audio = true;
1889 options.recv_video = true;
1890 options.data_channel_type = cricket::DCT_RTP;
1891 TestTransportInfo(false, options, true);
1894 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
1895 MediaSessionOptions options;
1896 options.recv_audio = true;
1897 options.recv_video = true;
1898 options.data_channel_type = cricket::DCT_RTP;
1899 options.bundle_enabled = true;
1900 TestTransportInfo(false, options, false);
1903 TEST_F(MediaSessionDescriptionFactoryTest,
1904 TestTransportInfoAnswerBundleCurrent) {
1905 MediaSessionOptions options;
1906 options.recv_audio = true;
1907 options.recv_video = true;
1908 options.data_channel_type = cricket::DCT_RTP;
1909 options.bundle_enabled = true;
1910 TestTransportInfo(false, options, true);
1913 // Create an offer with bundle enabled and verify the crypto parameters are
1914 // the common set of the available cryptos.
1915 TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
1916 TestCryptoWithBundle(true);
1919 // Create an answer with bundle enabled and verify the crypto parameters are
1920 // the common set of the available cryptos.
1921 TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
1922 TestCryptoWithBundle(false);
1925 // Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
1926 // DTLS is not enabled locally.
1927 TEST_F(MediaSessionDescriptionFactoryTest,
1928 TestOfferDtlsSavpfWithoutDtlsFailed) {
1929 f1_.set_secure(SEC_ENABLED);
1930 f2_.set_secure(SEC_ENABLED);
1931 tdf1_.set_secure(SEC_DISABLED);
1932 tdf2_.set_secure(SEC_DISABLED);
1934 rtc::scoped_ptr<SessionDescription> offer(
1935 f1_.CreateOffer(MediaSessionOptions(), NULL));
1936 ASSERT_TRUE(offer.get() != NULL);
1937 ContentInfo* offer_content = offer->GetContentByName("audio");
1938 ASSERT_TRUE(offer_content != NULL);
1939 AudioContentDescription* offer_audio_desc =
1940 static_cast<AudioContentDescription*>(offer_content->description);
1941 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
1943 rtc::scoped_ptr<SessionDescription> answer(
1944 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
1945 ASSERT_TRUE(answer != NULL);
1946 ContentInfo* answer_content = answer->GetContentByName("audio");
1947 ASSERT_TRUE(answer_content != NULL);
1949 ASSERT_TRUE(answer_content->rejected);
1952 // Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
1953 // UDP/TLS/RTP/SAVPF.
1954 TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
1955 f1_.set_secure(SEC_ENABLED);
1956 f2_.set_secure(SEC_ENABLED);
1957 tdf1_.set_secure(SEC_ENABLED);
1958 tdf2_.set_secure(SEC_ENABLED);
1960 rtc::scoped_ptr<SessionDescription> offer(
1961 f1_.CreateOffer(MediaSessionOptions(), NULL));
1962 ASSERT_TRUE(offer.get() != NULL);
1963 ContentInfo* offer_content = offer->GetContentByName("audio");
1964 ASSERT_TRUE(offer_content != NULL);
1965 AudioContentDescription* offer_audio_desc =
1966 static_cast<AudioContentDescription*>(offer_content->description);
1967 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
1969 rtc::scoped_ptr<SessionDescription> answer(
1970 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
1971 ASSERT_TRUE(answer != NULL);
1973 const ContentInfo* answer_content = answer->GetContentByName("audio");
1974 ASSERT_TRUE(answer_content != NULL);
1975 ASSERT_FALSE(answer_content->rejected);
1977 const AudioContentDescription* answer_audio_desc =
1978 static_cast<const AudioContentDescription*>(answer_content->description);
1979 EXPECT_EQ(std::string(cricket::kMediaProtocolDtlsSavpf),
1980 answer_audio_desc->protocol());
1983 // Test that we include both SDES and DTLS in the offer, but only include SDES
1984 // in the answer if DTLS isn't negotiated.
1985 TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
1986 f1_.set_secure(SEC_ENABLED);
1987 f2_.set_secure(SEC_ENABLED);
1988 tdf1_.set_secure(SEC_ENABLED);
1989 tdf2_.set_secure(SEC_DISABLED);
1990 MediaSessionOptions options;
1991 options.recv_audio = true;
1992 options.recv_video = true;
1993 rtc::scoped_ptr<SessionDescription> offer, answer;
1994 const cricket::MediaContentDescription* audio_media_desc;
1995 const cricket::MediaContentDescription* video_media_desc;
1996 const cricket::TransportDescription* audio_trans_desc;
1997 const cricket::TransportDescription* video_trans_desc;
1999 // Generate an offer with SDES and DTLS support.
2000 offer.reset(f1_.CreateOffer(options, NULL));
2001 ASSERT_TRUE(offer.get() != NULL);
2003 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2004 offer->GetContentDescriptionByName("audio"));
2005 ASSERT_TRUE(audio_media_desc != NULL);
2006 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
2007 offer->GetContentDescriptionByName("video"));
2008 ASSERT_TRUE(video_media_desc != NULL);
2009 EXPECT_EQ(2u, audio_media_desc->cryptos().size());
2010 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2012 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2013 ASSERT_TRUE(audio_trans_desc != NULL);
2014 video_trans_desc = offer->GetTransportDescriptionByName("video");
2015 ASSERT_TRUE(video_trans_desc != NULL);
2016 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2017 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
2019 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
2020 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2021 ASSERT_TRUE(answer.get() != NULL);
2023 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2024 answer->GetContentDescriptionByName("audio"));
2025 ASSERT_TRUE(audio_media_desc != NULL);
2026 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
2027 answer->GetContentDescriptionByName("video"));
2028 ASSERT_TRUE(video_media_desc != NULL);
2029 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
2030 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2032 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2033 ASSERT_TRUE(audio_trans_desc != NULL);
2034 video_trans_desc = answer->GetTransportDescriptionByName("video");
2035 ASSERT_TRUE(video_trans_desc != NULL);
2036 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
2037 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
2039 // Enable DTLS; the answer should now only have DTLS support.
2040 tdf2_.set_secure(SEC_ENABLED);
2041 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2042 ASSERT_TRUE(answer.get() != NULL);
2044 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2045 answer->GetContentDescriptionByName("audio"));
2046 ASSERT_TRUE(audio_media_desc != NULL);
2047 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
2048 answer->GetContentDescriptionByName("video"));
2049 ASSERT_TRUE(video_media_desc != NULL);
2050 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2051 EXPECT_TRUE(video_media_desc->cryptos().empty());
2052 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2053 audio_media_desc->protocol());
2054 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2055 video_media_desc->protocol());
2057 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2058 ASSERT_TRUE(audio_trans_desc != NULL);
2059 video_trans_desc = answer->GetTransportDescriptionByName("video");
2060 ASSERT_TRUE(video_trans_desc != NULL);
2061 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2062 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
2064 // Try creating offer again. DTLS enabled now, crypto's should be empty
2066 offer.reset(f1_.CreateOffer(options, offer.get()));
2067 ASSERT_TRUE(offer.get() != NULL);
2068 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2069 offer->GetContentDescriptionByName("audio"));
2070 ASSERT_TRUE(audio_media_desc != NULL);
2071 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
2072 offer->GetContentDescriptionByName("video"));
2073 ASSERT_TRUE(video_media_desc != NULL);
2074 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2075 EXPECT_TRUE(video_media_desc->cryptos().empty());
2077 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2078 ASSERT_TRUE(audio_trans_desc != NULL);
2079 video_trans_desc = offer->GetTransportDescriptionByName("video");
2080 ASSERT_TRUE(video_trans_desc != NULL);
2081 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2082 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
2085 // Test that an answer can't be created if cryptos are required but the offer is
2087 TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
2088 MediaSessionOptions options;
2089 f1_.set_secure(SEC_DISABLED);
2090 tdf1_.set_secure(SEC_DISABLED);
2091 f2_.set_secure(SEC_REQUIRED);
2092 tdf1_.set_secure(SEC_ENABLED);
2094 rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(options,
2096 ASSERT_TRUE(offer.get() != NULL);
2097 rtc::scoped_ptr<SessionDescription> answer(
2098 f2_.CreateAnswer(offer.get(), options, NULL));
2099 EXPECT_TRUE(answer.get() == NULL);
2102 // Test that we accept a DTLS offer without SDES and create an appropriate
2104 TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
2105 f1_.set_secure(SEC_DISABLED);
2106 f2_.set_secure(SEC_ENABLED);
2107 tdf1_.set_secure(SEC_ENABLED);
2108 tdf2_.set_secure(SEC_ENABLED);
2109 MediaSessionOptions options;
2110 options.recv_audio = true;
2111 options.recv_video = true;
2112 options.data_channel_type = cricket::DCT_RTP;
2114 rtc::scoped_ptr<SessionDescription> offer, answer;
2116 // Generate an offer with DTLS but without SDES.
2117 offer.reset(f1_.CreateOffer(options, NULL));
2118 ASSERT_TRUE(offer.get() != NULL);
2120 const AudioContentDescription* audio_offer =
2121 GetFirstAudioContentDescription(offer.get());
2122 ASSERT_TRUE(audio_offer->cryptos().empty());
2123 const VideoContentDescription* video_offer =
2124 GetFirstVideoContentDescription(offer.get());
2125 ASSERT_TRUE(video_offer->cryptos().empty());
2126 const DataContentDescription* data_offer =
2127 GetFirstDataContentDescription(offer.get());
2128 ASSERT_TRUE(data_offer->cryptos().empty());
2130 const cricket::TransportDescription* audio_offer_trans_desc =
2131 offer->GetTransportDescriptionByName("audio");
2132 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
2133 const cricket::TransportDescription* video_offer_trans_desc =
2134 offer->GetTransportDescriptionByName("video");
2135 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
2136 const cricket::TransportDescription* data_offer_trans_desc =
2137 offer->GetTransportDescriptionByName("data");
2138 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
2140 // Generate an answer with DTLS.
2141 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2142 ASSERT_TRUE(answer.get() != NULL);
2144 const cricket::TransportDescription* audio_answer_trans_desc =
2145 answer->GetTransportDescriptionByName("audio");
2146 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
2147 const cricket::TransportDescription* video_answer_trans_desc =
2148 answer->GetTransportDescriptionByName("video");
2149 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
2150 const cricket::TransportDescription* data_answer_trans_desc =
2151 answer->GetTransportDescriptionByName("data");
2152 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
2155 // Verifies if vad_enabled option is set to false, CN codecs are not present in
2157 TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
2158 MediaSessionOptions options;
2159 options.recv_audio = true;
2160 options.recv_video = true;
2161 rtc::scoped_ptr<SessionDescription> offer(
2162 f1_.CreateOffer(options, NULL));
2163 ASSERT_TRUE(offer.get() != NULL);
2164 const ContentInfo* audio_content = offer->GetContentByName("audio");
2165 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
2167 options.vad_enabled = false;
2168 offer.reset(f1_.CreateOffer(options, NULL));
2169 ASSERT_TRUE(offer.get() != NULL);
2170 audio_content = offer->GetContentByName("audio");
2171 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
2172 rtc::scoped_ptr<SessionDescription> answer(
2173 f1_.CreateAnswer(offer.get(), options, NULL));
2174 ASSERT_TRUE(answer.get() != NULL);
2175 audio_content = answer->GetContentByName("audio");
2176 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));