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