blob: 867640cf208110747a8d95987842515462bbcdbe [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
kjellander65c7f672016-02-12 00:05:01 -08002 * Copyright 2004 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
kjellander65c7f672016-02-12 00:05:01 -08004 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00009 */
10
kwiberg31022942016-03-11 14:18:21 -080011#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000012#include <string>
13#include <vector>
14
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "media/base/codec.h"
16#include "media/base/testutils.h"
17#include "p2p/base/p2pconstants.h"
18#include "p2p/base/transportdescription.h"
19#include "p2p/base/transportinfo.h"
20#include "pc/mediasession.h"
21#include "pc/srtpfilter.h"
22#include "rtc_base/checks.h"
23#include "rtc_base/fakesslidentity.h"
24#include "rtc_base/gunit.h"
25#include "rtc_base/messagedigest.h"
26#include "rtc_base/ssladapter.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000027
henrike@webrtc.org28e20752013-07-10 00:45:36 +000028#define ASSERT_CRYPTO(cd, s, cs) \
henrike@webrtc.org28e20752013-07-10 00:45:36 +000029 ASSERT_EQ(s, cd->cryptos().size()); \
30 ASSERT_EQ(std::string(cs), cd->cryptos()[0].cipher_suite)
henrike@webrtc.org28e20752013-07-10 00:45:36 +000031
32typedef std::vector<cricket::Candidate> Candidates;
33
34using cricket::MediaContentDescription;
35using cricket::MediaSessionDescriptionFactory;
ossu075af922016-06-14 03:29:38 -070036using cricket::MediaContentDirection;
zhihuang1c378ed2017-08-17 14:10:50 -070037using cricket::MediaDescriptionOptions;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000038using cricket::MediaSessionOptions;
39using cricket::MediaType;
40using cricket::SessionDescription;
41using cricket::SsrcGroup;
42using cricket::StreamParams;
43using cricket::StreamParamsVec;
44using cricket::TransportDescription;
45using cricket::TransportDescriptionFactory;
46using cricket::TransportInfo;
47using cricket::ContentInfo;
48using cricket::CryptoParamsVec;
49using cricket::AudioContentDescription;
50using cricket::VideoContentDescription;
51using cricket::DataContentDescription;
deadbeef44f08192015-12-15 16:20:09 -080052using cricket::GetFirstAudioContent;
53using cricket::GetFirstVideoContent;
54using cricket::GetFirstDataContent;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000055using cricket::GetFirstAudioContentDescription;
56using cricket::GetFirstVideoContentDescription;
57using cricket::GetFirstDataContentDescription;
58using cricket::kAutoBandwidth;
59using cricket::AudioCodec;
60using cricket::VideoCodec;
61using cricket::DataCodec;
62using cricket::NS_JINGLE_RTP;
63using cricket::MEDIA_TYPE_AUDIO;
64using cricket::MEDIA_TYPE_VIDEO;
65using cricket::MEDIA_TYPE_DATA;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000066using cricket::SEC_DISABLED;
67using cricket::SEC_ENABLED;
68using cricket::SEC_REQUIRED;
zhihuang1c378ed2017-08-17 14:10:50 -070069using cricket::RtpTransceiverDirection;
Guo-wei Shieh456696a2015-09-30 21:48:54 -070070using rtc::CS_AES_CM_128_HMAC_SHA1_32;
71using rtc::CS_AES_CM_128_HMAC_SHA1_80;
jbauchcb560652016-08-04 05:20:32 -070072using rtc::CS_AEAD_AES_128_GCM;
73using rtc::CS_AEAD_AES_256_GCM;
isheriff6f8d6862016-05-26 11:24:55 -070074using webrtc::RtpExtension;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000075
76static const AudioCodec kAudioCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070077 AudioCodec(103, "ISAC", 16000, -1, 1),
78 AudioCodec(102, "iLBC", 8000, 13300, 1),
79 AudioCodec(0, "PCMU", 8000, 64000, 1),
80 AudioCodec(8, "PCMA", 8000, 64000, 1),
81 AudioCodec(117, "red", 8000, 0, 1),
82 AudioCodec(107, "CN", 48000, 0, 1)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +000083
84static const AudioCodec kAudioCodecs2[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070085 AudioCodec(126, "speex", 16000, 22000, 1),
86 AudioCodec(0, "PCMU", 8000, 64000, 1),
87 AudioCodec(127, "iLBC", 8000, 13300, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +000088};
89
90static const AudioCodec kAudioCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070091 AudioCodec(102, "iLBC", 8000, 13300, 1),
92 AudioCodec(0, "PCMU", 8000, 64000, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +000093};
94
perkj26752742016-10-24 01:21:16 -070095static const VideoCodec kVideoCodecs1[] = {VideoCodec(96, "H264-SVC"),
96 VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +000097
zhihuang1c378ed2017-08-17 14:10:50 -070098static const VideoCodec kVideoCodecs1Reverse[] = {VideoCodec(97, "H264"),
99 VideoCodec(96, "H264-SVC")};
100
perkj26752742016-10-24 01:21:16 -0700101static const VideoCodec kVideoCodecs2[] = {VideoCodec(126, "H264"),
102 VideoCodec(127, "H263")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000103
perkj26752742016-10-24 01:21:16 -0700104static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000105
deadbeef67cf2c12016-04-13 10:07:16 -0700106static const DataCodec kDataCodecs1[] = {DataCodec(98, "binary-data"),
107 DataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000108
deadbeef67cf2c12016-04-13 10:07:16 -0700109static const DataCodec kDataCodecs2[] = {DataCodec(126, "binary-data"),
110 DataCodec(127, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000111
deadbeef67cf2c12016-04-13 10:07:16 -0700112static const DataCodec kDataCodecsAnswer[] = {DataCodec(98, "binary-data"),
113 DataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000114
isheriff6f8d6862016-05-26 11:24:55 -0700115static const RtpExtension kAudioRtpExtension1[] = {
116 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
117 RtpExtension("http://google.com/testing/audio_something", 10),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000118};
119
jbauch5869f502017-06-29 12:31:36 -0700120static const RtpExtension kAudioRtpExtensionEncrypted1[] = {
121 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
122 RtpExtension("http://google.com/testing/audio_something", 10),
123 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
124};
125
isheriff6f8d6862016-05-26 11:24:55 -0700126static const RtpExtension kAudioRtpExtension2[] = {
127 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
128 RtpExtension("http://google.com/testing/audio_something_else", 8),
129 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000130};
131
isheriff6f8d6862016-05-26 11:24:55 -0700132static const RtpExtension kAudioRtpExtension3[] = {
133 RtpExtension("http://google.com/testing/audio_something", 2),
134 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
deadbeefa5b273a2015-08-20 17:30:13 -0700135};
136
jbauch5869f502017-06-29 12:31:36 -0700137static const RtpExtension kAudioRtpExtension3ForEncryption[] = {
138 RtpExtension("http://google.com/testing/audio_something", 2),
139 // Use RTP extension that supports encryption.
140 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
141};
142
143static const RtpExtension kAudioRtpExtension3ForEncryptionOffer[] = {
144 RtpExtension("http://google.com/testing/audio_something", 2),
145 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
146 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14, true),
147};
148
isheriff6f8d6862016-05-26 11:24:55 -0700149static const RtpExtension kAudioRtpExtensionAnswer[] = {
150 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000151};
152
jbauch5869f502017-06-29 12:31:36 -0700153static const RtpExtension kAudioRtpExtensionEncryptedAnswer[] = {
154 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
155};
156
isheriff6f8d6862016-05-26 11:24:55 -0700157static const RtpExtension kVideoRtpExtension1[] = {
158 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
159 RtpExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000160};
161
jbauch5869f502017-06-29 12:31:36 -0700162static const RtpExtension kVideoRtpExtensionEncrypted1[] = {
163 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
164 RtpExtension("http://google.com/testing/video_something", 13),
165 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
166};
167
isheriff6f8d6862016-05-26 11:24:55 -0700168static const RtpExtension kVideoRtpExtension2[] = {
169 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
170 RtpExtension("http://google.com/testing/video_something_else", 14),
171 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000172};
173
isheriff6f8d6862016-05-26 11:24:55 -0700174static const RtpExtension kVideoRtpExtension3[] = {
175 RtpExtension("http://google.com/testing/video_something", 4),
176 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
deadbeefa5b273a2015-08-20 17:30:13 -0700177};
178
jbauch5869f502017-06-29 12:31:36 -0700179static const RtpExtension kVideoRtpExtension3ForEncryption[] = {
180 RtpExtension("http://google.com/testing/video_something", 4),
181 // Use RTP extension that supports encryption.
182 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 5),
183};
184
isheriff6f8d6862016-05-26 11:24:55 -0700185static const RtpExtension kVideoRtpExtensionAnswer[] = {
186 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000187};
188
jbauch5869f502017-06-29 12:31:36 -0700189static const RtpExtension kVideoRtpExtensionEncryptedAnswer[] = {
190 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
191};
192
Peter Boström0c4e06b2015-10-07 12:23:21 +0200193static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
194static const uint32_t kSimSsrc[] = {10, 20, 30};
195static const uint32_t kFec1Ssrc[] = {10, 11};
196static const uint32_t kFec2Ssrc[] = {20, 21};
197static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000198
199static const char kMediaStream1[] = "stream_1";
200static const char kMediaStream2[] = "stream_2";
201static const char kVideoTrack1[] = "video_1";
202static const char kVideoTrack2[] = "video_2";
203static const char kAudioTrack1[] = "audio_1";
204static const char kAudioTrack2[] = "audio_2";
205static const char kAudioTrack3[] = "audio_3";
206static const char kDataTrack1[] = "data_1";
207static const char kDataTrack2[] = "data_2";
208static const char kDataTrack3[] = "data_3";
209
zhihuangcf5b37c2016-05-05 11:44:35 -0700210static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
211 "RTP/SAVPF"};
212static const char* kMediaProtocolsDtls[] = {
213 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
214 "UDP/TLS/RTP/SAVP"};
215
zhihuang1c378ed2017-08-17 14:10:50 -0700216// These constants are used to make the code using "AddMediaSection" more
217// readable.
218static constexpr bool kStopped = true;
219static constexpr bool kActive = false;
220
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000221static bool IsMediaContentOfType(const ContentInfo* content,
222 MediaType media_type) {
223 const MediaContentDescription* mdesc =
224 static_cast<const MediaContentDescription*>(content->description);
225 return mdesc && mdesc->type() == media_type;
226}
227
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000228static cricket::MediaContentDirection
229GetMediaDirection(const ContentInfo* content) {
230 cricket::MediaContentDescription* desc =
231 reinterpret_cast<cricket::MediaContentDescription*>(content->description);
232 return desc->direction();
233}
234
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000235static void AddRtxCodec(const VideoCodec& rtx_codec,
236 std::vector<VideoCodec>* codecs) {
magjedb05fa242016-11-11 04:00:16 -0800237 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000238 codecs->push_back(rtx_codec);
239}
240
241template <class T>
242static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
243 std::vector<std::string> codec_names;
244 for (const auto& codec : codecs) {
245 codec_names.push_back(codec.name);
246 }
247 return codec_names;
248}
249
zhihuang1c378ed2017-08-17 14:10:50 -0700250// This is used for test only. MIDs are not the identification of the
251// MediaDescriptionOptions since some end points may not support MID and the SDP
252// may not contain 'mid'.
253std::vector<MediaDescriptionOptions>::iterator FindFirstMediaDescriptionByMid(
254 const std::string& mid,
255 MediaSessionOptions* opts) {
256 return std::find_if(
257 opts->media_description_options.begin(),
258 opts->media_description_options.end(),
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
Steve Anton8ffb9c32017-08-31 15:45:38 -0700287static void AttachSenderToMediaSection(
288 const std::string& mid,
289 MediaType type,
290 const std::string& track_id,
291 const std::vector<std::string>& stream_ids,
292 int num_sim_layer,
293 MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -0700294 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
295 switch (type) {
296 case MEDIA_TYPE_AUDIO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700297 it->AddAudioSender(track_id, stream_ids);
zhihuang1c378ed2017-08-17 14:10:50 -0700298 break;
299 case MEDIA_TYPE_VIDEO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700300 it->AddVideoSender(track_id, stream_ids, num_sim_layer);
zhihuang1c378ed2017-08-17 14:10:50 -0700301 break;
302 case MEDIA_TYPE_DATA:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700303 RTC_CHECK(stream_ids.size() == 1U);
304 it->AddRtpDataChannel(track_id, stream_ids[0]);
zhihuang1c378ed2017-08-17 14:10:50 -0700305 break;
306 default:
307 RTC_NOTREACHED();
308 }
309}
310
311static void DetachSenderFromMediaSection(const std::string& mid,
312 const std::string& track_id,
313 MediaSessionOptions* session_options) {
314 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
315 auto sender_it = it->sender_options.begin();
316 for (; sender_it != it->sender_options.end(); ++sender_it) {
317 if (sender_it->track_id == track_id) {
318 it->sender_options.erase(sender_it);
319 return;
320 }
321 }
322 RTC_NOTREACHED();
323}
324
325// Helper function used to create a default MediaSessionOptions for Plan B SDP.
326// (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
327static MediaSessionOptions CreatePlanBMediaSessionOptions() {
328 MediaSessionOptions session_options;
329 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
330 &session_options);
331 return session_options;
332}
333
334// TODO(zhihuang): Most of these tests were written while MediaSessionOptions
335// was designed for Plan B SDP, where only one audio "m=" section and one video
336// "m=" section could be generated, and ordering couldn't be controlled. Many of
337// these tests may be obsolete as a result, and should be refactored or removed.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000338class MediaSessionDescriptionFactoryTest : public testing::Test {
339 public:
zhihuang1c378ed2017-08-17 14:10:50 -0700340 MediaSessionDescriptionFactoryTest() : f1_(&tdf1_), f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -0700341 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
342 MAKE_VECTOR(kAudioCodecs1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000343 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
344 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700345 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
346 MAKE_VECTOR(kAudioCodecs2));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000347 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
348 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200349 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700350 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200351 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700352 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000353 }
354
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000355 // Create a video StreamParamsVec object with:
356 // - one video stream with 3 simulcast streams and FEC,
357 StreamParamsVec CreateComplexVideoStreamParamsVec() {
358 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
359 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
360 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
361 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
362
363 std::vector<SsrcGroup> ssrc_groups;
364 ssrc_groups.push_back(sim_group);
365 ssrc_groups.push_back(fec_group1);
366 ssrc_groups.push_back(fec_group2);
367 ssrc_groups.push_back(fec_group3);
368
369 StreamParams simulcast_params;
370 simulcast_params.id = kVideoTrack1;
371 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
372 simulcast_params.ssrc_groups = ssrc_groups;
373 simulcast_params.cname = "Video_SIM_FEC";
374 simulcast_params.sync_label = kMediaStream1;
375
376 StreamParamsVec video_streams;
377 video_streams.push_back(simulcast_params);
378
379 return video_streams;
380 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000381
382 bool CompareCryptoParams(const CryptoParamsVec& c1,
383 const CryptoParamsVec& c2) {
384 if (c1.size() != c2.size())
385 return false;
386 for (size_t i = 0; i < c1.size(); ++i)
387 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
388 c1[i].key_params != c2[i].key_params ||
389 c1[i].session_params != c2[i].session_params)
390 return false;
391 return true;
392 }
393
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700394 // Returns true if the transport info contains "renomination" as an
395 // ICE option.
396 bool GetIceRenomination(const TransportInfo* transport_info) {
397 const std::vector<std::string>& ice_options =
398 transport_info->description.transport_options;
deadbeef30952b42017-04-21 02:41:29 -0700399 auto iter =
400 std::find(ice_options.begin(), ice_options.end(), "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700401 return iter != ice_options.end();
402 }
403
zhihuang1c378ed2017-08-17 14:10:50 -0700404 void TestTransportInfo(bool offer,
405 MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000406 bool has_current_desc) {
407 const std::string current_audio_ufrag = "current_audio_ufrag";
408 const std::string current_audio_pwd = "current_audio_pwd";
409 const std::string current_video_ufrag = "current_video_ufrag";
410 const std::string current_video_pwd = "current_video_pwd";
411 const std::string current_data_ufrag = "current_data_ufrag";
412 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800413 std::unique_ptr<SessionDescription> current_desc;
414 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000415 if (has_current_desc) {
416 current_desc.reset(new SessionDescription());
417 EXPECT_TRUE(current_desc->AddTransportInfo(
418 TransportInfo("audio",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700419 TransportDescription(current_audio_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000420 current_audio_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000421 EXPECT_TRUE(current_desc->AddTransportInfo(
422 TransportInfo("video",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700423 TransportDescription(current_video_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000424 current_video_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000425 EXPECT_TRUE(current_desc->AddTransportInfo(
426 TransportInfo("data",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700427 TransportDescription(current_data_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000428 current_data_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000429 }
430 if (offer) {
431 desc.reset(f1_.CreateOffer(options, current_desc.get()));
432 } else {
kwiberg31022942016-03-11 14:18:21 -0800433 std::unique_ptr<SessionDescription> offer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000434 offer.reset(f1_.CreateOffer(options, NULL));
435 desc.reset(f1_.CreateAnswer(offer.get(), options, current_desc.get()));
436 }
437 ASSERT_TRUE(desc.get() != NULL);
438 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000439 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000440 EXPECT_TRUE(ti_audio != NULL);
441 if (has_current_desc) {
442 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
443 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
444 } else {
445 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
446 ti_audio->description.ice_ufrag.size());
447 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
448 ti_audio->description.ice_pwd.size());
449 }
zhihuang1c378ed2017-08-17 14:10:50 -0700450 auto media_desc_options_it =
451 FindFirstMediaDescriptionByMid("audio", &options);
452 EXPECT_EQ(
453 media_desc_options_it->transport_options.enable_ice_renomination,
454 GetIceRenomination(ti_audio));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000455
456 } else {
457 EXPECT_TRUE(ti_audio == NULL);
458 }
459 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000460 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000461 EXPECT_TRUE(ti_video != NULL);
462 if (options.bundle_enabled) {
463 EXPECT_EQ(ti_audio->description.ice_ufrag,
464 ti_video->description.ice_ufrag);
465 EXPECT_EQ(ti_audio->description.ice_pwd,
466 ti_video->description.ice_pwd);
467 } else {
468 if (has_current_desc) {
469 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
470 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
471 } else {
472 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
473 ti_video->description.ice_ufrag.size());
474 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
475 ti_video->description.ice_pwd.size());
476 }
477 }
zhihuang1c378ed2017-08-17 14:10:50 -0700478 auto media_desc_options_it =
479 FindFirstMediaDescriptionByMid("video", &options);
480 EXPECT_EQ(
481 media_desc_options_it->transport_options.enable_ice_renomination,
482 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000483 } else {
484 EXPECT_TRUE(ti_video == NULL);
485 }
486 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
487 if (options.has_data()) {
488 EXPECT_TRUE(ti_data != NULL);
489 if (options.bundle_enabled) {
490 EXPECT_EQ(ti_audio->description.ice_ufrag,
491 ti_data->description.ice_ufrag);
492 EXPECT_EQ(ti_audio->description.ice_pwd,
493 ti_data->description.ice_pwd);
494 } else {
495 if (has_current_desc) {
496 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
497 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
498 } else {
499 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
500 ti_data->description.ice_ufrag.size());
501 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
502 ti_data->description.ice_pwd.size());
503 }
504 }
zhihuang1c378ed2017-08-17 14:10:50 -0700505 auto media_desc_options_it =
506 FindFirstMediaDescriptionByMid("data", &options);
507 EXPECT_EQ(
508 media_desc_options_it->transport_options.enable_ice_renomination,
509 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700510
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000511 } else {
512 EXPECT_TRUE(ti_video == NULL);
513 }
514 }
515
516 void TestCryptoWithBundle(bool offer) {
517 f1_.set_secure(SEC_ENABLED);
518 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -0700519 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
520 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
kwiberg31022942016-03-11 14:18:21 -0800521 std::unique_ptr<SessionDescription> ref_desc;
522 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000523 if (offer) {
524 options.bundle_enabled = false;
525 ref_desc.reset(f1_.CreateOffer(options, NULL));
526 options.bundle_enabled = true;
527 desc.reset(f1_.CreateOffer(options, ref_desc.get()));
528 } else {
529 options.bundle_enabled = true;
530 ref_desc.reset(f1_.CreateOffer(options, NULL));
531 desc.reset(f1_.CreateAnswer(ref_desc.get(), options, NULL));
532 }
533 ASSERT_TRUE(desc.get() != NULL);
534 const cricket::MediaContentDescription* audio_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000535 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000536 desc.get()->GetContentDescriptionByName("audio"));
537 ASSERT_TRUE(audio_media_desc != NULL);
538 const cricket::MediaContentDescription* video_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000539 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000540 desc.get()->GetContentDescriptionByName("video"));
541 ASSERT_TRUE(video_media_desc != NULL);
542 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
543 video_media_desc->cryptos()));
544 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
545 EXPECT_EQ(std::string(CS_AES_CM_128_HMAC_SHA1_80),
546 audio_media_desc->cryptos()[0].cipher_suite);
547
548 // Verify the selected crypto is one from the reference audio
549 // media content.
550 const cricket::MediaContentDescription* ref_audio_media_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000551 static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000552 ref_desc.get()->GetContentDescriptionByName("audio"));
553 bool found = false;
554 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
555 if (ref_audio_media_desc->cryptos()[i].Matches(
556 audio_media_desc->cryptos()[0])) {
557 found = true;
558 break;
559 }
560 }
561 EXPECT_TRUE(found);
562 }
563
564 // This test that the audio and video media direction is set to
565 // |expected_direction_in_answer| in an answer if the offer direction is set
zhihuang1c378ed2017-08-17 14:10:50 -0700566 // to |direction_in_offer| and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000567 void TestMediaDirectionInAnswer(
568 cricket::MediaContentDirection direction_in_offer,
569 cricket::MediaContentDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700570 MediaSessionOptions offer_opts;
571 AddAudioVideoSections(direction_in_offer, &offer_opts);
572
573 std::unique_ptr<SessionDescription> offer(
574 f1_.CreateOffer(offer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000575 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700576 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000577 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700578 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000579 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000580
zhihuang1c378ed2017-08-17 14:10:50 -0700581 MediaSessionOptions answer_opts;
582 AddAudioVideoSections(cricket::MD_SENDRECV, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -0800583 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -0700584 f2_.CreateAnswer(offer.get(), answer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000585 const AudioContentDescription* acd_answer =
586 GetFirstAudioContentDescription(answer.get());
587 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
588 const VideoContentDescription* vcd_answer =
589 GetFirstVideoContentDescription(answer.get());
590 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
591 }
592
593 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
594 const cricket::ContentDescription* description = content->description;
nissec8ee8822017-01-18 07:20:55 -0800595 RTC_CHECK(description != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000596 const cricket::AudioContentDescription* audio_content_desc =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000597 static_cast<const cricket::AudioContentDescription*>(description);
nissec8ee8822017-01-18 07:20:55 -0800598 RTC_CHECK(audio_content_desc != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000599 for (size_t i = 0; i < audio_content_desc->codecs().size(); ++i) {
600 if (audio_content_desc->codecs()[i].name == "CN")
601 return false;
602 }
603 return true;
604 }
605
jbauchcb560652016-08-04 05:20:32 -0700606 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
607 MediaSessionOptions offer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -0700608 AddAudioVideoSections(cricket::MD_RECVONLY, &offer_opts);
jbauchcb560652016-08-04 05:20:32 -0700609 offer_opts.crypto_options.enable_gcm_crypto_suites = gcm_offer;
zhihuang1c378ed2017-08-17 14:10:50 -0700610
jbauchcb560652016-08-04 05:20:32 -0700611 MediaSessionOptions answer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -0700612 AddAudioVideoSections(cricket::MD_RECVONLY, &answer_opts);
jbauchcb560652016-08-04 05:20:32 -0700613 answer_opts.crypto_options.enable_gcm_crypto_suites = gcm_answer;
zhihuang1c378ed2017-08-17 14:10:50 -0700614
jbauchcb560652016-08-04 05:20:32 -0700615 f1_.set_secure(SEC_ENABLED);
616 f2_.set_secure(SEC_ENABLED);
617 std::unique_ptr<SessionDescription> offer(
618 f1_.CreateOffer(offer_opts, NULL));
619 ASSERT_TRUE(offer.get() != NULL);
620 std::unique_ptr<SessionDescription> answer(
621 f2_.CreateAnswer(offer.get(), answer_opts, NULL));
622 const ContentInfo* ac = answer->GetContentByName("audio");
623 const ContentInfo* vc = answer->GetContentByName("video");
624 ASSERT_TRUE(ac != NULL);
625 ASSERT_TRUE(vc != NULL);
626 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
627 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
628 const AudioContentDescription* acd =
629 static_cast<const AudioContentDescription*>(ac->description);
630 const VideoContentDescription* vcd =
631 static_cast<const VideoContentDescription*>(vc->description);
632 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
633 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
634 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700635 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700636 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
637 if (gcm_offer && gcm_answer) {
638 ASSERT_CRYPTO(acd, 1U, CS_AEAD_AES_256_GCM);
639 } else {
640 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
641 }
642 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
643 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700644 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700645 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
646 if (gcm_offer && gcm_answer) {
647 ASSERT_CRYPTO(vcd, 1U, CS_AEAD_AES_256_GCM);
648 } else {
649 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
650 }
651 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
652 }
653
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000654 protected:
655 MediaSessionDescriptionFactory f1_;
656 MediaSessionDescriptionFactory f2_;
657 TransportDescriptionFactory tdf1_;
658 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000659};
660
661// Create a typical audio offer, and ensure it matches what we expect.
662TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
663 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800664 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -0700665 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000666 ASSERT_TRUE(offer.get() != NULL);
667 const ContentInfo* ac = offer->GetContentByName("audio");
668 const ContentInfo* vc = offer->GetContentByName("video");
669 ASSERT_TRUE(ac != NULL);
670 ASSERT_TRUE(vc == NULL);
671 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
672 const AudioContentDescription* acd =
673 static_cast<const AudioContentDescription*>(ac->description);
674 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700675 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700676 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000677 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
678 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
679 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
680 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
681}
682
683// Create a typical video offer, and ensure it matches what we expect.
684TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
685 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -0700686 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000687 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800688 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000689 ASSERT_TRUE(offer.get() != NULL);
690 const ContentInfo* ac = offer->GetContentByName("audio");
691 const ContentInfo* vc = offer->GetContentByName("video");
692 ASSERT_TRUE(ac != NULL);
693 ASSERT_TRUE(vc != NULL);
694 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
695 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
696 const AudioContentDescription* acd =
697 static_cast<const AudioContentDescription*>(ac->description);
698 const VideoContentDescription* vcd =
699 static_cast<const VideoContentDescription*>(vc->description);
700 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700701 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700702 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000703 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
704 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
705 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
706 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
707 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
708 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700709 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000710 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
711 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
712 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
713 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
714}
715
716// Test creating an offer with bundle where the Codecs have the same dynamic
717// RTP playlod type. The test verifies that the offer don't contain the
718// duplicate RTP payload types.
719TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
720 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700721 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000722 const DataCodec& offered_data_codec = f2_.data_codecs()[0];
723 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
724 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
725
726 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -0700727 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
728 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000729 opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800730 std::unique_ptr<SessionDescription> offer(f2_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000731 const VideoContentDescription* vcd =
732 GetFirstVideoContentDescription(offer.get());
733 const AudioContentDescription* acd =
734 GetFirstAudioContentDescription(offer.get());
735 const DataContentDescription* dcd =
736 GetFirstDataContentDescription(offer.get());
737 ASSERT_TRUE(NULL != vcd);
738 ASSERT_TRUE(NULL != acd);
739 ASSERT_TRUE(NULL != dcd);
740 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
741 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
742 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
743 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
744 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
745 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
746}
747
zhihuang1c378ed2017-08-17 14:10:50 -0700748// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000749// after an audio only session has been negotiated.
750TEST_F(MediaSessionDescriptionFactoryTest,
751 TestCreateUpdatedVideoOfferWithBundle) {
752 f1_.set_secure(SEC_ENABLED);
753 f2_.set_secure(SEC_ENABLED);
754 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -0700755 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
756 &opts);
757 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_INACTIVE, kStopped,
758 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000759 opts.data_channel_type = cricket::DCT_NONE;
760 opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800761 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
762 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000763 f2_.CreateAnswer(offer.get(), opts, NULL));
764
765 MediaSessionOptions updated_opts;
zhihuang1c378ed2017-08-17 14:10:50 -0700766 AddAudioVideoSections(cricket::MD_RECVONLY, &updated_opts);
767 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000768 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800769 std::unique_ptr<SessionDescription> updated_offer(
770 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000771
772 const AudioContentDescription* acd =
773 GetFirstAudioContentDescription(updated_offer.get());
774 const VideoContentDescription* vcd =
775 GetFirstVideoContentDescription(updated_offer.get());
776 const DataContentDescription* dcd =
777 GetFirstDataContentDescription(updated_offer.get());
778 EXPECT_TRUE(NULL != vcd);
779 EXPECT_TRUE(NULL != acd);
780 EXPECT_TRUE(NULL != dcd);
781
782 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
783 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
784 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
785 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
786 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
787 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
788}
deadbeef44f08192015-12-15 16:20:09 -0800789
wu@webrtc.org78187522013-10-07 23:32:02 +0000790// Create a RTP data offer, and ensure it matches what we expect.
791TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000792 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -0700793 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
794 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000795 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800796 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000797 ASSERT_TRUE(offer.get() != NULL);
798 const ContentInfo* ac = offer->GetContentByName("audio");
799 const ContentInfo* dc = offer->GetContentByName("data");
800 ASSERT_TRUE(ac != NULL);
801 ASSERT_TRUE(dc != NULL);
802 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
803 EXPECT_EQ(std::string(NS_JINGLE_RTP), dc->type);
804 const AudioContentDescription* acd =
805 static_cast<const AudioContentDescription*>(ac->description);
806 const DataContentDescription* dcd =
807 static_cast<const DataContentDescription*>(dc->description);
808 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700809 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700810 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000811 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
812 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
813 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
814 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
815 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
816 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700817 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000818 EXPECT_EQ(cricket::kDataMaxBandwidth,
819 dcd->bandwidth()); // default bandwidth (auto)
820 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
821 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
822 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
823}
824
wu@webrtc.org78187522013-10-07 23:32:02 +0000825// Create an SCTP data offer with bundle without error.
826TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
827 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000828 opts.bundle_enabled = true;
zhihuang1c378ed2017-08-17 14:10:50 -0700829 AddDataSection(cricket::DCT_SCTP, cricket::MD_SENDRECV, &opts);
wu@webrtc.org78187522013-10-07 23:32:02 +0000830 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800831 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
wu@webrtc.org78187522013-10-07 23:32:02 +0000832 EXPECT_TRUE(offer.get() != NULL);
833 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
834}
835
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000836// Test creating an sctp data channel from an already generated offer.
837TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
838 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000839 opts.bundle_enabled = true;
zhihuang1c378ed2017-08-17 14:10:50 -0700840 AddDataSection(cricket::DCT_SCTP, cricket::MD_SENDRECV, &opts);
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000841 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800842 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000843 ASSERT_TRUE(offer1.get() != NULL);
844 const ContentInfo* data = offer1->GetContentByName("data");
845 ASSERT_TRUE(data != NULL);
846 const MediaContentDescription* mdesc =
847 static_cast<const MediaContentDescription*>(data->description);
848 ASSERT_EQ(cricket::kMediaProtocolSctp, mdesc->protocol());
849
850 // Now set data_channel_type to 'none' (default) and make sure that the
851 // datachannel type that gets generated from the previous offer, is of the
852 // same type.
853 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800854 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000855 f1_.CreateOffer(opts, offer1.get()));
856 data = offer2->GetContentByName("data");
857 ASSERT_TRUE(data != NULL);
858 mdesc = static_cast<const MediaContentDescription*>(data->description);
859 EXPECT_EQ(cricket::kMediaProtocolSctp, mdesc->protocol());
860}
861
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000862// Create an audio, video offer without legacy StreamParams.
863TEST_F(MediaSessionDescriptionFactoryTest,
864 TestCreateOfferWithoutLegacyStreams) {
865 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -0700866 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
kwiberg31022942016-03-11 14:18:21 -0800867 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000868 ASSERT_TRUE(offer.get() != NULL);
869 const ContentInfo* ac = offer->GetContentByName("audio");
870 const ContentInfo* vc = offer->GetContentByName("video");
871 ASSERT_TRUE(ac != NULL);
872 ASSERT_TRUE(vc != NULL);
873 const AudioContentDescription* acd =
874 static_cast<const AudioContentDescription*>(ac->description);
875 const VideoContentDescription* vcd =
876 static_cast<const VideoContentDescription*>(vc->description);
877
878 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
879 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
880}
881
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000882// Creates an audio+video sendonly offer.
883TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700884 MediaSessionOptions opts;
885 AddAudioVideoSections(cricket::MD_SENDONLY, &opts);
886 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700887 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700888 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700889 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000890
zhihuang1c378ed2017-08-17 14:10:50 -0700891 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000892 ASSERT_TRUE(offer.get() != NULL);
893 EXPECT_EQ(2u, offer->contents().size());
894 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
895 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
896
897 EXPECT_EQ(cricket::MD_SENDONLY, GetMediaDirection(&offer->contents()[0]));
898 EXPECT_EQ(cricket::MD_SENDONLY, GetMediaDirection(&offer->contents()[1]));
899}
900
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000901// Verifies that the order of the media contents in the current
902// SessionDescription is preserved in the new SessionDescription.
903TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
904 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -0700905 AddDataSection(cricket::DCT_SCTP, cricket::MD_SENDRECV, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000906
kwiberg31022942016-03-11 14:18:21 -0800907 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000908 ASSERT_TRUE(offer1.get() != NULL);
909 EXPECT_EQ(1u, offer1->contents().size());
910 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
911
zhihuang1c378ed2017-08-17 14:10:50 -0700912 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
913 &opts);
kwiberg31022942016-03-11 14:18:21 -0800914 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000915 f1_.CreateOffer(opts, offer1.get()));
916 ASSERT_TRUE(offer2.get() != NULL);
917 EXPECT_EQ(2u, offer2->contents().size());
918 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
919 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
920
zhihuang1c378ed2017-08-17 14:10:50 -0700921 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
922 &opts);
kwiberg31022942016-03-11 14:18:21 -0800923 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000924 f1_.CreateOffer(opts, offer2.get()));
925 ASSERT_TRUE(offer3.get() != NULL);
926 EXPECT_EQ(3u, offer3->contents().size());
927 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
928 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
929 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000930}
931
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000932// Create a typical audio answer, and ensure it matches what we expect.
933TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
934 f1_.set_secure(SEC_ENABLED);
935 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800936 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -0700937 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000938 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800939 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -0700940 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000941 const ContentInfo* ac = answer->GetContentByName("audio");
942 const ContentInfo* vc = answer->GetContentByName("video");
943 ASSERT_TRUE(ac != NULL);
944 ASSERT_TRUE(vc == NULL);
945 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
946 const AudioContentDescription* acd =
947 static_cast<const AudioContentDescription*>(ac->description);
948 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
949 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700950 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000951 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
952 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
953 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
954 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
955}
956
jbauchcb560652016-08-04 05:20:32 -0700957// Create a typical audio answer with GCM ciphers enabled, and ensure it
958// matches what we expect.
959TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
960 f1_.set_secure(SEC_ENABLED);
961 f2_.set_secure(SEC_ENABLED);
zhihuang1c378ed2017-08-17 14:10:50 -0700962 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
963 opts.crypto_options.enable_gcm_crypto_suites = true;
964 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
jbauchcb560652016-08-04 05:20:32 -0700965 ASSERT_TRUE(offer.get() != NULL);
966 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -0700967 f2_.CreateAnswer(offer.get(), opts, NULL));
jbauchcb560652016-08-04 05:20:32 -0700968 const ContentInfo* ac = answer->GetContentByName("audio");
969 const ContentInfo* vc = answer->GetContentByName("video");
970 ASSERT_TRUE(ac != NULL);
971 ASSERT_TRUE(vc == NULL);
972 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
973 const AudioContentDescription* acd =
974 static_cast<const AudioContentDescription*>(ac->description);
975 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
976 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700977 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700978 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
979 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
980 ASSERT_CRYPTO(acd, 1U, CS_AEAD_AES_256_GCM);
981 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
982}
983
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000984// Create a typical video answer, and ensure it matches what we expect.
985TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
986 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -0700987 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000988 f1_.set_secure(SEC_ENABLED);
989 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800990 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000991 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800992 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000993 f2_.CreateAnswer(offer.get(), opts, NULL));
994 const ContentInfo* ac = answer->GetContentByName("audio");
995 const ContentInfo* vc = answer->GetContentByName("video");
996 ASSERT_TRUE(ac != NULL);
997 ASSERT_TRUE(vc != NULL);
998 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
999 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
1000 const AudioContentDescription* acd =
1001 static_cast<const AudioContentDescription*>(ac->description);
1002 const VideoContentDescription* vcd =
1003 static_cast<const VideoContentDescription*>(vc->description);
1004 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1005 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1006 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001007 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001008 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
1009 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1010 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1011 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -07001012 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001013 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
1014 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1015 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
1016}
1017
jbauchcb560652016-08-04 05:20:32 -07001018// Create a typical video answer with GCM ciphers enabled, and ensure it
1019// matches what we expect.
1020TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1021 TestVideoGcmCipher(true, true);
1022}
1023
1024// Create a typical video answer with GCM ciphers enabled for the offer only,
1025// and ensure it matches what we expect.
1026TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1027 TestVideoGcmCipher(true, false);
1028}
1029
1030// Create a typical video answer with GCM ciphers enabled for the answer only,
1031// and ensure it matches what we expect.
1032TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1033 TestVideoGcmCipher(false, true);
1034}
1035
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001036TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001037 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
1038 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001039 f1_.set_secure(SEC_ENABLED);
1040 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001041 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001042 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001043 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001044 f2_.CreateAnswer(offer.get(), opts, NULL));
1045 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001046 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001047 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001048 ASSERT_TRUE(dc != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001049 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
zstein4b2e0822017-02-17 19:48:38 -08001050 EXPECT_EQ(std::string(NS_JINGLE_RTP), dc->type);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001051 const AudioContentDescription* acd =
1052 static_cast<const AudioContentDescription*>(ac->description);
zstein4b2e0822017-02-17 19:48:38 -08001053 const DataContentDescription* dcd =
1054 static_cast<const DataContentDescription*>(dc->description);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001055 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1056 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1057 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001058 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001059 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
1060 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
zstein4b2e0822017-02-17 19:48:38 -08001061 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1062 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -07001063 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001064 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
1065 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1066 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001067}
1068
jbauchcb560652016-08-04 05:20:32 -07001069TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
zhihuang1c378ed2017-08-17 14:10:50 -07001070 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
1071 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &opts);
jbauchcb560652016-08-04 05:20:32 -07001072 opts.crypto_options.enable_gcm_crypto_suites = true;
1073 f1_.set_secure(SEC_ENABLED);
1074 f2_.set_secure(SEC_ENABLED);
1075 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1076 ASSERT_TRUE(offer.get() != NULL);
1077 std::unique_ptr<SessionDescription> answer(
1078 f2_.CreateAnswer(offer.get(), opts, NULL));
1079 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001080 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -07001081 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001082 ASSERT_TRUE(dc != NULL);
jbauchcb560652016-08-04 05:20:32 -07001083 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
zstein4b2e0822017-02-17 19:48:38 -08001084 EXPECT_EQ(std::string(NS_JINGLE_RTP), dc->type);
jbauchcb560652016-08-04 05:20:32 -07001085 const AudioContentDescription* acd =
1086 static_cast<const AudioContentDescription*>(ac->description);
zstein4b2e0822017-02-17 19:48:38 -08001087 const DataContentDescription* dcd =
1088 static_cast<const DataContentDescription*>(dc->description);
jbauchcb560652016-08-04 05:20:32 -07001089 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1090 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1091 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001092 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001093 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
1094 ASSERT_CRYPTO(acd, 1U, CS_AEAD_AES_256_GCM);
zstein4b2e0822017-02-17 19:48:38 -08001095 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1096 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -07001097 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001098 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
1099 ASSERT_CRYPTO(dcd, 1U, CS_AEAD_AES_256_GCM);
1100 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
1101}
1102
1103// The use_sctpmap flag should be set in a DataContentDescription by default.
1104// The answer's use_sctpmap flag should match the offer's.
1105TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1106 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001107 AddDataSection(cricket::DCT_SCTP, cricket::MD_SENDRECV, &opts);
zstein4b2e0822017-02-17 19:48:38 -08001108 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1109 ASSERT_TRUE(offer.get() != NULL);
1110 ContentInfo* dc_offer = offer->GetContentByName("data");
1111 ASSERT_TRUE(dc_offer != NULL);
1112 DataContentDescription* dcd_offer =
1113 static_cast<DataContentDescription*>(dc_offer->description);
1114 EXPECT_TRUE(dcd_offer->use_sctpmap());
1115
1116 std::unique_ptr<SessionDescription> answer(
1117 f2_.CreateAnswer(offer.get(), opts, NULL));
1118 const ContentInfo* dc_answer = answer->GetContentByName("data");
1119 ASSERT_TRUE(dc_answer != NULL);
1120 const DataContentDescription* dcd_answer =
1121 static_cast<const DataContentDescription*>(dc_answer->description);
1122 EXPECT_TRUE(dcd_answer->use_sctpmap());
1123}
1124
1125// The answer's use_sctpmap flag should match the offer's.
1126TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1127 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001128 AddDataSection(cricket::DCT_SCTP, cricket::MD_SENDRECV, &opts);
zstein4b2e0822017-02-17 19:48:38 -08001129 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1130 ASSERT_TRUE(offer.get() != NULL);
1131 ContentInfo* dc_offer = offer->GetContentByName("data");
1132 ASSERT_TRUE(dc_offer != NULL);
1133 DataContentDescription* dcd_offer =
1134 static_cast<DataContentDescription*>(dc_offer->description);
1135 dcd_offer->set_use_sctpmap(false);
1136
1137 std::unique_ptr<SessionDescription> answer(
1138 f2_.CreateAnswer(offer.get(), opts, NULL));
1139 const ContentInfo* dc_answer = answer->GetContentByName("data");
1140 ASSERT_TRUE(dc_answer != NULL);
1141 const DataContentDescription* dcd_answer =
1142 static_cast<const DataContentDescription*>(dc_answer->description);
1143 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001144}
1145
deadbeef8b7e9ad2017-05-25 09:38:55 -07001146// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1147// and "TCP/DTLS/SCTP" offers.
1148TEST_F(MediaSessionDescriptionFactoryTest,
1149 TestCreateDataAnswerToDifferentOfferedProtos) {
1150 // Need to enable DTLS offer/answer generation (disabled by default in this
1151 // test).
1152 f1_.set_secure(SEC_ENABLED);
1153 f2_.set_secure(SEC_ENABLED);
1154 tdf1_.set_secure(SEC_ENABLED);
1155 tdf2_.set_secure(SEC_ENABLED);
1156
1157 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001158 AddDataSection(cricket::DCT_SCTP, cricket::MD_SENDRECV, &opts);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001159 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
1160 ASSERT_TRUE(offer.get() != nullptr);
1161 ContentInfo* dc_offer = offer->GetContentByName("data");
1162 ASSERT_TRUE(dc_offer != nullptr);
1163 DataContentDescription* dcd_offer =
1164 static_cast<DataContentDescription*>(dc_offer->description);
1165
1166 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1167 "TCP/DTLS/SCTP"};
1168 for (const std::string& proto : protos) {
1169 dcd_offer->set_protocol(proto);
1170 std::unique_ptr<SessionDescription> answer(
1171 f2_.CreateAnswer(offer.get(), opts, nullptr));
1172 const ContentInfo* dc_answer = answer->GetContentByName("data");
1173 ASSERT_TRUE(dc_answer != nullptr);
1174 const DataContentDescription* dcd_answer =
1175 static_cast<const DataContentDescription*>(dc_answer->description);
1176 EXPECT_FALSE(dc_answer->rejected);
1177 EXPECT_EQ(proto, dcd_answer->protocol());
1178 }
1179}
1180
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001181// Verifies that the order of the media contents in the offer is preserved in
1182// the answer.
1183TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1184 MediaSessionOptions opts;
1185
1186 // Creates a data only offer.
zhihuang1c378ed2017-08-17 14:10:50 -07001187 AddDataSection(cricket::DCT_SCTP, cricket::MD_SENDRECV, &opts);
kwiberg31022942016-03-11 14:18:21 -08001188 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001189 ASSERT_TRUE(offer1.get() != NULL);
1190
1191 // Appends audio to the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07001192 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
1193 &opts);
kwiberg31022942016-03-11 14:18:21 -08001194 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001195 f1_.CreateOffer(opts, offer1.get()));
1196 ASSERT_TRUE(offer2.get() != NULL);
1197
1198 // Appends video to the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07001199 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
1200 &opts);
kwiberg31022942016-03-11 14:18:21 -08001201 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001202 f1_.CreateOffer(opts, offer2.get()));
1203 ASSERT_TRUE(offer3.get() != NULL);
1204
kwiberg31022942016-03-11 14:18:21 -08001205 std::unique_ptr<SessionDescription> answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001206 f2_.CreateAnswer(offer3.get(), opts, NULL));
1207 ASSERT_TRUE(answer.get() != NULL);
1208 EXPECT_EQ(3u, answer->contents().size());
1209 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1210 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1211 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1212}
1213
ossu075af922016-06-14 03:29:38 -07001214// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1215// answerer settings.
1216
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001217// This test that the media direction is set to send/receive in an answer if
1218// the offer is send receive.
1219TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
1220 TestMediaDirectionInAnswer(cricket::MD_SENDRECV, cricket::MD_SENDRECV);
1221}
1222
1223// This test that the media direction is set to receive only in an answer if
1224// the offer is send only.
1225TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
1226 TestMediaDirectionInAnswer(cricket::MD_SENDONLY, cricket::MD_RECVONLY);
1227}
1228
1229// This test that the media direction is set to send only in an answer if
1230// the offer is recv only.
1231TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
1232 TestMediaDirectionInAnswer(cricket::MD_RECVONLY, cricket::MD_SENDONLY);
1233}
1234
1235// This test that the media direction is set to inactive in an answer if
1236// the offer is inactive.
1237TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
1238 TestMediaDirectionInAnswer(cricket::MD_INACTIVE, cricket::MD_INACTIVE);
1239}
1240
1241// Test that a data content with an unknown protocol is rejected in an answer.
1242TEST_F(MediaSessionDescriptionFactoryTest,
1243 CreateDataAnswerToOfferWithUnknownProtocol) {
1244 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001245 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001246 f1_.set_secure(SEC_ENABLED);
1247 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001248 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
terelius8c011e52016-04-26 05:28:11 -07001249 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001250 ASSERT_TRUE(dc_offer != NULL);
1251 DataContentDescription* dcd_offer =
1252 static_cast<DataContentDescription*>(dc_offer->description);
1253 ASSERT_TRUE(dcd_offer != NULL);
1254 std::string protocol = "a weird unknown protocol";
1255 dcd_offer->set_protocol(protocol);
1256
kwiberg31022942016-03-11 14:18:21 -08001257 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001258 f2_.CreateAnswer(offer.get(), opts, NULL));
1259
1260 const ContentInfo* dc_answer = answer->GetContentByName("data");
1261 ASSERT_TRUE(dc_answer != NULL);
1262 EXPECT_TRUE(dc_answer->rejected);
1263 const DataContentDescription* dcd_answer =
1264 static_cast<const DataContentDescription*>(dc_answer->description);
1265 ASSERT_TRUE(dcd_answer != NULL);
1266 EXPECT_EQ(protocol, dcd_answer->protocol());
1267}
1268
1269// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1270TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001271 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001272 f1_.set_secure(SEC_DISABLED);
1273 f2_.set_secure(SEC_DISABLED);
1274 tdf1_.set_secure(SEC_DISABLED);
1275 tdf2_.set_secure(SEC_DISABLED);
1276
kwiberg31022942016-03-11 14:18:21 -08001277 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001278 const AudioContentDescription* offer_acd =
1279 GetFirstAudioContentDescription(offer.get());
1280 ASSERT_TRUE(offer_acd != NULL);
1281 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), offer_acd->protocol());
1282
kwiberg31022942016-03-11 14:18:21 -08001283 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001284 f2_.CreateAnswer(offer.get(), opts, NULL));
1285
1286 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1287 ASSERT_TRUE(ac_answer != NULL);
1288 EXPECT_FALSE(ac_answer->rejected);
1289
1290 const AudioContentDescription* answer_acd =
1291 GetFirstAudioContentDescription(answer.get());
1292 ASSERT_TRUE(answer_acd != NULL);
1293 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), answer_acd->protocol());
1294}
1295
1296// Create a video offer and answer and ensure the RTP header extensions
1297// matches what we expect.
1298TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1299 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001300 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001301 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1302 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1303 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1304 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1305
kwiberg31022942016-03-11 14:18:21 -08001306 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001307 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001308 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001309 f2_.CreateAnswer(offer.get(), opts, NULL));
1310
1311 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension1),
1312 GetFirstAudioContentDescription(
1313 offer.get())->rtp_header_extensions());
1314 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtension1),
1315 GetFirstVideoContentDescription(
1316 offer.get())->rtp_header_extensions());
1317 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
1318 GetFirstAudioContentDescription(
1319 answer.get())->rtp_header_extensions());
1320 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
1321 GetFirstVideoContentDescription(
1322 answer.get())->rtp_header_extensions());
1323}
1324
jbauch5869f502017-06-29 12:31:36 -07001325TEST_F(MediaSessionDescriptionFactoryTest,
1326 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
1327 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001328 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
jbauch5869f502017-06-29 12:31:36 -07001329
1330 f1_.set_enable_encrypted_rtp_header_extensions(true);
1331 f2_.set_enable_encrypted_rtp_header_extensions(true);
1332
1333 f1_.set_audio_rtp_header_extensions(
1334 MAKE_VECTOR(kAudioRtpExtension1));
1335 f1_.set_video_rtp_header_extensions(
1336 MAKE_VECTOR(kVideoRtpExtension1));
1337 f2_.set_audio_rtp_header_extensions(
1338 MAKE_VECTOR(kAudioRtpExtension2));
1339 f2_.set_video_rtp_header_extensions(
1340 MAKE_VECTOR(kVideoRtpExtension2));
1341
1342 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1343 ASSERT_TRUE(offer.get() != NULL);
1344 std::unique_ptr<SessionDescription> answer(
1345 f2_.CreateAnswer(offer.get(), opts, NULL));
1346
1347 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1348 GetFirstAudioContentDescription(
1349 offer.get())->rtp_header_extensions());
1350 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1351 GetFirstVideoContentDescription(
1352 offer.get())->rtp_header_extensions());
1353 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
1354 GetFirstAudioContentDescription(
1355 answer.get())->rtp_header_extensions());
1356 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
1357 GetFirstVideoContentDescription(
1358 answer.get())->rtp_header_extensions());
1359}
1360
1361TEST_F(MediaSessionDescriptionFactoryTest,
1362 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
1363 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001364 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
jbauch5869f502017-06-29 12:31:36 -07001365
1366 f1_.set_enable_encrypted_rtp_header_extensions(true);
1367
1368 f1_.set_audio_rtp_header_extensions(
1369 MAKE_VECTOR(kAudioRtpExtension1));
1370 f1_.set_video_rtp_header_extensions(
1371 MAKE_VECTOR(kVideoRtpExtension1));
1372 f2_.set_audio_rtp_header_extensions(
1373 MAKE_VECTOR(kAudioRtpExtension2));
1374 f2_.set_video_rtp_header_extensions(
1375 MAKE_VECTOR(kVideoRtpExtension2));
1376
1377 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1378 ASSERT_TRUE(offer.get() != NULL);
1379 std::unique_ptr<SessionDescription> answer(
1380 f2_.CreateAnswer(offer.get(), opts, NULL));
1381
1382 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1383 GetFirstAudioContentDescription(
1384 offer.get())->rtp_header_extensions());
1385 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1386 GetFirstVideoContentDescription(
1387 offer.get())->rtp_header_extensions());
1388 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
1389 GetFirstAudioContentDescription(
1390 answer.get())->rtp_header_extensions());
1391 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
1392 GetFirstVideoContentDescription(
1393 answer.get())->rtp_header_extensions());
1394}
1395
1396TEST_F(MediaSessionDescriptionFactoryTest,
1397 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
1398 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001399 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
jbauch5869f502017-06-29 12:31:36 -07001400
1401 f2_.set_enable_encrypted_rtp_header_extensions(true);
1402
1403 f1_.set_audio_rtp_header_extensions(
1404 MAKE_VECTOR(kAudioRtpExtension1));
1405 f1_.set_video_rtp_header_extensions(
1406 MAKE_VECTOR(kVideoRtpExtension1));
1407 f2_.set_audio_rtp_header_extensions(
1408 MAKE_VECTOR(kAudioRtpExtension2));
1409 f2_.set_video_rtp_header_extensions(
1410 MAKE_VECTOR(kVideoRtpExtension2));
1411
1412 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1413 ASSERT_TRUE(offer.get() != NULL);
1414 std::unique_ptr<SessionDescription> answer(
1415 f2_.CreateAnswer(offer.get(), opts, NULL));
1416
1417 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension1),
1418 GetFirstAudioContentDescription(
1419 offer.get())->rtp_header_extensions());
1420 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtension1),
1421 GetFirstVideoContentDescription(
1422 offer.get())->rtp_header_extensions());
1423 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
1424 GetFirstAudioContentDescription(
1425 answer.get())->rtp_header_extensions());
1426 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
1427 GetFirstVideoContentDescription(
1428 answer.get())->rtp_header_extensions());
1429}
1430
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001431// Create an audio, video, data answer without legacy StreamParams.
1432TEST_F(MediaSessionDescriptionFactoryTest,
1433 TestCreateAnswerWithoutLegacyStreams) {
1434 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001435 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
1436 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &opts);
kwiberg31022942016-03-11 14:18:21 -08001437 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001438 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001439 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001440 f2_.CreateAnswer(offer.get(), opts, NULL));
1441 const ContentInfo* ac = answer->GetContentByName("audio");
1442 const ContentInfo* vc = answer->GetContentByName("video");
1443 const ContentInfo* dc = answer->GetContentByName("data");
1444 ASSERT_TRUE(ac != NULL);
1445 ASSERT_TRUE(vc != NULL);
1446 const AudioContentDescription* acd =
1447 static_cast<const AudioContentDescription*>(ac->description);
1448 const VideoContentDescription* vcd =
1449 static_cast<const VideoContentDescription*>(vc->description);
1450 const DataContentDescription* dcd =
1451 static_cast<const DataContentDescription*>(dc->description);
1452
1453 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1454 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1455 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1456}
1457
1458TEST_F(MediaSessionDescriptionFactoryTest, TestPartial) {
1459 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001460 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
1461 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001462 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001463 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001464 ASSERT_TRUE(offer.get() != NULL);
1465 const ContentInfo* ac = offer->GetContentByName("audio");
1466 const ContentInfo* vc = offer->GetContentByName("video");
1467 const ContentInfo* dc = offer->GetContentByName("data");
1468 AudioContentDescription* acd = const_cast<AudioContentDescription*>(
1469 static_cast<const AudioContentDescription*>(ac->description));
1470 VideoContentDescription* vcd = const_cast<VideoContentDescription*>(
1471 static_cast<const VideoContentDescription*>(vc->description));
1472 DataContentDescription* dcd = const_cast<DataContentDescription*>(
1473 static_cast<const DataContentDescription*>(dc->description));
1474
1475 EXPECT_FALSE(acd->partial()); // default is false.
1476 acd->set_partial(true);
1477 EXPECT_TRUE(acd->partial());
1478 acd->set_partial(false);
1479 EXPECT_FALSE(acd->partial());
1480
1481 EXPECT_FALSE(vcd->partial()); // default is false.
1482 vcd->set_partial(true);
1483 EXPECT_TRUE(vcd->partial());
1484 vcd->set_partial(false);
1485 EXPECT_FALSE(vcd->partial());
1486
1487 EXPECT_FALSE(dcd->partial()); // default is false.
1488 dcd->set_partial(true);
1489 EXPECT_TRUE(dcd->partial());
1490 dcd->set_partial(false);
1491 EXPECT_FALSE(dcd->partial());
1492}
1493
1494// Create a typical video answer, and ensure it matches what we expect.
1495TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1496 MediaSessionOptions offer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001497 AddAudioVideoSections(cricket::MD_SENDRECV, &offer_opts);
1498 AddDataSection(cricket::DCT_RTP, cricket::MD_SENDRECV, &offer_opts);
1499
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001500 MediaSessionOptions answer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001501 AddAudioVideoSections(cricket::MD_SENDRECV, &answer_opts);
1502 AddDataSection(cricket::DCT_RTP, cricket::MD_SENDRECV, &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001503
kwiberg31022942016-03-11 14:18:21 -08001504 std::unique_ptr<SessionDescription> offer;
1505 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001506
1507 offer_opts.rtcp_mux_enabled = true;
1508 answer_opts.rtcp_mux_enabled = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001509 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1510 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1511 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1512 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1513 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1514 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1515 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1516 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1517 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1518 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1519 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1520 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1521 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1522 EXPECT_TRUE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1523
1524 offer_opts.rtcp_mux_enabled = true;
1525 answer_opts.rtcp_mux_enabled = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001526 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1527 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1528 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1529 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1530 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1531 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1532 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1533 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1534 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1535 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1536 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1537 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1538 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1539 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1540
1541 offer_opts.rtcp_mux_enabled = false;
1542 answer_opts.rtcp_mux_enabled = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001543 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1544 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1545 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1546 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1547 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1548 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1549 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1550 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1551 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1552 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1553 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1554 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1555 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1556 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1557
1558 offer_opts.rtcp_mux_enabled = false;
1559 answer_opts.rtcp_mux_enabled = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001560 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1561 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1562 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1563 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1564 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1565 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1566 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1567 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1568 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1569 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1570 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1571 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1572 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1573 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1574}
1575
1576// Create an audio-only answer to a video offer.
1577TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1578 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001579 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
1580 &opts);
1581 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
1582 &opts);
kwiberg31022942016-03-11 14:18:21 -08001583 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001584 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001585
1586 opts.media_description_options[1].stopped = true;
kwiberg31022942016-03-11 14:18:21 -08001587 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001588 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001589 const ContentInfo* ac = answer->GetContentByName("audio");
1590 const ContentInfo* vc = answer->GetContentByName("video");
1591 ASSERT_TRUE(ac != NULL);
1592 ASSERT_TRUE(vc != NULL);
1593 ASSERT_TRUE(vc->description != NULL);
1594 EXPECT_TRUE(vc->rejected);
1595}
1596
1597// Create an audio-only answer to an offer with data.
1598TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001599 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001600 opts.data_channel_type = cricket::DCT_RTP;
zhihuang1c378ed2017-08-17 14:10:50 -07001601 AddMediaSection(MEDIA_TYPE_DATA, "data", cricket::MD_RECVONLY, kActive,
1602 &opts);
kwiberg31022942016-03-11 14:18:21 -08001603 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001604 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001605
1606 opts.media_description_options[1].stopped = true;
kwiberg31022942016-03-11 14:18:21 -08001607 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001608 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001609 const ContentInfo* ac = answer->GetContentByName("audio");
1610 const ContentInfo* dc = answer->GetContentByName("data");
1611 ASSERT_TRUE(ac != NULL);
1612 ASSERT_TRUE(dc != NULL);
1613 ASSERT_TRUE(dc->description != NULL);
1614 EXPECT_TRUE(dc->rejected);
1615}
1616
1617// Create an answer that rejects the contents which are rejected in the offer.
1618TEST_F(MediaSessionDescriptionFactoryTest,
1619 CreateAnswerToOfferWithRejectedMedia) {
1620 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001621 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
1622 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &opts);
kwiberg31022942016-03-11 14:18:21 -08001623 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001624 ASSERT_TRUE(offer.get() != NULL);
1625 ContentInfo* ac = offer->GetContentByName("audio");
1626 ContentInfo* vc = offer->GetContentByName("video");
1627 ContentInfo* dc = offer->GetContentByName("data");
1628 ASSERT_TRUE(ac != NULL);
1629 ASSERT_TRUE(vc != NULL);
1630 ASSERT_TRUE(dc != NULL);
1631 ac->rejected = true;
1632 vc->rejected = true;
1633 dc->rejected = true;
kwiberg31022942016-03-11 14:18:21 -08001634 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001635 f2_.CreateAnswer(offer.get(), opts, NULL));
1636 ac = answer->GetContentByName("audio");
1637 vc = answer->GetContentByName("video");
1638 dc = answer->GetContentByName("data");
1639 ASSERT_TRUE(ac != NULL);
1640 ASSERT_TRUE(vc != NULL);
1641 ASSERT_TRUE(dc != NULL);
1642 EXPECT_TRUE(ac->rejected);
1643 EXPECT_TRUE(vc->rejected);
1644 EXPECT_TRUE(dc->rejected);
1645}
1646
1647// Create an audio and video offer with:
1648// - one video track
1649// - two audio tracks
1650// - two data tracks
1651// and ensure it matches what we expect. Also updates the initial offer by
1652// adding a new video track and replaces one of the audio tracks.
1653TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
1654 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001655 AddAudioVideoSections(cricket::MD_SENDRECV, &opts);
1656 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001657 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001658 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001659 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001660 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001661 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001662
1663 AddDataSection(cricket::DCT_RTP, cricket::MD_SENDRECV, &opts);
1664 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001665 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001666 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001667 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001668
1669 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001670 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001671
1672 ASSERT_TRUE(offer.get() != NULL);
1673 const ContentInfo* ac = offer->GetContentByName("audio");
1674 const ContentInfo* vc = offer->GetContentByName("video");
1675 const ContentInfo* dc = offer->GetContentByName("data");
1676 ASSERT_TRUE(ac != NULL);
1677 ASSERT_TRUE(vc != NULL);
1678 ASSERT_TRUE(dc != NULL);
1679 const AudioContentDescription* acd =
1680 static_cast<const AudioContentDescription*>(ac->description);
1681 const VideoContentDescription* vcd =
1682 static_cast<const VideoContentDescription*>(vc->description);
1683 const DataContentDescription* dcd =
1684 static_cast<const DataContentDescription*>(dc->description);
1685 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07001686 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001687
1688 const StreamParamsVec& audio_streams = acd->streams();
1689 ASSERT_EQ(2U, audio_streams.size());
1690 EXPECT_EQ(audio_streams[0].cname , audio_streams[1].cname);
1691 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1692 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1693 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1694 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1695 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1696 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1697
1698 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1699 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1700 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
1701
1702 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1703 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
1704 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1705
1706 const StreamParamsVec& video_streams = vcd->streams();
1707 ASSERT_EQ(1U, video_streams.size());
1708 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1709 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1710 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1711 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1712
1713 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1714 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
1715 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1716
1717 const StreamParamsVec& data_streams = dcd->streams();
1718 ASSERT_EQ(2U, data_streams.size());
1719 EXPECT_EQ(data_streams[0].cname , data_streams[1].cname);
1720 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1721 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1722 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1723 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1724 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1725 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1726
1727 EXPECT_EQ(cricket::kDataMaxBandwidth,
1728 dcd->bandwidth()); // default bandwidth (auto)
1729 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
1730 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1731
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001732 // Update the offer. Add a new video track that is not synched to the
1733 // other tracks and replace audio track 2 with audio track 3.
zhihuang1c378ed2017-08-17 14:10:50 -07001734 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001735 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001736 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
1737 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001738 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001739 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
1740 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack3,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001741 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08001742 std::unique_ptr<SessionDescription> updated_offer(
1743 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001744
1745 ASSERT_TRUE(updated_offer.get() != NULL);
1746 ac = updated_offer->GetContentByName("audio");
1747 vc = updated_offer->GetContentByName("video");
1748 dc = updated_offer->GetContentByName("data");
1749 ASSERT_TRUE(ac != NULL);
1750 ASSERT_TRUE(vc != NULL);
1751 ASSERT_TRUE(dc != NULL);
1752 const AudioContentDescription* updated_acd =
1753 static_cast<const AudioContentDescription*>(ac->description);
1754 const VideoContentDescription* updated_vcd =
1755 static_cast<const VideoContentDescription*>(vc->description);
1756 const DataContentDescription* updated_dcd =
1757 static_cast<const DataContentDescription*>(dc->description);
1758
1759 EXPECT_EQ(acd->type(), updated_acd->type());
1760 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1761 EXPECT_EQ(vcd->type(), updated_vcd->type());
1762 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1763 EXPECT_EQ(dcd->type(), updated_dcd->type());
1764 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1765 ASSERT_CRYPTO(updated_acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
1766 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
1767 ASSERT_CRYPTO(updated_vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1768 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
1769 ASSERT_CRYPTO(updated_dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1770 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1771
1772 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1773 ASSERT_EQ(2U, updated_audio_streams.size());
1774 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
1775 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
1776 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
1777 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
1778 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
1779
1780 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1781 ASSERT_EQ(2U, updated_video_streams.size());
1782 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1783 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001784 // All the media streams in one PeerConnection share one RTCP CNAME.
1785 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001786
1787 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1788 ASSERT_EQ(2U, updated_data_streams.size());
1789 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
1790 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
1791 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
1792 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
1793 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07001794 // The stream correctly got the CNAME from the MediaSessionOptions.
1795 // The Expected RTCP CNAME is the default one as we are using the default
1796 // MediaSessionOptions.
1797 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001798}
1799
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001800// Create an offer with simulcast video stream.
1801TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
1802 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001803 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
1804 &opts);
1805 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_SENDRECV, kActive,
1806 &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001807 const int num_sim_layers = 3;
zhihuang1c378ed2017-08-17 14:10:50 -07001808 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001809 {kMediaStream1}, num_sim_layers, &opts);
kwiberg31022942016-03-11 14:18:21 -08001810 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001811
1812 ASSERT_TRUE(offer.get() != NULL);
1813 const ContentInfo* vc = offer->GetContentByName("video");
1814 ASSERT_TRUE(vc != NULL);
1815 const VideoContentDescription* vcd =
1816 static_cast<const VideoContentDescription*>(vc->description);
1817
1818 const StreamParamsVec& video_streams = vcd->streams();
1819 ASSERT_EQ(1U, video_streams.size());
1820 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1821 const SsrcGroup* sim_ssrc_group =
1822 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
1823 ASSERT_TRUE(sim_ssrc_group != NULL);
1824 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
1825}
1826
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001827// Create an audio and video answer to a standard video offer with:
1828// - one video track
1829// - two audio tracks
1830// - two data tracks
1831// and ensure it matches what we expect. Also updates the initial answer by
1832// adding a new video track and removes one of the audio tracks.
1833TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
1834 MediaSessionOptions offer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001835 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
1836 &offer_opts);
1837 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
1838 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001839 offer_opts.data_channel_type = cricket::DCT_RTP;
zhihuang1c378ed2017-08-17 14:10:50 -07001840 AddMediaSection(MEDIA_TYPE_DATA, "data", cricket::MD_RECVONLY, kActive,
1841 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001842 f1_.set_secure(SEC_ENABLED);
1843 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001844 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(offer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001845
zhihuang1c378ed2017-08-17 14:10:50 -07001846 MediaSessionOptions answer_opts;
1847 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_SENDRECV, kActive,
1848 &answer_opts);
1849 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_SENDRECV, kActive,
1850 &answer_opts);
1851 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001852 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001853 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001854 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001855 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001856 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001857
1858 AddMediaSection(MEDIA_TYPE_DATA, "data", cricket::MD_SENDRECV, kActive,
1859 &answer_opts);
1860 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001861 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001862 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001863 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001864 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001865
kwiberg31022942016-03-11 14:18:21 -08001866 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001867 f2_.CreateAnswer(offer.get(), answer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001868
1869 ASSERT_TRUE(answer.get() != NULL);
1870 const ContentInfo* ac = answer->GetContentByName("audio");
1871 const ContentInfo* vc = answer->GetContentByName("video");
1872 const ContentInfo* dc = answer->GetContentByName("data");
1873 ASSERT_TRUE(ac != NULL);
1874 ASSERT_TRUE(vc != NULL);
1875 ASSERT_TRUE(dc != NULL);
1876 const AudioContentDescription* acd =
1877 static_cast<const AudioContentDescription*>(ac->description);
1878 const VideoContentDescription* vcd =
1879 static_cast<const VideoContentDescription*>(vc->description);
1880 const DataContentDescription* dcd =
1881 static_cast<const DataContentDescription*>(dc->description);
1882 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1883 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1884 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1885
1886 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1887 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1888
1889 const StreamParamsVec& audio_streams = acd->streams();
1890 ASSERT_EQ(2U, audio_streams.size());
1891 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
1892 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1893 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1894 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1895 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1896 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1897 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1898
1899 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1900 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1901
1902 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1903 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1904
1905 const StreamParamsVec& video_streams = vcd->streams();
1906 ASSERT_EQ(1U, video_streams.size());
1907 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1908 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1909 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1910 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1911
1912 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1913 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
1914
1915 const StreamParamsVec& data_streams = dcd->streams();
1916 ASSERT_EQ(2U, data_streams.size());
1917 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
1918 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1919 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1920 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1921 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1922 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1923 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1924
1925 EXPECT_EQ(cricket::kDataMaxBandwidth,
1926 dcd->bandwidth()); // default bandwidth (auto)
1927 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
1928
1929 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07001930 // other tracks and remove 1 audio track.
zhihuang1c378ed2017-08-17 14:10:50 -07001931 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001932 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001933 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
1934 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08001935 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001936 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001937
1938 ASSERT_TRUE(updated_answer.get() != NULL);
1939 ac = updated_answer->GetContentByName("audio");
1940 vc = updated_answer->GetContentByName("video");
1941 dc = updated_answer->GetContentByName("data");
1942 ASSERT_TRUE(ac != NULL);
1943 ASSERT_TRUE(vc != NULL);
1944 ASSERT_TRUE(dc != NULL);
1945 const AudioContentDescription* updated_acd =
1946 static_cast<const AudioContentDescription*>(ac->description);
1947 const VideoContentDescription* updated_vcd =
1948 static_cast<const VideoContentDescription*>(vc->description);
1949 const DataContentDescription* updated_dcd =
1950 static_cast<const DataContentDescription*>(dc->description);
1951
1952 ASSERT_CRYPTO(updated_acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1953 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
1954 ASSERT_CRYPTO(updated_vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1955 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
1956 ASSERT_CRYPTO(updated_dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1957 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1958
1959 EXPECT_EQ(acd->type(), updated_acd->type());
1960 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1961 EXPECT_EQ(vcd->type(), updated_vcd->type());
1962 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1963 EXPECT_EQ(dcd->type(), updated_dcd->type());
1964 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1965
1966 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1967 ASSERT_EQ(1U, updated_audio_streams.size());
1968 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
1969
1970 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1971 ASSERT_EQ(2U, updated_video_streams.size());
1972 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1973 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001974 // All media streams in one PeerConnection share one CNAME.
1975 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001976
1977 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1978 ASSERT_EQ(1U, updated_data_streams.size());
1979 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
1980}
1981
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001982// Create an updated offer after creating an answer to the original offer and
1983// verify that the codecs that were part of the original answer are not changed
1984// in the updated offer.
1985TEST_F(MediaSessionDescriptionFactoryTest,
1986 RespondentCreatesOfferAfterCreatingAnswer) {
1987 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07001988 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001989
kwiberg31022942016-03-11 14:18:21 -08001990 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1991 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001992 f2_.CreateAnswer(offer.get(), opts, NULL));
1993
1994 const AudioContentDescription* acd =
1995 GetFirstAudioContentDescription(answer.get());
1996 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1997
1998 const VideoContentDescription* vcd =
1999 GetFirstVideoContentDescription(answer.get());
2000 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
2001
kwiberg31022942016-03-11 14:18:21 -08002002 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002003 f2_.CreateOffer(opts, answer.get()));
2004
2005 // The expected audio codecs are the common audio codecs from the first
2006 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
2007 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002008 // TODO(wu): |updated_offer| should not include the codec
2009 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002010 const AudioCodec kUpdatedAudioCodecOffer[] = {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002011 kAudioCodecsAnswer[0],
2012 kAudioCodecsAnswer[1],
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002013 kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002014 };
2015
2016 // The expected video codecs are the common video codecs from the first
2017 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
2018 // preference order.
2019 const VideoCodec kUpdatedVideoCodecOffer[] = {
2020 kVideoCodecsAnswer[0],
2021 kVideoCodecs2[1],
2022 };
2023
2024 const AudioContentDescription* updated_acd =
2025 GetFirstAudioContentDescription(updated_offer.get());
2026 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioCodecOffer), updated_acd->codecs());
2027
2028 const VideoContentDescription* updated_vcd =
2029 GetFirstVideoContentDescription(updated_offer.get());
2030 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoCodecOffer), updated_vcd->codecs());
2031}
2032
2033// Create an updated offer after creating an answer to the original offer and
2034// verify that the codecs that were part of the original answer are not changed
2035// in the updated offer. In this test Rtx is enabled.
2036TEST_F(MediaSessionDescriptionFactoryTest,
2037 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2038 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002039 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
2040 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002041 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002042 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002043 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002044 f1_.set_video_codecs(f1_codecs);
2045
2046 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002047 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002048 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002049 f2_.set_video_codecs(f2_codecs);
2050
kwiberg31022942016-03-11 14:18:21 -08002051 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002052 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002053 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002054 f2_.CreateAnswer(offer.get(), opts, NULL));
2055
2056 const VideoContentDescription* vcd =
2057 GetFirstVideoContentDescription(answer.get());
2058
2059 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002060 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2061 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002062
2063 EXPECT_EQ(expected_codecs, vcd->codecs());
2064
deadbeef67cf2c12016-04-13 10:07:16 -07002065 // Now, make sure we get same result (except for the order) if |f2_| creates
2066 // an updated offer even though the default payload types between |f1_| and
2067 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08002068 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002069 f2_.CreateOffer(opts, answer.get()));
2070 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002071 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002072 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2073
2074 const VideoContentDescription* updated_vcd =
2075 GetFirstVideoContentDescription(updated_answer.get());
2076
2077 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2078}
2079
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002080// Regression test for:
2081// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2082// Existing codecs should always appear before new codecs in re-offers. But
2083// under a specific set of circumstances, the existing RTX codec was ending up
2084// added to the end of the list.
2085TEST_F(MediaSessionDescriptionFactoryTest,
2086 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2087 MediaSessionOptions opts;
2088 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
2089 &opts);
2090 // We specifically choose different preferred payload types for VP8 to
2091 // trigger the issue.
2092 cricket::VideoCodec vp8_offerer(100, "VP8");
2093 cricket::VideoCodec vp8_offerer_rtx =
2094 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
2095 cricket::VideoCodec vp8_answerer(110, "VP8");
2096 cricket::VideoCodec vp8_answerer_rtx =
2097 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
2098 cricket::VideoCodec vp9(120, "VP9");
2099 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
2100
2101 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
2102 // We also specifically cause the answerer to prefer VP9, such that if it
2103 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
2104 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
2105 vp8_answerer_rtx};
2106
2107 f1_.set_video_codecs(f1_codecs);
2108 f2_.set_video_codecs(f2_codecs);
2109 std::vector<AudioCodec> audio_codecs;
2110 f1_.set_audio_codecs(audio_codecs, audio_codecs);
2111 f2_.set_audio_codecs(audio_codecs, audio_codecs);
2112
2113 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
2114 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2115 ASSERT_TRUE(offer.get() != NULL);
2116 std::unique_ptr<SessionDescription> answer(
2117 f2_.CreateAnswer(offer.get(), opts, NULL));
2118
2119 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
2120 // But if the bug is triggered, RTX for VP8 ends up last.
2121 std::unique_ptr<SessionDescription> updated_offer(
2122 f2_.CreateOffer(opts, answer.get()));
2123
2124 const VideoContentDescription* vcd =
2125 GetFirstVideoContentDescription(updated_offer.get());
2126 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
2127 ASSERT_EQ(4u, codecs.size());
2128 EXPECT_EQ(vp8_offerer, codecs[0]);
2129 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
2130 EXPECT_EQ(vp9, codecs[2]);
2131 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002132}
2133
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002134// Create an updated offer that adds video after creating an audio only answer
2135// to the original offer. This test verifies that if a video codec and the RTX
2136// codec have the same default payload type as an audio codec that is already in
2137// use, the added codecs payload types are changed.
2138TEST_F(MediaSessionDescriptionFactoryTest,
2139 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2140 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002141 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002142 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002143 f1_.set_video_codecs(f1_codecs);
2144
2145 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002146 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
2147 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002148
kwiberg31022942016-03-11 14:18:21 -08002149 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2150 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002151 f2_.CreateAnswer(offer.get(), opts, NULL));
2152
2153 const AudioContentDescription* acd =
2154 GetFirstAudioContentDescription(answer.get());
2155 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
2156
2157 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
2158 // reference be the same as an audio codec that was negotiated in the
2159 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002160 opts.media_description_options.clear();
2161 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002162
2163 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2164 int used_pl_type = acd->codecs()[0].id;
2165 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002166 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002167 f2_.set_video_codecs(f2_codecs);
2168
kwiberg31022942016-03-11 14:18:21 -08002169 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002170 f2_.CreateOffer(opts, answer.get()));
2171 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002172 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002173 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2174
2175 const AudioContentDescription* updated_acd =
2176 GetFirstAudioContentDescription(answer.get());
2177 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), updated_acd->codecs());
2178
2179 const VideoContentDescription* updated_vcd =
2180 GetFirstVideoContentDescription(updated_answer.get());
2181
2182 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
sergeyu@chromium.org32f485b2013-12-05 22:36:21 +00002183 ASSERT_EQ(std::string(cricket::kRtxCodecName), updated_vcd->codecs()[1].name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002184 int new_h264_pl_type = updated_vcd->codecs()[0].id;
2185 EXPECT_NE(used_pl_type, new_h264_pl_type);
2186 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002187 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002188 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
2189 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
2190}
2191
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002192// Create an updated offer with RTX after creating an answer to an offer
2193// without RTX, and with different default payload types.
2194// Verify that the added RTX codec references the correct payload type.
2195TEST_F(MediaSessionDescriptionFactoryTest,
2196 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
2197 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002198 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002199
2200 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2201 // This creates rtx for H264 with the payload type |f2_| uses.
2202 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
2203 f2_.set_video_codecs(f2_codecs);
2204
kwiberg31022942016-03-11 14:18:21 -08002205 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002206 ASSERT_TRUE(offer.get() != nullptr);
kwiberg31022942016-03-11 14:18:21 -08002207 std::unique_ptr<SessionDescription> answer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002208 f2_.CreateAnswer(offer.get(), opts, nullptr));
2209
2210 const VideoContentDescription* vcd =
2211 GetFirstVideoContentDescription(answer.get());
2212
2213 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2214 EXPECT_EQ(expected_codecs, vcd->codecs());
2215
2216 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
2217 // updated offer, even though the default payload types are different from
2218 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08002219 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002220 f2_.CreateOffer(opts, answer.get()));
2221 ASSERT_TRUE(updated_offer);
2222
2223 const VideoContentDescription* updated_vcd =
2224 GetFirstVideoContentDescription(updated_offer.get());
2225
2226 // New offer should attempt to add H263, and RTX for H264.
2227 expected_codecs.push_back(kVideoCodecs2[1]);
2228 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
2229 &expected_codecs);
2230 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2231}
2232
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002233// Test that RTX is ignored when there is no associated payload type parameter.
2234TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
2235 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002236 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
2237 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002238 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002239 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07002240 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002241 f1_.set_video_codecs(f1_codecs);
2242
2243 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002244 // This creates RTX for H264 with the payload type |f2_| uses.
2245 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002246 f2_.set_video_codecs(f2_codecs);
2247
kwiberg31022942016-03-11 14:18:21 -08002248 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002249 ASSERT_TRUE(offer.get() != NULL);
2250 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
2251 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
2252 // is possible to test that that RTX is dropped when
2253 // kCodecParamAssociatedPayloadType is missing in the offer.
2254 VideoContentDescription* desc =
2255 static_cast<cricket::VideoContentDescription*>(
2256 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
2257 ASSERT_TRUE(desc != NULL);
2258 std::vector<VideoCodec> codecs = desc->codecs();
2259 for (std::vector<VideoCodec>::iterator iter = codecs.begin();
2260 iter != codecs.end(); ++iter) {
2261 if (iter->name.find(cricket::kRtxCodecName) == 0) {
2262 iter->params.clear();
2263 }
2264 }
2265 desc->set_codecs(codecs);
2266
kwiberg31022942016-03-11 14:18:21 -08002267 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002268 f2_.CreateAnswer(offer.get(), opts, NULL));
2269
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002270 std::vector<std::string> codec_names =
2271 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
2272 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
2273 cricket::kRtxCodecName));
2274}
2275
2276// Test that RTX will be filtered out in the answer if its associated payload
2277// type doesn't match the local value.
2278TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
2279 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002280 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
2281 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002282 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2283 // This creates RTX for H264 in sender.
2284 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2285 f1_.set_video_codecs(f1_codecs);
2286
2287 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2288 // This creates RTX for H263 in receiver.
2289 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
2290 f2_.set_video_codecs(f2_codecs);
2291
kwiberg31022942016-03-11 14:18:21 -08002292 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002293 ASSERT_TRUE(offer.get() != NULL);
2294 // Associated payload type doesn't match, therefore, RTX codec is removed in
2295 // the answer.
kwiberg31022942016-03-11 14:18:21 -08002296 std::unique_ptr<SessionDescription> answer(
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002297 f2_.CreateAnswer(offer.get(), opts, NULL));
2298
2299 std::vector<std::string> codec_names =
2300 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
2301 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
2302 cricket::kRtxCodecName));
2303}
2304
2305// Test that when multiple RTX codecs are offered, only the matched RTX codec
2306// is added in the answer, and the unsupported RTX codec is filtered out.
2307TEST_F(MediaSessionDescriptionFactoryTest,
2308 FilterOutUnsupportedRtxWhenCreatingAnswer) {
2309 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002310 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
2311 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002312 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2313 // This creates RTX for H264-SVC in sender.
2314 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2315 f1_.set_video_codecs(f1_codecs);
2316
2317 // This creates RTX for H264 in sender.
2318 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2319 f1_.set_video_codecs(f1_codecs);
2320
2321 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2322 // This creates RTX for H264 in receiver.
2323 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
2324 f2_.set_video_codecs(f2_codecs);
2325
2326 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
2327 // for H264-SVC should also be removed.
kwiberg31022942016-03-11 14:18:21 -08002328 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002329 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002330 std::unique_ptr<SessionDescription> answer(
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002331 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002332 const VideoContentDescription* vcd =
2333 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002334 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2335 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2336 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002337
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002338 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002339}
2340
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002341// Test that after one RTX codec has been negotiated, a new offer can attempt
2342// to add another.
2343TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
2344 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002345 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
2346 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002347 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2348 // This creates RTX for H264 for the offerer.
2349 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2350 f1_.set_video_codecs(f1_codecs);
2351
kwiberg31022942016-03-11 14:18:21 -08002352 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002353 ASSERT_TRUE(offer);
2354 const VideoContentDescription* vcd =
2355 GetFirstVideoContentDescription(offer.get());
2356
2357 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
2358 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2359 &expected_codecs);
2360 EXPECT_EQ(expected_codecs, vcd->codecs());
2361
2362 // Now, attempt to add RTX for H264-SVC.
2363 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2364 f1_.set_video_codecs(f1_codecs);
2365
kwiberg31022942016-03-11 14:18:21 -08002366 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002367 f1_.CreateOffer(opts, offer.get()));
2368 ASSERT_TRUE(updated_offer);
2369 vcd = GetFirstVideoContentDescription(updated_offer.get());
2370
2371 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
2372 &expected_codecs);
2373 EXPECT_EQ(expected_codecs, vcd->codecs());
2374}
2375
Noah Richards2e7a0982015-05-18 14:02:54 -07002376// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
2377// generated for each simulcast ssrc and correctly grouped.
2378TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
2379 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002380 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_SENDRECV, kActive,
2381 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002382 // Add simulcast streams.
zhihuang1c378ed2017-08-17 14:10:50 -07002383 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002384 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002385
2386 // Use a single real codec, and then add RTX for it.
2387 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07002388 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07002389 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
2390 f1_.set_video_codecs(f1_codecs);
2391
2392 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
2393 // is a FID ssrc + grouping for each.
kwiberg31022942016-03-11 14:18:21 -08002394 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
Noah Richards2e7a0982015-05-18 14:02:54 -07002395 ASSERT_TRUE(offer.get() != NULL);
2396 VideoContentDescription* desc = static_cast<VideoContentDescription*>(
2397 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
2398 ASSERT_TRUE(desc != NULL);
2399 EXPECT_TRUE(desc->multistream());
2400 const StreamParamsVec& streams = desc->streams();
2401 // Single stream.
2402 ASSERT_EQ(1u, streams.size());
2403 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
2404 EXPECT_EQ(6u, streams[0].ssrcs.size());
2405 // And should have a SIM group for the simulcast.
2406 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2407 // And a FID group for RTX.
2408 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02002409 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002410 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2411 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02002412 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002413 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
2414 EXPECT_EQ(3u, fid_ssrcs.size());
2415}
2416
brandtr03d5fb12016-11-22 03:37:59 -08002417// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
2418// together with a FEC-FR grouping.
2419TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
2420 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002421 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_SENDRECV, kActive,
2422 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002423 // Add single stream.
zhihuang1c378ed2017-08-17 14:10:50 -07002424 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002425 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002426
2427 // Use a single real codec, and then add FlexFEC for it.
2428 std::vector<VideoCodec> f1_codecs;
2429 f1_codecs.push_back(VideoCodec(97, "H264"));
2430 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2431 f1_.set_video_codecs(f1_codecs);
2432
2433 // Ensure that the offer has a single FlexFEC ssrc and that
2434 // there is no FEC-FR ssrc + grouping for each.
2435 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
2436 ASSERT_TRUE(offer.get() != nullptr);
2437 VideoContentDescription* desc = static_cast<VideoContentDescription*>(
2438 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
2439 ASSERT_TRUE(desc != nullptr);
2440 EXPECT_TRUE(desc->multistream());
2441 const StreamParamsVec& streams = desc->streams();
2442 // Single stream.
2443 ASSERT_EQ(1u, streams.size());
2444 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
2445 EXPECT_EQ(2u, streams[0].ssrcs.size());
2446 // And should have a FEC-FR group for FlexFEC.
2447 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
2448 std::vector<uint32_t> primary_ssrcs;
2449 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2450 ASSERT_EQ(1u, primary_ssrcs.size());
2451 uint32_t flexfec_ssrc;
2452 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
2453 EXPECT_NE(flexfec_ssrc, 0u);
2454}
2455
2456// Test that FlexFEC is disabled for simulcast.
2457// TODO(brandtr): Remove this test when we support simulcast, either through
2458// multiple FlexfecSenders, or through multistream protection.
2459TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
2460 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002461 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_SENDRECV, kActive,
2462 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002463 // Add simulcast streams.
zhihuang1c378ed2017-08-17 14:10:50 -07002464 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002465 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002466
2467 // Use a single real codec, and then add FlexFEC for it.
2468 std::vector<VideoCodec> f1_codecs;
2469 f1_codecs.push_back(VideoCodec(97, "H264"));
2470 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2471 f1_.set_video_codecs(f1_codecs);
2472
2473 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
2474 // there is no FEC-FR ssrc + grouping for each.
2475 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
2476 ASSERT_TRUE(offer.get() != nullptr);
2477 VideoContentDescription* desc = static_cast<VideoContentDescription*>(
2478 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
2479 ASSERT_TRUE(desc != nullptr);
2480 EXPECT_FALSE(desc->multistream());
2481 const StreamParamsVec& streams = desc->streams();
2482 // Single stream.
2483 ASSERT_EQ(1u, streams.size());
2484 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
2485 EXPECT_EQ(3u, streams[0].ssrcs.size());
2486 // And should have a SIM group for the simulcast.
2487 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2488 // And not a FEC-FR group for FlexFEC.
2489 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
2490 std::vector<uint32_t> primary_ssrcs;
2491 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2492 EXPECT_EQ(3u, primary_ssrcs.size());
2493 for (uint32_t primary_ssrc : primary_ssrcs) {
2494 uint32_t flexfec_ssrc;
2495 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
2496 }
2497}
2498
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002499// Create an updated offer after creating an answer to the original offer and
2500// verify that the RTP header extensions that were part of the original answer
2501// are not changed in the updated offer.
2502TEST_F(MediaSessionDescriptionFactoryTest,
2503 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
2504 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002505 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002506
2507 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
2508 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
2509 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
2510 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
2511
kwiberg31022942016-03-11 14:18:21 -08002512 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2513 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002514 f2_.CreateAnswer(offer.get(), opts, NULL));
2515
2516 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
2517 GetFirstAudioContentDescription(
2518 answer.get())->rtp_header_extensions());
2519 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
2520 GetFirstVideoContentDescription(
2521 answer.get())->rtp_header_extensions());
2522
kwiberg31022942016-03-11 14:18:21 -08002523 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002524 f2_.CreateOffer(opts, answer.get()));
2525
2526 // The expected RTP header extensions in the new offer are the resulting
2527 // extensions from the first offer/answer exchange plus the extensions only
2528 // |f2_| offer.
2529 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002530 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07002531 const RtpExtension kUpdatedAudioRtpExtensions[] = {
2532 kAudioRtpExtensionAnswer[0], RtpExtension(kAudioRtpExtension2[1].uri, 13),
2533 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002534 };
2535
2536 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002537 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07002538 const RtpExtension kUpdatedVideoRtpExtensions[] = {
2539 kVideoRtpExtensionAnswer[0], RtpExtension(kVideoRtpExtension2[1].uri, 12),
2540 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002541 };
2542
2543 const AudioContentDescription* updated_acd =
2544 GetFirstAudioContentDescription(updated_offer.get());
2545 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
2546 updated_acd->rtp_header_extensions());
2547
2548 const VideoContentDescription* updated_vcd =
2549 GetFirstVideoContentDescription(updated_offer.get());
2550 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
2551 updated_vcd->rtp_header_extensions());
2552}
2553
deadbeefa5b273a2015-08-20 17:30:13 -07002554// Verify that if the same RTP extension URI is used for audio and video, the
2555// same ID is used. Also verify that the ID isn't changed when creating an
2556// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07002557TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07002558 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002559 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07002560
2561 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
2562 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
2563
kwiberg31022942016-03-11 14:18:21 -08002564 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
deadbeefa5b273a2015-08-20 17:30:13 -07002565
2566 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
2567 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07002568 const RtpExtension kExpectedVideoRtpExtension[] = {
2569 kVideoRtpExtension3[0], kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07002570 };
2571
2572 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
2573 GetFirstAudioContentDescription(
2574 offer.get())->rtp_header_extensions());
2575 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2576 GetFirstVideoContentDescription(
2577 offer.get())->rtp_header_extensions());
2578
2579 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08002580 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07002581 f1_.CreateOffer(opts, offer.get()));
2582
2583 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
2584 GetFirstAudioContentDescription(
2585 updated_offer.get())->rtp_header_extensions());
2586 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2587 GetFirstVideoContentDescription(
2588 updated_offer.get())->rtp_header_extensions());
2589}
2590
jbauch5869f502017-06-29 12:31:36 -07002591// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
2592TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
2593 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002594 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
jbauch5869f502017-06-29 12:31:36 -07002595
2596 f1_.set_enable_encrypted_rtp_header_extensions(true);
2597 f2_.set_enable_encrypted_rtp_header_extensions(true);
2598
2599 f1_.set_audio_rtp_header_extensions(
2600 MAKE_VECTOR(kAudioRtpExtension3ForEncryption));
2601 f1_.set_video_rtp_header_extensions(
2602 MAKE_VECTOR(kVideoRtpExtension3ForEncryption));
2603
2604 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2605
2606 // The extensions that are shared between audio and video should use the same
2607 // id.
2608 const RtpExtension kExpectedVideoRtpExtension[] = {
2609 kVideoRtpExtension3ForEncryption[0],
2610 kAudioRtpExtension3ForEncryptionOffer[1],
2611 kAudioRtpExtension3ForEncryptionOffer[2],
2612 };
2613
2614 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
2615 GetFirstAudioContentDescription(
2616 offer.get())->rtp_header_extensions());
2617 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2618 GetFirstVideoContentDescription(
2619 offer.get())->rtp_header_extensions());
2620
2621 // Nothing should change when creating a new offer
2622 std::unique_ptr<SessionDescription> updated_offer(
2623 f1_.CreateOffer(opts, offer.get()));
2624
2625 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
2626 GetFirstAudioContentDescription(
2627 updated_offer.get())->rtp_header_extensions());
2628 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2629 GetFirstVideoContentDescription(
2630 updated_offer.get())->rtp_header_extensions());
2631}
2632
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002633TEST(MediaSessionDescription, CopySessionDescription) {
2634 SessionDescription source;
2635 cricket::ContentGroup group(cricket::CN_AUDIO);
2636 source.AddGroup(group);
2637 AudioContentDescription* acd(new AudioContentDescription());
2638 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
2639 acd->AddLegacyStream(1);
2640 source.AddContent(cricket::CN_AUDIO, cricket::NS_JINGLE_RTP, acd);
2641 VideoContentDescription* vcd(new VideoContentDescription());
2642 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
2643 vcd->AddLegacyStream(2);
2644 source.AddContent(cricket::CN_VIDEO, cricket::NS_JINGLE_RTP, vcd);
2645
kwiberg31022942016-03-11 14:18:21 -08002646 std::unique_ptr<SessionDescription> copy(source.Copy());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002647 ASSERT_TRUE(copy.get() != NULL);
2648 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
2649 const ContentInfo* ac = copy->GetContentByName("audio");
2650 const ContentInfo* vc = copy->GetContentByName("video");
2651 ASSERT_TRUE(ac != NULL);
2652 ASSERT_TRUE(vc != NULL);
2653 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
2654 const AudioContentDescription* acd_copy =
2655 static_cast<const AudioContentDescription*>(ac->description);
2656 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
2657 EXPECT_EQ(1u, acd->first_ssrc());
2658
2659 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
2660 const VideoContentDescription* vcd_copy =
2661 static_cast<const VideoContentDescription*>(vc->description);
2662 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
2663 EXPECT_EQ(2u, vcd->first_ssrc());
2664}
2665
2666// The below TestTransportInfoXXX tests create different offers/answers, and
2667// ensure the TransportInfo in the SessionDescription matches what we expect.
2668TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
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(true, options, false);
2673}
2674
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002675TEST_F(MediaSessionDescriptionFactoryTest,
2676 TestTransportInfoOfferIceRenomination) {
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(true, options, false);
2683}
2684
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002685TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
2686 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002687 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
2688 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002689 TestTransportInfo(true, options, true);
2690}
2691
2692TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
2693 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002694 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2695 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002696 TestTransportInfo(true, options, false);
2697}
2698
2699TEST_F(MediaSessionDescriptionFactoryTest,
2700 TestTransportInfoOfferMultimediaCurrent) {
2701 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002702 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2703 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002704 TestTransportInfo(true, options, true);
2705}
2706
2707TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
2708 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002709 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2710 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002711 options.bundle_enabled = true;
2712 TestTransportInfo(true, options, false);
2713}
2714
2715TEST_F(MediaSessionDescriptionFactoryTest,
2716 TestTransportInfoOfferBundleCurrent) {
2717 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002718 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2719 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002720 options.bundle_enabled = true;
2721 TestTransportInfo(true, options, true);
2722}
2723
2724TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
2725 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002726 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
2727 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002728 TestTransportInfo(false, options, false);
2729}
2730
2731TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002732 TestTransportInfoAnswerIceRenomination) {
2733 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002734 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
2735 &options);
2736 options.media_description_options[0]
2737 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002738 TestTransportInfo(false, options, false);
2739}
2740
2741TEST_F(MediaSessionDescriptionFactoryTest,
2742 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002743 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002744 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
2745 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002746 TestTransportInfo(false, options, true);
2747}
2748
2749TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
2750 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002751 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2752 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002753 TestTransportInfo(false, options, false);
2754}
2755
2756TEST_F(MediaSessionDescriptionFactoryTest,
2757 TestTransportInfoAnswerMultimediaCurrent) {
2758 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002759 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2760 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002761 TestTransportInfo(false, options, true);
2762}
2763
2764TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
2765 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002766 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2767 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002768 options.bundle_enabled = true;
2769 TestTransportInfo(false, options, false);
2770}
2771
2772TEST_F(MediaSessionDescriptionFactoryTest,
2773 TestTransportInfoAnswerBundleCurrent) {
2774 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002775 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2776 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002777 options.bundle_enabled = true;
2778 TestTransportInfo(false, options, true);
2779}
2780
2781// Create an offer with bundle enabled and verify the crypto parameters are
2782// the common set of the available cryptos.
2783TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
2784 TestCryptoWithBundle(true);
2785}
2786
2787// Create an answer with bundle enabled and verify the crypto parameters are
2788// the common set of the available cryptos.
2789TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
2790 TestCryptoWithBundle(false);
2791}
2792
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002793// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
2794// DTLS is not enabled locally.
2795TEST_F(MediaSessionDescriptionFactoryTest,
2796 TestOfferDtlsSavpfWithoutDtlsFailed) {
2797 f1_.set_secure(SEC_ENABLED);
2798 f2_.set_secure(SEC_ENABLED);
2799 tdf1_.set_secure(SEC_DISABLED);
2800 tdf2_.set_secure(SEC_DISABLED);
2801
kwiberg31022942016-03-11 14:18:21 -08002802 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -07002803 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002804 ASSERT_TRUE(offer.get() != NULL);
2805 ContentInfo* offer_content = offer->GetContentByName("audio");
2806 ASSERT_TRUE(offer_content != NULL);
2807 AudioContentDescription* offer_audio_desc =
2808 static_cast<AudioContentDescription*>(offer_content->description);
2809 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2810
kwiberg31022942016-03-11 14:18:21 -08002811 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002812 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002813 ASSERT_TRUE(answer != NULL);
2814 ContentInfo* answer_content = answer->GetContentByName("audio");
2815 ASSERT_TRUE(answer_content != NULL);
2816
2817 ASSERT_TRUE(answer_content->rejected);
2818}
2819
2820// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
2821// UDP/TLS/RTP/SAVPF.
2822TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
2823 f1_.set_secure(SEC_ENABLED);
2824 f2_.set_secure(SEC_ENABLED);
2825 tdf1_.set_secure(SEC_ENABLED);
2826 tdf2_.set_secure(SEC_ENABLED);
2827
kwiberg31022942016-03-11 14:18:21 -08002828 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -07002829 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002830 ASSERT_TRUE(offer.get() != NULL);
2831 ContentInfo* offer_content = offer->GetContentByName("audio");
2832 ASSERT_TRUE(offer_content != NULL);
2833 AudioContentDescription* offer_audio_desc =
2834 static_cast<AudioContentDescription*>(offer_content->description);
2835 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2836
kwiberg31022942016-03-11 14:18:21 -08002837 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002838 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002839 ASSERT_TRUE(answer != NULL);
2840
2841 const ContentInfo* answer_content = answer->GetContentByName("audio");
2842 ASSERT_TRUE(answer_content != NULL);
2843 ASSERT_FALSE(answer_content->rejected);
2844
2845 const AudioContentDescription* answer_audio_desc =
2846 static_cast<const AudioContentDescription*>(answer_content->description);
2847 EXPECT_EQ(std::string(cricket::kMediaProtocolDtlsSavpf),
2848 answer_audio_desc->protocol());
2849}
2850
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002851// Test that we include both SDES and DTLS in the offer, but only include SDES
2852// in the answer if DTLS isn't negotiated.
2853TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
2854 f1_.set_secure(SEC_ENABLED);
2855 f2_.set_secure(SEC_ENABLED);
2856 tdf1_.set_secure(SEC_ENABLED);
2857 tdf2_.set_secure(SEC_DISABLED);
2858 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002859 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
kwiberg31022942016-03-11 14:18:21 -08002860 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002861 const cricket::MediaContentDescription* audio_media_desc;
2862 const cricket::MediaContentDescription* video_media_desc;
2863 const cricket::TransportDescription* audio_trans_desc;
2864 const cricket::TransportDescription* video_trans_desc;
2865
2866 // Generate an offer with SDES and DTLS support.
2867 offer.reset(f1_.CreateOffer(options, NULL));
2868 ASSERT_TRUE(offer.get() != NULL);
2869
2870 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2871 offer->GetContentDescriptionByName("audio"));
2872 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002873 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002874 offer->GetContentDescriptionByName("video"));
2875 ASSERT_TRUE(video_media_desc != NULL);
2876 EXPECT_EQ(2u, audio_media_desc->cryptos().size());
2877 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2878
2879 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2880 ASSERT_TRUE(audio_trans_desc != NULL);
2881 video_trans_desc = offer->GetTransportDescriptionByName("video");
2882 ASSERT_TRUE(video_trans_desc != NULL);
2883 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2884 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
2885
2886 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
2887 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2888 ASSERT_TRUE(answer.get() != NULL);
2889
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002890 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002891 answer->GetContentDescriptionByName("audio"));
2892 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002893 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002894 answer->GetContentDescriptionByName("video"));
2895 ASSERT_TRUE(video_media_desc != NULL);
2896 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
2897 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2898
2899 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2900 ASSERT_TRUE(audio_trans_desc != NULL);
2901 video_trans_desc = answer->GetTransportDescriptionByName("video");
2902 ASSERT_TRUE(video_trans_desc != NULL);
2903 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
2904 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
2905
2906 // Enable DTLS; the answer should now only have DTLS support.
2907 tdf2_.set_secure(SEC_ENABLED);
2908 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2909 ASSERT_TRUE(answer.get() != NULL);
2910
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002911 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002912 answer->GetContentDescriptionByName("audio"));
2913 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002914 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002915 answer->GetContentDescriptionByName("video"));
2916 ASSERT_TRUE(video_media_desc != NULL);
2917 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2918 EXPECT_TRUE(video_media_desc->cryptos().empty());
2919 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2920 audio_media_desc->protocol());
2921 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2922 video_media_desc->protocol());
2923
2924 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2925 ASSERT_TRUE(audio_trans_desc != NULL);
2926 video_trans_desc = answer->GetTransportDescriptionByName("video");
2927 ASSERT_TRUE(video_trans_desc != NULL);
2928 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2929 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00002930
2931 // Try creating offer again. DTLS enabled now, crypto's should be empty
2932 // in new offer.
2933 offer.reset(f1_.CreateOffer(options, offer.get()));
2934 ASSERT_TRUE(offer.get() != NULL);
2935 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2936 offer->GetContentDescriptionByName("audio"));
2937 ASSERT_TRUE(audio_media_desc != NULL);
2938 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
2939 offer->GetContentDescriptionByName("video"));
2940 ASSERT_TRUE(video_media_desc != NULL);
2941 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2942 EXPECT_TRUE(video_media_desc->cryptos().empty());
2943
2944 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2945 ASSERT_TRUE(audio_trans_desc != NULL);
2946 video_trans_desc = offer->GetTransportDescriptionByName("video");
2947 ASSERT_TRUE(video_trans_desc != NULL);
2948 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2949 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002950}
2951
2952// Test that an answer can't be created if cryptos are required but the offer is
2953// unsecure.
2954TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07002955 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002956 f1_.set_secure(SEC_DISABLED);
2957 tdf1_.set_secure(SEC_DISABLED);
2958 f2_.set_secure(SEC_REQUIRED);
2959 tdf1_.set_secure(SEC_ENABLED);
2960
kwiberg31022942016-03-11 14:18:21 -08002961 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002962 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002963 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002964 f2_.CreateAnswer(offer.get(), options, NULL));
2965 EXPECT_TRUE(answer.get() == NULL);
2966}
2967
2968// Test that we accept a DTLS offer without SDES and create an appropriate
2969// answer.
2970TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
2971 f1_.set_secure(SEC_DISABLED);
2972 f2_.set_secure(SEC_ENABLED);
2973 tdf1_.set_secure(SEC_ENABLED);
2974 tdf2_.set_secure(SEC_ENABLED);
2975 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002976 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2977 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002978
kwiberg31022942016-03-11 14:18:21 -08002979 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002980
2981 // Generate an offer with DTLS but without SDES.
2982 offer.reset(f1_.CreateOffer(options, NULL));
2983 ASSERT_TRUE(offer.get() != NULL);
2984
2985 const AudioContentDescription* audio_offer =
2986 GetFirstAudioContentDescription(offer.get());
2987 ASSERT_TRUE(audio_offer->cryptos().empty());
2988 const VideoContentDescription* video_offer =
2989 GetFirstVideoContentDescription(offer.get());
2990 ASSERT_TRUE(video_offer->cryptos().empty());
2991 const DataContentDescription* data_offer =
2992 GetFirstDataContentDescription(offer.get());
2993 ASSERT_TRUE(data_offer->cryptos().empty());
2994
2995 const cricket::TransportDescription* audio_offer_trans_desc =
2996 offer->GetTransportDescriptionByName("audio");
2997 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
2998 const cricket::TransportDescription* video_offer_trans_desc =
2999 offer->GetTransportDescriptionByName("video");
3000 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
3001 const cricket::TransportDescription* data_offer_trans_desc =
3002 offer->GetTransportDescriptionByName("data");
3003 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
3004
3005 // Generate an answer with DTLS.
3006 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
3007 ASSERT_TRUE(answer.get() != NULL);
3008
3009 const cricket::TransportDescription* audio_answer_trans_desc =
3010 answer->GetTransportDescriptionByName("audio");
3011 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3012 const cricket::TransportDescription* video_answer_trans_desc =
3013 answer->GetTransportDescriptionByName("video");
3014 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
3015 const cricket::TransportDescription* data_answer_trans_desc =
3016 answer->GetTransportDescriptionByName("data");
3017 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
3018}
3019
3020// Verifies if vad_enabled option is set to false, CN codecs are not present in
3021// offer or answer.
3022TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3023 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07003024 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
kwiberg31022942016-03-11 14:18:21 -08003025 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003026 ASSERT_TRUE(offer.get() != NULL);
3027 const ContentInfo* audio_content = offer->GetContentByName("audio");
3028 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
3029
3030 options.vad_enabled = false;
3031 offer.reset(f1_.CreateOffer(options, NULL));
3032 ASSERT_TRUE(offer.get() != NULL);
3033 audio_content = offer->GetContentByName("audio");
3034 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
kwiberg31022942016-03-11 14:18:21 -08003035 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003036 f1_.CreateAnswer(offer.get(), options, NULL));
3037 ASSERT_TRUE(answer.get() != NULL);
3038 audio_content = answer->GetContentByName("audio");
3039 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
3040}
deadbeef44f08192015-12-15 16:20:09 -08003041
zhihuang1c378ed2017-08-17 14:10:50 -07003042// Test that the generated MIDs match the existing offer.
3043TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08003044 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003045 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_modified", cricket::MD_RECVONLY,
3046 kActive, &opts);
3047 AddMediaSection(MEDIA_TYPE_VIDEO, "video_modified", cricket::MD_RECVONLY,
3048 kActive, &opts);
deadbeef44f08192015-12-15 16:20:09 -08003049 opts.data_channel_type = cricket::DCT_SCTP;
zhihuang1c378ed2017-08-17 14:10:50 -07003050 AddMediaSection(MEDIA_TYPE_DATA, "data_modified", cricket::MD_SENDRECV,
3051 kActive, &opts);
3052 // Create offer.
kwiberg31022942016-03-11 14:18:21 -08003053 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
kwiberg31022942016-03-11 14:18:21 -08003054 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08003055 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003056
deadbeef44f08192015-12-15 16:20:09 -08003057 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3058 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3059 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3060 ASSERT_TRUE(audio_content != nullptr);
3061 ASSERT_TRUE(video_content != nullptr);
3062 ASSERT_TRUE(data_content != nullptr);
3063 EXPECT_EQ("audio_modified", audio_content->name);
3064 EXPECT_EQ("video_modified", video_content->name);
3065 EXPECT_EQ("data_modified", data_content->name);
3066}
zhihuangcf5b37c2016-05-05 11:44:35 -07003067
zhihuang1c378ed2017-08-17 14:10:50 -07003068// The following tests verify that the unified plan SDP is supported.
3069// Test that we can create an offer with multiple media sections of same media
3070// type.
3071TEST_F(MediaSessionDescriptionFactoryTest,
3072 CreateOfferWithMultipleAVMediaSections) {
3073 MediaSessionOptions opts;
3074 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_1", cricket::MD_SENDRECV, kActive,
3075 &opts);
3076 AttachSenderToMediaSection("audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003077 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003078
3079 AddMediaSection(MEDIA_TYPE_VIDEO, "video_1", cricket::MD_SENDRECV, kActive,
3080 &opts);
3081 AttachSenderToMediaSection("video_1", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003082 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003083
3084 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_2", cricket::MD_SENDRECV, kActive,
3085 &opts);
3086 AttachSenderToMediaSection("audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003087 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003088
3089 AddMediaSection(MEDIA_TYPE_VIDEO, "video_2", cricket::MD_SENDRECV, kActive,
3090 &opts);
3091 AttachSenderToMediaSection("video_2", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003092 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003093 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3094 ASSERT_TRUE(offer);
3095
3096 ASSERT_EQ(4u, offer->contents().size());
3097 EXPECT_FALSE(offer->contents()[0].rejected);
3098 const AudioContentDescription* acd =
3099 static_cast<const AudioContentDescription*>(
3100 offer->contents()[0].description);
3101 ASSERT_EQ(1u, acd->streams().size());
3102 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
3103 EXPECT_EQ(cricket::MD_SENDRECV, acd->direction());
3104
3105 EXPECT_FALSE(offer->contents()[1].rejected);
3106 const VideoContentDescription* vcd =
3107 static_cast<const VideoContentDescription*>(
3108 offer->contents()[1].description);
3109 ASSERT_EQ(1u, vcd->streams().size());
3110 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
3111 EXPECT_EQ(cricket::MD_SENDRECV, vcd->direction());
3112
3113 EXPECT_FALSE(offer->contents()[2].rejected);
3114 acd = static_cast<const AudioContentDescription*>(
3115 offer->contents()[2].description);
3116 ASSERT_EQ(1u, acd->streams().size());
3117 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
3118 EXPECT_EQ(cricket::MD_SENDRECV, acd->direction());
3119
3120 EXPECT_FALSE(offer->contents()[3].rejected);
3121 vcd = static_cast<const VideoContentDescription*>(
3122 offer->contents()[3].description);
3123 ASSERT_EQ(1u, vcd->streams().size());
3124 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
3125 EXPECT_EQ(cricket::MD_SENDRECV, vcd->direction());
3126}
3127
3128// Test that we can create an answer with multiple media sections of same media
3129// type.
3130TEST_F(MediaSessionDescriptionFactoryTest,
3131 CreateAnswerWithMultipleAVMediaSections) {
3132 MediaSessionOptions opts;
3133 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_1", cricket::MD_SENDRECV, kActive,
3134 &opts);
3135 AttachSenderToMediaSection("audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003136 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003137
3138 AddMediaSection(MEDIA_TYPE_VIDEO, "video_1", cricket::MD_SENDRECV, kActive,
3139 &opts);
3140 AttachSenderToMediaSection("video_1", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003141 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003142
3143 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_2", cricket::MD_SENDRECV, kActive,
3144 &opts);
3145 AttachSenderToMediaSection("audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003146 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003147
3148 AddMediaSection(MEDIA_TYPE_VIDEO, "video_2", cricket::MD_SENDRECV, kActive,
3149 &opts);
3150 AttachSenderToMediaSection("video_2", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003151 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003152
3153 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3154 ASSERT_TRUE(offer);
3155 std::unique_ptr<SessionDescription> answer(
3156 f2_.CreateAnswer(offer.get(), opts, nullptr));
3157
3158 ASSERT_EQ(4u, answer->contents().size());
3159 EXPECT_FALSE(answer->contents()[0].rejected);
3160 const AudioContentDescription* acd =
3161 static_cast<const AudioContentDescription*>(
3162 answer->contents()[0].description);
3163 ASSERT_EQ(1u, acd->streams().size());
3164 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
3165 EXPECT_EQ(cricket::MD_SENDRECV, acd->direction());
3166
3167 EXPECT_FALSE(answer->contents()[1].rejected);
3168 const VideoContentDescription* vcd =
3169 static_cast<const VideoContentDescription*>(
3170 answer->contents()[1].description);
3171 ASSERT_EQ(1u, vcd->streams().size());
3172 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
3173 EXPECT_EQ(cricket::MD_SENDRECV, vcd->direction());
3174
3175 EXPECT_FALSE(answer->contents()[2].rejected);
3176 acd = static_cast<const AudioContentDescription*>(
3177 answer->contents()[2].description);
3178 ASSERT_EQ(1u, acd->streams().size());
3179 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
3180 EXPECT_EQ(cricket::MD_SENDRECV, acd->direction());
3181
3182 EXPECT_FALSE(answer->contents()[3].rejected);
3183 vcd = static_cast<const VideoContentDescription*>(
3184 answer->contents()[3].description);
3185 ASSERT_EQ(1u, vcd->streams().size());
3186 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
3187 EXPECT_EQ(cricket::MD_SENDRECV, vcd->direction());
3188}
3189
3190// Test that the media section will be rejected in offer if the corresponding
3191// MediaDescriptionOptions is stopped by the offerer.
3192TEST_F(MediaSessionDescriptionFactoryTest,
3193 CreateOfferWithMediaSectionStoppedByOfferer) {
3194 // Create an offer with two audio sections and one of them is stopped.
3195 MediaSessionOptions offer_opts;
3196 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1", cricket::MD_SENDRECV, kActive,
3197 &offer_opts);
3198 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2", cricket::MD_INACTIVE, kStopped,
3199 &offer_opts);
3200 std::unique_ptr<SessionDescription> offer(
3201 f1_.CreateOffer(offer_opts, nullptr));
3202 ASSERT_TRUE(offer);
3203 ASSERT_EQ(2u, offer->contents().size());
3204 EXPECT_FALSE(offer->contents()[0].rejected);
3205 EXPECT_TRUE(offer->contents()[1].rejected);
3206}
3207
3208// Test that the media section will be rejected in answer if the corresponding
3209// MediaDescriptionOptions is stopped by the offerer.
3210TEST_F(MediaSessionDescriptionFactoryTest,
3211 CreateAnswerWithMediaSectionStoppedByOfferer) {
3212 // Create an offer with two audio sections and one of them is stopped.
3213 MediaSessionOptions offer_opts;
3214 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1", cricket::MD_SENDRECV, kActive,
3215 &offer_opts);
3216 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2", cricket::MD_INACTIVE, kStopped,
3217 &offer_opts);
3218 std::unique_ptr<SessionDescription> offer(
3219 f1_.CreateOffer(offer_opts, nullptr));
3220 ASSERT_TRUE(offer);
3221 ASSERT_EQ(2u, offer->contents().size());
3222 EXPECT_FALSE(offer->contents()[0].rejected);
3223 EXPECT_TRUE(offer->contents()[1].rejected);
3224
3225 // Create an answer based on the offer.
3226 MediaSessionOptions answer_opts;
3227 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1", cricket::MD_SENDRECV, kActive,
3228 &answer_opts);
3229 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2", cricket::MD_SENDRECV, kActive,
3230 &answer_opts);
3231 std::unique_ptr<SessionDescription> answer(
3232 f2_.CreateAnswer(offer.get(), answer_opts, nullptr));
3233 ASSERT_EQ(2u, answer->contents().size());
3234 EXPECT_FALSE(answer->contents()[0].rejected);
3235 EXPECT_TRUE(answer->contents()[1].rejected);
3236}
3237
3238// Test that the media section will be rejected in answer if the corresponding
3239// MediaDescriptionOptions is stopped by the answerer.
3240TEST_F(MediaSessionDescriptionFactoryTest,
3241 CreateAnswerWithMediaSectionRejectedByAnswerer) {
3242 // Create an offer with two audio sections.
3243 MediaSessionOptions offer_opts;
3244 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1", cricket::MD_SENDRECV, kActive,
3245 &offer_opts);
3246 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2", cricket::MD_SENDRECV, kActive,
3247 &offer_opts);
3248 std::unique_ptr<SessionDescription> offer(
3249 f1_.CreateOffer(offer_opts, nullptr));
3250 ASSERT_TRUE(offer);
3251 ASSERT_EQ(2u, offer->contents().size());
3252 ASSERT_FALSE(offer->contents()[0].rejected);
3253 ASSERT_FALSE(offer->contents()[1].rejected);
3254
3255 // The answerer rejects one of the audio sections.
3256 MediaSessionOptions answer_opts;
3257 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1", cricket::MD_SENDRECV, kActive,
3258 &answer_opts);
3259 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2", cricket::MD_INACTIVE, kStopped,
3260 &answer_opts);
3261 std::unique_ptr<SessionDescription> answer(
3262 f2_.CreateAnswer(offer.get(), answer_opts, nullptr));
3263 ASSERT_EQ(2u, answer->contents().size());
3264 EXPECT_FALSE(answer->contents()[0].rejected);
3265 EXPECT_TRUE(answer->contents()[1].rejected);
3266}
3267
3268// Test the generated media sections has the same order of the
3269// corresponding MediaDescriptionOptions.
3270TEST_F(MediaSessionDescriptionFactoryTest,
3271 CreateOfferRespectsMediaDescriptionOptionsOrder) {
3272 MediaSessionOptions opts;
3273 // This tests put video section first because normally audio comes first by
3274 // default.
3275 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_SENDRECV, kActive,
3276 &opts);
3277 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_SENDRECV, kActive,
3278 &opts);
3279 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3280
3281 ASSERT_TRUE(offer);
3282 ASSERT_EQ(2u, offer->contents().size());
3283 EXPECT_EQ("video", offer->contents()[0].name);
3284 EXPECT_EQ("audio", offer->contents()[1].name);
3285}
3286
3287// Test that different media sections using the same codec have same payload
3288// type.
3289TEST_F(MediaSessionDescriptionFactoryTest,
3290 PayloadTypesSharedByMediaSectionsOfSameType) {
3291 MediaSessionOptions opts;
3292 AddMediaSection(MEDIA_TYPE_VIDEO, "video1", cricket::MD_SENDRECV, kActive,
3293 &opts);
3294 AddMediaSection(MEDIA_TYPE_VIDEO, "video2", cricket::MD_SENDRECV, kActive,
3295 &opts);
3296 // Create an offer with two video sections using same codecs.
3297 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3298 ASSERT_TRUE(offer);
3299 ASSERT_EQ(2u, offer->contents().size());
3300 const VideoContentDescription* vcd1 =
3301 static_cast<const VideoContentDescription*>(
3302 offer->contents()[0].description);
3303 const VideoContentDescription* vcd2 =
3304 static_cast<const VideoContentDescription*>(
3305 offer->contents()[1].description);
3306 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3307 ASSERT_EQ(2u, vcd1->codecs().size());
3308 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3309 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3310 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
3311 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
3312
3313 // Create answer and negotiate the codecs.
3314 std::unique_ptr<SessionDescription> answer(
3315 f2_.CreateAnswer(offer.get(), opts, nullptr));
3316 ASSERT_TRUE(answer);
3317 ASSERT_EQ(2u, answer->contents().size());
3318 vcd1 = static_cast<const VideoContentDescription*>(
3319 answer->contents()[0].description);
3320 vcd2 = static_cast<const VideoContentDescription*>(
3321 answer->contents()[1].description);
3322 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3323 ASSERT_EQ(1u, vcd1->codecs().size());
3324 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3325 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3326}
3327
3328// Test that the codec preference order per media section is respected in
3329// subsequent offer.
3330TEST_F(MediaSessionDescriptionFactoryTest,
3331 CreateOfferRespectsCodecPreferenceOrder) {
3332 MediaSessionOptions opts;
3333 AddMediaSection(MEDIA_TYPE_VIDEO, "video1", cricket::MD_SENDRECV, kActive,
3334 &opts);
3335 AddMediaSection(MEDIA_TYPE_VIDEO, "video2", cricket::MD_SENDRECV, kActive,
3336 &opts);
3337 // Create an offer with two video sections using same codecs.
3338 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3339 ASSERT_TRUE(offer);
3340 ASSERT_EQ(2u, offer->contents().size());
3341 VideoContentDescription* vcd1 =
3342 static_cast<VideoContentDescription*>(offer->contents()[0].description);
3343 const VideoContentDescription* vcd2 =
3344 static_cast<const VideoContentDescription*>(
3345 offer->contents()[1].description);
3346 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3347 EXPECT_EQ(video_codecs, vcd1->codecs());
3348 EXPECT_EQ(video_codecs, vcd2->codecs());
3349
3350 // Change the codec preference of the first video section and create a
3351 // follow-up offer.
3352 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3353 vcd1->set_codecs(video_codecs_reverse);
3354 std::unique_ptr<SessionDescription> updated_offer(
3355 f1_.CreateOffer(opts, offer.get()));
3356 vcd1 = static_cast<VideoContentDescription*>(
3357 updated_offer->contents()[0].description);
3358 vcd2 = static_cast<const VideoContentDescription*>(
3359 updated_offer->contents()[1].description);
3360 // The video codec preference order should be respected.
3361 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3362 EXPECT_EQ(video_codecs, vcd2->codecs());
3363}
3364
3365// Test that the codec preference order per media section is respected in
3366// the answer.
3367TEST_F(MediaSessionDescriptionFactoryTest,
3368 CreateAnswerRespectsCodecPreferenceOrder) {
3369 MediaSessionOptions opts;
3370 AddMediaSection(MEDIA_TYPE_VIDEO, "video1", cricket::MD_SENDRECV, kActive,
3371 &opts);
3372 AddMediaSection(MEDIA_TYPE_VIDEO, "video2", cricket::MD_SENDRECV, kActive,
3373 &opts);
3374 // Create an offer with two video sections using same codecs.
3375 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3376 ASSERT_TRUE(offer);
3377 ASSERT_EQ(2u, offer->contents().size());
3378 VideoContentDescription* vcd1 =
3379 static_cast<VideoContentDescription*>(offer->contents()[0].description);
3380 const VideoContentDescription* vcd2 =
3381 static_cast<const VideoContentDescription*>(
3382 offer->contents()[1].description);
3383 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3384 EXPECT_EQ(video_codecs, vcd1->codecs());
3385 EXPECT_EQ(video_codecs, vcd2->codecs());
3386
3387 // Change the codec preference of the first video section and create an
3388 // answer.
3389 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3390 vcd1->set_codecs(video_codecs_reverse);
3391 std::unique_ptr<SessionDescription> answer(
3392 f1_.CreateAnswer(offer.get(), opts, nullptr));
3393 vcd1 =
3394 static_cast<VideoContentDescription*>(answer->contents()[0].description);
3395 vcd2 = static_cast<const VideoContentDescription*>(
3396 answer->contents()[1].description);
3397 // The video codec preference order should be respected.
3398 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3399 EXPECT_EQ(video_codecs, vcd2->codecs());
3400}
3401
zhihuangcf5b37c2016-05-05 11:44:35 -07003402class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
3403 public:
3404 MediaProtocolTest() : f1_(&tdf1_), f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -07003405 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
3406 MAKE_VECTOR(kAudioCodecs1));
zhihuangcf5b37c2016-05-05 11:44:35 -07003407 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
3408 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07003409 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
3410 MAKE_VECTOR(kAudioCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07003411 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
3412 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
3413 f1_.set_secure(SEC_ENABLED);
3414 f2_.set_secure(SEC_ENABLED);
3415 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07003416 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07003417 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07003418 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07003419 tdf1_.set_secure(SEC_ENABLED);
3420 tdf2_.set_secure(SEC_ENABLED);
3421 }
3422
3423 protected:
3424 MediaSessionDescriptionFactory f1_;
3425 MediaSessionDescriptionFactory f2_;
3426 TransportDescriptionFactory tdf1_;
3427 TransportDescriptionFactory tdf2_;
3428};
3429
3430TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
3431 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003432 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
zhihuangcf5b37c2016-05-05 11:44:35 -07003433 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3434 ASSERT_TRUE(offer.get() != nullptr);
3435 // Set the protocol for all the contents.
3436 for (auto content : offer.get()->contents()) {
3437 static_cast<MediaContentDescription*>(content.description)
3438 ->set_protocol(GetParam());
3439 }
3440 std::unique_ptr<SessionDescription> answer(
3441 f2_.CreateAnswer(offer.get(), opts, nullptr));
3442 const ContentInfo* ac = answer->GetContentByName("audio");
3443 const ContentInfo* vc = answer->GetContentByName("video");
3444 ASSERT_TRUE(ac != nullptr);
3445 ASSERT_TRUE(vc != nullptr);
3446 EXPECT_FALSE(ac->rejected); // the offer is accepted
3447 EXPECT_FALSE(vc->rejected);
3448 const AudioContentDescription* acd =
3449 static_cast<const AudioContentDescription*>(ac->description);
3450 const VideoContentDescription* vcd =
3451 static_cast<const VideoContentDescription*>(vc->description);
3452 EXPECT_EQ(GetParam(), acd->protocol());
3453 EXPECT_EQ(GetParam(), vcd->protocol());
3454}
3455
3456INSTANTIATE_TEST_CASE_P(MediaProtocolPatternTest,
3457 MediaProtocolTest,
3458 ::testing::ValuesIn(kMediaProtocols));
3459INSTANTIATE_TEST_CASE_P(MediaProtocolDtlsPatternTest,
3460 MediaProtocolTest,
3461 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07003462
3463TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
3464 TransportDescriptionFactory tdf;
3465 MediaSessionDescriptionFactory sf(&tdf);
3466 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
3467 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
3468
3469 // The merged list of codecs should contain any send codecs that are also
3470 // nominally in the recieve codecs list. Payload types should be picked from
3471 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
3472 // (set to 1). This equals what happens when the send codecs are used in an
3473 // offer and the receive codecs are used in the following answer.
3474 const std::vector<AudioCodec> sendrecv_codecs =
3475 MAKE_VECTOR(kAudioCodecsAnswer);
3476 const std::vector<AudioCodec> no_codecs;
3477
3478 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
3479 << "Please don't change shared test data!";
3480 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
3481 << "Please don't change shared test data!";
3482 // Alter iLBC send codec to have zero channels, to test that that is handled
3483 // properly.
3484 send_codecs[1].channels = 0;
3485
3486 // Alther iLBC receive codec to be lowercase, to test that case conversions
3487 // are handled properly.
3488 recv_codecs[2].name = "ilbc";
3489
3490 // Test proper merge
3491 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003492 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
3493 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
3494 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003495
3496 // Test empty send codecs list
3497 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003498 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
3499 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
3500 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003501
3502 // Test empty recv codecs list
3503 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003504 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
3505 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
3506 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003507
3508 // Test all empty codec lists
3509 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003510 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
3511 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
3512 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003513}
3514
3515namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07003516// Compare the two vectors of codecs ignoring the payload type.
3517template <class Codec>
3518bool CodecsMatch(const std::vector<Codec>& codecs1,
3519 const std::vector<Codec>& codecs2) {
3520 if (codecs1.size() != codecs2.size()) {
3521 return false;
3522 }
3523
3524 for (size_t i = 0; i < codecs1.size(); ++i) {
3525 if (!codecs1[i].Matches(codecs2[i])) {
3526 return false;
3527 }
3528 }
3529 return true;
3530}
3531
3532void TestAudioCodecsOffer(MediaContentDirection direction) {
ossu075af922016-06-14 03:29:38 -07003533 TransportDescriptionFactory tdf;
3534 MediaSessionDescriptionFactory sf(&tdf);
3535 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
3536 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
3537 const std::vector<AudioCodec> sendrecv_codecs =
3538 MAKE_VECTOR(kAudioCodecsAnswer);
3539 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07003540
3541 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003542 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", direction, kActive, &opts);
3543
3544 if (RtpTransceiverDirection::FromMediaContentDirection(direction).send) {
3545 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003546 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003547 }
ossu075af922016-06-14 03:29:38 -07003548
3549 std::unique_ptr<SessionDescription> offer(sf.CreateOffer(opts, NULL));
3550 ASSERT_TRUE(offer.get() != NULL);
3551 const ContentInfo* ac = offer->GetContentByName("audio");
3552
3553 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07003554 // that the codecs put in are right. This happens when we neither want to
3555 // send nor receive audio. The checks are still in place if at some point
3556 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07003557 if (ac) {
3558 AudioContentDescription* acd =
3559 static_cast<AudioContentDescription*>(ac->description);
zhihuang1c378ed2017-08-17 14:10:50 -07003560 // sendrecv and inactive should both present lists as if the channel was
3561 // to be used for sending and receiving. Inactive essentially means it
3562 // might eventually be used anything, but we don't know more at this
3563 // moment.
ossu075af922016-06-14 03:29:38 -07003564 if (acd->direction() == cricket::MD_SENDONLY) {
zhihuang1c378ed2017-08-17 14:10:50 -07003565 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07003566 } else if (acd->direction() == cricket::MD_RECVONLY) {
zhihuang1c378ed2017-08-17 14:10:50 -07003567 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07003568 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07003569 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07003570 }
3571 }
3572}
3573
3574static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07003575 AudioCodec(0, "codec0", 16000, -1, 1),
3576 AudioCodec(1, "codec1", 8000, 13300, 1),
3577 AudioCodec(2, "codec2", 8000, 64000, 1),
3578 AudioCodec(3, "codec3", 8000, 64000, 1),
3579 AudioCodec(4, "codec4", 8000, 0, 2),
3580 AudioCodec(5, "codec5", 32000, 0, 1),
3581 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07003582
zhihuang1c378ed2017-08-17 14:10:50 -07003583/* The codecs groups below are chosen as per the matrix below. The objective
3584 * is to have different sets of codecs in the inputs, to get unique sets of
3585 * codecs after negotiation, depending on offer and answer communication
3586 * directions. One-way directions in the offer should either result in the
3587 * opposite direction in the answer, or an inactive answer. Regardless, the
3588 * choice of codecs should be as if the answer contained the opposite
3589 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07003590 *
3591 * | Offer | Answer | Result
3592 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
3593 * 0 | x - - | - x - | x - - - -
3594 * 1 | x x x | - x - | x - - x -
3595 * 2 | - x - | x - - | - x - - -
3596 * 3 | x x x | x - - | - x x - -
3597 * 4 | - x - | x x x | - x - - -
3598 * 5 | x - - | x x x | x - - - -
3599 * 6 | x x x | x x x | x x x x x
3600 */
3601// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07003602static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
3603static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07003604// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
3605// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07003606static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
3607static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07003608// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07003609static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
3610static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
3611static const int kResultSendrecv_SendCodecs[] = {3, 6};
3612static const int kResultSendrecv_RecvCodecs[] = {1, 6};
3613static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07003614
3615template <typename T, int IDXS>
3616std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
3617 std::vector<T> out;
3618 out.reserve(IDXS);
3619 for (int idx : indices)
3620 out.push_back(array[idx]);
3621
3622 return out;
3623}
3624
3625void TestAudioCodecsAnswer(MediaContentDirection offer_direction,
3626 MediaContentDirection answer_direction,
3627 bool add_legacy_stream) {
3628 TransportDescriptionFactory offer_tdf;
3629 TransportDescriptionFactory answer_tdf;
3630 MediaSessionDescriptionFactory offer_factory(&offer_tdf);
3631 MediaSessionDescriptionFactory answer_factory(&answer_tdf);
3632 offer_factory.set_audio_codecs(
3633 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
3634 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
3635 answer_factory.set_audio_codecs(
3636 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
3637 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
3638
ossu075af922016-06-14 03:29:38 -07003639 MediaSessionOptions offer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003640 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", offer_direction, kActive,
3641 &offer_opts);
3642
3643 if (RtpTransceiverDirection::FromMediaContentDirection(offer_direction)
3644 .send) {
3645 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003646 {kMediaStream1}, 1, &offer_opts);
ossu075af922016-06-14 03:29:38 -07003647 }
3648
3649 std::unique_ptr<SessionDescription> offer(
3650 offer_factory.CreateOffer(offer_opts, NULL));
3651 ASSERT_TRUE(offer.get() != NULL);
3652
3653 MediaSessionOptions answer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003654 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", answer_direction, kActive,
3655 &answer_opts);
3656
3657 if (RtpTransceiverDirection::FromMediaContentDirection(answer_direction)
3658 .send) {
3659 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003660 {kMediaStream1}, 1, &answer_opts);
ossu075af922016-06-14 03:29:38 -07003661 }
3662 std::unique_ptr<SessionDescription> answer(
3663 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL));
3664 const ContentInfo* ac = answer->GetContentByName("audio");
3665
zhihuang1c378ed2017-08-17 14:10:50 -07003666 // If the factory didn't add any audio content to the answer, we cannot
3667 // check that the codecs put in are right. This happens when we neither want
3668 // to send nor receive audio. The checks are still in place if at some point
3669 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07003670 if (ac) {
3671 const AudioContentDescription* acd =
3672 static_cast<const AudioContentDescription*>(ac->description);
3673 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
3674
ossu075af922016-06-14 03:29:38 -07003675 std::vector<AudioCodec> target_codecs;
3676 // For offers with sendrecv or inactive, we should never reply with more
3677 // codecs than offered, with these codec sets.
3678 switch (offer_direction) {
3679 case cricket::MD_INACTIVE:
3680 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
3681 kResultSendrecv_SendrecvCodecs);
3682 break;
3683 case cricket::MD_SENDONLY:
zhihuang1c378ed2017-08-17 14:10:50 -07003684 target_codecs =
3685 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07003686 break;
3687 case cricket::MD_RECVONLY:
zhihuang1c378ed2017-08-17 14:10:50 -07003688 target_codecs =
3689 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07003690 break;
3691 case cricket::MD_SENDRECV:
3692 if (acd->direction() == cricket::MD_SENDONLY) {
zhihuang1c378ed2017-08-17 14:10:50 -07003693 target_codecs =
3694 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07003695 } else if (acd->direction() == cricket::MD_RECVONLY) {
zhihuang1c378ed2017-08-17 14:10:50 -07003696 target_codecs =
3697 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07003698 } else {
3699 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
3700 kResultSendrecv_SendrecvCodecs);
3701 }
3702 break;
3703 }
3704
zhihuang1c378ed2017-08-17 14:10:50 -07003705 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
ossu075af922016-06-14 03:29:38 -07003706 std::stringstream os;
3707 bool first = true;
3708 os << "{";
3709 for (const auto& c : codecs) {
3710 os << (first ? " " : ", ") << c.id;
3711 first = false;
3712 }
3713 os << " }";
3714 return os.str();
3715 };
3716
3717 EXPECT_TRUE(acd->codecs() == target_codecs)
3718 << "Expected: " << format_codecs(target_codecs)
3719 << ", got: " << format_codecs(acd->codecs())
3720 << "; Offered: " << MediaContentDirectionToString(offer_direction)
3721 << ", answerer wants: "
3722 << MediaContentDirectionToString(answer_direction)
3723 << "; got: " << MediaContentDirectionToString(acd->direction());
3724 } else {
3725 EXPECT_EQ(offer_direction, cricket::MD_INACTIVE)
zhihuang1c378ed2017-08-17 14:10:50 -07003726 << "Only inactive offers are allowed to not generate any audio "
3727 "content";
ossu075af922016-06-14 03:29:38 -07003728 }
3729}
brandtr03d5fb12016-11-22 03:37:59 -08003730
3731} // namespace
ossu075af922016-06-14 03:29:38 -07003732
3733class AudioCodecsOfferTest
zhihuang1c378ed2017-08-17 14:10:50 -07003734 : public ::testing::TestWithParam<MediaContentDirection> {};
ossu075af922016-06-14 03:29:38 -07003735
3736TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003737 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07003738}
3739
3740INSTANTIATE_TEST_CASE_P(MediaSessionDescriptionFactoryTest,
3741 AudioCodecsOfferTest,
zhihuang1c378ed2017-08-17 14:10:50 -07003742 ::testing::Values(cricket::MD_SENDONLY,
3743 cricket::MD_RECVONLY,
3744 cricket::MD_SENDRECV,
3745 cricket::MD_INACTIVE));
ossu075af922016-06-14 03:29:38 -07003746
3747class AudioCodecsAnswerTest
ehmaldonadoabcef5d2017-02-08 04:07:11 -08003748 : public ::testing::TestWithParam<::testing::tuple<MediaContentDirection,
3749 MediaContentDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07003750 bool>> {};
ossu075af922016-06-14 03:29:38 -07003751
3752TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08003753 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
3754 ::testing::get<1>(GetParam()),
3755 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07003756}
3757
zhihuang1c378ed2017-08-17 14:10:50 -07003758INSTANTIATE_TEST_CASE_P(
3759 MediaSessionDescriptionFactoryTest,
3760 AudioCodecsAnswerTest,
3761 ::testing::Combine(::testing::Values(cricket::MD_SENDONLY,
3762 cricket::MD_RECVONLY,
3763 cricket::MD_SENDRECV,
3764 cricket::MD_INACTIVE),
3765 ::testing::Values(cricket::MD_SENDONLY,
3766 cricket::MD_RECVONLY,
3767 cricket::MD_SENDRECV,
3768 cricket::MD_INACTIVE),
3769 ::testing::Bool()));