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