1 /*
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/media/base/codec.h"
32 #include "talk/media/base/testutils.h"
33 #include "webrtc/p2p/base/constants.h"
34 #include "webrtc/p2p/base/transportdescription.h"
35 #include "webrtc/p2p/base/transportinfo.h"
36 #include "talk/session/media/mediasession.h"
37 #include "talk/session/media/srtpfilter.h"
38 #include "webrtc/base/fakesslidentity.h"
39 #include "webrtc/base/gunit.h"
40 #include "webrtc/base/messagedigest.h"
41 #include "webrtc/base/ssladapter.h"
42 
43 #ifdef HAVE_SRTP
44 #define ASSERT_CRYPTO(cd, s, cs) \
45     ASSERT_EQ(cricket::CT_NONE, cd->crypto_required()); \
46     ASSERT_EQ(s, cd->cryptos().size()); \
47     ASSERT_EQ(std::string(cs), cd->cryptos()[0].cipher_suite)
48 #else
49 #define ASSERT_CRYPTO(cd, s, cs) \
50   ASSERT_EQ(cricket::CT_NONE, cd->crypto_required()); \
51   ASSERT_EQ(0U, cd->cryptos().size());
52 #endif
53 
54 typedef std::vector<cricket::Candidate> Candidates;
55 
56 using cricket::MediaContentDescription;
57 using cricket::MediaSessionDescriptionFactory;
58 using cricket::MediaSessionOptions;
59 using cricket::MediaType;
60 using cricket::SessionDescription;
61 using cricket::SsrcGroup;
62 using cricket::StreamParams;
63 using cricket::StreamParamsVec;
64 using cricket::TransportDescription;
65 using cricket::TransportDescriptionFactory;
66 using cricket::TransportInfo;
67 using cricket::ContentInfo;
68 using cricket::CryptoParamsVec;
69 using cricket::AudioContentDescription;
70 using cricket::VideoContentDescription;
71 using cricket::DataContentDescription;
72 using cricket::GetFirstAudioContent;
73 using cricket::GetFirstVideoContent;
74 using cricket::GetFirstDataContent;
75 using cricket::GetFirstAudioContentDescription;
76 using cricket::GetFirstVideoContentDescription;
77 using cricket::GetFirstDataContentDescription;
78 using cricket::kAutoBandwidth;
79 using cricket::AudioCodec;
80 using cricket::VideoCodec;
81 using cricket::DataCodec;
82 using cricket::NS_JINGLE_RTP;
83 using cricket::MEDIA_TYPE_AUDIO;
84 using cricket::MEDIA_TYPE_VIDEO;
85 using cricket::MEDIA_TYPE_DATA;
86 using cricket::RtpHeaderExtension;
87 using cricket::SEC_DISABLED;
88 using cricket::SEC_ENABLED;
89 using cricket::SEC_REQUIRED;
90 using rtc::CS_AES_CM_128_HMAC_SHA1_32;
91 using rtc::CS_AES_CM_128_HMAC_SHA1_80;
92 
93 static const AudioCodec kAudioCodecs1[] = {
94   AudioCodec(103, "ISAC",   16000, -1,    1, 6),
95   AudioCodec(102, "iLBC",   8000,  13300, 1, 5),
96   AudioCodec(0,   "PCMU",   8000,  64000, 1, 4),
97   AudioCodec(8,   "PCMA",   8000,  64000, 1, 3),
98   AudioCodec(117, "red",    8000,  0,     1, 2),
99   AudioCodec(107, "CN",     48000, 0,     1, 1)
100 };
101 
102 static const AudioCodec kAudioCodecs2[] = {
103   AudioCodec(126, "speex",  16000, 22000, 1, 3),
104   AudioCodec(0,   "PCMU",   8000,  64000, 1, 2),
105   AudioCodec(127, "iLBC",   8000,  13300, 1, 1),
106 };
107 
108 static const AudioCodec kAudioCodecsAnswer[] = {
109   AudioCodec(102, "iLBC",   8000,  13300, 1, 5),
110   AudioCodec(0,   "PCMU",   8000,  64000, 1, 4),
111 };
112 
113 static const VideoCodec kVideoCodecs1[] = {
114   VideoCodec(96, "H264-SVC", 320, 200, 30, 2),
115   VideoCodec(97, "H264", 320, 200, 30, 1)
116 };
117 
118 static const VideoCodec kVideoCodecs2[] = {
119   VideoCodec(126, "H264", 320, 200, 30, 2),
120   VideoCodec(127, "H263", 320, 200, 30, 1)
121 };
122 
123 static const VideoCodec kVideoCodecsAnswer[] = {
124   VideoCodec(97, "H264", 320, 200, 30, 1)
125 };
126 
127 static const DataCodec kDataCodecs1[] = {
128   DataCodec(98, "binary-data", 2),
129   DataCodec(99, "utf8-text", 1)
130 };
131 
132 static const DataCodec kDataCodecs2[] = {
133   DataCodec(126, "binary-data", 2),
134   DataCodec(127, "utf8-text", 1)
135 };
136 
137 static const DataCodec kDataCodecsAnswer[] = {
138   DataCodec(98, "binary-data", 2),
139   DataCodec(99, "utf8-text", 1)
140 };
141 
142 static const RtpHeaderExtension kAudioRtpExtension1[] = {
143   RtpHeaderExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
144   RtpHeaderExtension("http://google.com/testing/audio_something", 10),
145 };
146 
147 static const RtpHeaderExtension kAudioRtpExtension2[] = {
148   RtpHeaderExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
149   RtpHeaderExtension("http://google.com/testing/audio_something_else", 8),
150   RtpHeaderExtension("http://google.com/testing/both_audio_and_video", 7),
151 };
152 
153 static const RtpHeaderExtension kAudioRtpExtension3[] = {
154   RtpHeaderExtension("http://google.com/testing/audio_something", 2),
155   RtpHeaderExtension("http://google.com/testing/both_audio_and_video", 3),
156 };
157 
158 static const RtpHeaderExtension kAudioRtpExtensionAnswer[] = {
159   RtpHeaderExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
160 };
161 
162 static const RtpHeaderExtension kVideoRtpExtension1[] = {
163   RtpHeaderExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
164   RtpHeaderExtension("http://google.com/testing/video_something", 13),
165 };
166 
167 static const RtpHeaderExtension kVideoRtpExtension2[] = {
168   RtpHeaderExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
169   RtpHeaderExtension("http://google.com/testing/video_something_else", 14),
170   RtpHeaderExtension("http://google.com/testing/both_audio_and_video", 7),
171 };
172 
173 static const RtpHeaderExtension kVideoRtpExtension3[] = {
174   RtpHeaderExtension("http://google.com/testing/video_something", 4),
175   RtpHeaderExtension("http://google.com/testing/both_audio_and_video", 5),
176 };
177 
178 static const RtpHeaderExtension kVideoRtpExtensionAnswer[] = {
179   RtpHeaderExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
180 };
181 
182 static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
183 static const uint32_t kSimSsrc[] = {10, 20, 30};
184 static const uint32_t kFec1Ssrc[] = {10, 11};
185 static const uint32_t kFec2Ssrc[] = {20, 21};
186 static const uint32_t kFec3Ssrc[] = {30, 31};
187 
188 static const char kMediaStream1[] = "stream_1";
189 static const char kMediaStream2[] = "stream_2";
190 static const char kVideoTrack1[] = "video_1";
191 static const char kVideoTrack2[] = "video_2";
192 static const char kAudioTrack1[] = "audio_1";
193 static const char kAudioTrack2[] = "audio_2";
194 static const char kAudioTrack3[] = "audio_3";
195 static const char kDataTrack1[] = "data_1";
196 static const char kDataTrack2[] = "data_2";
197 static const char kDataTrack3[] = "data_3";
198 
IsMediaContentOfType(const ContentInfo * content,MediaType media_type)199 static bool IsMediaContentOfType(const ContentInfo* content,
200                                  MediaType media_type) {
201   const MediaContentDescription* mdesc =
202       static_cast<const MediaContentDescription*>(content->description);
203   return mdesc && mdesc->type() == media_type;
204 }
205 
206 static cricket::MediaContentDirection
GetMediaDirection(const ContentInfo * content)207 GetMediaDirection(const ContentInfo* content) {
208   cricket::MediaContentDescription* desc =
209       reinterpret_cast<cricket::MediaContentDescription*>(content->description);
210   return desc->direction();
211 }
212 
AddRtxCodec(const VideoCodec & rtx_codec,std::vector<VideoCodec> * codecs)213 static void AddRtxCodec(const VideoCodec& rtx_codec,
214                         std::vector<VideoCodec>* codecs) {
215   VideoCodec rtx;
216   ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id, &rtx));
217   codecs->push_back(rtx_codec);
218 }
219 
220 template <class T>
GetCodecNames(const std::vector<T> & codecs)221 static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
222   std::vector<std::string> codec_names;
223   for (const auto& codec : codecs) {
224     codec_names.push_back(codec.name);
225   }
226   return codec_names;
227 }
228 
229 class MediaSessionDescriptionFactoryTest : public testing::Test {
230  public:
MediaSessionDescriptionFactoryTest()231   MediaSessionDescriptionFactoryTest()
232       : f1_(&tdf1_),
233         f2_(&tdf2_) {
234     f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1));
235     f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
236     f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
237     f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2));
238     f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
239     f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
240     tdf1_.set_certificate(rtc::RTCCertificate::Create(
241         rtc::scoped_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
242     tdf2_.set_certificate(rtc::RTCCertificate::Create(
243         rtc::scoped_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
244   }
245 
246   // Create a video StreamParamsVec object with:
247   // - one video stream with 3 simulcast streams and FEC,
CreateComplexVideoStreamParamsVec()248   StreamParamsVec CreateComplexVideoStreamParamsVec() {
249     SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
250     SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
251     SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
252     SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
253 
254     std::vector<SsrcGroup> ssrc_groups;
255     ssrc_groups.push_back(sim_group);
256     ssrc_groups.push_back(fec_group1);
257     ssrc_groups.push_back(fec_group2);
258     ssrc_groups.push_back(fec_group3);
259 
260     StreamParams simulcast_params;
261     simulcast_params.id = kVideoTrack1;
262     simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
263     simulcast_params.ssrc_groups = ssrc_groups;
264     simulcast_params.cname = "Video_SIM_FEC";
265     simulcast_params.sync_label = kMediaStream1;
266 
267     StreamParamsVec video_streams;
268     video_streams.push_back(simulcast_params);
269 
270     return video_streams;
271   }
272 
CompareCryptoParams(const CryptoParamsVec & c1,const CryptoParamsVec & c2)273   bool CompareCryptoParams(const CryptoParamsVec& c1,
274                            const CryptoParamsVec& c2) {
275     if (c1.size() != c2.size())
276       return false;
277     for (size_t i = 0; i < c1.size(); ++i)
278       if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
279           c1[i].key_params != c2[i].key_params ||
280           c1[i].session_params != c2[i].session_params)
281         return false;
282     return true;
283   }
284 
TestTransportInfo(bool offer,const MediaSessionOptions & options,bool has_current_desc)285   void TestTransportInfo(bool offer, const MediaSessionOptions& options,
286                          bool has_current_desc) {
287     const std::string current_audio_ufrag = "current_audio_ufrag";
288     const std::string current_audio_pwd = "current_audio_pwd";
289     const std::string current_video_ufrag = "current_video_ufrag";
290     const std::string current_video_pwd = "current_video_pwd";
291     const std::string current_data_ufrag = "current_data_ufrag";
292     const std::string current_data_pwd = "current_data_pwd";
293     rtc::scoped_ptr<SessionDescription> current_desc;
294     rtc::scoped_ptr<SessionDescription> desc;
295     if (has_current_desc) {
296       current_desc.reset(new SessionDescription());
297       EXPECT_TRUE(current_desc->AddTransportInfo(
298           TransportInfo("audio",
299                         TransportDescription(current_audio_ufrag,
300                                              current_audio_pwd))));
301       EXPECT_TRUE(current_desc->AddTransportInfo(
302           TransportInfo("video",
303                         TransportDescription(current_video_ufrag,
304                                              current_video_pwd))));
305       EXPECT_TRUE(current_desc->AddTransportInfo(
306           TransportInfo("data",
307                         TransportDescription(current_data_ufrag,
308                                              current_data_pwd))));
309     }
310     if (offer) {
311       desc.reset(f1_.CreateOffer(options, current_desc.get()));
312     } else {
313       rtc::scoped_ptr<SessionDescription> offer;
314       offer.reset(f1_.CreateOffer(options, NULL));
315       desc.reset(f1_.CreateAnswer(offer.get(), options, current_desc.get()));
316     }
317     ASSERT_TRUE(desc.get() != NULL);
318     const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
319     if (options.has_audio()) {
320       EXPECT_TRUE(ti_audio != NULL);
321       if (has_current_desc) {
322         EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
323         EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
324       } else {
325         EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
326                   ti_audio->description.ice_ufrag.size());
327         EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
328                   ti_audio->description.ice_pwd.size());
329       }
330 
331     } else {
332       EXPECT_TRUE(ti_audio == NULL);
333     }
334     const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
335     if (options.has_video()) {
336       EXPECT_TRUE(ti_video != NULL);
337       if (options.bundle_enabled) {
338         EXPECT_EQ(ti_audio->description.ice_ufrag,
339                   ti_video->description.ice_ufrag);
340         EXPECT_EQ(ti_audio->description.ice_pwd,
341                   ti_video->description.ice_pwd);
342       } else {
343         if (has_current_desc) {
344           EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
345           EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
346         } else {
347           EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
348                     ti_video->description.ice_ufrag.size());
349           EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
350                     ti_video->description.ice_pwd.size());
351         }
352       }
353     } else {
354       EXPECT_TRUE(ti_video == NULL);
355     }
356     const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
357     if (options.has_data()) {
358       EXPECT_TRUE(ti_data != NULL);
359       if (options.bundle_enabled) {
360         EXPECT_EQ(ti_audio->description.ice_ufrag,
361                   ti_data->description.ice_ufrag);
362         EXPECT_EQ(ti_audio->description.ice_pwd,
363                   ti_data->description.ice_pwd);
364       } else {
365         if (has_current_desc) {
366           EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
367           EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
368         } else {
369           EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
370                     ti_data->description.ice_ufrag.size());
371           EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
372                     ti_data->description.ice_pwd.size());
373         }
374       }
375     } else {
376       EXPECT_TRUE(ti_video == NULL);
377     }
378   }
379 
TestCryptoWithBundle(bool offer)380   void TestCryptoWithBundle(bool offer) {
381     f1_.set_secure(SEC_ENABLED);
382     MediaSessionOptions options;
383     options.recv_audio = true;
384     options.recv_video = true;
385     options.data_channel_type = cricket::DCT_RTP;
386     rtc::scoped_ptr<SessionDescription> ref_desc;
387     rtc::scoped_ptr<SessionDescription> desc;
388     if (offer) {
389       options.bundle_enabled = false;
390       ref_desc.reset(f1_.CreateOffer(options, NULL));
391       options.bundle_enabled = true;
392       desc.reset(f1_.CreateOffer(options, ref_desc.get()));
393     } else {
394       options.bundle_enabled = true;
395       ref_desc.reset(f1_.CreateOffer(options, NULL));
396       desc.reset(f1_.CreateAnswer(ref_desc.get(), options, NULL));
397     }
398     ASSERT_TRUE(desc.get() != NULL);
399     const cricket::MediaContentDescription* audio_media_desc =
400         static_cast<const cricket::MediaContentDescription*>(
401             desc.get()->GetContentDescriptionByName("audio"));
402     ASSERT_TRUE(audio_media_desc != NULL);
403     const cricket::MediaContentDescription* video_media_desc =
404         static_cast<const cricket::MediaContentDescription*>(
405             desc.get()->GetContentDescriptionByName("video"));
406     ASSERT_TRUE(video_media_desc != NULL);
407     EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
408                                     video_media_desc->cryptos()));
409     EXPECT_EQ(1u, audio_media_desc->cryptos().size());
410     EXPECT_EQ(std::string(CS_AES_CM_128_HMAC_SHA1_80),
411               audio_media_desc->cryptos()[0].cipher_suite);
412 
413     // Verify the selected crypto is one from the reference audio
414     // media content.
415     const cricket::MediaContentDescription* ref_audio_media_desc =
416         static_cast<const cricket::MediaContentDescription*>(
417             ref_desc.get()->GetContentDescriptionByName("audio"));
418     bool found = false;
419     for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
420       if (ref_audio_media_desc->cryptos()[i].Matches(
421           audio_media_desc->cryptos()[0])) {
422         found = true;
423         break;
424       }
425     }
426     EXPECT_TRUE(found);
427   }
428 
429   // This test that the audio and video media direction is set to
430   // |expected_direction_in_answer| in an answer if the offer direction is set
431   // to |direction_in_offer|.
TestMediaDirectionInAnswer(cricket::MediaContentDirection direction_in_offer,cricket::MediaContentDirection expected_direction_in_answer)432   void TestMediaDirectionInAnswer(
433       cricket::MediaContentDirection direction_in_offer,
434       cricket::MediaContentDirection expected_direction_in_answer) {
435     MediaSessionOptions opts;
436     opts.recv_video = true;
437     rtc::scoped_ptr<SessionDescription> offer(
438         f1_.CreateOffer(opts, NULL));
439     ASSERT_TRUE(offer.get() != NULL);
440     ContentInfo* ac_offer= offer->GetContentByName("audio");
441     ASSERT_TRUE(ac_offer != NULL);
442     AudioContentDescription* acd_offer =
443         static_cast<AudioContentDescription*>(ac_offer->description);
444     acd_offer->set_direction(direction_in_offer);
445     ContentInfo* vc_offer= offer->GetContentByName("video");
446     ASSERT_TRUE(vc_offer != NULL);
447     VideoContentDescription* vcd_offer =
448         static_cast<VideoContentDescription*>(vc_offer->description);
449     vcd_offer->set_direction(direction_in_offer);
450 
451     rtc::scoped_ptr<SessionDescription> answer(
452         f2_.CreateAnswer(offer.get(), opts, NULL));
453     const AudioContentDescription* acd_answer =
454         GetFirstAudioContentDescription(answer.get());
455     EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
456     const VideoContentDescription* vcd_answer =
457         GetFirstVideoContentDescription(answer.get());
458     EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
459   }
460 
VerifyNoCNCodecs(const cricket::ContentInfo * content)461   bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
462     const cricket::ContentDescription* description = content->description;
463     ASSERT(description != NULL);
464     const cricket::AudioContentDescription* audio_content_desc =
465         static_cast<const cricket::AudioContentDescription*>(description);
466     ASSERT(audio_content_desc != NULL);
467     for (size_t i = 0; i < audio_content_desc->codecs().size(); ++i) {
468       if (audio_content_desc->codecs()[i].name == "CN")
469         return false;
470     }
471     return true;
472   }
473 
474  protected:
475   MediaSessionDescriptionFactory f1_;
476   MediaSessionDescriptionFactory f2_;
477   TransportDescriptionFactory tdf1_;
478   TransportDescriptionFactory tdf2_;
479 };
480 
481 // Create a typical audio offer, and ensure it matches what we expect.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateAudioOffer)482 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
483   f1_.set_secure(SEC_ENABLED);
484   rtc::scoped_ptr<SessionDescription> offer(
485       f1_.CreateOffer(MediaSessionOptions(), NULL));
486   ASSERT_TRUE(offer.get() != NULL);
487   const ContentInfo* ac = offer->GetContentByName("audio");
488   const ContentInfo* vc = offer->GetContentByName("video");
489   ASSERT_TRUE(ac != NULL);
490   ASSERT_TRUE(vc == NULL);
491   EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
492   const AudioContentDescription* acd =
493       static_cast<const AudioContentDescription*>(ac->description);
494   EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
495   EXPECT_EQ(f1_.audio_codecs(), acd->codecs());
496   EXPECT_NE(0U, acd->first_ssrc());             // a random nonzero ssrc
497   EXPECT_EQ(kAutoBandwidth, acd->bandwidth());  // default bandwidth (auto)
498   EXPECT_TRUE(acd->rtcp_mux());                 // rtcp-mux defaults on
499   ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
500   EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
501 }
502 
503 // Create a typical video offer, and ensure it matches what we expect.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateVideoOffer)504 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
505   MediaSessionOptions opts;
506   opts.recv_video = true;
507   f1_.set_secure(SEC_ENABLED);
508   rtc::scoped_ptr<SessionDescription>
509       offer(f1_.CreateOffer(opts, NULL));
510   ASSERT_TRUE(offer.get() != NULL);
511   const ContentInfo* ac = offer->GetContentByName("audio");
512   const ContentInfo* vc = offer->GetContentByName("video");
513   ASSERT_TRUE(ac != NULL);
514   ASSERT_TRUE(vc != NULL);
515   EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
516   EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
517   const AudioContentDescription* acd =
518       static_cast<const AudioContentDescription*>(ac->description);
519   const VideoContentDescription* vcd =
520       static_cast<const VideoContentDescription*>(vc->description);
521   EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
522   EXPECT_EQ(f1_.audio_codecs(), acd->codecs());
523   EXPECT_NE(0U, acd->first_ssrc());             // a random nonzero ssrc
524   EXPECT_EQ(kAutoBandwidth, acd->bandwidth());  // default bandwidth (auto)
525   EXPECT_TRUE(acd->rtcp_mux());                 // rtcp-mux defaults on
526   ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
527   EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
528   EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
529   EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
530   EXPECT_NE(0U, vcd->first_ssrc());             // a random nonzero ssrc
531   EXPECT_EQ(kAutoBandwidth, vcd->bandwidth());  // default bandwidth (auto)
532   EXPECT_TRUE(vcd->rtcp_mux());                 // rtcp-mux defaults on
533   ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
534   EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
535 }
536 
537 // Test creating an offer with bundle where the Codecs have the same dynamic
538 // RTP playlod type. The test verifies that the offer don't contain the
539 // duplicate RTP payload types.
TEST_F(MediaSessionDescriptionFactoryTest,TestBundleOfferWithSameCodecPlType)540 TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
541   const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
542   const AudioCodec& offered_audio_codec = f2_.audio_codecs()[0];
543   const DataCodec& offered_data_codec = f2_.data_codecs()[0];
544   ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
545   ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
546 
547   MediaSessionOptions opts;
548   opts.recv_audio = true;
549   opts.recv_video = true;
550   opts.data_channel_type = cricket::DCT_RTP;
551   opts.bundle_enabled = true;
552   rtc::scoped_ptr<SessionDescription>
553   offer(f2_.CreateOffer(opts, NULL));
554   const VideoContentDescription* vcd =
555       GetFirstVideoContentDescription(offer.get());
556   const AudioContentDescription* acd =
557       GetFirstAudioContentDescription(offer.get());
558   const DataContentDescription* dcd =
559       GetFirstDataContentDescription(offer.get());
560   ASSERT_TRUE(NULL != vcd);
561   ASSERT_TRUE(NULL != acd);
562   ASSERT_TRUE(NULL != dcd);
563   EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
564   EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
565   EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
566   EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
567   EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
568   EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
569 }
570 
571 // Test creating an updated offer with with bundle, audio, video and data
572 // after an audio only session has been negotiated.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateUpdatedVideoOfferWithBundle)573 TEST_F(MediaSessionDescriptionFactoryTest,
574        TestCreateUpdatedVideoOfferWithBundle) {
575   f1_.set_secure(SEC_ENABLED);
576   f2_.set_secure(SEC_ENABLED);
577   MediaSessionOptions opts;
578   opts.recv_audio = true;
579   opts.recv_video = false;
580   opts.data_channel_type = cricket::DCT_NONE;
581   opts.bundle_enabled = true;
582   rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
583   rtc::scoped_ptr<SessionDescription> answer(
584       f2_.CreateAnswer(offer.get(), opts, NULL));
585 
586   MediaSessionOptions updated_opts;
587   updated_opts.recv_audio = true;
588   updated_opts.recv_video = true;
589   updated_opts.data_channel_type = cricket::DCT_RTP;
590   updated_opts.bundle_enabled = true;
591   rtc::scoped_ptr<SessionDescription> updated_offer(f1_.CreateOffer(
592       updated_opts, answer.get()));
593 
594   const AudioContentDescription* acd =
595       GetFirstAudioContentDescription(updated_offer.get());
596   const VideoContentDescription* vcd =
597       GetFirstVideoContentDescription(updated_offer.get());
598   const DataContentDescription* dcd =
599       GetFirstDataContentDescription(updated_offer.get());
600   EXPECT_TRUE(NULL != vcd);
601   EXPECT_TRUE(NULL != acd);
602   EXPECT_TRUE(NULL != dcd);
603 
604   ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
605   EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
606   ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
607   EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
608   ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
609   EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
610 }
611 
612 // Create a RTP data offer, and ensure it matches what we expect.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateRtpDataOffer)613 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
614   MediaSessionOptions opts;
615   opts.data_channel_type = cricket::DCT_RTP;
616   f1_.set_secure(SEC_ENABLED);
617   rtc::scoped_ptr<SessionDescription>
618       offer(f1_.CreateOffer(opts, NULL));
619   ASSERT_TRUE(offer.get() != NULL);
620   const ContentInfo* ac = offer->GetContentByName("audio");
621   const ContentInfo* dc = offer->GetContentByName("data");
622   ASSERT_TRUE(ac != NULL);
623   ASSERT_TRUE(dc != NULL);
624   EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
625   EXPECT_EQ(std::string(NS_JINGLE_RTP), dc->type);
626   const AudioContentDescription* acd =
627       static_cast<const AudioContentDescription*>(ac->description);
628   const DataContentDescription* dcd =
629       static_cast<const DataContentDescription*>(dc->description);
630   EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
631   EXPECT_EQ(f1_.audio_codecs(), acd->codecs());
632   EXPECT_NE(0U, acd->first_ssrc());             // a random nonzero ssrc
633   EXPECT_EQ(kAutoBandwidth, acd->bandwidth());  // default bandwidth (auto)
634   EXPECT_TRUE(acd->rtcp_mux());                 // rtcp-mux defaults on
635   ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
636   EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
637   EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
638   EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
639   EXPECT_NE(0U, dcd->first_ssrc());             // a random nonzero ssrc
640   EXPECT_EQ(cricket::kDataMaxBandwidth,
641             dcd->bandwidth());                  // default bandwidth (auto)
642   EXPECT_TRUE(dcd->rtcp_mux());                 // rtcp-mux defaults on
643   ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
644   EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
645 }
646 
647 // Create an SCTP data offer with bundle without error.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateSctpDataOffer)648 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
649   MediaSessionOptions opts;
650   opts.recv_audio = false;
651   opts.bundle_enabled = true;
652   opts.data_channel_type = cricket::DCT_SCTP;
653   f1_.set_secure(SEC_ENABLED);
654   rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
655   EXPECT_TRUE(offer.get() != NULL);
656   EXPECT_TRUE(offer->GetContentByName("data") != NULL);
657 }
658 
659 // Test creating an sctp data channel from an already generated offer.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateImplicitSctpDataOffer)660 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
661   MediaSessionOptions opts;
662   opts.recv_audio = false;
663   opts.bundle_enabled = true;
664   opts.data_channel_type = cricket::DCT_SCTP;
665   f1_.set_secure(SEC_ENABLED);
666   rtc::scoped_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
667   ASSERT_TRUE(offer1.get() != NULL);
668   const ContentInfo* data = offer1->GetContentByName("data");
669   ASSERT_TRUE(data != NULL);
670   const MediaContentDescription* mdesc =
671       static_cast<const MediaContentDescription*>(data->description);
672   ASSERT_EQ(cricket::kMediaProtocolSctp, mdesc->protocol());
673 
674   // Now set data_channel_type to 'none' (default) and make sure that the
675   // datachannel type that gets generated from the previous offer, is of the
676   // same type.
677   opts.data_channel_type = cricket::DCT_NONE;
678   rtc::scoped_ptr<SessionDescription> offer2(
679       f1_.CreateOffer(opts, offer1.get()));
680   data = offer2->GetContentByName("data");
681   ASSERT_TRUE(data != NULL);
682   mdesc = static_cast<const MediaContentDescription*>(data->description);
683   EXPECT_EQ(cricket::kMediaProtocolSctp, mdesc->protocol());
684 }
685 
686 // Create an audio, video offer without legacy StreamParams.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateOfferWithoutLegacyStreams)687 TEST_F(MediaSessionDescriptionFactoryTest,
688        TestCreateOfferWithoutLegacyStreams) {
689   MediaSessionOptions opts;
690   opts.recv_video = true;
691   f1_.set_add_legacy_streams(false);
692   rtc::scoped_ptr<SessionDescription>
693       offer(f1_.CreateOffer(opts, NULL));
694   ASSERT_TRUE(offer.get() != NULL);
695   const ContentInfo* ac = offer->GetContentByName("audio");
696   const ContentInfo* vc = offer->GetContentByName("video");
697   ASSERT_TRUE(ac != NULL);
698   ASSERT_TRUE(vc != NULL);
699   const AudioContentDescription* acd =
700       static_cast<const AudioContentDescription*>(ac->description);
701   const VideoContentDescription* vcd =
702       static_cast<const VideoContentDescription*>(vc->description);
703 
704   EXPECT_FALSE(vcd->has_ssrcs());             // No StreamParams.
705   EXPECT_FALSE(acd->has_ssrcs());             // No StreamParams.
706 }
707 
708 // Creates an audio+video sendonly offer.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateSendOnlyOffer)709 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
710   MediaSessionOptions options;
711   options.recv_audio = false;
712   options.recv_video = false;
713   options.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack1, kMediaStream1);
714   options.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
715 
716   rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
717   ASSERT_TRUE(offer.get() != NULL);
718   EXPECT_EQ(2u, offer->contents().size());
719   EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
720   EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
721 
722   EXPECT_EQ(cricket::MD_SENDONLY, GetMediaDirection(&offer->contents()[0]));
723   EXPECT_EQ(cricket::MD_SENDONLY, GetMediaDirection(&offer->contents()[1]));
724 }
725 
726 // Verifies that the order of the media contents in the current
727 // SessionDescription is preserved in the new SessionDescription.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateOfferContentOrder)728 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
729   MediaSessionOptions opts;
730   opts.recv_audio = false;
731   opts.recv_video = false;
732   opts.data_channel_type = cricket::DCT_SCTP;
733 
734   rtc::scoped_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
735   ASSERT_TRUE(offer1.get() != NULL);
736   EXPECT_EQ(1u, offer1->contents().size());
737   EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
738 
739   opts.recv_video = true;
740   rtc::scoped_ptr<SessionDescription> offer2(
741       f1_.CreateOffer(opts, offer1.get()));
742   ASSERT_TRUE(offer2.get() != NULL);
743   EXPECT_EQ(2u, offer2->contents().size());
744   EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
745   EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
746 
747   opts.recv_audio = true;
748   rtc::scoped_ptr<SessionDescription> offer3(
749       f1_.CreateOffer(opts, offer2.get()));
750   ASSERT_TRUE(offer3.get() != NULL);
751   EXPECT_EQ(3u, offer3->contents().size());
752   EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
753   EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
754   EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
755 
756   // Verifies the default order is audio-video-data, so that the previous checks
757   // didn't pass by accident.
758   rtc::scoped_ptr<SessionDescription> offer4(f1_.CreateOffer(opts, NULL));
759   ASSERT_TRUE(offer4.get() != NULL);
760   EXPECT_EQ(3u, offer4->contents().size());
761   EXPECT_TRUE(IsMediaContentOfType(&offer4->contents()[0], MEDIA_TYPE_AUDIO));
762   EXPECT_TRUE(IsMediaContentOfType(&offer4->contents()[1], MEDIA_TYPE_VIDEO));
763   EXPECT_TRUE(IsMediaContentOfType(&offer4->contents()[2], MEDIA_TYPE_DATA));
764 }
765 
766 // Create a typical audio answer, and ensure it matches what we expect.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateAudioAnswer)767 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
768   f1_.set_secure(SEC_ENABLED);
769   f2_.set_secure(SEC_ENABLED);
770   rtc::scoped_ptr<SessionDescription> offer(
771       f1_.CreateOffer(MediaSessionOptions(), NULL));
772   ASSERT_TRUE(offer.get() != NULL);
773   rtc::scoped_ptr<SessionDescription> answer(
774       f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
775   const ContentInfo* ac = answer->GetContentByName("audio");
776   const ContentInfo* vc = answer->GetContentByName("video");
777   ASSERT_TRUE(ac != NULL);
778   ASSERT_TRUE(vc == NULL);
779   EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
780   const AudioContentDescription* acd =
781       static_cast<const AudioContentDescription*>(ac->description);
782   EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
783   EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
784   EXPECT_NE(0U, acd->first_ssrc());             // a random nonzero ssrc
785   EXPECT_EQ(kAutoBandwidth, acd->bandwidth());  // negotiated auto bw
786   EXPECT_TRUE(acd->rtcp_mux());                 // negotiated rtcp-mux
787   ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
788   EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
789 }
790 
791 // Create a typical video answer, and ensure it matches what we expect.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateVideoAnswer)792 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
793   MediaSessionOptions opts;
794   opts.recv_video = true;
795   f1_.set_secure(SEC_ENABLED);
796   f2_.set_secure(SEC_ENABLED);
797   rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
798   ASSERT_TRUE(offer.get() != NULL);
799   rtc::scoped_ptr<SessionDescription> answer(
800       f2_.CreateAnswer(offer.get(), opts, NULL));
801   const ContentInfo* ac = answer->GetContentByName("audio");
802   const ContentInfo* vc = answer->GetContentByName("video");
803   ASSERT_TRUE(ac != NULL);
804   ASSERT_TRUE(vc != NULL);
805   EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
806   EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
807   const AudioContentDescription* acd =
808       static_cast<const AudioContentDescription*>(ac->description);
809   const VideoContentDescription* vcd =
810       static_cast<const VideoContentDescription*>(vc->description);
811   EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
812   EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
813   EXPECT_EQ(kAutoBandwidth, acd->bandwidth());  // negotiated auto bw
814   EXPECT_NE(0U, acd->first_ssrc());             // a random nonzero ssrc
815   EXPECT_TRUE(acd->rtcp_mux());                 // negotiated rtcp-mux
816   ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
817   EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
818   EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
819   EXPECT_NE(0U, vcd->first_ssrc());             // a random nonzero ssrc
820   EXPECT_TRUE(vcd->rtcp_mux());                 // negotiated rtcp-mux
821   ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
822   EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
823 }
824 
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateDataAnswer)825 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
826   MediaSessionOptions opts;
827   opts.data_channel_type = cricket::DCT_RTP;
828   f1_.set_secure(SEC_ENABLED);
829   f2_.set_secure(SEC_ENABLED);
830   rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
831   ASSERT_TRUE(offer.get() != NULL);
832   rtc::scoped_ptr<SessionDescription> answer(
833       f2_.CreateAnswer(offer.get(), opts, NULL));
834   const ContentInfo* ac = answer->GetContentByName("audio");
835   const ContentInfo* vc = answer->GetContentByName("data");
836   ASSERT_TRUE(ac != NULL);
837   ASSERT_TRUE(vc != NULL);
838   EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
839   EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
840   const AudioContentDescription* acd =
841       static_cast<const AudioContentDescription*>(ac->description);
842   const DataContentDescription* vcd =
843       static_cast<const DataContentDescription*>(vc->description);
844   EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
845   EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
846   EXPECT_EQ(kAutoBandwidth, acd->bandwidth());  // negotiated auto bw
847   EXPECT_NE(0U, acd->first_ssrc());             // a random nonzero ssrc
848   EXPECT_TRUE(acd->rtcp_mux());                 // negotiated rtcp-mux
849   ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
850   EXPECT_EQ(MEDIA_TYPE_DATA, vcd->type());
851   EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), vcd->codecs());
852   EXPECT_NE(0U, vcd->first_ssrc());             // a random nonzero ssrc
853   EXPECT_TRUE(vcd->rtcp_mux());                 // negotiated rtcp-mux
854   ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
855   EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
856 }
857 
858 // Verifies that the order of the media contents in the offer is preserved in
859 // the answer.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateAnswerContentOrder)860 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
861   MediaSessionOptions opts;
862 
863   // Creates a data only offer.
864   opts.recv_audio = false;
865   opts.data_channel_type = cricket::DCT_SCTP;
866   rtc::scoped_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
867   ASSERT_TRUE(offer1.get() != NULL);
868 
869   // Appends audio to the offer.
870   opts.recv_audio = true;
871   rtc::scoped_ptr<SessionDescription> offer2(
872       f1_.CreateOffer(opts, offer1.get()));
873   ASSERT_TRUE(offer2.get() != NULL);
874 
875   // Appends video to the offer.
876   opts.recv_video = true;
877   rtc::scoped_ptr<SessionDescription> offer3(
878       f1_.CreateOffer(opts, offer2.get()));
879   ASSERT_TRUE(offer3.get() != NULL);
880 
881   rtc::scoped_ptr<SessionDescription> answer(
882       f2_.CreateAnswer(offer3.get(), opts, NULL));
883   ASSERT_TRUE(answer.get() != NULL);
884   EXPECT_EQ(3u, answer->contents().size());
885   EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
886   EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
887   EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
888 }
889 
890 // This test that the media direction is set to send/receive in an answer if
891 // the offer is send receive.
TEST_F(MediaSessionDescriptionFactoryTest,CreateAnswerToSendReceiveOffer)892 TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
893   TestMediaDirectionInAnswer(cricket::MD_SENDRECV, cricket::MD_SENDRECV);
894 }
895 
896 // This test that the media direction is set to receive only in an answer if
897 // the offer is send only.
TEST_F(MediaSessionDescriptionFactoryTest,CreateAnswerToSendOnlyOffer)898 TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
899   TestMediaDirectionInAnswer(cricket::MD_SENDONLY, cricket::MD_RECVONLY);
900 }
901 
902 // This test that the media direction is set to send only in an answer if
903 // the offer is recv only.
TEST_F(MediaSessionDescriptionFactoryTest,CreateAnswerToRecvOnlyOffer)904 TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
905   TestMediaDirectionInAnswer(cricket::MD_RECVONLY, cricket::MD_SENDONLY);
906 }
907 
908 // This test that the media direction is set to inactive in an answer if
909 // the offer is inactive.
TEST_F(MediaSessionDescriptionFactoryTest,CreateAnswerToInactiveOffer)910 TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
911   TestMediaDirectionInAnswer(cricket::MD_INACTIVE, cricket::MD_INACTIVE);
912 }
913 
914 // Test that a data content with an unknown protocol is rejected in an answer.
TEST_F(MediaSessionDescriptionFactoryTest,CreateDataAnswerToOfferWithUnknownProtocol)915 TEST_F(MediaSessionDescriptionFactoryTest,
916        CreateDataAnswerToOfferWithUnknownProtocol) {
917   MediaSessionOptions opts;
918   opts.data_channel_type = cricket::DCT_RTP;
919   opts.recv_audio = false;
920   f1_.set_secure(SEC_ENABLED);
921   f2_.set_secure(SEC_ENABLED);
922   rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
923   ContentInfo* dc_offer= offer->GetContentByName("data");
924   ASSERT_TRUE(dc_offer != NULL);
925   DataContentDescription* dcd_offer =
926       static_cast<DataContentDescription*>(dc_offer->description);
927   ASSERT_TRUE(dcd_offer != NULL);
928   std::string protocol = "a weird unknown protocol";
929   dcd_offer->set_protocol(protocol);
930 
931   rtc::scoped_ptr<SessionDescription> answer(
932       f2_.CreateAnswer(offer.get(), opts, NULL));
933 
934   const ContentInfo* dc_answer = answer->GetContentByName("data");
935   ASSERT_TRUE(dc_answer != NULL);
936   EXPECT_TRUE(dc_answer->rejected);
937   const DataContentDescription* dcd_answer =
938       static_cast<const DataContentDescription*>(dc_answer->description);
939   ASSERT_TRUE(dcd_answer != NULL);
940   EXPECT_EQ(protocol, dcd_answer->protocol());
941 }
942 
943 // Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
TEST_F(MediaSessionDescriptionFactoryTest,AudioOfferAnswerWithCryptoDisabled)944 TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
945   MediaSessionOptions opts;
946   f1_.set_secure(SEC_DISABLED);
947   f2_.set_secure(SEC_DISABLED);
948   tdf1_.set_secure(SEC_DISABLED);
949   tdf2_.set_secure(SEC_DISABLED);
950 
951   rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
952   const AudioContentDescription* offer_acd =
953       GetFirstAudioContentDescription(offer.get());
954   ASSERT_TRUE(offer_acd != NULL);
955   EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), offer_acd->protocol());
956 
957   rtc::scoped_ptr<SessionDescription> answer(
958       f2_.CreateAnswer(offer.get(), opts, NULL));
959 
960   const ContentInfo* ac_answer = answer->GetContentByName("audio");
961   ASSERT_TRUE(ac_answer != NULL);
962   EXPECT_FALSE(ac_answer->rejected);
963 
964   const AudioContentDescription* answer_acd =
965       GetFirstAudioContentDescription(answer.get());
966   ASSERT_TRUE(answer_acd != NULL);
967   EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), answer_acd->protocol());
968 }
969 
970 // Create a video offer and answer and ensure the RTP header extensions
971 // matches what we expect.
TEST_F(MediaSessionDescriptionFactoryTest,TestOfferAnswerWithRtpExtensions)972 TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
973   MediaSessionOptions opts;
974   opts.recv_video = true;
975 
976   f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
977   f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
978   f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
979   f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
980 
981   rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
982   ASSERT_TRUE(offer.get() != NULL);
983   rtc::scoped_ptr<SessionDescription> answer(
984       f2_.CreateAnswer(offer.get(), opts, NULL));
985 
986   EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension1),
987             GetFirstAudioContentDescription(
988                 offer.get())->rtp_header_extensions());
989   EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtension1),
990             GetFirstVideoContentDescription(
991                 offer.get())->rtp_header_extensions());
992   EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
993             GetFirstAudioContentDescription(
994                 answer.get())->rtp_header_extensions());
995   EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
996             GetFirstVideoContentDescription(
997                 answer.get())->rtp_header_extensions());
998 }
999 
1000 // Create an audio, video, data answer without legacy StreamParams.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateAnswerWithoutLegacyStreams)1001 TEST_F(MediaSessionDescriptionFactoryTest,
1002        TestCreateAnswerWithoutLegacyStreams) {
1003   MediaSessionOptions opts;
1004   opts.recv_video = true;
1005   opts.data_channel_type = cricket::DCT_RTP;
1006   f1_.set_add_legacy_streams(false);
1007   f2_.set_add_legacy_streams(false);
1008   rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1009   ASSERT_TRUE(offer.get() != NULL);
1010   rtc::scoped_ptr<SessionDescription> answer(
1011       f2_.CreateAnswer(offer.get(), opts, NULL));
1012   const ContentInfo* ac = answer->GetContentByName("audio");
1013   const ContentInfo* vc = answer->GetContentByName("video");
1014   const ContentInfo* dc = answer->GetContentByName("data");
1015   ASSERT_TRUE(ac != NULL);
1016   ASSERT_TRUE(vc != NULL);
1017   const AudioContentDescription* acd =
1018       static_cast<const AudioContentDescription*>(ac->description);
1019   const VideoContentDescription* vcd =
1020       static_cast<const VideoContentDescription*>(vc->description);
1021   const DataContentDescription* dcd =
1022       static_cast<const DataContentDescription*>(dc->description);
1023 
1024   EXPECT_FALSE(acd->has_ssrcs());  // No StreamParams.
1025   EXPECT_FALSE(vcd->has_ssrcs());  // No StreamParams.
1026   EXPECT_FALSE(dcd->has_ssrcs());  // No StreamParams.
1027 }
1028 
TEST_F(MediaSessionDescriptionFactoryTest,TestPartial)1029 TEST_F(MediaSessionDescriptionFactoryTest, TestPartial) {
1030   MediaSessionOptions opts;
1031   opts.recv_video = true;
1032   opts.data_channel_type = cricket::DCT_RTP;
1033   f1_.set_secure(SEC_ENABLED);
1034   rtc::scoped_ptr<SessionDescription>
1035       offer(f1_.CreateOffer(opts, NULL));
1036   ASSERT_TRUE(offer.get() != NULL);
1037   const ContentInfo* ac = offer->GetContentByName("audio");
1038   const ContentInfo* vc = offer->GetContentByName("video");
1039   const ContentInfo* dc = offer->GetContentByName("data");
1040   AudioContentDescription* acd = const_cast<AudioContentDescription*>(
1041       static_cast<const AudioContentDescription*>(ac->description));
1042   VideoContentDescription* vcd = const_cast<VideoContentDescription*>(
1043       static_cast<const VideoContentDescription*>(vc->description));
1044   DataContentDescription* dcd = const_cast<DataContentDescription*>(
1045       static_cast<const DataContentDescription*>(dc->description));
1046 
1047   EXPECT_FALSE(acd->partial());  // default is false.
1048   acd->set_partial(true);
1049   EXPECT_TRUE(acd->partial());
1050   acd->set_partial(false);
1051   EXPECT_FALSE(acd->partial());
1052 
1053   EXPECT_FALSE(vcd->partial());  // default is false.
1054   vcd->set_partial(true);
1055   EXPECT_TRUE(vcd->partial());
1056   vcd->set_partial(false);
1057   EXPECT_FALSE(vcd->partial());
1058 
1059   EXPECT_FALSE(dcd->partial());  // default is false.
1060   dcd->set_partial(true);
1061   EXPECT_TRUE(dcd->partial());
1062   dcd->set_partial(false);
1063   EXPECT_FALSE(dcd->partial());
1064 }
1065 
1066 // Create a typical video answer, and ensure it matches what we expect.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateVideoAnswerRtcpMux)1067 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1068   MediaSessionOptions offer_opts;
1069   MediaSessionOptions answer_opts;
1070   answer_opts.recv_video = true;
1071   offer_opts.recv_video = true;
1072   answer_opts.data_channel_type = cricket::DCT_RTP;
1073   offer_opts.data_channel_type = cricket::DCT_RTP;
1074 
1075   rtc::scoped_ptr<SessionDescription> offer;
1076   rtc::scoped_ptr<SessionDescription> answer;
1077 
1078   offer_opts.rtcp_mux_enabled = true;
1079   answer_opts.rtcp_mux_enabled = true;
1080 
1081   offer.reset(f1_.CreateOffer(offer_opts, NULL));
1082   answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1083   ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1084   ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1085   ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1086   ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1087   ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1088   ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1089   EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1090   EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1091   EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1092   EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1093   EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1094   EXPECT_TRUE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1095 
1096   offer_opts.rtcp_mux_enabled = true;
1097   answer_opts.rtcp_mux_enabled = false;
1098 
1099   offer.reset(f1_.CreateOffer(offer_opts, NULL));
1100   answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1101   ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1102   ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1103   ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1104   ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1105   ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1106   ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1107   EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1108   EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1109   EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1110   EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1111   EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1112   EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1113 
1114   offer_opts.rtcp_mux_enabled = false;
1115   answer_opts.rtcp_mux_enabled = true;
1116 
1117   offer.reset(f1_.CreateOffer(offer_opts, NULL));
1118   answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1119   ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1120   ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1121   ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1122   ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1123   ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1124   ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1125   EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1126   EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1127   EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1128   EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1129   EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1130   EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1131 
1132   offer_opts.rtcp_mux_enabled = false;
1133   answer_opts.rtcp_mux_enabled = false;
1134 
1135   offer.reset(f1_.CreateOffer(offer_opts, NULL));
1136   answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1137   ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1138   ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1139   ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1140   ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1141   ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1142   ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1143   EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1144   EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1145   EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1146   EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1147   EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1148   EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1149 }
1150 
1151 // Create an audio-only answer to a video offer.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateAudioAnswerToVideo)1152 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1153   MediaSessionOptions opts;
1154   opts.recv_video = true;
1155   rtc::scoped_ptr<SessionDescription>
1156       offer(f1_.CreateOffer(opts, NULL));
1157   ASSERT_TRUE(offer.get() != NULL);
1158   rtc::scoped_ptr<SessionDescription> answer(
1159       f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
1160   const ContentInfo* ac = answer->GetContentByName("audio");
1161   const ContentInfo* vc = answer->GetContentByName("video");
1162   ASSERT_TRUE(ac != NULL);
1163   ASSERT_TRUE(vc != NULL);
1164   ASSERT_TRUE(vc->description != NULL);
1165   EXPECT_TRUE(vc->rejected);
1166 }
1167 
1168 // Create an audio-only answer to an offer with data.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateNoDataAnswerToDataOffer)1169 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
1170   MediaSessionOptions opts;
1171   opts.data_channel_type = cricket::DCT_RTP;
1172   rtc::scoped_ptr<SessionDescription>
1173       offer(f1_.CreateOffer(opts, NULL));
1174   ASSERT_TRUE(offer.get() != NULL);
1175   rtc::scoped_ptr<SessionDescription> answer(
1176       f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
1177   const ContentInfo* ac = answer->GetContentByName("audio");
1178   const ContentInfo* dc = answer->GetContentByName("data");
1179   ASSERT_TRUE(ac != NULL);
1180   ASSERT_TRUE(dc != NULL);
1181   ASSERT_TRUE(dc->description != NULL);
1182   EXPECT_TRUE(dc->rejected);
1183 }
1184 
1185 // Create an answer that rejects the contents which are rejected in the offer.
TEST_F(MediaSessionDescriptionFactoryTest,CreateAnswerToOfferWithRejectedMedia)1186 TEST_F(MediaSessionDescriptionFactoryTest,
1187        CreateAnswerToOfferWithRejectedMedia) {
1188   MediaSessionOptions opts;
1189   opts.recv_video = true;
1190   opts.data_channel_type = cricket::DCT_RTP;
1191   rtc::scoped_ptr<SessionDescription>
1192       offer(f1_.CreateOffer(opts, NULL));
1193   ASSERT_TRUE(offer.get() != NULL);
1194   ContentInfo* ac = offer->GetContentByName("audio");
1195   ContentInfo* vc = offer->GetContentByName("video");
1196   ContentInfo* dc = offer->GetContentByName("data");
1197   ASSERT_TRUE(ac != NULL);
1198   ASSERT_TRUE(vc != NULL);
1199   ASSERT_TRUE(dc != NULL);
1200   ac->rejected = true;
1201   vc->rejected = true;
1202   dc->rejected = true;
1203   rtc::scoped_ptr<SessionDescription> answer(
1204       f2_.CreateAnswer(offer.get(), opts, NULL));
1205   ac = answer->GetContentByName("audio");
1206   vc = answer->GetContentByName("video");
1207   dc = answer->GetContentByName("data");
1208   ASSERT_TRUE(ac != NULL);
1209   ASSERT_TRUE(vc != NULL);
1210   ASSERT_TRUE(dc != NULL);
1211   EXPECT_TRUE(ac->rejected);
1212   EXPECT_TRUE(vc->rejected);
1213   EXPECT_TRUE(dc->rejected);
1214 }
1215 
1216 // Create an audio and video offer with:
1217 // - one video track
1218 // - two audio tracks
1219 // - two data tracks
1220 // and ensure it matches what we expect. Also updates the initial offer by
1221 // adding a new video track and replaces one of the audio tracks.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateMultiStreamVideoOffer)1222 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
1223   MediaSessionOptions opts;
1224   opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack1, kMediaStream1);
1225   opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
1226   opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2, kMediaStream1);
1227   opts.data_channel_type = cricket::DCT_RTP;
1228   opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack1, kMediaStream1);
1229   opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack2, kMediaStream1);
1230 
1231   f1_.set_secure(SEC_ENABLED);
1232   rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1233 
1234   ASSERT_TRUE(offer.get() != NULL);
1235   const ContentInfo* ac = offer->GetContentByName("audio");
1236   const ContentInfo* vc = offer->GetContentByName("video");
1237   const ContentInfo* dc = offer->GetContentByName("data");
1238   ASSERT_TRUE(ac != NULL);
1239   ASSERT_TRUE(vc != NULL);
1240   ASSERT_TRUE(dc != NULL);
1241   const AudioContentDescription* acd =
1242       static_cast<const AudioContentDescription*>(ac->description);
1243   const VideoContentDescription* vcd =
1244       static_cast<const VideoContentDescription*>(vc->description);
1245   const DataContentDescription* dcd =
1246       static_cast<const DataContentDescription*>(dc->description);
1247   EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1248   EXPECT_EQ(f1_.audio_codecs(), acd->codecs());
1249 
1250   const StreamParamsVec& audio_streams = acd->streams();
1251   ASSERT_EQ(2U, audio_streams.size());
1252   EXPECT_EQ(audio_streams[0].cname , audio_streams[1].cname);
1253   EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1254   ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1255   EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1256   EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1257   ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1258   EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1259 
1260   EXPECT_EQ(kAutoBandwidth, acd->bandwidth());  // default bandwidth (auto)
1261   EXPECT_TRUE(acd->rtcp_mux());                 // rtcp-mux defaults on
1262   ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
1263 
1264   EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1265   EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
1266   ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1267 
1268   const StreamParamsVec& video_streams = vcd->streams();
1269   ASSERT_EQ(1U, video_streams.size());
1270   EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1271   EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1272   EXPECT_EQ(kAutoBandwidth, vcd->bandwidth());  // default bandwidth (auto)
1273   EXPECT_TRUE(vcd->rtcp_mux());                 // rtcp-mux defaults on
1274 
1275   EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1276   EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
1277   ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1278 
1279   const StreamParamsVec& data_streams = dcd->streams();
1280   ASSERT_EQ(2U, data_streams.size());
1281   EXPECT_EQ(data_streams[0].cname , data_streams[1].cname);
1282   EXPECT_EQ(kDataTrack1, data_streams[0].id);
1283   ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1284   EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1285   EXPECT_EQ(kDataTrack2, data_streams[1].id);
1286   ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1287   EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1288 
1289   EXPECT_EQ(cricket::kDataMaxBandwidth,
1290             dcd->bandwidth());                  // default bandwidth (auto)
1291   EXPECT_TRUE(dcd->rtcp_mux());                 // rtcp-mux defaults on
1292   ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1293 
1294 
1295   // Update the offer. Add a new video track that is not synched to the
1296   // other tracks and replace audio track 2 with audio track 3.
1297   opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack2, kMediaStream2);
1298   opts.RemoveSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2);
1299   opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack3, kMediaStream1);
1300   opts.RemoveSendStream(MEDIA_TYPE_DATA, kDataTrack2);
1301   opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack3, kMediaStream1);
1302   rtc::scoped_ptr<SessionDescription>
1303       updated_offer(f1_.CreateOffer(opts, offer.get()));
1304 
1305   ASSERT_TRUE(updated_offer.get() != NULL);
1306   ac = updated_offer->GetContentByName("audio");
1307   vc = updated_offer->GetContentByName("video");
1308   dc = updated_offer->GetContentByName("data");
1309   ASSERT_TRUE(ac != NULL);
1310   ASSERT_TRUE(vc != NULL);
1311   ASSERT_TRUE(dc != NULL);
1312   const AudioContentDescription* updated_acd =
1313       static_cast<const AudioContentDescription*>(ac->description);
1314   const VideoContentDescription* updated_vcd =
1315       static_cast<const VideoContentDescription*>(vc->description);
1316   const DataContentDescription* updated_dcd =
1317       static_cast<const DataContentDescription*>(dc->description);
1318 
1319   EXPECT_EQ(acd->type(), updated_acd->type());
1320   EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1321   EXPECT_EQ(vcd->type(), updated_vcd->type());
1322   EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1323   EXPECT_EQ(dcd->type(), updated_dcd->type());
1324   EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1325   ASSERT_CRYPTO(updated_acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
1326   EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
1327   ASSERT_CRYPTO(updated_vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1328   EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
1329   ASSERT_CRYPTO(updated_dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1330   EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1331 
1332   const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1333   ASSERT_EQ(2U, updated_audio_streams.size());
1334   EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
1335   EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id);  // New audio track.
1336   ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
1337   EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
1338   EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
1339 
1340   const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1341   ASSERT_EQ(2U, updated_video_streams.size());
1342   EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1343   EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
1344   EXPECT_NE(updated_video_streams[1].cname, updated_video_streams[0].cname);
1345 
1346   const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1347   ASSERT_EQ(2U, updated_data_streams.size());
1348   EXPECT_EQ(data_streams[0], updated_data_streams[0]);
1349   EXPECT_EQ(kDataTrack3, updated_data_streams[1].id);  // New data track.
1350   ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
1351   EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
1352   EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
1353 }
1354 
1355 // Create an offer with simulcast video stream.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateSimulcastVideoOffer)1356 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
1357   MediaSessionOptions opts;
1358   const int num_sim_layers = 3;
1359   opts.AddSendVideoStream(kVideoTrack1, kMediaStream1, num_sim_layers);
1360   rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1361 
1362   ASSERT_TRUE(offer.get() != NULL);
1363   const ContentInfo* vc = offer->GetContentByName("video");
1364   ASSERT_TRUE(vc != NULL);
1365   const VideoContentDescription* vcd =
1366       static_cast<const VideoContentDescription*>(vc->description);
1367 
1368   const StreamParamsVec& video_streams = vcd->streams();
1369   ASSERT_EQ(1U, video_streams.size());
1370   EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1371   const SsrcGroup* sim_ssrc_group =
1372       video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
1373   ASSERT_TRUE(sim_ssrc_group != NULL);
1374   EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
1375 }
1376 
1377 // Create an audio and video answer to a standard video offer with:
1378 // - one video track
1379 // - two audio tracks
1380 // - two data tracks
1381 // and ensure it matches what we expect. Also updates the initial answer by
1382 // adding a new video track and removes one of the audio tracks.
TEST_F(MediaSessionDescriptionFactoryTest,TestCreateMultiStreamVideoAnswer)1383 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
1384   MediaSessionOptions offer_opts;
1385   offer_opts.recv_video = true;
1386   offer_opts.data_channel_type = cricket::DCT_RTP;
1387   f1_.set_secure(SEC_ENABLED);
1388   f2_.set_secure(SEC_ENABLED);
1389   rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(offer_opts,
1390                                                                   NULL));
1391 
1392   MediaSessionOptions opts;
1393   opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack1, kMediaStream1);
1394   opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack1, kMediaStream1);
1395   opts.AddSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2, kMediaStream1);
1396   opts.data_channel_type = cricket::DCT_RTP;
1397   opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack1, kMediaStream1);
1398   opts.AddSendStream(MEDIA_TYPE_DATA, kDataTrack2, kMediaStream1);
1399 
1400   rtc::scoped_ptr<SessionDescription>
1401       answer(f2_.CreateAnswer(offer.get(), opts, NULL));
1402 
1403   ASSERT_TRUE(answer.get() != NULL);
1404   const ContentInfo* ac = answer->GetContentByName("audio");
1405   const ContentInfo* vc = answer->GetContentByName("video");
1406   const ContentInfo* dc = answer->GetContentByName("data");
1407   ASSERT_TRUE(ac != NULL);
1408   ASSERT_TRUE(vc != NULL);
1409   ASSERT_TRUE(dc != NULL);
1410   const AudioContentDescription* acd =
1411       static_cast<const AudioContentDescription*>(ac->description);
1412   const VideoContentDescription* vcd =
1413       static_cast<const VideoContentDescription*>(vc->description);
1414   const DataContentDescription* dcd =
1415       static_cast<const DataContentDescription*>(dc->description);
1416   ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1417   ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1418   ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1419 
1420   EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1421   EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1422 
1423   const StreamParamsVec& audio_streams = acd->streams();
1424   ASSERT_EQ(2U, audio_streams.size());
1425   EXPECT_TRUE(audio_streams[0].cname ==  audio_streams[1].cname);
1426   EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1427   ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1428   EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1429   EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1430   ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1431   EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1432 
1433   EXPECT_EQ(kAutoBandwidth, acd->bandwidth());  // default bandwidth (auto)
1434   EXPECT_TRUE(acd->rtcp_mux());                 // rtcp-mux defaults on
1435 
1436   EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1437   EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1438 
1439   const StreamParamsVec& video_streams = vcd->streams();
1440   ASSERT_EQ(1U, video_streams.size());
1441   EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1442   EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1443   EXPECT_EQ(kAutoBandwidth, vcd->bandwidth());  // default bandwidth (auto)
1444   EXPECT_TRUE(vcd->rtcp_mux());                 // rtcp-mux defaults on
1445 
1446   EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1447   EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
1448 
1449   const StreamParamsVec& data_streams = dcd->streams();
1450   ASSERT_EQ(2U, data_streams.size());
1451   EXPECT_TRUE(data_streams[0].cname ==  data_streams[1].cname);
1452   EXPECT_EQ(kDataTrack1, data_streams[0].id);
1453   ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1454   EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1455   EXPECT_EQ(kDataTrack2, data_streams[1].id);
1456   ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1457   EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1458 
1459   EXPECT_EQ(cricket::kDataMaxBandwidth,
1460             dcd->bandwidth());                  // default bandwidth (auto)
1461   EXPECT_TRUE(dcd->rtcp_mux());                 // rtcp-mux defaults on
1462 
1463   // Update the answer. Add a new video track that is not synched to the
1464   // other traacks and remove 1 audio track.
1465   opts.AddSendStream(MEDIA_TYPE_VIDEO, kVideoTrack2, kMediaStream2);
1466   opts.RemoveSendStream(MEDIA_TYPE_AUDIO, kAudioTrack2);
1467   opts.RemoveSendStream(MEDIA_TYPE_DATA, kDataTrack2);
1468   rtc::scoped_ptr<SessionDescription>
1469       updated_answer(f2_.CreateAnswer(offer.get(), opts, answer.get()));
1470 
1471   ASSERT_TRUE(updated_answer.get() != NULL);
1472   ac = updated_answer->GetContentByName("audio");
1473   vc = updated_answer->GetContentByName("video");
1474   dc = updated_answer->GetContentByName("data");
1475   ASSERT_TRUE(ac != NULL);
1476   ASSERT_TRUE(vc != NULL);
1477   ASSERT_TRUE(dc != NULL);
1478   const AudioContentDescription* updated_acd =
1479       static_cast<const AudioContentDescription*>(ac->description);
1480   const VideoContentDescription* updated_vcd =
1481       static_cast<const VideoContentDescription*>(vc->description);
1482   const DataContentDescription* updated_dcd =
1483       static_cast<const DataContentDescription*>(dc->description);
1484 
1485   ASSERT_CRYPTO(updated_acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1486   EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
1487   ASSERT_CRYPTO(updated_vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1488   EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
1489   ASSERT_CRYPTO(updated_dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1490   EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1491 
1492   EXPECT_EQ(acd->type(), updated_acd->type());
1493   EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1494   EXPECT_EQ(vcd->type(), updated_vcd->type());
1495   EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1496   EXPECT_EQ(dcd->type(), updated_dcd->type());
1497   EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1498 
1499   const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1500   ASSERT_EQ(1U, updated_audio_streams.size());
1501   EXPECT_TRUE(audio_streams[0] ==  updated_audio_streams[0]);
1502 
1503   const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1504   ASSERT_EQ(2U, updated_video_streams.size());
1505   EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1506   EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
1507   EXPECT_NE(updated_video_streams[1].cname, updated_video_streams[0].cname);
1508 
1509   const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1510   ASSERT_EQ(1U, updated_data_streams.size());
1511   EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
1512 }
1513 
1514 
1515 // Create an updated offer after creating an answer to the original offer and
1516 // verify that the codecs that were part of the original answer are not changed
1517 // in the updated offer.
TEST_F(MediaSessionDescriptionFactoryTest,RespondentCreatesOfferAfterCreatingAnswer)1518 TEST_F(MediaSessionDescriptionFactoryTest,
1519        RespondentCreatesOfferAfterCreatingAnswer) {
1520   MediaSessionOptions opts;
1521   opts.recv_audio = true;
1522   opts.recv_video = true;
1523 
1524   rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1525   rtc::scoped_ptr<SessionDescription> answer(
1526       f2_.CreateAnswer(offer.get(), opts, NULL));
1527 
1528   const AudioContentDescription* acd =
1529       GetFirstAudioContentDescription(answer.get());
1530   EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1531 
1532   const VideoContentDescription* vcd =
1533       GetFirstVideoContentDescription(answer.get());
1534   EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1535 
1536   rtc::scoped_ptr<SessionDescription> updated_offer(
1537       f2_.CreateOffer(opts, answer.get()));
1538 
1539   // The expected audio codecs are the common audio codecs from the first
1540   // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
1541   // preference order.
1542   // TODO(wu): |updated_offer| should not include the codec
1543   // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
1544   const AudioCodec kUpdatedAudioCodecOffer[] = {
1545     kAudioCodecsAnswer[0],
1546     kAudioCodecsAnswer[1],
1547     kAudioCodecs2[0],
1548   };
1549 
1550   // The expected video codecs are the common video codecs from the first
1551   // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
1552   // preference order.
1553   const VideoCodec kUpdatedVideoCodecOffer[] = {
1554     kVideoCodecsAnswer[0],
1555     kVideoCodecs2[1],
1556   };
1557 
1558   const AudioContentDescription* updated_acd =
1559       GetFirstAudioContentDescription(updated_offer.get());
1560   EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioCodecOffer), updated_acd->codecs());
1561 
1562   const VideoContentDescription* updated_vcd =
1563       GetFirstVideoContentDescription(updated_offer.get());
1564   EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoCodecOffer), updated_vcd->codecs());
1565 }
1566 
1567 // Create an updated offer after creating an answer to the original offer and
1568 // verify that the codecs that were part of the original answer are not changed
1569 // in the updated offer. In this test Rtx is enabled.
TEST_F(MediaSessionDescriptionFactoryTest,RespondentCreatesOfferAfterCreatingAnswerWithRtx)1570 TEST_F(MediaSessionDescriptionFactoryTest,
1571        RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
1572   MediaSessionOptions opts;
1573   opts.recv_video = true;
1574   opts.recv_audio = false;
1575   std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1576   // This creates rtx for H264 with the payload type |f1_| uses.
1577   AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
1578   f1_.set_video_codecs(f1_codecs);
1579 
1580   std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1581   // This creates rtx for H264 with the payload type |f2_| uses.
1582   AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
1583   f2_.set_video_codecs(f2_codecs);
1584 
1585   rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1586   ASSERT_TRUE(offer.get() != NULL);
1587   rtc::scoped_ptr<SessionDescription> answer(
1588       f2_.CreateAnswer(offer.get(), opts, NULL));
1589 
1590   const VideoContentDescription* vcd =
1591       GetFirstVideoContentDescription(answer.get());
1592 
1593   std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
1594   AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
1595               &expected_codecs);
1596 
1597   EXPECT_EQ(expected_codecs, vcd->codecs());
1598 
1599   // Now, make sure we get same result, except for the preference order,
1600   // if |f2_| creates an updated offer even though the default payload types
1601   // are different from |f1_|.
1602   expected_codecs[0].preference = f1_codecs[1].preference;
1603 
1604   rtc::scoped_ptr<SessionDescription> updated_offer(
1605       f2_.CreateOffer(opts, answer.get()));
1606   ASSERT_TRUE(updated_offer);
1607   rtc::scoped_ptr<SessionDescription> updated_answer(
1608       f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
1609 
1610   const VideoContentDescription* updated_vcd =
1611       GetFirstVideoContentDescription(updated_answer.get());
1612 
1613   EXPECT_EQ(expected_codecs, updated_vcd->codecs());
1614 }
1615 
1616 // Create an updated offer that adds video after creating an audio only answer
1617 // to the original offer. This test verifies that if a video codec and the RTX
1618 // codec have the same default payload type as an audio codec that is already in
1619 // use, the added codecs payload types are changed.
TEST_F(MediaSessionDescriptionFactoryTest,RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer)1620 TEST_F(MediaSessionDescriptionFactoryTest,
1621        RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
1622   std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1623   // This creates rtx for H264 with the payload type |f1_| uses.
1624   AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
1625   f1_.set_video_codecs(f1_codecs);
1626 
1627   MediaSessionOptions opts;
1628   opts.recv_audio = true;
1629   opts.recv_video = false;
1630 
1631   rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1632   rtc::scoped_ptr<SessionDescription> answer(
1633       f2_.CreateAnswer(offer.get(), opts, NULL));
1634 
1635   const AudioContentDescription* acd =
1636       GetFirstAudioContentDescription(answer.get());
1637   EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1638 
1639   // Now - let |f2_| add video with RTX and let the payload type the RTX codec
1640   // reference  be the same as an audio codec that was negotiated in the
1641   // first offer/answer exchange.
1642   opts.recv_audio = true;
1643   opts.recv_video = true;
1644 
1645   std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1646   int used_pl_type = acd->codecs()[0].id;
1647   f2_codecs[0].id = used_pl_type;  // Set the payload type for H264.
1648   AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
1649   f2_.set_video_codecs(f2_codecs);
1650 
1651   rtc::scoped_ptr<SessionDescription> updated_offer(
1652       f2_.CreateOffer(opts, answer.get()));
1653   ASSERT_TRUE(updated_offer);
1654   rtc::scoped_ptr<SessionDescription> updated_answer(
1655       f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
1656 
1657   const AudioContentDescription* updated_acd =
1658       GetFirstAudioContentDescription(answer.get());
1659   EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), updated_acd->codecs());
1660 
1661   const VideoContentDescription* updated_vcd =
1662       GetFirstVideoContentDescription(updated_answer.get());
1663 
1664   ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
1665   ASSERT_EQ(std::string(cricket::kRtxCodecName), updated_vcd->codecs()[1].name);
1666   int new_h264_pl_type =  updated_vcd->codecs()[0].id;
1667   EXPECT_NE(used_pl_type, new_h264_pl_type);
1668   VideoCodec rtx = updated_vcd->codecs()[1];
1669   int pt_referenced_by_rtx = rtc::FromString<int>(
1670       rtx.params[cricket::kCodecParamAssociatedPayloadType]);
1671   EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
1672 }
1673 
1674 // Test that RTX is ignored when there is no associated payload type parameter.
TEST_F(MediaSessionDescriptionFactoryTest,RtxWithoutApt)1675 TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
1676   MediaSessionOptions opts;
1677   opts.recv_video = true;
1678   opts.recv_audio = false;
1679   std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1680   // This creates RTX without associated payload type parameter.
1681   AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName, 0, 0, 0, 0), &f1_codecs);
1682   f1_.set_video_codecs(f1_codecs);
1683 
1684   std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1685   // This creates RTX for H264 with the payload type |f2_| uses.
1686   AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
1687   f2_.set_video_codecs(f2_codecs);
1688 
1689   rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1690   ASSERT_TRUE(offer.get() != NULL);
1691   // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
1692   // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
1693   // is possible to test that that RTX is dropped when
1694   // kCodecParamAssociatedPayloadType is missing in the offer.
1695   VideoContentDescription* desc =
1696       static_cast<cricket::VideoContentDescription*>(
1697           offer->GetContentDescriptionByName(cricket::CN_VIDEO));
1698   ASSERT_TRUE(desc != NULL);
1699   std::vector<VideoCodec> codecs = desc->codecs();
1700   for (std::vector<VideoCodec>::iterator iter = codecs.begin();
1701        iter != codecs.end(); ++iter) {
1702     if (iter->name.find(cricket::kRtxCodecName) == 0) {
1703       iter->params.clear();
1704     }
1705   }
1706   desc->set_codecs(codecs);
1707 
1708   rtc::scoped_ptr<SessionDescription> answer(
1709       f2_.CreateAnswer(offer.get(), opts, NULL));
1710 
1711   std::vector<std::string> codec_names =
1712       GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
1713   EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
1714                                          cricket::kRtxCodecName));
1715 }
1716 
1717 // Test that RTX will be filtered out in the answer if its associated payload
1718 // type doesn't match the local value.
TEST_F(MediaSessionDescriptionFactoryTest,FilterOutRtxIfAptDoesntMatch)1719 TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
1720   MediaSessionOptions opts;
1721   opts.recv_video = true;
1722   opts.recv_audio = false;
1723   std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1724   // This creates RTX for H264 in sender.
1725   AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
1726   f1_.set_video_codecs(f1_codecs);
1727 
1728   std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1729   // This creates RTX for H263 in receiver.
1730   AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
1731   f2_.set_video_codecs(f2_codecs);
1732 
1733   rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1734   ASSERT_TRUE(offer.get() != NULL);
1735   // Associated payload type doesn't match, therefore, RTX codec is removed in
1736   // the answer.
1737   rtc::scoped_ptr<SessionDescription> answer(
1738       f2_.CreateAnswer(offer.get(), opts, NULL));
1739 
1740   std::vector<std::string> codec_names =
1741       GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
1742   EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
1743                                          cricket::kRtxCodecName));
1744 }
1745 
1746 // Test that when multiple RTX codecs are offered, only the matched RTX codec
1747 // is added in the answer, and the unsupported RTX codec is filtered out.
TEST_F(MediaSessionDescriptionFactoryTest,FilterOutUnsupportedRtxWhenCreatingAnswer)1748 TEST_F(MediaSessionDescriptionFactoryTest,
1749        FilterOutUnsupportedRtxWhenCreatingAnswer) {
1750   MediaSessionOptions opts;
1751   opts.recv_video = true;
1752   opts.recv_audio = false;
1753   std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
1754   // This creates RTX for H264-SVC in sender.
1755   AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
1756   f1_.set_video_codecs(f1_codecs);
1757 
1758   // This creates RTX for H264 in sender.
1759   AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
1760   f1_.set_video_codecs(f1_codecs);
1761 
1762   std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
1763   // This creates RTX for H264 in receiver.
1764   AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
1765   f2_.set_video_codecs(f2_codecs);
1766 
1767   // H264-SVC codec is removed in the answer, therefore, associated RTX codec
1768   // for H264-SVC should also be removed.
1769   rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1770   ASSERT_TRUE(offer.get() != NULL);
1771   rtc::scoped_ptr<SessionDescription> answer(
1772       f2_.CreateAnswer(offer.get(), opts, NULL));
1773   const VideoContentDescription* vcd =
1774       GetFirstVideoContentDescription(answer.get());
1775   std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
1776   AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
1777               &expected_codecs);
1778 
1779   EXPECT_EQ(expected_codecs, vcd->codecs());
1780 }
1781 
1782 // Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
1783 // generated for each simulcast ssrc and correctly grouped.
TEST_F(MediaSessionDescriptionFactoryTest,SimSsrcsGenerateMultipleRtxSsrcs)1784 TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
1785   MediaSessionOptions opts;
1786   opts.recv_video = true;
1787   opts.recv_audio = false;
1788 
1789   // Add simulcast streams.
1790   opts.AddSendVideoStream("stream1", "stream1label", 3);
1791 
1792   // Use a single real codec, and then add RTX for it.
1793   std::vector<VideoCodec> f1_codecs;
1794   f1_codecs.push_back(VideoCodec(97, "H264", 320, 200, 30, 1));
1795   AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
1796   f1_.set_video_codecs(f1_codecs);
1797 
1798   // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
1799   // is a FID ssrc + grouping for each.
1800   rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1801   ASSERT_TRUE(offer.get() != NULL);
1802   VideoContentDescription* desc = static_cast<VideoContentDescription*>(
1803       offer->GetContentDescriptionByName(cricket::CN_VIDEO));
1804   ASSERT_TRUE(desc != NULL);
1805   EXPECT_TRUE(desc->multistream());
1806   const StreamParamsVec& streams = desc->streams();
1807   // Single stream.
1808   ASSERT_EQ(1u, streams.size());
1809   // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
1810   EXPECT_EQ(6u, streams[0].ssrcs.size());
1811   // And should have a SIM group for the simulcast.
1812   EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
1813   // And a FID group for RTX.
1814   EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
1815   std::vector<uint32_t> primary_ssrcs;
1816   streams[0].GetPrimarySsrcs(&primary_ssrcs);
1817   EXPECT_EQ(3u, primary_ssrcs.size());
1818   std::vector<uint32_t> fid_ssrcs;
1819   streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
1820   EXPECT_EQ(3u, fid_ssrcs.size());
1821 }
1822 
1823 // Create an updated offer after creating an answer to the original offer and
1824 // verify that the RTP header extensions that were part of the original answer
1825 // are not changed in the updated offer.
TEST_F(MediaSessionDescriptionFactoryTest,RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions)1826 TEST_F(MediaSessionDescriptionFactoryTest,
1827        RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
1828   MediaSessionOptions opts;
1829   opts.recv_audio = true;
1830   opts.recv_video = true;
1831 
1832   f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1833   f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1834   f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1835   f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1836 
1837   rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1838   rtc::scoped_ptr<SessionDescription> answer(
1839       f2_.CreateAnswer(offer.get(), opts, NULL));
1840 
1841   EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
1842             GetFirstAudioContentDescription(
1843                 answer.get())->rtp_header_extensions());
1844   EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
1845             GetFirstVideoContentDescription(
1846                 answer.get())->rtp_header_extensions());
1847 
1848   rtc::scoped_ptr<SessionDescription> updated_offer(
1849       f2_.CreateOffer(opts, answer.get()));
1850 
1851   // The expected RTP header extensions in the new offer are the resulting
1852   // extensions from the first offer/answer exchange plus the extensions only
1853   // |f2_| offer.
1854   // Since the default local extension id |f2_| uses has already been used by
1855   // |f1_| for another extensions, it is changed to 13.
1856   const RtpHeaderExtension kUpdatedAudioRtpExtensions[] = {
1857     kAudioRtpExtensionAnswer[0],
1858     RtpHeaderExtension(kAudioRtpExtension2[1].uri, 13),
1859     kAudioRtpExtension2[2],
1860   };
1861 
1862   // Since the default local extension id |f2_| uses has already been used by
1863   // |f1_| for another extensions, is is changed to 12.
1864   const RtpHeaderExtension kUpdatedVideoRtpExtensions[] = {
1865     kVideoRtpExtensionAnswer[0],
1866     RtpHeaderExtension(kVideoRtpExtension2[1].uri, 12),
1867     kVideoRtpExtension2[2],
1868   };
1869 
1870   const AudioContentDescription* updated_acd =
1871       GetFirstAudioContentDescription(updated_offer.get());
1872   EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
1873             updated_acd->rtp_header_extensions());
1874 
1875   const VideoContentDescription* updated_vcd =
1876       GetFirstVideoContentDescription(updated_offer.get());
1877   EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
1878             updated_vcd->rtp_header_extensions());
1879 }
1880 
1881 // Verify that if the same RTP extension URI is used for audio and video, the
1882 // same ID is used. Also verify that the ID isn't changed when creating an
1883 // updated offer (this was previously a bug).
TEST_F(MediaSessionDescriptionFactoryTest,RtpHeaderExtensionIdReused)1884 TEST_F(MediaSessionDescriptionFactoryTest,
1885        RtpHeaderExtensionIdReused) {
1886   MediaSessionOptions opts;
1887   opts.recv_audio = true;
1888   opts.recv_video = true;
1889 
1890   f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
1891   f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
1892 
1893   rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1894 
1895   // Since the audio extensions used ID 3 for "both_audio_and_video", so should
1896   // the video extensions.
1897   const RtpHeaderExtension kExpectedVideoRtpExtension[] = {
1898     kVideoRtpExtension3[0],
1899     kAudioRtpExtension3[1],
1900   };
1901 
1902   EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
1903             GetFirstAudioContentDescription(
1904                 offer.get())->rtp_header_extensions());
1905   EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
1906             GetFirstVideoContentDescription(
1907                 offer.get())->rtp_header_extensions());
1908 
1909   // Nothing should change when creating a new offer
1910   rtc::scoped_ptr<SessionDescription> updated_offer(
1911       f1_.CreateOffer(opts, offer.get()));
1912 
1913   EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
1914             GetFirstAudioContentDescription(
1915                 updated_offer.get())->rtp_header_extensions());
1916   EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
1917             GetFirstVideoContentDescription(
1918                 updated_offer.get())->rtp_header_extensions());
1919 }
1920 
TEST(MediaSessionDescription,CopySessionDescription)1921 TEST(MediaSessionDescription, CopySessionDescription) {
1922   SessionDescription source;
1923   cricket::ContentGroup group(cricket::CN_AUDIO);
1924   source.AddGroup(group);
1925   AudioContentDescription* acd(new AudioContentDescription());
1926   acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
1927   acd->AddLegacyStream(1);
1928   source.AddContent(cricket::CN_AUDIO, cricket::NS_JINGLE_RTP, acd);
1929   VideoContentDescription* vcd(new VideoContentDescription());
1930   vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
1931   vcd->AddLegacyStream(2);
1932   source.AddContent(cricket::CN_VIDEO, cricket::NS_JINGLE_RTP, vcd);
1933 
1934   rtc::scoped_ptr<SessionDescription> copy(source.Copy());
1935   ASSERT_TRUE(copy.get() != NULL);
1936   EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
1937   const ContentInfo* ac = copy->GetContentByName("audio");
1938   const ContentInfo* vc = copy->GetContentByName("video");
1939   ASSERT_TRUE(ac != NULL);
1940   ASSERT_TRUE(vc != NULL);
1941   EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
1942   const AudioContentDescription* acd_copy =
1943       static_cast<const AudioContentDescription*>(ac->description);
1944   EXPECT_EQ(acd->codecs(), acd_copy->codecs());
1945   EXPECT_EQ(1u, acd->first_ssrc());
1946 
1947   EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
1948   const VideoContentDescription* vcd_copy =
1949       static_cast<const VideoContentDescription*>(vc->description);
1950   EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
1951   EXPECT_EQ(2u, vcd->first_ssrc());
1952 }
1953 
1954 // The below TestTransportInfoXXX tests create different offers/answers, and
1955 // ensure the TransportInfo in the SessionDescription matches what we expect.
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoOfferAudio)1956 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
1957   MediaSessionOptions options;
1958   options.recv_audio = true;
1959   TestTransportInfo(true, options, false);
1960 }
1961 
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoOfferAudioCurrent)1962 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
1963   MediaSessionOptions options;
1964   options.recv_audio = true;
1965   TestTransportInfo(true, options, true);
1966 }
1967 
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoOfferMultimedia)1968 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
1969   MediaSessionOptions options;
1970   options.recv_audio = true;
1971   options.recv_video = true;
1972   options.data_channel_type = cricket::DCT_RTP;
1973   TestTransportInfo(true, options, false);
1974 }
1975 
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoOfferMultimediaCurrent)1976 TEST_F(MediaSessionDescriptionFactoryTest,
1977     TestTransportInfoOfferMultimediaCurrent) {
1978   MediaSessionOptions options;
1979   options.recv_audio = true;
1980   options.recv_video = true;
1981   options.data_channel_type = cricket::DCT_RTP;
1982   TestTransportInfo(true, options, true);
1983 }
1984 
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoOfferBundle)1985 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
1986   MediaSessionOptions options;
1987   options.recv_audio = true;
1988   options.recv_video = true;
1989   options.data_channel_type = cricket::DCT_RTP;
1990   options.bundle_enabled = true;
1991   TestTransportInfo(true, options, false);
1992 }
1993 
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoOfferBundleCurrent)1994 TEST_F(MediaSessionDescriptionFactoryTest,
1995        TestTransportInfoOfferBundleCurrent) {
1996   MediaSessionOptions options;
1997   options.recv_audio = true;
1998   options.recv_video = true;
1999   options.data_channel_type = cricket::DCT_RTP;
2000   options.bundle_enabled = true;
2001   TestTransportInfo(true, options, true);
2002 }
2003 
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoAnswerAudio)2004 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
2005   MediaSessionOptions options;
2006   options.recv_audio = true;
2007   TestTransportInfo(false, options, false);
2008 }
2009 
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoAnswerAudioCurrent)2010 TEST_F(MediaSessionDescriptionFactoryTest,
2011     TestTransportInfoAnswerAudioCurrent) {
2012   MediaSessionOptions options;
2013   options.recv_audio = true;
2014   TestTransportInfo(false, options, true);
2015 }
2016 
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoAnswerMultimedia)2017 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
2018   MediaSessionOptions options;
2019   options.recv_audio = true;
2020   options.recv_video = true;
2021   options.data_channel_type = cricket::DCT_RTP;
2022   TestTransportInfo(false, options, false);
2023 }
2024 
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoAnswerMultimediaCurrent)2025 TEST_F(MediaSessionDescriptionFactoryTest,
2026     TestTransportInfoAnswerMultimediaCurrent) {
2027   MediaSessionOptions options;
2028   options.recv_audio = true;
2029   options.recv_video = true;
2030   options.data_channel_type = cricket::DCT_RTP;
2031   TestTransportInfo(false, options, true);
2032 }
2033 
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoAnswerBundle)2034 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
2035   MediaSessionOptions options;
2036   options.recv_audio = true;
2037   options.recv_video = true;
2038   options.data_channel_type = cricket::DCT_RTP;
2039   options.bundle_enabled = true;
2040   TestTransportInfo(false, options, false);
2041 }
2042 
TEST_F(MediaSessionDescriptionFactoryTest,TestTransportInfoAnswerBundleCurrent)2043 TEST_F(MediaSessionDescriptionFactoryTest,
2044     TestTransportInfoAnswerBundleCurrent) {
2045   MediaSessionOptions options;
2046   options.recv_audio = true;
2047   options.recv_video = true;
2048   options.data_channel_type = cricket::DCT_RTP;
2049   options.bundle_enabled = true;
2050   TestTransportInfo(false, options, true);
2051 }
2052 
2053 // Create an offer with bundle enabled and verify the crypto parameters are
2054 // the common set of the available cryptos.
TEST_F(MediaSessionDescriptionFactoryTest,TestCryptoWithOfferBundle)2055 TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
2056   TestCryptoWithBundle(true);
2057 }
2058 
2059 // Create an answer with bundle enabled and verify the crypto parameters are
2060 // the common set of the available cryptos.
TEST_F(MediaSessionDescriptionFactoryTest,TestCryptoWithAnswerBundle)2061 TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
2062   TestCryptoWithBundle(false);
2063 }
2064 
2065 // Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
2066 // DTLS is not enabled locally.
TEST_F(MediaSessionDescriptionFactoryTest,TestOfferDtlsSavpfWithoutDtlsFailed)2067 TEST_F(MediaSessionDescriptionFactoryTest,
2068        TestOfferDtlsSavpfWithoutDtlsFailed) {
2069   f1_.set_secure(SEC_ENABLED);
2070   f2_.set_secure(SEC_ENABLED);
2071   tdf1_.set_secure(SEC_DISABLED);
2072   tdf2_.set_secure(SEC_DISABLED);
2073 
2074   rtc::scoped_ptr<SessionDescription> offer(
2075       f1_.CreateOffer(MediaSessionOptions(), NULL));
2076   ASSERT_TRUE(offer.get() != NULL);
2077   ContentInfo* offer_content = offer->GetContentByName("audio");
2078   ASSERT_TRUE(offer_content != NULL);
2079   AudioContentDescription* offer_audio_desc =
2080       static_cast<AudioContentDescription*>(offer_content->description);
2081   offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2082 
2083   rtc::scoped_ptr<SessionDescription> answer(
2084       f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
2085   ASSERT_TRUE(answer != NULL);
2086   ContentInfo* answer_content = answer->GetContentByName("audio");
2087   ASSERT_TRUE(answer_content != NULL);
2088 
2089   ASSERT_TRUE(answer_content->rejected);
2090 }
2091 
2092 // Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
2093 // UDP/TLS/RTP/SAVPF.
TEST_F(MediaSessionDescriptionFactoryTest,TestOfferDtlsSavpfCreateAnswer)2094 TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
2095   f1_.set_secure(SEC_ENABLED);
2096   f2_.set_secure(SEC_ENABLED);
2097   tdf1_.set_secure(SEC_ENABLED);
2098   tdf2_.set_secure(SEC_ENABLED);
2099 
2100   rtc::scoped_ptr<SessionDescription> offer(
2101       f1_.CreateOffer(MediaSessionOptions(), NULL));
2102   ASSERT_TRUE(offer.get() != NULL);
2103   ContentInfo* offer_content = offer->GetContentByName("audio");
2104   ASSERT_TRUE(offer_content != NULL);
2105   AudioContentDescription* offer_audio_desc =
2106       static_cast<AudioContentDescription*>(offer_content->description);
2107   offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2108 
2109   rtc::scoped_ptr<SessionDescription> answer(
2110       f2_.CreateAnswer(offer.get(), MediaSessionOptions(), NULL));
2111   ASSERT_TRUE(answer != NULL);
2112 
2113   const ContentInfo* answer_content = answer->GetContentByName("audio");
2114   ASSERT_TRUE(answer_content != NULL);
2115   ASSERT_FALSE(answer_content->rejected);
2116 
2117   const AudioContentDescription* answer_audio_desc =
2118       static_cast<const AudioContentDescription*>(answer_content->description);
2119   EXPECT_EQ(std::string(cricket::kMediaProtocolDtlsSavpf),
2120                         answer_audio_desc->protocol());
2121 }
2122 
2123 // Test that we include both SDES and DTLS in the offer, but only include SDES
2124 // in the answer if DTLS isn't negotiated.
TEST_F(MediaSessionDescriptionFactoryTest,TestCryptoDtls)2125 TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
2126   f1_.set_secure(SEC_ENABLED);
2127   f2_.set_secure(SEC_ENABLED);
2128   tdf1_.set_secure(SEC_ENABLED);
2129   tdf2_.set_secure(SEC_DISABLED);
2130   MediaSessionOptions options;
2131   options.recv_audio = true;
2132   options.recv_video = true;
2133   rtc::scoped_ptr<SessionDescription> offer, answer;
2134   const cricket::MediaContentDescription* audio_media_desc;
2135   const cricket::MediaContentDescription* video_media_desc;
2136   const cricket::TransportDescription* audio_trans_desc;
2137   const cricket::TransportDescription* video_trans_desc;
2138 
2139   // Generate an offer with SDES and DTLS support.
2140   offer.reset(f1_.CreateOffer(options, NULL));
2141   ASSERT_TRUE(offer.get() != NULL);
2142 
2143   audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2144       offer->GetContentDescriptionByName("audio"));
2145   ASSERT_TRUE(audio_media_desc != NULL);
2146   video_media_desc = static_cast<const cricket::MediaContentDescription*>(
2147       offer->GetContentDescriptionByName("video"));
2148   ASSERT_TRUE(video_media_desc != NULL);
2149   EXPECT_EQ(2u, audio_media_desc->cryptos().size());
2150   EXPECT_EQ(1u, video_media_desc->cryptos().size());
2151 
2152   audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2153   ASSERT_TRUE(audio_trans_desc != NULL);
2154   video_trans_desc = offer->GetTransportDescriptionByName("video");
2155   ASSERT_TRUE(video_trans_desc != NULL);
2156   ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2157   ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
2158 
2159   // Generate an answer with only SDES support, since tdf2 has crypto disabled.
2160   answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2161   ASSERT_TRUE(answer.get() != NULL);
2162 
2163   audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2164       answer->GetContentDescriptionByName("audio"));
2165   ASSERT_TRUE(audio_media_desc != NULL);
2166   video_media_desc = static_cast<const cricket::MediaContentDescription*>(
2167       answer->GetContentDescriptionByName("video"));
2168   ASSERT_TRUE(video_media_desc != NULL);
2169   EXPECT_EQ(1u, audio_media_desc->cryptos().size());
2170   EXPECT_EQ(1u, video_media_desc->cryptos().size());
2171 
2172   audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2173   ASSERT_TRUE(audio_trans_desc != NULL);
2174   video_trans_desc = answer->GetTransportDescriptionByName("video");
2175   ASSERT_TRUE(video_trans_desc != NULL);
2176   ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
2177   ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
2178 
2179   // Enable DTLS; the answer should now only have DTLS support.
2180   tdf2_.set_secure(SEC_ENABLED);
2181   answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2182   ASSERT_TRUE(answer.get() != NULL);
2183 
2184   audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2185       answer->GetContentDescriptionByName("audio"));
2186   ASSERT_TRUE(audio_media_desc != NULL);
2187   video_media_desc = static_cast<const cricket::MediaContentDescription*>(
2188       answer->GetContentDescriptionByName("video"));
2189   ASSERT_TRUE(video_media_desc != NULL);
2190   EXPECT_TRUE(audio_media_desc->cryptos().empty());
2191   EXPECT_TRUE(video_media_desc->cryptos().empty());
2192   EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2193             audio_media_desc->protocol());
2194   EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2195             video_media_desc->protocol());
2196 
2197   audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2198   ASSERT_TRUE(audio_trans_desc != NULL);
2199   video_trans_desc = answer->GetTransportDescriptionByName("video");
2200   ASSERT_TRUE(video_trans_desc != NULL);
2201   ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2202   ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
2203 
2204   // Try creating offer again. DTLS enabled now, crypto's should be empty
2205   // in new offer.
2206   offer.reset(f1_.CreateOffer(options, offer.get()));
2207   ASSERT_TRUE(offer.get() != NULL);
2208   audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2209       offer->GetContentDescriptionByName("audio"));
2210   ASSERT_TRUE(audio_media_desc != NULL);
2211   video_media_desc = static_cast<const cricket::MediaContentDescription*>(
2212       offer->GetContentDescriptionByName("video"));
2213   ASSERT_TRUE(video_media_desc != NULL);
2214   EXPECT_TRUE(audio_media_desc->cryptos().empty());
2215   EXPECT_TRUE(video_media_desc->cryptos().empty());
2216 
2217   audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2218   ASSERT_TRUE(audio_trans_desc != NULL);
2219   video_trans_desc = offer->GetTransportDescriptionByName("video");
2220   ASSERT_TRUE(video_trans_desc != NULL);
2221   ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2222   ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
2223 }
2224 
2225 // Test that an answer can't be created if cryptos are required but the offer is
2226 // unsecure.
TEST_F(MediaSessionDescriptionFactoryTest,TestSecureAnswerToUnsecureOffer)2227 TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
2228   MediaSessionOptions options;
2229   f1_.set_secure(SEC_DISABLED);
2230   tdf1_.set_secure(SEC_DISABLED);
2231   f2_.set_secure(SEC_REQUIRED);
2232   tdf1_.set_secure(SEC_ENABLED);
2233 
2234   rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(options,
2235                                                                   NULL));
2236   ASSERT_TRUE(offer.get() != NULL);
2237   rtc::scoped_ptr<SessionDescription> answer(
2238       f2_.CreateAnswer(offer.get(), options, NULL));
2239   EXPECT_TRUE(answer.get() == NULL);
2240 }
2241 
2242 // Test that we accept a DTLS offer without SDES and create an appropriate
2243 // answer.
TEST_F(MediaSessionDescriptionFactoryTest,TestCryptoOfferDtlsButNotSdes)2244 TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
2245   f1_.set_secure(SEC_DISABLED);
2246   f2_.set_secure(SEC_ENABLED);
2247   tdf1_.set_secure(SEC_ENABLED);
2248   tdf2_.set_secure(SEC_ENABLED);
2249   MediaSessionOptions options;
2250   options.recv_audio = true;
2251   options.recv_video = true;
2252   options.data_channel_type = cricket::DCT_RTP;
2253 
2254   rtc::scoped_ptr<SessionDescription> offer, answer;
2255 
2256   // Generate an offer with DTLS but without SDES.
2257   offer.reset(f1_.CreateOffer(options, NULL));
2258   ASSERT_TRUE(offer.get() != NULL);
2259 
2260   const AudioContentDescription* audio_offer =
2261       GetFirstAudioContentDescription(offer.get());
2262   ASSERT_TRUE(audio_offer->cryptos().empty());
2263   const VideoContentDescription* video_offer =
2264       GetFirstVideoContentDescription(offer.get());
2265   ASSERT_TRUE(video_offer->cryptos().empty());
2266   const DataContentDescription* data_offer =
2267       GetFirstDataContentDescription(offer.get());
2268   ASSERT_TRUE(data_offer->cryptos().empty());
2269 
2270   const cricket::TransportDescription* audio_offer_trans_desc =
2271       offer->GetTransportDescriptionByName("audio");
2272   ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
2273   const cricket::TransportDescription* video_offer_trans_desc =
2274       offer->GetTransportDescriptionByName("video");
2275   ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
2276   const cricket::TransportDescription* data_offer_trans_desc =
2277       offer->GetTransportDescriptionByName("data");
2278   ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
2279 
2280   // Generate an answer with DTLS.
2281   answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2282   ASSERT_TRUE(answer.get() != NULL);
2283 
2284   const cricket::TransportDescription* audio_answer_trans_desc =
2285       answer->GetTransportDescriptionByName("audio");
2286   EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
2287   const cricket::TransportDescription* video_answer_trans_desc =
2288       answer->GetTransportDescriptionByName("video");
2289   EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
2290   const cricket::TransportDescription* data_answer_trans_desc =
2291       answer->GetTransportDescriptionByName("data");
2292   EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
2293 }
2294 
2295 // Verifies if vad_enabled option is set to false, CN codecs are not present in
2296 // offer or answer.
TEST_F(MediaSessionDescriptionFactoryTest,TestVADEnableOption)2297 TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
2298   MediaSessionOptions options;
2299   options.recv_audio = true;
2300   options.recv_video = true;
2301   rtc::scoped_ptr<SessionDescription> offer(
2302       f1_.CreateOffer(options, NULL));
2303   ASSERT_TRUE(offer.get() != NULL);
2304   const ContentInfo* audio_content = offer->GetContentByName("audio");
2305   EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
2306 
2307   options.vad_enabled = false;
2308   offer.reset(f1_.CreateOffer(options, NULL));
2309   ASSERT_TRUE(offer.get() != NULL);
2310   audio_content = offer->GetContentByName("audio");
2311   EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
2312   rtc::scoped_ptr<SessionDescription> answer(
2313       f1_.CreateAnswer(offer.get(), options, NULL));
2314   ASSERT_TRUE(answer.get() != NULL);
2315   audio_content = answer->GetContentByName("audio");
2316   EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
2317 }
2318 
2319 // Test that the content name ("mid" in SDP) is unchanged when creating a
2320 // new offer.
TEST_F(MediaSessionDescriptionFactoryTest,TestContentNameNotChangedInSubsequentOffers)2321 TEST_F(MediaSessionDescriptionFactoryTest,
2322        TestContentNameNotChangedInSubsequentOffers) {
2323   MediaSessionOptions opts;
2324   opts.recv_audio = true;
2325   opts.recv_video = true;
2326   opts.data_channel_type = cricket::DCT_SCTP;
2327   // Create offer and modify the default content names.
2328   rtc::scoped_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
2329   for (ContentInfo& content : offer->contents()) {
2330     content.name.append("_modified");
2331   }
2332 
2333   rtc::scoped_ptr<SessionDescription> updated_offer(
2334       f1_.CreateOffer(opts, offer.get()));
2335   const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
2336   const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
2337   const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
2338   ASSERT_TRUE(audio_content != nullptr);
2339   ASSERT_TRUE(video_content != nullptr);
2340   ASSERT_TRUE(data_content != nullptr);
2341   EXPECT_EQ("audio_modified", audio_content->name);
2342   EXPECT_EQ("video_modified", video_content->name);
2343   EXPECT_EQ("data_modified", data_content->name);
2344 }
2345