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