blob: 583362dd4279acb36d611f7c86d194c8259c0333 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
kjellander65c7f672016-02-12 00:05:01 -08002 * Copyright 2004 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
kjellander65c7f672016-02-12 00:05:01 -08004 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00009 */
10
kwiberg31022942016-03-11 14:18:21 -080011#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000012#include <string>
13#include <vector>
14
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "media/base/codec.h"
16#include "media/base/testutils.h"
17#include "p2p/base/p2pconstants.h"
18#include "p2p/base/transportdescription.h"
19#include "p2p/base/transportinfo.h"
20#include "pc/mediasession.h"
21#include "pc/srtpfilter.h"
22#include "rtc_base/checks.h"
23#include "rtc_base/fakesslidentity.h"
24#include "rtc_base/gunit.h"
25#include "rtc_base/messagedigest.h"
26#include "rtc_base/ssladapter.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000027
henrike@webrtc.org28e20752013-07-10 00:45:36 +000028#define ASSERT_CRYPTO(cd, s, cs) \
henrike@webrtc.org28e20752013-07-10 00:45:36 +000029 ASSERT_EQ(s, cd->cryptos().size()); \
30 ASSERT_EQ(std::string(cs), cd->cryptos()[0].cipher_suite)
henrike@webrtc.org28e20752013-07-10 00:45:36 +000031
32typedef std::vector<cricket::Candidate> Candidates;
33
34using cricket::MediaContentDescription;
35using cricket::MediaSessionDescriptionFactory;
ossu075af922016-06-14 03:29:38 -070036using cricket::MediaContentDirection;
zhihuang1c378ed2017-08-17 14:10:50 -070037using cricket::MediaDescriptionOptions;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000038using cricket::MediaSessionOptions;
39using cricket::MediaType;
40using cricket::SessionDescription;
41using cricket::SsrcGroup;
42using cricket::StreamParams;
43using cricket::StreamParamsVec;
44using cricket::TransportDescription;
45using cricket::TransportDescriptionFactory;
46using cricket::TransportInfo;
47using cricket::ContentInfo;
48using cricket::CryptoParamsVec;
49using cricket::AudioContentDescription;
50using cricket::VideoContentDescription;
51using cricket::DataContentDescription;
deadbeef44f08192015-12-15 16:20:09 -080052using cricket::GetFirstAudioContent;
53using cricket::GetFirstVideoContent;
54using cricket::GetFirstDataContent;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000055using cricket::GetFirstAudioContentDescription;
56using cricket::GetFirstVideoContentDescription;
57using cricket::GetFirstDataContentDescription;
58using cricket::kAutoBandwidth;
59using cricket::AudioCodec;
60using cricket::VideoCodec;
61using cricket::DataCodec;
62using cricket::NS_JINGLE_RTP;
63using cricket::MEDIA_TYPE_AUDIO;
64using cricket::MEDIA_TYPE_VIDEO;
65using cricket::MEDIA_TYPE_DATA;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000066using cricket::SEC_DISABLED;
67using cricket::SEC_ENABLED;
68using cricket::SEC_REQUIRED;
zhihuang1c378ed2017-08-17 14:10:50 -070069using cricket::RtpTransceiverDirection;
Guo-wei Shieh456696a2015-09-30 21:48:54 -070070using rtc::CS_AES_CM_128_HMAC_SHA1_32;
71using rtc::CS_AES_CM_128_HMAC_SHA1_80;
jbauchcb560652016-08-04 05:20:32 -070072using rtc::CS_AEAD_AES_128_GCM;
73using rtc::CS_AEAD_AES_256_GCM;
isheriff6f8d6862016-05-26 11:24:55 -070074using webrtc::RtpExtension;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000075
76static const AudioCodec kAudioCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070077 AudioCodec(103, "ISAC", 16000, -1, 1),
78 AudioCodec(102, "iLBC", 8000, 13300, 1),
79 AudioCodec(0, "PCMU", 8000, 64000, 1),
80 AudioCodec(8, "PCMA", 8000, 64000, 1),
81 AudioCodec(117, "red", 8000, 0, 1),
82 AudioCodec(107, "CN", 48000, 0, 1)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +000083
84static const AudioCodec kAudioCodecs2[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070085 AudioCodec(126, "speex", 16000, 22000, 1),
86 AudioCodec(0, "PCMU", 8000, 64000, 1),
87 AudioCodec(127, "iLBC", 8000, 13300, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +000088};
89
90static const AudioCodec kAudioCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070091 AudioCodec(102, "iLBC", 8000, 13300, 1),
92 AudioCodec(0, "PCMU", 8000, 64000, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +000093};
94
perkj26752742016-10-24 01:21:16 -070095static const VideoCodec kVideoCodecs1[] = {VideoCodec(96, "H264-SVC"),
96 VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +000097
zhihuang1c378ed2017-08-17 14:10:50 -070098static const VideoCodec kVideoCodecs1Reverse[] = {VideoCodec(97, "H264"),
99 VideoCodec(96, "H264-SVC")};
100
perkj26752742016-10-24 01:21:16 -0700101static const VideoCodec kVideoCodecs2[] = {VideoCodec(126, "H264"),
102 VideoCodec(127, "H263")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000103
perkj26752742016-10-24 01:21:16 -0700104static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000105
deadbeef67cf2c12016-04-13 10:07:16 -0700106static const DataCodec kDataCodecs1[] = {DataCodec(98, "binary-data"),
107 DataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000108
deadbeef67cf2c12016-04-13 10:07:16 -0700109static const DataCodec kDataCodecs2[] = {DataCodec(126, "binary-data"),
110 DataCodec(127, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000111
deadbeef67cf2c12016-04-13 10:07:16 -0700112static const DataCodec kDataCodecsAnswer[] = {DataCodec(98, "binary-data"),
113 DataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000114
isheriff6f8d6862016-05-26 11:24:55 -0700115static const RtpExtension kAudioRtpExtension1[] = {
116 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
117 RtpExtension("http://google.com/testing/audio_something", 10),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000118};
119
jbauch5869f502017-06-29 12:31:36 -0700120static const RtpExtension kAudioRtpExtensionEncrypted1[] = {
121 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
122 RtpExtension("http://google.com/testing/audio_something", 10),
123 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
124};
125
isheriff6f8d6862016-05-26 11:24:55 -0700126static const RtpExtension kAudioRtpExtension2[] = {
127 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
128 RtpExtension("http://google.com/testing/audio_something_else", 8),
129 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000130};
131
isheriff6f8d6862016-05-26 11:24:55 -0700132static const RtpExtension kAudioRtpExtension3[] = {
133 RtpExtension("http://google.com/testing/audio_something", 2),
134 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
deadbeefa5b273a2015-08-20 17:30:13 -0700135};
136
jbauch5869f502017-06-29 12:31:36 -0700137static const RtpExtension kAudioRtpExtension3ForEncryption[] = {
138 RtpExtension("http://google.com/testing/audio_something", 2),
139 // Use RTP extension that supports encryption.
140 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
141};
142
143static const RtpExtension kAudioRtpExtension3ForEncryptionOffer[] = {
144 RtpExtension("http://google.com/testing/audio_something", 2),
145 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
146 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14, true),
147};
148
isheriff6f8d6862016-05-26 11:24:55 -0700149static const RtpExtension kAudioRtpExtensionAnswer[] = {
150 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000151};
152
jbauch5869f502017-06-29 12:31:36 -0700153static const RtpExtension kAudioRtpExtensionEncryptedAnswer[] = {
154 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
155};
156
isheriff6f8d6862016-05-26 11:24:55 -0700157static const RtpExtension kVideoRtpExtension1[] = {
158 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
159 RtpExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000160};
161
jbauch5869f502017-06-29 12:31:36 -0700162static const RtpExtension kVideoRtpExtensionEncrypted1[] = {
163 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
164 RtpExtension("http://google.com/testing/video_something", 13),
165 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
166};
167
isheriff6f8d6862016-05-26 11:24:55 -0700168static const RtpExtension kVideoRtpExtension2[] = {
169 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
170 RtpExtension("http://google.com/testing/video_something_else", 14),
171 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000172};
173
isheriff6f8d6862016-05-26 11:24:55 -0700174static const RtpExtension kVideoRtpExtension3[] = {
175 RtpExtension("http://google.com/testing/video_something", 4),
176 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
deadbeefa5b273a2015-08-20 17:30:13 -0700177};
178
jbauch5869f502017-06-29 12:31:36 -0700179static const RtpExtension kVideoRtpExtension3ForEncryption[] = {
180 RtpExtension("http://google.com/testing/video_something", 4),
181 // Use RTP extension that supports encryption.
182 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 5),
183};
184
isheriff6f8d6862016-05-26 11:24:55 -0700185static const RtpExtension kVideoRtpExtensionAnswer[] = {
186 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000187};
188
jbauch5869f502017-06-29 12:31:36 -0700189static const RtpExtension kVideoRtpExtensionEncryptedAnswer[] = {
190 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
191};
192
Peter Boström0c4e06b2015-10-07 12:23:21 +0200193static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
194static const uint32_t kSimSsrc[] = {10, 20, 30};
195static const uint32_t kFec1Ssrc[] = {10, 11};
196static const uint32_t kFec2Ssrc[] = {20, 21};
197static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000198
199static const char kMediaStream1[] = "stream_1";
200static const char kMediaStream2[] = "stream_2";
201static const char kVideoTrack1[] = "video_1";
202static const char kVideoTrack2[] = "video_2";
203static const char kAudioTrack1[] = "audio_1";
204static const char kAudioTrack2[] = "audio_2";
205static const char kAudioTrack3[] = "audio_3";
206static const char kDataTrack1[] = "data_1";
207static const char kDataTrack2[] = "data_2";
208static const char kDataTrack3[] = "data_3";
209
zhihuangcf5b37c2016-05-05 11:44:35 -0700210static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
211 "RTP/SAVPF"};
212static const char* kMediaProtocolsDtls[] = {
213 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
214 "UDP/TLS/RTP/SAVP"};
215
zhihuang1c378ed2017-08-17 14:10:50 -0700216// These constants are used to make the code using "AddMediaSection" more
217// readable.
218static constexpr bool kStopped = true;
219static constexpr bool kActive = false;
220
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000221static bool IsMediaContentOfType(const ContentInfo* content,
222 MediaType media_type) {
223 const MediaContentDescription* mdesc =
224 static_cast<const MediaContentDescription*>(content->description);
225 return mdesc && mdesc->type() == media_type;
226}
227
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000228static cricket::MediaContentDirection
229GetMediaDirection(const ContentInfo* content) {
230 cricket::MediaContentDescription* desc =
231 reinterpret_cast<cricket::MediaContentDescription*>(content->description);
232 return desc->direction();
233}
234
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000235static void AddRtxCodec(const VideoCodec& rtx_codec,
236 std::vector<VideoCodec>* codecs) {
magjedb05fa242016-11-11 04:00:16 -0800237 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000238 codecs->push_back(rtx_codec);
239}
240
241template <class T>
242static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
243 std::vector<std::string> codec_names;
244 for (const auto& codec : codecs) {
245 codec_names.push_back(codec.name);
246 }
247 return codec_names;
248}
249
zhihuang1c378ed2017-08-17 14:10:50 -0700250// This is used for test only. MIDs are not the identification of the
251// MediaDescriptionOptions since some end points may not support MID and the SDP
252// may not contain 'mid'.
253std::vector<MediaDescriptionOptions>::iterator FindFirstMediaDescriptionByMid(
254 const std::string& mid,
255 MediaSessionOptions* opts) {
256 return std::find_if(
257 opts->media_description_options.begin(),
258 opts->media_description_options.end(),
Steve Anton36b29d12017-10-30 09:57:42 -0700259 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
260}
261
262std::vector<MediaDescriptionOptions>::const_iterator
263FindFirstMediaDescriptionByMid(const std::string& mid,
264 const MediaSessionOptions& opts) {
265 return std::find_if(
266 opts.media_description_options.begin(),
267 opts.media_description_options.end(),
268 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
zhihuang1c378ed2017-08-17 14:10:50 -0700269}
270
271// Add a media section to the |session_options|.
272static void AddMediaSection(MediaType type,
273 const std::string& mid,
274 MediaContentDirection direction,
275 bool stopped,
276 MediaSessionOptions* opts) {
277 opts->media_description_options.push_back(MediaDescriptionOptions(
278 type, mid,
279 cricket::RtpTransceiverDirection::FromMediaContentDirection(direction),
280 stopped));
281}
282
283static void AddAudioVideoSections(MediaContentDirection direction,
284 MediaSessionOptions* opts) {
285 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", direction, kActive, opts);
286 AddMediaSection(MEDIA_TYPE_VIDEO, "video", direction, kActive, opts);
287}
288
289static void AddDataSection(cricket::DataChannelType dct,
290 MediaContentDirection direction,
291 MediaSessionOptions* opts) {
292 opts->data_channel_type = dct;
293 AddMediaSection(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
294}
295
Steve Anton8ffb9c32017-08-31 15:45:38 -0700296static void AttachSenderToMediaSection(
297 const std::string& mid,
298 MediaType type,
299 const std::string& track_id,
300 const std::vector<std::string>& stream_ids,
301 int num_sim_layer,
302 MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -0700303 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
304 switch (type) {
305 case MEDIA_TYPE_AUDIO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700306 it->AddAudioSender(track_id, stream_ids);
zhihuang1c378ed2017-08-17 14:10:50 -0700307 break;
308 case MEDIA_TYPE_VIDEO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700309 it->AddVideoSender(track_id, stream_ids, num_sim_layer);
zhihuang1c378ed2017-08-17 14:10:50 -0700310 break;
311 case MEDIA_TYPE_DATA:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700312 RTC_CHECK(stream_ids.size() == 1U);
313 it->AddRtpDataChannel(track_id, stream_ids[0]);
zhihuang1c378ed2017-08-17 14:10:50 -0700314 break;
315 default:
316 RTC_NOTREACHED();
317 }
318}
319
320static void DetachSenderFromMediaSection(const std::string& mid,
321 const std::string& track_id,
322 MediaSessionOptions* session_options) {
323 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
324 auto sender_it = it->sender_options.begin();
325 for (; sender_it != it->sender_options.end(); ++sender_it) {
326 if (sender_it->track_id == track_id) {
327 it->sender_options.erase(sender_it);
328 return;
329 }
330 }
331 RTC_NOTREACHED();
332}
333
334// Helper function used to create a default MediaSessionOptions for Plan B SDP.
335// (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
336static MediaSessionOptions CreatePlanBMediaSessionOptions() {
337 MediaSessionOptions session_options;
338 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
339 &session_options);
340 return session_options;
341}
342
343// TODO(zhihuang): Most of these tests were written while MediaSessionOptions
344// was designed for Plan B SDP, where only one audio "m=" section and one video
345// "m=" section could be generated, and ordering couldn't be controlled. Many of
346// these tests may be obsolete as a result, and should be refactored or removed.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000347class MediaSessionDescriptionFactoryTest : public testing::Test {
348 public:
zhihuang1c378ed2017-08-17 14:10:50 -0700349 MediaSessionDescriptionFactoryTest() : f1_(&tdf1_), f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -0700350 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
351 MAKE_VECTOR(kAudioCodecs1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000352 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
353 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700354 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
355 MAKE_VECTOR(kAudioCodecs2));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000356 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
357 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200358 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700359 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200360 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700361 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000362 }
363
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000364 // Create a video StreamParamsVec object with:
365 // - one video stream with 3 simulcast streams and FEC,
366 StreamParamsVec CreateComplexVideoStreamParamsVec() {
367 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
368 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
369 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
370 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
371
372 std::vector<SsrcGroup> ssrc_groups;
373 ssrc_groups.push_back(sim_group);
374 ssrc_groups.push_back(fec_group1);
375 ssrc_groups.push_back(fec_group2);
376 ssrc_groups.push_back(fec_group3);
377
378 StreamParams simulcast_params;
379 simulcast_params.id = kVideoTrack1;
380 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
381 simulcast_params.ssrc_groups = ssrc_groups;
382 simulcast_params.cname = "Video_SIM_FEC";
383 simulcast_params.sync_label = kMediaStream1;
384
385 StreamParamsVec video_streams;
386 video_streams.push_back(simulcast_params);
387
388 return video_streams;
389 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000390
391 bool CompareCryptoParams(const CryptoParamsVec& c1,
392 const CryptoParamsVec& c2) {
393 if (c1.size() != c2.size())
394 return false;
395 for (size_t i = 0; i < c1.size(); ++i)
396 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
397 c1[i].key_params != c2[i].key_params ||
398 c1[i].session_params != c2[i].session_params)
399 return false;
400 return true;
401 }
402
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700403 // Returns true if the transport info contains "renomination" as an
404 // ICE option.
405 bool GetIceRenomination(const TransportInfo* transport_info) {
406 const std::vector<std::string>& ice_options =
407 transport_info->description.transport_options;
deadbeef30952b42017-04-21 02:41:29 -0700408 auto iter =
409 std::find(ice_options.begin(), ice_options.end(), "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700410 return iter != ice_options.end();
411 }
412
zhihuang1c378ed2017-08-17 14:10:50 -0700413 void TestTransportInfo(bool offer,
Steve Anton36b29d12017-10-30 09:57:42 -0700414 const MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000415 bool has_current_desc) {
416 const std::string current_audio_ufrag = "current_audio_ufrag";
417 const std::string current_audio_pwd = "current_audio_pwd";
418 const std::string current_video_ufrag = "current_video_ufrag";
419 const std::string current_video_pwd = "current_video_pwd";
420 const std::string current_data_ufrag = "current_data_ufrag";
421 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800422 std::unique_ptr<SessionDescription> current_desc;
423 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000424 if (has_current_desc) {
425 current_desc.reset(new SessionDescription());
426 EXPECT_TRUE(current_desc->AddTransportInfo(
427 TransportInfo("audio",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700428 TransportDescription(current_audio_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000429 current_audio_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000430 EXPECT_TRUE(current_desc->AddTransportInfo(
431 TransportInfo("video",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700432 TransportDescription(current_video_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000433 current_video_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000434 EXPECT_TRUE(current_desc->AddTransportInfo(
435 TransportInfo("data",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700436 TransportDescription(current_data_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000437 current_data_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000438 }
439 if (offer) {
440 desc.reset(f1_.CreateOffer(options, current_desc.get()));
441 } else {
kwiberg31022942016-03-11 14:18:21 -0800442 std::unique_ptr<SessionDescription> offer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000443 offer.reset(f1_.CreateOffer(options, NULL));
444 desc.reset(f1_.CreateAnswer(offer.get(), options, current_desc.get()));
445 }
446 ASSERT_TRUE(desc.get() != NULL);
447 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000448 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000449 EXPECT_TRUE(ti_audio != NULL);
450 if (has_current_desc) {
451 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
452 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
453 } else {
454 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
455 ti_audio->description.ice_ufrag.size());
456 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
457 ti_audio->description.ice_pwd.size());
458 }
zhihuang1c378ed2017-08-17 14:10:50 -0700459 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700460 FindFirstMediaDescriptionByMid("audio", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700461 EXPECT_EQ(
462 media_desc_options_it->transport_options.enable_ice_renomination,
463 GetIceRenomination(ti_audio));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000464
465 } else {
466 EXPECT_TRUE(ti_audio == NULL);
467 }
468 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000469 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000470 EXPECT_TRUE(ti_video != NULL);
471 if (options.bundle_enabled) {
472 EXPECT_EQ(ti_audio->description.ice_ufrag,
473 ti_video->description.ice_ufrag);
474 EXPECT_EQ(ti_audio->description.ice_pwd,
475 ti_video->description.ice_pwd);
476 } else {
477 if (has_current_desc) {
478 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
479 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
480 } else {
481 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
482 ti_video->description.ice_ufrag.size());
483 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
484 ti_video->description.ice_pwd.size());
485 }
486 }
zhihuang1c378ed2017-08-17 14:10:50 -0700487 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700488 FindFirstMediaDescriptionByMid("video", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700489 EXPECT_EQ(
490 media_desc_options_it->transport_options.enable_ice_renomination,
491 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000492 } else {
493 EXPECT_TRUE(ti_video == NULL);
494 }
495 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
496 if (options.has_data()) {
497 EXPECT_TRUE(ti_data != NULL);
498 if (options.bundle_enabled) {
499 EXPECT_EQ(ti_audio->description.ice_ufrag,
500 ti_data->description.ice_ufrag);
501 EXPECT_EQ(ti_audio->description.ice_pwd,
502 ti_data->description.ice_pwd);
503 } else {
504 if (has_current_desc) {
505 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
506 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
507 } else {
508 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
509 ti_data->description.ice_ufrag.size());
510 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
511 ti_data->description.ice_pwd.size());
512 }
513 }
zhihuang1c378ed2017-08-17 14:10:50 -0700514 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700515 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700516 EXPECT_EQ(
517 media_desc_options_it->transport_options.enable_ice_renomination,
518 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700519
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000520 } else {
521 EXPECT_TRUE(ti_video == NULL);
522 }
523 }
524
525 void TestCryptoWithBundle(bool offer) {
526 f1_.set_secure(SEC_ENABLED);
527 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -0700528 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
529 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
kwiberg31022942016-03-11 14:18:21 -0800530 std::unique_ptr<SessionDescription> ref_desc;
531 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000532 if (offer) {
533 options.bundle_enabled = false;
534 ref_desc.reset(f1_.CreateOffer(options, NULL));
535 options.bundle_enabled = true;
536 desc.reset(f1_.CreateOffer(options, ref_desc.get()));
537 } else {
538 options.bundle_enabled = true;
539 ref_desc.reset(f1_.CreateOffer(options, NULL));
540 desc.reset(f1_.CreateAnswer(ref_desc.get(), options, NULL));
541 }
542 ASSERT_TRUE(desc.get() != NULL);
543 const cricket::MediaContentDescription* audio_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000544 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000545 desc.get()->GetContentDescriptionByName("audio"));
546 ASSERT_TRUE(audio_media_desc != NULL);
547 const cricket::MediaContentDescription* video_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000548 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000549 desc.get()->GetContentDescriptionByName("video"));
550 ASSERT_TRUE(video_media_desc != NULL);
551 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
552 video_media_desc->cryptos()));
553 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
554 EXPECT_EQ(std::string(CS_AES_CM_128_HMAC_SHA1_80),
555 audio_media_desc->cryptos()[0].cipher_suite);
556
557 // Verify the selected crypto is one from the reference audio
558 // media content.
559 const cricket::MediaContentDescription* ref_audio_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000560 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000561 ref_desc.get()->GetContentDescriptionByName("audio"));
562 bool found = false;
563 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
564 if (ref_audio_media_desc->cryptos()[i].Matches(
565 audio_media_desc->cryptos()[0])) {
566 found = true;
567 break;
568 }
569 }
570 EXPECT_TRUE(found);
571 }
572
573 // This test that the audio and video media direction is set to
574 // |expected_direction_in_answer| in an answer if the offer direction is set
zhihuang1c378ed2017-08-17 14:10:50 -0700575 // to |direction_in_offer| and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000576 void TestMediaDirectionInAnswer(
577 cricket::MediaContentDirection direction_in_offer,
578 cricket::MediaContentDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700579 MediaSessionOptions offer_opts;
580 AddAudioVideoSections(direction_in_offer, &offer_opts);
581
582 std::unique_ptr<SessionDescription> offer(
583 f1_.CreateOffer(offer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000584 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700585 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000586 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700587 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000588 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000589
zhihuang1c378ed2017-08-17 14:10:50 -0700590 MediaSessionOptions answer_opts;
591 AddAudioVideoSections(cricket::MD_SENDRECV, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -0800592 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -0700593 f2_.CreateAnswer(offer.get(), answer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000594 const AudioContentDescription* acd_answer =
595 GetFirstAudioContentDescription(answer.get());
596 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
597 const VideoContentDescription* vcd_answer =
598 GetFirstVideoContentDescription(answer.get());
599 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
600 }
601
602 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
603 const cricket::ContentDescription* description = content->description;
nissec8ee8822017-01-18 07:20:55 -0800604 RTC_CHECK(description != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000605 const cricket::AudioContentDescription* audio_content_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000606 static_cast<const cricket::AudioContentDescription*>(description);
nissec8ee8822017-01-18 07:20:55 -0800607 RTC_CHECK(audio_content_desc != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000608 for (size_t i = 0; i < audio_content_desc->codecs().size(); ++i) {
609 if (audio_content_desc->codecs()[i].name == "CN")
610 return false;
611 }
612 return true;
613 }
614
jbauchcb560652016-08-04 05:20:32 -0700615 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
616 MediaSessionOptions offer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -0700617 AddAudioVideoSections(cricket::MD_RECVONLY, &offer_opts);
jbauchcb560652016-08-04 05:20:32 -0700618 offer_opts.crypto_options.enable_gcm_crypto_suites = gcm_offer;
zhihuang1c378ed2017-08-17 14:10:50 -0700619
jbauchcb560652016-08-04 05:20:32 -0700620 MediaSessionOptions answer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -0700621 AddAudioVideoSections(cricket::MD_RECVONLY, &answer_opts);
jbauchcb560652016-08-04 05:20:32 -0700622 answer_opts.crypto_options.enable_gcm_crypto_suites = gcm_answer;
zhihuang1c378ed2017-08-17 14:10:50 -0700623
jbauchcb560652016-08-04 05:20:32 -0700624 f1_.set_secure(SEC_ENABLED);
625 f2_.set_secure(SEC_ENABLED);
626 std::unique_ptr<SessionDescription> offer(
627 f1_.CreateOffer(offer_opts, NULL));
628 ASSERT_TRUE(offer.get() != NULL);
629 std::unique_ptr<SessionDescription> answer(
630 f2_.CreateAnswer(offer.get(), answer_opts, NULL));
631 const ContentInfo* ac = answer->GetContentByName("audio");
632 const ContentInfo* vc = answer->GetContentByName("video");
633 ASSERT_TRUE(ac != NULL);
634 ASSERT_TRUE(vc != NULL);
635 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
636 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
637 const AudioContentDescription* acd =
638 static_cast<const AudioContentDescription*>(ac->description);
639 const VideoContentDescription* vcd =
640 static_cast<const VideoContentDescription*>(vc->description);
641 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
642 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
643 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700644 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700645 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
646 if (gcm_offer && gcm_answer) {
647 ASSERT_CRYPTO(acd, 1U, CS_AEAD_AES_256_GCM);
648 } else {
649 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
650 }
651 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
652 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700653 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700654 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
655 if (gcm_offer && gcm_answer) {
656 ASSERT_CRYPTO(vcd, 1U, CS_AEAD_AES_256_GCM);
657 } else {
658 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
659 }
660 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
661 }
662
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000663 protected:
664 MediaSessionDescriptionFactory f1_;
665 MediaSessionDescriptionFactory f2_;
666 TransportDescriptionFactory tdf1_;
667 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000668};
669
670// Create a typical audio offer, and ensure it matches what we expect.
671TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
672 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800673 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -0700674 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000675 ASSERT_TRUE(offer.get() != NULL);
676 const ContentInfo* ac = offer->GetContentByName("audio");
677 const ContentInfo* vc = offer->GetContentByName("video");
678 ASSERT_TRUE(ac != NULL);
679 ASSERT_TRUE(vc == NULL);
680 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
681 const AudioContentDescription* acd =
682 static_cast<const AudioContentDescription*>(ac->description);
683 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700684 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700685 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000686 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
687 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
688 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
689 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
690}
691
692// Create a typical video offer, and ensure it matches what we expect.
693TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
694 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -0700695 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000696 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800697 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000698 ASSERT_TRUE(offer.get() != NULL);
699 const ContentInfo* ac = offer->GetContentByName("audio");
700 const ContentInfo* vc = offer->GetContentByName("video");
701 ASSERT_TRUE(ac != NULL);
702 ASSERT_TRUE(vc != NULL);
703 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
704 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
705 const AudioContentDescription* acd =
706 static_cast<const AudioContentDescription*>(ac->description);
707 const VideoContentDescription* vcd =
708 static_cast<const VideoContentDescription*>(vc->description);
709 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700710 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700711 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000712 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
713 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
714 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
715 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
716 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
717 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700718 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000719 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
720 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
721 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
722 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
723}
724
725// Test creating an offer with bundle where the Codecs have the same dynamic
726// RTP playlod type. The test verifies that the offer don't contain the
727// duplicate RTP payload types.
728TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
729 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700730 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000731 const DataCodec& offered_data_codec = f2_.data_codecs()[0];
732 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
733 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
734
735 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -0700736 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
737 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000738 opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800739 std::unique_ptr<SessionDescription> offer(f2_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000740 const VideoContentDescription* vcd =
741 GetFirstVideoContentDescription(offer.get());
742 const AudioContentDescription* acd =
743 GetFirstAudioContentDescription(offer.get());
744 const DataContentDescription* dcd =
745 GetFirstDataContentDescription(offer.get());
746 ASSERT_TRUE(NULL != vcd);
747 ASSERT_TRUE(NULL != acd);
748 ASSERT_TRUE(NULL != dcd);
749 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
750 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
751 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
752 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
753 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
754 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
755}
756
zhihuang1c378ed2017-08-17 14:10:50 -0700757// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000758// after an audio only session has been negotiated.
759TEST_F(MediaSessionDescriptionFactoryTest,
760 TestCreateUpdatedVideoOfferWithBundle) {
761 f1_.set_secure(SEC_ENABLED);
762 f2_.set_secure(SEC_ENABLED);
763 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -0700764 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
765 &opts);
766 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_INACTIVE, kStopped,
767 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000768 opts.data_channel_type = cricket::DCT_NONE;
769 opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800770 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
771 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000772 f2_.CreateAnswer(offer.get(), opts, NULL));
773
774 MediaSessionOptions updated_opts;
zhihuang1c378ed2017-08-17 14:10:50 -0700775 AddAudioVideoSections(cricket::MD_RECVONLY, &updated_opts);
776 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000777 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800778 std::unique_ptr<SessionDescription> updated_offer(
779 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000780
781 const AudioContentDescription* acd =
782 GetFirstAudioContentDescription(updated_offer.get());
783 const VideoContentDescription* vcd =
784 GetFirstVideoContentDescription(updated_offer.get());
785 const DataContentDescription* dcd =
786 GetFirstDataContentDescription(updated_offer.get());
787 EXPECT_TRUE(NULL != vcd);
788 EXPECT_TRUE(NULL != acd);
789 EXPECT_TRUE(NULL != dcd);
790
791 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
792 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
793 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
794 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
795 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
796 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
797}
deadbeef44f08192015-12-15 16:20:09 -0800798
wu@webrtc.org78187522013-10-07 23:32:02 +0000799// Create a RTP data offer, and ensure it matches what we expect.
800TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000801 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -0700802 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
803 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000804 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800805 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000806 ASSERT_TRUE(offer.get() != NULL);
807 const ContentInfo* ac = offer->GetContentByName("audio");
808 const ContentInfo* dc = offer->GetContentByName("data");
809 ASSERT_TRUE(ac != NULL);
810 ASSERT_TRUE(dc != NULL);
811 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
812 EXPECT_EQ(std::string(NS_JINGLE_RTP), dc->type);
813 const AudioContentDescription* acd =
814 static_cast<const AudioContentDescription*>(ac->description);
815 const DataContentDescription* dcd =
816 static_cast<const DataContentDescription*>(dc->description);
817 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700818 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700819 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000820 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
821 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
822 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
823 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
824 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
825 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700826 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000827 EXPECT_EQ(cricket::kDataMaxBandwidth,
828 dcd->bandwidth()); // default bandwidth (auto)
829 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
830 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
831 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
832}
833
wu@webrtc.org78187522013-10-07 23:32:02 +0000834// Create an SCTP data offer with bundle without error.
835TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
836 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000837 opts.bundle_enabled = true;
zhihuang1c378ed2017-08-17 14:10:50 -0700838 AddDataSection(cricket::DCT_SCTP, cricket::MD_SENDRECV, &opts);
wu@webrtc.org78187522013-10-07 23:32:02 +0000839 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800840 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
wu@webrtc.org78187522013-10-07 23:32:02 +0000841 EXPECT_TRUE(offer.get() != NULL);
842 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
843}
844
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000845// Test creating an sctp data channel from an already generated offer.
846TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
847 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000848 opts.bundle_enabled = true;
zhihuang1c378ed2017-08-17 14:10:50 -0700849 AddDataSection(cricket::DCT_SCTP, cricket::MD_SENDRECV, &opts);
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000850 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800851 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000852 ASSERT_TRUE(offer1.get() != NULL);
853 const ContentInfo* data = offer1->GetContentByName("data");
854 ASSERT_TRUE(data != NULL);
855 const MediaContentDescription* mdesc =
856 static_cast<const MediaContentDescription*>(data->description);
857 ASSERT_EQ(cricket::kMediaProtocolSctp, mdesc->protocol());
858
859 // Now set data_channel_type to 'none' (default) and make sure that the
860 // datachannel type that gets generated from the previous offer, is of the
861 // same type.
862 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800863 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000864 f1_.CreateOffer(opts, offer1.get()));
865 data = offer2->GetContentByName("data");
866 ASSERT_TRUE(data != NULL);
867 mdesc = static_cast<const MediaContentDescription*>(data->description);
868 EXPECT_EQ(cricket::kMediaProtocolSctp, mdesc->protocol());
869}
870
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000871// Create an audio, video offer without legacy StreamParams.
872TEST_F(MediaSessionDescriptionFactoryTest,
873 TestCreateOfferWithoutLegacyStreams) {
874 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -0700875 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
kwiberg31022942016-03-11 14:18:21 -0800876 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000877 ASSERT_TRUE(offer.get() != NULL);
878 const ContentInfo* ac = offer->GetContentByName("audio");
879 const ContentInfo* vc = offer->GetContentByName("video");
880 ASSERT_TRUE(ac != NULL);
881 ASSERT_TRUE(vc != NULL);
882 const AudioContentDescription* acd =
883 static_cast<const AudioContentDescription*>(ac->description);
884 const VideoContentDescription* vcd =
885 static_cast<const VideoContentDescription*>(vc->description);
886
887 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
888 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
889}
890
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000891// Creates an audio+video sendonly offer.
892TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700893 MediaSessionOptions opts;
894 AddAudioVideoSections(cricket::MD_SENDONLY, &opts);
895 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700896 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700897 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700898 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000899
zhihuang1c378ed2017-08-17 14:10:50 -0700900 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000901 ASSERT_TRUE(offer.get() != NULL);
902 EXPECT_EQ(2u, offer->contents().size());
903 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
904 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
905
906 EXPECT_EQ(cricket::MD_SENDONLY, GetMediaDirection(&offer->contents()[0]));
907 EXPECT_EQ(cricket::MD_SENDONLY, GetMediaDirection(&offer->contents()[1]));
908}
909
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000910// Verifies that the order of the media contents in the current
911// SessionDescription is preserved in the new SessionDescription.
912TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
913 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -0700914 AddDataSection(cricket::DCT_SCTP, cricket::MD_SENDRECV, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000915
kwiberg31022942016-03-11 14:18:21 -0800916 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000917 ASSERT_TRUE(offer1.get() != NULL);
918 EXPECT_EQ(1u, offer1->contents().size());
919 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
920
zhihuang1c378ed2017-08-17 14:10:50 -0700921 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
922 &opts);
kwiberg31022942016-03-11 14:18:21 -0800923 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000924 f1_.CreateOffer(opts, offer1.get()));
925 ASSERT_TRUE(offer2.get() != NULL);
926 EXPECT_EQ(2u, offer2->contents().size());
927 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
928 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
929
zhihuang1c378ed2017-08-17 14:10:50 -0700930 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
931 &opts);
kwiberg31022942016-03-11 14:18:21 -0800932 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000933 f1_.CreateOffer(opts, offer2.get()));
934 ASSERT_TRUE(offer3.get() != NULL);
935 EXPECT_EQ(3u, offer3->contents().size());
936 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
937 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
938 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000939}
940
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000941// Create a typical audio answer, and ensure it matches what we expect.
942TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
943 f1_.set_secure(SEC_ENABLED);
944 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800945 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -0700946 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000947 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800948 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -0700949 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000950 const ContentInfo* ac = answer->GetContentByName("audio");
951 const ContentInfo* vc = answer->GetContentByName("video");
952 ASSERT_TRUE(ac != NULL);
953 ASSERT_TRUE(vc == NULL);
954 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
955 const AudioContentDescription* acd =
956 static_cast<const AudioContentDescription*>(ac->description);
957 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
958 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700959 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000960 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
961 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
962 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
963 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
964}
965
jbauchcb560652016-08-04 05:20:32 -0700966// Create a typical audio answer with GCM ciphers enabled, and ensure it
967// matches what we expect.
968TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
969 f1_.set_secure(SEC_ENABLED);
970 f2_.set_secure(SEC_ENABLED);
zhihuang1c378ed2017-08-17 14:10:50 -0700971 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
972 opts.crypto_options.enable_gcm_crypto_suites = true;
973 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
jbauchcb560652016-08-04 05:20:32 -0700974 ASSERT_TRUE(offer.get() != NULL);
975 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -0700976 f2_.CreateAnswer(offer.get(), opts, NULL));
jbauchcb560652016-08-04 05:20:32 -0700977 const ContentInfo* ac = answer->GetContentByName("audio");
978 const ContentInfo* vc = answer->GetContentByName("video");
979 ASSERT_TRUE(ac != NULL);
980 ASSERT_TRUE(vc == NULL);
981 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
982 const AudioContentDescription* acd =
983 static_cast<const AudioContentDescription*>(ac->description);
984 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
985 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700986 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700987 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
988 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
989 ASSERT_CRYPTO(acd, 1U, CS_AEAD_AES_256_GCM);
990 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
991}
992
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000993// Create a typical video answer, and ensure it matches what we expect.
994TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
995 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -0700996 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000997 f1_.set_secure(SEC_ENABLED);
998 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800999 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001000 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001001 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001002 f2_.CreateAnswer(offer.get(), opts, NULL));
1003 const ContentInfo* ac = answer->GetContentByName("audio");
1004 const ContentInfo* vc = answer->GetContentByName("video");
1005 ASSERT_TRUE(ac != NULL);
1006 ASSERT_TRUE(vc != NULL);
1007 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
1008 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
1009 const AudioContentDescription* acd =
1010 static_cast<const AudioContentDescription*>(ac->description);
1011 const VideoContentDescription* vcd =
1012 static_cast<const VideoContentDescription*>(vc->description);
1013 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1014 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1015 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001016 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001017 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
1018 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1019 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1020 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -07001021 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001022 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
1023 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1024 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
1025}
1026
jbauchcb560652016-08-04 05:20:32 -07001027// Create a typical video answer with GCM ciphers enabled, and ensure it
1028// matches what we expect.
1029TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1030 TestVideoGcmCipher(true, true);
1031}
1032
1033// Create a typical video answer with GCM ciphers enabled for the offer only,
1034// and ensure it matches what we expect.
1035TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1036 TestVideoGcmCipher(true, false);
1037}
1038
1039// Create a typical video answer with GCM ciphers enabled for the answer only,
1040// and ensure it matches what we expect.
1041TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1042 TestVideoGcmCipher(false, true);
1043}
1044
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001045TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001046 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
1047 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001048 f1_.set_secure(SEC_ENABLED);
1049 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001050 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001051 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001052 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001053 f2_.CreateAnswer(offer.get(), opts, NULL));
1054 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001055 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001056 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001057 ASSERT_TRUE(dc != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001058 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
zstein4b2e0822017-02-17 19:48:38 -08001059 EXPECT_EQ(std::string(NS_JINGLE_RTP), dc->type);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001060 const AudioContentDescription* acd =
1061 static_cast<const AudioContentDescription*>(ac->description);
zstein4b2e0822017-02-17 19:48:38 -08001062 const DataContentDescription* dcd =
1063 static_cast<const DataContentDescription*>(dc->description);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001064 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1065 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1066 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001067 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001068 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
1069 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
zstein4b2e0822017-02-17 19:48:38 -08001070 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1071 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -07001072 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001073 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
1074 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1075 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001076}
1077
jbauchcb560652016-08-04 05:20:32 -07001078TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
zhihuang1c378ed2017-08-17 14:10:50 -07001079 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
1080 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &opts);
jbauchcb560652016-08-04 05:20:32 -07001081 opts.crypto_options.enable_gcm_crypto_suites = true;
1082 f1_.set_secure(SEC_ENABLED);
1083 f2_.set_secure(SEC_ENABLED);
1084 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1085 ASSERT_TRUE(offer.get() != NULL);
1086 std::unique_ptr<SessionDescription> answer(
1087 f2_.CreateAnswer(offer.get(), opts, NULL));
1088 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001089 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -07001090 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001091 ASSERT_TRUE(dc != NULL);
jbauchcb560652016-08-04 05:20:32 -07001092 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
zstein4b2e0822017-02-17 19:48:38 -08001093 EXPECT_EQ(std::string(NS_JINGLE_RTP), dc->type);
jbauchcb560652016-08-04 05:20:32 -07001094 const AudioContentDescription* acd =
1095 static_cast<const AudioContentDescription*>(ac->description);
zstein4b2e0822017-02-17 19:48:38 -08001096 const DataContentDescription* dcd =
1097 static_cast<const DataContentDescription*>(dc->description);
jbauchcb560652016-08-04 05:20:32 -07001098 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1099 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1100 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001101 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001102 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
1103 ASSERT_CRYPTO(acd, 1U, CS_AEAD_AES_256_GCM);
zstein4b2e0822017-02-17 19:48:38 -08001104 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1105 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -07001106 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001107 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
1108 ASSERT_CRYPTO(dcd, 1U, CS_AEAD_AES_256_GCM);
1109 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
1110}
1111
1112// The use_sctpmap flag should be set in a DataContentDescription by default.
1113// The answer's use_sctpmap flag should match the offer's.
1114TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1115 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001116 AddDataSection(cricket::DCT_SCTP, cricket::MD_SENDRECV, &opts);
zstein4b2e0822017-02-17 19:48:38 -08001117 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1118 ASSERT_TRUE(offer.get() != NULL);
1119 ContentInfo* dc_offer = offer->GetContentByName("data");
1120 ASSERT_TRUE(dc_offer != NULL);
1121 DataContentDescription* dcd_offer =
1122 static_cast<DataContentDescription*>(dc_offer->description);
1123 EXPECT_TRUE(dcd_offer->use_sctpmap());
1124
1125 std::unique_ptr<SessionDescription> answer(
1126 f2_.CreateAnswer(offer.get(), opts, NULL));
1127 const ContentInfo* dc_answer = answer->GetContentByName("data");
1128 ASSERT_TRUE(dc_answer != NULL);
1129 const DataContentDescription* dcd_answer =
1130 static_cast<const DataContentDescription*>(dc_answer->description);
1131 EXPECT_TRUE(dcd_answer->use_sctpmap());
1132}
1133
1134// The answer's use_sctpmap flag should match the offer's.
1135TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1136 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001137 AddDataSection(cricket::DCT_SCTP, cricket::MD_SENDRECV, &opts);
zstein4b2e0822017-02-17 19:48:38 -08001138 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1139 ASSERT_TRUE(offer.get() != NULL);
1140 ContentInfo* dc_offer = offer->GetContentByName("data");
1141 ASSERT_TRUE(dc_offer != NULL);
1142 DataContentDescription* dcd_offer =
1143 static_cast<DataContentDescription*>(dc_offer->description);
1144 dcd_offer->set_use_sctpmap(false);
1145
1146 std::unique_ptr<SessionDescription> answer(
1147 f2_.CreateAnswer(offer.get(), opts, NULL));
1148 const ContentInfo* dc_answer = answer->GetContentByName("data");
1149 ASSERT_TRUE(dc_answer != NULL);
1150 const DataContentDescription* dcd_answer =
1151 static_cast<const DataContentDescription*>(dc_answer->description);
1152 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001153}
1154
deadbeef8b7e9ad2017-05-25 09:38:55 -07001155// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1156// and "TCP/DTLS/SCTP" offers.
1157TEST_F(MediaSessionDescriptionFactoryTest,
1158 TestCreateDataAnswerToDifferentOfferedProtos) {
1159 // Need to enable DTLS offer/answer generation (disabled by default in this
1160 // test).
1161 f1_.set_secure(SEC_ENABLED);
1162 f2_.set_secure(SEC_ENABLED);
1163 tdf1_.set_secure(SEC_ENABLED);
1164 tdf2_.set_secure(SEC_ENABLED);
1165
1166 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001167 AddDataSection(cricket::DCT_SCTP, cricket::MD_SENDRECV, &opts);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001168 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
1169 ASSERT_TRUE(offer.get() != nullptr);
1170 ContentInfo* dc_offer = offer->GetContentByName("data");
1171 ASSERT_TRUE(dc_offer != nullptr);
1172 DataContentDescription* dcd_offer =
1173 static_cast<DataContentDescription*>(dc_offer->description);
1174
1175 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1176 "TCP/DTLS/SCTP"};
1177 for (const std::string& proto : protos) {
1178 dcd_offer->set_protocol(proto);
1179 std::unique_ptr<SessionDescription> answer(
1180 f2_.CreateAnswer(offer.get(), opts, nullptr));
1181 const ContentInfo* dc_answer = answer->GetContentByName("data");
1182 ASSERT_TRUE(dc_answer != nullptr);
1183 const DataContentDescription* dcd_answer =
1184 static_cast<const DataContentDescription*>(dc_answer->description);
1185 EXPECT_FALSE(dc_answer->rejected);
1186 EXPECT_EQ(proto, dcd_answer->protocol());
1187 }
1188}
1189
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001190// Verifies that the order of the media contents in the offer is preserved in
1191// the answer.
1192TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1193 MediaSessionOptions opts;
1194
1195 // Creates a data only offer.
zhihuang1c378ed2017-08-17 14:10:50 -07001196 AddDataSection(cricket::DCT_SCTP, cricket::MD_SENDRECV, &opts);
kwiberg31022942016-03-11 14:18:21 -08001197 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001198 ASSERT_TRUE(offer1.get() != NULL);
1199
1200 // Appends audio to the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07001201 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
1202 &opts);
kwiberg31022942016-03-11 14:18:21 -08001203 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001204 f1_.CreateOffer(opts, offer1.get()));
1205 ASSERT_TRUE(offer2.get() != NULL);
1206
1207 // Appends video to the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07001208 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
1209 &opts);
kwiberg31022942016-03-11 14:18:21 -08001210 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001211 f1_.CreateOffer(opts, offer2.get()));
1212 ASSERT_TRUE(offer3.get() != NULL);
1213
kwiberg31022942016-03-11 14:18:21 -08001214 std::unique_ptr<SessionDescription> answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001215 f2_.CreateAnswer(offer3.get(), opts, NULL));
1216 ASSERT_TRUE(answer.get() != NULL);
1217 EXPECT_EQ(3u, answer->contents().size());
1218 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1219 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1220 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1221}
1222
ossu075af922016-06-14 03:29:38 -07001223// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1224// answerer settings.
1225
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001226// This test that the media direction is set to send/receive in an answer if
1227// the offer is send receive.
1228TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
1229 TestMediaDirectionInAnswer(cricket::MD_SENDRECV, cricket::MD_SENDRECV);
1230}
1231
1232// This test that the media direction is set to receive only in an answer if
1233// the offer is send only.
1234TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
1235 TestMediaDirectionInAnswer(cricket::MD_SENDONLY, cricket::MD_RECVONLY);
1236}
1237
1238// This test that the media direction is set to send only in an answer if
1239// the offer is recv only.
1240TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
1241 TestMediaDirectionInAnswer(cricket::MD_RECVONLY, cricket::MD_SENDONLY);
1242}
1243
1244// This test that the media direction is set to inactive in an answer if
1245// the offer is inactive.
1246TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
1247 TestMediaDirectionInAnswer(cricket::MD_INACTIVE, cricket::MD_INACTIVE);
1248}
1249
1250// Test that a data content with an unknown protocol is rejected in an answer.
1251TEST_F(MediaSessionDescriptionFactoryTest,
1252 CreateDataAnswerToOfferWithUnknownProtocol) {
1253 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001254 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001255 f1_.set_secure(SEC_ENABLED);
1256 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001257 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
terelius8c011e52016-04-26 05:28:11 -07001258 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001259 ASSERT_TRUE(dc_offer != NULL);
1260 DataContentDescription* dcd_offer =
1261 static_cast<DataContentDescription*>(dc_offer->description);
1262 ASSERT_TRUE(dcd_offer != NULL);
1263 std::string protocol = "a weird unknown protocol";
1264 dcd_offer->set_protocol(protocol);
1265
kwiberg31022942016-03-11 14:18:21 -08001266 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001267 f2_.CreateAnswer(offer.get(), opts, NULL));
1268
1269 const ContentInfo* dc_answer = answer->GetContentByName("data");
1270 ASSERT_TRUE(dc_answer != NULL);
1271 EXPECT_TRUE(dc_answer->rejected);
1272 const DataContentDescription* dcd_answer =
1273 static_cast<const DataContentDescription*>(dc_answer->description);
1274 ASSERT_TRUE(dcd_answer != NULL);
1275 EXPECT_EQ(protocol, dcd_answer->protocol());
1276}
1277
1278// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1279TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001280 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001281 f1_.set_secure(SEC_DISABLED);
1282 f2_.set_secure(SEC_DISABLED);
1283 tdf1_.set_secure(SEC_DISABLED);
1284 tdf2_.set_secure(SEC_DISABLED);
1285
kwiberg31022942016-03-11 14:18:21 -08001286 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001287 const AudioContentDescription* offer_acd =
1288 GetFirstAudioContentDescription(offer.get());
1289 ASSERT_TRUE(offer_acd != NULL);
1290 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), offer_acd->protocol());
1291
kwiberg31022942016-03-11 14:18:21 -08001292 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001293 f2_.CreateAnswer(offer.get(), opts, NULL));
1294
1295 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1296 ASSERT_TRUE(ac_answer != NULL);
1297 EXPECT_FALSE(ac_answer->rejected);
1298
1299 const AudioContentDescription* answer_acd =
1300 GetFirstAudioContentDescription(answer.get());
1301 ASSERT_TRUE(answer_acd != NULL);
1302 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), answer_acd->protocol());
1303}
1304
1305// Create a video offer and answer and ensure the RTP header extensions
1306// matches what we expect.
1307TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1308 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001309 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001310 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1311 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1312 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1313 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1314
kwiberg31022942016-03-11 14:18:21 -08001315 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001316 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001317 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001318 f2_.CreateAnswer(offer.get(), opts, NULL));
1319
1320 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension1),
1321 GetFirstAudioContentDescription(
1322 offer.get())->rtp_header_extensions());
1323 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtension1),
1324 GetFirstVideoContentDescription(
1325 offer.get())->rtp_header_extensions());
1326 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
1327 GetFirstAudioContentDescription(
1328 answer.get())->rtp_header_extensions());
1329 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
1330 GetFirstVideoContentDescription(
1331 answer.get())->rtp_header_extensions());
1332}
1333
jbauch5869f502017-06-29 12:31:36 -07001334TEST_F(MediaSessionDescriptionFactoryTest,
1335 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
1336 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001337 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
jbauch5869f502017-06-29 12:31:36 -07001338
1339 f1_.set_enable_encrypted_rtp_header_extensions(true);
1340 f2_.set_enable_encrypted_rtp_header_extensions(true);
1341
1342 f1_.set_audio_rtp_header_extensions(
1343 MAKE_VECTOR(kAudioRtpExtension1));
1344 f1_.set_video_rtp_header_extensions(
1345 MAKE_VECTOR(kVideoRtpExtension1));
1346 f2_.set_audio_rtp_header_extensions(
1347 MAKE_VECTOR(kAudioRtpExtension2));
1348 f2_.set_video_rtp_header_extensions(
1349 MAKE_VECTOR(kVideoRtpExtension2));
1350
1351 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1352 ASSERT_TRUE(offer.get() != NULL);
1353 std::unique_ptr<SessionDescription> answer(
1354 f2_.CreateAnswer(offer.get(), opts, NULL));
1355
1356 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1357 GetFirstAudioContentDescription(
1358 offer.get())->rtp_header_extensions());
1359 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1360 GetFirstVideoContentDescription(
1361 offer.get())->rtp_header_extensions());
1362 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
1363 GetFirstAudioContentDescription(
1364 answer.get())->rtp_header_extensions());
1365 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
1366 GetFirstVideoContentDescription(
1367 answer.get())->rtp_header_extensions());
1368}
1369
1370TEST_F(MediaSessionDescriptionFactoryTest,
1371 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
1372 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001373 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
jbauch5869f502017-06-29 12:31:36 -07001374
1375 f1_.set_enable_encrypted_rtp_header_extensions(true);
1376
1377 f1_.set_audio_rtp_header_extensions(
1378 MAKE_VECTOR(kAudioRtpExtension1));
1379 f1_.set_video_rtp_header_extensions(
1380 MAKE_VECTOR(kVideoRtpExtension1));
1381 f2_.set_audio_rtp_header_extensions(
1382 MAKE_VECTOR(kAudioRtpExtension2));
1383 f2_.set_video_rtp_header_extensions(
1384 MAKE_VECTOR(kVideoRtpExtension2));
1385
1386 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1387 ASSERT_TRUE(offer.get() != NULL);
1388 std::unique_ptr<SessionDescription> answer(
1389 f2_.CreateAnswer(offer.get(), opts, NULL));
1390
1391 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1392 GetFirstAudioContentDescription(
1393 offer.get())->rtp_header_extensions());
1394 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1395 GetFirstVideoContentDescription(
1396 offer.get())->rtp_header_extensions());
1397 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
1398 GetFirstAudioContentDescription(
1399 answer.get())->rtp_header_extensions());
1400 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
1401 GetFirstVideoContentDescription(
1402 answer.get())->rtp_header_extensions());
1403}
1404
1405TEST_F(MediaSessionDescriptionFactoryTest,
1406 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
1407 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001408 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
jbauch5869f502017-06-29 12:31:36 -07001409
1410 f2_.set_enable_encrypted_rtp_header_extensions(true);
1411
1412 f1_.set_audio_rtp_header_extensions(
1413 MAKE_VECTOR(kAudioRtpExtension1));
1414 f1_.set_video_rtp_header_extensions(
1415 MAKE_VECTOR(kVideoRtpExtension1));
1416 f2_.set_audio_rtp_header_extensions(
1417 MAKE_VECTOR(kAudioRtpExtension2));
1418 f2_.set_video_rtp_header_extensions(
1419 MAKE_VECTOR(kVideoRtpExtension2));
1420
1421 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1422 ASSERT_TRUE(offer.get() != NULL);
1423 std::unique_ptr<SessionDescription> answer(
1424 f2_.CreateAnswer(offer.get(), opts, NULL));
1425
1426 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension1),
1427 GetFirstAudioContentDescription(
1428 offer.get())->rtp_header_extensions());
1429 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtension1),
1430 GetFirstVideoContentDescription(
1431 offer.get())->rtp_header_extensions());
1432 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
1433 GetFirstAudioContentDescription(
1434 answer.get())->rtp_header_extensions());
1435 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
1436 GetFirstVideoContentDescription(
1437 answer.get())->rtp_header_extensions());
1438}
1439
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001440// Create an audio, video, data answer without legacy StreamParams.
1441TEST_F(MediaSessionDescriptionFactoryTest,
1442 TestCreateAnswerWithoutLegacyStreams) {
1443 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001444 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
1445 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &opts);
kwiberg31022942016-03-11 14:18:21 -08001446 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001447 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001448 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001449 f2_.CreateAnswer(offer.get(), opts, NULL));
1450 const ContentInfo* ac = answer->GetContentByName("audio");
1451 const ContentInfo* vc = answer->GetContentByName("video");
1452 const ContentInfo* dc = answer->GetContentByName("data");
1453 ASSERT_TRUE(ac != NULL);
1454 ASSERT_TRUE(vc != NULL);
1455 const AudioContentDescription* acd =
1456 static_cast<const AudioContentDescription*>(ac->description);
1457 const VideoContentDescription* vcd =
1458 static_cast<const VideoContentDescription*>(vc->description);
1459 const DataContentDescription* dcd =
1460 static_cast<const DataContentDescription*>(dc->description);
1461
1462 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1463 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1464 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1465}
1466
1467TEST_F(MediaSessionDescriptionFactoryTest, TestPartial) {
1468 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001469 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
1470 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001471 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001472 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001473 ASSERT_TRUE(offer.get() != NULL);
1474 const ContentInfo* ac = offer->GetContentByName("audio");
1475 const ContentInfo* vc = offer->GetContentByName("video");
1476 const ContentInfo* dc = offer->GetContentByName("data");
1477 AudioContentDescription* acd = const_cast<AudioContentDescription*>(
1478 static_cast<const AudioContentDescription*>(ac->description));
1479 VideoContentDescription* vcd = const_cast<VideoContentDescription*>(
1480 static_cast<const VideoContentDescription*>(vc->description));
1481 DataContentDescription* dcd = const_cast<DataContentDescription*>(
1482 static_cast<const DataContentDescription*>(dc->description));
1483
1484 EXPECT_FALSE(acd->partial()); // default is false.
1485 acd->set_partial(true);
1486 EXPECT_TRUE(acd->partial());
1487 acd->set_partial(false);
1488 EXPECT_FALSE(acd->partial());
1489
1490 EXPECT_FALSE(vcd->partial()); // default is false.
1491 vcd->set_partial(true);
1492 EXPECT_TRUE(vcd->partial());
1493 vcd->set_partial(false);
1494 EXPECT_FALSE(vcd->partial());
1495
1496 EXPECT_FALSE(dcd->partial()); // default is false.
1497 dcd->set_partial(true);
1498 EXPECT_TRUE(dcd->partial());
1499 dcd->set_partial(false);
1500 EXPECT_FALSE(dcd->partial());
1501}
1502
1503// Create a typical video answer, and ensure it matches what we expect.
1504TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1505 MediaSessionOptions offer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001506 AddAudioVideoSections(cricket::MD_SENDRECV, &offer_opts);
1507 AddDataSection(cricket::DCT_RTP, cricket::MD_SENDRECV, &offer_opts);
1508
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001509 MediaSessionOptions answer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001510 AddAudioVideoSections(cricket::MD_SENDRECV, &answer_opts);
1511 AddDataSection(cricket::DCT_RTP, cricket::MD_SENDRECV, &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001512
kwiberg31022942016-03-11 14:18:21 -08001513 std::unique_ptr<SessionDescription> offer;
1514 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001515
1516 offer_opts.rtcp_mux_enabled = true;
1517 answer_opts.rtcp_mux_enabled = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001518 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1519 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1520 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1521 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1522 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1523 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1524 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1525 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1526 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1527 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1528 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1529 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1530 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1531 EXPECT_TRUE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1532
1533 offer_opts.rtcp_mux_enabled = true;
1534 answer_opts.rtcp_mux_enabled = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001535 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1536 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1537 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1538 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1539 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1540 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1541 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1542 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1543 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1544 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1545 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1546 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1547 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1548 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1549
1550 offer_opts.rtcp_mux_enabled = false;
1551 answer_opts.rtcp_mux_enabled = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001552 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1553 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1554 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1555 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1556 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1557 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1558 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1559 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1560 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1561 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1562 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1563 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1564 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1565 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1566
1567 offer_opts.rtcp_mux_enabled = false;
1568 answer_opts.rtcp_mux_enabled = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001569 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1570 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1571 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1572 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1573 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1574 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1575 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1576 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1577 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1578 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1579 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1580 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1581 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1582 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1583}
1584
1585// Create an audio-only answer to a video offer.
1586TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1587 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001588 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
1589 &opts);
1590 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
1591 &opts);
kwiberg31022942016-03-11 14:18:21 -08001592 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001593 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001594
1595 opts.media_description_options[1].stopped = true;
kwiberg31022942016-03-11 14:18:21 -08001596 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001597 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001598 const ContentInfo* ac = answer->GetContentByName("audio");
1599 const ContentInfo* vc = answer->GetContentByName("video");
1600 ASSERT_TRUE(ac != NULL);
1601 ASSERT_TRUE(vc != NULL);
1602 ASSERT_TRUE(vc->description != NULL);
1603 EXPECT_TRUE(vc->rejected);
1604}
1605
1606// Create an audio-only answer to an offer with data.
1607TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001608 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001609 opts.data_channel_type = cricket::DCT_RTP;
zhihuang1c378ed2017-08-17 14:10:50 -07001610 AddMediaSection(MEDIA_TYPE_DATA, "data", cricket::MD_RECVONLY, kActive,
1611 &opts);
kwiberg31022942016-03-11 14:18:21 -08001612 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001613 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001614
1615 opts.media_description_options[1].stopped = true;
kwiberg31022942016-03-11 14:18:21 -08001616 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001617 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001618 const ContentInfo* ac = answer->GetContentByName("audio");
1619 const ContentInfo* dc = answer->GetContentByName("data");
1620 ASSERT_TRUE(ac != NULL);
1621 ASSERT_TRUE(dc != NULL);
1622 ASSERT_TRUE(dc->description != NULL);
1623 EXPECT_TRUE(dc->rejected);
1624}
1625
1626// Create an answer that rejects the contents which are rejected in the offer.
1627TEST_F(MediaSessionDescriptionFactoryTest,
1628 CreateAnswerToOfferWithRejectedMedia) {
1629 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001630 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
1631 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &opts);
kwiberg31022942016-03-11 14:18:21 -08001632 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001633 ASSERT_TRUE(offer.get() != NULL);
1634 ContentInfo* ac = offer->GetContentByName("audio");
1635 ContentInfo* vc = offer->GetContentByName("video");
1636 ContentInfo* dc = offer->GetContentByName("data");
1637 ASSERT_TRUE(ac != NULL);
1638 ASSERT_TRUE(vc != NULL);
1639 ASSERT_TRUE(dc != NULL);
1640 ac->rejected = true;
1641 vc->rejected = true;
1642 dc->rejected = true;
kwiberg31022942016-03-11 14:18:21 -08001643 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001644 f2_.CreateAnswer(offer.get(), opts, NULL));
1645 ac = answer->GetContentByName("audio");
1646 vc = answer->GetContentByName("video");
1647 dc = answer->GetContentByName("data");
1648 ASSERT_TRUE(ac != NULL);
1649 ASSERT_TRUE(vc != NULL);
1650 ASSERT_TRUE(dc != NULL);
1651 EXPECT_TRUE(ac->rejected);
1652 EXPECT_TRUE(vc->rejected);
1653 EXPECT_TRUE(dc->rejected);
1654}
1655
1656// Create an audio and video offer with:
1657// - one video track
1658// - two audio tracks
1659// - two data tracks
1660// and ensure it matches what we expect. Also updates the initial offer by
1661// adding a new video track and replaces one of the audio tracks.
1662TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
1663 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001664 AddAudioVideoSections(cricket::MD_SENDRECV, &opts);
1665 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001666 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001667 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001668 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001669 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001670 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001671
1672 AddDataSection(cricket::DCT_RTP, cricket::MD_SENDRECV, &opts);
1673 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001674 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001675 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001676 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001677
1678 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001679 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001680
1681 ASSERT_TRUE(offer.get() != NULL);
1682 const ContentInfo* ac = offer->GetContentByName("audio");
1683 const ContentInfo* vc = offer->GetContentByName("video");
1684 const ContentInfo* dc = offer->GetContentByName("data");
1685 ASSERT_TRUE(ac != NULL);
1686 ASSERT_TRUE(vc != NULL);
1687 ASSERT_TRUE(dc != NULL);
1688 const AudioContentDescription* acd =
1689 static_cast<const AudioContentDescription*>(ac->description);
1690 const VideoContentDescription* vcd =
1691 static_cast<const VideoContentDescription*>(vc->description);
1692 const DataContentDescription* dcd =
1693 static_cast<const DataContentDescription*>(dc->description);
1694 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07001695 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001696
1697 const StreamParamsVec& audio_streams = acd->streams();
1698 ASSERT_EQ(2U, audio_streams.size());
1699 EXPECT_EQ(audio_streams[0].cname , audio_streams[1].cname);
1700 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1701 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1702 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1703 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1704 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1705 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1706
1707 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1708 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1709 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
1710
1711 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1712 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
1713 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1714
1715 const StreamParamsVec& video_streams = vcd->streams();
1716 ASSERT_EQ(1U, video_streams.size());
1717 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1718 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1719 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1720 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1721
1722 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1723 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
1724 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1725
1726 const StreamParamsVec& data_streams = dcd->streams();
1727 ASSERT_EQ(2U, data_streams.size());
1728 EXPECT_EQ(data_streams[0].cname , data_streams[1].cname);
1729 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1730 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1731 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1732 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1733 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1734 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1735
1736 EXPECT_EQ(cricket::kDataMaxBandwidth,
1737 dcd->bandwidth()); // default bandwidth (auto)
1738 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
1739 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1740
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001741 // Update the offer. Add a new video track that is not synched to the
1742 // other tracks and replace audio track 2 with audio track 3.
zhihuang1c378ed2017-08-17 14:10:50 -07001743 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001744 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001745 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
1746 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001747 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001748 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
1749 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack3,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001750 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08001751 std::unique_ptr<SessionDescription> updated_offer(
1752 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001753
1754 ASSERT_TRUE(updated_offer.get() != NULL);
1755 ac = updated_offer->GetContentByName("audio");
1756 vc = updated_offer->GetContentByName("video");
1757 dc = updated_offer->GetContentByName("data");
1758 ASSERT_TRUE(ac != NULL);
1759 ASSERT_TRUE(vc != NULL);
1760 ASSERT_TRUE(dc != NULL);
1761 const AudioContentDescription* updated_acd =
1762 static_cast<const AudioContentDescription*>(ac->description);
1763 const VideoContentDescription* updated_vcd =
1764 static_cast<const VideoContentDescription*>(vc->description);
1765 const DataContentDescription* updated_dcd =
1766 static_cast<const DataContentDescription*>(dc->description);
1767
1768 EXPECT_EQ(acd->type(), updated_acd->type());
1769 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1770 EXPECT_EQ(vcd->type(), updated_vcd->type());
1771 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1772 EXPECT_EQ(dcd->type(), updated_dcd->type());
1773 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1774 ASSERT_CRYPTO(updated_acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
1775 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
1776 ASSERT_CRYPTO(updated_vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1777 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
1778 ASSERT_CRYPTO(updated_dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1779 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1780
1781 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1782 ASSERT_EQ(2U, updated_audio_streams.size());
1783 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
1784 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
1785 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
1786 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
1787 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
1788
1789 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1790 ASSERT_EQ(2U, updated_video_streams.size());
1791 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1792 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001793 // All the media streams in one PeerConnection share one RTCP CNAME.
1794 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001795
1796 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1797 ASSERT_EQ(2U, updated_data_streams.size());
1798 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
1799 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
1800 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
1801 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
1802 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07001803 // The stream correctly got the CNAME from the MediaSessionOptions.
1804 // The Expected RTCP CNAME is the default one as we are using the default
1805 // MediaSessionOptions.
1806 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001807}
1808
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001809// Create an offer with simulcast video stream.
1810TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
1811 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001812 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
1813 &opts);
1814 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_SENDRECV, kActive,
1815 &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001816 const int num_sim_layers = 3;
zhihuang1c378ed2017-08-17 14:10:50 -07001817 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001818 {kMediaStream1}, num_sim_layers, &opts);
kwiberg31022942016-03-11 14:18:21 -08001819 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001820
1821 ASSERT_TRUE(offer.get() != NULL);
1822 const ContentInfo* vc = offer->GetContentByName("video");
1823 ASSERT_TRUE(vc != NULL);
1824 const VideoContentDescription* vcd =
1825 static_cast<const VideoContentDescription*>(vc->description);
1826
1827 const StreamParamsVec& video_streams = vcd->streams();
1828 ASSERT_EQ(1U, video_streams.size());
1829 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1830 const SsrcGroup* sim_ssrc_group =
1831 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
1832 ASSERT_TRUE(sim_ssrc_group != NULL);
1833 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
1834}
1835
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001836// Create an audio and video answer to a standard video offer with:
1837// - one video track
1838// - two audio tracks
1839// - two data tracks
1840// and ensure it matches what we expect. Also updates the initial answer by
1841// adding a new video track and removes one of the audio tracks.
1842TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
1843 MediaSessionOptions offer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001844 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
1845 &offer_opts);
1846 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
1847 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001848 offer_opts.data_channel_type = cricket::DCT_RTP;
zhihuang1c378ed2017-08-17 14:10:50 -07001849 AddMediaSection(MEDIA_TYPE_DATA, "data", cricket::MD_RECVONLY, kActive,
1850 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001851 f1_.set_secure(SEC_ENABLED);
1852 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001853 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(offer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001854
zhihuang1c378ed2017-08-17 14:10:50 -07001855 MediaSessionOptions answer_opts;
1856 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_SENDRECV, kActive,
1857 &answer_opts);
1858 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_SENDRECV, kActive,
1859 &answer_opts);
1860 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001861 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001862 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001863 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001864 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001865 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001866
1867 AddMediaSection(MEDIA_TYPE_DATA, "data", cricket::MD_SENDRECV, kActive,
1868 &answer_opts);
1869 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001870 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001871 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001872 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001873 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001874
kwiberg31022942016-03-11 14:18:21 -08001875 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001876 f2_.CreateAnswer(offer.get(), answer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001877
1878 ASSERT_TRUE(answer.get() != NULL);
1879 const ContentInfo* ac = answer->GetContentByName("audio");
1880 const ContentInfo* vc = answer->GetContentByName("video");
1881 const ContentInfo* dc = answer->GetContentByName("data");
1882 ASSERT_TRUE(ac != NULL);
1883 ASSERT_TRUE(vc != NULL);
1884 ASSERT_TRUE(dc != NULL);
1885 const AudioContentDescription* acd =
1886 static_cast<const AudioContentDescription*>(ac->description);
1887 const VideoContentDescription* vcd =
1888 static_cast<const VideoContentDescription*>(vc->description);
1889 const DataContentDescription* dcd =
1890 static_cast<const DataContentDescription*>(dc->description);
1891 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1892 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1893 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1894
1895 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1896 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1897
1898 const StreamParamsVec& audio_streams = acd->streams();
1899 ASSERT_EQ(2U, audio_streams.size());
1900 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
1901 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1902 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1903 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1904 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1905 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1906 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1907
1908 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1909 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1910
1911 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1912 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1913
1914 const StreamParamsVec& video_streams = vcd->streams();
1915 ASSERT_EQ(1U, video_streams.size());
1916 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1917 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1918 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1919 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1920
1921 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1922 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
1923
1924 const StreamParamsVec& data_streams = dcd->streams();
1925 ASSERT_EQ(2U, data_streams.size());
1926 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
1927 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1928 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1929 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1930 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1931 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1932 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1933
1934 EXPECT_EQ(cricket::kDataMaxBandwidth,
1935 dcd->bandwidth()); // default bandwidth (auto)
1936 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
1937
1938 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07001939 // other tracks and remove 1 audio track.
zhihuang1c378ed2017-08-17 14:10:50 -07001940 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001941 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001942 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
1943 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08001944 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001945 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001946
1947 ASSERT_TRUE(updated_answer.get() != NULL);
1948 ac = updated_answer->GetContentByName("audio");
1949 vc = updated_answer->GetContentByName("video");
1950 dc = updated_answer->GetContentByName("data");
1951 ASSERT_TRUE(ac != NULL);
1952 ASSERT_TRUE(vc != NULL);
1953 ASSERT_TRUE(dc != NULL);
1954 const AudioContentDescription* updated_acd =
1955 static_cast<const AudioContentDescription*>(ac->description);
1956 const VideoContentDescription* updated_vcd =
1957 static_cast<const VideoContentDescription*>(vc->description);
1958 const DataContentDescription* updated_dcd =
1959 static_cast<const DataContentDescription*>(dc->description);
1960
1961 ASSERT_CRYPTO(updated_acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1962 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
1963 ASSERT_CRYPTO(updated_vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1964 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
1965 ASSERT_CRYPTO(updated_dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1966 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1967
1968 EXPECT_EQ(acd->type(), updated_acd->type());
1969 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1970 EXPECT_EQ(vcd->type(), updated_vcd->type());
1971 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1972 EXPECT_EQ(dcd->type(), updated_dcd->type());
1973 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1974
1975 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1976 ASSERT_EQ(1U, updated_audio_streams.size());
1977 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
1978
1979 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1980 ASSERT_EQ(2U, updated_video_streams.size());
1981 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1982 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001983 // All media streams in one PeerConnection share one CNAME.
1984 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001985
1986 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1987 ASSERT_EQ(1U, updated_data_streams.size());
1988 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
1989}
1990
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001991// Create an updated offer after creating an answer to the original offer and
1992// verify that the codecs that were part of the original answer are not changed
1993// in the updated offer.
1994TEST_F(MediaSessionDescriptionFactoryTest,
1995 RespondentCreatesOfferAfterCreatingAnswer) {
1996 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001997 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001998
kwiberg31022942016-03-11 14:18:21 -08001999 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2000 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002001 f2_.CreateAnswer(offer.get(), opts, NULL));
2002
2003 const AudioContentDescription* acd =
2004 GetFirstAudioContentDescription(answer.get());
2005 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
2006
2007 const VideoContentDescription* vcd =
2008 GetFirstVideoContentDescription(answer.get());
2009 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
2010
kwiberg31022942016-03-11 14:18:21 -08002011 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002012 f2_.CreateOffer(opts, answer.get()));
2013
2014 // The expected audio codecs are the common audio codecs from the first
2015 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
2016 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002017 // TODO(wu): |updated_offer| should not include the codec
2018 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002019 const AudioCodec kUpdatedAudioCodecOffer[] = {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002020 kAudioCodecsAnswer[0],
2021 kAudioCodecsAnswer[1],
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002022 kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002023 };
2024
2025 // The expected video codecs are the common video codecs from the first
2026 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
2027 // preference order.
2028 const VideoCodec kUpdatedVideoCodecOffer[] = {
2029 kVideoCodecsAnswer[0],
2030 kVideoCodecs2[1],
2031 };
2032
2033 const AudioContentDescription* updated_acd =
2034 GetFirstAudioContentDescription(updated_offer.get());
2035 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioCodecOffer), updated_acd->codecs());
2036
2037 const VideoContentDescription* updated_vcd =
2038 GetFirstVideoContentDescription(updated_offer.get());
2039 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoCodecOffer), updated_vcd->codecs());
2040}
2041
2042// Create an updated offer after creating an answer to the original offer and
2043// verify that the codecs that were part of the original answer are not changed
2044// in the updated offer. In this test Rtx is enabled.
2045TEST_F(MediaSessionDescriptionFactoryTest,
2046 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2047 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002048 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
2049 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002050 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002051 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002052 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002053 f1_.set_video_codecs(f1_codecs);
2054
2055 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002056 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002057 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002058 f2_.set_video_codecs(f2_codecs);
2059
kwiberg31022942016-03-11 14:18:21 -08002060 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002061 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002062 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002063 f2_.CreateAnswer(offer.get(), opts, NULL));
2064
2065 const VideoContentDescription* vcd =
2066 GetFirstVideoContentDescription(answer.get());
2067
2068 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002069 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2070 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002071
2072 EXPECT_EQ(expected_codecs, vcd->codecs());
2073
deadbeef67cf2c12016-04-13 10:07:16 -07002074 // Now, make sure we get same result (except for the order) if |f2_| creates
2075 // an updated offer even though the default payload types between |f1_| and
2076 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08002077 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002078 f2_.CreateOffer(opts, answer.get()));
2079 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002080 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002081 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2082
2083 const VideoContentDescription* updated_vcd =
2084 GetFirstVideoContentDescription(updated_answer.get());
2085
2086 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2087}
2088
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002089// Regression test for:
2090// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2091// Existing codecs should always appear before new codecs in re-offers. But
2092// under a specific set of circumstances, the existing RTX codec was ending up
2093// added to the end of the list.
2094TEST_F(MediaSessionDescriptionFactoryTest,
2095 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2096 MediaSessionOptions opts;
2097 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
2098 &opts);
2099 // We specifically choose different preferred payload types for VP8 to
2100 // trigger the issue.
2101 cricket::VideoCodec vp8_offerer(100, "VP8");
2102 cricket::VideoCodec vp8_offerer_rtx =
2103 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
2104 cricket::VideoCodec vp8_answerer(110, "VP8");
2105 cricket::VideoCodec vp8_answerer_rtx =
2106 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
2107 cricket::VideoCodec vp9(120, "VP9");
2108 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
2109
2110 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
2111 // We also specifically cause the answerer to prefer VP9, such that if it
2112 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
2113 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
2114 vp8_answerer_rtx};
2115
2116 f1_.set_video_codecs(f1_codecs);
2117 f2_.set_video_codecs(f2_codecs);
2118 std::vector<AudioCodec> audio_codecs;
2119 f1_.set_audio_codecs(audio_codecs, audio_codecs);
2120 f2_.set_audio_codecs(audio_codecs, audio_codecs);
2121
2122 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
2123 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2124 ASSERT_TRUE(offer.get() != NULL);
2125 std::unique_ptr<SessionDescription> answer(
2126 f2_.CreateAnswer(offer.get(), opts, NULL));
2127
2128 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
2129 // But if the bug is triggered, RTX for VP8 ends up last.
2130 std::unique_ptr<SessionDescription> updated_offer(
2131 f2_.CreateOffer(opts, answer.get()));
2132
2133 const VideoContentDescription* vcd =
2134 GetFirstVideoContentDescription(updated_offer.get());
2135 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
2136 ASSERT_EQ(4u, codecs.size());
2137 EXPECT_EQ(vp8_offerer, codecs[0]);
2138 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
2139 EXPECT_EQ(vp9, codecs[2]);
2140 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002141}
2142
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002143// Create an updated offer that adds video after creating an audio only answer
2144// to the original offer. This test verifies that if a video codec and the RTX
2145// codec have the same default payload type as an audio codec that is already in
2146// use, the added codecs payload types are changed.
2147TEST_F(MediaSessionDescriptionFactoryTest,
2148 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2149 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002150 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002151 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002152 f1_.set_video_codecs(f1_codecs);
2153
2154 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002155 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
2156 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002157
kwiberg31022942016-03-11 14:18:21 -08002158 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2159 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002160 f2_.CreateAnswer(offer.get(), opts, NULL));
2161
2162 const AudioContentDescription* acd =
2163 GetFirstAudioContentDescription(answer.get());
2164 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
2165
2166 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
2167 // reference be the same as an audio codec that was negotiated in the
2168 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002169 opts.media_description_options.clear();
2170 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002171
2172 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2173 int used_pl_type = acd->codecs()[0].id;
2174 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002175 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002176 f2_.set_video_codecs(f2_codecs);
2177
kwiberg31022942016-03-11 14:18:21 -08002178 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002179 f2_.CreateOffer(opts, answer.get()));
2180 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002181 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002182 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2183
2184 const AudioContentDescription* updated_acd =
2185 GetFirstAudioContentDescription(answer.get());
2186 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), updated_acd->codecs());
2187
2188 const VideoContentDescription* updated_vcd =
2189 GetFirstVideoContentDescription(updated_answer.get());
2190
2191 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
sergeyu@chromium.org32f485b2013-12-05 22:36:21 +00002192 ASSERT_EQ(std::string(cricket::kRtxCodecName), updated_vcd->codecs()[1].name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002193 int new_h264_pl_type = updated_vcd->codecs()[0].id;
2194 EXPECT_NE(used_pl_type, new_h264_pl_type);
2195 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002196 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002197 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
2198 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
2199}
2200
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002201// Create an updated offer with RTX after creating an answer to an offer
2202// without RTX, and with different default payload types.
2203// Verify that the added RTX codec references the correct payload type.
2204TEST_F(MediaSessionDescriptionFactoryTest,
2205 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
2206 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002207 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002208
2209 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2210 // This creates rtx for H264 with the payload type |f2_| uses.
2211 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
2212 f2_.set_video_codecs(f2_codecs);
2213
kwiberg31022942016-03-11 14:18:21 -08002214 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002215 ASSERT_TRUE(offer.get() != nullptr);
kwiberg31022942016-03-11 14:18:21 -08002216 std::unique_ptr<SessionDescription> answer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002217 f2_.CreateAnswer(offer.get(), opts, nullptr));
2218
2219 const VideoContentDescription* vcd =
2220 GetFirstVideoContentDescription(answer.get());
2221
2222 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2223 EXPECT_EQ(expected_codecs, vcd->codecs());
2224
2225 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
2226 // updated offer, even though the default payload types are different from
2227 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08002228 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002229 f2_.CreateOffer(opts, answer.get()));
2230 ASSERT_TRUE(updated_offer);
2231
2232 const VideoContentDescription* updated_vcd =
2233 GetFirstVideoContentDescription(updated_offer.get());
2234
2235 // New offer should attempt to add H263, and RTX for H264.
2236 expected_codecs.push_back(kVideoCodecs2[1]);
2237 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
2238 &expected_codecs);
2239 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2240}
2241
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002242// Test that RTX is ignored when there is no associated payload type parameter.
2243TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
2244 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002245 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
2246 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002247 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002248 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07002249 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002250 f1_.set_video_codecs(f1_codecs);
2251
2252 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002253 // This creates RTX for H264 with the payload type |f2_| uses.
2254 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002255 f2_.set_video_codecs(f2_codecs);
2256
kwiberg31022942016-03-11 14:18:21 -08002257 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002258 ASSERT_TRUE(offer.get() != NULL);
2259 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
2260 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
2261 // is possible to test that that RTX is dropped when
2262 // kCodecParamAssociatedPayloadType is missing in the offer.
2263 VideoContentDescription* desc =
2264 static_cast<cricket::VideoContentDescription*>(
2265 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
2266 ASSERT_TRUE(desc != NULL);
2267 std::vector<VideoCodec> codecs = desc->codecs();
2268 for (std::vector<VideoCodec>::iterator iter = codecs.begin();
2269 iter != codecs.end(); ++iter) {
2270 if (iter->name.find(cricket::kRtxCodecName) == 0) {
2271 iter->params.clear();
2272 }
2273 }
2274 desc->set_codecs(codecs);
2275
kwiberg31022942016-03-11 14:18:21 -08002276 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002277 f2_.CreateAnswer(offer.get(), opts, NULL));
2278
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002279 std::vector<std::string> codec_names =
2280 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
2281 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
2282 cricket::kRtxCodecName));
2283}
2284
2285// Test that RTX will be filtered out in the answer if its associated payload
2286// type doesn't match the local value.
2287TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
2288 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002289 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
2290 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002291 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2292 // This creates RTX for H264 in sender.
2293 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2294 f1_.set_video_codecs(f1_codecs);
2295
2296 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2297 // This creates RTX for H263 in receiver.
2298 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
2299 f2_.set_video_codecs(f2_codecs);
2300
kwiberg31022942016-03-11 14:18:21 -08002301 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002302 ASSERT_TRUE(offer.get() != NULL);
2303 // Associated payload type doesn't match, therefore, RTX codec is removed in
2304 // the answer.
kwiberg31022942016-03-11 14:18:21 -08002305 std::unique_ptr<SessionDescription> answer(
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002306 f2_.CreateAnswer(offer.get(), opts, NULL));
2307
2308 std::vector<std::string> codec_names =
2309 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
2310 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
2311 cricket::kRtxCodecName));
2312}
2313
2314// Test that when multiple RTX codecs are offered, only the matched RTX codec
2315// is added in the answer, and the unsupported RTX codec is filtered out.
2316TEST_F(MediaSessionDescriptionFactoryTest,
2317 FilterOutUnsupportedRtxWhenCreatingAnswer) {
2318 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002319 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
2320 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002321 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2322 // This creates RTX for H264-SVC in sender.
2323 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2324 f1_.set_video_codecs(f1_codecs);
2325
2326 // This creates RTX for H264 in sender.
2327 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2328 f1_.set_video_codecs(f1_codecs);
2329
2330 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2331 // This creates RTX for H264 in receiver.
2332 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
2333 f2_.set_video_codecs(f2_codecs);
2334
2335 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
2336 // for H264-SVC should also be removed.
kwiberg31022942016-03-11 14:18:21 -08002337 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002338 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002339 std::unique_ptr<SessionDescription> answer(
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002340 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002341 const VideoContentDescription* vcd =
2342 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002343 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2344 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2345 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002346
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002347 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002348}
2349
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002350// Test that after one RTX codec has been negotiated, a new offer can attempt
2351// to add another.
2352TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
2353 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002354 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
2355 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002356 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2357 // This creates RTX for H264 for the offerer.
2358 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2359 f1_.set_video_codecs(f1_codecs);
2360
kwiberg31022942016-03-11 14:18:21 -08002361 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002362 ASSERT_TRUE(offer);
2363 const VideoContentDescription* vcd =
2364 GetFirstVideoContentDescription(offer.get());
2365
2366 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
2367 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2368 &expected_codecs);
2369 EXPECT_EQ(expected_codecs, vcd->codecs());
2370
2371 // Now, attempt to add RTX for H264-SVC.
2372 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2373 f1_.set_video_codecs(f1_codecs);
2374
kwiberg31022942016-03-11 14:18:21 -08002375 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002376 f1_.CreateOffer(opts, offer.get()));
2377 ASSERT_TRUE(updated_offer);
2378 vcd = GetFirstVideoContentDescription(updated_offer.get());
2379
2380 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
2381 &expected_codecs);
2382 EXPECT_EQ(expected_codecs, vcd->codecs());
2383}
2384
Noah Richards2e7a0982015-05-18 14:02:54 -07002385// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
2386// generated for each simulcast ssrc and correctly grouped.
2387TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
2388 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002389 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_SENDRECV, kActive,
2390 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002391 // Add simulcast streams.
zhihuang1c378ed2017-08-17 14:10:50 -07002392 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002393 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002394
2395 // Use a single real codec, and then add RTX for it.
2396 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07002397 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07002398 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
2399 f1_.set_video_codecs(f1_codecs);
2400
2401 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
2402 // is a FID ssrc + grouping for each.
kwiberg31022942016-03-11 14:18:21 -08002403 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
Noah Richards2e7a0982015-05-18 14:02:54 -07002404 ASSERT_TRUE(offer.get() != NULL);
2405 VideoContentDescription* desc = static_cast<VideoContentDescription*>(
2406 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
2407 ASSERT_TRUE(desc != NULL);
2408 EXPECT_TRUE(desc->multistream());
2409 const StreamParamsVec& streams = desc->streams();
2410 // Single stream.
2411 ASSERT_EQ(1u, streams.size());
2412 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
2413 EXPECT_EQ(6u, streams[0].ssrcs.size());
2414 // And should have a SIM group for the simulcast.
2415 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2416 // And a FID group for RTX.
2417 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02002418 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002419 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2420 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02002421 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002422 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
2423 EXPECT_EQ(3u, fid_ssrcs.size());
2424}
2425
brandtr03d5fb12016-11-22 03:37:59 -08002426// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
2427// together with a FEC-FR grouping.
2428TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
2429 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002430 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_SENDRECV, kActive,
2431 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002432 // Add single stream.
zhihuang1c378ed2017-08-17 14:10:50 -07002433 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002434 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002435
2436 // Use a single real codec, and then add FlexFEC for it.
2437 std::vector<VideoCodec> f1_codecs;
2438 f1_codecs.push_back(VideoCodec(97, "H264"));
2439 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2440 f1_.set_video_codecs(f1_codecs);
2441
2442 // Ensure that the offer has a single FlexFEC ssrc and that
2443 // there is no FEC-FR ssrc + grouping for each.
2444 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
2445 ASSERT_TRUE(offer.get() != nullptr);
2446 VideoContentDescription* desc = static_cast<VideoContentDescription*>(
2447 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
2448 ASSERT_TRUE(desc != nullptr);
2449 EXPECT_TRUE(desc->multistream());
2450 const StreamParamsVec& streams = desc->streams();
2451 // Single stream.
2452 ASSERT_EQ(1u, streams.size());
2453 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
2454 EXPECT_EQ(2u, streams[0].ssrcs.size());
2455 // And should have a FEC-FR group for FlexFEC.
2456 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
2457 std::vector<uint32_t> primary_ssrcs;
2458 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2459 ASSERT_EQ(1u, primary_ssrcs.size());
2460 uint32_t flexfec_ssrc;
2461 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
2462 EXPECT_NE(flexfec_ssrc, 0u);
2463}
2464
2465// Test that FlexFEC is disabled for simulcast.
2466// TODO(brandtr): Remove this test when we support simulcast, either through
2467// multiple FlexfecSenders, or through multistream protection.
2468TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
2469 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002470 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_SENDRECV, kActive,
2471 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002472 // Add simulcast streams.
zhihuang1c378ed2017-08-17 14:10:50 -07002473 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002474 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002475
2476 // Use a single real codec, and then add FlexFEC for it.
2477 std::vector<VideoCodec> f1_codecs;
2478 f1_codecs.push_back(VideoCodec(97, "H264"));
2479 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2480 f1_.set_video_codecs(f1_codecs);
2481
2482 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
2483 // there is no FEC-FR ssrc + grouping for each.
2484 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
2485 ASSERT_TRUE(offer.get() != nullptr);
2486 VideoContentDescription* desc = static_cast<VideoContentDescription*>(
2487 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
2488 ASSERT_TRUE(desc != nullptr);
2489 EXPECT_FALSE(desc->multistream());
2490 const StreamParamsVec& streams = desc->streams();
2491 // Single stream.
2492 ASSERT_EQ(1u, streams.size());
2493 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
2494 EXPECT_EQ(3u, streams[0].ssrcs.size());
2495 // And should have a SIM group for the simulcast.
2496 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2497 // And not a FEC-FR group for FlexFEC.
2498 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
2499 std::vector<uint32_t> primary_ssrcs;
2500 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2501 EXPECT_EQ(3u, primary_ssrcs.size());
2502 for (uint32_t primary_ssrc : primary_ssrcs) {
2503 uint32_t flexfec_ssrc;
2504 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
2505 }
2506}
2507
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002508// Create an updated offer after creating an answer to the original offer and
2509// verify that the RTP header extensions that were part of the original answer
2510// are not changed in the updated offer.
2511TEST_F(MediaSessionDescriptionFactoryTest,
2512 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
2513 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002514 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002515
2516 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
2517 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
2518 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
2519 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
2520
kwiberg31022942016-03-11 14:18:21 -08002521 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2522 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002523 f2_.CreateAnswer(offer.get(), opts, NULL));
2524
2525 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
2526 GetFirstAudioContentDescription(
2527 answer.get())->rtp_header_extensions());
2528 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
2529 GetFirstVideoContentDescription(
2530 answer.get())->rtp_header_extensions());
2531
kwiberg31022942016-03-11 14:18:21 -08002532 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002533 f2_.CreateOffer(opts, answer.get()));
2534
2535 // The expected RTP header extensions in the new offer are the resulting
2536 // extensions from the first offer/answer exchange plus the extensions only
2537 // |f2_| offer.
2538 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002539 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07002540 const RtpExtension kUpdatedAudioRtpExtensions[] = {
2541 kAudioRtpExtensionAnswer[0], RtpExtension(kAudioRtpExtension2[1].uri, 13),
2542 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002543 };
2544
2545 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002546 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07002547 const RtpExtension kUpdatedVideoRtpExtensions[] = {
2548 kVideoRtpExtensionAnswer[0], RtpExtension(kVideoRtpExtension2[1].uri, 12),
2549 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002550 };
2551
2552 const AudioContentDescription* updated_acd =
2553 GetFirstAudioContentDescription(updated_offer.get());
2554 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
2555 updated_acd->rtp_header_extensions());
2556
2557 const VideoContentDescription* updated_vcd =
2558 GetFirstVideoContentDescription(updated_offer.get());
2559 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
2560 updated_vcd->rtp_header_extensions());
2561}
2562
deadbeefa5b273a2015-08-20 17:30:13 -07002563// Verify that if the same RTP extension URI is used for audio and video, the
2564// same ID is used. Also verify that the ID isn't changed when creating an
2565// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07002566TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07002567 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002568 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07002569
2570 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
2571 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
2572
kwiberg31022942016-03-11 14:18:21 -08002573 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
deadbeefa5b273a2015-08-20 17:30:13 -07002574
2575 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
2576 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07002577 const RtpExtension kExpectedVideoRtpExtension[] = {
2578 kVideoRtpExtension3[0], kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07002579 };
2580
2581 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
2582 GetFirstAudioContentDescription(
2583 offer.get())->rtp_header_extensions());
2584 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2585 GetFirstVideoContentDescription(
2586 offer.get())->rtp_header_extensions());
2587
2588 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08002589 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07002590 f1_.CreateOffer(opts, offer.get()));
2591
2592 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
2593 GetFirstAudioContentDescription(
2594 updated_offer.get())->rtp_header_extensions());
2595 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2596 GetFirstVideoContentDescription(
2597 updated_offer.get())->rtp_header_extensions());
2598}
2599
jbauch5869f502017-06-29 12:31:36 -07002600// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
2601TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
2602 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002603 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
jbauch5869f502017-06-29 12:31:36 -07002604
2605 f1_.set_enable_encrypted_rtp_header_extensions(true);
2606 f2_.set_enable_encrypted_rtp_header_extensions(true);
2607
2608 f1_.set_audio_rtp_header_extensions(
2609 MAKE_VECTOR(kAudioRtpExtension3ForEncryption));
2610 f1_.set_video_rtp_header_extensions(
2611 MAKE_VECTOR(kVideoRtpExtension3ForEncryption));
2612
2613 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2614
2615 // The extensions that are shared between audio and video should use the same
2616 // id.
2617 const RtpExtension kExpectedVideoRtpExtension[] = {
2618 kVideoRtpExtension3ForEncryption[0],
2619 kAudioRtpExtension3ForEncryptionOffer[1],
2620 kAudioRtpExtension3ForEncryptionOffer[2],
2621 };
2622
2623 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
2624 GetFirstAudioContentDescription(
2625 offer.get())->rtp_header_extensions());
2626 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2627 GetFirstVideoContentDescription(
2628 offer.get())->rtp_header_extensions());
2629
2630 // Nothing should change when creating a new offer
2631 std::unique_ptr<SessionDescription> updated_offer(
2632 f1_.CreateOffer(opts, offer.get()));
2633
2634 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
2635 GetFirstAudioContentDescription(
2636 updated_offer.get())->rtp_header_extensions());
2637 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2638 GetFirstVideoContentDescription(
2639 updated_offer.get())->rtp_header_extensions());
2640}
2641
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002642TEST(MediaSessionDescription, CopySessionDescription) {
2643 SessionDescription source;
2644 cricket::ContentGroup group(cricket::CN_AUDIO);
2645 source.AddGroup(group);
2646 AudioContentDescription* acd(new AudioContentDescription());
2647 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
2648 acd->AddLegacyStream(1);
2649 source.AddContent(cricket::CN_AUDIO, cricket::NS_JINGLE_RTP, acd);
2650 VideoContentDescription* vcd(new VideoContentDescription());
2651 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
2652 vcd->AddLegacyStream(2);
2653 source.AddContent(cricket::CN_VIDEO, cricket::NS_JINGLE_RTP, vcd);
2654
kwiberg31022942016-03-11 14:18:21 -08002655 std::unique_ptr<SessionDescription> copy(source.Copy());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002656 ASSERT_TRUE(copy.get() != NULL);
2657 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
2658 const ContentInfo* ac = copy->GetContentByName("audio");
2659 const ContentInfo* vc = copy->GetContentByName("video");
2660 ASSERT_TRUE(ac != NULL);
2661 ASSERT_TRUE(vc != NULL);
2662 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
2663 const AudioContentDescription* acd_copy =
2664 static_cast<const AudioContentDescription*>(ac->description);
2665 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
2666 EXPECT_EQ(1u, acd->first_ssrc());
2667
2668 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
2669 const VideoContentDescription* vcd_copy =
2670 static_cast<const VideoContentDescription*>(vc->description);
2671 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
2672 EXPECT_EQ(2u, vcd->first_ssrc());
2673}
2674
2675// The below TestTransportInfoXXX tests create different offers/answers, and
2676// ensure the TransportInfo in the SessionDescription matches what we expect.
2677TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
2678 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002679 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
2680 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002681 TestTransportInfo(true, options, false);
2682}
2683
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002684TEST_F(MediaSessionDescriptionFactoryTest,
2685 TestTransportInfoOfferIceRenomination) {
2686 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002687 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
2688 &options);
2689 options.media_description_options[0]
2690 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002691 TestTransportInfo(true, options, false);
2692}
2693
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002694TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
2695 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002696 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
2697 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002698 TestTransportInfo(true, options, true);
2699}
2700
2701TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
2702 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002703 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2704 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002705 TestTransportInfo(true, options, false);
2706}
2707
2708TEST_F(MediaSessionDescriptionFactoryTest,
2709 TestTransportInfoOfferMultimediaCurrent) {
2710 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002711 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2712 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002713 TestTransportInfo(true, options, true);
2714}
2715
2716TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
2717 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002718 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2719 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002720 options.bundle_enabled = true;
2721 TestTransportInfo(true, options, false);
2722}
2723
2724TEST_F(MediaSessionDescriptionFactoryTest,
2725 TestTransportInfoOfferBundleCurrent) {
2726 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002727 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2728 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002729 options.bundle_enabled = true;
2730 TestTransportInfo(true, options, true);
2731}
2732
2733TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
2734 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002735 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
2736 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002737 TestTransportInfo(false, options, false);
2738}
2739
2740TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002741 TestTransportInfoAnswerIceRenomination) {
2742 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002743 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
2744 &options);
2745 options.media_description_options[0]
2746 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002747 TestTransportInfo(false, options, false);
2748}
2749
2750TEST_F(MediaSessionDescriptionFactoryTest,
2751 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002752 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002753 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
2754 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002755 TestTransportInfo(false, options, true);
2756}
2757
2758TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
2759 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002760 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2761 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002762 TestTransportInfo(false, options, false);
2763}
2764
2765TEST_F(MediaSessionDescriptionFactoryTest,
2766 TestTransportInfoAnswerMultimediaCurrent) {
2767 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002768 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2769 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002770 TestTransportInfo(false, options, true);
2771}
2772
2773TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
2774 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002775 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2776 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002777 options.bundle_enabled = true;
2778 TestTransportInfo(false, options, false);
2779}
2780
2781TEST_F(MediaSessionDescriptionFactoryTest,
2782 TestTransportInfoAnswerBundleCurrent) {
2783 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002784 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2785 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002786 options.bundle_enabled = true;
2787 TestTransportInfo(false, options, true);
2788}
2789
2790// Create an offer with bundle enabled and verify the crypto parameters are
2791// the common set of the available cryptos.
2792TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
2793 TestCryptoWithBundle(true);
2794}
2795
2796// Create an answer with bundle enabled and verify the crypto parameters are
2797// the common set of the available cryptos.
2798TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
2799 TestCryptoWithBundle(false);
2800}
2801
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002802// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
2803// DTLS is not enabled locally.
2804TEST_F(MediaSessionDescriptionFactoryTest,
2805 TestOfferDtlsSavpfWithoutDtlsFailed) {
2806 f1_.set_secure(SEC_ENABLED);
2807 f2_.set_secure(SEC_ENABLED);
2808 tdf1_.set_secure(SEC_DISABLED);
2809 tdf2_.set_secure(SEC_DISABLED);
2810
kwiberg31022942016-03-11 14:18:21 -08002811 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -07002812 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002813 ASSERT_TRUE(offer.get() != NULL);
2814 ContentInfo* offer_content = offer->GetContentByName("audio");
2815 ASSERT_TRUE(offer_content != NULL);
2816 AudioContentDescription* offer_audio_desc =
2817 static_cast<AudioContentDescription*>(offer_content->description);
2818 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2819
kwiberg31022942016-03-11 14:18:21 -08002820 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002821 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002822 ASSERT_TRUE(answer != NULL);
2823 ContentInfo* answer_content = answer->GetContentByName("audio");
2824 ASSERT_TRUE(answer_content != NULL);
2825
2826 ASSERT_TRUE(answer_content->rejected);
2827}
2828
2829// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
2830// UDP/TLS/RTP/SAVPF.
2831TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
2832 f1_.set_secure(SEC_ENABLED);
2833 f2_.set_secure(SEC_ENABLED);
2834 tdf1_.set_secure(SEC_ENABLED);
2835 tdf2_.set_secure(SEC_ENABLED);
2836
kwiberg31022942016-03-11 14:18:21 -08002837 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -07002838 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002839 ASSERT_TRUE(offer.get() != NULL);
2840 ContentInfo* offer_content = offer->GetContentByName("audio");
2841 ASSERT_TRUE(offer_content != NULL);
2842 AudioContentDescription* offer_audio_desc =
2843 static_cast<AudioContentDescription*>(offer_content->description);
2844 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2845
kwiberg31022942016-03-11 14:18:21 -08002846 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002847 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002848 ASSERT_TRUE(answer != NULL);
2849
2850 const ContentInfo* answer_content = answer->GetContentByName("audio");
2851 ASSERT_TRUE(answer_content != NULL);
2852 ASSERT_FALSE(answer_content->rejected);
2853
2854 const AudioContentDescription* answer_audio_desc =
2855 static_cast<const AudioContentDescription*>(answer_content->description);
2856 EXPECT_EQ(std::string(cricket::kMediaProtocolDtlsSavpf),
2857 answer_audio_desc->protocol());
2858}
2859
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002860// Test that we include both SDES and DTLS in the offer, but only include SDES
2861// in the answer if DTLS isn't negotiated.
2862TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
2863 f1_.set_secure(SEC_ENABLED);
2864 f2_.set_secure(SEC_ENABLED);
2865 tdf1_.set_secure(SEC_ENABLED);
2866 tdf2_.set_secure(SEC_DISABLED);
2867 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002868 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
kwiberg31022942016-03-11 14:18:21 -08002869 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002870 const cricket::MediaContentDescription* audio_media_desc;
2871 const cricket::MediaContentDescription* video_media_desc;
2872 const cricket::TransportDescription* audio_trans_desc;
2873 const cricket::TransportDescription* video_trans_desc;
2874
2875 // Generate an offer with SDES and DTLS support.
2876 offer.reset(f1_.CreateOffer(options, NULL));
2877 ASSERT_TRUE(offer.get() != NULL);
2878
2879 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2880 offer->GetContentDescriptionByName("audio"));
2881 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002882 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002883 offer->GetContentDescriptionByName("video"));
2884 ASSERT_TRUE(video_media_desc != NULL);
2885 EXPECT_EQ(2u, audio_media_desc->cryptos().size());
2886 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2887
2888 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2889 ASSERT_TRUE(audio_trans_desc != NULL);
2890 video_trans_desc = offer->GetTransportDescriptionByName("video");
2891 ASSERT_TRUE(video_trans_desc != NULL);
2892 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2893 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
2894
2895 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
2896 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2897 ASSERT_TRUE(answer.get() != NULL);
2898
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002899 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002900 answer->GetContentDescriptionByName("audio"));
2901 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002902 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002903 answer->GetContentDescriptionByName("video"));
2904 ASSERT_TRUE(video_media_desc != NULL);
2905 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
2906 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2907
2908 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2909 ASSERT_TRUE(audio_trans_desc != NULL);
2910 video_trans_desc = answer->GetTransportDescriptionByName("video");
2911 ASSERT_TRUE(video_trans_desc != NULL);
2912 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
2913 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
2914
2915 // Enable DTLS; the answer should now only have DTLS support.
2916 tdf2_.set_secure(SEC_ENABLED);
2917 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2918 ASSERT_TRUE(answer.get() != NULL);
2919
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002920 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002921 answer->GetContentDescriptionByName("audio"));
2922 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002923 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002924 answer->GetContentDescriptionByName("video"));
2925 ASSERT_TRUE(video_media_desc != NULL);
2926 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2927 EXPECT_TRUE(video_media_desc->cryptos().empty());
2928 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2929 audio_media_desc->protocol());
2930 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2931 video_media_desc->protocol());
2932
2933 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2934 ASSERT_TRUE(audio_trans_desc != NULL);
2935 video_trans_desc = answer->GetTransportDescriptionByName("video");
2936 ASSERT_TRUE(video_trans_desc != NULL);
2937 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2938 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00002939
2940 // Try creating offer again. DTLS enabled now, crypto's should be empty
2941 // in new offer.
2942 offer.reset(f1_.CreateOffer(options, offer.get()));
2943 ASSERT_TRUE(offer.get() != NULL);
2944 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2945 offer->GetContentDescriptionByName("audio"));
2946 ASSERT_TRUE(audio_media_desc != NULL);
2947 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
2948 offer->GetContentDescriptionByName("video"));
2949 ASSERT_TRUE(video_media_desc != NULL);
2950 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2951 EXPECT_TRUE(video_media_desc->cryptos().empty());
2952
2953 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2954 ASSERT_TRUE(audio_trans_desc != NULL);
2955 video_trans_desc = offer->GetTransportDescriptionByName("video");
2956 ASSERT_TRUE(video_trans_desc != NULL);
2957 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2958 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002959}
2960
2961// Test that an answer can't be created if cryptos are required but the offer is
2962// unsecure.
2963TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07002964 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002965 f1_.set_secure(SEC_DISABLED);
2966 tdf1_.set_secure(SEC_DISABLED);
2967 f2_.set_secure(SEC_REQUIRED);
2968 tdf1_.set_secure(SEC_ENABLED);
2969
kwiberg31022942016-03-11 14:18:21 -08002970 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002971 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002972 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002973 f2_.CreateAnswer(offer.get(), options, NULL));
2974 EXPECT_TRUE(answer.get() == NULL);
2975}
2976
2977// Test that we accept a DTLS offer without SDES and create an appropriate
2978// answer.
2979TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
2980 f1_.set_secure(SEC_DISABLED);
2981 f2_.set_secure(SEC_ENABLED);
2982 tdf1_.set_secure(SEC_ENABLED);
2983 tdf2_.set_secure(SEC_ENABLED);
2984 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002985 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2986 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002987
kwiberg31022942016-03-11 14:18:21 -08002988 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002989
2990 // Generate an offer with DTLS but without SDES.
2991 offer.reset(f1_.CreateOffer(options, NULL));
2992 ASSERT_TRUE(offer.get() != NULL);
2993
2994 const AudioContentDescription* audio_offer =
2995 GetFirstAudioContentDescription(offer.get());
2996 ASSERT_TRUE(audio_offer->cryptos().empty());
2997 const VideoContentDescription* video_offer =
2998 GetFirstVideoContentDescription(offer.get());
2999 ASSERT_TRUE(video_offer->cryptos().empty());
3000 const DataContentDescription* data_offer =
3001 GetFirstDataContentDescription(offer.get());
3002 ASSERT_TRUE(data_offer->cryptos().empty());
3003
3004 const cricket::TransportDescription* audio_offer_trans_desc =
3005 offer->GetTransportDescriptionByName("audio");
3006 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
3007 const cricket::TransportDescription* video_offer_trans_desc =
3008 offer->GetTransportDescriptionByName("video");
3009 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
3010 const cricket::TransportDescription* data_offer_trans_desc =
3011 offer->GetTransportDescriptionByName("data");
3012 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
3013
3014 // Generate an answer with DTLS.
3015 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
3016 ASSERT_TRUE(answer.get() != NULL);
3017
3018 const cricket::TransportDescription* audio_answer_trans_desc =
3019 answer->GetTransportDescriptionByName("audio");
3020 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3021 const cricket::TransportDescription* video_answer_trans_desc =
3022 answer->GetTransportDescriptionByName("video");
3023 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
3024 const cricket::TransportDescription* data_answer_trans_desc =
3025 answer->GetTransportDescriptionByName("data");
3026 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
3027}
3028
3029// Verifies if vad_enabled option is set to false, CN codecs are not present in
3030// offer or answer.
3031TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3032 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07003033 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
kwiberg31022942016-03-11 14:18:21 -08003034 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003035 ASSERT_TRUE(offer.get() != NULL);
3036 const ContentInfo* audio_content = offer->GetContentByName("audio");
3037 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
3038
3039 options.vad_enabled = false;
3040 offer.reset(f1_.CreateOffer(options, NULL));
3041 ASSERT_TRUE(offer.get() != NULL);
3042 audio_content = offer->GetContentByName("audio");
3043 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
kwiberg31022942016-03-11 14:18:21 -08003044 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003045 f1_.CreateAnswer(offer.get(), options, NULL));
3046 ASSERT_TRUE(answer.get() != NULL);
3047 audio_content = answer->GetContentByName("audio");
3048 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
3049}
deadbeef44f08192015-12-15 16:20:09 -08003050
zhihuang1c378ed2017-08-17 14:10:50 -07003051// Test that the generated MIDs match the existing offer.
3052TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08003053 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003054 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_modified", cricket::MD_RECVONLY,
3055 kActive, &opts);
3056 AddMediaSection(MEDIA_TYPE_VIDEO, "video_modified", cricket::MD_RECVONLY,
3057 kActive, &opts);
deadbeef44f08192015-12-15 16:20:09 -08003058 opts.data_channel_type = cricket::DCT_SCTP;
zhihuang1c378ed2017-08-17 14:10:50 -07003059 AddMediaSection(MEDIA_TYPE_DATA, "data_modified", cricket::MD_SENDRECV,
3060 kActive, &opts);
3061 // Create offer.
kwiberg31022942016-03-11 14:18:21 -08003062 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
kwiberg31022942016-03-11 14:18:21 -08003063 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08003064 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003065
deadbeef44f08192015-12-15 16:20:09 -08003066 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3067 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3068 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3069 ASSERT_TRUE(audio_content != nullptr);
3070 ASSERT_TRUE(video_content != nullptr);
3071 ASSERT_TRUE(data_content != nullptr);
3072 EXPECT_EQ("audio_modified", audio_content->name);
3073 EXPECT_EQ("video_modified", video_content->name);
3074 EXPECT_EQ("data_modified", data_content->name);
3075}
zhihuangcf5b37c2016-05-05 11:44:35 -07003076
zhihuang1c378ed2017-08-17 14:10:50 -07003077// The following tests verify that the unified plan SDP is supported.
3078// Test that we can create an offer with multiple media sections of same media
3079// type.
3080TEST_F(MediaSessionDescriptionFactoryTest,
3081 CreateOfferWithMultipleAVMediaSections) {
3082 MediaSessionOptions opts;
3083 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_1", cricket::MD_SENDRECV, kActive,
3084 &opts);
3085 AttachSenderToMediaSection("audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003086 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003087
3088 AddMediaSection(MEDIA_TYPE_VIDEO, "video_1", cricket::MD_SENDRECV, kActive,
3089 &opts);
3090 AttachSenderToMediaSection("video_1", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003091 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003092
3093 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_2", cricket::MD_SENDRECV, kActive,
3094 &opts);
3095 AttachSenderToMediaSection("audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003096 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003097
3098 AddMediaSection(MEDIA_TYPE_VIDEO, "video_2", cricket::MD_SENDRECV, kActive,
3099 &opts);
3100 AttachSenderToMediaSection("video_2", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003101 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003102 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3103 ASSERT_TRUE(offer);
3104
3105 ASSERT_EQ(4u, offer->contents().size());
3106 EXPECT_FALSE(offer->contents()[0].rejected);
3107 const AudioContentDescription* acd =
3108 static_cast<const AudioContentDescription*>(
3109 offer->contents()[0].description);
3110 ASSERT_EQ(1u, acd->streams().size());
3111 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
3112 EXPECT_EQ(cricket::MD_SENDRECV, acd->direction());
3113
3114 EXPECT_FALSE(offer->contents()[1].rejected);
3115 const VideoContentDescription* vcd =
3116 static_cast<const VideoContentDescription*>(
3117 offer->contents()[1].description);
3118 ASSERT_EQ(1u, vcd->streams().size());
3119 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
3120 EXPECT_EQ(cricket::MD_SENDRECV, vcd->direction());
3121
3122 EXPECT_FALSE(offer->contents()[2].rejected);
3123 acd = static_cast<const AudioContentDescription*>(
3124 offer->contents()[2].description);
3125 ASSERT_EQ(1u, acd->streams().size());
3126 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
3127 EXPECT_EQ(cricket::MD_SENDRECV, acd->direction());
3128
3129 EXPECT_FALSE(offer->contents()[3].rejected);
3130 vcd = static_cast<const VideoContentDescription*>(
3131 offer->contents()[3].description);
3132 ASSERT_EQ(1u, vcd->streams().size());
3133 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
3134 EXPECT_EQ(cricket::MD_SENDRECV, vcd->direction());
3135}
3136
3137// Test that we can create an answer with multiple media sections of same media
3138// type.
3139TEST_F(MediaSessionDescriptionFactoryTest,
3140 CreateAnswerWithMultipleAVMediaSections) {
3141 MediaSessionOptions opts;
3142 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_1", cricket::MD_SENDRECV, kActive,
3143 &opts);
3144 AttachSenderToMediaSection("audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003145 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003146
3147 AddMediaSection(MEDIA_TYPE_VIDEO, "video_1", cricket::MD_SENDRECV, kActive,
3148 &opts);
3149 AttachSenderToMediaSection("video_1", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003150 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003151
3152 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_2", cricket::MD_SENDRECV, kActive,
3153 &opts);
3154 AttachSenderToMediaSection("audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003155 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003156
3157 AddMediaSection(MEDIA_TYPE_VIDEO, "video_2", cricket::MD_SENDRECV, kActive,
3158 &opts);
3159 AttachSenderToMediaSection("video_2", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003160 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003161
3162 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3163 ASSERT_TRUE(offer);
3164 std::unique_ptr<SessionDescription> answer(
3165 f2_.CreateAnswer(offer.get(), opts, nullptr));
3166
3167 ASSERT_EQ(4u, answer->contents().size());
3168 EXPECT_FALSE(answer->contents()[0].rejected);
3169 const AudioContentDescription* acd =
3170 static_cast<const AudioContentDescription*>(
3171 answer->contents()[0].description);
3172 ASSERT_EQ(1u, acd->streams().size());
3173 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
3174 EXPECT_EQ(cricket::MD_SENDRECV, acd->direction());
3175
3176 EXPECT_FALSE(answer->contents()[1].rejected);
3177 const VideoContentDescription* vcd =
3178 static_cast<const VideoContentDescription*>(
3179 answer->contents()[1].description);
3180 ASSERT_EQ(1u, vcd->streams().size());
3181 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
3182 EXPECT_EQ(cricket::MD_SENDRECV, vcd->direction());
3183
3184 EXPECT_FALSE(answer->contents()[2].rejected);
3185 acd = static_cast<const AudioContentDescription*>(
3186 answer->contents()[2].description);
3187 ASSERT_EQ(1u, acd->streams().size());
3188 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
3189 EXPECT_EQ(cricket::MD_SENDRECV, acd->direction());
3190
3191 EXPECT_FALSE(answer->contents()[3].rejected);
3192 vcd = static_cast<const VideoContentDescription*>(
3193 answer->contents()[3].description);
3194 ASSERT_EQ(1u, vcd->streams().size());
3195 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
3196 EXPECT_EQ(cricket::MD_SENDRECV, vcd->direction());
3197}
3198
3199// Test that the media section will be rejected in offer if the corresponding
3200// MediaDescriptionOptions is stopped by the offerer.
3201TEST_F(MediaSessionDescriptionFactoryTest,
3202 CreateOfferWithMediaSectionStoppedByOfferer) {
3203 // Create an offer with two audio sections and one of them is stopped.
3204 MediaSessionOptions offer_opts;
3205 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1", cricket::MD_SENDRECV, kActive,
3206 &offer_opts);
3207 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2", cricket::MD_INACTIVE, kStopped,
3208 &offer_opts);
3209 std::unique_ptr<SessionDescription> offer(
3210 f1_.CreateOffer(offer_opts, nullptr));
3211 ASSERT_TRUE(offer);
3212 ASSERT_EQ(2u, offer->contents().size());
3213 EXPECT_FALSE(offer->contents()[0].rejected);
3214 EXPECT_TRUE(offer->contents()[1].rejected);
3215}
3216
3217// Test that the media section will be rejected in answer if the corresponding
3218// MediaDescriptionOptions is stopped by the offerer.
3219TEST_F(MediaSessionDescriptionFactoryTest,
3220 CreateAnswerWithMediaSectionStoppedByOfferer) {
3221 // Create an offer with two audio sections and one of them is stopped.
3222 MediaSessionOptions offer_opts;
3223 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1", cricket::MD_SENDRECV, kActive,
3224 &offer_opts);
3225 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2", cricket::MD_INACTIVE, kStopped,
3226 &offer_opts);
3227 std::unique_ptr<SessionDescription> offer(
3228 f1_.CreateOffer(offer_opts, nullptr));
3229 ASSERT_TRUE(offer);
3230 ASSERT_EQ(2u, offer->contents().size());
3231 EXPECT_FALSE(offer->contents()[0].rejected);
3232 EXPECT_TRUE(offer->contents()[1].rejected);
3233
3234 // Create an answer based on the offer.
3235 MediaSessionOptions answer_opts;
3236 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1", cricket::MD_SENDRECV, kActive,
3237 &answer_opts);
3238 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2", cricket::MD_SENDRECV, kActive,
3239 &answer_opts);
3240 std::unique_ptr<SessionDescription> answer(
3241 f2_.CreateAnswer(offer.get(), answer_opts, nullptr));
3242 ASSERT_EQ(2u, answer->contents().size());
3243 EXPECT_FALSE(answer->contents()[0].rejected);
3244 EXPECT_TRUE(answer->contents()[1].rejected);
3245}
3246
3247// Test that the media section will be rejected in answer if the corresponding
3248// MediaDescriptionOptions is stopped by the answerer.
3249TEST_F(MediaSessionDescriptionFactoryTest,
3250 CreateAnswerWithMediaSectionRejectedByAnswerer) {
3251 // Create an offer with two audio sections.
3252 MediaSessionOptions offer_opts;
3253 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1", cricket::MD_SENDRECV, kActive,
3254 &offer_opts);
3255 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2", cricket::MD_SENDRECV, kActive,
3256 &offer_opts);
3257 std::unique_ptr<SessionDescription> offer(
3258 f1_.CreateOffer(offer_opts, nullptr));
3259 ASSERT_TRUE(offer);
3260 ASSERT_EQ(2u, offer->contents().size());
3261 ASSERT_FALSE(offer->contents()[0].rejected);
3262 ASSERT_FALSE(offer->contents()[1].rejected);
3263
3264 // The answerer rejects one of the audio sections.
3265 MediaSessionOptions answer_opts;
3266 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1", cricket::MD_SENDRECV, kActive,
3267 &answer_opts);
3268 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2", cricket::MD_INACTIVE, kStopped,
3269 &answer_opts);
3270 std::unique_ptr<SessionDescription> answer(
3271 f2_.CreateAnswer(offer.get(), answer_opts, nullptr));
3272 ASSERT_EQ(2u, answer->contents().size());
3273 EXPECT_FALSE(answer->contents()[0].rejected);
3274 EXPECT_TRUE(answer->contents()[1].rejected);
3275}
3276
3277// Test the generated media sections has the same order of the
3278// corresponding MediaDescriptionOptions.
3279TEST_F(MediaSessionDescriptionFactoryTest,
3280 CreateOfferRespectsMediaDescriptionOptionsOrder) {
3281 MediaSessionOptions opts;
3282 // This tests put video section first because normally audio comes first by
3283 // default.
3284 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_SENDRECV, kActive,
3285 &opts);
3286 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_SENDRECV, kActive,
3287 &opts);
3288 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3289
3290 ASSERT_TRUE(offer);
3291 ASSERT_EQ(2u, offer->contents().size());
3292 EXPECT_EQ("video", offer->contents()[0].name);
3293 EXPECT_EQ("audio", offer->contents()[1].name);
3294}
3295
3296// Test that different media sections using the same codec have same payload
3297// type.
3298TEST_F(MediaSessionDescriptionFactoryTest,
3299 PayloadTypesSharedByMediaSectionsOfSameType) {
3300 MediaSessionOptions opts;
3301 AddMediaSection(MEDIA_TYPE_VIDEO, "video1", cricket::MD_SENDRECV, kActive,
3302 &opts);
3303 AddMediaSection(MEDIA_TYPE_VIDEO, "video2", cricket::MD_SENDRECV, kActive,
3304 &opts);
3305 // Create an offer with two video sections using same codecs.
3306 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3307 ASSERT_TRUE(offer);
3308 ASSERT_EQ(2u, offer->contents().size());
3309 const VideoContentDescription* vcd1 =
3310 static_cast<const VideoContentDescription*>(
3311 offer->contents()[0].description);
3312 const VideoContentDescription* vcd2 =
3313 static_cast<const VideoContentDescription*>(
3314 offer->contents()[1].description);
3315 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3316 ASSERT_EQ(2u, vcd1->codecs().size());
3317 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3318 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3319 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
3320 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
3321
3322 // Create answer and negotiate the codecs.
3323 std::unique_ptr<SessionDescription> answer(
3324 f2_.CreateAnswer(offer.get(), opts, nullptr));
3325 ASSERT_TRUE(answer);
3326 ASSERT_EQ(2u, answer->contents().size());
3327 vcd1 = static_cast<const VideoContentDescription*>(
3328 answer->contents()[0].description);
3329 vcd2 = static_cast<const VideoContentDescription*>(
3330 answer->contents()[1].description);
3331 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3332 ASSERT_EQ(1u, vcd1->codecs().size());
3333 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3334 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3335}
3336
3337// Test that the codec preference order per media section is respected in
3338// subsequent offer.
3339TEST_F(MediaSessionDescriptionFactoryTest,
3340 CreateOfferRespectsCodecPreferenceOrder) {
3341 MediaSessionOptions opts;
3342 AddMediaSection(MEDIA_TYPE_VIDEO, "video1", cricket::MD_SENDRECV, kActive,
3343 &opts);
3344 AddMediaSection(MEDIA_TYPE_VIDEO, "video2", cricket::MD_SENDRECV, kActive,
3345 &opts);
3346 // Create an offer with two video sections using same codecs.
3347 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3348 ASSERT_TRUE(offer);
3349 ASSERT_EQ(2u, offer->contents().size());
3350 VideoContentDescription* vcd1 =
3351 static_cast<VideoContentDescription*>(offer->contents()[0].description);
3352 const VideoContentDescription* vcd2 =
3353 static_cast<const VideoContentDescription*>(
3354 offer->contents()[1].description);
3355 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3356 EXPECT_EQ(video_codecs, vcd1->codecs());
3357 EXPECT_EQ(video_codecs, vcd2->codecs());
3358
3359 // Change the codec preference of the first video section and create a
3360 // follow-up offer.
3361 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3362 vcd1->set_codecs(video_codecs_reverse);
3363 std::unique_ptr<SessionDescription> updated_offer(
3364 f1_.CreateOffer(opts, offer.get()));
3365 vcd1 = static_cast<VideoContentDescription*>(
3366 updated_offer->contents()[0].description);
3367 vcd2 = static_cast<const VideoContentDescription*>(
3368 updated_offer->contents()[1].description);
3369 // The video codec preference order should be respected.
3370 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3371 EXPECT_EQ(video_codecs, vcd2->codecs());
3372}
3373
3374// Test that the codec preference order per media section is respected in
3375// the answer.
3376TEST_F(MediaSessionDescriptionFactoryTest,
3377 CreateAnswerRespectsCodecPreferenceOrder) {
3378 MediaSessionOptions opts;
3379 AddMediaSection(MEDIA_TYPE_VIDEO, "video1", cricket::MD_SENDRECV, kActive,
3380 &opts);
3381 AddMediaSection(MEDIA_TYPE_VIDEO, "video2", cricket::MD_SENDRECV, kActive,
3382 &opts);
3383 // Create an offer with two video sections using same codecs.
3384 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3385 ASSERT_TRUE(offer);
3386 ASSERT_EQ(2u, offer->contents().size());
3387 VideoContentDescription* vcd1 =
3388 static_cast<VideoContentDescription*>(offer->contents()[0].description);
3389 const VideoContentDescription* vcd2 =
3390 static_cast<const VideoContentDescription*>(
3391 offer->contents()[1].description);
3392 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3393 EXPECT_EQ(video_codecs, vcd1->codecs());
3394 EXPECT_EQ(video_codecs, vcd2->codecs());
3395
3396 // Change the codec preference of the first video section and create an
3397 // answer.
3398 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3399 vcd1->set_codecs(video_codecs_reverse);
3400 std::unique_ptr<SessionDescription> answer(
3401 f1_.CreateAnswer(offer.get(), opts, nullptr));
3402 vcd1 =
3403 static_cast<VideoContentDescription*>(answer->contents()[0].description);
3404 vcd2 = static_cast<const VideoContentDescription*>(
3405 answer->contents()[1].description);
3406 // The video codec preference order should be respected.
3407 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3408 EXPECT_EQ(video_codecs, vcd2->codecs());
3409}
3410
zhihuangcf5b37c2016-05-05 11:44:35 -07003411class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
3412 public:
3413 MediaProtocolTest() : f1_(&tdf1_), f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -07003414 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
3415 MAKE_VECTOR(kAudioCodecs1));
zhihuangcf5b37c2016-05-05 11:44:35 -07003416 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
3417 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07003418 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
3419 MAKE_VECTOR(kAudioCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07003420 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
3421 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
3422 f1_.set_secure(SEC_ENABLED);
3423 f2_.set_secure(SEC_ENABLED);
3424 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07003425 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07003426 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07003427 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07003428 tdf1_.set_secure(SEC_ENABLED);
3429 tdf2_.set_secure(SEC_ENABLED);
3430 }
3431
3432 protected:
3433 MediaSessionDescriptionFactory f1_;
3434 MediaSessionDescriptionFactory f2_;
3435 TransportDescriptionFactory tdf1_;
3436 TransportDescriptionFactory tdf2_;
3437};
3438
3439TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
3440 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003441 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
zhihuangcf5b37c2016-05-05 11:44:35 -07003442 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3443 ASSERT_TRUE(offer.get() != nullptr);
3444 // Set the protocol for all the contents.
3445 for (auto content : offer.get()->contents()) {
3446 static_cast<MediaContentDescription*>(content.description)
3447 ->set_protocol(GetParam());
3448 }
3449 std::unique_ptr<SessionDescription> answer(
3450 f2_.CreateAnswer(offer.get(), opts, nullptr));
3451 const ContentInfo* ac = answer->GetContentByName("audio");
3452 const ContentInfo* vc = answer->GetContentByName("video");
3453 ASSERT_TRUE(ac != nullptr);
3454 ASSERT_TRUE(vc != nullptr);
3455 EXPECT_FALSE(ac->rejected); // the offer is accepted
3456 EXPECT_FALSE(vc->rejected);
3457 const AudioContentDescription* acd =
3458 static_cast<const AudioContentDescription*>(ac->description);
3459 const VideoContentDescription* vcd =
3460 static_cast<const VideoContentDescription*>(vc->description);
3461 EXPECT_EQ(GetParam(), acd->protocol());
3462 EXPECT_EQ(GetParam(), vcd->protocol());
3463}
3464
3465INSTANTIATE_TEST_CASE_P(MediaProtocolPatternTest,
3466 MediaProtocolTest,
3467 ::testing::ValuesIn(kMediaProtocols));
3468INSTANTIATE_TEST_CASE_P(MediaProtocolDtlsPatternTest,
3469 MediaProtocolTest,
3470 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07003471
3472TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
3473 TransportDescriptionFactory tdf;
3474 MediaSessionDescriptionFactory sf(&tdf);
3475 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
3476 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
3477
3478 // The merged list of codecs should contain any send codecs that are also
3479 // nominally in the recieve codecs list. Payload types should be picked from
3480 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
3481 // (set to 1). This equals what happens when the send codecs are used in an
3482 // offer and the receive codecs are used in the following answer.
3483 const std::vector<AudioCodec> sendrecv_codecs =
3484 MAKE_VECTOR(kAudioCodecsAnswer);
3485 const std::vector<AudioCodec> no_codecs;
3486
3487 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
3488 << "Please don't change shared test data!";
3489 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
3490 << "Please don't change shared test data!";
3491 // Alter iLBC send codec to have zero channels, to test that that is handled
3492 // properly.
3493 send_codecs[1].channels = 0;
3494
3495 // Alther iLBC receive codec to be lowercase, to test that case conversions
3496 // are handled properly.
3497 recv_codecs[2].name = "ilbc";
3498
3499 // Test proper merge
3500 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003501 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
3502 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
3503 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003504
3505 // Test empty send codecs list
3506 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003507 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
3508 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
3509 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003510
3511 // Test empty recv codecs list
3512 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003513 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
3514 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
3515 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003516
3517 // Test all empty codec lists
3518 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003519 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
3520 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
3521 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003522}
3523
3524namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07003525// Compare the two vectors of codecs ignoring the payload type.
3526template <class Codec>
3527bool CodecsMatch(const std::vector<Codec>& codecs1,
3528 const std::vector<Codec>& codecs2) {
3529 if (codecs1.size() != codecs2.size()) {
3530 return false;
3531 }
3532
3533 for (size_t i = 0; i < codecs1.size(); ++i) {
3534 if (!codecs1[i].Matches(codecs2[i])) {
3535 return false;
3536 }
3537 }
3538 return true;
3539}
3540
3541void TestAudioCodecsOffer(MediaContentDirection direction) {
ossu075af922016-06-14 03:29:38 -07003542 TransportDescriptionFactory tdf;
3543 MediaSessionDescriptionFactory sf(&tdf);
3544 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
3545 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
3546 const std::vector<AudioCodec> sendrecv_codecs =
3547 MAKE_VECTOR(kAudioCodecsAnswer);
3548 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07003549
3550 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003551 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", direction, kActive, &opts);
3552
3553 if (RtpTransceiverDirection::FromMediaContentDirection(direction).send) {
3554 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003555 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003556 }
ossu075af922016-06-14 03:29:38 -07003557
3558 std::unique_ptr<SessionDescription> offer(sf.CreateOffer(opts, NULL));
3559 ASSERT_TRUE(offer.get() != NULL);
3560 const ContentInfo* ac = offer->GetContentByName("audio");
3561
3562 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07003563 // that the codecs put in are right. This happens when we neither want to
3564 // send nor receive audio. The checks are still in place if at some point
3565 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07003566 if (ac) {
3567 AudioContentDescription* acd =
3568 static_cast<AudioContentDescription*>(ac->description);
zhihuang1c378ed2017-08-17 14:10:50 -07003569 // sendrecv and inactive should both present lists as if the channel was
3570 // to be used for sending and receiving. Inactive essentially means it
3571 // might eventually be used anything, but we don't know more at this
3572 // moment.
ossu075af922016-06-14 03:29:38 -07003573 if (acd->direction() == cricket::MD_SENDONLY) {
zhihuang1c378ed2017-08-17 14:10:50 -07003574 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07003575 } else if (acd->direction() == cricket::MD_RECVONLY) {
zhihuang1c378ed2017-08-17 14:10:50 -07003576 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07003577 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07003578 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07003579 }
3580 }
3581}
3582
3583static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07003584 AudioCodec(0, "codec0", 16000, -1, 1),
3585 AudioCodec(1, "codec1", 8000, 13300, 1),
3586 AudioCodec(2, "codec2", 8000, 64000, 1),
3587 AudioCodec(3, "codec3", 8000, 64000, 1),
3588 AudioCodec(4, "codec4", 8000, 0, 2),
3589 AudioCodec(5, "codec5", 32000, 0, 1),
3590 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07003591
zhihuang1c378ed2017-08-17 14:10:50 -07003592/* The codecs groups below are chosen as per the matrix below. The objective
3593 * is to have different sets of codecs in the inputs, to get unique sets of
3594 * codecs after negotiation, depending on offer and answer communication
3595 * directions. One-way directions in the offer should either result in the
3596 * opposite direction in the answer, or an inactive answer. Regardless, the
3597 * choice of codecs should be as if the answer contained the opposite
3598 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07003599 *
3600 * | Offer | Answer | Result
3601 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
3602 * 0 | x - - | - x - | x - - - -
3603 * 1 | x x x | - x - | x - - x -
3604 * 2 | - x - | x - - | - x - - -
3605 * 3 | x x x | x - - | - x x - -
3606 * 4 | - x - | x x x | - x - - -
3607 * 5 | x - - | x x x | x - - - -
3608 * 6 | x x x | x x x | x x x x x
3609 */
3610// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07003611static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
3612static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07003613// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
3614// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07003615static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
3616static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07003617// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07003618static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
3619static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
3620static const int kResultSendrecv_SendCodecs[] = {3, 6};
3621static const int kResultSendrecv_RecvCodecs[] = {1, 6};
3622static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07003623
3624template <typename T, int IDXS>
3625std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
3626 std::vector<T> out;
3627 out.reserve(IDXS);
3628 for (int idx : indices)
3629 out.push_back(array[idx]);
3630
3631 return out;
3632}
3633
3634void TestAudioCodecsAnswer(MediaContentDirection offer_direction,
3635 MediaContentDirection answer_direction,
3636 bool add_legacy_stream) {
3637 TransportDescriptionFactory offer_tdf;
3638 TransportDescriptionFactory answer_tdf;
3639 MediaSessionDescriptionFactory offer_factory(&offer_tdf);
3640 MediaSessionDescriptionFactory answer_factory(&answer_tdf);
3641 offer_factory.set_audio_codecs(
3642 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
3643 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
3644 answer_factory.set_audio_codecs(
3645 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
3646 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
3647
ossu075af922016-06-14 03:29:38 -07003648 MediaSessionOptions offer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003649 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", offer_direction, kActive,
3650 &offer_opts);
3651
3652 if (RtpTransceiverDirection::FromMediaContentDirection(offer_direction)
3653 .send) {
3654 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003655 {kMediaStream1}, 1, &offer_opts);
ossu075af922016-06-14 03:29:38 -07003656 }
3657
3658 std::unique_ptr<SessionDescription> offer(
3659 offer_factory.CreateOffer(offer_opts, NULL));
3660 ASSERT_TRUE(offer.get() != NULL);
3661
3662 MediaSessionOptions answer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003663 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", answer_direction, kActive,
3664 &answer_opts);
3665
3666 if (RtpTransceiverDirection::FromMediaContentDirection(answer_direction)
3667 .send) {
3668 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003669 {kMediaStream1}, 1, &answer_opts);
ossu075af922016-06-14 03:29:38 -07003670 }
3671 std::unique_ptr<SessionDescription> answer(
3672 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL));
3673 const ContentInfo* ac = answer->GetContentByName("audio");
3674
zhihuang1c378ed2017-08-17 14:10:50 -07003675 // If the factory didn't add any audio content to the answer, we cannot
3676 // check that the codecs put in are right. This happens when we neither want
3677 // to send nor receive audio. The checks are still in place if at some point
3678 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07003679 if (ac) {
3680 const AudioContentDescription* acd =
3681 static_cast<const AudioContentDescription*>(ac->description);
3682 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
3683
ossu075af922016-06-14 03:29:38 -07003684 std::vector<AudioCodec> target_codecs;
3685 // For offers with sendrecv or inactive, we should never reply with more
3686 // codecs than offered, with these codec sets.
3687 switch (offer_direction) {
3688 case cricket::MD_INACTIVE:
3689 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
3690 kResultSendrecv_SendrecvCodecs);
3691 break;
3692 case cricket::MD_SENDONLY:
zhihuang1c378ed2017-08-17 14:10:50 -07003693 target_codecs =
3694 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07003695 break;
3696 case cricket::MD_RECVONLY:
zhihuang1c378ed2017-08-17 14:10:50 -07003697 target_codecs =
3698 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07003699 break;
3700 case cricket::MD_SENDRECV:
3701 if (acd->direction() == cricket::MD_SENDONLY) {
zhihuang1c378ed2017-08-17 14:10:50 -07003702 target_codecs =
3703 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07003704 } else if (acd->direction() == cricket::MD_RECVONLY) {
zhihuang1c378ed2017-08-17 14:10:50 -07003705 target_codecs =
3706 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07003707 } else {
3708 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
3709 kResultSendrecv_SendrecvCodecs);
3710 }
3711 break;
3712 }
3713
zhihuang1c378ed2017-08-17 14:10:50 -07003714 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
ossu075af922016-06-14 03:29:38 -07003715 std::stringstream os;
3716 bool first = true;
3717 os << "{";
3718 for (const auto& c : codecs) {
3719 os << (first ? " " : ", ") << c.id;
3720 first = false;
3721 }
3722 os << " }";
3723 return os.str();
3724 };
3725
3726 EXPECT_TRUE(acd->codecs() == target_codecs)
3727 << "Expected: " << format_codecs(target_codecs)
3728 << ", got: " << format_codecs(acd->codecs())
3729 << "; Offered: " << MediaContentDirectionToString(offer_direction)
3730 << ", answerer wants: "
3731 << MediaContentDirectionToString(answer_direction)
3732 << "; got: " << MediaContentDirectionToString(acd->direction());
3733 } else {
3734 EXPECT_EQ(offer_direction, cricket::MD_INACTIVE)
zhihuang1c378ed2017-08-17 14:10:50 -07003735 << "Only inactive offers are allowed to not generate any audio "
3736 "content";
ossu075af922016-06-14 03:29:38 -07003737 }
3738}
brandtr03d5fb12016-11-22 03:37:59 -08003739
3740} // namespace
ossu075af922016-06-14 03:29:38 -07003741
3742class AudioCodecsOfferTest
zhihuang1c378ed2017-08-17 14:10:50 -07003743 : public ::testing::TestWithParam<MediaContentDirection> {};
ossu075af922016-06-14 03:29:38 -07003744
3745TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003746 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07003747}
3748
3749INSTANTIATE_TEST_CASE_P(MediaSessionDescriptionFactoryTest,
3750 AudioCodecsOfferTest,
zhihuang1c378ed2017-08-17 14:10:50 -07003751 ::testing::Values(cricket::MD_SENDONLY,
3752 cricket::MD_RECVONLY,
3753 cricket::MD_SENDRECV,
3754 cricket::MD_INACTIVE));
ossu075af922016-06-14 03:29:38 -07003755
3756class AudioCodecsAnswerTest
ehmaldonadoabcef5d2017-02-08 04:07:11 -08003757 : public ::testing::TestWithParam<::testing::tuple<MediaContentDirection,
3758 MediaContentDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07003759 bool>> {};
ossu075af922016-06-14 03:29:38 -07003760
3761TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08003762 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
3763 ::testing::get<1>(GetParam()),
3764 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07003765}
3766
zhihuang1c378ed2017-08-17 14:10:50 -07003767INSTANTIATE_TEST_CASE_P(
3768 MediaSessionDescriptionFactoryTest,
3769 AudioCodecsAnswerTest,
3770 ::testing::Combine(::testing::Values(cricket::MD_SENDONLY,
3771 cricket::MD_RECVONLY,
3772 cricket::MD_SENDRECV,
3773 cricket::MD_INACTIVE),
3774 ::testing::Values(cricket::MD_SENDONLY,
3775 cricket::MD_RECVONLY,
3776 cricket::MD_SENDRECV,
3777 cricket::MD_INACTIVE),
3778 ::testing::Bool()));