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