blob: 95c7afff3b6c81c1a74314c3a652342a0ac2b708 [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]);
2132 LOG(LS_INFO) << "Offer codecs: ";
2133 for (auto codec : codecs) {
2134 LOG(LS_INFO) << codec.ToString();
2135 }
2136}
2137
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002138// Create an updated offer that adds video after creating an audio only answer
2139// to the original offer. This test verifies that if a video codec and the RTX
2140// codec have the same default payload type as an audio codec that is already in
2141// use, the added codecs payload types are changed.
2142TEST_F(MediaSessionDescriptionFactoryTest,
2143 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2144 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002145 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002146 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002147 f1_.set_video_codecs(f1_codecs);
2148
2149 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002150 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
2151 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002152
kwiberg31022942016-03-11 14:18:21 -08002153 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2154 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002155 f2_.CreateAnswer(offer.get(), opts, NULL));
2156
2157 const AudioContentDescription* acd =
2158 GetFirstAudioContentDescription(answer.get());
2159 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
2160
2161 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
2162 // reference be the same as an audio codec that was negotiated in the
2163 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002164 opts.media_description_options.clear();
2165 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002166
2167 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2168 int used_pl_type = acd->codecs()[0].id;
2169 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002170 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002171 f2_.set_video_codecs(f2_codecs);
2172
kwiberg31022942016-03-11 14:18:21 -08002173 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002174 f2_.CreateOffer(opts, answer.get()));
2175 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002176 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002177 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2178
2179 const AudioContentDescription* updated_acd =
2180 GetFirstAudioContentDescription(answer.get());
2181 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), updated_acd->codecs());
2182
2183 const VideoContentDescription* updated_vcd =
2184 GetFirstVideoContentDescription(updated_answer.get());
2185
2186 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
sergeyu@chromium.org32f485b2013-12-05 22:36:21 +00002187 ASSERT_EQ(std::string(cricket::kRtxCodecName), updated_vcd->codecs()[1].name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002188 int new_h264_pl_type = updated_vcd->codecs()[0].id;
2189 EXPECT_NE(used_pl_type, new_h264_pl_type);
2190 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002191 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002192 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
2193 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
2194}
2195
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002196// Create an updated offer with RTX after creating an answer to an offer
2197// without RTX, and with different default payload types.
2198// Verify that the added RTX codec references the correct payload type.
2199TEST_F(MediaSessionDescriptionFactoryTest,
2200 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
2201 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002202 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002203
2204 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2205 // This creates rtx for H264 with the payload type |f2_| uses.
2206 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
2207 f2_.set_video_codecs(f2_codecs);
2208
kwiberg31022942016-03-11 14:18:21 -08002209 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002210 ASSERT_TRUE(offer.get() != nullptr);
kwiberg31022942016-03-11 14:18:21 -08002211 std::unique_ptr<SessionDescription> answer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002212 f2_.CreateAnswer(offer.get(), opts, nullptr));
2213
2214 const VideoContentDescription* vcd =
2215 GetFirstVideoContentDescription(answer.get());
2216
2217 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2218 EXPECT_EQ(expected_codecs, vcd->codecs());
2219
2220 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
2221 // updated offer, even though the default payload types are different from
2222 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08002223 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002224 f2_.CreateOffer(opts, answer.get()));
2225 ASSERT_TRUE(updated_offer);
2226
2227 const VideoContentDescription* updated_vcd =
2228 GetFirstVideoContentDescription(updated_offer.get());
2229
2230 // New offer should attempt to add H263, and RTX for H264.
2231 expected_codecs.push_back(kVideoCodecs2[1]);
2232 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
2233 &expected_codecs);
2234 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2235}
2236
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002237// Test that RTX is ignored when there is no associated payload type parameter.
2238TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
2239 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002240 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
2241 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002242 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002243 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07002244 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002245 f1_.set_video_codecs(f1_codecs);
2246
2247 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002248 // This creates RTX for H264 with the payload type |f2_| uses.
2249 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002250 f2_.set_video_codecs(f2_codecs);
2251
kwiberg31022942016-03-11 14:18:21 -08002252 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002253 ASSERT_TRUE(offer.get() != NULL);
2254 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
2255 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
2256 // is possible to test that that RTX is dropped when
2257 // kCodecParamAssociatedPayloadType is missing in the offer.
2258 VideoContentDescription* desc =
2259 static_cast<cricket::VideoContentDescription*>(
2260 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
2261 ASSERT_TRUE(desc != NULL);
2262 std::vector<VideoCodec> codecs = desc->codecs();
2263 for (std::vector<VideoCodec>::iterator iter = codecs.begin();
2264 iter != codecs.end(); ++iter) {
2265 if (iter->name.find(cricket::kRtxCodecName) == 0) {
2266 iter->params.clear();
2267 }
2268 }
2269 desc->set_codecs(codecs);
2270
kwiberg31022942016-03-11 14:18:21 -08002271 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002272 f2_.CreateAnswer(offer.get(), opts, NULL));
2273
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002274 std::vector<std::string> codec_names =
2275 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
2276 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
2277 cricket::kRtxCodecName));
2278}
2279
2280// Test that RTX will be filtered out in the answer if its associated payload
2281// type doesn't match the local value.
2282TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
2283 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002284 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
2285 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002286 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2287 // This creates RTX for H264 in sender.
2288 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2289 f1_.set_video_codecs(f1_codecs);
2290
2291 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2292 // This creates RTX for H263 in receiver.
2293 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
2294 f2_.set_video_codecs(f2_codecs);
2295
kwiberg31022942016-03-11 14:18:21 -08002296 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002297 ASSERT_TRUE(offer.get() != NULL);
2298 // Associated payload type doesn't match, therefore, RTX codec is removed in
2299 // the answer.
kwiberg31022942016-03-11 14:18:21 -08002300 std::unique_ptr<SessionDescription> answer(
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002301 f2_.CreateAnswer(offer.get(), opts, NULL));
2302
2303 std::vector<std::string> codec_names =
2304 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
2305 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
2306 cricket::kRtxCodecName));
2307}
2308
2309// Test that when multiple RTX codecs are offered, only the matched RTX codec
2310// is added in the answer, and the unsupported RTX codec is filtered out.
2311TEST_F(MediaSessionDescriptionFactoryTest,
2312 FilterOutUnsupportedRtxWhenCreatingAnswer) {
2313 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002314 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
2315 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002316 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2317 // This creates RTX for H264-SVC in sender.
2318 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2319 f1_.set_video_codecs(f1_codecs);
2320
2321 // This creates RTX for H264 in sender.
2322 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2323 f1_.set_video_codecs(f1_codecs);
2324
2325 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2326 // This creates RTX for H264 in receiver.
2327 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
2328 f2_.set_video_codecs(f2_codecs);
2329
2330 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
2331 // for H264-SVC should also be removed.
kwiberg31022942016-03-11 14:18:21 -08002332 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002333 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002334 std::unique_ptr<SessionDescription> answer(
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002335 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002336 const VideoContentDescription* vcd =
2337 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002338 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2339 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2340 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002341
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002342 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002343}
2344
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002345// Test that after one RTX codec has been negotiated, a new offer can attempt
2346// to add another.
2347TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
2348 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002349 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
2350 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002351 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2352 // This creates RTX for H264 for the offerer.
2353 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2354 f1_.set_video_codecs(f1_codecs);
2355
kwiberg31022942016-03-11 14:18:21 -08002356 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002357 ASSERT_TRUE(offer);
2358 const VideoContentDescription* vcd =
2359 GetFirstVideoContentDescription(offer.get());
2360
2361 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
2362 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2363 &expected_codecs);
2364 EXPECT_EQ(expected_codecs, vcd->codecs());
2365
2366 // Now, attempt to add RTX for H264-SVC.
2367 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2368 f1_.set_video_codecs(f1_codecs);
2369
kwiberg31022942016-03-11 14:18:21 -08002370 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002371 f1_.CreateOffer(opts, offer.get()));
2372 ASSERT_TRUE(updated_offer);
2373 vcd = GetFirstVideoContentDescription(updated_offer.get());
2374
2375 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
2376 &expected_codecs);
2377 EXPECT_EQ(expected_codecs, vcd->codecs());
2378}
2379
Noah Richards2e7a0982015-05-18 14:02:54 -07002380// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
2381// generated for each simulcast ssrc and correctly grouped.
2382TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
2383 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002384 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_SENDRECV, kActive,
2385 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002386 // Add simulcast streams.
zhihuang1c378ed2017-08-17 14:10:50 -07002387 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002388 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002389
2390 // Use a single real codec, and then add RTX for it.
2391 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07002392 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07002393 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
2394 f1_.set_video_codecs(f1_codecs);
2395
2396 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
2397 // is a FID ssrc + grouping for each.
kwiberg31022942016-03-11 14:18:21 -08002398 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
Noah Richards2e7a0982015-05-18 14:02:54 -07002399 ASSERT_TRUE(offer.get() != NULL);
2400 VideoContentDescription* desc = static_cast<VideoContentDescription*>(
2401 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
2402 ASSERT_TRUE(desc != NULL);
2403 EXPECT_TRUE(desc->multistream());
2404 const StreamParamsVec& streams = desc->streams();
2405 // Single stream.
2406 ASSERT_EQ(1u, streams.size());
2407 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
2408 EXPECT_EQ(6u, streams[0].ssrcs.size());
2409 // And should have a SIM group for the simulcast.
2410 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2411 // And a FID group for RTX.
2412 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02002413 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002414 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2415 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02002416 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002417 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
2418 EXPECT_EQ(3u, fid_ssrcs.size());
2419}
2420
brandtr03d5fb12016-11-22 03:37:59 -08002421// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
2422// together with a FEC-FR grouping.
2423TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
2424 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002425 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_SENDRECV, kActive,
2426 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002427 // Add single stream.
zhihuang1c378ed2017-08-17 14:10:50 -07002428 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002429 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002430
2431 // Use a single real codec, and then add FlexFEC for it.
2432 std::vector<VideoCodec> f1_codecs;
2433 f1_codecs.push_back(VideoCodec(97, "H264"));
2434 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2435 f1_.set_video_codecs(f1_codecs);
2436
2437 // Ensure that the offer has a single FlexFEC ssrc and that
2438 // there is no FEC-FR ssrc + grouping for each.
2439 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
2440 ASSERT_TRUE(offer.get() != nullptr);
2441 VideoContentDescription* desc = static_cast<VideoContentDescription*>(
2442 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
2443 ASSERT_TRUE(desc != nullptr);
2444 EXPECT_TRUE(desc->multistream());
2445 const StreamParamsVec& streams = desc->streams();
2446 // Single stream.
2447 ASSERT_EQ(1u, streams.size());
2448 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
2449 EXPECT_EQ(2u, streams[0].ssrcs.size());
2450 // And should have a FEC-FR group for FlexFEC.
2451 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
2452 std::vector<uint32_t> primary_ssrcs;
2453 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2454 ASSERT_EQ(1u, primary_ssrcs.size());
2455 uint32_t flexfec_ssrc;
2456 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
2457 EXPECT_NE(flexfec_ssrc, 0u);
2458}
2459
2460// Test that FlexFEC is disabled for simulcast.
2461// TODO(brandtr): Remove this test when we support simulcast, either through
2462// multiple FlexfecSenders, or through multistream protection.
2463TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
2464 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002465 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_SENDRECV, kActive,
2466 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002467 // Add simulcast streams.
zhihuang1c378ed2017-08-17 14:10:50 -07002468 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002469 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002470
2471 // Use a single real codec, and then add FlexFEC for it.
2472 std::vector<VideoCodec> f1_codecs;
2473 f1_codecs.push_back(VideoCodec(97, "H264"));
2474 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2475 f1_.set_video_codecs(f1_codecs);
2476
2477 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
2478 // there is no FEC-FR ssrc + grouping for each.
2479 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
2480 ASSERT_TRUE(offer.get() != nullptr);
2481 VideoContentDescription* desc = static_cast<VideoContentDescription*>(
2482 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
2483 ASSERT_TRUE(desc != nullptr);
2484 EXPECT_FALSE(desc->multistream());
2485 const StreamParamsVec& streams = desc->streams();
2486 // Single stream.
2487 ASSERT_EQ(1u, streams.size());
2488 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
2489 EXPECT_EQ(3u, streams[0].ssrcs.size());
2490 // And should have a SIM group for the simulcast.
2491 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2492 // And not a FEC-FR group for FlexFEC.
2493 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
2494 std::vector<uint32_t> primary_ssrcs;
2495 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2496 EXPECT_EQ(3u, primary_ssrcs.size());
2497 for (uint32_t primary_ssrc : primary_ssrcs) {
2498 uint32_t flexfec_ssrc;
2499 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
2500 }
2501}
2502
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002503// Create an updated offer after creating an answer to the original offer and
2504// verify that the RTP header extensions that were part of the original answer
2505// are not changed in the updated offer.
2506TEST_F(MediaSessionDescriptionFactoryTest,
2507 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
2508 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002509 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002510
2511 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
2512 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
2513 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
2514 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
2515
kwiberg31022942016-03-11 14:18:21 -08002516 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2517 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002518 f2_.CreateAnswer(offer.get(), opts, NULL));
2519
2520 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
2521 GetFirstAudioContentDescription(
2522 answer.get())->rtp_header_extensions());
2523 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
2524 GetFirstVideoContentDescription(
2525 answer.get())->rtp_header_extensions());
2526
kwiberg31022942016-03-11 14:18:21 -08002527 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002528 f2_.CreateOffer(opts, answer.get()));
2529
2530 // The expected RTP header extensions in the new offer are the resulting
2531 // extensions from the first offer/answer exchange plus the extensions only
2532 // |f2_| offer.
2533 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002534 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07002535 const RtpExtension kUpdatedAudioRtpExtensions[] = {
2536 kAudioRtpExtensionAnswer[0], RtpExtension(kAudioRtpExtension2[1].uri, 13),
2537 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002538 };
2539
2540 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002541 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07002542 const RtpExtension kUpdatedVideoRtpExtensions[] = {
2543 kVideoRtpExtensionAnswer[0], RtpExtension(kVideoRtpExtension2[1].uri, 12),
2544 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002545 };
2546
2547 const AudioContentDescription* updated_acd =
2548 GetFirstAudioContentDescription(updated_offer.get());
2549 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
2550 updated_acd->rtp_header_extensions());
2551
2552 const VideoContentDescription* updated_vcd =
2553 GetFirstVideoContentDescription(updated_offer.get());
2554 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
2555 updated_vcd->rtp_header_extensions());
2556}
2557
deadbeefa5b273a2015-08-20 17:30:13 -07002558// Verify that if the same RTP extension URI is used for audio and video, the
2559// same ID is used. Also verify that the ID isn't changed when creating an
2560// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07002561TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07002562 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002563 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07002564
2565 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
2566 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
2567
kwiberg31022942016-03-11 14:18:21 -08002568 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
deadbeefa5b273a2015-08-20 17:30:13 -07002569
2570 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
2571 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07002572 const RtpExtension kExpectedVideoRtpExtension[] = {
2573 kVideoRtpExtension3[0], kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07002574 };
2575
2576 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
2577 GetFirstAudioContentDescription(
2578 offer.get())->rtp_header_extensions());
2579 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2580 GetFirstVideoContentDescription(
2581 offer.get())->rtp_header_extensions());
2582
2583 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08002584 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07002585 f1_.CreateOffer(opts, offer.get()));
2586
2587 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
2588 GetFirstAudioContentDescription(
2589 updated_offer.get())->rtp_header_extensions());
2590 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2591 GetFirstVideoContentDescription(
2592 updated_offer.get())->rtp_header_extensions());
2593}
2594
jbauch5869f502017-06-29 12:31:36 -07002595// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
2596TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
2597 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002598 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
jbauch5869f502017-06-29 12:31:36 -07002599
2600 f1_.set_enable_encrypted_rtp_header_extensions(true);
2601 f2_.set_enable_encrypted_rtp_header_extensions(true);
2602
2603 f1_.set_audio_rtp_header_extensions(
2604 MAKE_VECTOR(kAudioRtpExtension3ForEncryption));
2605 f1_.set_video_rtp_header_extensions(
2606 MAKE_VECTOR(kVideoRtpExtension3ForEncryption));
2607
2608 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2609
2610 // The extensions that are shared between audio and video should use the same
2611 // id.
2612 const RtpExtension kExpectedVideoRtpExtension[] = {
2613 kVideoRtpExtension3ForEncryption[0],
2614 kAudioRtpExtension3ForEncryptionOffer[1],
2615 kAudioRtpExtension3ForEncryptionOffer[2],
2616 };
2617
2618 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
2619 GetFirstAudioContentDescription(
2620 offer.get())->rtp_header_extensions());
2621 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2622 GetFirstVideoContentDescription(
2623 offer.get())->rtp_header_extensions());
2624
2625 // Nothing should change when creating a new offer
2626 std::unique_ptr<SessionDescription> updated_offer(
2627 f1_.CreateOffer(opts, offer.get()));
2628
2629 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
2630 GetFirstAudioContentDescription(
2631 updated_offer.get())->rtp_header_extensions());
2632 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2633 GetFirstVideoContentDescription(
2634 updated_offer.get())->rtp_header_extensions());
2635}
2636
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002637TEST(MediaSessionDescription, CopySessionDescription) {
2638 SessionDescription source;
2639 cricket::ContentGroup group(cricket::CN_AUDIO);
2640 source.AddGroup(group);
2641 AudioContentDescription* acd(new AudioContentDescription());
2642 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
2643 acd->AddLegacyStream(1);
2644 source.AddContent(cricket::CN_AUDIO, cricket::NS_JINGLE_RTP, acd);
2645 VideoContentDescription* vcd(new VideoContentDescription());
2646 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
2647 vcd->AddLegacyStream(2);
2648 source.AddContent(cricket::CN_VIDEO, cricket::NS_JINGLE_RTP, vcd);
2649
kwiberg31022942016-03-11 14:18:21 -08002650 std::unique_ptr<SessionDescription> copy(source.Copy());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002651 ASSERT_TRUE(copy.get() != NULL);
2652 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
2653 const ContentInfo* ac = copy->GetContentByName("audio");
2654 const ContentInfo* vc = copy->GetContentByName("video");
2655 ASSERT_TRUE(ac != NULL);
2656 ASSERT_TRUE(vc != NULL);
2657 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
2658 const AudioContentDescription* acd_copy =
2659 static_cast<const AudioContentDescription*>(ac->description);
2660 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
2661 EXPECT_EQ(1u, acd->first_ssrc());
2662
2663 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
2664 const VideoContentDescription* vcd_copy =
2665 static_cast<const VideoContentDescription*>(vc->description);
2666 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
2667 EXPECT_EQ(2u, vcd->first_ssrc());
2668}
2669
2670// The below TestTransportInfoXXX tests create different offers/answers, and
2671// ensure the TransportInfo in the SessionDescription matches what we expect.
2672TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
2673 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002674 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
2675 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002676 TestTransportInfo(true, options, false);
2677}
2678
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002679TEST_F(MediaSessionDescriptionFactoryTest,
2680 TestTransportInfoOfferIceRenomination) {
2681 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002682 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
2683 &options);
2684 options.media_description_options[0]
2685 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002686 TestTransportInfo(true, options, false);
2687}
2688
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002689TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
2690 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002691 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
2692 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002693 TestTransportInfo(true, options, true);
2694}
2695
2696TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
2697 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002698 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2699 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002700 TestTransportInfo(true, options, false);
2701}
2702
2703TEST_F(MediaSessionDescriptionFactoryTest,
2704 TestTransportInfoOfferMultimediaCurrent) {
2705 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002706 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2707 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002708 TestTransportInfo(true, options, true);
2709}
2710
2711TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
2712 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002713 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2714 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002715 options.bundle_enabled = true;
2716 TestTransportInfo(true, options, false);
2717}
2718
2719TEST_F(MediaSessionDescriptionFactoryTest,
2720 TestTransportInfoOfferBundleCurrent) {
2721 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002722 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2723 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002724 options.bundle_enabled = true;
2725 TestTransportInfo(true, options, true);
2726}
2727
2728TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
2729 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002730 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
2731 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002732 TestTransportInfo(false, options, false);
2733}
2734
2735TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002736 TestTransportInfoAnswerIceRenomination) {
2737 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002738 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
2739 &options);
2740 options.media_description_options[0]
2741 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002742 TestTransportInfo(false, options, false);
2743}
2744
2745TEST_F(MediaSessionDescriptionFactoryTest,
2746 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002747 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002748 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
2749 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002750 TestTransportInfo(false, options, true);
2751}
2752
2753TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
2754 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002755 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2756 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002757 TestTransportInfo(false, options, false);
2758}
2759
2760TEST_F(MediaSessionDescriptionFactoryTest,
2761 TestTransportInfoAnswerMultimediaCurrent) {
2762 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002763 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2764 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002765 TestTransportInfo(false, options, true);
2766}
2767
2768TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
2769 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002770 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2771 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002772 options.bundle_enabled = true;
2773 TestTransportInfo(false, options, false);
2774}
2775
2776TEST_F(MediaSessionDescriptionFactoryTest,
2777 TestTransportInfoAnswerBundleCurrent) {
2778 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002779 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2780 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002781 options.bundle_enabled = true;
2782 TestTransportInfo(false, options, true);
2783}
2784
2785// Create an offer with bundle enabled and verify the crypto parameters are
2786// the common set of the available cryptos.
2787TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
2788 TestCryptoWithBundle(true);
2789}
2790
2791// Create an answer with bundle enabled and verify the crypto parameters are
2792// the common set of the available cryptos.
2793TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
2794 TestCryptoWithBundle(false);
2795}
2796
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002797// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
2798// DTLS is not enabled locally.
2799TEST_F(MediaSessionDescriptionFactoryTest,
2800 TestOfferDtlsSavpfWithoutDtlsFailed) {
2801 f1_.set_secure(SEC_ENABLED);
2802 f2_.set_secure(SEC_ENABLED);
2803 tdf1_.set_secure(SEC_DISABLED);
2804 tdf2_.set_secure(SEC_DISABLED);
2805
kwiberg31022942016-03-11 14:18:21 -08002806 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -07002807 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002808 ASSERT_TRUE(offer.get() != NULL);
2809 ContentInfo* offer_content = offer->GetContentByName("audio");
2810 ASSERT_TRUE(offer_content != NULL);
2811 AudioContentDescription* offer_audio_desc =
2812 static_cast<AudioContentDescription*>(offer_content->description);
2813 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2814
kwiberg31022942016-03-11 14:18:21 -08002815 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002816 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002817 ASSERT_TRUE(answer != NULL);
2818 ContentInfo* answer_content = answer->GetContentByName("audio");
2819 ASSERT_TRUE(answer_content != NULL);
2820
2821 ASSERT_TRUE(answer_content->rejected);
2822}
2823
2824// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
2825// UDP/TLS/RTP/SAVPF.
2826TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
2827 f1_.set_secure(SEC_ENABLED);
2828 f2_.set_secure(SEC_ENABLED);
2829 tdf1_.set_secure(SEC_ENABLED);
2830 tdf2_.set_secure(SEC_ENABLED);
2831
kwiberg31022942016-03-11 14:18:21 -08002832 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -07002833 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002834 ASSERT_TRUE(offer.get() != NULL);
2835 ContentInfo* offer_content = offer->GetContentByName("audio");
2836 ASSERT_TRUE(offer_content != NULL);
2837 AudioContentDescription* offer_audio_desc =
2838 static_cast<AudioContentDescription*>(offer_content->description);
2839 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2840
kwiberg31022942016-03-11 14:18:21 -08002841 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002842 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002843 ASSERT_TRUE(answer != NULL);
2844
2845 const ContentInfo* answer_content = answer->GetContentByName("audio");
2846 ASSERT_TRUE(answer_content != NULL);
2847 ASSERT_FALSE(answer_content->rejected);
2848
2849 const AudioContentDescription* answer_audio_desc =
2850 static_cast<const AudioContentDescription*>(answer_content->description);
2851 EXPECT_EQ(std::string(cricket::kMediaProtocolDtlsSavpf),
2852 answer_audio_desc->protocol());
2853}
2854
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002855// Test that we include both SDES and DTLS in the offer, but only include SDES
2856// in the answer if DTLS isn't negotiated.
2857TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
2858 f1_.set_secure(SEC_ENABLED);
2859 f2_.set_secure(SEC_ENABLED);
2860 tdf1_.set_secure(SEC_ENABLED);
2861 tdf2_.set_secure(SEC_DISABLED);
2862 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002863 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
kwiberg31022942016-03-11 14:18:21 -08002864 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002865 const cricket::MediaContentDescription* audio_media_desc;
2866 const cricket::MediaContentDescription* video_media_desc;
2867 const cricket::TransportDescription* audio_trans_desc;
2868 const cricket::TransportDescription* video_trans_desc;
2869
2870 // Generate an offer with SDES and DTLS support.
2871 offer.reset(f1_.CreateOffer(options, NULL));
2872 ASSERT_TRUE(offer.get() != NULL);
2873
2874 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2875 offer->GetContentDescriptionByName("audio"));
2876 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002877 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002878 offer->GetContentDescriptionByName("video"));
2879 ASSERT_TRUE(video_media_desc != NULL);
2880 EXPECT_EQ(2u, audio_media_desc->cryptos().size());
2881 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2882
2883 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2884 ASSERT_TRUE(audio_trans_desc != NULL);
2885 video_trans_desc = offer->GetTransportDescriptionByName("video");
2886 ASSERT_TRUE(video_trans_desc != NULL);
2887 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2888 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
2889
2890 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
2891 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2892 ASSERT_TRUE(answer.get() != NULL);
2893
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002894 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002895 answer->GetContentDescriptionByName("audio"));
2896 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002897 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002898 answer->GetContentDescriptionByName("video"));
2899 ASSERT_TRUE(video_media_desc != NULL);
2900 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
2901 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2902
2903 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2904 ASSERT_TRUE(audio_trans_desc != NULL);
2905 video_trans_desc = answer->GetTransportDescriptionByName("video");
2906 ASSERT_TRUE(video_trans_desc != NULL);
2907 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
2908 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
2909
2910 // Enable DTLS; the answer should now only have DTLS support.
2911 tdf2_.set_secure(SEC_ENABLED);
2912 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2913 ASSERT_TRUE(answer.get() != NULL);
2914
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002915 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002916 answer->GetContentDescriptionByName("audio"));
2917 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002918 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002919 answer->GetContentDescriptionByName("video"));
2920 ASSERT_TRUE(video_media_desc != NULL);
2921 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2922 EXPECT_TRUE(video_media_desc->cryptos().empty());
2923 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2924 audio_media_desc->protocol());
2925 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2926 video_media_desc->protocol());
2927
2928 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2929 ASSERT_TRUE(audio_trans_desc != NULL);
2930 video_trans_desc = answer->GetTransportDescriptionByName("video");
2931 ASSERT_TRUE(video_trans_desc != NULL);
2932 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2933 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00002934
2935 // Try creating offer again. DTLS enabled now, crypto's should be empty
2936 // in new offer.
2937 offer.reset(f1_.CreateOffer(options, offer.get()));
2938 ASSERT_TRUE(offer.get() != NULL);
2939 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2940 offer->GetContentDescriptionByName("audio"));
2941 ASSERT_TRUE(audio_media_desc != NULL);
2942 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
2943 offer->GetContentDescriptionByName("video"));
2944 ASSERT_TRUE(video_media_desc != NULL);
2945 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2946 EXPECT_TRUE(video_media_desc->cryptos().empty());
2947
2948 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2949 ASSERT_TRUE(audio_trans_desc != NULL);
2950 video_trans_desc = offer->GetTransportDescriptionByName("video");
2951 ASSERT_TRUE(video_trans_desc != NULL);
2952 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2953 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002954}
2955
2956// Test that an answer can't be created if cryptos are required but the offer is
2957// unsecure.
2958TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07002959 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002960 f1_.set_secure(SEC_DISABLED);
2961 tdf1_.set_secure(SEC_DISABLED);
2962 f2_.set_secure(SEC_REQUIRED);
2963 tdf1_.set_secure(SEC_ENABLED);
2964
kwiberg31022942016-03-11 14:18:21 -08002965 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002966 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002967 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002968 f2_.CreateAnswer(offer.get(), options, NULL));
2969 EXPECT_TRUE(answer.get() == NULL);
2970}
2971
2972// Test that we accept a DTLS offer without SDES and create an appropriate
2973// answer.
2974TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
2975 f1_.set_secure(SEC_DISABLED);
2976 f2_.set_secure(SEC_ENABLED);
2977 tdf1_.set_secure(SEC_ENABLED);
2978 tdf2_.set_secure(SEC_ENABLED);
2979 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002980 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2981 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002982
kwiberg31022942016-03-11 14:18:21 -08002983 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002984
2985 // Generate an offer with DTLS but without SDES.
2986 offer.reset(f1_.CreateOffer(options, NULL));
2987 ASSERT_TRUE(offer.get() != NULL);
2988
2989 const AudioContentDescription* audio_offer =
2990 GetFirstAudioContentDescription(offer.get());
2991 ASSERT_TRUE(audio_offer->cryptos().empty());
2992 const VideoContentDescription* video_offer =
2993 GetFirstVideoContentDescription(offer.get());
2994 ASSERT_TRUE(video_offer->cryptos().empty());
2995 const DataContentDescription* data_offer =
2996 GetFirstDataContentDescription(offer.get());
2997 ASSERT_TRUE(data_offer->cryptos().empty());
2998
2999 const cricket::TransportDescription* audio_offer_trans_desc =
3000 offer->GetTransportDescriptionByName("audio");
3001 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
3002 const cricket::TransportDescription* video_offer_trans_desc =
3003 offer->GetTransportDescriptionByName("video");
3004 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
3005 const cricket::TransportDescription* data_offer_trans_desc =
3006 offer->GetTransportDescriptionByName("data");
3007 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
3008
3009 // Generate an answer with DTLS.
3010 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
3011 ASSERT_TRUE(answer.get() != NULL);
3012
3013 const cricket::TransportDescription* audio_answer_trans_desc =
3014 answer->GetTransportDescriptionByName("audio");
3015 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3016 const cricket::TransportDescription* video_answer_trans_desc =
3017 answer->GetTransportDescriptionByName("video");
3018 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
3019 const cricket::TransportDescription* data_answer_trans_desc =
3020 answer->GetTransportDescriptionByName("data");
3021 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
3022}
3023
3024// Verifies if vad_enabled option is set to false, CN codecs are not present in
3025// offer or answer.
3026TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3027 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07003028 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
kwiberg31022942016-03-11 14:18:21 -08003029 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003030 ASSERT_TRUE(offer.get() != NULL);
3031 const ContentInfo* audio_content = offer->GetContentByName("audio");
3032 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
3033
3034 options.vad_enabled = false;
3035 offer.reset(f1_.CreateOffer(options, NULL));
3036 ASSERT_TRUE(offer.get() != NULL);
3037 audio_content = offer->GetContentByName("audio");
3038 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
kwiberg31022942016-03-11 14:18:21 -08003039 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003040 f1_.CreateAnswer(offer.get(), options, NULL));
3041 ASSERT_TRUE(answer.get() != NULL);
3042 audio_content = answer->GetContentByName("audio");
3043 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
3044}
deadbeef44f08192015-12-15 16:20:09 -08003045
zhihuang1c378ed2017-08-17 14:10:50 -07003046// Test that the generated MIDs match the existing offer.
3047TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08003048 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003049 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_modified", cricket::MD_RECVONLY,
3050 kActive, &opts);
3051 AddMediaSection(MEDIA_TYPE_VIDEO, "video_modified", cricket::MD_RECVONLY,
3052 kActive, &opts);
deadbeef44f08192015-12-15 16:20:09 -08003053 opts.data_channel_type = cricket::DCT_SCTP;
zhihuang1c378ed2017-08-17 14:10:50 -07003054 AddMediaSection(MEDIA_TYPE_DATA, "data_modified", cricket::MD_SENDRECV,
3055 kActive, &opts);
3056 // Create offer.
kwiberg31022942016-03-11 14:18:21 -08003057 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
kwiberg31022942016-03-11 14:18:21 -08003058 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08003059 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003060
deadbeef44f08192015-12-15 16:20:09 -08003061 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3062 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3063 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3064 ASSERT_TRUE(audio_content != nullptr);
3065 ASSERT_TRUE(video_content != nullptr);
3066 ASSERT_TRUE(data_content != nullptr);
3067 EXPECT_EQ("audio_modified", audio_content->name);
3068 EXPECT_EQ("video_modified", video_content->name);
3069 EXPECT_EQ("data_modified", data_content->name);
3070}
zhihuangcf5b37c2016-05-05 11:44:35 -07003071
zhihuang1c378ed2017-08-17 14:10:50 -07003072// The following tests verify that the unified plan SDP is supported.
3073// Test that we can create an offer with multiple media sections of same media
3074// type.
3075TEST_F(MediaSessionDescriptionFactoryTest,
3076 CreateOfferWithMultipleAVMediaSections) {
3077 MediaSessionOptions opts;
3078 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_1", cricket::MD_SENDRECV, kActive,
3079 &opts);
3080 AttachSenderToMediaSection("audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003081 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003082
3083 AddMediaSection(MEDIA_TYPE_VIDEO, "video_1", cricket::MD_SENDRECV, kActive,
3084 &opts);
3085 AttachSenderToMediaSection("video_1", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003086 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003087
3088 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_2", cricket::MD_SENDRECV, kActive,
3089 &opts);
3090 AttachSenderToMediaSection("audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003091 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003092
3093 AddMediaSection(MEDIA_TYPE_VIDEO, "video_2", cricket::MD_SENDRECV, kActive,
3094 &opts);
3095 AttachSenderToMediaSection("video_2", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003096 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003097 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3098 ASSERT_TRUE(offer);
3099
3100 ASSERT_EQ(4u, offer->contents().size());
3101 EXPECT_FALSE(offer->contents()[0].rejected);
3102 const AudioContentDescription* acd =
3103 static_cast<const AudioContentDescription*>(
3104 offer->contents()[0].description);
3105 ASSERT_EQ(1u, acd->streams().size());
3106 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
3107 EXPECT_EQ(cricket::MD_SENDRECV, acd->direction());
3108
3109 EXPECT_FALSE(offer->contents()[1].rejected);
3110 const VideoContentDescription* vcd =
3111 static_cast<const VideoContentDescription*>(
3112 offer->contents()[1].description);
3113 ASSERT_EQ(1u, vcd->streams().size());
3114 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
3115 EXPECT_EQ(cricket::MD_SENDRECV, vcd->direction());
3116
3117 EXPECT_FALSE(offer->contents()[2].rejected);
3118 acd = static_cast<const AudioContentDescription*>(
3119 offer->contents()[2].description);
3120 ASSERT_EQ(1u, acd->streams().size());
3121 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
3122 EXPECT_EQ(cricket::MD_SENDRECV, acd->direction());
3123
3124 EXPECT_FALSE(offer->contents()[3].rejected);
3125 vcd = static_cast<const VideoContentDescription*>(
3126 offer->contents()[3].description);
3127 ASSERT_EQ(1u, vcd->streams().size());
3128 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
3129 EXPECT_EQ(cricket::MD_SENDRECV, vcd->direction());
3130}
3131
3132// Test that we can create an answer with multiple media sections of same media
3133// type.
3134TEST_F(MediaSessionDescriptionFactoryTest,
3135 CreateAnswerWithMultipleAVMediaSections) {
3136 MediaSessionOptions opts;
3137 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_1", cricket::MD_SENDRECV, kActive,
3138 &opts);
3139 AttachSenderToMediaSection("audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003140 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003141
3142 AddMediaSection(MEDIA_TYPE_VIDEO, "video_1", cricket::MD_SENDRECV, kActive,
3143 &opts);
3144 AttachSenderToMediaSection("video_1", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003145 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003146
3147 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_2", cricket::MD_SENDRECV, kActive,
3148 &opts);
3149 AttachSenderToMediaSection("audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003150 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003151
3152 AddMediaSection(MEDIA_TYPE_VIDEO, "video_2", cricket::MD_SENDRECV, kActive,
3153 &opts);
3154 AttachSenderToMediaSection("video_2", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003155 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003156
3157 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3158 ASSERT_TRUE(offer);
3159 std::unique_ptr<SessionDescription> answer(
3160 f2_.CreateAnswer(offer.get(), opts, nullptr));
3161
3162 ASSERT_EQ(4u, answer->contents().size());
3163 EXPECT_FALSE(answer->contents()[0].rejected);
3164 const AudioContentDescription* acd =
3165 static_cast<const AudioContentDescription*>(
3166 answer->contents()[0].description);
3167 ASSERT_EQ(1u, acd->streams().size());
3168 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
3169 EXPECT_EQ(cricket::MD_SENDRECV, acd->direction());
3170
3171 EXPECT_FALSE(answer->contents()[1].rejected);
3172 const VideoContentDescription* vcd =
3173 static_cast<const VideoContentDescription*>(
3174 answer->contents()[1].description);
3175 ASSERT_EQ(1u, vcd->streams().size());
3176 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
3177 EXPECT_EQ(cricket::MD_SENDRECV, vcd->direction());
3178
3179 EXPECT_FALSE(answer->contents()[2].rejected);
3180 acd = static_cast<const AudioContentDescription*>(
3181 answer->contents()[2].description);
3182 ASSERT_EQ(1u, acd->streams().size());
3183 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
3184 EXPECT_EQ(cricket::MD_SENDRECV, acd->direction());
3185
3186 EXPECT_FALSE(answer->contents()[3].rejected);
3187 vcd = static_cast<const VideoContentDescription*>(
3188 answer->contents()[3].description);
3189 ASSERT_EQ(1u, vcd->streams().size());
3190 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
3191 EXPECT_EQ(cricket::MD_SENDRECV, vcd->direction());
3192}
3193
3194// Test that the media section will be rejected in offer if the corresponding
3195// MediaDescriptionOptions is stopped by the offerer.
3196TEST_F(MediaSessionDescriptionFactoryTest,
3197 CreateOfferWithMediaSectionStoppedByOfferer) {
3198 // Create an offer with two audio sections and one of them is stopped.
3199 MediaSessionOptions offer_opts;
3200 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1", cricket::MD_SENDRECV, kActive,
3201 &offer_opts);
3202 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2", cricket::MD_INACTIVE, kStopped,
3203 &offer_opts);
3204 std::unique_ptr<SessionDescription> offer(
3205 f1_.CreateOffer(offer_opts, nullptr));
3206 ASSERT_TRUE(offer);
3207 ASSERT_EQ(2u, offer->contents().size());
3208 EXPECT_FALSE(offer->contents()[0].rejected);
3209 EXPECT_TRUE(offer->contents()[1].rejected);
3210}
3211
3212// Test that the media section will be rejected in answer if the corresponding
3213// MediaDescriptionOptions is stopped by the offerer.
3214TEST_F(MediaSessionDescriptionFactoryTest,
3215 CreateAnswerWithMediaSectionStoppedByOfferer) {
3216 // Create an offer with two audio sections and one of them is stopped.
3217 MediaSessionOptions offer_opts;
3218 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1", cricket::MD_SENDRECV, kActive,
3219 &offer_opts);
3220 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2", cricket::MD_INACTIVE, kStopped,
3221 &offer_opts);
3222 std::unique_ptr<SessionDescription> offer(
3223 f1_.CreateOffer(offer_opts, nullptr));
3224 ASSERT_TRUE(offer);
3225 ASSERT_EQ(2u, offer->contents().size());
3226 EXPECT_FALSE(offer->contents()[0].rejected);
3227 EXPECT_TRUE(offer->contents()[1].rejected);
3228
3229 // Create an answer based on the offer.
3230 MediaSessionOptions answer_opts;
3231 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1", cricket::MD_SENDRECV, kActive,
3232 &answer_opts);
3233 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2", cricket::MD_SENDRECV, kActive,
3234 &answer_opts);
3235 std::unique_ptr<SessionDescription> answer(
3236 f2_.CreateAnswer(offer.get(), answer_opts, nullptr));
3237 ASSERT_EQ(2u, answer->contents().size());
3238 EXPECT_FALSE(answer->contents()[0].rejected);
3239 EXPECT_TRUE(answer->contents()[1].rejected);
3240}
3241
3242// Test that the media section will be rejected in answer if the corresponding
3243// MediaDescriptionOptions is stopped by the answerer.
3244TEST_F(MediaSessionDescriptionFactoryTest,
3245 CreateAnswerWithMediaSectionRejectedByAnswerer) {
3246 // Create an offer with two audio sections.
3247 MediaSessionOptions offer_opts;
3248 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1", cricket::MD_SENDRECV, kActive,
3249 &offer_opts);
3250 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2", cricket::MD_SENDRECV, kActive,
3251 &offer_opts);
3252 std::unique_ptr<SessionDescription> offer(
3253 f1_.CreateOffer(offer_opts, nullptr));
3254 ASSERT_TRUE(offer);
3255 ASSERT_EQ(2u, offer->contents().size());
3256 ASSERT_FALSE(offer->contents()[0].rejected);
3257 ASSERT_FALSE(offer->contents()[1].rejected);
3258
3259 // The answerer rejects one of the audio sections.
3260 MediaSessionOptions answer_opts;
3261 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1", cricket::MD_SENDRECV, kActive,
3262 &answer_opts);
3263 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2", cricket::MD_INACTIVE, kStopped,
3264 &answer_opts);
3265 std::unique_ptr<SessionDescription> answer(
3266 f2_.CreateAnswer(offer.get(), answer_opts, nullptr));
3267 ASSERT_EQ(2u, answer->contents().size());
3268 EXPECT_FALSE(answer->contents()[0].rejected);
3269 EXPECT_TRUE(answer->contents()[1].rejected);
3270}
3271
3272// Test the generated media sections has the same order of the
3273// corresponding MediaDescriptionOptions.
3274TEST_F(MediaSessionDescriptionFactoryTest,
3275 CreateOfferRespectsMediaDescriptionOptionsOrder) {
3276 MediaSessionOptions opts;
3277 // This tests put video section first because normally audio comes first by
3278 // default.
3279 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_SENDRECV, kActive,
3280 &opts);
3281 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_SENDRECV, kActive,
3282 &opts);
3283 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3284
3285 ASSERT_TRUE(offer);
3286 ASSERT_EQ(2u, offer->contents().size());
3287 EXPECT_EQ("video", offer->contents()[0].name);
3288 EXPECT_EQ("audio", offer->contents()[1].name);
3289}
3290
3291// Test that different media sections using the same codec have same payload
3292// type.
3293TEST_F(MediaSessionDescriptionFactoryTest,
3294 PayloadTypesSharedByMediaSectionsOfSameType) {
3295 MediaSessionOptions opts;
3296 AddMediaSection(MEDIA_TYPE_VIDEO, "video1", cricket::MD_SENDRECV, kActive,
3297 &opts);
3298 AddMediaSection(MEDIA_TYPE_VIDEO, "video2", cricket::MD_SENDRECV, kActive,
3299 &opts);
3300 // Create an offer with two video sections using same codecs.
3301 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3302 ASSERT_TRUE(offer);
3303 ASSERT_EQ(2u, offer->contents().size());
3304 const VideoContentDescription* vcd1 =
3305 static_cast<const VideoContentDescription*>(
3306 offer->contents()[0].description);
3307 const VideoContentDescription* vcd2 =
3308 static_cast<const VideoContentDescription*>(
3309 offer->contents()[1].description);
3310 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3311 ASSERT_EQ(2u, vcd1->codecs().size());
3312 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3313 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3314 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
3315 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
3316
3317 // Create answer and negotiate the codecs.
3318 std::unique_ptr<SessionDescription> answer(
3319 f2_.CreateAnswer(offer.get(), opts, nullptr));
3320 ASSERT_TRUE(answer);
3321 ASSERT_EQ(2u, answer->contents().size());
3322 vcd1 = static_cast<const VideoContentDescription*>(
3323 answer->contents()[0].description);
3324 vcd2 = static_cast<const VideoContentDescription*>(
3325 answer->contents()[1].description);
3326 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3327 ASSERT_EQ(1u, vcd1->codecs().size());
3328 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3329 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3330}
3331
3332// Test that the codec preference order per media section is respected in
3333// subsequent offer.
3334TEST_F(MediaSessionDescriptionFactoryTest,
3335 CreateOfferRespectsCodecPreferenceOrder) {
3336 MediaSessionOptions opts;
3337 AddMediaSection(MEDIA_TYPE_VIDEO, "video1", cricket::MD_SENDRECV, kActive,
3338 &opts);
3339 AddMediaSection(MEDIA_TYPE_VIDEO, "video2", cricket::MD_SENDRECV, kActive,
3340 &opts);
3341 // Create an offer with two video sections using same codecs.
3342 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3343 ASSERT_TRUE(offer);
3344 ASSERT_EQ(2u, offer->contents().size());
3345 VideoContentDescription* vcd1 =
3346 static_cast<VideoContentDescription*>(offer->contents()[0].description);
3347 const VideoContentDescription* vcd2 =
3348 static_cast<const VideoContentDescription*>(
3349 offer->contents()[1].description);
3350 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3351 EXPECT_EQ(video_codecs, vcd1->codecs());
3352 EXPECT_EQ(video_codecs, vcd2->codecs());
3353
3354 // Change the codec preference of the first video section and create a
3355 // follow-up offer.
3356 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3357 vcd1->set_codecs(video_codecs_reverse);
3358 std::unique_ptr<SessionDescription> updated_offer(
3359 f1_.CreateOffer(opts, offer.get()));
3360 vcd1 = static_cast<VideoContentDescription*>(
3361 updated_offer->contents()[0].description);
3362 vcd2 = static_cast<const VideoContentDescription*>(
3363 updated_offer->contents()[1].description);
3364 // The video codec preference order should be respected.
3365 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3366 EXPECT_EQ(video_codecs, vcd2->codecs());
3367}
3368
3369// Test that the codec preference order per media section is respected in
3370// the answer.
3371TEST_F(MediaSessionDescriptionFactoryTest,
3372 CreateAnswerRespectsCodecPreferenceOrder) {
3373 MediaSessionOptions opts;
3374 AddMediaSection(MEDIA_TYPE_VIDEO, "video1", cricket::MD_SENDRECV, kActive,
3375 &opts);
3376 AddMediaSection(MEDIA_TYPE_VIDEO, "video2", cricket::MD_SENDRECV, kActive,
3377 &opts);
3378 // Create an offer with two video sections using same codecs.
3379 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3380 ASSERT_TRUE(offer);
3381 ASSERT_EQ(2u, offer->contents().size());
3382 VideoContentDescription* vcd1 =
3383 static_cast<VideoContentDescription*>(offer->contents()[0].description);
3384 const VideoContentDescription* vcd2 =
3385 static_cast<const VideoContentDescription*>(
3386 offer->contents()[1].description);
3387 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3388 EXPECT_EQ(video_codecs, vcd1->codecs());
3389 EXPECT_EQ(video_codecs, vcd2->codecs());
3390
3391 // Change the codec preference of the first video section and create an
3392 // answer.
3393 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3394 vcd1->set_codecs(video_codecs_reverse);
3395 std::unique_ptr<SessionDescription> answer(
3396 f1_.CreateAnswer(offer.get(), opts, nullptr));
3397 vcd1 =
3398 static_cast<VideoContentDescription*>(answer->contents()[0].description);
3399 vcd2 = static_cast<const VideoContentDescription*>(
3400 answer->contents()[1].description);
3401 // The video codec preference order should be respected.
3402 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3403 EXPECT_EQ(video_codecs, vcd2->codecs());
3404}
3405
zhihuangcf5b37c2016-05-05 11:44:35 -07003406class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
3407 public:
3408 MediaProtocolTest() : f1_(&tdf1_), f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -07003409 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
3410 MAKE_VECTOR(kAudioCodecs1));
zhihuangcf5b37c2016-05-05 11:44:35 -07003411 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
3412 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07003413 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
3414 MAKE_VECTOR(kAudioCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07003415 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
3416 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
3417 f1_.set_secure(SEC_ENABLED);
3418 f2_.set_secure(SEC_ENABLED);
3419 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07003420 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07003421 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07003422 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07003423 tdf1_.set_secure(SEC_ENABLED);
3424 tdf2_.set_secure(SEC_ENABLED);
3425 }
3426
3427 protected:
3428 MediaSessionDescriptionFactory f1_;
3429 MediaSessionDescriptionFactory f2_;
3430 TransportDescriptionFactory tdf1_;
3431 TransportDescriptionFactory tdf2_;
3432};
3433
3434TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
3435 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003436 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
zhihuangcf5b37c2016-05-05 11:44:35 -07003437 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3438 ASSERT_TRUE(offer.get() != nullptr);
3439 // Set the protocol for all the contents.
3440 for (auto content : offer.get()->contents()) {
3441 static_cast<MediaContentDescription*>(content.description)
3442 ->set_protocol(GetParam());
3443 }
3444 std::unique_ptr<SessionDescription> answer(
3445 f2_.CreateAnswer(offer.get(), opts, nullptr));
3446 const ContentInfo* ac = answer->GetContentByName("audio");
3447 const ContentInfo* vc = answer->GetContentByName("video");
3448 ASSERT_TRUE(ac != nullptr);
3449 ASSERT_TRUE(vc != nullptr);
3450 EXPECT_FALSE(ac->rejected); // the offer is accepted
3451 EXPECT_FALSE(vc->rejected);
3452 const AudioContentDescription* acd =
3453 static_cast<const AudioContentDescription*>(ac->description);
3454 const VideoContentDescription* vcd =
3455 static_cast<const VideoContentDescription*>(vc->description);
3456 EXPECT_EQ(GetParam(), acd->protocol());
3457 EXPECT_EQ(GetParam(), vcd->protocol());
3458}
3459
3460INSTANTIATE_TEST_CASE_P(MediaProtocolPatternTest,
3461 MediaProtocolTest,
3462 ::testing::ValuesIn(kMediaProtocols));
3463INSTANTIATE_TEST_CASE_P(MediaProtocolDtlsPatternTest,
3464 MediaProtocolTest,
3465 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07003466
3467TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
3468 TransportDescriptionFactory tdf;
3469 MediaSessionDescriptionFactory sf(&tdf);
3470 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
3471 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
3472
3473 // The merged list of codecs should contain any send codecs that are also
3474 // nominally in the recieve codecs list. Payload types should be picked from
3475 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
3476 // (set to 1). This equals what happens when the send codecs are used in an
3477 // offer and the receive codecs are used in the following answer.
3478 const std::vector<AudioCodec> sendrecv_codecs =
3479 MAKE_VECTOR(kAudioCodecsAnswer);
3480 const std::vector<AudioCodec> no_codecs;
3481
3482 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
3483 << "Please don't change shared test data!";
3484 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
3485 << "Please don't change shared test data!";
3486 // Alter iLBC send codec to have zero channels, to test that that is handled
3487 // properly.
3488 send_codecs[1].channels = 0;
3489
3490 // Alther iLBC receive codec to be lowercase, to test that case conversions
3491 // are handled properly.
3492 recv_codecs[2].name = "ilbc";
3493
3494 // Test proper merge
3495 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003496 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
3497 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
3498 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003499
3500 // Test empty send codecs list
3501 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003502 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
3503 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
3504 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003505
3506 // Test empty recv codecs list
3507 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003508 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
3509 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
3510 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003511
3512 // Test all empty codec lists
3513 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003514 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
3515 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
3516 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003517}
3518
3519namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07003520// Compare the two vectors of codecs ignoring the payload type.
3521template <class Codec>
3522bool CodecsMatch(const std::vector<Codec>& codecs1,
3523 const std::vector<Codec>& codecs2) {
3524 if (codecs1.size() != codecs2.size()) {
3525 return false;
3526 }
3527
3528 for (size_t i = 0; i < codecs1.size(); ++i) {
3529 if (!codecs1[i].Matches(codecs2[i])) {
3530 return false;
3531 }
3532 }
3533 return true;
3534}
3535
3536void TestAudioCodecsOffer(MediaContentDirection direction) {
ossu075af922016-06-14 03:29:38 -07003537 TransportDescriptionFactory tdf;
3538 MediaSessionDescriptionFactory sf(&tdf);
3539 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
3540 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
3541 const std::vector<AudioCodec> sendrecv_codecs =
3542 MAKE_VECTOR(kAudioCodecsAnswer);
3543 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07003544
3545 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003546 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", direction, kActive, &opts);
3547
3548 if (RtpTransceiverDirection::FromMediaContentDirection(direction).send) {
3549 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003550 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003551 }
ossu075af922016-06-14 03:29:38 -07003552
3553 std::unique_ptr<SessionDescription> offer(sf.CreateOffer(opts, NULL));
3554 ASSERT_TRUE(offer.get() != NULL);
3555 const ContentInfo* ac = offer->GetContentByName("audio");
3556
3557 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07003558 // that the codecs put in are right. This happens when we neither want to
3559 // send nor receive audio. The checks are still in place if at some point
3560 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07003561 if (ac) {
3562 AudioContentDescription* acd =
3563 static_cast<AudioContentDescription*>(ac->description);
zhihuang1c378ed2017-08-17 14:10:50 -07003564 // sendrecv and inactive should both present lists as if the channel was
3565 // to be used for sending and receiving. Inactive essentially means it
3566 // might eventually be used anything, but we don't know more at this
3567 // moment.
ossu075af922016-06-14 03:29:38 -07003568 if (acd->direction() == cricket::MD_SENDONLY) {
zhihuang1c378ed2017-08-17 14:10:50 -07003569 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07003570 } else if (acd->direction() == cricket::MD_RECVONLY) {
zhihuang1c378ed2017-08-17 14:10:50 -07003571 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07003572 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07003573 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07003574 }
3575 }
3576}
3577
3578static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07003579 AudioCodec(0, "codec0", 16000, -1, 1),
3580 AudioCodec(1, "codec1", 8000, 13300, 1),
3581 AudioCodec(2, "codec2", 8000, 64000, 1),
3582 AudioCodec(3, "codec3", 8000, 64000, 1),
3583 AudioCodec(4, "codec4", 8000, 0, 2),
3584 AudioCodec(5, "codec5", 32000, 0, 1),
3585 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07003586
zhihuang1c378ed2017-08-17 14:10:50 -07003587/* The codecs groups below are chosen as per the matrix below. The objective
3588 * is to have different sets of codecs in the inputs, to get unique sets of
3589 * codecs after negotiation, depending on offer and answer communication
3590 * directions. One-way directions in the offer should either result in the
3591 * opposite direction in the answer, or an inactive answer. Regardless, the
3592 * choice of codecs should be as if the answer contained the opposite
3593 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07003594 *
3595 * | Offer | Answer | Result
3596 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
3597 * 0 | x - - | - x - | x - - - -
3598 * 1 | x x x | - x - | x - - x -
3599 * 2 | - x - | x - - | - x - - -
3600 * 3 | x x x | x - - | - x x - -
3601 * 4 | - x - | x x x | - x - - -
3602 * 5 | x - - | x x x | x - - - -
3603 * 6 | x x x | x x x | x x x x x
3604 */
3605// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07003606static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
3607static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07003608// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
3609// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07003610static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
3611static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07003612// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07003613static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
3614static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
3615static const int kResultSendrecv_SendCodecs[] = {3, 6};
3616static const int kResultSendrecv_RecvCodecs[] = {1, 6};
3617static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07003618
3619template <typename T, int IDXS>
3620std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
3621 std::vector<T> out;
3622 out.reserve(IDXS);
3623 for (int idx : indices)
3624 out.push_back(array[idx]);
3625
3626 return out;
3627}
3628
3629void TestAudioCodecsAnswer(MediaContentDirection offer_direction,
3630 MediaContentDirection answer_direction,
3631 bool add_legacy_stream) {
3632 TransportDescriptionFactory offer_tdf;
3633 TransportDescriptionFactory answer_tdf;
3634 MediaSessionDescriptionFactory offer_factory(&offer_tdf);
3635 MediaSessionDescriptionFactory answer_factory(&answer_tdf);
3636 offer_factory.set_audio_codecs(
3637 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
3638 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
3639 answer_factory.set_audio_codecs(
3640 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
3641 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
3642
ossu075af922016-06-14 03:29:38 -07003643 MediaSessionOptions offer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003644 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", offer_direction, kActive,
3645 &offer_opts);
3646
3647 if (RtpTransceiverDirection::FromMediaContentDirection(offer_direction)
3648 .send) {
3649 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003650 {kMediaStream1}, 1, &offer_opts);
ossu075af922016-06-14 03:29:38 -07003651 }
3652
3653 std::unique_ptr<SessionDescription> offer(
3654 offer_factory.CreateOffer(offer_opts, NULL));
3655 ASSERT_TRUE(offer.get() != NULL);
3656
3657 MediaSessionOptions answer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003658 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", answer_direction, kActive,
3659 &answer_opts);
3660
3661 if (RtpTransceiverDirection::FromMediaContentDirection(answer_direction)
3662 .send) {
3663 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003664 {kMediaStream1}, 1, &answer_opts);
ossu075af922016-06-14 03:29:38 -07003665 }
3666 std::unique_ptr<SessionDescription> answer(
3667 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL));
3668 const ContentInfo* ac = answer->GetContentByName("audio");
3669
zhihuang1c378ed2017-08-17 14:10:50 -07003670 // If the factory didn't add any audio content to the answer, we cannot
3671 // check that the codecs put in are right. This happens when we neither want
3672 // to send nor receive audio. The checks are still in place if at some point
3673 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07003674 if (ac) {
3675 const AudioContentDescription* acd =
3676 static_cast<const AudioContentDescription*>(ac->description);
3677 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
3678
ossu075af922016-06-14 03:29:38 -07003679 std::vector<AudioCodec> target_codecs;
3680 // For offers with sendrecv or inactive, we should never reply with more
3681 // codecs than offered, with these codec sets.
3682 switch (offer_direction) {
3683 case cricket::MD_INACTIVE:
3684 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
3685 kResultSendrecv_SendrecvCodecs);
3686 break;
3687 case cricket::MD_SENDONLY:
zhihuang1c378ed2017-08-17 14:10:50 -07003688 target_codecs =
3689 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07003690 break;
3691 case cricket::MD_RECVONLY:
zhihuang1c378ed2017-08-17 14:10:50 -07003692 target_codecs =
3693 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07003694 break;
3695 case cricket::MD_SENDRECV:
3696 if (acd->direction() == cricket::MD_SENDONLY) {
zhihuang1c378ed2017-08-17 14:10:50 -07003697 target_codecs =
3698 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07003699 } else if (acd->direction() == cricket::MD_RECVONLY) {
zhihuang1c378ed2017-08-17 14:10:50 -07003700 target_codecs =
3701 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07003702 } else {
3703 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
3704 kResultSendrecv_SendrecvCodecs);
3705 }
3706 break;
3707 }
3708
zhihuang1c378ed2017-08-17 14:10:50 -07003709 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
ossu075af922016-06-14 03:29:38 -07003710 std::stringstream os;
3711 bool first = true;
3712 os << "{";
3713 for (const auto& c : codecs) {
3714 os << (first ? " " : ", ") << c.id;
3715 first = false;
3716 }
3717 os << " }";
3718 return os.str();
3719 };
3720
3721 EXPECT_TRUE(acd->codecs() == target_codecs)
3722 << "Expected: " << format_codecs(target_codecs)
3723 << ", got: " << format_codecs(acd->codecs())
3724 << "; Offered: " << MediaContentDirectionToString(offer_direction)
3725 << ", answerer wants: "
3726 << MediaContentDirectionToString(answer_direction)
3727 << "; got: " << MediaContentDirectionToString(acd->direction());
3728 } else {
3729 EXPECT_EQ(offer_direction, cricket::MD_INACTIVE)
zhihuang1c378ed2017-08-17 14:10:50 -07003730 << "Only inactive offers are allowed to not generate any audio "
3731 "content";
ossu075af922016-06-14 03:29:38 -07003732 }
3733}
brandtr03d5fb12016-11-22 03:37:59 -08003734
3735} // namespace
ossu075af922016-06-14 03:29:38 -07003736
3737class AudioCodecsOfferTest
zhihuang1c378ed2017-08-17 14:10:50 -07003738 : public ::testing::TestWithParam<MediaContentDirection> {};
ossu075af922016-06-14 03:29:38 -07003739
3740TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003741 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07003742}
3743
3744INSTANTIATE_TEST_CASE_P(MediaSessionDescriptionFactoryTest,
3745 AudioCodecsOfferTest,
zhihuang1c378ed2017-08-17 14:10:50 -07003746 ::testing::Values(cricket::MD_SENDONLY,
3747 cricket::MD_RECVONLY,
3748 cricket::MD_SENDRECV,
3749 cricket::MD_INACTIVE));
ossu075af922016-06-14 03:29:38 -07003750
3751class AudioCodecsAnswerTest
ehmaldonadoabcef5d2017-02-08 04:07:11 -08003752 : public ::testing::TestWithParam<::testing::tuple<MediaContentDirection,
3753 MediaContentDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07003754 bool>> {};
ossu075af922016-06-14 03:29:38 -07003755
3756TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08003757 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
3758 ::testing::get<1>(GetParam()),
3759 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07003760}
3761
zhihuang1c378ed2017-08-17 14:10:50 -07003762INSTANTIATE_TEST_CASE_P(
3763 MediaSessionDescriptionFactoryTest,
3764 AudioCodecsAnswerTest,
3765 ::testing::Combine(::testing::Values(cricket::MD_SENDONLY,
3766 cricket::MD_RECVONLY,
3767 cricket::MD_SENDRECV,
3768 cricket::MD_INACTIVE),
3769 ::testing::Values(cricket::MD_SENDONLY,
3770 cricket::MD_RECVONLY,
3771 cricket::MD_SENDRECV,
3772 cricket::MD_INACTIVE),
3773 ::testing::Bool()));