blob: 28883f2384e98d6e64dd5ce71d59ce5f867273cd [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
kjellander65c7f672016-02-12 00:05:01 -08002 * Copyright 2004 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
kjellander65c7f672016-02-12 00:05:01 -08004 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00009 */
10
kwiberg31022942016-03-11 14:18:21 -080011#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000012#include <string>
13#include <vector>
14
kjellandera96e2d72016-02-04 23:52:28 -080015#include "webrtc/media/base/codec.h"
16#include "webrtc/media/base/testutils.h"
kjellanderf4752772016-03-02 05:42:30 -080017#include "webrtc/p2p/base/p2pconstants.h"
kjellandera96e2d72016-02-04 23:52:28 -080018#include "webrtc/p2p/base/transportdescription.h"
19#include "webrtc/p2p/base/transportinfo.h"
kjellander@webrtc.org9b8df252016-02-12 06:47:59 +010020#include "webrtc/pc/mediasession.h"
21#include "webrtc/pc/srtpfilter.h"
Edward Lemurc20978e2017-07-06 19:44:34 +020022#include "webrtc/rtc_base/checks.h"
23#include "webrtc/rtc_base/fakesslidentity.h"
24#include "webrtc/rtc_base/gunit.h"
25#include "webrtc/rtc_base/messagedigest.h"
26#include "webrtc/rtc_base/ssladapter.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000027
henrike@webrtc.org28e20752013-07-10 00:45:36 +000028#define ASSERT_CRYPTO(cd, s, cs) \
henrike@webrtc.org28e20752013-07-10 00:45:36 +000029 ASSERT_EQ(s, cd->cryptos().size()); \
30 ASSERT_EQ(std::string(cs), cd->cryptos()[0].cipher_suite)
henrike@webrtc.org28e20752013-07-10 00:45:36 +000031
32typedef std::vector<cricket::Candidate> Candidates;
33
34using cricket::MediaContentDescription;
35using cricket::MediaSessionDescriptionFactory;
ossu075af922016-06-14 03:29:38 -070036using cricket::MediaContentDirection;
zhihuang1c378ed2017-08-17 14:10:50 -070037using cricket::MediaDescriptionOptions;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000038using cricket::MediaSessionOptions;
39using cricket::MediaType;
40using cricket::SessionDescription;
41using cricket::SsrcGroup;
42using cricket::StreamParams;
43using cricket::StreamParamsVec;
44using cricket::TransportDescription;
45using cricket::TransportDescriptionFactory;
46using cricket::TransportInfo;
47using cricket::ContentInfo;
48using cricket::CryptoParamsVec;
49using cricket::AudioContentDescription;
50using cricket::VideoContentDescription;
51using cricket::DataContentDescription;
deadbeef44f08192015-12-15 16:20:09 -080052using cricket::GetFirstAudioContent;
53using cricket::GetFirstVideoContent;
54using cricket::GetFirstDataContent;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000055using cricket::GetFirstAudioContentDescription;
56using cricket::GetFirstVideoContentDescription;
57using cricket::GetFirstDataContentDescription;
58using cricket::kAutoBandwidth;
59using cricket::AudioCodec;
60using cricket::VideoCodec;
61using cricket::DataCodec;
62using cricket::NS_JINGLE_RTP;
63using cricket::MEDIA_TYPE_AUDIO;
64using cricket::MEDIA_TYPE_VIDEO;
65using cricket::MEDIA_TYPE_DATA;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000066using cricket::SEC_DISABLED;
67using cricket::SEC_ENABLED;
68using cricket::SEC_REQUIRED;
zhihuang1c378ed2017-08-17 14:10:50 -070069using cricket::RtpTransceiverDirection;
Guo-wei Shieh456696a2015-09-30 21:48:54 -070070using rtc::CS_AES_CM_128_HMAC_SHA1_32;
71using rtc::CS_AES_CM_128_HMAC_SHA1_80;
jbauchcb560652016-08-04 05:20:32 -070072using rtc::CS_AEAD_AES_128_GCM;
73using rtc::CS_AEAD_AES_256_GCM;
isheriff6f8d6862016-05-26 11:24:55 -070074using webrtc::RtpExtension;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000075
76static const AudioCodec kAudioCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070077 AudioCodec(103, "ISAC", 16000, -1, 1),
78 AudioCodec(102, "iLBC", 8000, 13300, 1),
79 AudioCodec(0, "PCMU", 8000, 64000, 1),
80 AudioCodec(8, "PCMA", 8000, 64000, 1),
81 AudioCodec(117, "red", 8000, 0, 1),
82 AudioCodec(107, "CN", 48000, 0, 1)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +000083
84static const AudioCodec kAudioCodecs2[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070085 AudioCodec(126, "speex", 16000, 22000, 1),
86 AudioCodec(0, "PCMU", 8000, 64000, 1),
87 AudioCodec(127, "iLBC", 8000, 13300, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +000088};
89
90static const AudioCodec kAudioCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070091 AudioCodec(102, "iLBC", 8000, 13300, 1),
92 AudioCodec(0, "PCMU", 8000, 64000, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +000093};
94
perkj26752742016-10-24 01:21:16 -070095static const VideoCodec kVideoCodecs1[] = {VideoCodec(96, "H264-SVC"),
96 VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +000097
zhihuang1c378ed2017-08-17 14:10:50 -070098static const VideoCodec kVideoCodecs1Reverse[] = {VideoCodec(97, "H264"),
99 VideoCodec(96, "H264-SVC")};
100
perkj26752742016-10-24 01:21:16 -0700101static const VideoCodec kVideoCodecs2[] = {VideoCodec(126, "H264"),
102 VideoCodec(127, "H263")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000103
perkj26752742016-10-24 01:21:16 -0700104static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000105
deadbeef67cf2c12016-04-13 10:07:16 -0700106static const DataCodec kDataCodecs1[] = {DataCodec(98, "binary-data"),
107 DataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000108
deadbeef67cf2c12016-04-13 10:07:16 -0700109static const DataCodec kDataCodecs2[] = {DataCodec(126, "binary-data"),
110 DataCodec(127, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000111
deadbeef67cf2c12016-04-13 10:07:16 -0700112static const DataCodec kDataCodecsAnswer[] = {DataCodec(98, "binary-data"),
113 DataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000114
isheriff6f8d6862016-05-26 11:24:55 -0700115static const RtpExtension kAudioRtpExtension1[] = {
116 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
117 RtpExtension("http://google.com/testing/audio_something", 10),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000118};
119
jbauch5869f502017-06-29 12:31:36 -0700120static const RtpExtension kAudioRtpExtensionEncrypted1[] = {
121 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
122 RtpExtension("http://google.com/testing/audio_something", 10),
123 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
124};
125
isheriff6f8d6862016-05-26 11:24:55 -0700126static const RtpExtension kAudioRtpExtension2[] = {
127 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
128 RtpExtension("http://google.com/testing/audio_something_else", 8),
129 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000130};
131
isheriff6f8d6862016-05-26 11:24:55 -0700132static const RtpExtension kAudioRtpExtension3[] = {
133 RtpExtension("http://google.com/testing/audio_something", 2),
134 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
deadbeefa5b273a2015-08-20 17:30:13 -0700135};
136
jbauch5869f502017-06-29 12:31:36 -0700137static const RtpExtension kAudioRtpExtension3ForEncryption[] = {
138 RtpExtension("http://google.com/testing/audio_something", 2),
139 // Use RTP extension that supports encryption.
140 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
141};
142
143static const RtpExtension kAudioRtpExtension3ForEncryptionOffer[] = {
144 RtpExtension("http://google.com/testing/audio_something", 2),
145 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
146 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14, true),
147};
148
isheriff6f8d6862016-05-26 11:24:55 -0700149static const RtpExtension kAudioRtpExtensionAnswer[] = {
150 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000151};
152
jbauch5869f502017-06-29 12:31:36 -0700153static const RtpExtension kAudioRtpExtensionEncryptedAnswer[] = {
154 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
155};
156
isheriff6f8d6862016-05-26 11:24:55 -0700157static const RtpExtension kVideoRtpExtension1[] = {
158 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
159 RtpExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000160};
161
jbauch5869f502017-06-29 12:31:36 -0700162static const RtpExtension kVideoRtpExtensionEncrypted1[] = {
163 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
164 RtpExtension("http://google.com/testing/video_something", 13),
165 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
166};
167
isheriff6f8d6862016-05-26 11:24:55 -0700168static const RtpExtension kVideoRtpExtension2[] = {
169 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
170 RtpExtension("http://google.com/testing/video_something_else", 14),
171 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000172};
173
isheriff6f8d6862016-05-26 11:24:55 -0700174static const RtpExtension kVideoRtpExtension3[] = {
175 RtpExtension("http://google.com/testing/video_something", 4),
176 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
deadbeefa5b273a2015-08-20 17:30:13 -0700177};
178
jbauch5869f502017-06-29 12:31:36 -0700179static const RtpExtension kVideoRtpExtension3ForEncryption[] = {
180 RtpExtension("http://google.com/testing/video_something", 4),
181 // Use RTP extension that supports encryption.
182 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 5),
183};
184
isheriff6f8d6862016-05-26 11:24:55 -0700185static const RtpExtension kVideoRtpExtensionAnswer[] = {
186 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000187};
188
jbauch5869f502017-06-29 12:31:36 -0700189static const RtpExtension kVideoRtpExtensionEncryptedAnswer[] = {
190 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
191};
192
Peter Boström0c4e06b2015-10-07 12:23:21 +0200193static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
194static const uint32_t kSimSsrc[] = {10, 20, 30};
195static const uint32_t kFec1Ssrc[] = {10, 11};
196static const uint32_t kFec2Ssrc[] = {20, 21};
197static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000198
199static const char kMediaStream1[] = "stream_1";
200static const char kMediaStream2[] = "stream_2";
201static const char kVideoTrack1[] = "video_1";
202static const char kVideoTrack2[] = "video_2";
203static const char kAudioTrack1[] = "audio_1";
204static const char kAudioTrack2[] = "audio_2";
205static const char kAudioTrack3[] = "audio_3";
206static const char kDataTrack1[] = "data_1";
207static const char kDataTrack2[] = "data_2";
208static const char kDataTrack3[] = "data_3";
209
zhihuangcf5b37c2016-05-05 11:44:35 -0700210static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
211 "RTP/SAVPF"};
212static const char* kMediaProtocolsDtls[] = {
213 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
214 "UDP/TLS/RTP/SAVP"};
215
zhihuang1c378ed2017-08-17 14:10:50 -0700216// These constants are used to make the code using "AddMediaSection" more
217// readable.
218static constexpr bool kStopped = true;
219static constexpr bool kActive = false;
220
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000221static bool IsMediaContentOfType(const ContentInfo* content,
222 MediaType media_type) {
223 const MediaContentDescription* mdesc =
224 static_cast<const MediaContentDescription*>(content->description);
225 return mdesc && mdesc->type() == media_type;
226}
227
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000228static cricket::MediaContentDirection
229GetMediaDirection(const ContentInfo* content) {
230 cricket::MediaContentDescription* desc =
231 reinterpret_cast<cricket::MediaContentDescription*>(content->description);
232 return desc->direction();
233}
234
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000235static void AddRtxCodec(const VideoCodec& rtx_codec,
236 std::vector<VideoCodec>* codecs) {
magjedb05fa242016-11-11 04:00:16 -0800237 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000238 codecs->push_back(rtx_codec);
239}
240
241template <class T>
242static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
243 std::vector<std::string> codec_names;
244 for (const auto& codec : codecs) {
245 codec_names.push_back(codec.name);
246 }
247 return codec_names;
248}
249
zhihuang1c378ed2017-08-17 14:10:50 -0700250// This is used for test only. MIDs are not the identification of the
251// MediaDescriptionOptions since some end points may not support MID and the SDP
252// may not contain 'mid'.
253std::vector<MediaDescriptionOptions>::iterator FindFirstMediaDescriptionByMid(
254 const std::string& mid,
255 MediaSessionOptions* opts) {
256 return std::find_if(
257 opts->media_description_options.begin(),
258 opts->media_description_options.end(),
259 [mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
260}
261
262// Add a media section to the |session_options|.
263static void AddMediaSection(MediaType type,
264 const std::string& mid,
265 MediaContentDirection direction,
266 bool stopped,
267 MediaSessionOptions* opts) {
268 opts->media_description_options.push_back(MediaDescriptionOptions(
269 type, mid,
270 cricket::RtpTransceiverDirection::FromMediaContentDirection(direction),
271 stopped));
272}
273
274static void AddAudioVideoSections(MediaContentDirection direction,
275 MediaSessionOptions* opts) {
276 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", direction, kActive, opts);
277 AddMediaSection(MEDIA_TYPE_VIDEO, "video", direction, kActive, opts);
278}
279
280static void AddDataSection(cricket::DataChannelType dct,
281 MediaContentDirection direction,
282 MediaSessionOptions* opts) {
283 opts->data_channel_type = dct;
284 AddMediaSection(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
285}
286
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
2080// Create an updated offer that adds video after creating an audio only answer
2081// to the original offer. This test verifies that if a video codec and the RTX
2082// codec have the same default payload type as an audio codec that is already in
2083// use, the added codecs payload types are changed.
2084TEST_F(MediaSessionDescriptionFactoryTest,
2085 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2086 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002087 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002088 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002089 f1_.set_video_codecs(f1_codecs);
2090
2091 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002092 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
2093 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002094
kwiberg31022942016-03-11 14:18:21 -08002095 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2096 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002097 f2_.CreateAnswer(offer.get(), opts, NULL));
2098
2099 const AudioContentDescription* acd =
2100 GetFirstAudioContentDescription(answer.get());
2101 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
2102
2103 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
2104 // reference be the same as an audio codec that was negotiated in the
2105 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002106 opts.media_description_options.clear();
2107 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002108
2109 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2110 int used_pl_type = acd->codecs()[0].id;
2111 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002112 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002113 f2_.set_video_codecs(f2_codecs);
2114
kwiberg31022942016-03-11 14:18:21 -08002115 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002116 f2_.CreateOffer(opts, answer.get()));
2117 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002118 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002119 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2120
2121 const AudioContentDescription* updated_acd =
2122 GetFirstAudioContentDescription(answer.get());
2123 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), updated_acd->codecs());
2124
2125 const VideoContentDescription* updated_vcd =
2126 GetFirstVideoContentDescription(updated_answer.get());
2127
2128 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
sergeyu@chromium.org32f485b2013-12-05 22:36:21 +00002129 ASSERT_EQ(std::string(cricket::kRtxCodecName), updated_vcd->codecs()[1].name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002130 int new_h264_pl_type = updated_vcd->codecs()[0].id;
2131 EXPECT_NE(used_pl_type, new_h264_pl_type);
2132 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002133 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002134 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
2135 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
2136}
2137
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002138// Create an updated offer with RTX after creating an answer to an offer
2139// without RTX, and with different default payload types.
2140// Verify that the added RTX codec references the correct payload type.
2141TEST_F(MediaSessionDescriptionFactoryTest,
2142 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
2143 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002144 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002145
2146 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2147 // This creates rtx for H264 with the payload type |f2_| uses.
2148 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
2149 f2_.set_video_codecs(f2_codecs);
2150
kwiberg31022942016-03-11 14:18:21 -08002151 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002152 ASSERT_TRUE(offer.get() != nullptr);
kwiberg31022942016-03-11 14:18:21 -08002153 std::unique_ptr<SessionDescription> answer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002154 f2_.CreateAnswer(offer.get(), opts, nullptr));
2155
2156 const VideoContentDescription* vcd =
2157 GetFirstVideoContentDescription(answer.get());
2158
2159 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2160 EXPECT_EQ(expected_codecs, vcd->codecs());
2161
2162 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
2163 // updated offer, even though the default payload types are different from
2164 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08002165 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002166 f2_.CreateOffer(opts, answer.get()));
2167 ASSERT_TRUE(updated_offer);
2168
2169 const VideoContentDescription* updated_vcd =
2170 GetFirstVideoContentDescription(updated_offer.get());
2171
2172 // New offer should attempt to add H263, and RTX for H264.
2173 expected_codecs.push_back(kVideoCodecs2[1]);
2174 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
2175 &expected_codecs);
2176 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2177}
2178
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002179// Test that RTX is ignored when there is no associated payload type parameter.
2180TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
2181 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002182 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
2183 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002184 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002185 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07002186 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002187 f1_.set_video_codecs(f1_codecs);
2188
2189 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002190 // This creates RTX for H264 with the payload type |f2_| uses.
2191 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002192 f2_.set_video_codecs(f2_codecs);
2193
kwiberg31022942016-03-11 14:18:21 -08002194 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002195 ASSERT_TRUE(offer.get() != NULL);
2196 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
2197 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
2198 // is possible to test that that RTX is dropped when
2199 // kCodecParamAssociatedPayloadType is missing in the offer.
2200 VideoContentDescription* desc =
2201 static_cast<cricket::VideoContentDescription*>(
2202 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
2203 ASSERT_TRUE(desc != NULL);
2204 std::vector<VideoCodec> codecs = desc->codecs();
2205 for (std::vector<VideoCodec>::iterator iter = codecs.begin();
2206 iter != codecs.end(); ++iter) {
2207 if (iter->name.find(cricket::kRtxCodecName) == 0) {
2208 iter->params.clear();
2209 }
2210 }
2211 desc->set_codecs(codecs);
2212
kwiberg31022942016-03-11 14:18:21 -08002213 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002214 f2_.CreateAnswer(offer.get(), opts, NULL));
2215
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002216 std::vector<std::string> codec_names =
2217 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
2218 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
2219 cricket::kRtxCodecName));
2220}
2221
2222// Test that RTX will be filtered out in the answer if its associated payload
2223// type doesn't match the local value.
2224TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
2225 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002226 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
2227 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002228 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2229 // This creates RTX for H264 in sender.
2230 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2231 f1_.set_video_codecs(f1_codecs);
2232
2233 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2234 // This creates RTX for H263 in receiver.
2235 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
2236 f2_.set_video_codecs(f2_codecs);
2237
kwiberg31022942016-03-11 14:18:21 -08002238 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002239 ASSERT_TRUE(offer.get() != NULL);
2240 // Associated payload type doesn't match, therefore, RTX codec is removed in
2241 // the answer.
kwiberg31022942016-03-11 14:18:21 -08002242 std::unique_ptr<SessionDescription> answer(
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002243 f2_.CreateAnswer(offer.get(), opts, NULL));
2244
2245 std::vector<std::string> codec_names =
2246 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
2247 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
2248 cricket::kRtxCodecName));
2249}
2250
2251// Test that when multiple RTX codecs are offered, only the matched RTX codec
2252// is added in the answer, and the unsupported RTX codec is filtered out.
2253TEST_F(MediaSessionDescriptionFactoryTest,
2254 FilterOutUnsupportedRtxWhenCreatingAnswer) {
2255 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002256 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
2257 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002258 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2259 // This creates RTX for H264-SVC in sender.
2260 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2261 f1_.set_video_codecs(f1_codecs);
2262
2263 // This creates RTX for H264 in sender.
2264 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2265 f1_.set_video_codecs(f1_codecs);
2266
2267 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2268 // This creates RTX for H264 in receiver.
2269 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
2270 f2_.set_video_codecs(f2_codecs);
2271
2272 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
2273 // for H264-SVC should also be removed.
kwiberg31022942016-03-11 14:18:21 -08002274 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002275 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002276 std::unique_ptr<SessionDescription> answer(
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002277 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002278 const VideoContentDescription* vcd =
2279 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002280 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2281 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2282 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002283
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002284 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002285}
2286
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002287// Test that after one RTX codec has been negotiated, a new offer can attempt
2288// to add another.
2289TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
2290 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002291 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
2292 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002293 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2294 // This creates RTX for H264 for the offerer.
2295 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2296 f1_.set_video_codecs(f1_codecs);
2297
kwiberg31022942016-03-11 14:18:21 -08002298 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002299 ASSERT_TRUE(offer);
2300 const VideoContentDescription* vcd =
2301 GetFirstVideoContentDescription(offer.get());
2302
2303 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
2304 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2305 &expected_codecs);
2306 EXPECT_EQ(expected_codecs, vcd->codecs());
2307
2308 // Now, attempt to add RTX for H264-SVC.
2309 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2310 f1_.set_video_codecs(f1_codecs);
2311
kwiberg31022942016-03-11 14:18:21 -08002312 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002313 f1_.CreateOffer(opts, offer.get()));
2314 ASSERT_TRUE(updated_offer);
2315 vcd = GetFirstVideoContentDescription(updated_offer.get());
2316
2317 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
2318 &expected_codecs);
2319 EXPECT_EQ(expected_codecs, vcd->codecs());
2320}
2321
Noah Richards2e7a0982015-05-18 14:02:54 -07002322// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
2323// generated for each simulcast ssrc and correctly grouped.
2324TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
2325 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002326 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_SENDRECV, kActive,
2327 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002328 // Add simulcast streams.
zhihuang1c378ed2017-08-17 14:10:50 -07002329 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002330 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002331
2332 // Use a single real codec, and then add RTX for it.
2333 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07002334 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07002335 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
2336 f1_.set_video_codecs(f1_codecs);
2337
2338 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
2339 // is a FID ssrc + grouping for each.
kwiberg31022942016-03-11 14:18:21 -08002340 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
Noah Richards2e7a0982015-05-18 14:02:54 -07002341 ASSERT_TRUE(offer.get() != NULL);
2342 VideoContentDescription* desc = static_cast<VideoContentDescription*>(
2343 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
2344 ASSERT_TRUE(desc != NULL);
2345 EXPECT_TRUE(desc->multistream());
2346 const StreamParamsVec& streams = desc->streams();
2347 // Single stream.
2348 ASSERT_EQ(1u, streams.size());
2349 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
2350 EXPECT_EQ(6u, streams[0].ssrcs.size());
2351 // And should have a SIM group for the simulcast.
2352 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2353 // And a FID group for RTX.
2354 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02002355 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002356 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2357 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02002358 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002359 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
2360 EXPECT_EQ(3u, fid_ssrcs.size());
2361}
2362
brandtr03d5fb12016-11-22 03:37:59 -08002363// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
2364// together with a FEC-FR grouping.
2365TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
2366 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002367 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_SENDRECV, kActive,
2368 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002369 // Add single stream.
zhihuang1c378ed2017-08-17 14:10:50 -07002370 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002371 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002372
2373 // Use a single real codec, and then add FlexFEC for it.
2374 std::vector<VideoCodec> f1_codecs;
2375 f1_codecs.push_back(VideoCodec(97, "H264"));
2376 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2377 f1_.set_video_codecs(f1_codecs);
2378
2379 // Ensure that the offer has a single FlexFEC ssrc and that
2380 // there is no FEC-FR ssrc + grouping for each.
2381 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
2382 ASSERT_TRUE(offer.get() != nullptr);
2383 VideoContentDescription* desc = static_cast<VideoContentDescription*>(
2384 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
2385 ASSERT_TRUE(desc != nullptr);
2386 EXPECT_TRUE(desc->multistream());
2387 const StreamParamsVec& streams = desc->streams();
2388 // Single stream.
2389 ASSERT_EQ(1u, streams.size());
2390 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
2391 EXPECT_EQ(2u, streams[0].ssrcs.size());
2392 // And should have a FEC-FR group for FlexFEC.
2393 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
2394 std::vector<uint32_t> primary_ssrcs;
2395 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2396 ASSERT_EQ(1u, primary_ssrcs.size());
2397 uint32_t flexfec_ssrc;
2398 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
2399 EXPECT_NE(flexfec_ssrc, 0u);
2400}
2401
2402// Test that FlexFEC is disabled for simulcast.
2403// TODO(brandtr): Remove this test when we support simulcast, either through
2404// multiple FlexfecSenders, or through multistream protection.
2405TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
2406 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002407 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_SENDRECV, kActive,
2408 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002409 // Add simulcast streams.
zhihuang1c378ed2017-08-17 14:10:50 -07002410 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002411 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002412
2413 // Use a single real codec, and then add FlexFEC for it.
2414 std::vector<VideoCodec> f1_codecs;
2415 f1_codecs.push_back(VideoCodec(97, "H264"));
2416 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2417 f1_.set_video_codecs(f1_codecs);
2418
2419 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
2420 // there is no FEC-FR ssrc + grouping for each.
2421 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
2422 ASSERT_TRUE(offer.get() != nullptr);
2423 VideoContentDescription* desc = static_cast<VideoContentDescription*>(
2424 offer->GetContentDescriptionByName(cricket::CN_VIDEO));
2425 ASSERT_TRUE(desc != nullptr);
2426 EXPECT_FALSE(desc->multistream());
2427 const StreamParamsVec& streams = desc->streams();
2428 // Single stream.
2429 ASSERT_EQ(1u, streams.size());
2430 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
2431 EXPECT_EQ(3u, streams[0].ssrcs.size());
2432 // And should have a SIM group for the simulcast.
2433 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2434 // And not a FEC-FR group for FlexFEC.
2435 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
2436 std::vector<uint32_t> primary_ssrcs;
2437 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2438 EXPECT_EQ(3u, primary_ssrcs.size());
2439 for (uint32_t primary_ssrc : primary_ssrcs) {
2440 uint32_t flexfec_ssrc;
2441 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
2442 }
2443}
2444
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002445// Create an updated offer after creating an answer to the original offer and
2446// verify that the RTP header extensions that were part of the original answer
2447// are not changed in the updated offer.
2448TEST_F(MediaSessionDescriptionFactoryTest,
2449 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
2450 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002451 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002452
2453 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
2454 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
2455 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
2456 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
2457
kwiberg31022942016-03-11 14:18:21 -08002458 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2459 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002460 f2_.CreateAnswer(offer.get(), opts, NULL));
2461
2462 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
2463 GetFirstAudioContentDescription(
2464 answer.get())->rtp_header_extensions());
2465 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
2466 GetFirstVideoContentDescription(
2467 answer.get())->rtp_header_extensions());
2468
kwiberg31022942016-03-11 14:18:21 -08002469 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002470 f2_.CreateOffer(opts, answer.get()));
2471
2472 // The expected RTP header extensions in the new offer are the resulting
2473 // extensions from the first offer/answer exchange plus the extensions only
2474 // |f2_| offer.
2475 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002476 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07002477 const RtpExtension kUpdatedAudioRtpExtensions[] = {
2478 kAudioRtpExtensionAnswer[0], RtpExtension(kAudioRtpExtension2[1].uri, 13),
2479 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002480 };
2481
2482 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002483 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07002484 const RtpExtension kUpdatedVideoRtpExtensions[] = {
2485 kVideoRtpExtensionAnswer[0], RtpExtension(kVideoRtpExtension2[1].uri, 12),
2486 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002487 };
2488
2489 const AudioContentDescription* updated_acd =
2490 GetFirstAudioContentDescription(updated_offer.get());
2491 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
2492 updated_acd->rtp_header_extensions());
2493
2494 const VideoContentDescription* updated_vcd =
2495 GetFirstVideoContentDescription(updated_offer.get());
2496 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
2497 updated_vcd->rtp_header_extensions());
2498}
2499
deadbeefa5b273a2015-08-20 17:30:13 -07002500// Verify that if the same RTP extension URI is used for audio and video, the
2501// same ID is used. Also verify that the ID isn't changed when creating an
2502// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07002503TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07002504 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002505 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07002506
2507 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
2508 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
2509
kwiberg31022942016-03-11 14:18:21 -08002510 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
deadbeefa5b273a2015-08-20 17:30:13 -07002511
2512 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
2513 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07002514 const RtpExtension kExpectedVideoRtpExtension[] = {
2515 kVideoRtpExtension3[0], kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07002516 };
2517
2518 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
2519 GetFirstAudioContentDescription(
2520 offer.get())->rtp_header_extensions());
2521 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2522 GetFirstVideoContentDescription(
2523 offer.get())->rtp_header_extensions());
2524
2525 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08002526 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07002527 f1_.CreateOffer(opts, offer.get()));
2528
2529 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
2530 GetFirstAudioContentDescription(
2531 updated_offer.get())->rtp_header_extensions());
2532 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2533 GetFirstVideoContentDescription(
2534 updated_offer.get())->rtp_header_extensions());
2535}
2536
jbauch5869f502017-06-29 12:31:36 -07002537// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
2538TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
2539 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002540 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
jbauch5869f502017-06-29 12:31:36 -07002541
2542 f1_.set_enable_encrypted_rtp_header_extensions(true);
2543 f2_.set_enable_encrypted_rtp_header_extensions(true);
2544
2545 f1_.set_audio_rtp_header_extensions(
2546 MAKE_VECTOR(kAudioRtpExtension3ForEncryption));
2547 f1_.set_video_rtp_header_extensions(
2548 MAKE_VECTOR(kVideoRtpExtension3ForEncryption));
2549
2550 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2551
2552 // The extensions that are shared between audio and video should use the same
2553 // id.
2554 const RtpExtension kExpectedVideoRtpExtension[] = {
2555 kVideoRtpExtension3ForEncryption[0],
2556 kAudioRtpExtension3ForEncryptionOffer[1],
2557 kAudioRtpExtension3ForEncryptionOffer[2],
2558 };
2559
2560 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
2561 GetFirstAudioContentDescription(
2562 offer.get())->rtp_header_extensions());
2563 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2564 GetFirstVideoContentDescription(
2565 offer.get())->rtp_header_extensions());
2566
2567 // Nothing should change when creating a new offer
2568 std::unique_ptr<SessionDescription> updated_offer(
2569 f1_.CreateOffer(opts, offer.get()));
2570
2571 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
2572 GetFirstAudioContentDescription(
2573 updated_offer.get())->rtp_header_extensions());
2574 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2575 GetFirstVideoContentDescription(
2576 updated_offer.get())->rtp_header_extensions());
2577}
2578
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002579TEST(MediaSessionDescription, CopySessionDescription) {
2580 SessionDescription source;
2581 cricket::ContentGroup group(cricket::CN_AUDIO);
2582 source.AddGroup(group);
2583 AudioContentDescription* acd(new AudioContentDescription());
2584 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
2585 acd->AddLegacyStream(1);
2586 source.AddContent(cricket::CN_AUDIO, cricket::NS_JINGLE_RTP, acd);
2587 VideoContentDescription* vcd(new VideoContentDescription());
2588 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
2589 vcd->AddLegacyStream(2);
2590 source.AddContent(cricket::CN_VIDEO, cricket::NS_JINGLE_RTP, vcd);
2591
kwiberg31022942016-03-11 14:18:21 -08002592 std::unique_ptr<SessionDescription> copy(source.Copy());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002593 ASSERT_TRUE(copy.get() != NULL);
2594 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
2595 const ContentInfo* ac = copy->GetContentByName("audio");
2596 const ContentInfo* vc = copy->GetContentByName("video");
2597 ASSERT_TRUE(ac != NULL);
2598 ASSERT_TRUE(vc != NULL);
2599 EXPECT_EQ(std::string(NS_JINGLE_RTP), ac->type);
2600 const AudioContentDescription* acd_copy =
2601 static_cast<const AudioContentDescription*>(ac->description);
2602 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
2603 EXPECT_EQ(1u, acd->first_ssrc());
2604
2605 EXPECT_EQ(std::string(NS_JINGLE_RTP), vc->type);
2606 const VideoContentDescription* vcd_copy =
2607 static_cast<const VideoContentDescription*>(vc->description);
2608 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
2609 EXPECT_EQ(2u, vcd->first_ssrc());
2610}
2611
2612// The below TestTransportInfoXXX tests create different offers/answers, and
2613// ensure the TransportInfo in the SessionDescription matches what we expect.
2614TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
2615 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002616 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
2617 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002618 TestTransportInfo(true, options, false);
2619}
2620
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002621TEST_F(MediaSessionDescriptionFactoryTest,
2622 TestTransportInfoOfferIceRenomination) {
2623 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002624 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
2625 &options);
2626 options.media_description_options[0]
2627 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002628 TestTransportInfo(true, options, false);
2629}
2630
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002631TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
2632 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002633 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
2634 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002635 TestTransportInfo(true, options, true);
2636}
2637
2638TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
2639 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002640 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2641 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002642 TestTransportInfo(true, options, false);
2643}
2644
2645TEST_F(MediaSessionDescriptionFactoryTest,
2646 TestTransportInfoOfferMultimediaCurrent) {
2647 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002648 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2649 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002650 TestTransportInfo(true, options, true);
2651}
2652
2653TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
2654 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002655 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2656 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002657 options.bundle_enabled = true;
2658 TestTransportInfo(true, options, false);
2659}
2660
2661TEST_F(MediaSessionDescriptionFactoryTest,
2662 TestTransportInfoOfferBundleCurrent) {
2663 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002664 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2665 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002666 options.bundle_enabled = true;
2667 TestTransportInfo(true, options, true);
2668}
2669
2670TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
2671 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002672 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
2673 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002674 TestTransportInfo(false, options, false);
2675}
2676
2677TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002678 TestTransportInfoAnswerIceRenomination) {
2679 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002680 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
2681 &options);
2682 options.media_description_options[0]
2683 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002684 TestTransportInfo(false, options, false);
2685}
2686
2687TEST_F(MediaSessionDescriptionFactoryTest,
2688 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002689 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002690 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
2691 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002692 TestTransportInfo(false, options, true);
2693}
2694
2695TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
2696 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002697 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2698 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002699 TestTransportInfo(false, options, false);
2700}
2701
2702TEST_F(MediaSessionDescriptionFactoryTest,
2703 TestTransportInfoAnswerMultimediaCurrent) {
2704 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002705 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2706 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002707 TestTransportInfo(false, options, true);
2708}
2709
2710TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
2711 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002712 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2713 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002714 options.bundle_enabled = true;
2715 TestTransportInfo(false, options, false);
2716}
2717
2718TEST_F(MediaSessionDescriptionFactoryTest,
2719 TestTransportInfoAnswerBundleCurrent) {
2720 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002721 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2722 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002723 options.bundle_enabled = true;
2724 TestTransportInfo(false, options, true);
2725}
2726
2727// Create an offer with bundle enabled and verify the crypto parameters are
2728// the common set of the available cryptos.
2729TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
2730 TestCryptoWithBundle(true);
2731}
2732
2733// Create an answer with bundle enabled and verify the crypto parameters are
2734// the common set of the available cryptos.
2735TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
2736 TestCryptoWithBundle(false);
2737}
2738
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002739// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
2740// DTLS is not enabled locally.
2741TEST_F(MediaSessionDescriptionFactoryTest,
2742 TestOfferDtlsSavpfWithoutDtlsFailed) {
2743 f1_.set_secure(SEC_ENABLED);
2744 f2_.set_secure(SEC_ENABLED);
2745 tdf1_.set_secure(SEC_DISABLED);
2746 tdf2_.set_secure(SEC_DISABLED);
2747
kwiberg31022942016-03-11 14:18:21 -08002748 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -07002749 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002750 ASSERT_TRUE(offer.get() != NULL);
2751 ContentInfo* offer_content = offer->GetContentByName("audio");
2752 ASSERT_TRUE(offer_content != NULL);
2753 AudioContentDescription* offer_audio_desc =
2754 static_cast<AudioContentDescription*>(offer_content->description);
2755 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2756
kwiberg31022942016-03-11 14:18:21 -08002757 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002758 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002759 ASSERT_TRUE(answer != NULL);
2760 ContentInfo* answer_content = answer->GetContentByName("audio");
2761 ASSERT_TRUE(answer_content != NULL);
2762
2763 ASSERT_TRUE(answer_content->rejected);
2764}
2765
2766// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
2767// UDP/TLS/RTP/SAVPF.
2768TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
2769 f1_.set_secure(SEC_ENABLED);
2770 f2_.set_secure(SEC_ENABLED);
2771 tdf1_.set_secure(SEC_ENABLED);
2772 tdf2_.set_secure(SEC_ENABLED);
2773
kwiberg31022942016-03-11 14:18:21 -08002774 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -07002775 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002776 ASSERT_TRUE(offer.get() != NULL);
2777 ContentInfo* offer_content = offer->GetContentByName("audio");
2778 ASSERT_TRUE(offer_content != NULL);
2779 AudioContentDescription* offer_audio_desc =
2780 static_cast<AudioContentDescription*>(offer_content->description);
2781 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2782
kwiberg31022942016-03-11 14:18:21 -08002783 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002784 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002785 ASSERT_TRUE(answer != NULL);
2786
2787 const ContentInfo* answer_content = answer->GetContentByName("audio");
2788 ASSERT_TRUE(answer_content != NULL);
2789 ASSERT_FALSE(answer_content->rejected);
2790
2791 const AudioContentDescription* answer_audio_desc =
2792 static_cast<const AudioContentDescription*>(answer_content->description);
2793 EXPECT_EQ(std::string(cricket::kMediaProtocolDtlsSavpf),
2794 answer_audio_desc->protocol());
2795}
2796
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002797// Test that we include both SDES and DTLS in the offer, but only include SDES
2798// in the answer if DTLS isn't negotiated.
2799TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
2800 f1_.set_secure(SEC_ENABLED);
2801 f2_.set_secure(SEC_ENABLED);
2802 tdf1_.set_secure(SEC_ENABLED);
2803 tdf2_.set_secure(SEC_DISABLED);
2804 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002805 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
kwiberg31022942016-03-11 14:18:21 -08002806 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002807 const cricket::MediaContentDescription* audio_media_desc;
2808 const cricket::MediaContentDescription* video_media_desc;
2809 const cricket::TransportDescription* audio_trans_desc;
2810 const cricket::TransportDescription* video_trans_desc;
2811
2812 // Generate an offer with SDES and DTLS support.
2813 offer.reset(f1_.CreateOffer(options, NULL));
2814 ASSERT_TRUE(offer.get() != NULL);
2815
2816 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2817 offer->GetContentDescriptionByName("audio"));
2818 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002819 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002820 offer->GetContentDescriptionByName("video"));
2821 ASSERT_TRUE(video_media_desc != NULL);
2822 EXPECT_EQ(2u, audio_media_desc->cryptos().size());
2823 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2824
2825 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2826 ASSERT_TRUE(audio_trans_desc != NULL);
2827 video_trans_desc = offer->GetTransportDescriptionByName("video");
2828 ASSERT_TRUE(video_trans_desc != NULL);
2829 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2830 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
2831
2832 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
2833 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2834 ASSERT_TRUE(answer.get() != NULL);
2835
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002836 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002837 answer->GetContentDescriptionByName("audio"));
2838 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002839 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002840 answer->GetContentDescriptionByName("video"));
2841 ASSERT_TRUE(video_media_desc != NULL);
2842 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
2843 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2844
2845 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2846 ASSERT_TRUE(audio_trans_desc != NULL);
2847 video_trans_desc = answer->GetTransportDescriptionByName("video");
2848 ASSERT_TRUE(video_trans_desc != NULL);
2849 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
2850 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
2851
2852 // Enable DTLS; the answer should now only have DTLS support.
2853 tdf2_.set_secure(SEC_ENABLED);
2854 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2855 ASSERT_TRUE(answer.get() != NULL);
2856
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002857 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002858 answer->GetContentDescriptionByName("audio"));
2859 ASSERT_TRUE(audio_media_desc != NULL);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002860 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002861 answer->GetContentDescriptionByName("video"));
2862 ASSERT_TRUE(video_media_desc != NULL);
2863 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2864 EXPECT_TRUE(video_media_desc->cryptos().empty());
2865 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2866 audio_media_desc->protocol());
2867 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2868 video_media_desc->protocol());
2869
2870 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2871 ASSERT_TRUE(audio_trans_desc != NULL);
2872 video_trans_desc = answer->GetTransportDescriptionByName("video");
2873 ASSERT_TRUE(video_trans_desc != NULL);
2874 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2875 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00002876
2877 // Try creating offer again. DTLS enabled now, crypto's should be empty
2878 // in new offer.
2879 offer.reset(f1_.CreateOffer(options, offer.get()));
2880 ASSERT_TRUE(offer.get() != NULL);
2881 audio_media_desc = static_cast<const cricket::MediaContentDescription*>(
2882 offer->GetContentDescriptionByName("audio"));
2883 ASSERT_TRUE(audio_media_desc != NULL);
2884 video_media_desc = static_cast<const cricket::MediaContentDescription*>(
2885 offer->GetContentDescriptionByName("video"));
2886 ASSERT_TRUE(video_media_desc != NULL);
2887 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2888 EXPECT_TRUE(video_media_desc->cryptos().empty());
2889
2890 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2891 ASSERT_TRUE(audio_trans_desc != NULL);
2892 video_trans_desc = offer->GetTransportDescriptionByName("video");
2893 ASSERT_TRUE(video_trans_desc != NULL);
2894 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2895 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002896}
2897
2898// Test that an answer can't be created if cryptos are required but the offer is
2899// unsecure.
2900TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07002901 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002902 f1_.set_secure(SEC_DISABLED);
2903 tdf1_.set_secure(SEC_DISABLED);
2904 f2_.set_secure(SEC_REQUIRED);
2905 tdf1_.set_secure(SEC_ENABLED);
2906
kwiberg31022942016-03-11 14:18:21 -08002907 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002908 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002909 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002910 f2_.CreateAnswer(offer.get(), options, NULL));
2911 EXPECT_TRUE(answer.get() == NULL);
2912}
2913
2914// Test that we accept a DTLS offer without SDES and create an appropriate
2915// answer.
2916TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
2917 f1_.set_secure(SEC_DISABLED);
2918 f2_.set_secure(SEC_ENABLED);
2919 tdf1_.set_secure(SEC_ENABLED);
2920 tdf2_.set_secure(SEC_ENABLED);
2921 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002922 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
2923 AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002924
kwiberg31022942016-03-11 14:18:21 -08002925 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002926
2927 // Generate an offer with DTLS but without SDES.
2928 offer.reset(f1_.CreateOffer(options, NULL));
2929 ASSERT_TRUE(offer.get() != NULL);
2930
2931 const AudioContentDescription* audio_offer =
2932 GetFirstAudioContentDescription(offer.get());
2933 ASSERT_TRUE(audio_offer->cryptos().empty());
2934 const VideoContentDescription* video_offer =
2935 GetFirstVideoContentDescription(offer.get());
2936 ASSERT_TRUE(video_offer->cryptos().empty());
2937 const DataContentDescription* data_offer =
2938 GetFirstDataContentDescription(offer.get());
2939 ASSERT_TRUE(data_offer->cryptos().empty());
2940
2941 const cricket::TransportDescription* audio_offer_trans_desc =
2942 offer->GetTransportDescriptionByName("audio");
2943 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
2944 const cricket::TransportDescription* video_offer_trans_desc =
2945 offer->GetTransportDescriptionByName("video");
2946 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
2947 const cricket::TransportDescription* data_offer_trans_desc =
2948 offer->GetTransportDescriptionByName("data");
2949 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
2950
2951 // Generate an answer with DTLS.
2952 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2953 ASSERT_TRUE(answer.get() != NULL);
2954
2955 const cricket::TransportDescription* audio_answer_trans_desc =
2956 answer->GetTransportDescriptionByName("audio");
2957 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
2958 const cricket::TransportDescription* video_answer_trans_desc =
2959 answer->GetTransportDescriptionByName("video");
2960 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
2961 const cricket::TransportDescription* data_answer_trans_desc =
2962 answer->GetTransportDescriptionByName("data");
2963 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
2964}
2965
2966// Verifies if vad_enabled option is set to false, CN codecs are not present in
2967// offer or answer.
2968TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
2969 MediaSessionOptions options;
zhihuang1c378ed2017-08-17 14:10:50 -07002970 AddAudioVideoSections(cricket::MD_RECVONLY, &options);
kwiberg31022942016-03-11 14:18:21 -08002971 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002972 ASSERT_TRUE(offer.get() != NULL);
2973 const ContentInfo* audio_content = offer->GetContentByName("audio");
2974 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
2975
2976 options.vad_enabled = false;
2977 offer.reset(f1_.CreateOffer(options, NULL));
2978 ASSERT_TRUE(offer.get() != NULL);
2979 audio_content = offer->GetContentByName("audio");
2980 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
kwiberg31022942016-03-11 14:18:21 -08002981 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002982 f1_.CreateAnswer(offer.get(), options, NULL));
2983 ASSERT_TRUE(answer.get() != NULL);
2984 audio_content = answer->GetContentByName("audio");
2985 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
2986}
deadbeef44f08192015-12-15 16:20:09 -08002987
zhihuang1c378ed2017-08-17 14:10:50 -07002988// Test that the generated MIDs match the existing offer.
2989TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08002990 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07002991 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_modified", cricket::MD_RECVONLY,
2992 kActive, &opts);
2993 AddMediaSection(MEDIA_TYPE_VIDEO, "video_modified", cricket::MD_RECVONLY,
2994 kActive, &opts);
deadbeef44f08192015-12-15 16:20:09 -08002995 opts.data_channel_type = cricket::DCT_SCTP;
zhihuang1c378ed2017-08-17 14:10:50 -07002996 AddMediaSection(MEDIA_TYPE_DATA, "data_modified", cricket::MD_SENDRECV,
2997 kActive, &opts);
2998 // Create offer.
kwiberg31022942016-03-11 14:18:21 -08002999 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
kwiberg31022942016-03-11 14:18:21 -08003000 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08003001 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003002
deadbeef44f08192015-12-15 16:20:09 -08003003 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3004 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3005 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3006 ASSERT_TRUE(audio_content != nullptr);
3007 ASSERT_TRUE(video_content != nullptr);
3008 ASSERT_TRUE(data_content != nullptr);
3009 EXPECT_EQ("audio_modified", audio_content->name);
3010 EXPECT_EQ("video_modified", video_content->name);
3011 EXPECT_EQ("data_modified", data_content->name);
3012}
zhihuangcf5b37c2016-05-05 11:44:35 -07003013
zhihuang1c378ed2017-08-17 14:10:50 -07003014// The following tests verify that the unified plan SDP is supported.
3015// Test that we can create an offer with multiple media sections of same media
3016// type.
3017TEST_F(MediaSessionDescriptionFactoryTest,
3018 CreateOfferWithMultipleAVMediaSections) {
3019 MediaSessionOptions opts;
3020 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_1", cricket::MD_SENDRECV, kActive,
3021 &opts);
3022 AttachSenderToMediaSection("audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003023 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003024
3025 AddMediaSection(MEDIA_TYPE_VIDEO, "video_1", cricket::MD_SENDRECV, kActive,
3026 &opts);
3027 AttachSenderToMediaSection("video_1", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003028 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003029
3030 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_2", cricket::MD_SENDRECV, kActive,
3031 &opts);
3032 AttachSenderToMediaSection("audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003033 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003034
3035 AddMediaSection(MEDIA_TYPE_VIDEO, "video_2", cricket::MD_SENDRECV, kActive,
3036 &opts);
3037 AttachSenderToMediaSection("video_2", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003038 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003039 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3040 ASSERT_TRUE(offer);
3041
3042 ASSERT_EQ(4u, offer->contents().size());
3043 EXPECT_FALSE(offer->contents()[0].rejected);
3044 const AudioContentDescription* acd =
3045 static_cast<const AudioContentDescription*>(
3046 offer->contents()[0].description);
3047 ASSERT_EQ(1u, acd->streams().size());
3048 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
3049 EXPECT_EQ(cricket::MD_SENDRECV, acd->direction());
3050
3051 EXPECT_FALSE(offer->contents()[1].rejected);
3052 const VideoContentDescription* vcd =
3053 static_cast<const VideoContentDescription*>(
3054 offer->contents()[1].description);
3055 ASSERT_EQ(1u, vcd->streams().size());
3056 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
3057 EXPECT_EQ(cricket::MD_SENDRECV, vcd->direction());
3058
3059 EXPECT_FALSE(offer->contents()[2].rejected);
3060 acd = static_cast<const AudioContentDescription*>(
3061 offer->contents()[2].description);
3062 ASSERT_EQ(1u, acd->streams().size());
3063 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
3064 EXPECT_EQ(cricket::MD_SENDRECV, acd->direction());
3065
3066 EXPECT_FALSE(offer->contents()[3].rejected);
3067 vcd = static_cast<const VideoContentDescription*>(
3068 offer->contents()[3].description);
3069 ASSERT_EQ(1u, vcd->streams().size());
3070 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
3071 EXPECT_EQ(cricket::MD_SENDRECV, vcd->direction());
3072}
3073
3074// Test that we can create an answer with multiple media sections of same media
3075// type.
3076TEST_F(MediaSessionDescriptionFactoryTest,
3077 CreateAnswerWithMultipleAVMediaSections) {
3078 MediaSessionOptions opts;
3079 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_1", cricket::MD_SENDRECV, kActive,
3080 &opts);
3081 AttachSenderToMediaSection("audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003082 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003083
3084 AddMediaSection(MEDIA_TYPE_VIDEO, "video_1", cricket::MD_SENDRECV, kActive,
3085 &opts);
3086 AttachSenderToMediaSection("video_1", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003087 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003088
3089 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_2", cricket::MD_SENDRECV, kActive,
3090 &opts);
3091 AttachSenderToMediaSection("audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003092 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003093
3094 AddMediaSection(MEDIA_TYPE_VIDEO, "video_2", cricket::MD_SENDRECV, kActive,
3095 &opts);
3096 AttachSenderToMediaSection("video_2", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003097 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003098
3099 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3100 ASSERT_TRUE(offer);
3101 std::unique_ptr<SessionDescription> answer(
3102 f2_.CreateAnswer(offer.get(), opts, nullptr));
3103
3104 ASSERT_EQ(4u, answer->contents().size());
3105 EXPECT_FALSE(answer->contents()[0].rejected);
3106 const AudioContentDescription* acd =
3107 static_cast<const AudioContentDescription*>(
3108 answer->contents()[0].description);
3109 ASSERT_EQ(1u, acd->streams().size());
3110 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
3111 EXPECT_EQ(cricket::MD_SENDRECV, acd->direction());
3112
3113 EXPECT_FALSE(answer->contents()[1].rejected);
3114 const VideoContentDescription* vcd =
3115 static_cast<const VideoContentDescription*>(
3116 answer->contents()[1].description);
3117 ASSERT_EQ(1u, vcd->streams().size());
3118 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
3119 EXPECT_EQ(cricket::MD_SENDRECV, vcd->direction());
3120
3121 EXPECT_FALSE(answer->contents()[2].rejected);
3122 acd = static_cast<const AudioContentDescription*>(
3123 answer->contents()[2].description);
3124 ASSERT_EQ(1u, acd->streams().size());
3125 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
3126 EXPECT_EQ(cricket::MD_SENDRECV, acd->direction());
3127
3128 EXPECT_FALSE(answer->contents()[3].rejected);
3129 vcd = static_cast<const VideoContentDescription*>(
3130 answer->contents()[3].description);
3131 ASSERT_EQ(1u, vcd->streams().size());
3132 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
3133 EXPECT_EQ(cricket::MD_SENDRECV, vcd->direction());
3134}
3135
3136// Test that the media section will be rejected in offer if the corresponding
3137// MediaDescriptionOptions is stopped by the offerer.
3138TEST_F(MediaSessionDescriptionFactoryTest,
3139 CreateOfferWithMediaSectionStoppedByOfferer) {
3140 // Create an offer with two audio sections and one of them is stopped.
3141 MediaSessionOptions offer_opts;
3142 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1", cricket::MD_SENDRECV, kActive,
3143 &offer_opts);
3144 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2", cricket::MD_INACTIVE, kStopped,
3145 &offer_opts);
3146 std::unique_ptr<SessionDescription> offer(
3147 f1_.CreateOffer(offer_opts, nullptr));
3148 ASSERT_TRUE(offer);
3149 ASSERT_EQ(2u, offer->contents().size());
3150 EXPECT_FALSE(offer->contents()[0].rejected);
3151 EXPECT_TRUE(offer->contents()[1].rejected);
3152}
3153
3154// Test that the media section will be rejected in answer if the corresponding
3155// MediaDescriptionOptions is stopped by the offerer.
3156TEST_F(MediaSessionDescriptionFactoryTest,
3157 CreateAnswerWithMediaSectionStoppedByOfferer) {
3158 // Create an offer with two audio sections and one of them is stopped.
3159 MediaSessionOptions offer_opts;
3160 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1", cricket::MD_SENDRECV, kActive,
3161 &offer_opts);
3162 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2", cricket::MD_INACTIVE, kStopped,
3163 &offer_opts);
3164 std::unique_ptr<SessionDescription> offer(
3165 f1_.CreateOffer(offer_opts, nullptr));
3166 ASSERT_TRUE(offer);
3167 ASSERT_EQ(2u, offer->contents().size());
3168 EXPECT_FALSE(offer->contents()[0].rejected);
3169 EXPECT_TRUE(offer->contents()[1].rejected);
3170
3171 // Create an answer based on the offer.
3172 MediaSessionOptions answer_opts;
3173 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1", cricket::MD_SENDRECV, kActive,
3174 &answer_opts);
3175 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2", cricket::MD_SENDRECV, kActive,
3176 &answer_opts);
3177 std::unique_ptr<SessionDescription> answer(
3178 f2_.CreateAnswer(offer.get(), answer_opts, nullptr));
3179 ASSERT_EQ(2u, answer->contents().size());
3180 EXPECT_FALSE(answer->contents()[0].rejected);
3181 EXPECT_TRUE(answer->contents()[1].rejected);
3182}
3183
3184// Test that the media section will be rejected in answer if the corresponding
3185// MediaDescriptionOptions is stopped by the answerer.
3186TEST_F(MediaSessionDescriptionFactoryTest,
3187 CreateAnswerWithMediaSectionRejectedByAnswerer) {
3188 // Create an offer with two audio sections.
3189 MediaSessionOptions offer_opts;
3190 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1", cricket::MD_SENDRECV, kActive,
3191 &offer_opts);
3192 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2", cricket::MD_SENDRECV, kActive,
3193 &offer_opts);
3194 std::unique_ptr<SessionDescription> offer(
3195 f1_.CreateOffer(offer_opts, nullptr));
3196 ASSERT_TRUE(offer);
3197 ASSERT_EQ(2u, offer->contents().size());
3198 ASSERT_FALSE(offer->contents()[0].rejected);
3199 ASSERT_FALSE(offer->contents()[1].rejected);
3200
3201 // The answerer rejects one of the audio sections.
3202 MediaSessionOptions answer_opts;
3203 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1", cricket::MD_SENDRECV, kActive,
3204 &answer_opts);
3205 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2", cricket::MD_INACTIVE, kStopped,
3206 &answer_opts);
3207 std::unique_ptr<SessionDescription> answer(
3208 f2_.CreateAnswer(offer.get(), answer_opts, nullptr));
3209 ASSERT_EQ(2u, answer->contents().size());
3210 EXPECT_FALSE(answer->contents()[0].rejected);
3211 EXPECT_TRUE(answer->contents()[1].rejected);
3212}
3213
3214// Test the generated media sections has the same order of the
3215// corresponding MediaDescriptionOptions.
3216TEST_F(MediaSessionDescriptionFactoryTest,
3217 CreateOfferRespectsMediaDescriptionOptionsOrder) {
3218 MediaSessionOptions opts;
3219 // This tests put video section first because normally audio comes first by
3220 // default.
3221 AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_SENDRECV, kActive,
3222 &opts);
3223 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_SENDRECV, kActive,
3224 &opts);
3225 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3226
3227 ASSERT_TRUE(offer);
3228 ASSERT_EQ(2u, offer->contents().size());
3229 EXPECT_EQ("video", offer->contents()[0].name);
3230 EXPECT_EQ("audio", offer->contents()[1].name);
3231}
3232
3233// Test that different media sections using the same codec have same payload
3234// type.
3235TEST_F(MediaSessionDescriptionFactoryTest,
3236 PayloadTypesSharedByMediaSectionsOfSameType) {
3237 MediaSessionOptions opts;
3238 AddMediaSection(MEDIA_TYPE_VIDEO, "video1", cricket::MD_SENDRECV, kActive,
3239 &opts);
3240 AddMediaSection(MEDIA_TYPE_VIDEO, "video2", cricket::MD_SENDRECV, kActive,
3241 &opts);
3242 // Create an offer with two video sections using same codecs.
3243 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3244 ASSERT_TRUE(offer);
3245 ASSERT_EQ(2u, offer->contents().size());
3246 const VideoContentDescription* vcd1 =
3247 static_cast<const VideoContentDescription*>(
3248 offer->contents()[0].description);
3249 const VideoContentDescription* vcd2 =
3250 static_cast<const VideoContentDescription*>(
3251 offer->contents()[1].description);
3252 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3253 ASSERT_EQ(2u, vcd1->codecs().size());
3254 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3255 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3256 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
3257 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
3258
3259 // Create answer and negotiate the codecs.
3260 std::unique_ptr<SessionDescription> answer(
3261 f2_.CreateAnswer(offer.get(), opts, nullptr));
3262 ASSERT_TRUE(answer);
3263 ASSERT_EQ(2u, answer->contents().size());
3264 vcd1 = static_cast<const VideoContentDescription*>(
3265 answer->contents()[0].description);
3266 vcd2 = static_cast<const VideoContentDescription*>(
3267 answer->contents()[1].description);
3268 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3269 ASSERT_EQ(1u, vcd1->codecs().size());
3270 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3271 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3272}
3273
3274// Test that the codec preference order per media section is respected in
3275// subsequent offer.
3276TEST_F(MediaSessionDescriptionFactoryTest,
3277 CreateOfferRespectsCodecPreferenceOrder) {
3278 MediaSessionOptions opts;
3279 AddMediaSection(MEDIA_TYPE_VIDEO, "video1", cricket::MD_SENDRECV, kActive,
3280 &opts);
3281 AddMediaSection(MEDIA_TYPE_VIDEO, "video2", cricket::MD_SENDRECV, kActive,
3282 &opts);
3283 // Create an offer with two video sections using same codecs.
3284 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3285 ASSERT_TRUE(offer);
3286 ASSERT_EQ(2u, offer->contents().size());
3287 VideoContentDescription* vcd1 =
3288 static_cast<VideoContentDescription*>(offer->contents()[0].description);
3289 const VideoContentDescription* vcd2 =
3290 static_cast<const VideoContentDescription*>(
3291 offer->contents()[1].description);
3292 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3293 EXPECT_EQ(video_codecs, vcd1->codecs());
3294 EXPECT_EQ(video_codecs, vcd2->codecs());
3295
3296 // Change the codec preference of the first video section and create a
3297 // follow-up offer.
3298 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3299 vcd1->set_codecs(video_codecs_reverse);
3300 std::unique_ptr<SessionDescription> updated_offer(
3301 f1_.CreateOffer(opts, offer.get()));
3302 vcd1 = static_cast<VideoContentDescription*>(
3303 updated_offer->contents()[0].description);
3304 vcd2 = static_cast<const VideoContentDescription*>(
3305 updated_offer->contents()[1].description);
3306 // The video codec preference order should be respected.
3307 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3308 EXPECT_EQ(video_codecs, vcd2->codecs());
3309}
3310
3311// Test that the codec preference order per media section is respected in
3312// the answer.
3313TEST_F(MediaSessionDescriptionFactoryTest,
3314 CreateAnswerRespectsCodecPreferenceOrder) {
3315 MediaSessionOptions opts;
3316 AddMediaSection(MEDIA_TYPE_VIDEO, "video1", cricket::MD_SENDRECV, kActive,
3317 &opts);
3318 AddMediaSection(MEDIA_TYPE_VIDEO, "video2", cricket::MD_SENDRECV, kActive,
3319 &opts);
3320 // Create an offer with two video sections using same codecs.
3321 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3322 ASSERT_TRUE(offer);
3323 ASSERT_EQ(2u, offer->contents().size());
3324 VideoContentDescription* vcd1 =
3325 static_cast<VideoContentDescription*>(offer->contents()[0].description);
3326 const VideoContentDescription* vcd2 =
3327 static_cast<const VideoContentDescription*>(
3328 offer->contents()[1].description);
3329 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3330 EXPECT_EQ(video_codecs, vcd1->codecs());
3331 EXPECT_EQ(video_codecs, vcd2->codecs());
3332
3333 // Change the codec preference of the first video section and create an
3334 // answer.
3335 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3336 vcd1->set_codecs(video_codecs_reverse);
3337 std::unique_ptr<SessionDescription> answer(
3338 f1_.CreateAnswer(offer.get(), opts, nullptr));
3339 vcd1 =
3340 static_cast<VideoContentDescription*>(answer->contents()[0].description);
3341 vcd2 = static_cast<const VideoContentDescription*>(
3342 answer->contents()[1].description);
3343 // The video codec preference order should be respected.
3344 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3345 EXPECT_EQ(video_codecs, vcd2->codecs());
3346}
3347
zhihuangcf5b37c2016-05-05 11:44:35 -07003348class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
3349 public:
3350 MediaProtocolTest() : f1_(&tdf1_), f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -07003351 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
3352 MAKE_VECTOR(kAudioCodecs1));
zhihuangcf5b37c2016-05-05 11:44:35 -07003353 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
3354 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07003355 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
3356 MAKE_VECTOR(kAudioCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07003357 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
3358 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
3359 f1_.set_secure(SEC_ENABLED);
3360 f2_.set_secure(SEC_ENABLED);
3361 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07003362 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07003363 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07003364 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07003365 tdf1_.set_secure(SEC_ENABLED);
3366 tdf2_.set_secure(SEC_ENABLED);
3367 }
3368
3369 protected:
3370 MediaSessionDescriptionFactory f1_;
3371 MediaSessionDescriptionFactory f2_;
3372 TransportDescriptionFactory tdf1_;
3373 TransportDescriptionFactory tdf2_;
3374};
3375
3376TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
3377 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003378 AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
zhihuangcf5b37c2016-05-05 11:44:35 -07003379 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3380 ASSERT_TRUE(offer.get() != nullptr);
3381 // Set the protocol for all the contents.
3382 for (auto content : offer.get()->contents()) {
3383 static_cast<MediaContentDescription*>(content.description)
3384 ->set_protocol(GetParam());
3385 }
3386 std::unique_ptr<SessionDescription> answer(
3387 f2_.CreateAnswer(offer.get(), opts, nullptr));
3388 const ContentInfo* ac = answer->GetContentByName("audio");
3389 const ContentInfo* vc = answer->GetContentByName("video");
3390 ASSERT_TRUE(ac != nullptr);
3391 ASSERT_TRUE(vc != nullptr);
3392 EXPECT_FALSE(ac->rejected); // the offer is accepted
3393 EXPECT_FALSE(vc->rejected);
3394 const AudioContentDescription* acd =
3395 static_cast<const AudioContentDescription*>(ac->description);
3396 const VideoContentDescription* vcd =
3397 static_cast<const VideoContentDescription*>(vc->description);
3398 EXPECT_EQ(GetParam(), acd->protocol());
3399 EXPECT_EQ(GetParam(), vcd->protocol());
3400}
3401
3402INSTANTIATE_TEST_CASE_P(MediaProtocolPatternTest,
3403 MediaProtocolTest,
3404 ::testing::ValuesIn(kMediaProtocols));
3405INSTANTIATE_TEST_CASE_P(MediaProtocolDtlsPatternTest,
3406 MediaProtocolTest,
3407 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07003408
3409TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
3410 TransportDescriptionFactory tdf;
3411 MediaSessionDescriptionFactory sf(&tdf);
3412 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
3413 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
3414
3415 // The merged list of codecs should contain any send codecs that are also
3416 // nominally in the recieve codecs list. Payload types should be picked from
3417 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
3418 // (set to 1). This equals what happens when the send codecs are used in an
3419 // offer and the receive codecs are used in the following answer.
3420 const std::vector<AudioCodec> sendrecv_codecs =
3421 MAKE_VECTOR(kAudioCodecsAnswer);
3422 const std::vector<AudioCodec> no_codecs;
3423
3424 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
3425 << "Please don't change shared test data!";
3426 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
3427 << "Please don't change shared test data!";
3428 // Alter iLBC send codec to have zero channels, to test that that is handled
3429 // properly.
3430 send_codecs[1].channels = 0;
3431
3432 // Alther iLBC receive codec to be lowercase, to test that case conversions
3433 // are handled properly.
3434 recv_codecs[2].name = "ilbc";
3435
3436 // Test proper merge
3437 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003438 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
3439 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
3440 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003441
3442 // Test empty send codecs list
3443 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003444 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
3445 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
3446 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003447
3448 // Test empty recv codecs list
3449 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003450 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
3451 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
3452 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003453
3454 // Test all empty codec lists
3455 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003456 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
3457 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
3458 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003459}
3460
3461namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07003462// Compare the two vectors of codecs ignoring the payload type.
3463template <class Codec>
3464bool CodecsMatch(const std::vector<Codec>& codecs1,
3465 const std::vector<Codec>& codecs2) {
3466 if (codecs1.size() != codecs2.size()) {
3467 return false;
3468 }
3469
3470 for (size_t i = 0; i < codecs1.size(); ++i) {
3471 if (!codecs1[i].Matches(codecs2[i])) {
3472 return false;
3473 }
3474 }
3475 return true;
3476}
3477
3478void TestAudioCodecsOffer(MediaContentDirection direction) {
ossu075af922016-06-14 03:29:38 -07003479 TransportDescriptionFactory tdf;
3480 MediaSessionDescriptionFactory sf(&tdf);
3481 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
3482 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
3483 const std::vector<AudioCodec> sendrecv_codecs =
3484 MAKE_VECTOR(kAudioCodecsAnswer);
3485 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07003486
3487 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003488 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", direction, kActive, &opts);
3489
3490 if (RtpTransceiverDirection::FromMediaContentDirection(direction).send) {
3491 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003492 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003493 }
ossu075af922016-06-14 03:29:38 -07003494
3495 std::unique_ptr<SessionDescription> offer(sf.CreateOffer(opts, NULL));
3496 ASSERT_TRUE(offer.get() != NULL);
3497 const ContentInfo* ac = offer->GetContentByName("audio");
3498
3499 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07003500 // that the codecs put in are right. This happens when we neither want to
3501 // send nor receive audio. The checks are still in place if at some point
3502 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07003503 if (ac) {
3504 AudioContentDescription* acd =
3505 static_cast<AudioContentDescription*>(ac->description);
zhihuang1c378ed2017-08-17 14:10:50 -07003506 // sendrecv and inactive should both present lists as if the channel was
3507 // to be used for sending and receiving. Inactive essentially means it
3508 // might eventually be used anything, but we don't know more at this
3509 // moment.
ossu075af922016-06-14 03:29:38 -07003510 if (acd->direction() == cricket::MD_SENDONLY) {
zhihuang1c378ed2017-08-17 14:10:50 -07003511 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07003512 } else if (acd->direction() == cricket::MD_RECVONLY) {
zhihuang1c378ed2017-08-17 14:10:50 -07003513 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07003514 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07003515 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07003516 }
3517 }
3518}
3519
3520static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07003521 AudioCodec(0, "codec0", 16000, -1, 1),
3522 AudioCodec(1, "codec1", 8000, 13300, 1),
3523 AudioCodec(2, "codec2", 8000, 64000, 1),
3524 AudioCodec(3, "codec3", 8000, 64000, 1),
3525 AudioCodec(4, "codec4", 8000, 0, 2),
3526 AudioCodec(5, "codec5", 32000, 0, 1),
3527 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07003528
zhihuang1c378ed2017-08-17 14:10:50 -07003529/* The codecs groups below are chosen as per the matrix below. The objective
3530 * is to have different sets of codecs in the inputs, to get unique sets of
3531 * codecs after negotiation, depending on offer and answer communication
3532 * directions. One-way directions in the offer should either result in the
3533 * opposite direction in the answer, or an inactive answer. Regardless, the
3534 * choice of codecs should be as if the answer contained the opposite
3535 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07003536 *
3537 * | Offer | Answer | Result
3538 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
3539 * 0 | x - - | - x - | x - - - -
3540 * 1 | x x x | - x - | x - - x -
3541 * 2 | - x - | x - - | - x - - -
3542 * 3 | x x x | x - - | - x x - -
3543 * 4 | - x - | x x x | - x - - -
3544 * 5 | x - - | x x x | x - - - -
3545 * 6 | x x x | x x x | x x x x x
3546 */
3547// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07003548static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
3549static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07003550// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
3551// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07003552static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
3553static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07003554// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07003555static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
3556static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
3557static const int kResultSendrecv_SendCodecs[] = {3, 6};
3558static const int kResultSendrecv_RecvCodecs[] = {1, 6};
3559static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07003560
3561template <typename T, int IDXS>
3562std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
3563 std::vector<T> out;
3564 out.reserve(IDXS);
3565 for (int idx : indices)
3566 out.push_back(array[idx]);
3567
3568 return out;
3569}
3570
3571void TestAudioCodecsAnswer(MediaContentDirection offer_direction,
3572 MediaContentDirection answer_direction,
3573 bool add_legacy_stream) {
3574 TransportDescriptionFactory offer_tdf;
3575 TransportDescriptionFactory answer_tdf;
3576 MediaSessionDescriptionFactory offer_factory(&offer_tdf);
3577 MediaSessionDescriptionFactory answer_factory(&answer_tdf);
3578 offer_factory.set_audio_codecs(
3579 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
3580 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
3581 answer_factory.set_audio_codecs(
3582 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
3583 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
3584
ossu075af922016-06-14 03:29:38 -07003585 MediaSessionOptions offer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003586 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", offer_direction, kActive,
3587 &offer_opts);
3588
3589 if (RtpTransceiverDirection::FromMediaContentDirection(offer_direction)
3590 .send) {
3591 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003592 {kMediaStream1}, 1, &offer_opts);
ossu075af922016-06-14 03:29:38 -07003593 }
3594
3595 std::unique_ptr<SessionDescription> offer(
3596 offer_factory.CreateOffer(offer_opts, NULL));
3597 ASSERT_TRUE(offer.get() != NULL);
3598
3599 MediaSessionOptions answer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003600 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", answer_direction, kActive,
3601 &answer_opts);
3602
3603 if (RtpTransceiverDirection::FromMediaContentDirection(answer_direction)
3604 .send) {
3605 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003606 {kMediaStream1}, 1, &answer_opts);
ossu075af922016-06-14 03:29:38 -07003607 }
3608 std::unique_ptr<SessionDescription> answer(
3609 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL));
3610 const ContentInfo* ac = answer->GetContentByName("audio");
3611
zhihuang1c378ed2017-08-17 14:10:50 -07003612 // If the factory didn't add any audio content to the answer, we cannot
3613 // check that the codecs put in are right. This happens when we neither want
3614 // to send nor receive audio. The checks are still in place if at some point
3615 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07003616 if (ac) {
3617 const AudioContentDescription* acd =
3618 static_cast<const AudioContentDescription*>(ac->description);
3619 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
3620
ossu075af922016-06-14 03:29:38 -07003621 std::vector<AudioCodec> target_codecs;
3622 // For offers with sendrecv or inactive, we should never reply with more
3623 // codecs than offered, with these codec sets.
3624 switch (offer_direction) {
3625 case cricket::MD_INACTIVE:
3626 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
3627 kResultSendrecv_SendrecvCodecs);
3628 break;
3629 case cricket::MD_SENDONLY:
zhihuang1c378ed2017-08-17 14:10:50 -07003630 target_codecs =
3631 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07003632 break;
3633 case cricket::MD_RECVONLY:
zhihuang1c378ed2017-08-17 14:10:50 -07003634 target_codecs =
3635 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07003636 break;
3637 case cricket::MD_SENDRECV:
3638 if (acd->direction() == cricket::MD_SENDONLY) {
zhihuang1c378ed2017-08-17 14:10:50 -07003639 target_codecs =
3640 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07003641 } else if (acd->direction() == cricket::MD_RECVONLY) {
zhihuang1c378ed2017-08-17 14:10:50 -07003642 target_codecs =
3643 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07003644 } else {
3645 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
3646 kResultSendrecv_SendrecvCodecs);
3647 }
3648 break;
3649 }
3650
zhihuang1c378ed2017-08-17 14:10:50 -07003651 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
ossu075af922016-06-14 03:29:38 -07003652 std::stringstream os;
3653 bool first = true;
3654 os << "{";
3655 for (const auto& c : codecs) {
3656 os << (first ? " " : ", ") << c.id;
3657 first = false;
3658 }
3659 os << " }";
3660 return os.str();
3661 };
3662
3663 EXPECT_TRUE(acd->codecs() == target_codecs)
3664 << "Expected: " << format_codecs(target_codecs)
3665 << ", got: " << format_codecs(acd->codecs())
3666 << "; Offered: " << MediaContentDirectionToString(offer_direction)
3667 << ", answerer wants: "
3668 << MediaContentDirectionToString(answer_direction)
3669 << "; got: " << MediaContentDirectionToString(acd->direction());
3670 } else {
3671 EXPECT_EQ(offer_direction, cricket::MD_INACTIVE)
zhihuang1c378ed2017-08-17 14:10:50 -07003672 << "Only inactive offers are allowed to not generate any audio "
3673 "content";
ossu075af922016-06-14 03:29:38 -07003674 }
3675}
brandtr03d5fb12016-11-22 03:37:59 -08003676
3677} // namespace
ossu075af922016-06-14 03:29:38 -07003678
3679class AudioCodecsOfferTest
zhihuang1c378ed2017-08-17 14:10:50 -07003680 : public ::testing::TestWithParam<MediaContentDirection> {};
ossu075af922016-06-14 03:29:38 -07003681
3682TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003683 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07003684}
3685
3686INSTANTIATE_TEST_CASE_P(MediaSessionDescriptionFactoryTest,
3687 AudioCodecsOfferTest,
zhihuang1c378ed2017-08-17 14:10:50 -07003688 ::testing::Values(cricket::MD_SENDONLY,
3689 cricket::MD_RECVONLY,
3690 cricket::MD_SENDRECV,
3691 cricket::MD_INACTIVE));
ossu075af922016-06-14 03:29:38 -07003692
3693class AudioCodecsAnswerTest
ehmaldonadoabcef5d2017-02-08 04:07:11 -08003694 : public ::testing::TestWithParam<::testing::tuple<MediaContentDirection,
3695 MediaContentDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07003696 bool>> {};
ossu075af922016-06-14 03:29:38 -07003697
3698TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08003699 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
3700 ::testing::get<1>(GetParam()),
3701 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07003702}
3703
zhihuang1c378ed2017-08-17 14:10:50 -07003704INSTANTIATE_TEST_CASE_P(
3705 MediaSessionDescriptionFactoryTest,
3706 AudioCodecsAnswerTest,
3707 ::testing::Combine(::testing::Values(cricket::MD_SENDONLY,
3708 cricket::MD_RECVONLY,
3709 cricket::MD_SENDRECV,
3710 cricket::MD_INACTIVE),
3711 ::testing::Values(cricket::MD_SENDONLY,
3712 cricket::MD_RECVONLY,
3713 cricket::MD_SENDRECV,
3714 cricket::MD_INACTIVE),
3715 ::testing::Bool()));