blob: cf492a65ee1f48a201fcb1b14719984f98d1af06 [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) \
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +000044 ASSERT_EQ(cricket::CT_NONE, cd->crypto_required()); \
henrike@webrtc.org28e20752013-07-10 00:45:36 +000045 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) \
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +000049 ASSERT_EQ(cricket::CT_NONE, cd->crypto_required()); \
henrike@webrtc.org28e20752013-07-10 00:45:36 +000050 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),
henrike@webrtc.org79047f92014-03-06 23:46:59 +0000146 RtpHeaderExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000147};
148
149static const RtpHeaderExtension kAudioRtpExtensionAnswer[] = {
150 RtpHeaderExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
151};
152
153static const RtpHeaderExtension kVideoRtpExtension1[] = {
154 RtpHeaderExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org79047f92014-03-06 23:46:59 +0000155 RtpHeaderExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000156};
157
158static const RtpHeaderExtension kVideoRtpExtension2[] = {
159 RtpHeaderExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
160 RtpHeaderExtension("http://google.com/testing/video_something_else", 14),
henrike@webrtc.org79047f92014-03-06 23:46:59 +0000161 RtpHeaderExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000162};
163
164static const RtpHeaderExtension kVideoRtpExtensionAnswer[] = {
165 RtpHeaderExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
166};
167
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000168static const uint32 kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
169static const uint32 kSimSsrc[] = {10, 20, 30};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000170static const uint32 kFec1Ssrc[] = {10, 11};
171static const uint32 kFec2Ssrc[] = {20, 21};
172static const uint32 kFec3Ssrc[] = {30, 31};
173
174static const char kMediaStream1[] = "stream_1";
175static const char kMediaStream2[] = "stream_2";
176static const char kVideoTrack1[] = "video_1";
177static const char kVideoTrack2[] = "video_2";
178static const char kAudioTrack1[] = "audio_1";
179static const char kAudioTrack2[] = "audio_2";
180static const char kAudioTrack3[] = "audio_3";
181static const char kDataTrack1[] = "data_1";
182static const char kDataTrack2[] = "data_2";
183static const char kDataTrack3[] = "data_3";
184
185class MediaSessionDescriptionFactoryTest : public testing::Test {
186 public:
187 MediaSessionDescriptionFactoryTest()
188 : f1_(&tdf1_), f2_(&tdf2_), id1_("id1"), id2_("id2") {
189 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1));
190 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
191 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
192 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2));
193 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
194 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
195 tdf1_.set_identity(&id1_);
196 tdf2_.set_identity(&id2_);
197 }
198
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000199 // Create a video StreamParamsVec object with:
200 // - one video stream with 3 simulcast streams and FEC,
201 StreamParamsVec CreateComplexVideoStreamParamsVec() {
202 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
203 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
204 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
205 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
206
207 std::vector<SsrcGroup> ssrc_groups;
208 ssrc_groups.push_back(sim_group);
209 ssrc_groups.push_back(fec_group1);
210 ssrc_groups.push_back(fec_group2);
211 ssrc_groups.push_back(fec_group3);
212
213 StreamParams simulcast_params;
214 simulcast_params.id = kVideoTrack1;
215 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
216 simulcast_params.ssrc_groups = ssrc_groups;
217 simulcast_params.cname = "Video_SIM_FEC";
218 simulcast_params.sync_label = kMediaStream1;
219
220 StreamParamsVec video_streams;
221 video_streams.push_back(simulcast_params);
222
223 return video_streams;
224 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000225
226 bool CompareCryptoParams(const CryptoParamsVec& c1,
227 const CryptoParamsVec& c2) {
228 if (c1.size() != c2.size())
229 return false;
230 for (size_t i = 0; i < c1.size(); ++i)
231 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
232 c1[i].key_params != c2[i].key_params ||
233 c1[i].session_params != c2[i].session_params)
234 return false;
235 return true;
236 }
237
238 void TestTransportInfo(bool offer, const MediaSessionOptions& options,
239 bool has_current_desc) {
240 const std::string current_audio_ufrag = "current_audio_ufrag";
241 const std::string current_audio_pwd = "current_audio_pwd";
242 const std::string current_video_ufrag = "current_video_ufrag";
243 const std::string current_video_pwd = "current_video_pwd";
244 const std::string current_data_ufrag = "current_data_ufrag";
245 const std::string current_data_pwd = "current_data_pwd";
246 talk_base::scoped_ptr<SessionDescription> current_desc;
247 talk_base::scoped_ptr<SessionDescription> desc;
248 if (has_current_desc) {
249 current_desc.reset(new SessionDescription());
250 EXPECT_TRUE(current_desc->AddTransportInfo(
251 TransportInfo("audio",
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000252 TransportDescription("",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000253 current_audio_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000254 current_audio_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000255 EXPECT_TRUE(current_desc->AddTransportInfo(
256 TransportInfo("video",
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000257 TransportDescription("",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000258 current_video_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000259 current_video_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000260 EXPECT_TRUE(current_desc->AddTransportInfo(
261 TransportInfo("data",
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000262 TransportDescription("",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000263 current_data_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000264 current_data_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000265 }
266 if (offer) {
267 desc.reset(f1_.CreateOffer(options, current_desc.get()));
268 } else {
269 talk_base::scoped_ptr<SessionDescription> offer;
270 offer.reset(f1_.CreateOffer(options, NULL));
271 desc.reset(f1_.CreateAnswer(offer.get(), options, current_desc.get()));
272 }
273 ASSERT_TRUE(desc.get() != NULL);
274 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
275 if (options.has_audio) {
276 EXPECT_TRUE(ti_audio != NULL);
277 if (has_current_desc) {
278 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
279 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
280 } else {
281 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
282 ti_audio->description.ice_ufrag.size());
283 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
284 ti_audio->description.ice_pwd.size());
285 }
286
287 } else {
288 EXPECT_TRUE(ti_audio == NULL);
289 }
290 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
291 if (options.has_video) {
292 EXPECT_TRUE(ti_video != NULL);
293 if (options.bundle_enabled) {
294 EXPECT_EQ(ti_audio->description.ice_ufrag,
295 ti_video->description.ice_ufrag);
296 EXPECT_EQ(ti_audio->description.ice_pwd,
297 ti_video->description.ice_pwd);
298 } else {
299 if (has_current_desc) {
300 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
301 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
302 } else {
303 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
304 ti_video->description.ice_ufrag.size());
305 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
306 ti_video->description.ice_pwd.size());
307 }
308 }
309 } else {
310 EXPECT_TRUE(ti_video == NULL);
311 }
312 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
313 if (options.has_data()) {
314 EXPECT_TRUE(ti_data != NULL);
315 if (options.bundle_enabled) {
316 EXPECT_EQ(ti_audio->description.ice_ufrag,
317 ti_data->description.ice_ufrag);
318 EXPECT_EQ(ti_audio->description.ice_pwd,
319 ti_data->description.ice_pwd);
320 } else {
321 if (has_current_desc) {
322 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
323 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
324 } else {
325 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
326 ti_data->description.ice_ufrag.size());
327 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
328 ti_data->description.ice_pwd.size());
329 }
330 }
331 } else {
332 EXPECT_TRUE(ti_video == NULL);
333 }
334 }
335
336 void TestCryptoWithBundle(bool offer) {
337 f1_.set_secure(SEC_ENABLED);
338 MediaSessionOptions options;
339 options.has_audio = true;
340 options.has_video = true;
341 options.data_channel_type = cricket::DCT_RTP;
342 talk_base::scoped_ptr<SessionDescription> ref_desc;
343 talk_base::scoped_ptr<SessionDescription> desc;
344 if (offer) {
345 options.bundle_enabled = false;
346 ref_desc.reset(f1_.CreateOffer(options, NULL));
347 options.bundle_enabled = true;
348 desc.reset(f1_.CreateOffer(options, ref_desc.get()));
349 } else {
350 options.bundle_enabled = true;
351 ref_desc.reset(f1_.CreateOffer(options, NULL));
352 desc.reset(f1_.CreateAnswer(ref_desc.get(), options, NULL));
353 }
354 ASSERT_TRUE(desc.get() != NULL);
355 const cricket::MediaContentDescription* audio_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000356 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000357 desc.get()->GetContentDescriptionByName("audio"));
358 ASSERT_TRUE(audio_media_desc != NULL);
359 const cricket::MediaContentDescription* video_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000360 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000361 desc.get()->GetContentDescriptionByName("video"));
362 ASSERT_TRUE(video_media_desc != NULL);
363 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
364 video_media_desc->cryptos()));
365 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
366 EXPECT_EQ(std::string(CS_AES_CM_128_HMAC_SHA1_80),
367 audio_media_desc->cryptos()[0].cipher_suite);
368
369 // Verify the selected crypto is one from the reference audio
370 // media content.
371 const cricket::MediaContentDescription* ref_audio_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000372 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000373 ref_desc.get()->GetContentDescriptionByName("audio"));
374 bool found = false;
375 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
376 if (ref_audio_media_desc->cryptos()[i].Matches(
377 audio_media_desc->cryptos()[0])) {
378 found = true;
379 break;
380 }
381 }
382 EXPECT_TRUE(found);
383 }
384
385 // This test that the audio and video media direction is set to
386 // |expected_direction_in_answer| in an answer if the offer direction is set
387 // to |direction_in_offer|.
388 void TestMediaDirectionInAnswer(
389 cricket::MediaContentDirection direction_in_offer,
390 cricket::MediaContentDirection expected_direction_in_answer) {
391 MediaSessionOptions opts;
392 opts.has_video = true;
393 talk_base::scoped_ptr<SessionDescription> offer(
394 f1_.CreateOffer(opts, NULL));
395 ASSERT_TRUE(offer.get() != NULL);
396 ContentInfo* ac_offer= offer->GetContentByName("audio");
397 ASSERT_TRUE(ac_offer != NULL);
398 AudioContentDescription* acd_offer =
399 static_cast<AudioContentDescription*>(ac_offer->description);
400 acd_offer->set_direction(direction_in_offer);
401 ContentInfo* vc_offer= offer->GetContentByName("video");
402 ASSERT_TRUE(vc_offer != NULL);
403 VideoContentDescription* vcd_offer =
404 static_cast<VideoContentDescription*>(vc_offer->description);
405 vcd_offer->set_direction(direction_in_offer);
406
407 talk_base::scoped_ptr<SessionDescription> answer(
408 f2_.CreateAnswer(offer.get(), opts, NULL));
409 const AudioContentDescription* acd_answer =
410 GetFirstAudioContentDescription(answer.get());
411 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
412 const VideoContentDescription* vcd_answer =
413 GetFirstVideoContentDescription(answer.get());
414 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
415 }
416
417 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
418 const cricket::ContentDescription* description = content->description;
419 ASSERT(description != NULL);
420 const cricket::AudioContentDescription* audio_content_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000421 static_cast<const cricket::AudioContentDescription*>(description);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000422 ASSERT(audio_content_desc != NULL);
423 for (size_t i = 0; i < audio_content_desc->codecs().size(); ++i) {
424 if (audio_content_desc->codecs()[i].name == "CN")
425 return false;
426 }
427 return true;
428 }
429
430 protected:
431 MediaSessionDescriptionFactory f1_;
432 MediaSessionDescriptionFactory f2_;
433 TransportDescriptionFactory tdf1_;
434 TransportDescriptionFactory tdf2_;
435 talk_base::FakeSSLIdentity id1_;
436 talk_base::FakeSSLIdentity id2_;
437};
438
439// Create a typical audio offer, and ensure it matches what we expect.
440TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
441 f1_.set_secure(SEC_ENABLED);
442 talk_base::scoped_ptr<SessionDescription> offer(
443 f1_.CreateOffer(MediaSessionOptions(), 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 const AudioContentDescription* acd =
451 static_cast<const AudioContentDescription*>(ac->description);
452 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
453 EXPECT_EQ(f1_.audio_codecs(), acd->codecs());
454 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
455 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
456 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
457 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
458 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
459}
460
461// Create a typical video offer, and ensure it matches what we expect.
462TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
463 MediaSessionOptions opts;
464 opts.has_video = true;
465 f1_.set_secure(SEC_ENABLED);
466 talk_base::scoped_ptr<SessionDescription>
467 offer(f1_.CreateOffer(opts, NULL));
468 ASSERT_TRUE(offer.get() != NULL);
469 const ContentInfo* ac = offer->GetContentByName("audio");
470 const ContentInfo* vc = offer->GetContentByName("video");
471 ASSERT_TRUE(ac != NULL);
472 ASSERT_TRUE(vc != NULL);
473 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
474 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
475 const AudioContentDescription* acd =
476 static_cast<const AudioContentDescription*>(ac->description);
477 const VideoContentDescription* vcd =
478 static_cast<const VideoContentDescription*>(vc->description);
479 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
480 EXPECT_EQ(f1_.audio_codecs(), acd->codecs());
481 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
482 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
483 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
484 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
485 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
486 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
487 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
488 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
489 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
490 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
491 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
492 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
493}
494
495// Test creating an offer with bundle where the Codecs have the same dynamic
496// RTP playlod type. The test verifies that the offer don't contain the
497// duplicate RTP payload types.
498TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
499 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
500 const AudioCodec& offered_audio_codec = f2_.audio_codecs()[0];
501 const DataCodec& offered_data_codec = f2_.data_codecs()[0];
502 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
503 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
504
505 MediaSessionOptions opts;
506 opts.has_audio = true;
507 opts.has_video = true;
508 opts.data_channel_type = cricket::DCT_RTP;
509 opts.bundle_enabled = true;
510 talk_base::scoped_ptr<SessionDescription>
511 offer(f2_.CreateOffer(opts, NULL));
512 const VideoContentDescription* vcd =
513 GetFirstVideoContentDescription(offer.get());
514 const AudioContentDescription* acd =
515 GetFirstAudioContentDescription(offer.get());
516 const DataContentDescription* dcd =
517 GetFirstDataContentDescription(offer.get());
518 ASSERT_TRUE(NULL != vcd);
519 ASSERT_TRUE(NULL != acd);
520 ASSERT_TRUE(NULL != dcd);
521 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
522 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
523 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
524 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
525 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
526 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
527}
528
529// Test creating an updated offer with with bundle, audio, video and data
530// after an audio only session has been negotiated.
531TEST_F(MediaSessionDescriptionFactoryTest,
532 TestCreateUpdatedVideoOfferWithBundle) {
533 f1_.set_secure(SEC_ENABLED);
534 f2_.set_secure(SEC_ENABLED);
535 MediaSessionOptions opts;
536 opts.has_audio = true;
537 opts.has_video = false;
538 opts.data_channel_type = cricket::DCT_NONE;
539 opts.bundle_enabled = true;
540 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
541 talk_base::scoped_ptr<SessionDescription> answer(
542 f2_.CreateAnswer(offer.get(), opts, NULL));
543
544 MediaSessionOptions updated_opts;
545 updated_opts.has_audio = true;
546 updated_opts.has_video = true;
547 updated_opts.data_channel_type = cricket::DCT_RTP;
548 updated_opts.bundle_enabled = true;
549 talk_base::scoped_ptr<SessionDescription> updated_offer(f1_.CreateOffer(
550 updated_opts, answer.get()));
551
552 const AudioContentDescription* acd =
553 GetFirstAudioContentDescription(updated_offer.get());
554 const VideoContentDescription* vcd =
555 GetFirstVideoContentDescription(updated_offer.get());
556 const DataContentDescription* dcd =
557 GetFirstDataContentDescription(updated_offer.get());
558 EXPECT_TRUE(NULL != vcd);
559 EXPECT_TRUE(NULL != acd);
560 EXPECT_TRUE(NULL != dcd);
561
562 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
563 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
564 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
565 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
566 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
567 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
568}
wu@webrtc.org78187522013-10-07 23:32:02 +0000569// Create a RTP data offer, and ensure it matches what we expect.
570TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000571 MediaSessionOptions opts;
572 opts.data_channel_type = cricket::DCT_RTP;
573 f1_.set_secure(SEC_ENABLED);
574 talk_base::scoped_ptr<SessionDescription>
575 offer(f1_.CreateOffer(opts, NULL));
576 ASSERT_TRUE(offer.get() != NULL);
577 const ContentInfo* ac = offer->GetContentByName("audio");
578 const ContentInfo* dc = offer->GetContentByName("data");
579 ASSERT_TRUE(ac != NULL);
580 ASSERT_TRUE(dc != NULL);
581 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
582 EXPECT_EQ(std::string(NS_JINGLE_RTP), dc->type);
583 const AudioContentDescription* acd =
584 static_cast<const AudioContentDescription*>(ac->description);
585 const DataContentDescription* dcd =
586 static_cast<const DataContentDescription*>(dc->description);
587 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
588 EXPECT_EQ(f1_.audio_codecs(), acd->codecs());
589 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
590 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
591 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
592 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
593 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
594 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
595 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
596 EXPECT_NE(0U, dcd->first_ssrc()); // a random nonzero ssrc
597 EXPECT_EQ(cricket::kDataMaxBandwidth,
598 dcd->bandwidth()); // default bandwidth (auto)
599 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
600 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
601 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
602}
603
wu@webrtc.org78187522013-10-07 23:32:02 +0000604// Create an SCTP data offer with bundle without error.
605TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
606 MediaSessionOptions opts;
607 opts.has_audio = false;
608 opts.bundle_enabled = true;
609 opts.data_channel_type = cricket::DCT_SCTP;
610 f1_.set_secure(SEC_ENABLED);
611 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
612 EXPECT_TRUE(offer.get() != NULL);
613 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
614}
615
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000616// Create an audio, video offer without legacy StreamParams.
617TEST_F(MediaSessionDescriptionFactoryTest,
618 TestCreateOfferWithoutLegacyStreams) {
619 MediaSessionOptions opts;
620 opts.has_video = true;
621 f1_.set_add_legacy_streams(false);
622 talk_base::scoped_ptr<SessionDescription>
623 offer(f1_.CreateOffer(opts, NULL));
624 ASSERT_TRUE(offer.get() != NULL);
625 const ContentInfo* ac = offer->GetContentByName("audio");
626 const ContentInfo* vc = offer->GetContentByName("video");
627 ASSERT_TRUE(ac != NULL);
628 ASSERT_TRUE(vc != NULL);
629 const AudioContentDescription* acd =
630 static_cast<const AudioContentDescription*>(ac->description);
631 const VideoContentDescription* vcd =
632 static_cast<const VideoContentDescription*>(vc->description);
633
634 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
635 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
636}
637
638// Create a typical audio answer, and ensure it matches what we expect.
639TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
640 f1_.set_secure(SEC_ENABLED);
641 f2_.set_secure(SEC_ENABLED);
642 talk_base::scoped_ptr<SessionDescription> offer(
643 f1_.CreateOffer(MediaSessionOptions(), NULL));
644 ASSERT_TRUE(offer.get() != NULL);
645 talk_base::scoped_ptr<SessionDescription> answer(
646 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
647 const ContentInfo* ac = answer->GetContentByName("audio");
648 const ContentInfo* vc = answer->GetContentByName("video");
649 ASSERT_TRUE(ac != NULL);
650 ASSERT_TRUE(vc == NULL);
651 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
652 const AudioContentDescription* acd =
653 static_cast<const AudioContentDescription*>(ac->description);
654 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
655 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
656 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
657 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
658 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
659 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
660 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
661}
662
663// Create a typical video answer, and ensure it matches what we expect.
664TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
665 MediaSessionOptions opts;
666 opts.has_video = true;
667 f1_.set_secure(SEC_ENABLED);
668 f2_.set_secure(SEC_ENABLED);
669 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
670 ASSERT_TRUE(offer.get() != NULL);
671 talk_base::scoped_ptr<SessionDescription> answer(
672 f2_.CreateAnswer(offer.get(), opts, NULL));
673 const ContentInfo* ac = answer->GetContentByName("audio");
674 const ContentInfo* vc = answer->GetContentByName("video");
675 ASSERT_TRUE(ac != NULL);
676 ASSERT_TRUE(vc != NULL);
677 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
678 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
679 const AudioContentDescription* acd =
680 static_cast<const AudioContentDescription*>(ac->description);
681 const VideoContentDescription* vcd =
682 static_cast<const VideoContentDescription*>(vc->description);
683 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
684 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
685 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
686 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
687 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
688 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
689 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
690 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
691 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
692 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
693 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
694 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
695}
696
697TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
698 MediaSessionOptions opts;
699 opts.data_channel_type = cricket::DCT_RTP;
700 f1_.set_secure(SEC_ENABLED);
701 f2_.set_secure(SEC_ENABLED);
702 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
703 ASSERT_TRUE(offer.get() != NULL);
704 talk_base::scoped_ptr<SessionDescription> answer(
705 f2_.CreateAnswer(offer.get(), opts, NULL));
706 const ContentInfo* ac = answer->GetContentByName("audio");
707 const ContentInfo* vc = answer->GetContentByName("data");
708 ASSERT_TRUE(ac != NULL);
709 ASSERT_TRUE(vc != NULL);
710 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
711 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
712 const AudioContentDescription* acd =
713 static_cast<const AudioContentDescription*>(ac->description);
714 const DataContentDescription* vcd =
715 static_cast<const DataContentDescription*>(vc->description);
716 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
717 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
718 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
719 EXPECT_NE(0U, acd->first_ssrc()); // a random nonzero ssrc
720 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
721 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
722 EXPECT_EQ(MEDIA_TYPE_DATA, vcd->type());
723 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), vcd->codecs());
724 EXPECT_NE(0U, vcd->first_ssrc()); // a random nonzero ssrc
725 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
726 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
727 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
728}
729
730// This test that the media direction is set to send/receive in an answer if
731// the offer is send receive.
732TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
733 TestMediaDirectionInAnswer(cricket::MD_SENDRECV, cricket::MD_SENDRECV);
734}
735
736// This test that the media direction is set to receive only in an answer if
737// the offer is send only.
738TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
739 TestMediaDirectionInAnswer(cricket::MD_SENDONLY, cricket::MD_RECVONLY);
740}
741
742// This test that the media direction is set to send only in an answer if
743// the offer is recv only.
744TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
745 TestMediaDirectionInAnswer(cricket::MD_RECVONLY, cricket::MD_SENDONLY);
746}
747
748// This test that the media direction is set to inactive in an answer if
749// the offer is inactive.
750TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
751 TestMediaDirectionInAnswer(cricket::MD_INACTIVE, cricket::MD_INACTIVE);
752}
753
754// Test that a data content with an unknown protocol is rejected in an answer.
755TEST_F(MediaSessionDescriptionFactoryTest,
756 CreateDataAnswerToOfferWithUnknownProtocol) {
757 MediaSessionOptions opts;
758 opts.data_channel_type = cricket::DCT_RTP;
759 opts.has_audio = false;
760 f1_.set_secure(SEC_ENABLED);
761 f2_.set_secure(SEC_ENABLED);
762 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
763 ContentInfo* dc_offer= offer->GetContentByName("data");
764 ASSERT_TRUE(dc_offer != NULL);
765 DataContentDescription* dcd_offer =
766 static_cast<DataContentDescription*>(dc_offer->description);
767 ASSERT_TRUE(dcd_offer != NULL);
768 std::string protocol = "a weird unknown protocol";
769 dcd_offer->set_protocol(protocol);
770
771 talk_base::scoped_ptr<SessionDescription> answer(
772 f2_.CreateAnswer(offer.get(), opts, NULL));
773
774 const ContentInfo* dc_answer = answer->GetContentByName("data");
775 ASSERT_TRUE(dc_answer != NULL);
776 EXPECT_TRUE(dc_answer->rejected);
777 const DataContentDescription* dcd_answer =
778 static_cast<const DataContentDescription*>(dc_answer->description);
779 ASSERT_TRUE(dcd_answer != NULL);
780 EXPECT_EQ(protocol, dcd_answer->protocol());
781}
782
783// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
784TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
785 MediaSessionOptions opts;
786 f1_.set_secure(SEC_DISABLED);
787 f2_.set_secure(SEC_DISABLED);
788 tdf1_.set_secure(SEC_DISABLED);
789 tdf2_.set_secure(SEC_DISABLED);
790
791 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
792 const AudioContentDescription* offer_acd =
793 GetFirstAudioContentDescription(offer.get());
794 ASSERT_TRUE(offer_acd != NULL);
795 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), offer_acd->protocol());
796
797 talk_base::scoped_ptr<SessionDescription> answer(
798 f2_.CreateAnswer(offer.get(), opts, NULL));
799
800 const ContentInfo* ac_answer = answer->GetContentByName("audio");
801 ASSERT_TRUE(ac_answer != NULL);
802 EXPECT_FALSE(ac_answer->rejected);
803
804 const AudioContentDescription* answer_acd =
805 GetFirstAudioContentDescription(answer.get());
806 ASSERT_TRUE(answer_acd != NULL);
807 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), answer_acd->protocol());
808}
809
810// Create a video offer and answer and ensure the RTP header extensions
811// matches what we expect.
812TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
813 MediaSessionOptions opts;
814 opts.has_video = true;
815
816 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
817 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
818 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
819 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
820
821 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
822 ASSERT_TRUE(offer.get() != NULL);
823 talk_base::scoped_ptr<SessionDescription> answer(
824 f2_.CreateAnswer(offer.get(), opts, NULL));
825
826 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension1),
827 GetFirstAudioContentDescription(
828 offer.get())->rtp_header_extensions());
829 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtension1),
830 GetFirstVideoContentDescription(
831 offer.get())->rtp_header_extensions());
832 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
833 GetFirstAudioContentDescription(
834 answer.get())->rtp_header_extensions());
835 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
836 GetFirstVideoContentDescription(
837 answer.get())->rtp_header_extensions());
838}
839
840// Create an audio, video, data answer without legacy StreamParams.
841TEST_F(MediaSessionDescriptionFactoryTest,
842 TestCreateAnswerWithoutLegacyStreams) {
843 MediaSessionOptions opts;
844 opts.has_video = true;
845 opts.data_channel_type = cricket::DCT_RTP;
846 f1_.set_add_legacy_streams(false);
847 f2_.set_add_legacy_streams(false);
848 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
849 ASSERT_TRUE(offer.get() != NULL);
850 talk_base::scoped_ptr<SessionDescription> answer(
851 f2_.CreateAnswer(offer.get(), opts, NULL));
852 const ContentInfo* ac = answer->GetContentByName("audio");
853 const ContentInfo* vc = answer->GetContentByName("video");
854 const ContentInfo* dc = answer->GetContentByName("data");
855 ASSERT_TRUE(ac != NULL);
856 ASSERT_TRUE(vc != NULL);
857 const AudioContentDescription* acd =
858 static_cast<const AudioContentDescription*>(ac->description);
859 const VideoContentDescription* vcd =
860 static_cast<const VideoContentDescription*>(vc->description);
861 const DataContentDescription* dcd =
862 static_cast<const DataContentDescription*>(dc->description);
863
864 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
865 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
866 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
867}
868
869TEST_F(MediaSessionDescriptionFactoryTest, TestPartial) {
870 MediaSessionOptions opts;
871 opts.has_video = true;
872 opts.data_channel_type = cricket::DCT_RTP;
873 f1_.set_secure(SEC_ENABLED);
874 talk_base::scoped_ptr<SessionDescription>
875 offer(f1_.CreateOffer(opts, NULL));
876 ASSERT_TRUE(offer.get() != NULL);
877 const ContentInfo* ac = offer->GetContentByName("audio");
878 const ContentInfo* vc = offer->GetContentByName("video");
879 const ContentInfo* dc = offer->GetContentByName("data");
880 AudioContentDescription* acd = const_cast<AudioContentDescription*>(
881 static_cast<const AudioContentDescription*>(ac->description));
882 VideoContentDescription* vcd = const_cast<VideoContentDescription*>(
883 static_cast<const VideoContentDescription*>(vc->description));
884 DataContentDescription* dcd = const_cast<DataContentDescription*>(
885 static_cast<const DataContentDescription*>(dc->description));
886
887 EXPECT_FALSE(acd->partial()); // default is false.
888 acd->set_partial(true);
889 EXPECT_TRUE(acd->partial());
890 acd->set_partial(false);
891 EXPECT_FALSE(acd->partial());
892
893 EXPECT_FALSE(vcd->partial()); // default is false.
894 vcd->set_partial(true);
895 EXPECT_TRUE(vcd->partial());
896 vcd->set_partial(false);
897 EXPECT_FALSE(vcd->partial());
898
899 EXPECT_FALSE(dcd->partial()); // default is false.
900 dcd->set_partial(true);
901 EXPECT_TRUE(dcd->partial());
902 dcd->set_partial(false);
903 EXPECT_FALSE(dcd->partial());
904}
905
906// Create a typical video answer, and ensure it matches what we expect.
907TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
908 MediaSessionOptions offer_opts;
909 MediaSessionOptions answer_opts;
910 answer_opts.has_video = true;
911 offer_opts.has_video = true;
912 answer_opts.data_channel_type = cricket::DCT_RTP;
913 offer_opts.data_channel_type = cricket::DCT_RTP;
914
wu@webrtc.org97077a32013-10-25 21:18:33 +0000915 talk_base::scoped_ptr<SessionDescription> offer;
916 talk_base::scoped_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000917
918 offer_opts.rtcp_mux_enabled = true;
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_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
930 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
931 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
932 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
933 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
934 EXPECT_TRUE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
935
936 offer_opts.rtcp_mux_enabled = true;
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_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
948 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
949 EXPECT_TRUE(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 offer_opts.rtcp_mux_enabled = false;
955 answer_opts.rtcp_mux_enabled = true;
956
957 offer.reset(f1_.CreateOffer(offer_opts, NULL));
958 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
959 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
960 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
961 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
962 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
963 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
964 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
965 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
966 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
967 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
968 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
969 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
970 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
971
972 offer_opts.rtcp_mux_enabled = false;
973 answer_opts.rtcp_mux_enabled = false;
974
975 offer.reset(f1_.CreateOffer(offer_opts, NULL));
976 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
977 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
978 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
979 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
980 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
981 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
982 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
983 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
984 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
985 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
986 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
987 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
988 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
989}
990
991// Create an audio-only answer to a video offer.
992TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
993 MediaSessionOptions opts;
994 opts.has_video = true;
995 talk_base::scoped_ptr<SessionDescription>
996 offer(f1_.CreateOffer(opts, NULL));
997 ASSERT_TRUE(offer.get() != NULL);
998 talk_base::scoped_ptr<SessionDescription> answer(
999 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
1000 const ContentInfo* ac = answer->GetContentByName("audio");
1001 const ContentInfo* vc = answer->GetContentByName("video");
1002 ASSERT_TRUE(ac != NULL);
1003 ASSERT_TRUE(vc != NULL);
1004 ASSERT_TRUE(vc->description != NULL);
1005 EXPECT_TRUE(vc->rejected);
1006}
1007
1008// Create an audio-only answer to an offer with data.
1009TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
1010 MediaSessionOptions opts;
1011 opts.data_channel_type = cricket::DCT_RTP;
1012 talk_base::scoped_ptr<SessionDescription>
1013 offer(f1_.CreateOffer(opts, NULL));
1014 ASSERT_TRUE(offer.get() != NULL);
1015 talk_base::scoped_ptr<SessionDescription> answer(
1016 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
1017 const ContentInfo* ac = answer->GetContentByName("audio");
1018 const ContentInfo* dc = answer->GetContentByName("data");
1019 ASSERT_TRUE(ac != NULL);
1020 ASSERT_TRUE(dc != NULL);
1021 ASSERT_TRUE(dc->description != NULL);
1022 EXPECT_TRUE(dc->rejected);
1023}
1024
1025// Create an answer that rejects the contents which are rejected in the offer.
1026TEST_F(MediaSessionDescriptionFactoryTest,
1027 CreateAnswerToOfferWithRejectedMedia) {
1028 MediaSessionOptions opts;
1029 opts.has_video = true;
1030 opts.data_channel_type = cricket::DCT_RTP;
1031 talk_base::scoped_ptr<SessionDescription>
1032 offer(f1_.CreateOffer(opts, NULL));
1033 ASSERT_TRUE(offer.get() != NULL);
1034 ContentInfo* ac = offer->GetContentByName("audio");
1035 ContentInfo* vc = offer->GetContentByName("video");
1036 ContentInfo* dc = offer->GetContentByName("data");
1037 ASSERT_TRUE(ac != NULL);
1038 ASSERT_TRUE(vc != NULL);
1039 ASSERT_TRUE(dc != NULL);
1040 ac->rejected = true;
1041 vc->rejected = true;
1042 dc->rejected = true;
1043 talk_base::scoped_ptr<SessionDescription> answer(
1044 f2_.CreateAnswer(offer.get(), opts, NULL));
1045 ac = answer->GetContentByName("audio");
1046 vc = answer->GetContentByName("video");
1047 dc = answer->GetContentByName("data");
1048 ASSERT_TRUE(ac != NULL);
1049 ASSERT_TRUE(vc != NULL);
1050 ASSERT_TRUE(dc != NULL);
1051 EXPECT_TRUE(ac->rejected);
1052 EXPECT_TRUE(vc->rejected);
1053 EXPECT_TRUE(dc->rejected);
1054}
1055
1056// Create an audio and video offer with:
1057// - one video track
1058// - two audio tracks
1059// - two data tracks
1060// and ensure it matches what we expect. Also updates the initial offer by
1061// adding a new video track and replaces one of the audio tracks.
1062TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
1063 MediaSessionOptions opts;
1064 opts.AddStream(MEDIA_TYPE_VIDEO, kVideoTrack1, kMediaStream1);
1065 opts.AddStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
1066 opts.AddStream(MEDIA_TYPE_AUDIO, kAudioTrack2, kMediaStream1);
1067 opts.data_channel_type = cricket::DCT_RTP;
1068 opts.AddStream(MEDIA_TYPE_DATA, kDataTrack1, kMediaStream1);
1069 opts.AddStream(MEDIA_TYPE_DATA, kDataTrack2, kMediaStream1);
1070
1071 f1_.set_secure(SEC_ENABLED);
1072 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1073
1074 ASSERT_TRUE(offer.get() != NULL);
1075 const ContentInfo* ac = offer->GetContentByName("audio");
1076 const ContentInfo* vc = offer->GetContentByName("video");
1077 const ContentInfo* dc = offer->GetContentByName("data");
1078 ASSERT_TRUE(ac != NULL);
1079 ASSERT_TRUE(vc != NULL);
1080 ASSERT_TRUE(dc != NULL);
1081 const AudioContentDescription* acd =
1082 static_cast<const AudioContentDescription*>(ac->description);
1083 const VideoContentDescription* vcd =
1084 static_cast<const VideoContentDescription*>(vc->description);
1085 const DataContentDescription* dcd =
1086 static_cast<const DataContentDescription*>(dc->description);
1087 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1088 EXPECT_EQ(f1_.audio_codecs(), acd->codecs());
1089
1090 const StreamParamsVec& audio_streams = acd->streams();
1091 ASSERT_EQ(2U, audio_streams.size());
1092 EXPECT_EQ(audio_streams[0].cname , audio_streams[1].cname);
1093 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1094 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1095 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1096 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1097 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1098 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1099
1100 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1101 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1102 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
1103
1104 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1105 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
1106 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1107
1108 const StreamParamsVec& video_streams = vcd->streams();
1109 ASSERT_EQ(1U, video_streams.size());
1110 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1111 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1112 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1113 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1114
1115 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1116 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
1117 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1118
1119 const StreamParamsVec& data_streams = dcd->streams();
1120 ASSERT_EQ(2U, data_streams.size());
1121 EXPECT_EQ(data_streams[0].cname , data_streams[1].cname);
1122 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1123 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1124 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1125 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1126 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1127 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1128
1129 EXPECT_EQ(cricket::kDataMaxBandwidth,
1130 dcd->bandwidth()); // default bandwidth (auto)
1131 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
1132 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1133
1134
1135 // Update the offer. Add a new video track that is not synched to the
1136 // other tracks and replace audio track 2 with audio track 3.
1137 opts.AddStream(MEDIA_TYPE_VIDEO, kVideoTrack2, kMediaStream2);
1138 opts.RemoveStream(MEDIA_TYPE_AUDIO, kAudioTrack2);
1139 opts.AddStream(MEDIA_TYPE_AUDIO, kAudioTrack3, kMediaStream1);
1140 opts.RemoveStream(MEDIA_TYPE_DATA, kDataTrack2);
1141 opts.AddStream(MEDIA_TYPE_DATA, kDataTrack3, kMediaStream1);
1142 talk_base::scoped_ptr<SessionDescription>
1143 updated_offer(f1_.CreateOffer(opts, offer.get()));
1144
1145 ASSERT_TRUE(updated_offer.get() != NULL);
1146 ac = updated_offer->GetContentByName("audio");
1147 vc = updated_offer->GetContentByName("video");
1148 dc = updated_offer->GetContentByName("data");
1149 ASSERT_TRUE(ac != NULL);
1150 ASSERT_TRUE(vc != NULL);
1151 ASSERT_TRUE(dc != NULL);
1152 const AudioContentDescription* updated_acd =
1153 static_cast<const AudioContentDescription*>(ac->description);
1154 const VideoContentDescription* updated_vcd =
1155 static_cast<const VideoContentDescription*>(vc->description);
1156 const DataContentDescription* updated_dcd =
1157 static_cast<const DataContentDescription*>(dc->description);
1158
1159 EXPECT_EQ(acd->type(), updated_acd->type());
1160 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1161 EXPECT_EQ(vcd->type(), updated_vcd->type());
1162 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1163 EXPECT_EQ(dcd->type(), updated_dcd->type());
1164 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1165 ASSERT_CRYPTO(updated_acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
1166 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
1167 ASSERT_CRYPTO(updated_vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1168 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
1169 ASSERT_CRYPTO(updated_dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1170 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1171
1172 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1173 ASSERT_EQ(2U, updated_audio_streams.size());
1174 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
1175 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
1176 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
1177 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
1178 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
1179
1180 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1181 ASSERT_EQ(2U, updated_video_streams.size());
1182 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1183 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
1184 EXPECT_NE(updated_video_streams[1].cname, updated_video_streams[0].cname);
1185
1186 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1187 ASSERT_EQ(2U, updated_data_streams.size());
1188 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
1189 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
1190 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
1191 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
1192 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
1193}
1194
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001195// Create an offer with simulcast video stream.
1196TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
1197 MediaSessionOptions opts;
1198 const int num_sim_layers = 3;
1199 opts.AddVideoStream(kVideoTrack1, kMediaStream1, num_sim_layers);
1200 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1201
1202 ASSERT_TRUE(offer.get() != NULL);
1203 const ContentInfo* vc = offer->GetContentByName("video");
1204 ASSERT_TRUE(vc != NULL);
1205 const VideoContentDescription* vcd =
1206 static_cast<const VideoContentDescription*>(vc->description);
1207
1208 const StreamParamsVec& video_streams = vcd->streams();
1209 ASSERT_EQ(1U, video_streams.size());
1210 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1211 const SsrcGroup* sim_ssrc_group =
1212 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
1213 ASSERT_TRUE(sim_ssrc_group != NULL);
1214 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
1215}
1216
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001217// Create an audio and video answer to a standard video offer with:
1218// - one video track
1219// - two audio tracks
1220// - two data tracks
1221// and ensure it matches what we expect. Also updates the initial answer by
1222// adding a new video track and removes one of the audio tracks.
1223TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
1224 MediaSessionOptions offer_opts;
1225 offer_opts.has_video = true;
1226 offer_opts.data_channel_type = cricket::DCT_RTP;
1227 f1_.set_secure(SEC_ENABLED);
1228 f2_.set_secure(SEC_ENABLED);
1229 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(offer_opts,
1230 NULL));
1231
1232 MediaSessionOptions opts;
1233 opts.AddStream(MEDIA_TYPE_VIDEO, kVideoTrack1, kMediaStream1);
1234 opts.AddStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
1235 opts.AddStream(MEDIA_TYPE_AUDIO, kAudioTrack2, kMediaStream1);
1236 opts.data_channel_type = cricket::DCT_RTP;
1237 opts.AddStream(MEDIA_TYPE_DATA, kDataTrack1, kMediaStream1);
1238 opts.AddStream(MEDIA_TYPE_DATA, kDataTrack2, kMediaStream1);
1239
1240 talk_base::scoped_ptr<SessionDescription>
1241 answer(f2_.CreateAnswer(offer.get(), opts, NULL));
1242
1243 ASSERT_TRUE(answer.get() != NULL);
1244 const ContentInfo* ac = answer->GetContentByName("audio");
1245 const ContentInfo* vc = answer->GetContentByName("video");
1246 const ContentInfo* dc = answer->GetContentByName("data");
1247 ASSERT_TRUE(ac != NULL);
1248 ASSERT_TRUE(vc != NULL);
1249 ASSERT_TRUE(dc != NULL);
1250 const AudioContentDescription* acd =
1251 static_cast<const AudioContentDescription*>(ac->description);
1252 const VideoContentDescription* vcd =
1253 static_cast<const VideoContentDescription*>(vc->description);
1254 const DataContentDescription* dcd =
1255 static_cast<const DataContentDescription*>(dc->description);
1256 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1257 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1258 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1259
1260 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1261 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1262
1263 const StreamParamsVec& audio_streams = acd->streams();
1264 ASSERT_EQ(2U, audio_streams.size());
1265 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
1266 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1267 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1268 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1269 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1270 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1271 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1272
1273 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1274 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1275
1276 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1277 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1278
1279 const StreamParamsVec& video_streams = vcd->streams();
1280 ASSERT_EQ(1U, video_streams.size());
1281 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1282 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1283 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1284 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1285
1286 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1287 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
1288
1289 const StreamParamsVec& data_streams = dcd->streams();
1290 ASSERT_EQ(2U, data_streams.size());
1291 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
1292 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1293 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1294 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1295 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1296 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1297 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1298
1299 EXPECT_EQ(cricket::kDataMaxBandwidth,
1300 dcd->bandwidth()); // default bandwidth (auto)
1301 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
1302
1303 // Update the answer. Add a new video track that is not synched to the
1304 // other traacks and remove 1 audio track.
1305 opts.AddStream(MEDIA_TYPE_VIDEO, kVideoTrack2, kMediaStream2);
1306 opts.RemoveStream(MEDIA_TYPE_AUDIO, kAudioTrack2);
1307 opts.RemoveStream(MEDIA_TYPE_DATA, kDataTrack2);
1308 talk_base::scoped_ptr<SessionDescription>
1309 updated_answer(f2_.CreateAnswer(offer.get(), opts, answer.get()));
1310
1311 ASSERT_TRUE(updated_answer.get() != NULL);
1312 ac = updated_answer->GetContentByName("audio");
1313 vc = updated_answer->GetContentByName("video");
1314 dc = updated_answer->GetContentByName("data");
1315 ASSERT_TRUE(ac != NULL);
1316 ASSERT_TRUE(vc != NULL);
1317 ASSERT_TRUE(dc != NULL);
1318 const AudioContentDescription* updated_acd =
1319 static_cast<const AudioContentDescription*>(ac->description);
1320 const VideoContentDescription* updated_vcd =
1321 static_cast<const VideoContentDescription*>(vc->description);
1322 const DataContentDescription* updated_dcd =
1323 static_cast<const DataContentDescription*>(dc->description);
1324
1325 ASSERT_CRYPTO(updated_acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1326 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
1327 ASSERT_CRYPTO(updated_vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1328 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
1329 ASSERT_CRYPTO(updated_dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1330 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1331
1332 EXPECT_EQ(acd->type(), updated_acd->type());
1333 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1334 EXPECT_EQ(vcd->type(), updated_vcd->type());
1335 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1336 EXPECT_EQ(dcd->type(), updated_dcd->type());
1337 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1338
1339 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1340 ASSERT_EQ(1U, updated_audio_streams.size());
1341 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
1342
1343 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1344 ASSERT_EQ(2U, updated_video_streams.size());
1345 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1346 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
1347 EXPECT_NE(updated_video_streams[1].cname, updated_video_streams[0].cname);
1348
1349 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1350 ASSERT_EQ(1U, updated_data_streams.size());
1351 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
1352}
1353
1354
1355// Create an updated offer after creating an answer to the original offer and
1356// verify that the codecs that were part of the original answer are not changed
1357// in the updated offer.
1358TEST_F(MediaSessionDescriptionFactoryTest,
1359 RespondentCreatesOfferAfterCreatingAnswer) {
1360 MediaSessionOptions opts;
1361 opts.has_audio = true;
1362 opts.has_video = true;
1363
1364 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1365 talk_base::scoped_ptr<SessionDescription> answer(
1366 f2_.CreateAnswer(offer.get(), opts, NULL));
1367
1368 const AudioContentDescription* acd =
1369 GetFirstAudioContentDescription(answer.get());
1370 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1371
1372 const VideoContentDescription* vcd =
1373 GetFirstVideoContentDescription(answer.get());
1374 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1375
1376 talk_base::scoped_ptr<SessionDescription> updated_offer(
1377 f2_.CreateOffer(opts, answer.get()));
1378
1379 // The expected audio codecs are the common audio codecs from the first
1380 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
1381 // preference order.
1382 const AudioCodec kUpdatedAudioCodecOffer[] = {
1383 kAudioCodecs2[0],
1384 kAudioCodecsAnswer[0],
1385 kAudioCodecsAnswer[1],
1386 };
1387
1388 // The expected video codecs are the common video codecs from the first
1389 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
1390 // preference order.
1391 const VideoCodec kUpdatedVideoCodecOffer[] = {
1392 kVideoCodecsAnswer[0],
1393 kVideoCodecs2[1],
1394 };
1395
1396 const AudioContentDescription* updated_acd =
1397 GetFirstAudioContentDescription(updated_offer.get());
1398 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioCodecOffer), updated_acd->codecs());
1399
1400 const VideoContentDescription* updated_vcd =
1401 GetFirstVideoContentDescription(updated_offer.get());
1402 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoCodecOffer), updated_vcd->codecs());
1403}
1404
1405// Create an updated offer after creating an answer to the original offer and
1406// verify that the codecs that were part of the original answer are not changed
1407// in the updated offer. In this test Rtx is enabled.
1408TEST_F(MediaSessionDescriptionFactoryTest,
1409 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
1410 MediaSessionOptions opts;
1411 opts.has_video = true;
1412 opts.has_audio = false;
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 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1425 VideoCodec rtx_f2;
1426 rtx_f2.id = 127;
1427 rtx_f2.name = cricket::kRtxCodecName;
1428
1429 // This creates rtx for H264 with the payload type |f2_| uses.
1430 rtx_f2.params[cricket::kCodecParamAssociatedPayloadType] =
1431 talk_base::ToString<int>(kVideoCodecs2[0].id);
1432 f2_codecs.push_back(rtx_f2);
1433 f2_.set_video_codecs(f2_codecs);
1434
1435 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1436 ASSERT_TRUE(offer.get() != NULL);
1437 talk_base::scoped_ptr<SessionDescription> answer(
1438 f2_.CreateAnswer(offer.get(), opts, NULL));
1439
1440 const VideoContentDescription* vcd =
1441 GetFirstVideoContentDescription(answer.get());
1442
1443 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
1444 expected_codecs.push_back(rtx_f1);
1445
1446 EXPECT_EQ(expected_codecs, vcd->codecs());
1447
1448 // Now, make sure we get same result, except for the preference order,
1449 // if |f2_| creates an updated offer even though the default payload types
1450 // are different from |f1_|.
1451 expected_codecs[0].preference = f1_codecs[1].preference;
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 VideoContentDescription* updated_vcd =
1460 GetFirstVideoContentDescription(updated_answer.get());
1461
1462 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
1463}
1464
1465// Create an updated offer that adds video after creating an audio only answer
1466// to the original offer. This test verifies that if a video codec and the RTX
1467// codec have the same default payload type as an audio codec that is already in
1468// use, the added codecs payload types are changed.
1469TEST_F(MediaSessionDescriptionFactoryTest,
1470 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
1471 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1472 VideoCodec rtx_f1;
1473 rtx_f1.id = 126;
1474 rtx_f1.name = cricket::kRtxCodecName;
1475
1476 // This creates rtx for H264 with the payload type |f1_| uses.
1477 rtx_f1.params[cricket::kCodecParamAssociatedPayloadType] =
1478 talk_base::ToString<int>(kVideoCodecs1[1].id);
1479 f1_codecs.push_back(rtx_f1);
1480 f1_.set_video_codecs(f1_codecs);
1481
1482 MediaSessionOptions opts;
1483 opts.has_audio = true;
1484 opts.has_video = false;
1485
1486 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1487 talk_base::scoped_ptr<SessionDescription> answer(
1488 f2_.CreateAnswer(offer.get(), opts, NULL));
1489
1490 const AudioContentDescription* acd =
1491 GetFirstAudioContentDescription(answer.get());
1492 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1493
1494 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
1495 // reference be the same as an audio codec that was negotiated in the
1496 // first offer/answer exchange.
1497 opts.has_audio = true;
1498 opts.has_video = true;
1499
1500 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1501 int used_pl_type = acd->codecs()[0].id;
1502 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
1503 VideoCodec rtx_f2;
1504 rtx_f2.id = 127;
1505 rtx_f2.name = cricket::kRtxCodecName;
1506 rtx_f2.params[cricket::kCodecParamAssociatedPayloadType] =
1507 talk_base::ToString<int>(used_pl_type);
1508 f2_codecs.push_back(rtx_f2);
1509 f2_.set_video_codecs(f2_codecs);
1510
1511 talk_base::scoped_ptr<SessionDescription> updated_offer(
1512 f2_.CreateOffer(opts, answer.get()));
1513 ASSERT_TRUE(updated_offer);
1514 talk_base::scoped_ptr<SessionDescription> updated_answer(
1515 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
1516
1517 const AudioContentDescription* updated_acd =
1518 GetFirstAudioContentDescription(answer.get());
1519 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), updated_acd->codecs());
1520
1521 const VideoContentDescription* updated_vcd =
1522 GetFirstVideoContentDescription(updated_answer.get());
1523
1524 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
sergeyu@chromium.org32f485b2013-12-05 22:36:21 +00001525 ASSERT_EQ(std::string(cricket::kRtxCodecName), updated_vcd->codecs()[1].name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001526 int new_h264_pl_type = updated_vcd->codecs()[0].id;
1527 EXPECT_NE(used_pl_type, new_h264_pl_type);
1528 VideoCodec rtx = updated_vcd->codecs()[1];
1529 int pt_referenced_by_rtx = talk_base::FromString<int>(
1530 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
1531 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
1532}
1533
1534// Test that RTX is ignored when there is no associated payload type parameter.
1535TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
1536 MediaSessionOptions opts;
1537 opts.has_video = true;
1538 opts.has_audio = false;
1539 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1540 VideoCodec rtx_f1;
1541 rtx_f1.id = 126;
1542 rtx_f1.name = cricket::kRtxCodecName;
1543
1544 f1_codecs.push_back(rtx_f1);
1545 f1_.set_video_codecs(f1_codecs);
1546
1547 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1548 VideoCodec rtx_f2;
1549 rtx_f2.id = 127;
1550 rtx_f2.name = cricket::kRtxCodecName;
1551
1552 // This creates rtx for H264 with the payload type |f2_| uses.
1553 rtx_f2.SetParam(cricket::kCodecParamAssociatedPayloadType,
1554 talk_base::ToString<int>(kVideoCodecs2[0].id));
1555 f2_codecs.push_back(rtx_f2);
1556 f2_.set_video_codecs(f2_codecs);
1557
1558 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1559 ASSERT_TRUE(offer.get() != NULL);
1560 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
1561 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
1562 // is possible to test that that RTX is dropped when
1563 // kCodecParamAssociatedPayloadType is missing in the offer.
1564 VideoContentDescription* desc =
1565 static_cast<cricket::VideoContentDescription*>(
1566 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
1567 ASSERT_TRUE(desc != NULL);
1568 std::vector<VideoCodec> codecs = desc->codecs();
1569 for (std::vector<VideoCodec>::iterator iter = codecs.begin();
1570 iter != codecs.end(); ++iter) {
1571 if (iter->name.find(cricket::kRtxCodecName) == 0) {
1572 iter->params.clear();
1573 }
1574 }
1575 desc->set_codecs(codecs);
1576
1577 talk_base::scoped_ptr<SessionDescription> answer(
1578 f2_.CreateAnswer(offer.get(), opts, NULL));
1579
1580 const VideoContentDescription* vcd =
1581 GetFirstVideoContentDescription(answer.get());
1582
1583 for (std::vector<VideoCodec>::const_iterator iter = vcd->codecs().begin();
1584 iter != vcd->codecs().end(); ++iter) {
1585 ASSERT_STRNE(iter->name.c_str(), cricket::kRtxCodecName);
1586 }
1587}
1588
1589// Create an updated offer after creating an answer to the original offer and
1590// verify that the RTP header extensions that were part of the original answer
1591// are not changed in the updated offer.
1592TEST_F(MediaSessionDescriptionFactoryTest,
1593 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
1594 MediaSessionOptions opts;
1595 opts.has_audio = true;
1596 opts.has_video = true;
1597
1598 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1599 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1600 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1601 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1602
1603 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1604 talk_base::scoped_ptr<SessionDescription> answer(
1605 f2_.CreateAnswer(offer.get(), opts, NULL));
1606
1607 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
1608 GetFirstAudioContentDescription(
1609 answer.get())->rtp_header_extensions());
1610 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
1611 GetFirstVideoContentDescription(
1612 answer.get())->rtp_header_extensions());
1613
1614 talk_base::scoped_ptr<SessionDescription> updated_offer(
1615 f2_.CreateOffer(opts, answer.get()));
1616
1617 // The expected RTP header extensions in the new offer are the resulting
1618 // extensions from the first offer/answer exchange plus the extensions only
1619 // |f2_| offer.
1620 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001621 // |f1_| for another extensions, it is changed to 13.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001622 const RtpHeaderExtension kUpdatedAudioRtpExtensions[] = {
1623 kAudioRtpExtensionAnswer[0],
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001624 RtpHeaderExtension(kAudioRtpExtension2[1].uri, 13),
1625 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001626 };
1627
1628 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001629 // |f1_| for another extensions, is is changed to 12.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001630 const RtpHeaderExtension kUpdatedVideoRtpExtensions[] = {
1631 kVideoRtpExtensionAnswer[0],
henrike@webrtc.org79047f92014-03-06 23:46:59 +00001632 RtpHeaderExtension(kVideoRtpExtension2[1].uri, 12),
1633 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001634 };
1635
1636 const AudioContentDescription* updated_acd =
1637 GetFirstAudioContentDescription(updated_offer.get());
1638 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
1639 updated_acd->rtp_header_extensions());
1640
1641 const VideoContentDescription* updated_vcd =
1642 GetFirstVideoContentDescription(updated_offer.get());
1643 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
1644 updated_vcd->rtp_header_extensions());
1645}
1646
1647TEST(MediaSessionDescription, CopySessionDescription) {
1648 SessionDescription source;
1649 cricket::ContentGroup group(cricket::CN_AUDIO);
1650 source.AddGroup(group);
1651 AudioContentDescription* acd(new AudioContentDescription());
1652 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
1653 acd->AddLegacyStream(1);
1654 source.AddContent(cricket::CN_AUDIO, cricket::NS_JINGLE_RTP, acd);
1655 VideoContentDescription* vcd(new VideoContentDescription());
1656 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
1657 vcd->AddLegacyStream(2);
1658 source.AddContent(cricket::CN_VIDEO, cricket::NS_JINGLE_RTP, vcd);
1659
1660 talk_base::scoped_ptr<SessionDescription> copy(source.Copy());
1661 ASSERT_TRUE(copy.get() != NULL);
1662 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
1663 const ContentInfo* ac = copy->GetContentByName("audio");
1664 const ContentInfo* vc = copy->GetContentByName("video");
1665 ASSERT_TRUE(ac != NULL);
1666 ASSERT_TRUE(vc != NULL);
1667 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
1668 const AudioContentDescription* acd_copy =
1669 static_cast<const AudioContentDescription*>(ac->description);
1670 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
1671 EXPECT_EQ(1u, acd->first_ssrc());
1672
1673 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
1674 const VideoContentDescription* vcd_copy =
1675 static_cast<const VideoContentDescription*>(vc->description);
1676 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
1677 EXPECT_EQ(2u, vcd->first_ssrc());
1678}
1679
1680// The below TestTransportInfoXXX tests create different offers/answers, and
1681// ensure the TransportInfo in the SessionDescription matches what we expect.
1682TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
1683 MediaSessionOptions options;
1684 options.has_audio = true;
1685 TestTransportInfo(true, options, false);
1686}
1687
1688TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
1689 MediaSessionOptions options;
1690 options.has_audio = true;
1691 TestTransportInfo(true, options, true);
1692}
1693
1694TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
1695 MediaSessionOptions options;
1696 options.has_audio = true;
1697 options.has_video = true;
1698 options.data_channel_type = cricket::DCT_RTP;
1699 TestTransportInfo(true, options, false);
1700}
1701
1702TEST_F(MediaSessionDescriptionFactoryTest,
1703 TestTransportInfoOfferMultimediaCurrent) {
1704 MediaSessionOptions options;
1705 options.has_audio = true;
1706 options.has_video = true;
1707 options.data_channel_type = cricket::DCT_RTP;
1708 TestTransportInfo(true, options, true);
1709}
1710
1711TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
1712 MediaSessionOptions options;
1713 options.has_audio = true;
1714 options.has_video = true;
1715 options.data_channel_type = cricket::DCT_RTP;
1716 options.bundle_enabled = true;
1717 TestTransportInfo(true, options, false);
1718}
1719
1720TEST_F(MediaSessionDescriptionFactoryTest,
1721 TestTransportInfoOfferBundleCurrent) {
1722 MediaSessionOptions options;
1723 options.has_audio = true;
1724 options.has_video = true;
1725 options.data_channel_type = cricket::DCT_RTP;
1726 options.bundle_enabled = true;
1727 TestTransportInfo(true, options, true);
1728}
1729
1730TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
1731 MediaSessionOptions options;
1732 options.has_audio = true;
1733 TestTransportInfo(false, options, false);
1734}
1735
1736TEST_F(MediaSessionDescriptionFactoryTest,
1737 TestTransportInfoAnswerAudioCurrent) {
1738 MediaSessionOptions options;
1739 options.has_audio = true;
1740 TestTransportInfo(false, options, true);
1741}
1742
1743TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
1744 MediaSessionOptions options;
1745 options.has_audio = true;
1746 options.has_video = true;
1747 options.data_channel_type = cricket::DCT_RTP;
1748 TestTransportInfo(false, options, false);
1749}
1750
1751TEST_F(MediaSessionDescriptionFactoryTest,
1752 TestTransportInfoAnswerMultimediaCurrent) {
1753 MediaSessionOptions options;
1754 options.has_audio = true;
1755 options.has_video = true;
1756 options.data_channel_type = cricket::DCT_RTP;
1757 TestTransportInfo(false, options, true);
1758}
1759
1760TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
1761 MediaSessionOptions options;
1762 options.has_audio = true;
1763 options.has_video = true;
1764 options.data_channel_type = cricket::DCT_RTP;
1765 options.bundle_enabled = true;
1766 TestTransportInfo(false, options, false);
1767}
1768
1769TEST_F(MediaSessionDescriptionFactoryTest,
1770 TestTransportInfoAnswerBundleCurrent) {
1771 MediaSessionOptions options;
1772 options.has_audio = true;
1773 options.has_video = true;
1774 options.data_channel_type = cricket::DCT_RTP;
1775 options.bundle_enabled = true;
1776 TestTransportInfo(false, options, true);
1777}
1778
1779// Create an offer with bundle enabled and verify the crypto parameters are
1780// the common set of the available cryptos.
1781TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
1782 TestCryptoWithBundle(true);
1783}
1784
1785// Create an answer with bundle enabled and verify the crypto parameters are
1786// the common set of the available cryptos.
1787TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
1788 TestCryptoWithBundle(false);
1789}
1790
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00001791// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
1792// DTLS is not enabled locally.
1793TEST_F(MediaSessionDescriptionFactoryTest,
1794 TestOfferDtlsSavpfWithoutDtlsFailed) {
1795 f1_.set_secure(SEC_ENABLED);
1796 f2_.set_secure(SEC_ENABLED);
1797 tdf1_.set_secure(SEC_DISABLED);
1798 tdf2_.set_secure(SEC_DISABLED);
1799
1800 talk_base::scoped_ptr<SessionDescription> offer(
1801 f1_.CreateOffer(MediaSessionOptions(), NULL));
1802 ASSERT_TRUE(offer.get() != NULL);
1803 ContentInfo* offer_content = offer->GetContentByName("audio");
1804 ASSERT_TRUE(offer_content != NULL);
1805 AudioContentDescription* offer_audio_desc =
1806 static_cast<AudioContentDescription*>(offer_content->description);
1807 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
1808
1809 talk_base::scoped_ptr<SessionDescription> answer(
1810 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
1811 ASSERT_TRUE(answer != NULL);
1812 ContentInfo* answer_content = answer->GetContentByName("audio");
1813 ASSERT_TRUE(answer_content != NULL);
1814
1815 ASSERT_TRUE(answer_content->rejected);
1816}
1817
1818// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
1819// UDP/TLS/RTP/SAVPF.
1820TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
1821 f1_.set_secure(SEC_ENABLED);
1822 f2_.set_secure(SEC_ENABLED);
1823 tdf1_.set_secure(SEC_ENABLED);
1824 tdf2_.set_secure(SEC_ENABLED);
1825
1826 talk_base::scoped_ptr<SessionDescription> offer(
1827 f1_.CreateOffer(MediaSessionOptions(), NULL));
1828 ASSERT_TRUE(offer.get() != NULL);
1829 ContentInfo* offer_content = offer->GetContentByName("audio");
1830 ASSERT_TRUE(offer_content != NULL);
1831 AudioContentDescription* offer_audio_desc =
1832 static_cast<AudioContentDescription*>(offer_content->description);
1833 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
1834
1835 talk_base::scoped_ptr<SessionDescription> answer(
1836 f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
1837 ASSERT_TRUE(answer != NULL);
1838
1839 const ContentInfo* answer_content = answer->GetContentByName("audio");
1840 ASSERT_TRUE(answer_content != NULL);
1841 ASSERT_FALSE(answer_content->rejected);
1842
1843 const AudioContentDescription* answer_audio_desc =
1844 static_cast<const AudioContentDescription*>(answer_content->description);
1845 EXPECT_EQ(std::string(cricket::kMediaProtocolDtlsSavpf),
1846 answer_audio_desc->protocol());
1847}
1848
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001849// Test that we include both SDES and DTLS in the offer, but only include SDES
1850// in the answer if DTLS isn't negotiated.
1851TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
1852 f1_.set_secure(SEC_ENABLED);
1853 f2_.set_secure(SEC_ENABLED);
1854 tdf1_.set_secure(SEC_ENABLED);
1855 tdf2_.set_secure(SEC_DISABLED);
1856 MediaSessionOptions options;
1857 options.has_audio = true;
1858 options.has_video = true;
1859 talk_base::scoped_ptr<SessionDescription> offer, answer;
1860 const cricket::MediaContentDescription* audio_media_desc;
1861 const cricket::MediaContentDescription* video_media_desc;
1862 const cricket::TransportDescription* audio_trans_desc;
1863 const cricket::TransportDescription* video_trans_desc;
1864
1865 // Generate an offer with SDES and DTLS support.
1866 offer.reset(f1_.CreateOffer(options, NULL));
1867 ASSERT_TRUE(offer.get() != NULL);
1868
1869 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
1870 offer->GetContentDescriptionByName("audio"));
1871 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00001872 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001873 offer->GetContentDescriptionByName("video"));
1874 ASSERT_TRUE(video_media_desc != NULL);
1875 EXPECT_EQ(2u, audio_media_desc->cryptos().size());
1876 EXPECT_EQ(1u, video_media_desc->cryptos().size());
1877
1878 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
1879 ASSERT_TRUE(audio_trans_desc != NULL);
1880 video_trans_desc = offer->GetTransportDescriptionByName("video");
1881 ASSERT_TRUE(video_trans_desc != NULL);
1882 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
1883 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
1884
1885 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
1886 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
1887 ASSERT_TRUE(answer.get() != NULL);
1888
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00001889 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001890 answer->GetContentDescriptionByName("audio"));
1891 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00001892 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001893 answer->GetContentDescriptionByName("video"));
1894 ASSERT_TRUE(video_media_desc != NULL);
1895 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
1896 EXPECT_EQ(1u, video_media_desc->cryptos().size());
1897
1898 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
1899 ASSERT_TRUE(audio_trans_desc != NULL);
1900 video_trans_desc = answer->GetTransportDescriptionByName("video");
1901 ASSERT_TRUE(video_trans_desc != NULL);
1902 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
1903 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
1904
1905 // Enable DTLS; the answer should now only have DTLS support.
1906 tdf2_.set_secure(SEC_ENABLED);
1907 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
1908 ASSERT_TRUE(answer.get() != NULL);
1909
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00001910 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001911 answer->GetContentDescriptionByName("audio"));
1912 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00001913 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001914 answer->GetContentDescriptionByName("video"));
1915 ASSERT_TRUE(video_media_desc != NULL);
1916 EXPECT_TRUE(audio_media_desc->cryptos().empty());
1917 EXPECT_TRUE(video_media_desc->cryptos().empty());
1918 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
1919 audio_media_desc->protocol());
1920 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
1921 video_media_desc->protocol());
1922
1923 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
1924 ASSERT_TRUE(audio_trans_desc != NULL);
1925 video_trans_desc = answer->GetTransportDescriptionByName("video");
1926 ASSERT_TRUE(video_trans_desc != NULL);
1927 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
1928 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001929
1930 // Try creating offer again. DTLS enabled now, crypto's should be empty
1931 // in new offer.
1932 offer.reset(f1_.CreateOffer(options, offer.get()));
1933 ASSERT_TRUE(offer.get() != NULL);
1934 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
1935 offer->GetContentDescriptionByName("audio"));
1936 ASSERT_TRUE(audio_media_desc != NULL);
1937 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
1938 offer->GetContentDescriptionByName("video"));
1939 ASSERT_TRUE(video_media_desc != NULL);
1940 EXPECT_TRUE(audio_media_desc->cryptos().empty());
1941 EXPECT_TRUE(video_media_desc->cryptos().empty());
1942
1943 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
1944 ASSERT_TRUE(audio_trans_desc != NULL);
1945 video_trans_desc = offer->GetTransportDescriptionByName("video");
1946 ASSERT_TRUE(video_trans_desc != NULL);
1947 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
1948 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001949}
1950
1951// Test that an answer can't be created if cryptos are required but the offer is
1952// unsecure.
1953TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
1954 MediaSessionOptions options;
1955 f1_.set_secure(SEC_DISABLED);
1956 tdf1_.set_secure(SEC_DISABLED);
1957 f2_.set_secure(SEC_REQUIRED);
1958 tdf1_.set_secure(SEC_ENABLED);
1959
1960 talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(options,
1961 NULL));
1962 ASSERT_TRUE(offer.get() != NULL);
1963 talk_base::scoped_ptr<SessionDescription> answer(
1964 f2_.CreateAnswer(offer.get(), options, NULL));
1965 EXPECT_TRUE(answer.get() == NULL);
1966}
1967
1968// Test that we accept a DTLS offer without SDES and create an appropriate
1969// answer.
1970TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
1971 f1_.set_secure(SEC_DISABLED);
1972 f2_.set_secure(SEC_ENABLED);
1973 tdf1_.set_secure(SEC_ENABLED);
1974 tdf2_.set_secure(SEC_ENABLED);
1975 MediaSessionOptions options;
1976 options.has_audio = true;
1977 options.has_video = true;
1978 options.data_channel_type = cricket::DCT_RTP;
1979
1980 talk_base::scoped_ptr<SessionDescription> offer, answer;
1981
1982 // Generate an offer with DTLS but without SDES.
1983 offer.reset(f1_.CreateOffer(options, NULL));
1984 ASSERT_TRUE(offer.get() != NULL);
1985
1986 const AudioContentDescription* audio_offer =
1987 GetFirstAudioContentDescription(offer.get());
1988 ASSERT_TRUE(audio_offer->cryptos().empty());
1989 const VideoContentDescription* video_offer =
1990 GetFirstVideoContentDescription(offer.get());
1991 ASSERT_TRUE(video_offer->cryptos().empty());
1992 const DataContentDescription* data_offer =
1993 GetFirstDataContentDescription(offer.get());
1994 ASSERT_TRUE(data_offer->cryptos().empty());
1995
1996 const cricket::TransportDescription* audio_offer_trans_desc =
1997 offer->GetTransportDescriptionByName("audio");
1998 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
1999 const cricket::TransportDescription* video_offer_trans_desc =
2000 offer->GetTransportDescriptionByName("video");
2001 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
2002 const cricket::TransportDescription* data_offer_trans_desc =
2003 offer->GetTransportDescriptionByName("data");
2004 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
2005
2006 // Generate an answer with DTLS.
2007 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2008 ASSERT_TRUE(answer.get() != NULL);
2009
2010 const cricket::TransportDescription* audio_answer_trans_desc =
2011 answer->GetTransportDescriptionByName("audio");
2012 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
2013 const cricket::TransportDescription* video_answer_trans_desc =
2014 answer->GetTransportDescriptionByName("video");
2015 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
2016 const cricket::TransportDescription* data_answer_trans_desc =
2017 answer->GetTransportDescriptionByName("data");
2018 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
2019}
2020
2021// Verifies if vad_enabled option is set to false, CN codecs are not present in
2022// offer or answer.
2023TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
2024 MediaSessionOptions options;
2025 options.has_audio = true;
2026 options.has_video = true;
2027 talk_base::scoped_ptr<SessionDescription> offer(
2028 f1_.CreateOffer(options, NULL));
2029 ASSERT_TRUE(offer.get() != NULL);
2030 const ContentInfo* audio_content = offer->GetContentByName("audio");
2031 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
2032
2033 options.vad_enabled = false;
2034 offer.reset(f1_.CreateOffer(options, NULL));
2035 ASSERT_TRUE(offer.get() != NULL);
2036 audio_content = offer->GetContentByName("audio");
2037 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
2038 talk_base::scoped_ptr<SessionDescription> answer(
2039 f1_.CreateAnswer(offer.get(), options, NULL));
2040 ASSERT_TRUE(answer.get() != NULL);
2041 audio_content = answer->GetContentByName("audio");
2042 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
2043}