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