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