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