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