blob: f87dda1bf377d89e5f79638e1744a8a4de6dd1b7 [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
kjellandera96e2d72016-02-04 23:52:28 -080015#include "webrtc/media/base/codec.h"
16#include "webrtc/media/base/testutils.h"
kjellanderf4752772016-03-02 05:42:30 -080017#include "webrtc/p2p/base/p2pconstants.h"
kjellandera96e2d72016-02-04 23:52:28 -080018#include "webrtc/p2p/base/transportdescription.h"
19#include "webrtc/p2p/base/transportinfo.h"
kjellander@webrtc.org9b8df252016-02-12 06:47:59 +010020#include "webrtc/pc/mediasession.h"
21#include "webrtc/pc/srtpfilter.h"
Edward Lemurc20978e2017-07-06 19:44:34 +020022#include "webrtc/rtc_base/checks.h"
23#include "webrtc/rtc_base/fakesslidentity.h"
24#include "webrtc/rtc_base/gunit.h"
25#include "webrtc/rtc_base/messagedigest.h"
26#include "webrtc/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(),
259 [mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
260}
261
262// Add a media section to the |session_options|.
263static void AddMediaSection(MediaType type,
264 const std::string& mid,
265 MediaContentDirection direction,
266 bool stopped,
267 MediaSessionOptions* opts) {
268 opts->media_description_options.push_back(MediaDescriptionOptions(
269 type, mid,
270 cricket::RtpTransceiverDirection::FromMediaContentDirection(direction),
271 stopped));
272}
273
274static void AddAudioVideoSections(MediaContentDirection direction,
275 MediaSessionOptions* opts) {
276 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", direction, kActive, opts);
277 AddMediaSection(MEDIA_TYPE_VIDEO, "video", direction, kActive, opts);
278}
279
280static void AddDataSection(cricket::DataChannelType dct,
281 MediaContentDirection direction,
282 MediaSessionOptions* opts) {
283 opts->data_channel_type = dct;
284 AddMediaSection(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
285}
286
287static void AttachSenderToMediaSection(const std::string& mid,
288 MediaType type,
289 const std::string& track_id,
290 const std::string& stream_id,
291 int num_sim_layer,
292 MediaSessionOptions* session_options) {
293 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
294 switch (type) {
295 case MEDIA_TYPE_AUDIO:
296 it->AddAudioSender(track_id, stream_id);
297 break;
298 case MEDIA_TYPE_VIDEO:
299 it->AddVideoSender(track_id, stream_id, num_sim_layer);
300 break;
301 case MEDIA_TYPE_DATA:
302 it->AddRtpDataChannel(track_id, stream_id);
303 break;
304 default:
305 RTC_NOTREACHED();
306 }
307}
308
309static void DetachSenderFromMediaSection(const std::string& mid,
310 const std::string& track_id,
311 MediaSessionOptions* session_options) {
312 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
313 auto sender_it = it->sender_options.begin();
314 for (; sender_it != it->sender_options.end(); ++sender_it) {
315 if (sender_it->track_id == track_id) {
316 it->sender_options.erase(sender_it);
317 return;
318 }
319 }
320 RTC_NOTREACHED();
321}
322
323// Helper function used to create a default MediaSessionOptions for Plan B SDP.
324// (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
325static MediaSessionOptions CreatePlanBMediaSessionOptions() {
326 MediaSessionOptions session_options;
327 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
328 &session_options);
329 return session_options;
330}
331
332// TODO(zhihuang): Most of these tests were written while MediaSessionOptions
333// was designed for Plan B SDP, where only one audio "m=" section and one video
334// "m=" section could be generated, and ordering couldn't be controlled. Many of
335// these tests may be obsolete as a result, and should be refactored or removed.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000336class MediaSessionDescriptionFactoryTest : public testing::Test {
337 public:
zhihuang1c378ed2017-08-17 14:10:50 -0700338 MediaSessionDescriptionFactoryTest() : f1_(&tdf1_), f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -0700339 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
340 MAKE_VECTOR(kAudioCodecs1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000341 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
342 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700343 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
344 MAKE_VECTOR(kAudioCodecs2));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000345 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
346 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200347 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700348 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200349 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700350 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000351 }
352
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000353 // Create a video StreamParamsVec object with:
354 // - one video stream with 3 simulcast streams and FEC,
355 StreamParamsVec CreateComplexVideoStreamParamsVec() {
356 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
357 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
358 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
359 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
360
361 std::vector<SsrcGroup> ssrc_groups;
362 ssrc_groups.push_back(sim_group);
363 ssrc_groups.push_back(fec_group1);
364 ssrc_groups.push_back(fec_group2);
365 ssrc_groups.push_back(fec_group3);
366
367 StreamParams simulcast_params;
368 simulcast_params.id = kVideoTrack1;
369 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
370 simulcast_params.ssrc_groups = ssrc_groups;
371 simulcast_params.cname = "Video_SIM_FEC";
372 simulcast_params.sync_label = kMediaStream1;
373
374 StreamParamsVec video_streams;
375 video_streams.push_back(simulcast_params);
376
377 return video_streams;
378 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000379
380 bool CompareCryptoParams(const CryptoParamsVec& c1,
381 const CryptoParamsVec& c2) {
382 if (c1.size() != c2.size())
383 return false;
384 for (size_t i = 0; i < c1.size(); ++i)
385 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
386 c1[i].key_params != c2[i].key_params ||
387 c1[i].session_params != c2[i].session_params)
388 return false;
389 return true;
390 }
391
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700392 // Returns true if the transport info contains "renomination" as an
393 // ICE option.
394 bool GetIceRenomination(const TransportInfo* transport_info) {
395 const std::vector<std::string>& ice_options =
396 transport_info->description.transport_options;
deadbeef30952b42017-04-21 02:41:29 -0700397 auto iter =
398 std::find(ice_options.begin(), ice_options.end(), "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700399 return iter != ice_options.end();
400 }
401
zhihuang1c378ed2017-08-17 14:10:50 -0700402 void TestTransportInfo(bool offer,
403 MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000404 bool has_current_desc) {
405 const std::string current_audio_ufrag = "current_audio_ufrag";
406 const std::string current_audio_pwd = "current_audio_pwd";
407 const std::string current_video_ufrag = "current_video_ufrag";
408 const std::string current_video_pwd = "current_video_pwd";
409 const std::string current_data_ufrag = "current_data_ufrag";
410 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800411 std::unique_ptr<SessionDescription> current_desc;
412 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000413 if (has_current_desc) {
414 current_desc.reset(new SessionDescription());
415 EXPECT_TRUE(current_desc->AddTransportInfo(
416 TransportInfo("audio",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700417 TransportDescription(current_audio_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000418 current_audio_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000419 EXPECT_TRUE(current_desc->AddTransportInfo(
420 TransportInfo("video",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700421 TransportDescription(current_video_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000422 current_video_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000423 EXPECT_TRUE(current_desc->AddTransportInfo(
424 TransportInfo("data",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700425 TransportDescription(current_data_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000426 current_data_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000427 }
428 if (offer) {
429 desc.reset(f1_.CreateOffer(options, current_desc.get()));
430 } else {
kwiberg31022942016-03-11 14:18:21 -0800431 std::unique_ptr<SessionDescription> offer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000432 offer.reset(f1_.CreateOffer(options, NULL));
433 desc.reset(f1_.CreateAnswer(offer.get(), options, current_desc.get()));
434 }
435 ASSERT_TRUE(desc.get() != NULL);
436 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000437 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000438 EXPECT_TRUE(ti_audio != NULL);
439 if (has_current_desc) {
440 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
441 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
442 } else {
443 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
444 ti_audio->description.ice_ufrag.size());
445 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
446 ti_audio->description.ice_pwd.size());
447 }
zhihuang1c378ed2017-08-17 14:10:50 -0700448 auto media_desc_options_it =
449 FindFirstMediaDescriptionByMid("audio", &options);
450 EXPECT_EQ(
451 media_desc_options_it->transport_options.enable_ice_renomination,
452 GetIceRenomination(ti_audio));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000453
454 } else {
455 EXPECT_TRUE(ti_audio == NULL);
456 }
457 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000458 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000459 EXPECT_TRUE(ti_video != NULL);
460 if (options.bundle_enabled) {
461 EXPECT_EQ(ti_audio->description.ice_ufrag,
462 ti_video->description.ice_ufrag);
463 EXPECT_EQ(ti_audio->description.ice_pwd,
464 ti_video->description.ice_pwd);
465 } else {
466 if (has_current_desc) {
467 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
468 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
469 } else {
470 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
471 ti_video->description.ice_ufrag.size());
472 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
473 ti_video->description.ice_pwd.size());
474 }
475 }
zhihuang1c378ed2017-08-17 14:10:50 -0700476 auto media_desc_options_it =
477 FindFirstMediaDescriptionByMid("video", &options);
478 EXPECT_EQ(
479 media_desc_options_it->transport_options.enable_ice_renomination,
480 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000481 } else {
482 EXPECT_TRUE(ti_video == NULL);
483 }
484 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
485 if (options.has_data()) {
486 EXPECT_TRUE(ti_data != NULL);
487 if (options.bundle_enabled) {
488 EXPECT_EQ(ti_audio->description.ice_ufrag,
489 ti_data->description.ice_ufrag);
490 EXPECT_EQ(ti_audio->description.ice_pwd,
491 ti_data->description.ice_pwd);
492 } else {
493 if (has_current_desc) {
494 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
495 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
496 } else {
497 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
498 ti_data->description.ice_ufrag.size());
499 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
500 ti_data->description.ice_pwd.size());
501 }
502 }
zhihuang1c378ed2017-08-17 14:10:50 -0700503 auto media_desc_options_it =
504 FindFirstMediaDescriptionByMid("data", &options);
505 EXPECT_EQ(
506 media_desc_options_it->transport_options.enable_ice_renomination,
507 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700508
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000509 } else {
510 EXPECT_TRUE(ti_video == NULL);
511 }
512 }
513
514 void TestCryptoWithBundle(bool offer) {
515 f1_.set_secure(SEC_ENABLED);
516 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -0700517 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
518 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
kwiberg31022942016-03-11 14:18:21 -0800519 std::unique_ptr<SessionDescription> ref_desc;
520 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000521 if (offer) {
522 options.bundle_enabled = false;
523 ref_desc.reset(f1_.CreateOffer(options, NULL));
524 options.bundle_enabled = true;
525 desc.reset(f1_.CreateOffer(options, ref_desc.get()));
526 } else {
527 options.bundle_enabled = true;
528 ref_desc.reset(f1_.CreateOffer(options, NULL));
529 desc.reset(f1_.CreateAnswer(ref_desc.get(), options, NULL));
530 }
531 ASSERT_TRUE(desc.get() != NULL);
532 const cricket::MediaContentDescription* audio_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000533 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000534 desc.get()->GetContentDescriptionByName("audio"));
535 ASSERT_TRUE(audio_media_desc != NULL);
536 const cricket::MediaContentDescription* video_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000537 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000538 desc.get()->GetContentDescriptionByName("video"));
539 ASSERT_TRUE(video_media_desc != NULL);
540 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
541 video_media_desc->cryptos()));
542 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
543 EXPECT_EQ(std::string(CS_AES_CM_128_HMAC_SHA1_80),
544 audio_media_desc->cryptos()[0].cipher_suite);
545
546 // Verify the selected crypto is one from the reference audio
547 // media content.
548 const cricket::MediaContentDescription* ref_audio_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000549 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000550 ref_desc.get()->GetContentDescriptionByName("audio"));
551 bool found = false;
552 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
553 if (ref_audio_media_desc->cryptos()[i].Matches(
554 audio_media_desc->cryptos()[0])) {
555 found = true;
556 break;
557 }
558 }
559 EXPECT_TRUE(found);
560 }
561
562 // This test that the audio and video media direction is set to
563 // |expected_direction_in_answer| in an answer if the offer direction is set
zhihuang1c378ed2017-08-17 14:10:50 -0700564 // to |direction_in_offer| and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000565 void TestMediaDirectionInAnswer(
566 cricket::MediaContentDirection direction_in_offer,
567 cricket::MediaContentDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700568 MediaSessionOptions offer_opts;
569 AddAudioVideoSections(direction_in_offer, &offer_opts);
570
571 std::unique_ptr<SessionDescription> offer(
572 f1_.CreateOffer(offer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000573 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700574 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000575 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700576 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000577 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000578
zhihuang1c378ed2017-08-17 14:10:50 -0700579 MediaSessionOptions answer_opts;
580 AddAudioVideoSections(cricket::MD_SENDRECV, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -0800581 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -0700582 f2_.CreateAnswer(offer.get(), answer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000583 const AudioContentDescription* acd_answer =
584 GetFirstAudioContentDescription(answer.get());
585 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
586 const VideoContentDescription* vcd_answer =
587 GetFirstVideoContentDescription(answer.get());
588 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
589 }
590
591 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
592 const cricket::ContentDescription* description = content->description;
nissec8ee8822017-01-18 07:20:55 -0800593 RTC_CHECK(description != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000594 const cricket::AudioContentDescription* audio_content_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000595 static_cast<const cricket::AudioContentDescription*>(description);
nissec8ee8822017-01-18 07:20:55 -0800596 RTC_CHECK(audio_content_desc != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000597 for (size_t i = 0; i < audio_content_desc->codecs().size(); ++i) {
598 if (audio_content_desc->codecs()[i].name == "CN")
599 return false;
600 }
601 return true;
602 }
603
jbauchcb560652016-08-04 05:20:32 -0700604 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
605 MediaSessionOptions offer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -0700606 AddAudioVideoSections(cricket::MD_RECVONLY, &offer_opts);
jbauchcb560652016-08-04 05:20:32 -0700607 offer_opts.crypto_options.enable_gcm_crypto_suites = gcm_offer;
zhihuang1c378ed2017-08-17 14:10:50 -0700608
jbauchcb560652016-08-04 05:20:32 -0700609 MediaSessionOptions answer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -0700610 AddAudioVideoSections(cricket::MD_RECVONLY, &answer_opts);
jbauchcb560652016-08-04 05:20:32 -0700611 answer_opts.crypto_options.enable_gcm_crypto_suites = gcm_answer;
zhihuang1c378ed2017-08-17 14:10:50 -0700612
jbauchcb560652016-08-04 05:20:32 -0700613 f1_.set_secure(SEC_ENABLED);
614 f2_.set_secure(SEC_ENABLED);
615 std::unique_ptr<SessionDescription> offer(
616 f1_.CreateOffer(offer_opts, NULL));
617 ASSERT_TRUE(offer.get() != NULL);
618 std::unique_ptr<SessionDescription> answer(
619 f2_.CreateAnswer(offer.get(), answer_opts, NULL));
620 const ContentInfo* ac = answer->GetContentByName("audio");
621 const ContentInfo* vc = answer->GetContentByName("video");
622 ASSERT_TRUE(ac != NULL);
623 ASSERT_TRUE(vc != NULL);
624 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
625 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
626 const AudioContentDescription* acd =
627 static_cast<const AudioContentDescription*>(ac->description);
628 const VideoContentDescription* vcd =
629 static_cast<const VideoContentDescription*>(vc->description);
630 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
631 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
632 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700633 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700634 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
635 if (gcm_offer && gcm_answer) {
636 ASSERT_CRYPTO(acd, 1U, CS_AEAD_AES_256_GCM);
637 } else {
638 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
639 }
640 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
641 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700642 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700643 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
644 if (gcm_offer && gcm_answer) {
645 ASSERT_CRYPTO(vcd, 1U, CS_AEAD_AES_256_GCM);
646 } else {
647 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
648 }
649 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
650 }
651
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000652 protected:
653 MediaSessionDescriptionFactory f1_;
654 MediaSessionDescriptionFactory f2_;
655 TransportDescriptionFactory tdf1_;
656 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000657};
658
659// Create a typical audio offer, and ensure it matches what we expect.
660TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
661 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800662 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -0700663 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000664 ASSERT_TRUE(offer.get() != NULL);
665 const ContentInfo* ac = offer->GetContentByName("audio");
666 const ContentInfo* vc = offer->GetContentByName("video");
667 ASSERT_TRUE(ac != NULL);
668 ASSERT_TRUE(vc == NULL);
669 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
670 const AudioContentDescription* acd =
671 static_cast<const AudioContentDescription*>(ac->description);
672 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700673 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700674 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000675 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
676 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
677 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
678 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
679}
680
681// Create a typical video offer, and ensure it matches what we expect.
682TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
683 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -0700684 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000685 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800686 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000687 ASSERT_TRUE(offer.get() != NULL);
688 const ContentInfo* ac = offer->GetContentByName("audio");
689 const ContentInfo* vc = offer->GetContentByName("video");
690 ASSERT_TRUE(ac != NULL);
691 ASSERT_TRUE(vc != NULL);
692 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
693 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
694 const AudioContentDescription* acd =
695 static_cast<const AudioContentDescription*>(ac->description);
696 const VideoContentDescription* vcd =
697 static_cast<const VideoContentDescription*>(vc->description);
698 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700699 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700700 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000701 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
702 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
703 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
704 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
705 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
706 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700707 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000708 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
709 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
710 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
711 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
712}
713
714// Test creating an offer with bundle where the Codecs have the same dynamic
715// RTP playlod type. The test verifies that the offer don't contain the
716// duplicate RTP payload types.
717TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
718 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700719 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000720 const DataCodec& offered_data_codec = f2_.data_codecs()[0];
721 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
722 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
723
724 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -0700725 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
726 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000727 opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800728 std::unique_ptr<SessionDescription> offer(f2_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000729 const VideoContentDescription* vcd =
730 GetFirstVideoContentDescription(offer.get());
731 const AudioContentDescription* acd =
732 GetFirstAudioContentDescription(offer.get());
733 const DataContentDescription* dcd =
734 GetFirstDataContentDescription(offer.get());
735 ASSERT_TRUE(NULL != vcd);
736 ASSERT_TRUE(NULL != acd);
737 ASSERT_TRUE(NULL != dcd);
738 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
739 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
740 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
741 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
742 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
743 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
744}
745
zhihuang1c378ed2017-08-17 14:10:50 -0700746// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000747// after an audio only session has been negotiated.
748TEST_F(MediaSessionDescriptionFactoryTest,
749 TestCreateUpdatedVideoOfferWithBundle) {
750 f1_.set_secure(SEC_ENABLED);
751 f2_.set_secure(SEC_ENABLED);
752 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -0700753 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
754 &opts);
755 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_INACTIVE, kStopped,
756 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000757 opts.data_channel_type = cricket::DCT_NONE;
758 opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800759 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
760 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000761 f2_.CreateAnswer(offer.get(), opts, NULL));
762
763 MediaSessionOptions updated_opts;
zhihuang1c378ed2017-08-17 14:10:50 -0700764 AddAudioVideoSections(cricket::MD_RECVONLY, &updated_opts);
765 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000766 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800767 std::unique_ptr<SessionDescription> updated_offer(
768 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000769
770 const AudioContentDescription* acd =
771 GetFirstAudioContentDescription(updated_offer.get());
772 const VideoContentDescription* vcd =
773 GetFirstVideoContentDescription(updated_offer.get());
774 const DataContentDescription* dcd =
775 GetFirstDataContentDescription(updated_offer.get());
776 EXPECT_TRUE(NULL != vcd);
777 EXPECT_TRUE(NULL != acd);
778 EXPECT_TRUE(NULL != dcd);
779
780 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
781 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
782 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
783 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
784 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
785 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
786}
deadbeef44f08192015-12-15 16:20:09 -0800787
wu@webrtc.org78187522013-10-07 23:32:02 +0000788// Create a RTP data offer, and ensure it matches what we expect.
789TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000790 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -0700791 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
792 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000793 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800794 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000795 ASSERT_TRUE(offer.get() != NULL);
796 const ContentInfo* ac = offer->GetContentByName("audio");
797 const ContentInfo* dc = offer->GetContentByName("data");
798 ASSERT_TRUE(ac != NULL);
799 ASSERT_TRUE(dc != NULL);
800 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
801 EXPECT_EQ(std::string(NS_JINGLE_RTP), dc->type);
802 const AudioContentDescription* acd =
803 static_cast<const AudioContentDescription*>(ac->description);
804 const DataContentDescription* dcd =
805 static_cast<const DataContentDescription*>(dc->description);
806 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700807 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700808 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000809 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
810 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
811 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
812 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
813 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
814 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700815 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000816 EXPECT_EQ(cricket::kDataMaxBandwidth,
817 dcd->bandwidth()); // default bandwidth (auto)
818 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
819 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
820 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
821}
822
wu@webrtc.org78187522013-10-07 23:32:02 +0000823// Create an SCTP data offer with bundle without error.
824TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
825 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000826 opts.bundle_enabled = true;
zhihuang1c378ed2017-08-17 14:10:50 -0700827 AddDataSection(cricket::DCT_SCTP, cricket::MD_SENDRECV, &opts);
wu@webrtc.org78187522013-10-07 23:32:02 +0000828 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800829 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
wu@webrtc.org78187522013-10-07 23:32:02 +0000830 EXPECT_TRUE(offer.get() != NULL);
831 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
832}
833
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000834// Test creating an sctp data channel from an already generated offer.
835TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
836 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000837 opts.bundle_enabled = true;
zhihuang1c378ed2017-08-17 14:10:50 -0700838 AddDataSection(cricket::DCT_SCTP, cricket::MD_SENDRECV, &opts);
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000839 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800840 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000841 ASSERT_TRUE(offer1.get() != NULL);
842 const ContentInfo* data = offer1->GetContentByName("data");
843 ASSERT_TRUE(data != NULL);
844 const MediaContentDescription* mdesc =
845 static_cast<const MediaContentDescription*>(data->description);
846 ASSERT_EQ(cricket::kMediaProtocolSctp, mdesc->protocol());
847
848 // Now set data_channel_type to 'none' (default) and make sure that the
849 // datachannel type that gets generated from the previous offer, is of the
850 // same type.
851 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800852 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000853 f1_.CreateOffer(opts, offer1.get()));
854 data = offer2->GetContentByName("data");
855 ASSERT_TRUE(data != NULL);
856 mdesc = static_cast<const MediaContentDescription*>(data->description);
857 EXPECT_EQ(cricket::kMediaProtocolSctp, mdesc->protocol());
858}
859
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000860// Create an audio, video offer without legacy StreamParams.
861TEST_F(MediaSessionDescriptionFactoryTest,
862 TestCreateOfferWithoutLegacyStreams) {
863 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -0700864 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
kwiberg31022942016-03-11 14:18:21 -0800865 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000866 ASSERT_TRUE(offer.get() != NULL);
867 const ContentInfo* ac = offer->GetContentByName("audio");
868 const ContentInfo* vc = offer->GetContentByName("video");
869 ASSERT_TRUE(ac != NULL);
870 ASSERT_TRUE(vc != NULL);
871 const AudioContentDescription* acd =
872 static_cast<const AudioContentDescription*>(ac->description);
873 const VideoContentDescription* vcd =
874 static_cast<const VideoContentDescription*>(vc->description);
875
876 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
877 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
878}
879
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000880// Creates an audio+video sendonly offer.
881TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700882 MediaSessionOptions opts;
883 AddAudioVideoSections(cricket::MD_SENDONLY, &opts);
884 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
885 kMediaStream1, 1, &opts);
886 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
887 kMediaStream1, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000888
zhihuang1c378ed2017-08-17 14:10:50 -0700889 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000890 ASSERT_TRUE(offer.get() != NULL);
891 EXPECT_EQ(2u, offer->contents().size());
892 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
893 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
894
895 EXPECT_EQ(cricket::MD_SENDONLY, GetMediaDirection(&offer->contents()[0]));
896 EXPECT_EQ(cricket::MD_SENDONLY, GetMediaDirection(&offer->contents()[1]));
897}
898
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000899// Verifies that the order of the media contents in the current
900// SessionDescription is preserved in the new SessionDescription.
901TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
902 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -0700903 AddDataSection(cricket::DCT_SCTP, cricket::MD_SENDRECV, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000904
kwiberg31022942016-03-11 14:18:21 -0800905 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000906 ASSERT_TRUE(offer1.get() != NULL);
907 EXPECT_EQ(1u, offer1->contents().size());
908 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
909
zhihuang1c378ed2017-08-17 14:10:50 -0700910 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
911 &opts);
kwiberg31022942016-03-11 14:18:21 -0800912 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000913 f1_.CreateOffer(opts, offer1.get()));
914 ASSERT_TRUE(offer2.get() != NULL);
915 EXPECT_EQ(2u, offer2->contents().size());
916 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
917 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
918
zhihuang1c378ed2017-08-17 14:10:50 -0700919 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
920 &opts);
kwiberg31022942016-03-11 14:18:21 -0800921 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000922 f1_.CreateOffer(opts, offer2.get()));
923 ASSERT_TRUE(offer3.get() != NULL);
924 EXPECT_EQ(3u, offer3->contents().size());
925 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
926 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
927 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000928}
929
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000930// Create a typical audio answer, and ensure it matches what we expect.
931TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
932 f1_.set_secure(SEC_ENABLED);
933 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800934 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -0700935 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000936 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800937 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -0700938 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000939 const ContentInfo* ac = answer->GetContentByName("audio");
940 const ContentInfo* vc = answer->GetContentByName("video");
941 ASSERT_TRUE(ac != NULL);
942 ASSERT_TRUE(vc == NULL);
943 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
944 const AudioContentDescription* acd =
945 static_cast<const AudioContentDescription*>(ac->description);
946 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
947 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700948 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000949 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
950 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
951 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
952 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
953}
954
jbauchcb560652016-08-04 05:20:32 -0700955// Create a typical audio answer with GCM ciphers enabled, and ensure it
956// matches what we expect.
957TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
958 f1_.set_secure(SEC_ENABLED);
959 f2_.set_secure(SEC_ENABLED);
zhihuang1c378ed2017-08-17 14:10:50 -0700960 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
961 opts.crypto_options.enable_gcm_crypto_suites = true;
962 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
jbauchcb560652016-08-04 05:20:32 -0700963 ASSERT_TRUE(offer.get() != NULL);
964 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -0700965 f2_.CreateAnswer(offer.get(), opts, NULL));
jbauchcb560652016-08-04 05:20:32 -0700966 const ContentInfo* ac = answer->GetContentByName("audio");
967 const ContentInfo* vc = answer->GetContentByName("video");
968 ASSERT_TRUE(ac != NULL);
969 ASSERT_TRUE(vc == NULL);
970 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
971 const AudioContentDescription* acd =
972 static_cast<const AudioContentDescription*>(ac->description);
973 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
974 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700975 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700976 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
977 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
978 ASSERT_CRYPTO(acd, 1U, CS_AEAD_AES_256_GCM);
979 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
980}
981
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000982// Create a typical video answer, and ensure it matches what we expect.
983TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
984 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -0700985 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000986 f1_.set_secure(SEC_ENABLED);
987 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800988 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000989 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800990 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000991 f2_.CreateAnswer(offer.get(), opts, NULL));
992 const ContentInfo* ac = answer->GetContentByName("audio");
993 const ContentInfo* vc = answer->GetContentByName("video");
994 ASSERT_TRUE(ac != NULL);
995 ASSERT_TRUE(vc != NULL);
996 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
997 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
998 const AudioContentDescription* acd =
999 static_cast<const AudioContentDescription*>(ac->description);
1000 const VideoContentDescription* vcd =
1001 static_cast<const VideoContentDescription*>(vc->description);
1002 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1003 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1004 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001005 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001006 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
1007 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1008 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1009 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -07001010 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001011 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
1012 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1013 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
1014}
1015
jbauchcb560652016-08-04 05:20:32 -07001016// Create a typical video answer with GCM ciphers enabled, and ensure it
1017// matches what we expect.
1018TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1019 TestVideoGcmCipher(true, true);
1020}
1021
1022// Create a typical video answer with GCM ciphers enabled for the offer only,
1023// and ensure it matches what we expect.
1024TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1025 TestVideoGcmCipher(true, false);
1026}
1027
1028// Create a typical video answer with GCM ciphers enabled for the answer only,
1029// and ensure it matches what we expect.
1030TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1031 TestVideoGcmCipher(false, true);
1032}
1033
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001034TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001035 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
1036 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001037 f1_.set_secure(SEC_ENABLED);
1038 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001039 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001040 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001041 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001042 f2_.CreateAnswer(offer.get(), opts, NULL));
1043 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001044 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001045 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001046 ASSERT_TRUE(dc != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001047 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
zstein4b2e0822017-02-17 19:48:38 -08001048 EXPECT_EQ(std::string(NS_JINGLE_RTP), dc->type);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001049 const AudioContentDescription* acd =
1050 static_cast<const AudioContentDescription*>(ac->description);
zstein4b2e0822017-02-17 19:48:38 -08001051 const DataContentDescription* dcd =
1052 static_cast<const DataContentDescription*>(dc->description);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001053 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1054 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1055 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001056 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001057 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
1058 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
zstein4b2e0822017-02-17 19:48:38 -08001059 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1060 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -07001061 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001062 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
1063 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1064 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001065}
1066
jbauchcb560652016-08-04 05:20:32 -07001067TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
zhihuang1c378ed2017-08-17 14:10:50 -07001068 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
1069 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &opts);
jbauchcb560652016-08-04 05:20:32 -07001070 opts.crypto_options.enable_gcm_crypto_suites = true;
1071 f1_.set_secure(SEC_ENABLED);
1072 f2_.set_secure(SEC_ENABLED);
1073 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1074 ASSERT_TRUE(offer.get() != NULL);
1075 std::unique_ptr<SessionDescription> answer(
1076 f2_.CreateAnswer(offer.get(), opts, NULL));
1077 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001078 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -07001079 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001080 ASSERT_TRUE(dc != NULL);
jbauchcb560652016-08-04 05:20:32 -07001081 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
zstein4b2e0822017-02-17 19:48:38 -08001082 EXPECT_EQ(std::string(NS_JINGLE_RTP), dc->type);
jbauchcb560652016-08-04 05:20:32 -07001083 const AudioContentDescription* acd =
1084 static_cast<const AudioContentDescription*>(ac->description);
zstein4b2e0822017-02-17 19:48:38 -08001085 const DataContentDescription* dcd =
1086 static_cast<const DataContentDescription*>(dc->description);
jbauchcb560652016-08-04 05:20:32 -07001087 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1088 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1089 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001090 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001091 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
1092 ASSERT_CRYPTO(acd, 1U, CS_AEAD_AES_256_GCM);
zstein4b2e0822017-02-17 19:48:38 -08001093 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1094 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -07001095 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001096 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
1097 ASSERT_CRYPTO(dcd, 1U, CS_AEAD_AES_256_GCM);
1098 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
1099}
1100
1101// The use_sctpmap flag should be set in a DataContentDescription by default.
1102// The answer's use_sctpmap flag should match the offer's.
1103TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1104 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001105 AddDataSection(cricket::DCT_SCTP, cricket::MD_SENDRECV, &opts);
zstein4b2e0822017-02-17 19:48:38 -08001106 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1107 ASSERT_TRUE(offer.get() != NULL);
1108 ContentInfo* dc_offer = offer->GetContentByName("data");
1109 ASSERT_TRUE(dc_offer != NULL);
1110 DataContentDescription* dcd_offer =
1111 static_cast<DataContentDescription*>(dc_offer->description);
1112 EXPECT_TRUE(dcd_offer->use_sctpmap());
1113
1114 std::unique_ptr<SessionDescription> answer(
1115 f2_.CreateAnswer(offer.get(), opts, NULL));
1116 const ContentInfo* dc_answer = answer->GetContentByName("data");
1117 ASSERT_TRUE(dc_answer != NULL);
1118 const DataContentDescription* dcd_answer =
1119 static_cast<const DataContentDescription*>(dc_answer->description);
1120 EXPECT_TRUE(dcd_answer->use_sctpmap());
1121}
1122
1123// The answer's use_sctpmap flag should match the offer's.
1124TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1125 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001126 AddDataSection(cricket::DCT_SCTP, cricket::MD_SENDRECV, &opts);
zstein4b2e0822017-02-17 19:48:38 -08001127 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1128 ASSERT_TRUE(offer.get() != NULL);
1129 ContentInfo* dc_offer = offer->GetContentByName("data");
1130 ASSERT_TRUE(dc_offer != NULL);
1131 DataContentDescription* dcd_offer =
1132 static_cast<DataContentDescription*>(dc_offer->description);
1133 dcd_offer->set_use_sctpmap(false);
1134
1135 std::unique_ptr<SessionDescription> answer(
1136 f2_.CreateAnswer(offer.get(), opts, NULL));
1137 const ContentInfo* dc_answer = answer->GetContentByName("data");
1138 ASSERT_TRUE(dc_answer != NULL);
1139 const DataContentDescription* dcd_answer =
1140 static_cast<const DataContentDescription*>(dc_answer->description);
1141 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001142}
1143
deadbeef8b7e9ad2017-05-25 09:38:55 -07001144// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1145// and "TCP/DTLS/SCTP" offers.
1146TEST_F(MediaSessionDescriptionFactoryTest,
1147 TestCreateDataAnswerToDifferentOfferedProtos) {
1148 // Need to enable DTLS offer/answer generation (disabled by default in this
1149 // test).
1150 f1_.set_secure(SEC_ENABLED);
1151 f2_.set_secure(SEC_ENABLED);
1152 tdf1_.set_secure(SEC_ENABLED);
1153 tdf2_.set_secure(SEC_ENABLED);
1154
1155 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001156 AddDataSection(cricket::DCT_SCTP, cricket::MD_SENDRECV, &opts);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001157 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
1158 ASSERT_TRUE(offer.get() != nullptr);
1159 ContentInfo* dc_offer = offer->GetContentByName("data");
1160 ASSERT_TRUE(dc_offer != nullptr);
1161 DataContentDescription* dcd_offer =
1162 static_cast<DataContentDescription*>(dc_offer->description);
1163
1164 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1165 "TCP/DTLS/SCTP"};
1166 for (const std::string& proto : protos) {
1167 dcd_offer->set_protocol(proto);
1168 std::unique_ptr<SessionDescription> answer(
1169 f2_.CreateAnswer(offer.get(), opts, nullptr));
1170 const ContentInfo* dc_answer = answer->GetContentByName("data");
1171 ASSERT_TRUE(dc_answer != nullptr);
1172 const DataContentDescription* dcd_answer =
1173 static_cast<const DataContentDescription*>(dc_answer->description);
1174 EXPECT_FALSE(dc_answer->rejected);
1175 EXPECT_EQ(proto, dcd_answer->protocol());
1176 }
1177}
1178
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001179// Verifies that the order of the media contents in the offer is preserved in
1180// the answer.
1181TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1182 MediaSessionOptions opts;
1183
1184 // Creates a data only offer.
zhihuang1c378ed2017-08-17 14:10:50 -07001185 AddDataSection(cricket::DCT_SCTP, cricket::MD_SENDRECV, &opts);
kwiberg31022942016-03-11 14:18:21 -08001186 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001187 ASSERT_TRUE(offer1.get() != NULL);
1188
1189 // Appends audio to the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07001190 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
1191 &opts);
kwiberg31022942016-03-11 14:18:21 -08001192 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001193 f1_.CreateOffer(opts, offer1.get()));
1194 ASSERT_TRUE(offer2.get() != NULL);
1195
1196 // Appends video to the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07001197 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
1198 &opts);
kwiberg31022942016-03-11 14:18:21 -08001199 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001200 f1_.CreateOffer(opts, offer2.get()));
1201 ASSERT_TRUE(offer3.get() != NULL);
1202
kwiberg31022942016-03-11 14:18:21 -08001203 std::unique_ptr<SessionDescription> answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001204 f2_.CreateAnswer(offer3.get(), opts, NULL));
1205 ASSERT_TRUE(answer.get() != NULL);
1206 EXPECT_EQ(3u, answer->contents().size());
1207 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1208 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1209 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1210}
1211
ossu075af922016-06-14 03:29:38 -07001212// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1213// answerer settings.
1214
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001215// This test that the media direction is set to send/receive in an answer if
1216// the offer is send receive.
1217TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
1218 TestMediaDirectionInAnswer(cricket::MD_SENDRECV, cricket::MD_SENDRECV);
1219}
1220
1221// This test that the media direction is set to receive only in an answer if
1222// the offer is send only.
1223TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
1224 TestMediaDirectionInAnswer(cricket::MD_SENDONLY, cricket::MD_RECVONLY);
1225}
1226
1227// This test that the media direction is set to send only in an answer if
1228// the offer is recv only.
1229TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
1230 TestMediaDirectionInAnswer(cricket::MD_RECVONLY, cricket::MD_SENDONLY);
1231}
1232
1233// This test that the media direction is set to inactive in an answer if
1234// the offer is inactive.
1235TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
1236 TestMediaDirectionInAnswer(cricket::MD_INACTIVE, cricket::MD_INACTIVE);
1237}
1238
1239// Test that a data content with an unknown protocol is rejected in an answer.
1240TEST_F(MediaSessionDescriptionFactoryTest,
1241 CreateDataAnswerToOfferWithUnknownProtocol) {
1242 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001243 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001244 f1_.set_secure(SEC_ENABLED);
1245 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001246 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
terelius8c011e52016-04-26 05:28:11 -07001247 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001248 ASSERT_TRUE(dc_offer != NULL);
1249 DataContentDescription* dcd_offer =
1250 static_cast<DataContentDescription*>(dc_offer->description);
1251 ASSERT_TRUE(dcd_offer != NULL);
1252 std::string protocol = "a weird unknown protocol";
1253 dcd_offer->set_protocol(protocol);
1254
kwiberg31022942016-03-11 14:18:21 -08001255 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001256 f2_.CreateAnswer(offer.get(), opts, NULL));
1257
1258 const ContentInfo* dc_answer = answer->GetContentByName("data");
1259 ASSERT_TRUE(dc_answer != NULL);
1260 EXPECT_TRUE(dc_answer->rejected);
1261 const DataContentDescription* dcd_answer =
1262 static_cast<const DataContentDescription*>(dc_answer->description);
1263 ASSERT_TRUE(dcd_answer != NULL);
1264 EXPECT_EQ(protocol, dcd_answer->protocol());
1265}
1266
1267// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1268TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001269 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001270 f1_.set_secure(SEC_DISABLED);
1271 f2_.set_secure(SEC_DISABLED);
1272 tdf1_.set_secure(SEC_DISABLED);
1273 tdf2_.set_secure(SEC_DISABLED);
1274
kwiberg31022942016-03-11 14:18:21 -08001275 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001276 const AudioContentDescription* offer_acd =
1277 GetFirstAudioContentDescription(offer.get());
1278 ASSERT_TRUE(offer_acd != NULL);
1279 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), offer_acd->protocol());
1280
kwiberg31022942016-03-11 14:18:21 -08001281 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001282 f2_.CreateAnswer(offer.get(), opts, NULL));
1283
1284 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1285 ASSERT_TRUE(ac_answer != NULL);
1286 EXPECT_FALSE(ac_answer->rejected);
1287
1288 const AudioContentDescription* answer_acd =
1289 GetFirstAudioContentDescription(answer.get());
1290 ASSERT_TRUE(answer_acd != NULL);
1291 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), answer_acd->protocol());
1292}
1293
1294// Create a video offer and answer and ensure the RTP header extensions
1295// matches what we expect.
1296TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1297 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001298 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001299 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1300 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1301 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1302 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1303
kwiberg31022942016-03-11 14:18:21 -08001304 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001305 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001306 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001307 f2_.CreateAnswer(offer.get(), opts, NULL));
1308
1309 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension1),
1310 GetFirstAudioContentDescription(
1311 offer.get())->rtp_header_extensions());
1312 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtension1),
1313 GetFirstVideoContentDescription(
1314 offer.get())->rtp_header_extensions());
1315 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
1316 GetFirstAudioContentDescription(
1317 answer.get())->rtp_header_extensions());
1318 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
1319 GetFirstVideoContentDescription(
1320 answer.get())->rtp_header_extensions());
1321}
1322
jbauch5869f502017-06-29 12:31:36 -07001323TEST_F(MediaSessionDescriptionFactoryTest,
1324 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
1325 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001326 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
jbauch5869f502017-06-29 12:31:36 -07001327
1328 f1_.set_enable_encrypted_rtp_header_extensions(true);
1329 f2_.set_enable_encrypted_rtp_header_extensions(true);
1330
1331 f1_.set_audio_rtp_header_extensions(
1332 MAKE_VECTOR(kAudioRtpExtension1));
1333 f1_.set_video_rtp_header_extensions(
1334 MAKE_VECTOR(kVideoRtpExtension1));
1335 f2_.set_audio_rtp_header_extensions(
1336 MAKE_VECTOR(kAudioRtpExtension2));
1337 f2_.set_video_rtp_header_extensions(
1338 MAKE_VECTOR(kVideoRtpExtension2));
1339
1340 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1341 ASSERT_TRUE(offer.get() != NULL);
1342 std::unique_ptr<SessionDescription> answer(
1343 f2_.CreateAnswer(offer.get(), opts, NULL));
1344
1345 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1346 GetFirstAudioContentDescription(
1347 offer.get())->rtp_header_extensions());
1348 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1349 GetFirstVideoContentDescription(
1350 offer.get())->rtp_header_extensions());
1351 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
1352 GetFirstAudioContentDescription(
1353 answer.get())->rtp_header_extensions());
1354 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
1355 GetFirstVideoContentDescription(
1356 answer.get())->rtp_header_extensions());
1357}
1358
1359TEST_F(MediaSessionDescriptionFactoryTest,
1360 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
1361 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001362 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
jbauch5869f502017-06-29 12:31:36 -07001363
1364 f1_.set_enable_encrypted_rtp_header_extensions(true);
1365
1366 f1_.set_audio_rtp_header_extensions(
1367 MAKE_VECTOR(kAudioRtpExtension1));
1368 f1_.set_video_rtp_header_extensions(
1369 MAKE_VECTOR(kVideoRtpExtension1));
1370 f2_.set_audio_rtp_header_extensions(
1371 MAKE_VECTOR(kAudioRtpExtension2));
1372 f2_.set_video_rtp_header_extensions(
1373 MAKE_VECTOR(kVideoRtpExtension2));
1374
1375 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1376 ASSERT_TRUE(offer.get() != NULL);
1377 std::unique_ptr<SessionDescription> answer(
1378 f2_.CreateAnswer(offer.get(), opts, NULL));
1379
1380 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1381 GetFirstAudioContentDescription(
1382 offer.get())->rtp_header_extensions());
1383 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1384 GetFirstVideoContentDescription(
1385 offer.get())->rtp_header_extensions());
1386 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
1387 GetFirstAudioContentDescription(
1388 answer.get())->rtp_header_extensions());
1389 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
1390 GetFirstVideoContentDescription(
1391 answer.get())->rtp_header_extensions());
1392}
1393
1394TEST_F(MediaSessionDescriptionFactoryTest,
1395 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
1396 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001397 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
jbauch5869f502017-06-29 12:31:36 -07001398
1399 f2_.set_enable_encrypted_rtp_header_extensions(true);
1400
1401 f1_.set_audio_rtp_header_extensions(
1402 MAKE_VECTOR(kAudioRtpExtension1));
1403 f1_.set_video_rtp_header_extensions(
1404 MAKE_VECTOR(kVideoRtpExtension1));
1405 f2_.set_audio_rtp_header_extensions(
1406 MAKE_VECTOR(kAudioRtpExtension2));
1407 f2_.set_video_rtp_header_extensions(
1408 MAKE_VECTOR(kVideoRtpExtension2));
1409
1410 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1411 ASSERT_TRUE(offer.get() != NULL);
1412 std::unique_ptr<SessionDescription> answer(
1413 f2_.CreateAnswer(offer.get(), opts, NULL));
1414
1415 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension1),
1416 GetFirstAudioContentDescription(
1417 offer.get())->rtp_header_extensions());
1418 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtension1),
1419 GetFirstVideoContentDescription(
1420 offer.get())->rtp_header_extensions());
1421 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
1422 GetFirstAudioContentDescription(
1423 answer.get())->rtp_header_extensions());
1424 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
1425 GetFirstVideoContentDescription(
1426 answer.get())->rtp_header_extensions());
1427}
1428
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001429// Create an audio, video, data answer without legacy StreamParams.
1430TEST_F(MediaSessionDescriptionFactoryTest,
1431 TestCreateAnswerWithoutLegacyStreams) {
1432 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001433 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
1434 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &opts);
kwiberg31022942016-03-11 14:18:21 -08001435 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001436 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001437 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001438 f2_.CreateAnswer(offer.get(), opts, NULL));
1439 const ContentInfo* ac = answer->GetContentByName("audio");
1440 const ContentInfo* vc = answer->GetContentByName("video");
1441 const ContentInfo* dc = answer->GetContentByName("data");
1442 ASSERT_TRUE(ac != NULL);
1443 ASSERT_TRUE(vc != NULL);
1444 const AudioContentDescription* acd =
1445 static_cast<const AudioContentDescription*>(ac->description);
1446 const VideoContentDescription* vcd =
1447 static_cast<const VideoContentDescription*>(vc->description);
1448 const DataContentDescription* dcd =
1449 static_cast<const DataContentDescription*>(dc->description);
1450
1451 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1452 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1453 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1454}
1455
1456TEST_F(MediaSessionDescriptionFactoryTest, TestPartial) {
1457 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001458 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
1459 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001460 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001461 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001462 ASSERT_TRUE(offer.get() != NULL);
1463 const ContentInfo* ac = offer->GetContentByName("audio");
1464 const ContentInfo* vc = offer->GetContentByName("video");
1465 const ContentInfo* dc = offer->GetContentByName("data");
1466 AudioContentDescription* acd = const_cast<AudioContentDescription*>(
1467 static_cast<const AudioContentDescription*>(ac->description));
1468 VideoContentDescription* vcd = const_cast<VideoContentDescription*>(
1469 static_cast<const VideoContentDescription*>(vc->description));
1470 DataContentDescription* dcd = const_cast<DataContentDescription*>(
1471 static_cast<const DataContentDescription*>(dc->description));
1472
1473 EXPECT_FALSE(acd->partial()); // default is false.
1474 acd->set_partial(true);
1475 EXPECT_TRUE(acd->partial());
1476 acd->set_partial(false);
1477 EXPECT_FALSE(acd->partial());
1478
1479 EXPECT_FALSE(vcd->partial()); // default is false.
1480 vcd->set_partial(true);
1481 EXPECT_TRUE(vcd->partial());
1482 vcd->set_partial(false);
1483 EXPECT_FALSE(vcd->partial());
1484
1485 EXPECT_FALSE(dcd->partial()); // default is false.
1486 dcd->set_partial(true);
1487 EXPECT_TRUE(dcd->partial());
1488 dcd->set_partial(false);
1489 EXPECT_FALSE(dcd->partial());
1490}
1491
1492// Create a typical video answer, and ensure it matches what we expect.
1493TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1494 MediaSessionOptions offer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001495 AddAudioVideoSections(cricket::MD_SENDRECV, &offer_opts);
1496 AddDataSection(cricket::DCT_RTP, cricket::MD_SENDRECV, &offer_opts);
1497
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001498 MediaSessionOptions answer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001499 AddAudioVideoSections(cricket::MD_SENDRECV, &answer_opts);
1500 AddDataSection(cricket::DCT_RTP, cricket::MD_SENDRECV, &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001501
kwiberg31022942016-03-11 14:18:21 -08001502 std::unique_ptr<SessionDescription> offer;
1503 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001504
1505 offer_opts.rtcp_mux_enabled = true;
1506 answer_opts.rtcp_mux_enabled = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001507 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1508 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1509 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1510 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1511 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1512 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1513 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1514 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1515 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1516 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1517 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1518 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1519 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1520 EXPECT_TRUE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1521
1522 offer_opts.rtcp_mux_enabled = true;
1523 answer_opts.rtcp_mux_enabled = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001524 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1525 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1526 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1527 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1528 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1529 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1530 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1531 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1532 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1533 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1534 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1535 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1536 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1537 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1538
1539 offer_opts.rtcp_mux_enabled = false;
1540 answer_opts.rtcp_mux_enabled = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001541 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1542 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1543 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1544 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1545 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1546 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1547 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1548 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1549 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1550 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1551 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1552 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1553 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1554 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1555
1556 offer_opts.rtcp_mux_enabled = false;
1557 answer_opts.rtcp_mux_enabled = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001558 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1559 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1560 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1561 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1562 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1563 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1564 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1565 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1566 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1567 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1568 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1569 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1570 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1571 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1572}
1573
1574// Create an audio-only answer to a video offer.
1575TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1576 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001577 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
1578 &opts);
1579 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
1580 &opts);
kwiberg31022942016-03-11 14:18:21 -08001581 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001582 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001583
1584 opts.media_description_options[1].stopped = true;
kwiberg31022942016-03-11 14:18:21 -08001585 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001586 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001587 const ContentInfo* ac = answer->GetContentByName("audio");
1588 const ContentInfo* vc = answer->GetContentByName("video");
1589 ASSERT_TRUE(ac != NULL);
1590 ASSERT_TRUE(vc != NULL);
1591 ASSERT_TRUE(vc->description != NULL);
1592 EXPECT_TRUE(vc->rejected);
1593}
1594
1595// Create an audio-only answer to an offer with data.
1596TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001597 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001598 opts.data_channel_type = cricket::DCT_RTP;
zhihuang1c378ed2017-08-17 14:10:50 -07001599 AddMediaSection(MEDIA_TYPE_DATA, "data", cricket::MD_RECVONLY, kActive,
1600 &opts);
kwiberg31022942016-03-11 14:18:21 -08001601 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001602 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001603
1604 opts.media_description_options[1].stopped = true;
kwiberg31022942016-03-11 14:18:21 -08001605 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001606 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001607 const ContentInfo* ac = answer->GetContentByName("audio");
1608 const ContentInfo* dc = answer->GetContentByName("data");
1609 ASSERT_TRUE(ac != NULL);
1610 ASSERT_TRUE(dc != NULL);
1611 ASSERT_TRUE(dc->description != NULL);
1612 EXPECT_TRUE(dc->rejected);
1613}
1614
1615// Create an answer that rejects the contents which are rejected in the offer.
1616TEST_F(MediaSessionDescriptionFactoryTest,
1617 CreateAnswerToOfferWithRejectedMedia) {
1618 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001619 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
1620 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &opts);
kwiberg31022942016-03-11 14:18:21 -08001621 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001622 ASSERT_TRUE(offer.get() != NULL);
1623 ContentInfo* ac = offer->GetContentByName("audio");
1624 ContentInfo* vc = offer->GetContentByName("video");
1625 ContentInfo* dc = offer->GetContentByName("data");
1626 ASSERT_TRUE(ac != NULL);
1627 ASSERT_TRUE(vc != NULL);
1628 ASSERT_TRUE(dc != NULL);
1629 ac->rejected = true;
1630 vc->rejected = true;
1631 dc->rejected = true;
kwiberg31022942016-03-11 14:18:21 -08001632 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001633 f2_.CreateAnswer(offer.get(), opts, NULL));
1634 ac = answer->GetContentByName("audio");
1635 vc = answer->GetContentByName("video");
1636 dc = answer->GetContentByName("data");
1637 ASSERT_TRUE(ac != NULL);
1638 ASSERT_TRUE(vc != NULL);
1639 ASSERT_TRUE(dc != NULL);
1640 EXPECT_TRUE(ac->rejected);
1641 EXPECT_TRUE(vc->rejected);
1642 EXPECT_TRUE(dc->rejected);
1643}
1644
1645// Create an audio and video offer with:
1646// - one video track
1647// - two audio tracks
1648// - two data tracks
1649// and ensure it matches what we expect. Also updates the initial offer by
1650// adding a new video track and replaces one of the audio tracks.
1651TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
1652 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001653 AddAudioVideoSections(cricket::MD_SENDRECV, &opts);
1654 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1655 kMediaStream1, 1, &opts);
1656 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1657 kMediaStream1, 1, &opts);
1658 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
1659 kMediaStream1, 1, &opts);
1660
1661 AddDataSection(cricket::DCT_RTP, cricket::MD_SENDRECV, &opts);
1662 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack1,
1663 kMediaStream1, 1, &opts);
1664 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack2,
1665 kMediaStream1, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001666
1667 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001668 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001669
1670 ASSERT_TRUE(offer.get() != NULL);
1671 const ContentInfo* ac = offer->GetContentByName("audio");
1672 const ContentInfo* vc = offer->GetContentByName("video");
1673 const ContentInfo* dc = offer->GetContentByName("data");
1674 ASSERT_TRUE(ac != NULL);
1675 ASSERT_TRUE(vc != NULL);
1676 ASSERT_TRUE(dc != NULL);
1677 const AudioContentDescription* acd =
1678 static_cast<const AudioContentDescription*>(ac->description);
1679 const VideoContentDescription* vcd =
1680 static_cast<const VideoContentDescription*>(vc->description);
1681 const DataContentDescription* dcd =
1682 static_cast<const DataContentDescription*>(dc->description);
1683 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07001684 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001685
1686 const StreamParamsVec& audio_streams = acd->streams();
1687 ASSERT_EQ(2U, audio_streams.size());
1688 EXPECT_EQ(audio_streams[0].cname , audio_streams[1].cname);
1689 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1690 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1691 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1692 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1693 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1694 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1695
1696 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1697 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1698 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
1699
1700 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1701 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
1702 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1703
1704 const StreamParamsVec& video_streams = vcd->streams();
1705 ASSERT_EQ(1U, video_streams.size());
1706 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1707 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1708 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1709 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1710
1711 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1712 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
1713 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1714
1715 const StreamParamsVec& data_streams = dcd->streams();
1716 ASSERT_EQ(2U, data_streams.size());
1717 EXPECT_EQ(data_streams[0].cname , data_streams[1].cname);
1718 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1719 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1720 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1721 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1722 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1723 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1724
1725 EXPECT_EQ(cricket::kDataMaxBandwidth,
1726 dcd->bandwidth()); // default bandwidth (auto)
1727 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
1728 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1729
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001730 // Update the offer. Add a new video track that is not synched to the
1731 // other tracks and replace audio track 2 with audio track 3.
zhihuang1c378ed2017-08-17 14:10:50 -07001732 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
1733 kMediaStream2, 1, &opts);
1734 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
1735 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
1736 kMediaStream1, 1, &opts);
1737 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
1738 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack3,
1739 kMediaStream1, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08001740 std::unique_ptr<SessionDescription> updated_offer(
1741 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001742
1743 ASSERT_TRUE(updated_offer.get() != NULL);
1744 ac = updated_offer->GetContentByName("audio");
1745 vc = updated_offer->GetContentByName("video");
1746 dc = updated_offer->GetContentByName("data");
1747 ASSERT_TRUE(ac != NULL);
1748 ASSERT_TRUE(vc != NULL);
1749 ASSERT_TRUE(dc != NULL);
1750 const AudioContentDescription* updated_acd =
1751 static_cast<const AudioContentDescription*>(ac->description);
1752 const VideoContentDescription* updated_vcd =
1753 static_cast<const VideoContentDescription*>(vc->description);
1754 const DataContentDescription* updated_dcd =
1755 static_cast<const DataContentDescription*>(dc->description);
1756
1757 EXPECT_EQ(acd->type(), updated_acd->type());
1758 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1759 EXPECT_EQ(vcd->type(), updated_vcd->type());
1760 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1761 EXPECT_EQ(dcd->type(), updated_dcd->type());
1762 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1763 ASSERT_CRYPTO(updated_acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
1764 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
1765 ASSERT_CRYPTO(updated_vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1766 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
1767 ASSERT_CRYPTO(updated_dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1768 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1769
1770 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1771 ASSERT_EQ(2U, updated_audio_streams.size());
1772 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
1773 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
1774 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
1775 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
1776 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
1777
1778 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1779 ASSERT_EQ(2U, updated_video_streams.size());
1780 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1781 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001782 // All the media streams in one PeerConnection share one RTCP CNAME.
1783 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001784
1785 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1786 ASSERT_EQ(2U, updated_data_streams.size());
1787 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
1788 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
1789 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
1790 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
1791 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07001792 // The stream correctly got the CNAME from the MediaSessionOptions.
1793 // The Expected RTCP CNAME is the default one as we are using the default
1794 // MediaSessionOptions.
1795 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001796}
1797
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001798// Create an offer with simulcast video stream.
1799TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
1800 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001801 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
1802 &opts);
1803 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_SENDRECV, kActive,
1804 &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001805 const int num_sim_layers = 3;
zhihuang1c378ed2017-08-17 14:10:50 -07001806 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1807 kMediaStream1, num_sim_layers, &opts);
kwiberg31022942016-03-11 14:18:21 -08001808 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001809
1810 ASSERT_TRUE(offer.get() != NULL);
1811 const ContentInfo* vc = offer->GetContentByName("video");
1812 ASSERT_TRUE(vc != NULL);
1813 const VideoContentDescription* vcd =
1814 static_cast<const VideoContentDescription*>(vc->description);
1815
1816 const StreamParamsVec& video_streams = vcd->streams();
1817 ASSERT_EQ(1U, video_streams.size());
1818 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1819 const SsrcGroup* sim_ssrc_group =
1820 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
1821 ASSERT_TRUE(sim_ssrc_group != NULL);
1822 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
1823}
1824
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001825// Create an audio and video answer to a standard video offer with:
1826// - one video track
1827// - two audio tracks
1828// - two data tracks
1829// and ensure it matches what we expect. Also updates the initial answer by
1830// adding a new video track and removes one of the audio tracks.
1831TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
1832 MediaSessionOptions offer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001833 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
1834 &offer_opts);
1835 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
1836 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001837 offer_opts.data_channel_type = cricket::DCT_RTP;
zhihuang1c378ed2017-08-17 14:10:50 -07001838 AddMediaSection(MEDIA_TYPE_DATA, "data", cricket::MD_RECVONLY, kActive,
1839 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001840 f1_.set_secure(SEC_ENABLED);
1841 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001842 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(offer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001843
zhihuang1c378ed2017-08-17 14:10:50 -07001844 MediaSessionOptions answer_opts;
1845 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_SENDRECV, kActive,
1846 &answer_opts);
1847 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_SENDRECV, kActive,
1848 &answer_opts);
1849 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1850 kMediaStream1, 1, &answer_opts);
1851 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1852 kMediaStream1, 1, &answer_opts);
1853 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
1854 kMediaStream1, 1, &answer_opts);
1855
1856 AddMediaSection(MEDIA_TYPE_DATA, "data", cricket::MD_SENDRECV, kActive,
1857 &answer_opts);
1858 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack1,
1859 kMediaStream1, 1, &answer_opts);
1860 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack2,
1861 kMediaStream1, 1, &answer_opts);
1862 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001863
kwiberg31022942016-03-11 14:18:21 -08001864 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001865 f2_.CreateAnswer(offer.get(), answer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001866
1867 ASSERT_TRUE(answer.get() != NULL);
1868 const ContentInfo* ac = answer->GetContentByName("audio");
1869 const ContentInfo* vc = answer->GetContentByName("video");
1870 const ContentInfo* dc = answer->GetContentByName("data");
1871 ASSERT_TRUE(ac != NULL);
1872 ASSERT_TRUE(vc != NULL);
1873 ASSERT_TRUE(dc != NULL);
1874 const AudioContentDescription* acd =
1875 static_cast<const AudioContentDescription*>(ac->description);
1876 const VideoContentDescription* vcd =
1877 static_cast<const VideoContentDescription*>(vc->description);
1878 const DataContentDescription* dcd =
1879 static_cast<const DataContentDescription*>(dc->description);
1880 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1881 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1882 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1883
1884 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1885 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1886
1887 const StreamParamsVec& audio_streams = acd->streams();
1888 ASSERT_EQ(2U, audio_streams.size());
1889 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
1890 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1891 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1892 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1893 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1894 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1895 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1896
1897 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1898 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1899
1900 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1901 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1902
1903 const StreamParamsVec& video_streams = vcd->streams();
1904 ASSERT_EQ(1U, video_streams.size());
1905 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1906 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1907 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1908 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1909
1910 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1911 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
1912
1913 const StreamParamsVec& data_streams = dcd->streams();
1914 ASSERT_EQ(2U, data_streams.size());
1915 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
1916 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1917 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1918 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1919 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1920 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1921 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1922
1923 EXPECT_EQ(cricket::kDataMaxBandwidth,
1924 dcd->bandwidth()); // default bandwidth (auto)
1925 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
1926
1927 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07001928 // other tracks and remove 1 audio track.
zhihuang1c378ed2017-08-17 14:10:50 -07001929 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
1930 kMediaStream2, 1, &answer_opts);
1931 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
1932 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08001933 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001934 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001935
1936 ASSERT_TRUE(updated_answer.get() != NULL);
1937 ac = updated_answer->GetContentByName("audio");
1938 vc = updated_answer->GetContentByName("video");
1939 dc = updated_answer->GetContentByName("data");
1940 ASSERT_TRUE(ac != NULL);
1941 ASSERT_TRUE(vc != NULL);
1942 ASSERT_TRUE(dc != NULL);
1943 const AudioContentDescription* updated_acd =
1944 static_cast<const AudioContentDescription*>(ac->description);
1945 const VideoContentDescription* updated_vcd =
1946 static_cast<const VideoContentDescription*>(vc->description);
1947 const DataContentDescription* updated_dcd =
1948 static_cast<const DataContentDescription*>(dc->description);
1949
1950 ASSERT_CRYPTO(updated_acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1951 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
1952 ASSERT_CRYPTO(updated_vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1953 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
1954 ASSERT_CRYPTO(updated_dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1955 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1956
1957 EXPECT_EQ(acd->type(), updated_acd->type());
1958 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1959 EXPECT_EQ(vcd->type(), updated_vcd->type());
1960 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1961 EXPECT_EQ(dcd->type(), updated_dcd->type());
1962 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1963
1964 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1965 ASSERT_EQ(1U, updated_audio_streams.size());
1966 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
1967
1968 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1969 ASSERT_EQ(2U, updated_video_streams.size());
1970 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1971 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001972 // All media streams in one PeerConnection share one CNAME.
1973 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001974
1975 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1976 ASSERT_EQ(1U, updated_data_streams.size());
1977 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
1978}
1979
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001980// Create an updated offer after creating an answer to the original offer and
1981// verify that the codecs that were part of the original answer are not changed
1982// in the updated offer.
1983TEST_F(MediaSessionDescriptionFactoryTest,
1984 RespondentCreatesOfferAfterCreatingAnswer) {
1985 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001986 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001987
kwiberg31022942016-03-11 14:18:21 -08001988 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1989 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001990 f2_.CreateAnswer(offer.get(), opts, NULL));
1991
1992 const AudioContentDescription* acd =
1993 GetFirstAudioContentDescription(answer.get());
1994 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1995
1996 const VideoContentDescription* vcd =
1997 GetFirstVideoContentDescription(answer.get());
1998 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1999
kwiberg31022942016-03-11 14:18:21 -08002000 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002001 f2_.CreateOffer(opts, answer.get()));
2002
2003 // The expected audio codecs are the common audio codecs from the first
2004 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
2005 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002006 // TODO(wu): |updated_offer| should not include the codec
2007 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002008 const AudioCodec kUpdatedAudioCodecOffer[] = {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002009 kAudioCodecsAnswer[0],
2010 kAudioCodecsAnswer[1],
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002011 kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002012 };
2013
2014 // The expected video codecs are the common video codecs from the first
2015 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
2016 // preference order.
2017 const VideoCodec kUpdatedVideoCodecOffer[] = {
2018 kVideoCodecsAnswer[0],
2019 kVideoCodecs2[1],
2020 };
2021
2022 const AudioContentDescription* updated_acd =
2023 GetFirstAudioContentDescription(updated_offer.get());
2024 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioCodecOffer), updated_acd->codecs());
2025
2026 const VideoContentDescription* updated_vcd =
2027 GetFirstVideoContentDescription(updated_offer.get());
2028 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoCodecOffer), updated_vcd->codecs());
2029}
2030
2031// Create an updated offer after creating an answer to the original offer and
2032// verify that the codecs that were part of the original answer are not changed
2033// in the updated offer. In this test Rtx is enabled.
2034TEST_F(MediaSessionDescriptionFactoryTest,
2035 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2036 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002037 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
2038 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002039 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002040 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002041 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002042 f1_.set_video_codecs(f1_codecs);
2043
2044 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002045 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002046 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002047 f2_.set_video_codecs(f2_codecs);
2048
kwiberg31022942016-03-11 14:18:21 -08002049 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002050 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002051 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002052 f2_.CreateAnswer(offer.get(), opts, NULL));
2053
2054 const VideoContentDescription* vcd =
2055 GetFirstVideoContentDescription(answer.get());
2056
2057 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002058 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2059 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002060
2061 EXPECT_EQ(expected_codecs, vcd->codecs());
2062
deadbeef67cf2c12016-04-13 10:07:16 -07002063 // Now, make sure we get same result (except for the order) if |f2_| creates
2064 // an updated offer even though the default payload types between |f1_| and
2065 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08002066 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002067 f2_.CreateOffer(opts, answer.get()));
2068 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002069 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002070 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2071
2072 const VideoContentDescription* updated_vcd =
2073 GetFirstVideoContentDescription(updated_answer.get());
2074
2075 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2076}
2077
2078// Create an updated offer that adds video after creating an audio only answer
2079// to the original offer. This test verifies that if a video codec and the RTX
2080// codec have the same default payload type as an audio codec that is already in
2081// use, the added codecs payload types are changed.
2082TEST_F(MediaSessionDescriptionFactoryTest,
2083 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2084 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002085 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002086 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002087 f1_.set_video_codecs(f1_codecs);
2088
2089 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002090 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
2091 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002092
kwiberg31022942016-03-11 14:18:21 -08002093 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2094 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002095 f2_.CreateAnswer(offer.get(), opts, NULL));
2096
2097 const AudioContentDescription* acd =
2098 GetFirstAudioContentDescription(answer.get());
2099 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
2100
2101 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
2102 // reference be the same as an audio codec that was negotiated in the
2103 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002104 opts.media_description_options.clear();
2105 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002106
2107 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2108 int used_pl_type = acd->codecs()[0].id;
2109 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002110 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002111 f2_.set_video_codecs(f2_codecs);
2112
kwiberg31022942016-03-11 14:18:21 -08002113 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002114 f2_.CreateOffer(opts, answer.get()));
2115 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002116 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002117 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2118
2119 const AudioContentDescription* updated_acd =
2120 GetFirstAudioContentDescription(answer.get());
2121 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), updated_acd->codecs());
2122
2123 const VideoContentDescription* updated_vcd =
2124 GetFirstVideoContentDescription(updated_answer.get());
2125
2126 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
sergeyu@chromium.org32f485b2013-12-05 22:36:21 +00002127 ASSERT_EQ(std::string(cricket::kRtxCodecName), updated_vcd->codecs()[1].name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002128 int new_h264_pl_type = updated_vcd->codecs()[0].id;
2129 EXPECT_NE(used_pl_type, new_h264_pl_type);
2130 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002131 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002132 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
2133 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
2134}
2135
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002136// Create an updated offer with RTX after creating an answer to an offer
2137// without RTX, and with different default payload types.
2138// Verify that the added RTX codec references the correct payload type.
2139TEST_F(MediaSessionDescriptionFactoryTest,
2140 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
2141 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002142 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002143
2144 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2145 // This creates rtx for H264 with the payload type |f2_| uses.
2146 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
2147 f2_.set_video_codecs(f2_codecs);
2148
kwiberg31022942016-03-11 14:18:21 -08002149 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002150 ASSERT_TRUE(offer.get() != nullptr);
kwiberg31022942016-03-11 14:18:21 -08002151 std::unique_ptr<SessionDescription> answer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002152 f2_.CreateAnswer(offer.get(), opts, nullptr));
2153
2154 const VideoContentDescription* vcd =
2155 GetFirstVideoContentDescription(answer.get());
2156
2157 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2158 EXPECT_EQ(expected_codecs, vcd->codecs());
2159
2160 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
2161 // updated offer, even though the default payload types are different from
2162 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08002163 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002164 f2_.CreateOffer(opts, answer.get()));
2165 ASSERT_TRUE(updated_offer);
2166
2167 const VideoContentDescription* updated_vcd =
2168 GetFirstVideoContentDescription(updated_offer.get());
2169
2170 // New offer should attempt to add H263, and RTX for H264.
2171 expected_codecs.push_back(kVideoCodecs2[1]);
2172 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
2173 &expected_codecs);
2174 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2175}
2176
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002177// Test that RTX is ignored when there is no associated payload type parameter.
2178TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
2179 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002180 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
2181 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002182 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002183 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07002184 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002185 f1_.set_video_codecs(f1_codecs);
2186
2187 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002188 // This creates RTX for H264 with the payload type |f2_| uses.
2189 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002190 f2_.set_video_codecs(f2_codecs);
2191
kwiberg31022942016-03-11 14:18:21 -08002192 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002193 ASSERT_TRUE(offer.get() != NULL);
2194 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
2195 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
2196 // is possible to test that that RTX is dropped when
2197 // kCodecParamAssociatedPayloadType is missing in the offer.
2198 VideoContentDescription* desc =
2199 static_cast<cricket::VideoContentDescription*>(
2200 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
2201 ASSERT_TRUE(desc != NULL);
2202 std::vector<VideoCodec> codecs = desc->codecs();
2203 for (std::vector<VideoCodec>::iterator iter = codecs.begin();
2204 iter != codecs.end(); ++iter) {
2205 if (iter->name.find(cricket::kRtxCodecName) == 0) {
2206 iter->params.clear();
2207 }
2208 }
2209 desc->set_codecs(codecs);
2210
kwiberg31022942016-03-11 14:18:21 -08002211 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002212 f2_.CreateAnswer(offer.get(), opts, NULL));
2213
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002214 std::vector<std::string> codec_names =
2215 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
2216 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
2217 cricket::kRtxCodecName));
2218}
2219
2220// Test that RTX will be filtered out in the answer if its associated payload
2221// type doesn't match the local value.
2222TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
2223 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002224 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
2225 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002226 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2227 // This creates RTX for H264 in sender.
2228 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2229 f1_.set_video_codecs(f1_codecs);
2230
2231 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2232 // This creates RTX for H263 in receiver.
2233 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
2234 f2_.set_video_codecs(f2_codecs);
2235
kwiberg31022942016-03-11 14:18:21 -08002236 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002237 ASSERT_TRUE(offer.get() != NULL);
2238 // Associated payload type doesn't match, therefore, RTX codec is removed in
2239 // the answer.
kwiberg31022942016-03-11 14:18:21 -08002240 std::unique_ptr<SessionDescription> answer(
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002241 f2_.CreateAnswer(offer.get(), opts, NULL));
2242
2243 std::vector<std::string> codec_names =
2244 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
2245 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
2246 cricket::kRtxCodecName));
2247}
2248
2249// Test that when multiple RTX codecs are offered, only the matched RTX codec
2250// is added in the answer, and the unsupported RTX codec is filtered out.
2251TEST_F(MediaSessionDescriptionFactoryTest,
2252 FilterOutUnsupportedRtxWhenCreatingAnswer) {
2253 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002254 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
2255 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002256 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2257 // This creates RTX for H264-SVC in sender.
2258 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2259 f1_.set_video_codecs(f1_codecs);
2260
2261 // This creates RTX for H264 in sender.
2262 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2263 f1_.set_video_codecs(f1_codecs);
2264
2265 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2266 // This creates RTX for H264 in receiver.
2267 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
2268 f2_.set_video_codecs(f2_codecs);
2269
2270 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
2271 // for H264-SVC should also be removed.
kwiberg31022942016-03-11 14:18:21 -08002272 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002273 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002274 std::unique_ptr<SessionDescription> answer(
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002275 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002276 const VideoContentDescription* vcd =
2277 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002278 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2279 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2280 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002281
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002282 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002283}
2284
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002285// Test that after one RTX codec has been negotiated, a new offer can attempt
2286// to add another.
2287TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
2288 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002289 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
2290 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002291 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2292 // This creates RTX for H264 for the offerer.
2293 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2294 f1_.set_video_codecs(f1_codecs);
2295
kwiberg31022942016-03-11 14:18:21 -08002296 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002297 ASSERT_TRUE(offer);
2298 const VideoContentDescription* vcd =
2299 GetFirstVideoContentDescription(offer.get());
2300
2301 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
2302 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2303 &expected_codecs);
2304 EXPECT_EQ(expected_codecs, vcd->codecs());
2305
2306 // Now, attempt to add RTX for H264-SVC.
2307 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2308 f1_.set_video_codecs(f1_codecs);
2309
kwiberg31022942016-03-11 14:18:21 -08002310 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002311 f1_.CreateOffer(opts, offer.get()));
2312 ASSERT_TRUE(updated_offer);
2313 vcd = GetFirstVideoContentDescription(updated_offer.get());
2314
2315 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
2316 &expected_codecs);
2317 EXPECT_EQ(expected_codecs, vcd->codecs());
2318}
2319
Noah Richards2e7a0982015-05-18 14:02:54 -07002320// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
2321// generated for each simulcast ssrc and correctly grouped.
2322TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
2323 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002324 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_SENDRECV, kActive,
2325 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002326 // Add simulcast streams.
zhihuang1c378ed2017-08-17 14:10:50 -07002327 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
2328 "stream1label", 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002329
2330 // Use a single real codec, and then add RTX for it.
2331 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07002332 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07002333 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
2334 f1_.set_video_codecs(f1_codecs);
2335
2336 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
2337 // is a FID ssrc + grouping for each.
kwiberg31022942016-03-11 14:18:21 -08002338 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
Noah Richards2e7a0982015-05-18 14:02:54 -07002339 ASSERT_TRUE(offer.get() != NULL);
2340 VideoContentDescription* desc = static_cast<VideoContentDescription*>(
2341 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
2342 ASSERT_TRUE(desc != NULL);
2343 EXPECT_TRUE(desc->multistream());
2344 const StreamParamsVec& streams = desc->streams();
2345 // Single stream.
2346 ASSERT_EQ(1u, streams.size());
2347 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
2348 EXPECT_EQ(6u, streams[0].ssrcs.size());
2349 // And should have a SIM group for the simulcast.
2350 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2351 // And a FID group for RTX.
2352 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02002353 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002354 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2355 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02002356 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002357 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
2358 EXPECT_EQ(3u, fid_ssrcs.size());
2359}
2360
brandtr03d5fb12016-11-22 03:37:59 -08002361// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
2362// together with a FEC-FR grouping.
2363TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
2364 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002365 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_SENDRECV, kActive,
2366 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002367 // Add single stream.
zhihuang1c378ed2017-08-17 14:10:50 -07002368 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
2369 "stream1label", 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002370
2371 // Use a single real codec, and then add FlexFEC for it.
2372 std::vector<VideoCodec> f1_codecs;
2373 f1_codecs.push_back(VideoCodec(97, "H264"));
2374 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2375 f1_.set_video_codecs(f1_codecs);
2376
2377 // Ensure that the offer has a single FlexFEC ssrc and that
2378 // there is no FEC-FR ssrc + grouping for each.
2379 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
2380 ASSERT_TRUE(offer.get() != nullptr);
2381 VideoContentDescription* desc = static_cast<VideoContentDescription*>(
2382 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
2383 ASSERT_TRUE(desc != nullptr);
2384 EXPECT_TRUE(desc->multistream());
2385 const StreamParamsVec& streams = desc->streams();
2386 // Single stream.
2387 ASSERT_EQ(1u, streams.size());
2388 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
2389 EXPECT_EQ(2u, streams[0].ssrcs.size());
2390 // And should have a FEC-FR group for FlexFEC.
2391 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
2392 std::vector<uint32_t> primary_ssrcs;
2393 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2394 ASSERT_EQ(1u, primary_ssrcs.size());
2395 uint32_t flexfec_ssrc;
2396 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
2397 EXPECT_NE(flexfec_ssrc, 0u);
2398}
2399
2400// Test that FlexFEC is disabled for simulcast.
2401// TODO(brandtr): Remove this test when we support simulcast, either through
2402// multiple FlexfecSenders, or through multistream protection.
2403TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
2404 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002405 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_SENDRECV, kActive,
2406 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002407 // Add simulcast streams.
zhihuang1c378ed2017-08-17 14:10:50 -07002408 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
2409 "stream1label", 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002410
2411 // Use a single real codec, and then add FlexFEC for it.
2412 std::vector<VideoCodec> f1_codecs;
2413 f1_codecs.push_back(VideoCodec(97, "H264"));
2414 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2415 f1_.set_video_codecs(f1_codecs);
2416
2417 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
2418 // there is no FEC-FR ssrc + grouping for each.
2419 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
2420 ASSERT_TRUE(offer.get() != nullptr);
2421 VideoContentDescription* desc = static_cast<VideoContentDescription*>(
2422 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
2423 ASSERT_TRUE(desc != nullptr);
2424 EXPECT_FALSE(desc->multistream());
2425 const StreamParamsVec& streams = desc->streams();
2426 // Single stream.
2427 ASSERT_EQ(1u, streams.size());
2428 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
2429 EXPECT_EQ(3u, streams[0].ssrcs.size());
2430 // And should have a SIM group for the simulcast.
2431 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2432 // And not a FEC-FR group for FlexFEC.
2433 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
2434 std::vector<uint32_t> primary_ssrcs;
2435 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2436 EXPECT_EQ(3u, primary_ssrcs.size());
2437 for (uint32_t primary_ssrc : primary_ssrcs) {
2438 uint32_t flexfec_ssrc;
2439 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
2440 }
2441}
2442
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002443// Create an updated offer after creating an answer to the original offer and
2444// verify that the RTP header extensions that were part of the original answer
2445// are not changed in the updated offer.
2446TEST_F(MediaSessionDescriptionFactoryTest,
2447 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
2448 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002449 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002450
2451 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
2452 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
2453 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
2454 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
2455
kwiberg31022942016-03-11 14:18:21 -08002456 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2457 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002458 f2_.CreateAnswer(offer.get(), opts, NULL));
2459
2460 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
2461 GetFirstAudioContentDescription(
2462 answer.get())->rtp_header_extensions());
2463 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
2464 GetFirstVideoContentDescription(
2465 answer.get())->rtp_header_extensions());
2466
kwiberg31022942016-03-11 14:18:21 -08002467 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002468 f2_.CreateOffer(opts, answer.get()));
2469
2470 // The expected RTP header extensions in the new offer are the resulting
2471 // extensions from the first offer/answer exchange plus the extensions only
2472 // |f2_| offer.
2473 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002474 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07002475 const RtpExtension kUpdatedAudioRtpExtensions[] = {
2476 kAudioRtpExtensionAnswer[0], RtpExtension(kAudioRtpExtension2[1].uri, 13),
2477 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002478 };
2479
2480 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002481 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07002482 const RtpExtension kUpdatedVideoRtpExtensions[] = {
2483 kVideoRtpExtensionAnswer[0], RtpExtension(kVideoRtpExtension2[1].uri, 12),
2484 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002485 };
2486
2487 const AudioContentDescription* updated_acd =
2488 GetFirstAudioContentDescription(updated_offer.get());
2489 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
2490 updated_acd->rtp_header_extensions());
2491
2492 const VideoContentDescription* updated_vcd =
2493 GetFirstVideoContentDescription(updated_offer.get());
2494 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
2495 updated_vcd->rtp_header_extensions());
2496}
2497
deadbeefa5b273a2015-08-20 17:30:13 -07002498// Verify that if the same RTP extension URI is used for audio and video, the
2499// same ID is used. Also verify that the ID isn't changed when creating an
2500// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07002501TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07002502 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002503 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07002504
2505 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
2506 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
2507
kwiberg31022942016-03-11 14:18:21 -08002508 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
deadbeefa5b273a2015-08-20 17:30:13 -07002509
2510 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
2511 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07002512 const RtpExtension kExpectedVideoRtpExtension[] = {
2513 kVideoRtpExtension3[0], kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07002514 };
2515
2516 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
2517 GetFirstAudioContentDescription(
2518 offer.get())->rtp_header_extensions());
2519 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2520 GetFirstVideoContentDescription(
2521 offer.get())->rtp_header_extensions());
2522
2523 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08002524 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07002525 f1_.CreateOffer(opts, offer.get()));
2526
2527 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
2528 GetFirstAudioContentDescription(
2529 updated_offer.get())->rtp_header_extensions());
2530 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2531 GetFirstVideoContentDescription(
2532 updated_offer.get())->rtp_header_extensions());
2533}
2534
jbauch5869f502017-06-29 12:31:36 -07002535// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
2536TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
2537 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002538 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
jbauch5869f502017-06-29 12:31:36 -07002539
2540 f1_.set_enable_encrypted_rtp_header_extensions(true);
2541 f2_.set_enable_encrypted_rtp_header_extensions(true);
2542
2543 f1_.set_audio_rtp_header_extensions(
2544 MAKE_VECTOR(kAudioRtpExtension3ForEncryption));
2545 f1_.set_video_rtp_header_extensions(
2546 MAKE_VECTOR(kVideoRtpExtension3ForEncryption));
2547
2548 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2549
2550 // The extensions that are shared between audio and video should use the same
2551 // id.
2552 const RtpExtension kExpectedVideoRtpExtension[] = {
2553 kVideoRtpExtension3ForEncryption[0],
2554 kAudioRtpExtension3ForEncryptionOffer[1],
2555 kAudioRtpExtension3ForEncryptionOffer[2],
2556 };
2557
2558 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
2559 GetFirstAudioContentDescription(
2560 offer.get())->rtp_header_extensions());
2561 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2562 GetFirstVideoContentDescription(
2563 offer.get())->rtp_header_extensions());
2564
2565 // Nothing should change when creating a new offer
2566 std::unique_ptr<SessionDescription> updated_offer(
2567 f1_.CreateOffer(opts, offer.get()));
2568
2569 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
2570 GetFirstAudioContentDescription(
2571 updated_offer.get())->rtp_header_extensions());
2572 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2573 GetFirstVideoContentDescription(
2574 updated_offer.get())->rtp_header_extensions());
2575}
2576
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002577TEST(MediaSessionDescription, CopySessionDescription) {
2578 SessionDescription source;
2579 cricket::ContentGroup group(cricket::CN_AUDIO);
2580 source.AddGroup(group);
2581 AudioContentDescription* acd(new AudioContentDescription());
2582 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
2583 acd->AddLegacyStream(1);
2584 source.AddContent(cricket::CN_AUDIO, cricket::NS_JINGLE_RTP, acd);
2585 VideoContentDescription* vcd(new VideoContentDescription());
2586 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
2587 vcd->AddLegacyStream(2);
2588 source.AddContent(cricket::CN_VIDEO, cricket::NS_JINGLE_RTP, vcd);
2589
kwiberg31022942016-03-11 14:18:21 -08002590 std::unique_ptr<SessionDescription> copy(source.Copy());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002591 ASSERT_TRUE(copy.get() != NULL);
2592 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
2593 const ContentInfo* ac = copy->GetContentByName("audio");
2594 const ContentInfo* vc = copy->GetContentByName("video");
2595 ASSERT_TRUE(ac != NULL);
2596 ASSERT_TRUE(vc != NULL);
2597 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
2598 const AudioContentDescription* acd_copy =
2599 static_cast<const AudioContentDescription*>(ac->description);
2600 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
2601 EXPECT_EQ(1u, acd->first_ssrc());
2602
2603 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
2604 const VideoContentDescription* vcd_copy =
2605 static_cast<const VideoContentDescription*>(vc->description);
2606 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
2607 EXPECT_EQ(2u, vcd->first_ssrc());
2608}
2609
2610// The below TestTransportInfoXXX tests create different offers/answers, and
2611// ensure the TransportInfo in the SessionDescription matches what we expect.
2612TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
2613 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002614 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
2615 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002616 TestTransportInfo(true, options, false);
2617}
2618
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002619TEST_F(MediaSessionDescriptionFactoryTest,
2620 TestTransportInfoOfferIceRenomination) {
2621 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002622 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
2623 &options);
2624 options.media_description_options[0]
2625 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002626 TestTransportInfo(true, options, false);
2627}
2628
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002629TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
2630 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002631 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
2632 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002633 TestTransportInfo(true, options, true);
2634}
2635
2636TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
2637 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002638 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2639 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002640 TestTransportInfo(true, options, false);
2641}
2642
2643TEST_F(MediaSessionDescriptionFactoryTest,
2644 TestTransportInfoOfferMultimediaCurrent) {
2645 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002646 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2647 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002648 TestTransportInfo(true, options, true);
2649}
2650
2651TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
2652 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002653 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2654 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002655 options.bundle_enabled = true;
2656 TestTransportInfo(true, options, false);
2657}
2658
2659TEST_F(MediaSessionDescriptionFactoryTest,
2660 TestTransportInfoOfferBundleCurrent) {
2661 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002662 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2663 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002664 options.bundle_enabled = true;
2665 TestTransportInfo(true, options, true);
2666}
2667
2668TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
2669 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002670 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
2671 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002672 TestTransportInfo(false, options, false);
2673}
2674
2675TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002676 TestTransportInfoAnswerIceRenomination) {
2677 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002678 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
2679 &options);
2680 options.media_description_options[0]
2681 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002682 TestTransportInfo(false, options, false);
2683}
2684
2685TEST_F(MediaSessionDescriptionFactoryTest,
2686 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002687 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002688 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
2689 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002690 TestTransportInfo(false, options, true);
2691}
2692
2693TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
2694 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002695 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2696 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002697 TestTransportInfo(false, options, false);
2698}
2699
2700TEST_F(MediaSessionDescriptionFactoryTest,
2701 TestTransportInfoAnswerMultimediaCurrent) {
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(false, options, true);
2706}
2707
2708TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
2709 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002710 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2711 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002712 options.bundle_enabled = true;
2713 TestTransportInfo(false, options, false);
2714}
2715
2716TEST_F(MediaSessionDescriptionFactoryTest,
2717 TestTransportInfoAnswerBundleCurrent) {
2718 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002719 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2720 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002721 options.bundle_enabled = true;
2722 TestTransportInfo(false, options, true);
2723}
2724
2725// Create an offer with bundle enabled and verify the crypto parameters are
2726// the common set of the available cryptos.
2727TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
2728 TestCryptoWithBundle(true);
2729}
2730
2731// Create an answer with bundle enabled and verify the crypto parameters are
2732// the common set of the available cryptos.
2733TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
2734 TestCryptoWithBundle(false);
2735}
2736
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002737// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
2738// DTLS is not enabled locally.
2739TEST_F(MediaSessionDescriptionFactoryTest,
2740 TestOfferDtlsSavpfWithoutDtlsFailed) {
2741 f1_.set_secure(SEC_ENABLED);
2742 f2_.set_secure(SEC_ENABLED);
2743 tdf1_.set_secure(SEC_DISABLED);
2744 tdf2_.set_secure(SEC_DISABLED);
2745
kwiberg31022942016-03-11 14:18:21 -08002746 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -07002747 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002748 ASSERT_TRUE(offer.get() != NULL);
2749 ContentInfo* offer_content = offer->GetContentByName("audio");
2750 ASSERT_TRUE(offer_content != NULL);
2751 AudioContentDescription* offer_audio_desc =
2752 static_cast<AudioContentDescription*>(offer_content->description);
2753 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2754
kwiberg31022942016-03-11 14:18:21 -08002755 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002756 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002757 ASSERT_TRUE(answer != NULL);
2758 ContentInfo* answer_content = answer->GetContentByName("audio");
2759 ASSERT_TRUE(answer_content != NULL);
2760
2761 ASSERT_TRUE(answer_content->rejected);
2762}
2763
2764// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
2765// UDP/TLS/RTP/SAVPF.
2766TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
2767 f1_.set_secure(SEC_ENABLED);
2768 f2_.set_secure(SEC_ENABLED);
2769 tdf1_.set_secure(SEC_ENABLED);
2770 tdf2_.set_secure(SEC_ENABLED);
2771
kwiberg31022942016-03-11 14:18:21 -08002772 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -07002773 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002774 ASSERT_TRUE(offer.get() != NULL);
2775 ContentInfo* offer_content = offer->GetContentByName("audio");
2776 ASSERT_TRUE(offer_content != NULL);
2777 AudioContentDescription* offer_audio_desc =
2778 static_cast<AudioContentDescription*>(offer_content->description);
2779 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2780
kwiberg31022942016-03-11 14:18:21 -08002781 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002782 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002783 ASSERT_TRUE(answer != NULL);
2784
2785 const ContentInfo* answer_content = answer->GetContentByName("audio");
2786 ASSERT_TRUE(answer_content != NULL);
2787 ASSERT_FALSE(answer_content->rejected);
2788
2789 const AudioContentDescription* answer_audio_desc =
2790 static_cast<const AudioContentDescription*>(answer_content->description);
2791 EXPECT_EQ(std::string(cricket::kMediaProtocolDtlsSavpf),
2792 answer_audio_desc->protocol());
2793}
2794
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002795// Test that we include both SDES and DTLS in the offer, but only include SDES
2796// in the answer if DTLS isn't negotiated.
2797TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
2798 f1_.set_secure(SEC_ENABLED);
2799 f2_.set_secure(SEC_ENABLED);
2800 tdf1_.set_secure(SEC_ENABLED);
2801 tdf2_.set_secure(SEC_DISABLED);
2802 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002803 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
kwiberg31022942016-03-11 14:18:21 -08002804 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002805 const cricket::MediaContentDescription* audio_media_desc;
2806 const cricket::MediaContentDescription* video_media_desc;
2807 const cricket::TransportDescription* audio_trans_desc;
2808 const cricket::TransportDescription* video_trans_desc;
2809
2810 // Generate an offer with SDES and DTLS support.
2811 offer.reset(f1_.CreateOffer(options, NULL));
2812 ASSERT_TRUE(offer.get() != NULL);
2813
2814 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2815 offer->GetContentDescriptionByName("audio"));
2816 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002817 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002818 offer->GetContentDescriptionByName("video"));
2819 ASSERT_TRUE(video_media_desc != NULL);
2820 EXPECT_EQ(2u, audio_media_desc->cryptos().size());
2821 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2822
2823 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2824 ASSERT_TRUE(audio_trans_desc != NULL);
2825 video_trans_desc = offer->GetTransportDescriptionByName("video");
2826 ASSERT_TRUE(video_trans_desc != NULL);
2827 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2828 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
2829
2830 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
2831 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2832 ASSERT_TRUE(answer.get() != NULL);
2833
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002834 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002835 answer->GetContentDescriptionByName("audio"));
2836 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002837 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002838 answer->GetContentDescriptionByName("video"));
2839 ASSERT_TRUE(video_media_desc != NULL);
2840 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
2841 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2842
2843 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2844 ASSERT_TRUE(audio_trans_desc != NULL);
2845 video_trans_desc = answer->GetTransportDescriptionByName("video");
2846 ASSERT_TRUE(video_trans_desc != NULL);
2847 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
2848 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
2849
2850 // Enable DTLS; the answer should now only have DTLS support.
2851 tdf2_.set_secure(SEC_ENABLED);
2852 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2853 ASSERT_TRUE(answer.get() != NULL);
2854
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002855 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002856 answer->GetContentDescriptionByName("audio"));
2857 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002858 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002859 answer->GetContentDescriptionByName("video"));
2860 ASSERT_TRUE(video_media_desc != NULL);
2861 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2862 EXPECT_TRUE(video_media_desc->cryptos().empty());
2863 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2864 audio_media_desc->protocol());
2865 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2866 video_media_desc->protocol());
2867
2868 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2869 ASSERT_TRUE(audio_trans_desc != NULL);
2870 video_trans_desc = answer->GetTransportDescriptionByName("video");
2871 ASSERT_TRUE(video_trans_desc != NULL);
2872 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2873 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00002874
2875 // Try creating offer again. DTLS enabled now, crypto's should be empty
2876 // in new offer.
2877 offer.reset(f1_.CreateOffer(options, offer.get()));
2878 ASSERT_TRUE(offer.get() != NULL);
2879 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2880 offer->GetContentDescriptionByName("audio"));
2881 ASSERT_TRUE(audio_media_desc != NULL);
2882 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
2883 offer->GetContentDescriptionByName("video"));
2884 ASSERT_TRUE(video_media_desc != NULL);
2885 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2886 EXPECT_TRUE(video_media_desc->cryptos().empty());
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);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002894}
2895
2896// Test that an answer can't be created if cryptos are required but the offer is
2897// unsecure.
2898TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07002899 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002900 f1_.set_secure(SEC_DISABLED);
2901 tdf1_.set_secure(SEC_DISABLED);
2902 f2_.set_secure(SEC_REQUIRED);
2903 tdf1_.set_secure(SEC_ENABLED);
2904
kwiberg31022942016-03-11 14:18:21 -08002905 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002906 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002907 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002908 f2_.CreateAnswer(offer.get(), options, NULL));
2909 EXPECT_TRUE(answer.get() == NULL);
2910}
2911
2912// Test that we accept a DTLS offer without SDES and create an appropriate
2913// answer.
2914TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
2915 f1_.set_secure(SEC_DISABLED);
2916 f2_.set_secure(SEC_ENABLED);
2917 tdf1_.set_secure(SEC_ENABLED);
2918 tdf2_.set_secure(SEC_ENABLED);
2919 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002920 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2921 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002922
kwiberg31022942016-03-11 14:18:21 -08002923 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002924
2925 // Generate an offer with DTLS but without SDES.
2926 offer.reset(f1_.CreateOffer(options, NULL));
2927 ASSERT_TRUE(offer.get() != NULL);
2928
2929 const AudioContentDescription* audio_offer =
2930 GetFirstAudioContentDescription(offer.get());
2931 ASSERT_TRUE(audio_offer->cryptos().empty());
2932 const VideoContentDescription* video_offer =
2933 GetFirstVideoContentDescription(offer.get());
2934 ASSERT_TRUE(video_offer->cryptos().empty());
2935 const DataContentDescription* data_offer =
2936 GetFirstDataContentDescription(offer.get());
2937 ASSERT_TRUE(data_offer->cryptos().empty());
2938
2939 const cricket::TransportDescription* audio_offer_trans_desc =
2940 offer->GetTransportDescriptionByName("audio");
2941 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
2942 const cricket::TransportDescription* video_offer_trans_desc =
2943 offer->GetTransportDescriptionByName("video");
2944 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
2945 const cricket::TransportDescription* data_offer_trans_desc =
2946 offer->GetTransportDescriptionByName("data");
2947 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
2948
2949 // Generate an answer with DTLS.
2950 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2951 ASSERT_TRUE(answer.get() != NULL);
2952
2953 const cricket::TransportDescription* audio_answer_trans_desc =
2954 answer->GetTransportDescriptionByName("audio");
2955 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
2956 const cricket::TransportDescription* video_answer_trans_desc =
2957 answer->GetTransportDescriptionByName("video");
2958 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
2959 const cricket::TransportDescription* data_answer_trans_desc =
2960 answer->GetTransportDescriptionByName("data");
2961 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
2962}
2963
2964// Verifies if vad_enabled option is set to false, CN codecs are not present in
2965// offer or answer.
2966TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
2967 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002968 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
kwiberg31022942016-03-11 14:18:21 -08002969 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002970 ASSERT_TRUE(offer.get() != NULL);
2971 const ContentInfo* audio_content = offer->GetContentByName("audio");
2972 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
2973
2974 options.vad_enabled = false;
2975 offer.reset(f1_.CreateOffer(options, NULL));
2976 ASSERT_TRUE(offer.get() != NULL);
2977 audio_content = offer->GetContentByName("audio");
2978 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
kwiberg31022942016-03-11 14:18:21 -08002979 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002980 f1_.CreateAnswer(offer.get(), options, NULL));
2981 ASSERT_TRUE(answer.get() != NULL);
2982 audio_content = answer->GetContentByName("audio");
2983 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
2984}
deadbeef44f08192015-12-15 16:20:09 -08002985
zhihuang1c378ed2017-08-17 14:10:50 -07002986// Test that the generated MIDs match the existing offer.
2987TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08002988 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002989 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_modified", cricket::MD_RECVONLY,
2990 kActive, &opts);
2991 AddMediaSection(MEDIA_TYPE_VIDEO, "video_modified", cricket::MD_RECVONLY,
2992 kActive, &opts);
deadbeef44f08192015-12-15 16:20:09 -08002993 opts.data_channel_type = cricket::DCT_SCTP;
zhihuang1c378ed2017-08-17 14:10:50 -07002994 AddMediaSection(MEDIA_TYPE_DATA, "data_modified", cricket::MD_SENDRECV,
2995 kActive, &opts);
2996 // Create offer.
kwiberg31022942016-03-11 14:18:21 -08002997 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
kwiberg31022942016-03-11 14:18:21 -08002998 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08002999 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003000
deadbeef44f08192015-12-15 16:20:09 -08003001 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3002 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3003 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3004 ASSERT_TRUE(audio_content != nullptr);
3005 ASSERT_TRUE(video_content != nullptr);
3006 ASSERT_TRUE(data_content != nullptr);
3007 EXPECT_EQ("audio_modified", audio_content->name);
3008 EXPECT_EQ("video_modified", video_content->name);
3009 EXPECT_EQ("data_modified", data_content->name);
3010}
zhihuangcf5b37c2016-05-05 11:44:35 -07003011
zhihuang1c378ed2017-08-17 14:10:50 -07003012// The following tests verify that the unified plan SDP is supported.
3013// Test that we can create an offer with multiple media sections of same media
3014// type.
3015TEST_F(MediaSessionDescriptionFactoryTest,
3016 CreateOfferWithMultipleAVMediaSections) {
3017 MediaSessionOptions opts;
3018 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_1", cricket::MD_SENDRECV, kActive,
3019 &opts);
3020 AttachSenderToMediaSection("audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1,
3021 kMediaStream1, 1, &opts);
3022
3023 AddMediaSection(MEDIA_TYPE_VIDEO, "video_1", cricket::MD_SENDRECV, kActive,
3024 &opts);
3025 AttachSenderToMediaSection("video_1", MEDIA_TYPE_VIDEO, kVideoTrack1,
3026 kMediaStream1, 1, &opts);
3027
3028 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_2", cricket::MD_SENDRECV, kActive,
3029 &opts);
3030 AttachSenderToMediaSection("audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2,
3031 kMediaStream2, 1, &opts);
3032
3033 AddMediaSection(MEDIA_TYPE_VIDEO, "video_2", cricket::MD_SENDRECV, kActive,
3034 &opts);
3035 AttachSenderToMediaSection("video_2", MEDIA_TYPE_VIDEO, kVideoTrack2,
3036 kMediaStream2, 1, &opts);
3037 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3038 ASSERT_TRUE(offer);
3039
3040 ASSERT_EQ(4u, offer->contents().size());
3041 EXPECT_FALSE(offer->contents()[0].rejected);
3042 const AudioContentDescription* acd =
3043 static_cast<const AudioContentDescription*>(
3044 offer->contents()[0].description);
3045 ASSERT_EQ(1u, acd->streams().size());
3046 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
3047 EXPECT_EQ(cricket::MD_SENDRECV, acd->direction());
3048
3049 EXPECT_FALSE(offer->contents()[1].rejected);
3050 const VideoContentDescription* vcd =
3051 static_cast<const VideoContentDescription*>(
3052 offer->contents()[1].description);
3053 ASSERT_EQ(1u, vcd->streams().size());
3054 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
3055 EXPECT_EQ(cricket::MD_SENDRECV, vcd->direction());
3056
3057 EXPECT_FALSE(offer->contents()[2].rejected);
3058 acd = static_cast<const AudioContentDescription*>(
3059 offer->contents()[2].description);
3060 ASSERT_EQ(1u, acd->streams().size());
3061 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
3062 EXPECT_EQ(cricket::MD_SENDRECV, acd->direction());
3063
3064 EXPECT_FALSE(offer->contents()[3].rejected);
3065 vcd = static_cast<const VideoContentDescription*>(
3066 offer->contents()[3].description);
3067 ASSERT_EQ(1u, vcd->streams().size());
3068 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
3069 EXPECT_EQ(cricket::MD_SENDRECV, vcd->direction());
3070}
3071
3072// Test that we can create an answer with multiple media sections of same media
3073// type.
3074TEST_F(MediaSessionDescriptionFactoryTest,
3075 CreateAnswerWithMultipleAVMediaSections) {
3076 MediaSessionOptions opts;
3077 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_1", cricket::MD_SENDRECV, kActive,
3078 &opts);
3079 AttachSenderToMediaSection("audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1,
3080 kMediaStream1, 1, &opts);
3081
3082 AddMediaSection(MEDIA_TYPE_VIDEO, "video_1", cricket::MD_SENDRECV, kActive,
3083 &opts);
3084 AttachSenderToMediaSection("video_1", MEDIA_TYPE_VIDEO, kVideoTrack1,
3085 kMediaStream1, 1, &opts);
3086
3087 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_2", cricket::MD_SENDRECV, kActive,
3088 &opts);
3089 AttachSenderToMediaSection("audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2,
3090 kMediaStream2, 1, &opts);
3091
3092 AddMediaSection(MEDIA_TYPE_VIDEO, "video_2", cricket::MD_SENDRECV, kActive,
3093 &opts);
3094 AttachSenderToMediaSection("video_2", MEDIA_TYPE_VIDEO, kVideoTrack2,
3095 kMediaStream2, 1, &opts);
3096
3097 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3098 ASSERT_TRUE(offer);
3099 std::unique_ptr<SessionDescription> answer(
3100 f2_.CreateAnswer(offer.get(), opts, nullptr));
3101
3102 ASSERT_EQ(4u, answer->contents().size());
3103 EXPECT_FALSE(answer->contents()[0].rejected);
3104 const AudioContentDescription* acd =
3105 static_cast<const AudioContentDescription*>(
3106 answer->contents()[0].description);
3107 ASSERT_EQ(1u, acd->streams().size());
3108 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
3109 EXPECT_EQ(cricket::MD_SENDRECV, acd->direction());
3110
3111 EXPECT_FALSE(answer->contents()[1].rejected);
3112 const VideoContentDescription* vcd =
3113 static_cast<const VideoContentDescription*>(
3114 answer->contents()[1].description);
3115 ASSERT_EQ(1u, vcd->streams().size());
3116 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
3117 EXPECT_EQ(cricket::MD_SENDRECV, vcd->direction());
3118
3119 EXPECT_FALSE(answer->contents()[2].rejected);
3120 acd = static_cast<const AudioContentDescription*>(
3121 answer->contents()[2].description);
3122 ASSERT_EQ(1u, acd->streams().size());
3123 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
3124 EXPECT_EQ(cricket::MD_SENDRECV, acd->direction());
3125
3126 EXPECT_FALSE(answer->contents()[3].rejected);
3127 vcd = static_cast<const VideoContentDescription*>(
3128 answer->contents()[3].description);
3129 ASSERT_EQ(1u, vcd->streams().size());
3130 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
3131 EXPECT_EQ(cricket::MD_SENDRECV, vcd->direction());
3132}
3133
3134// Test that the media section will be rejected in offer if the corresponding
3135// MediaDescriptionOptions is stopped by the offerer.
3136TEST_F(MediaSessionDescriptionFactoryTest,
3137 CreateOfferWithMediaSectionStoppedByOfferer) {
3138 // Create an offer with two audio sections and one of them is stopped.
3139 MediaSessionOptions offer_opts;
3140 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1", cricket::MD_SENDRECV, kActive,
3141 &offer_opts);
3142 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2", cricket::MD_INACTIVE, kStopped,
3143 &offer_opts);
3144 std::unique_ptr<SessionDescription> offer(
3145 f1_.CreateOffer(offer_opts, nullptr));
3146 ASSERT_TRUE(offer);
3147 ASSERT_EQ(2u, offer->contents().size());
3148 EXPECT_FALSE(offer->contents()[0].rejected);
3149 EXPECT_TRUE(offer->contents()[1].rejected);
3150}
3151
3152// Test that the media section will be rejected in answer if the corresponding
3153// MediaDescriptionOptions is stopped by the offerer.
3154TEST_F(MediaSessionDescriptionFactoryTest,
3155 CreateAnswerWithMediaSectionStoppedByOfferer) {
3156 // Create an offer with two audio sections and one of them is stopped.
3157 MediaSessionOptions offer_opts;
3158 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1", cricket::MD_SENDRECV, kActive,
3159 &offer_opts);
3160 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2", cricket::MD_INACTIVE, kStopped,
3161 &offer_opts);
3162 std::unique_ptr<SessionDescription> offer(
3163 f1_.CreateOffer(offer_opts, nullptr));
3164 ASSERT_TRUE(offer);
3165 ASSERT_EQ(2u, offer->contents().size());
3166 EXPECT_FALSE(offer->contents()[0].rejected);
3167 EXPECT_TRUE(offer->contents()[1].rejected);
3168
3169 // Create an answer based on the offer.
3170 MediaSessionOptions answer_opts;
3171 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1", cricket::MD_SENDRECV, kActive,
3172 &answer_opts);
3173 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2", cricket::MD_SENDRECV, kActive,
3174 &answer_opts);
3175 std::unique_ptr<SessionDescription> answer(
3176 f2_.CreateAnswer(offer.get(), answer_opts, nullptr));
3177 ASSERT_EQ(2u, answer->contents().size());
3178 EXPECT_FALSE(answer->contents()[0].rejected);
3179 EXPECT_TRUE(answer->contents()[1].rejected);
3180}
3181
3182// Test that the media section will be rejected in answer if the corresponding
3183// MediaDescriptionOptions is stopped by the answerer.
3184TEST_F(MediaSessionDescriptionFactoryTest,
3185 CreateAnswerWithMediaSectionRejectedByAnswerer) {
3186 // Create an offer with two audio sections.
3187 MediaSessionOptions offer_opts;
3188 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1", cricket::MD_SENDRECV, kActive,
3189 &offer_opts);
3190 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2", cricket::MD_SENDRECV, kActive,
3191 &offer_opts);
3192 std::unique_ptr<SessionDescription> offer(
3193 f1_.CreateOffer(offer_opts, nullptr));
3194 ASSERT_TRUE(offer);
3195 ASSERT_EQ(2u, offer->contents().size());
3196 ASSERT_FALSE(offer->contents()[0].rejected);
3197 ASSERT_FALSE(offer->contents()[1].rejected);
3198
3199 // The answerer rejects one of the audio sections.
3200 MediaSessionOptions answer_opts;
3201 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1", cricket::MD_SENDRECV, kActive,
3202 &answer_opts);
3203 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2", cricket::MD_INACTIVE, kStopped,
3204 &answer_opts);
3205 std::unique_ptr<SessionDescription> answer(
3206 f2_.CreateAnswer(offer.get(), answer_opts, nullptr));
3207 ASSERT_EQ(2u, answer->contents().size());
3208 EXPECT_FALSE(answer->contents()[0].rejected);
3209 EXPECT_TRUE(answer->contents()[1].rejected);
3210}
3211
3212// Test the generated media sections has the same order of the
3213// corresponding MediaDescriptionOptions.
3214TEST_F(MediaSessionDescriptionFactoryTest,
3215 CreateOfferRespectsMediaDescriptionOptionsOrder) {
3216 MediaSessionOptions opts;
3217 // This tests put video section first because normally audio comes first by
3218 // default.
3219 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_SENDRECV, kActive,
3220 &opts);
3221 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_SENDRECV, kActive,
3222 &opts);
3223 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3224
3225 ASSERT_TRUE(offer);
3226 ASSERT_EQ(2u, offer->contents().size());
3227 EXPECT_EQ("video", offer->contents()[0].name);
3228 EXPECT_EQ("audio", offer->contents()[1].name);
3229}
3230
3231// Test that different media sections using the same codec have same payload
3232// type.
3233TEST_F(MediaSessionDescriptionFactoryTest,
3234 PayloadTypesSharedByMediaSectionsOfSameType) {
3235 MediaSessionOptions opts;
3236 AddMediaSection(MEDIA_TYPE_VIDEO, "video1", cricket::MD_SENDRECV, kActive,
3237 &opts);
3238 AddMediaSection(MEDIA_TYPE_VIDEO, "video2", cricket::MD_SENDRECV, kActive,
3239 &opts);
3240 // Create an offer with two video sections using same codecs.
3241 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3242 ASSERT_TRUE(offer);
3243 ASSERT_EQ(2u, offer->contents().size());
3244 const VideoContentDescription* vcd1 =
3245 static_cast<const VideoContentDescription*>(
3246 offer->contents()[0].description);
3247 const VideoContentDescription* vcd2 =
3248 static_cast<const VideoContentDescription*>(
3249 offer->contents()[1].description);
3250 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3251 ASSERT_EQ(2u, vcd1->codecs().size());
3252 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3253 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3254 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
3255 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
3256
3257 // Create answer and negotiate the codecs.
3258 std::unique_ptr<SessionDescription> answer(
3259 f2_.CreateAnswer(offer.get(), opts, nullptr));
3260 ASSERT_TRUE(answer);
3261 ASSERT_EQ(2u, answer->contents().size());
3262 vcd1 = static_cast<const VideoContentDescription*>(
3263 answer->contents()[0].description);
3264 vcd2 = static_cast<const VideoContentDescription*>(
3265 answer->contents()[1].description);
3266 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3267 ASSERT_EQ(1u, vcd1->codecs().size());
3268 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3269 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3270}
3271
3272// Test that the codec preference order per media section is respected in
3273// subsequent offer.
3274TEST_F(MediaSessionDescriptionFactoryTest,
3275 CreateOfferRespectsCodecPreferenceOrder) {
3276 MediaSessionOptions opts;
3277 AddMediaSection(MEDIA_TYPE_VIDEO, "video1", cricket::MD_SENDRECV, kActive,
3278 &opts);
3279 AddMediaSection(MEDIA_TYPE_VIDEO, "video2", cricket::MD_SENDRECV, kActive,
3280 &opts);
3281 // Create an offer with two video sections using same codecs.
3282 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3283 ASSERT_TRUE(offer);
3284 ASSERT_EQ(2u, offer->contents().size());
3285 VideoContentDescription* vcd1 =
3286 static_cast<VideoContentDescription*>(offer->contents()[0].description);
3287 const VideoContentDescription* vcd2 =
3288 static_cast<const VideoContentDescription*>(
3289 offer->contents()[1].description);
3290 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3291 EXPECT_EQ(video_codecs, vcd1->codecs());
3292 EXPECT_EQ(video_codecs, vcd2->codecs());
3293
3294 // Change the codec preference of the first video section and create a
3295 // follow-up offer.
3296 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3297 vcd1->set_codecs(video_codecs_reverse);
3298 std::unique_ptr<SessionDescription> updated_offer(
3299 f1_.CreateOffer(opts, offer.get()));
3300 vcd1 = static_cast<VideoContentDescription*>(
3301 updated_offer->contents()[0].description);
3302 vcd2 = static_cast<const VideoContentDescription*>(
3303 updated_offer->contents()[1].description);
3304 // The video codec preference order should be respected.
3305 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3306 EXPECT_EQ(video_codecs, vcd2->codecs());
3307}
3308
3309// Test that the codec preference order per media section is respected in
3310// the answer.
3311TEST_F(MediaSessionDescriptionFactoryTest,
3312 CreateAnswerRespectsCodecPreferenceOrder) {
3313 MediaSessionOptions opts;
3314 AddMediaSection(MEDIA_TYPE_VIDEO, "video1", cricket::MD_SENDRECV, kActive,
3315 &opts);
3316 AddMediaSection(MEDIA_TYPE_VIDEO, "video2", cricket::MD_SENDRECV, kActive,
3317 &opts);
3318 // Create an offer with two video sections using same codecs.
3319 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3320 ASSERT_TRUE(offer);
3321 ASSERT_EQ(2u, offer->contents().size());
3322 VideoContentDescription* vcd1 =
3323 static_cast<VideoContentDescription*>(offer->contents()[0].description);
3324 const VideoContentDescription* vcd2 =
3325 static_cast<const VideoContentDescription*>(
3326 offer->contents()[1].description);
3327 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3328 EXPECT_EQ(video_codecs, vcd1->codecs());
3329 EXPECT_EQ(video_codecs, vcd2->codecs());
3330
3331 // Change the codec preference of the first video section and create an
3332 // answer.
3333 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3334 vcd1->set_codecs(video_codecs_reverse);
3335 std::unique_ptr<SessionDescription> answer(
3336 f1_.CreateAnswer(offer.get(), opts, nullptr));
3337 vcd1 =
3338 static_cast<VideoContentDescription*>(answer->contents()[0].description);
3339 vcd2 = static_cast<const VideoContentDescription*>(
3340 answer->contents()[1].description);
3341 // The video codec preference order should be respected.
3342 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3343 EXPECT_EQ(video_codecs, vcd2->codecs());
3344}
3345
zhihuangcf5b37c2016-05-05 11:44:35 -07003346class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
3347 public:
3348 MediaProtocolTest() : f1_(&tdf1_), f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -07003349 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
3350 MAKE_VECTOR(kAudioCodecs1));
zhihuangcf5b37c2016-05-05 11:44:35 -07003351 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
3352 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07003353 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
3354 MAKE_VECTOR(kAudioCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07003355 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
3356 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
3357 f1_.set_secure(SEC_ENABLED);
3358 f2_.set_secure(SEC_ENABLED);
3359 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07003360 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07003361 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07003362 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07003363 tdf1_.set_secure(SEC_ENABLED);
3364 tdf2_.set_secure(SEC_ENABLED);
3365 }
3366
3367 protected:
3368 MediaSessionDescriptionFactory f1_;
3369 MediaSessionDescriptionFactory f2_;
3370 TransportDescriptionFactory tdf1_;
3371 TransportDescriptionFactory tdf2_;
3372};
3373
3374TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
3375 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003376 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
zhihuangcf5b37c2016-05-05 11:44:35 -07003377 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3378 ASSERT_TRUE(offer.get() != nullptr);
3379 // Set the protocol for all the contents.
3380 for (auto content : offer.get()->contents()) {
3381 static_cast<MediaContentDescription*>(content.description)
3382 ->set_protocol(GetParam());
3383 }
3384 std::unique_ptr<SessionDescription> answer(
3385 f2_.CreateAnswer(offer.get(), opts, nullptr));
3386 const ContentInfo* ac = answer->GetContentByName("audio");
3387 const ContentInfo* vc = answer->GetContentByName("video");
3388 ASSERT_TRUE(ac != nullptr);
3389 ASSERT_TRUE(vc != nullptr);
3390 EXPECT_FALSE(ac->rejected); // the offer is accepted
3391 EXPECT_FALSE(vc->rejected);
3392 const AudioContentDescription* acd =
3393 static_cast<const AudioContentDescription*>(ac->description);
3394 const VideoContentDescription* vcd =
3395 static_cast<const VideoContentDescription*>(vc->description);
3396 EXPECT_EQ(GetParam(), acd->protocol());
3397 EXPECT_EQ(GetParam(), vcd->protocol());
3398}
3399
3400INSTANTIATE_TEST_CASE_P(MediaProtocolPatternTest,
3401 MediaProtocolTest,
3402 ::testing::ValuesIn(kMediaProtocols));
3403INSTANTIATE_TEST_CASE_P(MediaProtocolDtlsPatternTest,
3404 MediaProtocolTest,
3405 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07003406
3407TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
3408 TransportDescriptionFactory tdf;
3409 MediaSessionDescriptionFactory sf(&tdf);
3410 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
3411 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
3412
3413 // The merged list of codecs should contain any send codecs that are also
3414 // nominally in the recieve codecs list. Payload types should be picked from
3415 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
3416 // (set to 1). This equals what happens when the send codecs are used in an
3417 // offer and the receive codecs are used in the following answer.
3418 const std::vector<AudioCodec> sendrecv_codecs =
3419 MAKE_VECTOR(kAudioCodecsAnswer);
3420 const std::vector<AudioCodec> no_codecs;
3421
3422 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
3423 << "Please don't change shared test data!";
3424 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
3425 << "Please don't change shared test data!";
3426 // Alter iLBC send codec to have zero channels, to test that that is handled
3427 // properly.
3428 send_codecs[1].channels = 0;
3429
3430 // Alther iLBC receive codec to be lowercase, to test that case conversions
3431 // are handled properly.
3432 recv_codecs[2].name = "ilbc";
3433
3434 // Test proper merge
3435 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003436 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
3437 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
3438 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003439
3440 // Test empty send codecs list
3441 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003442 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
3443 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
3444 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003445
3446 // Test empty recv codecs list
3447 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003448 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
3449 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
3450 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003451
3452 // Test all empty codec lists
3453 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003454 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
3455 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
3456 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003457}
3458
3459namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07003460// Compare the two vectors of codecs ignoring the payload type.
3461template <class Codec>
3462bool CodecsMatch(const std::vector<Codec>& codecs1,
3463 const std::vector<Codec>& codecs2) {
3464 if (codecs1.size() != codecs2.size()) {
3465 return false;
3466 }
3467
3468 for (size_t i = 0; i < codecs1.size(); ++i) {
3469 if (!codecs1[i].Matches(codecs2[i])) {
3470 return false;
3471 }
3472 }
3473 return true;
3474}
3475
3476void TestAudioCodecsOffer(MediaContentDirection direction) {
ossu075af922016-06-14 03:29:38 -07003477 TransportDescriptionFactory tdf;
3478 MediaSessionDescriptionFactory sf(&tdf);
3479 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
3480 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
3481 const std::vector<AudioCodec> sendrecv_codecs =
3482 MAKE_VECTOR(kAudioCodecsAnswer);
3483 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07003484
3485 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003486 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", direction, kActive, &opts);
3487
3488 if (RtpTransceiverDirection::FromMediaContentDirection(direction).send) {
3489 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
3490 kMediaStream1, 1, &opts);
3491 }
ossu075af922016-06-14 03:29:38 -07003492
3493 std::unique_ptr<SessionDescription> offer(sf.CreateOffer(opts, NULL));
3494 ASSERT_TRUE(offer.get() != NULL);
3495 const ContentInfo* ac = offer->GetContentByName("audio");
3496
3497 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07003498 // that the codecs put in are right. This happens when we neither want to
3499 // send nor receive audio. The checks are still in place if at some point
3500 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07003501 if (ac) {
3502 AudioContentDescription* acd =
3503 static_cast<AudioContentDescription*>(ac->description);
zhihuang1c378ed2017-08-17 14:10:50 -07003504 // sendrecv and inactive should both present lists as if the channel was
3505 // to be used for sending and receiving. Inactive essentially means it
3506 // might eventually be used anything, but we don't know more at this
3507 // moment.
ossu075af922016-06-14 03:29:38 -07003508 if (acd->direction() == cricket::MD_SENDONLY) {
zhihuang1c378ed2017-08-17 14:10:50 -07003509 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07003510 } else if (acd->direction() == cricket::MD_RECVONLY) {
zhihuang1c378ed2017-08-17 14:10:50 -07003511 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07003512 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07003513 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07003514 }
3515 }
3516}
3517
3518static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07003519 AudioCodec(0, "codec0", 16000, -1, 1),
3520 AudioCodec(1, "codec1", 8000, 13300, 1),
3521 AudioCodec(2, "codec2", 8000, 64000, 1),
3522 AudioCodec(3, "codec3", 8000, 64000, 1),
3523 AudioCodec(4, "codec4", 8000, 0, 2),
3524 AudioCodec(5, "codec5", 32000, 0, 1),
3525 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07003526
zhihuang1c378ed2017-08-17 14:10:50 -07003527/* The codecs groups below are chosen as per the matrix below. The objective
3528 * is to have different sets of codecs in the inputs, to get unique sets of
3529 * codecs after negotiation, depending on offer and answer communication
3530 * directions. One-way directions in the offer should either result in the
3531 * opposite direction in the answer, or an inactive answer. Regardless, the
3532 * choice of codecs should be as if the answer contained the opposite
3533 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07003534 *
3535 * | Offer | Answer | Result
3536 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
3537 * 0 | x - - | - x - | x - - - -
3538 * 1 | x x x | - x - | x - - x -
3539 * 2 | - x - | x - - | - x - - -
3540 * 3 | x x x | x - - | - x x - -
3541 * 4 | - x - | x x x | - x - - -
3542 * 5 | x - - | x x x | x - - - -
3543 * 6 | x x x | x x x | x x x x x
3544 */
3545// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07003546static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
3547static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07003548// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
3549// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07003550static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
3551static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07003552// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07003553static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
3554static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
3555static const int kResultSendrecv_SendCodecs[] = {3, 6};
3556static const int kResultSendrecv_RecvCodecs[] = {1, 6};
3557static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07003558
3559template <typename T, int IDXS>
3560std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
3561 std::vector<T> out;
3562 out.reserve(IDXS);
3563 for (int idx : indices)
3564 out.push_back(array[idx]);
3565
3566 return out;
3567}
3568
3569void TestAudioCodecsAnswer(MediaContentDirection offer_direction,
3570 MediaContentDirection answer_direction,
3571 bool add_legacy_stream) {
3572 TransportDescriptionFactory offer_tdf;
3573 TransportDescriptionFactory answer_tdf;
3574 MediaSessionDescriptionFactory offer_factory(&offer_tdf);
3575 MediaSessionDescriptionFactory answer_factory(&answer_tdf);
3576 offer_factory.set_audio_codecs(
3577 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
3578 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
3579 answer_factory.set_audio_codecs(
3580 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
3581 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
3582
ossu075af922016-06-14 03:29:38 -07003583 MediaSessionOptions offer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003584 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", offer_direction, kActive,
3585 &offer_opts);
3586
3587 if (RtpTransceiverDirection::FromMediaContentDirection(offer_direction)
3588 .send) {
3589 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
3590 kMediaStream1, 1, &offer_opts);
ossu075af922016-06-14 03:29:38 -07003591 }
3592
3593 std::unique_ptr<SessionDescription> offer(
3594 offer_factory.CreateOffer(offer_opts, NULL));
3595 ASSERT_TRUE(offer.get() != NULL);
3596
3597 MediaSessionOptions answer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003598 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", answer_direction, kActive,
3599 &answer_opts);
3600
3601 if (RtpTransceiverDirection::FromMediaContentDirection(answer_direction)
3602 .send) {
3603 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
3604 kMediaStream1, 1, &answer_opts);
ossu075af922016-06-14 03:29:38 -07003605 }
3606 std::unique_ptr<SessionDescription> answer(
3607 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL));
3608 const ContentInfo* ac = answer->GetContentByName("audio");
3609
zhihuang1c378ed2017-08-17 14:10:50 -07003610 // If the factory didn't add any audio content to the answer, we cannot
3611 // check that the codecs put in are right. This happens when we neither want
3612 // to send nor receive audio. The checks are still in place if at some point
3613 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07003614 if (ac) {
3615 const AudioContentDescription* acd =
3616 static_cast<const AudioContentDescription*>(ac->description);
3617 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
3618
ossu075af922016-06-14 03:29:38 -07003619 std::vector<AudioCodec> target_codecs;
3620 // For offers with sendrecv or inactive, we should never reply with more
3621 // codecs than offered, with these codec sets.
3622 switch (offer_direction) {
3623 case cricket::MD_INACTIVE:
3624 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
3625 kResultSendrecv_SendrecvCodecs);
3626 break;
3627 case cricket::MD_SENDONLY:
zhihuang1c378ed2017-08-17 14:10:50 -07003628 target_codecs =
3629 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07003630 break;
3631 case cricket::MD_RECVONLY:
zhihuang1c378ed2017-08-17 14:10:50 -07003632 target_codecs =
3633 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07003634 break;
3635 case cricket::MD_SENDRECV:
3636 if (acd->direction() == cricket::MD_SENDONLY) {
zhihuang1c378ed2017-08-17 14:10:50 -07003637 target_codecs =
3638 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07003639 } else if (acd->direction() == cricket::MD_RECVONLY) {
zhihuang1c378ed2017-08-17 14:10:50 -07003640 target_codecs =
3641 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07003642 } else {
3643 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
3644 kResultSendrecv_SendrecvCodecs);
3645 }
3646 break;
3647 }
3648
zhihuang1c378ed2017-08-17 14:10:50 -07003649 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
ossu075af922016-06-14 03:29:38 -07003650 std::stringstream os;
3651 bool first = true;
3652 os << "{";
3653 for (const auto& c : codecs) {
3654 os << (first ? " " : ", ") << c.id;
3655 first = false;
3656 }
3657 os << " }";
3658 return os.str();
3659 };
3660
3661 EXPECT_TRUE(acd->codecs() == target_codecs)
3662 << "Expected: " << format_codecs(target_codecs)
3663 << ", got: " << format_codecs(acd->codecs())
3664 << "; Offered: " << MediaContentDirectionToString(offer_direction)
3665 << ", answerer wants: "
3666 << MediaContentDirectionToString(answer_direction)
3667 << "; got: " << MediaContentDirectionToString(acd->direction());
3668 } else {
3669 EXPECT_EQ(offer_direction, cricket::MD_INACTIVE)
zhihuang1c378ed2017-08-17 14:10:50 -07003670 << "Only inactive offers are allowed to not generate any audio "
3671 "content";
ossu075af922016-06-14 03:29:38 -07003672 }
3673}
brandtr03d5fb12016-11-22 03:37:59 -08003674
3675} // namespace
ossu075af922016-06-14 03:29:38 -07003676
3677class AudioCodecsOfferTest
zhihuang1c378ed2017-08-17 14:10:50 -07003678 : public ::testing::TestWithParam<MediaContentDirection> {};
ossu075af922016-06-14 03:29:38 -07003679
3680TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003681 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07003682}
3683
3684INSTANTIATE_TEST_CASE_P(MediaSessionDescriptionFactoryTest,
3685 AudioCodecsOfferTest,
zhihuang1c378ed2017-08-17 14:10:50 -07003686 ::testing::Values(cricket::MD_SENDONLY,
3687 cricket::MD_RECVONLY,
3688 cricket::MD_SENDRECV,
3689 cricket::MD_INACTIVE));
ossu075af922016-06-14 03:29:38 -07003690
3691class AudioCodecsAnswerTest
ehmaldonadoabcef5d2017-02-08 04:07:11 -08003692 : public ::testing::TestWithParam<::testing::tuple<MediaContentDirection,
3693 MediaContentDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07003694 bool>> {};
ossu075af922016-06-14 03:29:38 -07003695
3696TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08003697 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
3698 ::testing::get<1>(GetParam()),
3699 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07003700}
3701
zhihuang1c378ed2017-08-17 14:10:50 -07003702INSTANTIATE_TEST_CASE_P(
3703 MediaSessionDescriptionFactoryTest,
3704 AudioCodecsAnswerTest,
3705 ::testing::Combine(::testing::Values(cricket::MD_SENDONLY,
3706 cricket::MD_RECVONLY,
3707 cricket::MD_SENDRECV,
3708 cricket::MD_INACTIVE),
3709 ::testing::Values(cricket::MD_SENDONLY,
3710 cricket::MD_RECVONLY,
3711 cricket::MD_SENDRECV,
3712 cricket::MD_INACTIVE),
3713 ::testing::Bool()));