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