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 |