1 /*
2  * libjingle
3  * Copyright 2004--2011, 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/p2p/base/constants.h"
33 #include "talk/session/phone/codec.h"
34 #include "talk/session/phone/mediasession.h"
35 #include "talk/session/phone/srtpfilter.h"
36 #include "talk/session/phone/testutils.h"
37 
38 #ifdef HAVE_SRTP
39 #define ASSERT_CRYPTO(cd, r, s, cs) \
40     ASSERT_EQ(r, cd->crypto_required()); \
41     ASSERT_EQ(s, cd->cryptos().size()); \
42     ASSERT_EQ(std::string(cs), cd->cryptos()[0].cipher_suite)
43 #else
44 #define ASSERT_CRYPTO(c, r, s, cs) \
45   ASSERT_EQ(false, cd->crypto_required()); \
46   ASSERT_EQ(0U, cd->cryptos().size());
47 #endif
48 
49 using cricket::MediaSessionDescriptionFactory;
50 using cricket::MediaSessionOptions;
51 using cricket::MediaType;
52 using cricket::SessionDescription;
53 using cricket::SsrcGroup;
54 using cricket::StreamParams;
55 using cricket::StreamParamsVec;
56 using cricket::ContentInfo;
57 using cricket::CryptoParamsVec;
58 using cricket::AudioContentDescription;
59 using cricket::VideoContentDescription;
60 using cricket::DataContentDescription;
61 using cricket::GetFirstAudioContentDescription;
62 using cricket::GetFirstVideoContentDescription;
63 using cricket::GetFirstDataContentDescription;
64 using cricket::kAutoBandwidth;
65 using cricket::AudioCodec;
66 using cricket::VideoCodec;
67 using cricket::DataCodec;
68 using cricket::NS_JINGLE_RTP;
69 using cricket::MEDIA_TYPE_AUDIO;
70 using cricket::MEDIA_TYPE_VIDEO;
71 using cricket::MEDIA_TYPE_DATA;
72 using cricket::SEC_ENABLED;
73 using cricket::CS_AES_CM_128_HMAC_SHA1_32;
74 using cricket::CS_AES_CM_128_HMAC_SHA1_80;
75 
76 static const AudioCodec kAudioCodecs1[] = {
77   AudioCodec(103, "ISAC",   16000, -1,    1, 5),
78   AudioCodec(102, "iLBC",   8000,  13300, 1, 4),
79   AudioCodec(0,   "PCMU",   8000,  64000, 1, 3),
80   AudioCodec(8,   "PCMA",   8000,  64000, 1, 2),
81   AudioCodec(117, "red",    8000,  0,     1, 1),
82 };
83 
84 static const AudioCodec kAudioCodecs2[] = {
85   AudioCodec(126, "speex",  16000, 22000, 1, 3),
86   AudioCodec(127, "iLBC",   8000,  13300, 1, 2),
87   AudioCodec(0,   "PCMU",   8000,  64000, 1, 1),
88 };
89 
90 static const AudioCodec kAudioCodecsAnswer[] = {
91   AudioCodec(102, "iLBC",   8000,  13300, 1, 2),
92   AudioCodec(0,   "PCMU",   8000,  64000, 1, 1),
93 };
94 
95 static const VideoCodec kVideoCodecs1[] = {
96   VideoCodec(96, "H264-SVC", 320, 200, 30, 2),
97   VideoCodec(97, "H264", 320, 200, 30, 1)
98 };
99 
100 static const VideoCodec kVideoCodecs2[] = {
101   VideoCodec(126, "H264", 320, 200, 30, 2),
102   VideoCodec(127, "H263", 320, 200, 30, 1)
103 };
104 
105 static const VideoCodec kVideoCodecsAnswer[] = {
106   VideoCodec(97, "H264", 320, 200, 30, 2)
107 };
108 
109 static const DataCodec kDataCodecs1[] = {
110   DataCodec(96, "binary-data", 2),
111   DataCodec(97, "utf8-text", 1)
112 };
113 
114 static const DataCodec kDataCodecs2[] = {
115   DataCodec(126, "binary-data", 2),
116   DataCodec(127, "utf8-text", 1)
117 };
118 
119 static const DataCodec kDataCodecsAnswer[] = {
120   DataCodec(96, "binary-data", 2),
121   DataCodec(97, "utf8-text", 1)
122 };
123 
124 static const uint32 kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
125 static const uint32 kSimSsrc[] = {10, 20, 30};
126 static const uint32 kFec1Ssrc[] = {10, 11};
127 static const uint32 kFec2Ssrc[] = {20, 21};
128 static const uint32 kFec3Ssrc[] = {30, 31};
129 
130 static const char kMediaStream1[] = "stream_1";
131 static const char kMediaStream2[] = "stream_2";
132 static const char kVideoTrack1[] = "video_1";
133 static const char kVideoTrack2[] = "video_2";
134 static const char kAudioTrack1[] = "audio_1";
135 static const char kAudioTrack2[] = "audio_2";
136 static const char kAudioTrack3[] = "audio_3";
137 static const char kDataTrack1[] = "data_1";
138 static const char kDataTrack2[] = "data_2";
139 static const char kDataTrack3[] = "data_3";
140 
141 class MediaSessionDescriptionFactoryTest : public testing::Test {
142  public:
MediaSessionDescriptionFactoryTest()143   MediaSessionDescriptionFactoryTest() {
144     f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1));
145     f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
146     f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
147     f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2));
148     f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
149     f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
150   }
151 
152   // Create a video StreamParamsVec object with:
153   // - one video stream with 3 simulcast streams and FEC,
CreateComplexVideoStreamParamsVec()154   StreamParamsVec CreateComplexVideoStreamParamsVec() {
155     SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
156     SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
157     SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
158     SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
159 
160     std::vector<SsrcGroup> ssrc_groups;
161     ssrc_groups.push_back(sim_group);
162     ssrc_groups.push_back(fec_group1);
163     ssrc_groups.push_back(fec_group2);
164     ssrc_groups.push_back(fec_group3);
165 
166     StreamParams simulcast_params;
167     simulcast_params.name = kVideoTrack1;
168     simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
169     simulcast_params.ssrc_groups = ssrc_groups;
170     simulcast_params.cname = "Video_SIM_FEC";
171     simulcast_params.sync_label = kMediaStream1;
172 
173     StreamParamsVec video_streams;
174     video_streams.push_back(simulcast_params);
175 
176     return video_streams;
177   }
CompareCryptoParams(const CryptoParamsVec & c1,const CryptoParamsVec & c2)178   bool CompareCryptoParams(const CryptoParamsVec& c1,
179                            const CryptoParamsVec& c2) {
180     if (c1.size() != c2.size())
181       return false;
182     for (size_t i = 0; i < c1.size(); ++i)
183       if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
184           c1[i].key_params != c2[i].key_params ||
185           c1[i].session_params != c2[i].session_params)
186         return false;
187     return true;
188   }
189 
190  protected:
191   MediaSessionDescriptionFactory f1_;
192   MediaSessionDescriptionFactory f2_;
193 };
194 
195 // Create a typical audio offer, and ensure it matches what we expect.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateAudioOffer)196 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
197   f1_.set_secure(SEC_ENABLED);
198   talk_base::scoped_ptr<SessionDescription> offer(
199       f1_.CreateOffer(MediaSessionOptions(), NULL));
200   ASSERT_TRUE(offer.get() != NULL);
201   const ContentInfo* ac = offer->GetContentByName("audio");
202   const ContentInfo* vc = offer->GetContentByName("video");
203   ASSERT_TRUE(ac != NULL);
204   ASSERT_TRUE(vc == NULL);
205   EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
206   const AudioContentDescription* acd =
207       static_cast<const AudioContentDescription*>(ac->description);
208   EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
209   EXPECT_EQ(f1_.audio_codecs(), acd->codecs());
210   EXPECT_NE(0U, acd->first_ssrc());             // a random nonzero ssrc
211   EXPECT_EQ(kAutoBandwidth, acd->bandwidth());  // default bandwidth (auto)
212   EXPECT_TRUE(acd->rtcp_mux());                 // rtcp-mux defaults on
213   ASSERT_CRYPTO(acd, false, 2U, CS_AES_CM_128_HMAC_SHA1_32);
214 }
215 
216 // Create a typical video offer, and ensure it matches what we expect.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateVideoOffer)217 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
218   MediaSessionOptions opts;
219   opts.has_video = true;
220   f1_.set_secure(SEC_ENABLED);
221   talk_base::scoped_ptr<SessionDescription>
222       offer(f1_.CreateOffer(opts, NULL));
223   ASSERT_TRUE(offer.get() != NULL);
224   const ContentInfo* ac = offer->GetContentByName("audio");
225   const ContentInfo* vc = offer->GetContentByName("video");
226   ASSERT_TRUE(ac != NULL);
227   ASSERT_TRUE(vc != NULL);
228   EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
229   EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
230   const AudioContentDescription* acd =
231       static_cast<const AudioContentDescription*>(ac->description);
232   const VideoContentDescription* vcd =
233       static_cast<const VideoContentDescription*>(vc->description);
234   EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
235   EXPECT_EQ(f1_.audio_codecs(), acd->codecs());
236   EXPECT_NE(0U, acd->first_ssrc());             // a random nonzero ssrc
237   EXPECT_EQ(kAutoBandwidth, acd->bandwidth());  // default bandwidth (auto)
238   EXPECT_TRUE(acd->rtcp_mux());                 // rtcp-mux defaults on
239   ASSERT_CRYPTO(acd, false, 2U, CS_AES_CM_128_HMAC_SHA1_32);
240   EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
241   EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
242   EXPECT_NE(0U, vcd->first_ssrc());             // a random nonzero ssrc
243   EXPECT_EQ(kAutoBandwidth, vcd->bandwidth());  // default bandwidth (auto)
244   EXPECT_TRUE(vcd->rtcp_mux());                 // rtcp-mux defaults on
245   ASSERT_CRYPTO(vcd, false, 1U, CS_AES_CM_128_HMAC_SHA1_80);
246 }
247 
248 // Create a typical data offer, and ensure it matches what we expect.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateDataOffer)249 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataOffer) {
250   MediaSessionOptions opts;
251   opts.has_data = true;
252   f1_.set_secure(SEC_ENABLED);
253   talk_base::scoped_ptr<SessionDescription>
254       offer(f1_.CreateOffer(opts, NULL));
255   ASSERT_TRUE(offer.get() != NULL);
256   const ContentInfo* ac = offer->GetContentByName("audio");
257   const ContentInfo* dc = offer->GetContentByName("data");
258   ASSERT_TRUE(ac != NULL);
259   ASSERT_TRUE(dc != NULL);
260   EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
261   EXPECT_EQ(std::string(NS_JINGLE_RTP), dc->type);
262   const AudioContentDescription* acd =
263       static_cast<const AudioContentDescription*>(ac->description);
264   const DataContentDescription* dcd =
265       static_cast<const DataContentDescription*>(dc->description);
266   EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
267   EXPECT_EQ(f1_.audio_codecs(), acd->codecs());
268   EXPECT_NE(0U, acd->first_ssrc());             // a random nonzero ssrc
269   EXPECT_EQ(kAutoBandwidth, acd->bandwidth());  // default bandwidth (auto)
270   EXPECT_TRUE(acd->rtcp_mux());                 // rtcp-mux defaults on
271   ASSERT_CRYPTO(acd, false, 2U, CS_AES_CM_128_HMAC_SHA1_32);
272   EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
273   EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
274   EXPECT_NE(0U, dcd->first_ssrc());             // a random nonzero ssrc
275   EXPECT_EQ(cricket::kDataMaxBandwidth,
276             dcd->bandwidth());                  // default bandwidth (auto)
277   EXPECT_TRUE(dcd->rtcp_mux());                 // rtcp-mux defaults on
278   ASSERT_CRYPTO(dcd, false, 1U, CS_AES_CM_128_HMAC_SHA1_80);
279 }
280 
281 // Create an audio, video offer without legacy StreamParams.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateOfferWithoutLegacyStreams)282 TEST_F(MediaSessionDescriptionFactoryTest,
283        TestCreateOfferWithoutLegacyStreams) {
284   MediaSessionOptions opts;
285   opts.has_video = true;
286   f1_.set_add_legacy_streams(false);
287   talk_base::scoped_ptr<SessionDescription>
288       offer(f1_.CreateOffer(opts, NULL));
289   ASSERT_TRUE(offer.get() != NULL);
290   const ContentInfo* ac = offer->GetContentByName("audio");
291   const ContentInfo* vc = offer->GetContentByName("video");
292   ASSERT_TRUE(ac != NULL);
293   ASSERT_TRUE(vc != NULL);
294   const AudioContentDescription* acd =
295       static_cast<const AudioContentDescription*>(ac->description);
296   const VideoContentDescription* vcd =
297       static_cast<const VideoContentDescription*>(vc->description);
298 
299   EXPECT_FALSE(vcd->has_ssrcs());             // No StreamParams.
300   EXPECT_FALSE(acd->has_ssrcs());             // No StreamParams.
301 }
302 
303 // Create a typical audio answer, and ensure it matches what we expect.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateAudioAnswer)304 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
305   f1_.set_secure(SEC_ENABLED);
306   f2_.set_secure(SEC_ENABLED);
307   talk_base::scoped_ptr<SessionDescription> offer(
308       f1_.CreateOffer(MediaSessionOptions(), NULL));
309   ASSERT_TRUE(offer.get() != NULL);
310   talk_base::scoped_ptr<SessionDescription> answer(
311       f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
312   const ContentInfo* ac = answer->GetContentByName("audio");
313   const ContentInfo* vc = answer->GetContentByName("video");
314   ASSERT_TRUE(ac != NULL);
315   ASSERT_TRUE(vc == NULL);
316   EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
317   const AudioContentDescription* acd =
318       static_cast<const AudioContentDescription*>(ac->description);
319   EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
320   EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
321   EXPECT_NE(0U, acd->first_ssrc());             // a random nonzero ssrc
322   EXPECT_EQ(kAutoBandwidth, acd->bandwidth());  // negotiated auto bw
323   EXPECT_TRUE(acd->rtcp_mux());                 // negotiated rtcp-mux
324   ASSERT_CRYPTO(acd, false, 1U, CS_AES_CM_128_HMAC_SHA1_32);
325 }
326 
327 // Create a typical video answer, and ensure it matches what we expect.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateVideoAnswer)328 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
329   MediaSessionOptions opts;
330   opts.has_video = true;
331   f1_.set_secure(SEC_ENABLED);
332   f2_.set_secure(SEC_ENABLED);
333   talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
334   ASSERT_TRUE(offer.get() != NULL);
335   talk_base::scoped_ptr<SessionDescription> answer(
336       f2_.CreateAnswer(offer.get(), opts, NULL));
337   const ContentInfo* ac = answer->GetContentByName("audio");
338   const ContentInfo* vc = answer->GetContentByName("video");
339   ASSERT_TRUE(ac != NULL);
340   ASSERT_TRUE(vc != NULL);
341   EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
342   EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
343   const AudioContentDescription* acd =
344       static_cast<const AudioContentDescription*>(ac->description);
345   const VideoContentDescription* vcd =
346       static_cast<const VideoContentDescription*>(vc->description);
347   EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
348   EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
349   EXPECT_EQ(kAutoBandwidth, acd->bandwidth());  // negotiated auto bw
350   EXPECT_NE(0U, acd->first_ssrc());             // a random nonzero ssrc
351   EXPECT_TRUE(acd->rtcp_mux());                 // negotiated rtcp-mux
352   ASSERT_CRYPTO(acd, false, 1U, CS_AES_CM_128_HMAC_SHA1_32);
353   EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
354   EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
355   EXPECT_NE(0U, vcd->first_ssrc());             // a random nonzero ssrc
356   EXPECT_TRUE(vcd->rtcp_mux());                 // negotiated rtcp-mux
357   ASSERT_CRYPTO(vcd, false, 1U, CS_AES_CM_128_HMAC_SHA1_80);
358 }
359 
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateDataAnswer)360 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
361   MediaSessionOptions opts;
362   opts.has_data = true;
363   f1_.set_secure(SEC_ENABLED);
364   f2_.set_secure(SEC_ENABLED);
365   talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
366   ASSERT_TRUE(offer.get() != NULL);
367   talk_base::scoped_ptr<SessionDescription> answer(
368       f2_.CreateAnswer(offer.get(), opts, NULL));
369   const ContentInfo* ac = answer->GetContentByName("audio");
370   const ContentInfo* vc = answer->GetContentByName("data");
371   ASSERT_TRUE(ac != NULL);
372   ASSERT_TRUE(vc != NULL);
373   EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
374   EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
375   const AudioContentDescription* acd =
376       static_cast<const AudioContentDescription*>(ac->description);
377   const DataContentDescription* vcd =
378       static_cast<const DataContentDescription*>(vc->description);
379   EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
380   EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
381   EXPECT_EQ(kAutoBandwidth, acd->bandwidth());  // negotiated auto bw
382   EXPECT_NE(0U, acd->first_ssrc());             // a random nonzero ssrc
383   EXPECT_TRUE(acd->rtcp_mux());                 // negotiated rtcp-mux
384   ASSERT_CRYPTO(acd, false, 1U, CS_AES_CM_128_HMAC_SHA1_32);
385   EXPECT_EQ(MEDIA_TYPE_DATA, vcd->type());
386   EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), vcd->codecs());
387   EXPECT_NE(0U, vcd->first_ssrc());             // a random nonzero ssrc
388   EXPECT_TRUE(vcd->rtcp_mux());                 // negotiated rtcp-mux
389   ASSERT_CRYPTO(vcd, false, 1U, CS_AES_CM_128_HMAC_SHA1_80);
390 }
391 
392 // Create an audio, video, data answer without legacy StreamParams.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateAnswerWithoutLegacyStreams)393 TEST_F(MediaSessionDescriptionFactoryTest,
394        TestCreateAnswerWithoutLegacyStreams) {
395   MediaSessionOptions opts;
396   opts.has_video = true;
397   opts.has_data = true;
398   f1_.set_add_legacy_streams(false);
399   f2_.set_add_legacy_streams(false);
400   talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
401   ASSERT_TRUE(offer.get() != NULL);
402   talk_base::scoped_ptr<SessionDescription> answer(
403       f2_.CreateAnswer(offer.get(), opts, NULL));
404   const ContentInfo* ac = answer->GetContentByName("audio");
405   const ContentInfo* vc = answer->GetContentByName("video");
406   const ContentInfo* dc = answer->GetContentByName("data");
407   ASSERT_TRUE(ac != NULL);
408   ASSERT_TRUE(vc != NULL);
409   const AudioContentDescription* acd =
410       static_cast<const AudioContentDescription*>(ac->description);
411   const VideoContentDescription* vcd =
412       static_cast<const VideoContentDescription*>(vc->description);
413   const DataContentDescription* dcd =
414       static_cast<const DataContentDescription*>(dc->description);
415 
416   EXPECT_FALSE(acd->has_ssrcs());  // No StreamParams.
417   EXPECT_FALSE(vcd->has_ssrcs());  // No StreamParams.
418   EXPECT_FALSE(dcd->has_ssrcs());  // No StreamParams.
419 }
420 
TEST_F(MediaSessionDescriptionFactoryTest,TestPartial)421 TEST_F(MediaSessionDescriptionFactoryTest, TestPartial) {
422   MediaSessionOptions opts;
423   opts.has_video = true;
424   opts.has_data = true;
425   f1_.set_secure(SEC_ENABLED);
426   talk_base::scoped_ptr<SessionDescription>
427       offer(f1_.CreateOffer(opts, NULL));
428   ASSERT_TRUE(offer.get() != NULL);
429   const ContentInfo* ac = offer->GetContentByName("audio");
430   const ContentInfo* vc = offer->GetContentByName("video");
431   const ContentInfo* dc = offer->GetContentByName("data");
432   AudioContentDescription* acd = const_cast<AudioContentDescription*>(
433       static_cast<const AudioContentDescription*>(ac->description));
434   VideoContentDescription* vcd = const_cast<VideoContentDescription*>(
435       static_cast<const VideoContentDescription*>(vc->description));
436   DataContentDescription* dcd = const_cast<DataContentDescription*>(
437       static_cast<const DataContentDescription*>(dc->description));
438 
439   EXPECT_FALSE(acd->partial());  // default is false.
440   acd->set_partial(true);
441   EXPECT_TRUE(acd->partial());
442   acd->set_partial(false);
443   EXPECT_FALSE(acd->partial());
444 
445   EXPECT_FALSE(vcd->partial());  // default is false.
446   vcd->set_partial(true);
447   EXPECT_TRUE(vcd->partial());
448   vcd->set_partial(false);
449   EXPECT_FALSE(vcd->partial());
450 
451   EXPECT_FALSE(dcd->partial());  // default is false.
452   dcd->set_partial(true);
453   EXPECT_TRUE(dcd->partial());
454   dcd->set_partial(false);
455   EXPECT_FALSE(dcd->partial());
456 }
457 
458 // Create a typical video answer, and ensure it matches what we expect.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateVideoAnswerRtcpMux)459 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
460   MediaSessionOptions offer_opts;
461   MediaSessionOptions answer_opts;
462   answer_opts.has_video = true;
463   offer_opts.has_video = true;
464   answer_opts.has_data = true;
465   offer_opts.has_data = true;
466 
467   talk_base::scoped_ptr<SessionDescription> offer(NULL);
468   talk_base::scoped_ptr<SessionDescription> answer(NULL);
469 
470   offer_opts.rtcp_mux_enabled = true;
471   answer_opts.rtcp_mux_enabled = true;
472 
473   offer.reset(f1_.CreateOffer(offer_opts, NULL));
474   answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
475   ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
476   ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
477   ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
478   ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
479   ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
480   ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
481   EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
482   EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
483   EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
484   EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
485   EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
486   EXPECT_TRUE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
487 
488   offer_opts.rtcp_mux_enabled = true;
489   answer_opts.rtcp_mux_enabled = false;
490 
491   offer.reset(f1_.CreateOffer(offer_opts, NULL));
492   answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
493   ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
494   ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
495   ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
496   ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
497   ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
498   ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
499   EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
500   EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
501   EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
502   EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
503   EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
504   EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
505 
506   offer_opts.rtcp_mux_enabled = false;
507   answer_opts.rtcp_mux_enabled = true;
508 
509   offer.reset(f1_.CreateOffer(offer_opts, NULL));
510   answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
511   ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
512   ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
513   ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
514   ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
515   ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
516   ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
517   EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
518   EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
519   EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
520   EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
521   EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
522   EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
523 
524   offer_opts.rtcp_mux_enabled = false;
525   answer_opts.rtcp_mux_enabled = false;
526 
527   offer.reset(f1_.CreateOffer(offer_opts, NULL));
528   answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
529   ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
530   ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
531   ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
532   ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
533   ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
534   ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
535   EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
536   EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
537   EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
538   EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
539   EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
540   EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
541 }
542 
543 // Create an audio-only answer to a video offer.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateAudioAnswerToVideo)544 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
545   MediaSessionOptions opts;
546   opts.has_video = true;
547   talk_base::scoped_ptr<SessionDescription>
548       offer(f1_.CreateOffer(opts, NULL));
549   ASSERT_TRUE(offer.get() != NULL);
550   talk_base::scoped_ptr<SessionDescription> answer(
551       f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
552   const ContentInfo* ac = answer->GetContentByName("audio");
553   const ContentInfo* vc = answer->GetContentByName("video");
554   ASSERT_TRUE(ac != NULL);
555   ASSERT_TRUE(vc == NULL);
556 }
557 
558 // Create an audio-only answer to a video offer.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateNoDataAnswerToDataOffer)559 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
560   MediaSessionOptions opts;
561   opts.has_data = true;
562   talk_base::scoped_ptr<SessionDescription>
563       offer(f1_.CreateOffer(opts, NULL));
564   ASSERT_TRUE(offer.get() != NULL);
565   talk_base::scoped_ptr<SessionDescription> answer(
566       f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
567   const ContentInfo* ac = answer->GetContentByName("audio");
568   const ContentInfo* dc = answer->GetContentByName("data");
569   ASSERT_TRUE(ac != NULL);
570   ASSERT_TRUE(dc == NULL);
571 }
572 
573 // Create an audio and video offer with:
574 // - one video track
575 // - two audio tracks
576 // - two data tracks
577 // and ensure it matches what we expect. Also updates the initial offer by
578 // adding a new video track and replaces one of the audio tracks.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateMultiStreamVideoOffer)579 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
580   MediaSessionOptions opts;
581   opts.AddStream(MEDIA_TYPE_VIDEO, kVideoTrack1, kMediaStream1);
582   opts.AddStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
583   opts.AddStream(MEDIA_TYPE_AUDIO, kAudioTrack2, kMediaStream1);
584   opts.AddStream(MEDIA_TYPE_DATA, kDataTrack1, kMediaStream1);
585   opts.AddStream(MEDIA_TYPE_DATA, kDataTrack2, kMediaStream1);
586 
587   f1_.set_secure(SEC_ENABLED);
588   talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
589 
590   ASSERT_TRUE(offer.get() != NULL);
591   const ContentInfo* ac = offer->GetContentByName("audio");
592   const ContentInfo* vc = offer->GetContentByName("video");
593   const ContentInfo* dc = offer->GetContentByName("data");
594   ASSERT_TRUE(ac != NULL);
595   ASSERT_TRUE(vc != NULL);
596   ASSERT_TRUE(dc != NULL);
597   const AudioContentDescription* acd =
598       static_cast<const AudioContentDescription*>(ac->description);
599   const VideoContentDescription* vcd =
600       static_cast<const VideoContentDescription*>(vc->description);
601   const DataContentDescription* dcd =
602       static_cast<const DataContentDescription*>(dc->description);
603   EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
604   EXPECT_EQ(f1_.audio_codecs(), acd->codecs());
605 
606   const StreamParamsVec& audio_streams = acd->streams();
607   ASSERT_EQ(2U, audio_streams.size());
608   EXPECT_EQ(audio_streams[0].cname , audio_streams[1].cname);
609   EXPECT_EQ(kAudioTrack1, audio_streams[0].name);
610   ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
611   EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
612   EXPECT_EQ(kAudioTrack2, audio_streams[1].name);
613   ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
614   EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
615 
616   EXPECT_EQ(kAutoBandwidth, acd->bandwidth());  // default bandwidth (auto)
617   EXPECT_TRUE(acd->rtcp_mux());                 // rtcp-mux defaults on
618   ASSERT_CRYPTO(acd, false, 2U, CS_AES_CM_128_HMAC_SHA1_32);
619 
620   EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
621   EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
622   ASSERT_CRYPTO(vcd, false, 1U, CS_AES_CM_128_HMAC_SHA1_80);
623 
624   const StreamParamsVec& video_streams = vcd->streams();
625   ASSERT_EQ(1U, video_streams.size());
626   EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
627   EXPECT_EQ(kVideoTrack1, video_streams[0].name);
628   EXPECT_EQ(kAutoBandwidth, vcd->bandwidth());  // default bandwidth (auto)
629   EXPECT_TRUE(vcd->rtcp_mux());                 // rtcp-mux defaults on
630 
631   EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
632   EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
633   ASSERT_CRYPTO(dcd, false, 1U, CS_AES_CM_128_HMAC_SHA1_80);
634 
635   const StreamParamsVec& data_streams = dcd->streams();
636   ASSERT_EQ(2U, data_streams.size());
637   EXPECT_EQ(data_streams[0].cname , data_streams[1].cname);
638   EXPECT_EQ(kDataTrack1, data_streams[0].name);
639   ASSERT_EQ(1U, data_streams[0].ssrcs.size());
640   EXPECT_NE(0U, data_streams[0].ssrcs[0]);
641   EXPECT_EQ(kDataTrack2, data_streams[1].name);
642   ASSERT_EQ(1U, data_streams[1].ssrcs.size());
643   EXPECT_NE(0U, data_streams[1].ssrcs[0]);
644 
645   EXPECT_EQ(cricket::kDataMaxBandwidth,
646             dcd->bandwidth());                  // default bandwidth (auto)
647   EXPECT_TRUE(dcd->rtcp_mux());                 // rtcp-mux defaults on
648   ASSERT_CRYPTO(dcd, false, 1U, CS_AES_CM_128_HMAC_SHA1_80);
649 
650   // Update the offer. Add a new video track that is not synched to the
651   // other tracks and replace audio track 2 with audio track 3.
652   opts.AddStream(MEDIA_TYPE_VIDEO, kVideoTrack2, kMediaStream2);
653   opts.RemoveStream(MEDIA_TYPE_AUDIO, kAudioTrack2);
654   opts.AddStream(MEDIA_TYPE_AUDIO, kAudioTrack3, kMediaStream1);
655   opts.RemoveStream(MEDIA_TYPE_DATA, kDataTrack2);
656   opts.AddStream(MEDIA_TYPE_DATA, kDataTrack3, kMediaStream1);
657   talk_base::scoped_ptr<SessionDescription>
658       updated_offer(f1_.CreateOffer(opts, offer.get()));
659 
660   ASSERT_TRUE(updated_offer.get() != NULL);
661   ac = updated_offer->GetContentByName("audio");
662   vc = updated_offer->GetContentByName("video");
663   dc = updated_offer->GetContentByName("data");
664   ASSERT_TRUE(ac != NULL);
665   ASSERT_TRUE(vc != NULL);
666   ASSERT_TRUE(dc != NULL);
667   const AudioContentDescription* updated_acd =
668       static_cast<const AudioContentDescription*>(ac->description);
669   const VideoContentDescription* updated_vcd =
670       static_cast<const VideoContentDescription*>(vc->description);
671   const DataContentDescription* updated_dcd =
672       static_cast<const DataContentDescription*>(dc->description);
673 
674   EXPECT_EQ(acd->type(), updated_acd->type());
675   EXPECT_EQ(acd->codecs(), updated_acd->codecs());
676   EXPECT_EQ(vcd->type(), updated_vcd->type());
677   EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
678   EXPECT_EQ(dcd->type(), updated_dcd->type());
679   EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
680   ASSERT_CRYPTO(updated_acd, false, 2U, CS_AES_CM_128_HMAC_SHA1_32);
681   EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
682   ASSERT_CRYPTO(updated_vcd, false, 1U, CS_AES_CM_128_HMAC_SHA1_80);
683   EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
684   ASSERT_CRYPTO(updated_dcd, false, 1U, CS_AES_CM_128_HMAC_SHA1_80);
685   EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
686 
687   const StreamParamsVec& updated_audio_streams = updated_acd->streams();
688   ASSERT_EQ(2U, updated_audio_streams.size());
689   EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
690   EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].name);  // New audio track.
691   ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
692   EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
693   EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
694 
695   const StreamParamsVec& updated_video_streams = updated_vcd->streams();
696   ASSERT_EQ(2U, updated_video_streams.size());
697   EXPECT_EQ(video_streams[0], updated_video_streams[0]);
698   EXPECT_EQ(kVideoTrack2, updated_video_streams[1].name);
699   EXPECT_NE(updated_video_streams[1].cname, updated_video_streams[0].cname);
700 
701   const StreamParamsVec& updated_data_streams = updated_dcd->streams();
702   ASSERT_EQ(2U, updated_data_streams.size());
703   EXPECT_EQ(data_streams[0], updated_data_streams[0]);
704   EXPECT_EQ(kDataTrack3, updated_data_streams[1].name);  // New data track.
705   ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
706   EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
707   EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
708 }
709 
710 // Create an audio and video answer to a standard video offer with:
711 // - one video track
712 // - two audio tracks
713 // - two data tracks
714 // and ensure it matches what we expect. Also updates the initial answer by
715 // adding a new video track and removes one of the audio tracks.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateMultiStreamVideoAnswer)716 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
717   MediaSessionOptions offer_opts;
718   offer_opts.has_video = true;
719   offer_opts.has_data = true;
720   f1_.set_secure(SEC_ENABLED);
721   f2_.set_secure(SEC_ENABLED);
722   talk_base::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(offer_opts,
723                                                                   NULL));
724 
725   MediaSessionOptions opts;
726   opts.AddStream(MEDIA_TYPE_VIDEO, kVideoTrack1, kMediaStream1);
727   opts.AddStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
728   opts.AddStream(MEDIA_TYPE_AUDIO, kAudioTrack2, kMediaStream1);
729   opts.AddStream(MEDIA_TYPE_DATA, kDataTrack1, kMediaStream1);
730   opts.AddStream(MEDIA_TYPE_DATA, kDataTrack2, kMediaStream1);
731 
732   talk_base::scoped_ptr<SessionDescription>
733       answer(f2_.CreateAnswer(offer.get(), opts, NULL));
734 
735   ASSERT_TRUE(answer.get() != NULL);
736   const ContentInfo* ac = answer->GetContentByName("audio");
737   const ContentInfo* vc = answer->GetContentByName("video");
738   const ContentInfo* dc = answer->GetContentByName("data");
739   ASSERT_TRUE(ac != NULL);
740   ASSERT_TRUE(vc != NULL);
741   ASSERT_TRUE(dc != NULL);
742   const AudioContentDescription* acd =
743       static_cast<const AudioContentDescription*>(ac->description);
744   const VideoContentDescription* vcd =
745       static_cast<const VideoContentDescription*>(vc->description);
746   const DataContentDescription* dcd =
747       static_cast<const DataContentDescription*>(dc->description);
748   ASSERT_CRYPTO(acd, false, 1U, CS_AES_CM_128_HMAC_SHA1_32);
749   ASSERT_CRYPTO(vcd, false, 1U, CS_AES_CM_128_HMAC_SHA1_80);
750   ASSERT_CRYPTO(dcd, false, 1U, CS_AES_CM_128_HMAC_SHA1_80);
751 
752   EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
753   EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
754 
755   const StreamParamsVec& audio_streams = acd->streams();
756   ASSERT_EQ(2U, audio_streams.size());
757   EXPECT_TRUE(audio_streams[0].cname ==  audio_streams[1].cname);
758   EXPECT_EQ(kAudioTrack1, audio_streams[0].name);
759   ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
760   EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
761   EXPECT_EQ(kAudioTrack2, audio_streams[1].name);
762   ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
763   EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
764 
765   EXPECT_EQ(kAutoBandwidth, acd->bandwidth());  // default bandwidth (auto)
766   EXPECT_TRUE(acd->rtcp_mux());                 // rtcp-mux defaults on
767 
768   EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
769   EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
770 
771   const StreamParamsVec& video_streams = vcd->streams();
772   ASSERT_EQ(1U, video_streams.size());
773   EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
774   EXPECT_EQ(kVideoTrack1, video_streams[0].name);
775   EXPECT_EQ(kAutoBandwidth, vcd->bandwidth());  // default bandwidth (auto)
776   EXPECT_TRUE(vcd->rtcp_mux());                 // rtcp-mux defaults on
777 
778   EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
779   EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
780 
781   const StreamParamsVec& data_streams = dcd->streams();
782   ASSERT_EQ(2U, data_streams.size());
783   EXPECT_TRUE(data_streams[0].cname ==  data_streams[1].cname);
784   EXPECT_EQ(kDataTrack1, data_streams[0].name);
785   ASSERT_EQ(1U, data_streams[0].ssrcs.size());
786   EXPECT_NE(0U, data_streams[0].ssrcs[0]);
787   EXPECT_EQ(kDataTrack2, data_streams[1].name);
788   ASSERT_EQ(1U, data_streams[1].ssrcs.size());
789   EXPECT_NE(0U, data_streams[1].ssrcs[0]);
790 
791   EXPECT_EQ(cricket::kDataMaxBandwidth,
792             dcd->bandwidth());                  // default bandwidth (auto)
793   EXPECT_TRUE(dcd->rtcp_mux());                 // rtcp-mux defaults on
794 
795   // Update the answer. Add a new video track that is not synched to the
796   // other traacks and remove 1 audio track.
797   opts.AddStream(MEDIA_TYPE_VIDEO, kVideoTrack2, kMediaStream2);
798   opts.RemoveStream(MEDIA_TYPE_AUDIO, kAudioTrack2);
799   opts.RemoveStream(MEDIA_TYPE_DATA, kDataTrack2);
800   talk_base::scoped_ptr<SessionDescription>
801       updated_answer(f2_.CreateAnswer(offer.get(), opts, answer.get()));
802 
803   ASSERT_TRUE(updated_answer.get() != NULL);
804   ac = updated_answer->GetContentByName("audio");
805   vc = updated_answer->GetContentByName("video");
806   dc = updated_answer->GetContentByName("data");
807   ASSERT_TRUE(ac != NULL);
808   ASSERT_TRUE(vc != NULL);
809   ASSERT_TRUE(dc != NULL);
810   const AudioContentDescription* updated_acd =
811       static_cast<const AudioContentDescription*>(ac->description);
812   const VideoContentDescription* updated_vcd =
813       static_cast<const VideoContentDescription*>(vc->description);
814   const DataContentDescription* updated_dcd =
815       static_cast<const DataContentDescription*>(dc->description);
816 
817   ASSERT_CRYPTO(updated_acd, false, 1U, CS_AES_CM_128_HMAC_SHA1_32);
818   EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
819   ASSERT_CRYPTO(updated_vcd, false, 1U, CS_AES_CM_128_HMAC_SHA1_80);
820   EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
821   ASSERT_CRYPTO(updated_dcd, false, 1U, CS_AES_CM_128_HMAC_SHA1_80);
822   EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
823 
824   EXPECT_EQ(acd->type(), updated_acd->type());
825   EXPECT_EQ(acd->codecs(), updated_acd->codecs());
826   EXPECT_EQ(vcd->type(), updated_vcd->type());
827   EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
828   EXPECT_EQ(dcd->type(), updated_dcd->type());
829   EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
830 
831   const StreamParamsVec& updated_audio_streams = updated_acd->streams();
832   ASSERT_EQ(1U, updated_audio_streams.size());
833   EXPECT_TRUE(audio_streams[0] ==  updated_audio_streams[0]);
834 
835   const StreamParamsVec& updated_video_streams = updated_vcd->streams();
836   ASSERT_EQ(2U, updated_video_streams.size());
837   EXPECT_EQ(video_streams[0], updated_video_streams[0]);
838   EXPECT_EQ(kVideoTrack2, updated_video_streams[1].name);
839   EXPECT_NE(updated_video_streams[1].cname, updated_video_streams[0].cname);
840 
841   const StreamParamsVec& updated_data_streams = updated_dcd->streams();
842   ASSERT_EQ(1U, updated_data_streams.size());
843   EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
844 }
845 
TEST(MediaSessionDescription,CopySessionDescription)846 TEST(MediaSessionDescription, CopySessionDescription) {
847   SessionDescription source;
848   cricket::ContentGroup group(cricket::CN_AUDIO);
849   source.AddGroup(group);
850   AudioContentDescription* acd(new AudioContentDescription());
851   acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
852   acd->AddLegacyStream(1);
853   source.AddContent(cricket::CN_AUDIO, cricket::NS_JINGLE_RTP, acd);
854   VideoContentDescription* vcd(new VideoContentDescription());
855   vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
856   vcd->AddLegacyStream(2);
857   source.AddContent(cricket::CN_VIDEO, cricket::NS_JINGLE_RTP, vcd);
858 
859   talk_base::scoped_ptr<SessionDescription> copy(source.Copy());
860   ASSERT_TRUE(copy.get() != NULL);
861   EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
862   const ContentInfo* ac = copy->GetContentByName("audio");
863   const ContentInfo* vc = copy->GetContentByName("video");
864   ASSERT_TRUE(ac != NULL);
865   ASSERT_TRUE(vc != NULL);
866   EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
867   const AudioContentDescription* acd_copy =
868       static_cast<const AudioContentDescription*>(ac->description);
869   EXPECT_EQ(acd->codecs(), acd_copy->codecs());
870   EXPECT_EQ(1u, acd->first_ssrc());
871 
872   EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
873   const VideoContentDescription* vcd_copy =
874       static_cast<const VideoContentDescription*>(vc->description);
875   EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
876   EXPECT_EQ(2u, vcd->first_ssrc());
877 }
878