blob: 971e5688893cf35c73ccb13bcf1d07917e3d1d54 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
kjellander65c7f672016-02-12 00:05:01 -08002 * Copyright 2004 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
kjellander65c7f672016-02-12 00:05:01 -08004 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00009 */
10
kwiberg31022942016-03-11 14:18:21 -080011#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000012#include <string>
13#include <vector>
14
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "media/base/codec.h"
16#include "media/base/testutils.h"
17#include "p2p/base/p2pconstants.h"
18#include "p2p/base/transportdescription.h"
19#include "p2p/base/transportinfo.h"
20#include "pc/mediasession.h"
Steve Anton1d03a752017-11-27 14:30:09 -080021#include "pc/rtpmediautils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "pc/srtpfilter.h"
23#include "rtc_base/checks.h"
24#include "rtc_base/fakesslidentity.h"
25#include "rtc_base/gunit.h"
26#include "rtc_base/messagedigest.h"
27#include "rtc_base/ssladapter.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000028
henrike@webrtc.org28e20752013-07-10 00:45:36 +000029#define ASSERT_CRYPTO(cd, s, cs) \
henrike@webrtc.org28e20752013-07-10 00:45:36 +000030 ASSERT_EQ(s, cd->cryptos().size()); \
31 ASSERT_EQ(std::string(cs), cd->cryptos()[0].cipher_suite)
henrike@webrtc.org28e20752013-07-10 00:45:36 +000032
33typedef std::vector<cricket::Candidate> Candidates;
34
35using cricket::MediaContentDescription;
36using cricket::MediaSessionDescriptionFactory;
zhihuang1c378ed2017-08-17 14:10:50 -070037using cricket::MediaDescriptionOptions;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000038using cricket::MediaSessionOptions;
39using cricket::MediaType;
Steve Anton5adfafd2017-12-20 16:34:00 -080040using cricket::MediaProtocolType;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000041using cricket::SessionDescription;
42using cricket::SsrcGroup;
43using cricket::StreamParams;
44using cricket::StreamParamsVec;
45using cricket::TransportDescription;
46using cricket::TransportDescriptionFactory;
47using cricket::TransportInfo;
48using cricket::ContentInfo;
49using cricket::CryptoParamsVec;
50using cricket::AudioContentDescription;
51using cricket::VideoContentDescription;
52using cricket::DataContentDescription;
deadbeef44f08192015-12-15 16:20:09 -080053using cricket::GetFirstAudioContent;
54using cricket::GetFirstVideoContent;
55using cricket::GetFirstDataContent;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000056using cricket::GetFirstAudioContentDescription;
57using cricket::GetFirstVideoContentDescription;
58using cricket::GetFirstDataContentDescription;
59using cricket::kAutoBandwidth;
60using cricket::AudioCodec;
61using cricket::VideoCodec;
62using cricket::DataCodec;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000063using 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;
Guo-wei Shieh456696a2015-09-30 21:48:54 -070069using rtc::CS_AES_CM_128_HMAC_SHA1_32;
70using rtc::CS_AES_CM_128_HMAC_SHA1_80;
jbauchcb560652016-08-04 05:20:32 -070071using rtc::CS_AEAD_AES_128_GCM;
72using rtc::CS_AEAD_AES_256_GCM;
isheriff6f8d6862016-05-26 11:24:55 -070073using webrtc::RtpExtension;
Steve Anton4e70a722017-11-28 14:57:10 -080074using webrtc::RtpTransceiverDirection;
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) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800223 RTC_DCHECK(content);
224 return content->media_description()->type() == media_type;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000225}
226
Steve Anton4e70a722017-11-28 14:57:10 -0800227static RtpTransceiverDirection GetMediaDirection(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800228 RTC_DCHECK(content);
229 return content->media_description()->direction();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000230}
231
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000232static void AddRtxCodec(const VideoCodec& rtx_codec,
233 std::vector<VideoCodec>* codecs) {
magjedb05fa242016-11-11 04:00:16 -0800234 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000235 codecs->push_back(rtx_codec);
236}
237
238template <class T>
239static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
240 std::vector<std::string> codec_names;
241 for (const auto& codec : codecs) {
242 codec_names.push_back(codec.name);
243 }
244 return codec_names;
245}
246
zhihuang1c378ed2017-08-17 14:10:50 -0700247// This is used for test only. MIDs are not the identification of the
248// MediaDescriptionOptions since some end points may not support MID and the SDP
249// may not contain 'mid'.
250std::vector<MediaDescriptionOptions>::iterator FindFirstMediaDescriptionByMid(
251 const std::string& mid,
252 MediaSessionOptions* opts) {
253 return std::find_if(
254 opts->media_description_options.begin(),
255 opts->media_description_options.end(),
Steve Anton36b29d12017-10-30 09:57:42 -0700256 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
257}
258
259std::vector<MediaDescriptionOptions>::const_iterator
260FindFirstMediaDescriptionByMid(const std::string& mid,
261 const MediaSessionOptions& opts) {
262 return std::find_if(
263 opts.media_description_options.begin(),
264 opts.media_description_options.end(),
265 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
zhihuang1c378ed2017-08-17 14:10:50 -0700266}
267
268// Add a media section to the |session_options|.
269static void AddMediaSection(MediaType type,
270 const std::string& mid,
Steve Anton4e70a722017-11-28 14:57:10 -0800271 RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700272 bool stopped,
273 MediaSessionOptions* opts) {
Steve Anton4e70a722017-11-28 14:57:10 -0800274 opts->media_description_options.push_back(
275 MediaDescriptionOptions(type, mid, direction, stopped));
zhihuang1c378ed2017-08-17 14:10:50 -0700276}
277
Steve Anton4e70a722017-11-28 14:57:10 -0800278static void AddAudioVideoSections(RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700279 MediaSessionOptions* opts) {
280 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", direction, kActive, opts);
281 AddMediaSection(MEDIA_TYPE_VIDEO, "video", direction, kActive, opts);
282}
283
284static void AddDataSection(cricket::DataChannelType dct,
Steve Anton4e70a722017-11-28 14:57:10 -0800285 RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700286 MediaSessionOptions* opts) {
287 opts->data_channel_type = dct;
288 AddMediaSection(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
289}
290
Steve Anton8ffb9c32017-08-31 15:45:38 -0700291static void AttachSenderToMediaSection(
292 const std::string& mid,
293 MediaType type,
294 const std::string& track_id,
295 const std::vector<std::string>& stream_ids,
296 int num_sim_layer,
297 MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -0700298 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
299 switch (type) {
300 case MEDIA_TYPE_AUDIO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700301 it->AddAudioSender(track_id, stream_ids);
zhihuang1c378ed2017-08-17 14:10:50 -0700302 break;
303 case MEDIA_TYPE_VIDEO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700304 it->AddVideoSender(track_id, stream_ids, num_sim_layer);
zhihuang1c378ed2017-08-17 14:10:50 -0700305 break;
306 case MEDIA_TYPE_DATA:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700307 RTC_CHECK(stream_ids.size() == 1U);
308 it->AddRtpDataChannel(track_id, stream_ids[0]);
zhihuang1c378ed2017-08-17 14:10:50 -0700309 break;
310 default:
311 RTC_NOTREACHED();
312 }
313}
314
315static void DetachSenderFromMediaSection(const std::string& mid,
316 const std::string& track_id,
317 MediaSessionOptions* session_options) {
318 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
319 auto sender_it = it->sender_options.begin();
320 for (; sender_it != it->sender_options.end(); ++sender_it) {
321 if (sender_it->track_id == track_id) {
322 it->sender_options.erase(sender_it);
323 return;
324 }
325 }
326 RTC_NOTREACHED();
327}
328
329// Helper function used to create a default MediaSessionOptions for Plan B SDP.
330// (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
331static MediaSessionOptions CreatePlanBMediaSessionOptions() {
332 MediaSessionOptions session_options;
Steve Anton4e70a722017-11-28 14:57:10 -0800333 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
334 kActive, &session_options);
zhihuang1c378ed2017-08-17 14:10:50 -0700335 return session_options;
336}
337
338// TODO(zhihuang): Most of these tests were written while MediaSessionOptions
339// was designed for Plan B SDP, where only one audio "m=" section and one video
340// "m=" section could be generated, and ordering couldn't be controlled. Many of
341// these tests may be obsolete as a result, and should be refactored or removed.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000342class MediaSessionDescriptionFactoryTest : public testing::Test {
343 public:
zhihuang1c378ed2017-08-17 14:10:50 -0700344 MediaSessionDescriptionFactoryTest() : f1_(&tdf1_), f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -0700345 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
346 MAKE_VECTOR(kAudioCodecs1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000347 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
348 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700349 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
350 MAKE_VECTOR(kAudioCodecs2));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000351 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
352 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200353 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700354 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200355 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700356 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000357 }
358
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000359 // Create a video StreamParamsVec object with:
360 // - one video stream with 3 simulcast streams and FEC,
361 StreamParamsVec CreateComplexVideoStreamParamsVec() {
362 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
363 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
364 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
365 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
366
367 std::vector<SsrcGroup> ssrc_groups;
368 ssrc_groups.push_back(sim_group);
369 ssrc_groups.push_back(fec_group1);
370 ssrc_groups.push_back(fec_group2);
371 ssrc_groups.push_back(fec_group3);
372
373 StreamParams simulcast_params;
374 simulcast_params.id = kVideoTrack1;
375 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
376 simulcast_params.ssrc_groups = ssrc_groups;
377 simulcast_params.cname = "Video_SIM_FEC";
378 simulcast_params.sync_label = kMediaStream1;
379
380 StreamParamsVec video_streams;
381 video_streams.push_back(simulcast_params);
382
383 return video_streams;
384 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000385
386 bool CompareCryptoParams(const CryptoParamsVec& c1,
387 const CryptoParamsVec& c2) {
388 if (c1.size() != c2.size())
389 return false;
390 for (size_t i = 0; i < c1.size(); ++i)
391 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
392 c1[i].key_params != c2[i].key_params ||
393 c1[i].session_params != c2[i].session_params)
394 return false;
395 return true;
396 }
397
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700398 // Returns true if the transport info contains "renomination" as an
399 // ICE option.
400 bool GetIceRenomination(const TransportInfo* transport_info) {
401 const std::vector<std::string>& ice_options =
402 transport_info->description.transport_options;
deadbeef30952b42017-04-21 02:41:29 -0700403 auto iter =
404 std::find(ice_options.begin(), ice_options.end(), "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700405 return iter != ice_options.end();
406 }
407
zhihuang1c378ed2017-08-17 14:10:50 -0700408 void TestTransportInfo(bool offer,
Steve Anton36b29d12017-10-30 09:57:42 -0700409 const MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000410 bool has_current_desc) {
411 const std::string current_audio_ufrag = "current_audio_ufrag";
412 const std::string current_audio_pwd = "current_audio_pwd";
413 const std::string current_video_ufrag = "current_video_ufrag";
414 const std::string current_video_pwd = "current_video_pwd";
415 const std::string current_data_ufrag = "current_data_ufrag";
416 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800417 std::unique_ptr<SessionDescription> current_desc;
418 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000419 if (has_current_desc) {
420 current_desc.reset(new SessionDescription());
421 EXPECT_TRUE(current_desc->AddTransportInfo(
422 TransportInfo("audio",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700423 TransportDescription(current_audio_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000424 current_audio_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000425 EXPECT_TRUE(current_desc->AddTransportInfo(
426 TransportInfo("video",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700427 TransportDescription(current_video_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000428 current_video_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000429 EXPECT_TRUE(current_desc->AddTransportInfo(
430 TransportInfo("data",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700431 TransportDescription(current_data_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000432 current_data_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000433 }
434 if (offer) {
435 desc.reset(f1_.CreateOffer(options, current_desc.get()));
436 } else {
kwiberg31022942016-03-11 14:18:21 -0800437 std::unique_ptr<SessionDescription> offer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000438 offer.reset(f1_.CreateOffer(options, NULL));
439 desc.reset(f1_.CreateAnswer(offer.get(), options, current_desc.get()));
440 }
441 ASSERT_TRUE(desc.get() != NULL);
442 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000443 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000444 EXPECT_TRUE(ti_audio != NULL);
445 if (has_current_desc) {
446 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
447 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
448 } else {
449 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
450 ti_audio->description.ice_ufrag.size());
451 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
452 ti_audio->description.ice_pwd.size());
453 }
zhihuang1c378ed2017-08-17 14:10:50 -0700454 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700455 FindFirstMediaDescriptionByMid("audio", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700456 EXPECT_EQ(
457 media_desc_options_it->transport_options.enable_ice_renomination,
458 GetIceRenomination(ti_audio));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000459
460 } else {
461 EXPECT_TRUE(ti_audio == NULL);
462 }
463 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000464 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000465 EXPECT_TRUE(ti_video != NULL);
466 if (options.bundle_enabled) {
467 EXPECT_EQ(ti_audio->description.ice_ufrag,
468 ti_video->description.ice_ufrag);
469 EXPECT_EQ(ti_audio->description.ice_pwd,
470 ti_video->description.ice_pwd);
471 } else {
472 if (has_current_desc) {
473 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
474 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
475 } else {
476 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
477 ti_video->description.ice_ufrag.size());
478 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
479 ti_video->description.ice_pwd.size());
480 }
481 }
zhihuang1c378ed2017-08-17 14:10:50 -0700482 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700483 FindFirstMediaDescriptionByMid("video", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700484 EXPECT_EQ(
485 media_desc_options_it->transport_options.enable_ice_renomination,
486 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000487 } else {
488 EXPECT_TRUE(ti_video == NULL);
489 }
490 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
491 if (options.has_data()) {
492 EXPECT_TRUE(ti_data != NULL);
493 if (options.bundle_enabled) {
494 EXPECT_EQ(ti_audio->description.ice_ufrag,
495 ti_data->description.ice_ufrag);
496 EXPECT_EQ(ti_audio->description.ice_pwd,
497 ti_data->description.ice_pwd);
498 } else {
499 if (has_current_desc) {
500 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
501 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
502 } else {
503 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
504 ti_data->description.ice_ufrag.size());
505 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
506 ti_data->description.ice_pwd.size());
507 }
508 }
zhihuang1c378ed2017-08-17 14:10:50 -0700509 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700510 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700511 EXPECT_EQ(
512 media_desc_options_it->transport_options.enable_ice_renomination,
513 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700514
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000515 } else {
516 EXPECT_TRUE(ti_video == NULL);
517 }
518 }
519
520 void TestCryptoWithBundle(bool offer) {
521 f1_.set_secure(SEC_ENABLED);
522 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -0800523 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
524 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
525 &options);
kwiberg31022942016-03-11 14:18:21 -0800526 std::unique_ptr<SessionDescription> ref_desc;
527 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000528 if (offer) {
529 options.bundle_enabled = false;
530 ref_desc.reset(f1_.CreateOffer(options, NULL));
531 options.bundle_enabled = true;
532 desc.reset(f1_.CreateOffer(options, ref_desc.get()));
533 } else {
534 options.bundle_enabled = true;
535 ref_desc.reset(f1_.CreateOffer(options, NULL));
536 desc.reset(f1_.CreateAnswer(ref_desc.get(), options, NULL));
537 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800538 ASSERT_TRUE(desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000539 const cricket::MediaContentDescription* audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800540 desc->GetContentDescriptionByName("audio");
541 ASSERT_TRUE(audio_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000542 const cricket::MediaContentDescription* video_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800543 desc->GetContentDescriptionByName("video");
544 ASSERT_TRUE(video_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000545 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
546 video_media_desc->cryptos()));
547 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
548 EXPECT_EQ(std::string(CS_AES_CM_128_HMAC_SHA1_80),
549 audio_media_desc->cryptos()[0].cipher_suite);
550
551 // Verify the selected crypto is one from the reference audio
552 // media content.
553 const cricket::MediaContentDescription* ref_audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800554 ref_desc->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000555 bool found = false;
556 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
557 if (ref_audio_media_desc->cryptos()[i].Matches(
558 audio_media_desc->cryptos()[0])) {
559 found = true;
560 break;
561 }
562 }
563 EXPECT_TRUE(found);
564 }
565
566 // This test that the audio and video media direction is set to
567 // |expected_direction_in_answer| in an answer if the offer direction is set
zhihuang1c378ed2017-08-17 14:10:50 -0700568 // to |direction_in_offer| and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000569 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800570 RtpTransceiverDirection direction_in_offer,
571 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700572 MediaSessionOptions offer_opts;
573 AddAudioVideoSections(direction_in_offer, &offer_opts);
574
575 std::unique_ptr<SessionDescription> offer(
576 f1_.CreateOffer(offer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000577 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700578 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000579 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700580 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000581 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000582
zhihuang1c378ed2017-08-17 14:10:50 -0700583 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800584 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -0800585 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -0700586 f2_.CreateAnswer(offer.get(), answer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000587 const AudioContentDescription* acd_answer =
588 GetFirstAudioContentDescription(answer.get());
589 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
590 const VideoContentDescription* vcd_answer =
591 GetFirstVideoContentDescription(answer.get());
592 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
593 }
594
595 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800596 RTC_DCHECK(content);
597 RTC_CHECK(content->media_description());
598 const cricket::AudioContentDescription* audio_desc =
599 content->media_description()->as_audio();
600 RTC_CHECK(audio_desc);
601 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
602 if (codec.name == "CN") {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000603 return false;
Steve Antonb1c1de12017-12-21 15:14:30 -0800604 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000605 }
606 return true;
607 }
608
jbauchcb560652016-08-04 05:20:32 -0700609 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
610 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800611 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
jbauchcb560652016-08-04 05:20:32 -0700612 offer_opts.crypto_options.enable_gcm_crypto_suites = gcm_offer;
zhihuang1c378ed2017-08-17 14:10:50 -0700613
jbauchcb560652016-08-04 05:20:32 -0700614 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800615 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
jbauchcb560652016-08-04 05:20:32 -0700616 answer_opts.crypto_options.enable_gcm_crypto_suites = gcm_answer;
zhihuang1c378ed2017-08-17 14:10:50 -0700617
jbauchcb560652016-08-04 05:20:32 -0700618 f1_.set_secure(SEC_ENABLED);
619 f2_.set_secure(SEC_ENABLED);
620 std::unique_ptr<SessionDescription> offer(
621 f1_.CreateOffer(offer_opts, NULL));
622 ASSERT_TRUE(offer.get() != NULL);
623 std::unique_ptr<SessionDescription> answer(
624 f2_.CreateAnswer(offer.get(), answer_opts, NULL));
625 const ContentInfo* ac = answer->GetContentByName("audio");
626 const ContentInfo* vc = answer->GetContentByName("video");
627 ASSERT_TRUE(ac != NULL);
628 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800629 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
630 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800631 const AudioContentDescription* acd = ac->media_description()->as_audio();
632 const VideoContentDescription* vcd = vc->media_description()->as_video();
jbauchcb560652016-08-04 05:20:32 -0700633 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
634 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
635 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700636 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700637 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
638 if (gcm_offer && gcm_answer) {
639 ASSERT_CRYPTO(acd, 1U, CS_AEAD_AES_256_GCM);
640 } else {
641 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
642 }
643 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
644 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700645 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700646 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
647 if (gcm_offer && gcm_answer) {
648 ASSERT_CRYPTO(vcd, 1U, CS_AEAD_AES_256_GCM);
649 } else {
650 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
651 }
652 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
653 }
654
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000655 protected:
656 MediaSessionDescriptionFactory f1_;
657 MediaSessionDescriptionFactory f2_;
658 TransportDescriptionFactory tdf1_;
659 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000660};
661
662// Create a typical audio offer, and ensure it matches what we expect.
663TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
664 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800665 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -0700666 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000667 ASSERT_TRUE(offer.get() != NULL);
668 const ContentInfo* ac = offer->GetContentByName("audio");
669 const ContentInfo* vc = offer->GetContentByName("video");
670 ASSERT_TRUE(ac != NULL);
671 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800672 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800673 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000674 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;
Steve Anton4e70a722017-11-28 14:57:10 -0800686 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &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);
Steve Anton5adfafd2017-12-20 16:34:00 -0800694 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
695 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800696 const AudioContentDescription* acd = ac->media_description()->as_audio();
697 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000698 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700699 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700700 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000701 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
702 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
703 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
704 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
705 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
706 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700707 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000708 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
709 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
710 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
711 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
712}
713
714// Test creating an offer with bundle where the Codecs have the same dynamic
715// RTP playlod type. The test verifies that the offer don't contain the
716// duplicate RTP payload types.
717TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
718 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700719 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000720 const DataCodec& offered_data_codec = f2_.data_codecs()[0];
721 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
722 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
723
724 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800725 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
726 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000727 opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800728 std::unique_ptr<SessionDescription> offer(f2_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000729 const VideoContentDescription* vcd =
730 GetFirstVideoContentDescription(offer.get());
731 const AudioContentDescription* acd =
732 GetFirstAudioContentDescription(offer.get());
733 const DataContentDescription* dcd =
734 GetFirstDataContentDescription(offer.get());
735 ASSERT_TRUE(NULL != vcd);
736 ASSERT_TRUE(NULL != acd);
737 ASSERT_TRUE(NULL != dcd);
738 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
739 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
740 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
741 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
742 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
743 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
744}
745
zhihuang1c378ed2017-08-17 14:10:50 -0700746// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000747// after an audio only session has been negotiated.
748TEST_F(MediaSessionDescriptionFactoryTest,
749 TestCreateUpdatedVideoOfferWithBundle) {
750 f1_.set_secure(SEC_ENABLED);
751 f2_.set_secure(SEC_ENABLED);
752 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800753 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
754 kActive, &opts);
755 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kInactive,
756 kStopped, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000757 opts.data_channel_type = cricket::DCT_NONE;
758 opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800759 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
760 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000761 f2_.CreateAnswer(offer.get(), opts, NULL));
762
763 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800764 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
765 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
766 &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000767 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800768 std::unique_ptr<SessionDescription> updated_offer(
769 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000770
771 const AudioContentDescription* acd =
772 GetFirstAudioContentDescription(updated_offer.get());
773 const VideoContentDescription* vcd =
774 GetFirstVideoContentDescription(updated_offer.get());
775 const DataContentDescription* dcd =
776 GetFirstDataContentDescription(updated_offer.get());
777 EXPECT_TRUE(NULL != vcd);
778 EXPECT_TRUE(NULL != acd);
779 EXPECT_TRUE(NULL != dcd);
780
781 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
782 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
783 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
784 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
785 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
786 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
787}
deadbeef44f08192015-12-15 16:20:09 -0800788
wu@webrtc.org78187522013-10-07 23:32:02 +0000789// Create a RTP data offer, and ensure it matches what we expect.
790TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000791 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800792 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
793 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000794 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800795 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000796 ASSERT_TRUE(offer.get() != NULL);
797 const ContentInfo* ac = offer->GetContentByName("audio");
798 const ContentInfo* dc = offer->GetContentByName("data");
799 ASSERT_TRUE(ac != NULL);
800 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800801 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
802 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800803 const AudioContentDescription* acd = ac->media_description()->as_audio();
804 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000805 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700806 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700807 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000808 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
809 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
810 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
811 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
812 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
813 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700814 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000815 EXPECT_EQ(cricket::kDataMaxBandwidth,
816 dcd->bandwidth()); // default bandwidth (auto)
817 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
818 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
819 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
820}
821
wu@webrtc.org78187522013-10-07 23:32:02 +0000822// Create an SCTP data offer with bundle without error.
823TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
824 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000825 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800826 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
wu@webrtc.org78187522013-10-07 23:32:02 +0000827 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800828 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
wu@webrtc.org78187522013-10-07 23:32:02 +0000829 EXPECT_TRUE(offer.get() != NULL);
830 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
831}
832
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000833// Test creating an sctp data channel from an already generated offer.
834TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
835 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000836 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800837 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000838 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800839 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000840 ASSERT_TRUE(offer1.get() != NULL);
841 const ContentInfo* data = offer1->GetContentByName("data");
842 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800843 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000844
845 // Now set data_channel_type to 'none' (default) and make sure that the
846 // datachannel type that gets generated from the previous offer, is of the
847 // same type.
848 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800849 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000850 f1_.CreateOffer(opts, offer1.get()));
851 data = offer2->GetContentByName("data");
852 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800853 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000854}
855
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000856// Create an audio, video offer without legacy StreamParams.
857TEST_F(MediaSessionDescriptionFactoryTest,
858 TestCreateOfferWithoutLegacyStreams) {
859 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800860 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
kwiberg31022942016-03-11 14:18:21 -0800861 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000862 ASSERT_TRUE(offer.get() != NULL);
863 const ContentInfo* ac = offer->GetContentByName("audio");
864 const ContentInfo* vc = offer->GetContentByName("video");
865 ASSERT_TRUE(ac != NULL);
866 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800867 const AudioContentDescription* acd = ac->media_description()->as_audio();
868 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000869
870 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
871 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
872}
873
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000874// Creates an audio+video sendonly offer.
875TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700876 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800877 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700878 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700879 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700880 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700881 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000882
zhihuang1c378ed2017-08-17 14:10:50 -0700883 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000884 ASSERT_TRUE(offer.get() != NULL);
885 EXPECT_EQ(2u, offer->contents().size());
886 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
887 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
888
Steve Anton4e70a722017-11-28 14:57:10 -0800889 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
890 GetMediaDirection(&offer->contents()[0]));
891 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
892 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000893}
894
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000895// Verifies that the order of the media contents in the current
896// SessionDescription is preserved in the new SessionDescription.
897TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
898 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800899 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000900
kwiberg31022942016-03-11 14:18:21 -0800901 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000902 ASSERT_TRUE(offer1.get() != NULL);
903 EXPECT_EQ(1u, offer1->contents().size());
904 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
905
Steve Anton4e70a722017-11-28 14:57:10 -0800906 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
907 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -0800908 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000909 f1_.CreateOffer(opts, offer1.get()));
910 ASSERT_TRUE(offer2.get() != NULL);
911 EXPECT_EQ(2u, offer2->contents().size());
912 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
913 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
914
Steve Anton4e70a722017-11-28 14:57:10 -0800915 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
916 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -0800917 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000918 f1_.CreateOffer(opts, offer2.get()));
919 ASSERT_TRUE(offer3.get() != NULL);
920 EXPECT_EQ(3u, offer3->contents().size());
921 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
922 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
923 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000924}
925
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000926// Create a typical audio answer, and ensure it matches what we expect.
927TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
928 f1_.set_secure(SEC_ENABLED);
929 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800930 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -0700931 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000932 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800933 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -0700934 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000935 const ContentInfo* ac = answer->GetContentByName("audio");
936 const ContentInfo* vc = answer->GetContentByName("video");
937 ASSERT_TRUE(ac != NULL);
938 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800939 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800940 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000941 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
942 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700943 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000944 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
945 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
946 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
947 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
948}
949
jbauchcb560652016-08-04 05:20:32 -0700950// Create a typical audio answer with GCM ciphers enabled, and ensure it
951// matches what we expect.
952TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
953 f1_.set_secure(SEC_ENABLED);
954 f2_.set_secure(SEC_ENABLED);
zhihuang1c378ed2017-08-17 14:10:50 -0700955 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
956 opts.crypto_options.enable_gcm_crypto_suites = true;
957 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
jbauchcb560652016-08-04 05:20:32 -0700958 ASSERT_TRUE(offer.get() != NULL);
959 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -0700960 f2_.CreateAnswer(offer.get(), opts, NULL));
jbauchcb560652016-08-04 05:20:32 -0700961 const ContentInfo* ac = answer->GetContentByName("audio");
962 const ContentInfo* vc = answer->GetContentByName("video");
963 ASSERT_TRUE(ac != NULL);
964 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800965 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800966 const AudioContentDescription* acd = ac->media_description()->as_audio();
jbauchcb560652016-08-04 05:20:32 -0700967 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
968 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700969 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700970 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
971 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
972 ASSERT_CRYPTO(acd, 1U, CS_AEAD_AES_256_GCM);
973 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
974}
975
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000976// Create a typical video answer, and ensure it matches what we expect.
977TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
978 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800979 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000980 f1_.set_secure(SEC_ENABLED);
981 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800982 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000983 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800984 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000985 f2_.CreateAnswer(offer.get(), opts, NULL));
986 const ContentInfo* ac = answer->GetContentByName("audio");
987 const ContentInfo* vc = answer->GetContentByName("video");
988 ASSERT_TRUE(ac != NULL);
989 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800990 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
991 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800992 const AudioContentDescription* acd = ac->media_description()->as_audio();
993 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000994 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
995 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
996 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700997 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000998 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
999 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1000 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1001 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -07001002 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001003 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
1004 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1005 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
1006}
1007
jbauchcb560652016-08-04 05:20:32 -07001008// Create a typical video answer with GCM ciphers enabled, and ensure it
1009// matches what we expect.
1010TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1011 TestVideoGcmCipher(true, true);
1012}
1013
1014// Create a typical video answer with GCM ciphers enabled for the offer only,
1015// and ensure it matches what we expect.
1016TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1017 TestVideoGcmCipher(true, false);
1018}
1019
1020// Create a typical video answer with GCM ciphers enabled for the answer only,
1021// and ensure it matches what we expect.
1022TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1023 TestVideoGcmCipher(false, true);
1024}
1025
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001026TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001027 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001028 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001029 f1_.set_secure(SEC_ENABLED);
1030 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001031 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001032 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001033 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001034 f2_.CreateAnswer(offer.get(), opts, NULL));
1035 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001036 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001037 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001038 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001039 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1040 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001041 const AudioContentDescription* acd = ac->media_description()->as_audio();
1042 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001043 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1044 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1045 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001046 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001047 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
1048 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
zstein4b2e0822017-02-17 19:48:38 -08001049 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1050 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -07001051 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001052 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
1053 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1054 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001055}
1056
jbauchcb560652016-08-04 05:20:32 -07001057TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
zhihuang1c378ed2017-08-17 14:10:50 -07001058 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001059 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
jbauchcb560652016-08-04 05:20:32 -07001060 opts.crypto_options.enable_gcm_crypto_suites = true;
1061 f1_.set_secure(SEC_ENABLED);
1062 f2_.set_secure(SEC_ENABLED);
1063 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1064 ASSERT_TRUE(offer.get() != NULL);
1065 std::unique_ptr<SessionDescription> answer(
1066 f2_.CreateAnswer(offer.get(), opts, NULL));
1067 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001068 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -07001069 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001070 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001071 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1072 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001073 const AudioContentDescription* acd = ac->media_description()->as_audio();
1074 const DataContentDescription* dcd = dc->media_description()->as_data();
jbauchcb560652016-08-04 05:20:32 -07001075 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1076 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1077 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001078 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001079 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
1080 ASSERT_CRYPTO(acd, 1U, CS_AEAD_AES_256_GCM);
zstein4b2e0822017-02-17 19:48:38 -08001081 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1082 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -07001083 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001084 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
1085 ASSERT_CRYPTO(dcd, 1U, CS_AEAD_AES_256_GCM);
1086 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
1087}
1088
1089// The use_sctpmap flag should be set in a DataContentDescription by default.
1090// The answer's use_sctpmap flag should match the offer's.
1091TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1092 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001093 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
zstein4b2e0822017-02-17 19:48:38 -08001094 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1095 ASSERT_TRUE(offer.get() != NULL);
1096 ContentInfo* dc_offer = offer->GetContentByName("data");
1097 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001098 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001099 EXPECT_TRUE(dcd_offer->use_sctpmap());
1100
1101 std::unique_ptr<SessionDescription> answer(
1102 f2_.CreateAnswer(offer.get(), opts, NULL));
1103 const ContentInfo* dc_answer = answer->GetContentByName("data");
1104 ASSERT_TRUE(dc_answer != NULL);
1105 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001106 dc_answer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001107 EXPECT_TRUE(dcd_answer->use_sctpmap());
1108}
1109
1110// The answer's use_sctpmap flag should match the offer's.
1111TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1112 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001113 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
zstein4b2e0822017-02-17 19:48:38 -08001114 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1115 ASSERT_TRUE(offer.get() != NULL);
1116 ContentInfo* dc_offer = offer->GetContentByName("data");
1117 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001118 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001119 dcd_offer->set_use_sctpmap(false);
1120
1121 std::unique_ptr<SessionDescription> answer(
1122 f2_.CreateAnswer(offer.get(), opts, NULL));
1123 const ContentInfo* dc_answer = answer->GetContentByName("data");
1124 ASSERT_TRUE(dc_answer != NULL);
1125 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001126 dc_answer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001127 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001128}
1129
deadbeef8b7e9ad2017-05-25 09:38:55 -07001130// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1131// and "TCP/DTLS/SCTP" offers.
1132TEST_F(MediaSessionDescriptionFactoryTest,
1133 TestCreateDataAnswerToDifferentOfferedProtos) {
1134 // Need to enable DTLS offer/answer generation (disabled by default in this
1135 // test).
1136 f1_.set_secure(SEC_ENABLED);
1137 f2_.set_secure(SEC_ENABLED);
1138 tdf1_.set_secure(SEC_ENABLED);
1139 tdf2_.set_secure(SEC_ENABLED);
1140
1141 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001142 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001143 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
1144 ASSERT_TRUE(offer.get() != nullptr);
1145 ContentInfo* dc_offer = offer->GetContentByName("data");
1146 ASSERT_TRUE(dc_offer != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08001147 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001148
1149 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1150 "TCP/DTLS/SCTP"};
1151 for (const std::string& proto : protos) {
1152 dcd_offer->set_protocol(proto);
1153 std::unique_ptr<SessionDescription> answer(
1154 f2_.CreateAnswer(offer.get(), opts, nullptr));
1155 const ContentInfo* dc_answer = answer->GetContentByName("data");
1156 ASSERT_TRUE(dc_answer != nullptr);
1157 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001158 dc_answer->media_description()->as_data();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001159 EXPECT_FALSE(dc_answer->rejected);
1160 EXPECT_EQ(proto, dcd_answer->protocol());
1161 }
1162}
1163
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001164// Verifies that the order of the media contents in the offer is preserved in
1165// the answer.
1166TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1167 MediaSessionOptions opts;
1168
1169 // Creates a data only offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001170 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001171 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001172 ASSERT_TRUE(offer1.get() != NULL);
1173
1174 // Appends audio to the offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001175 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
1176 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -08001177 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001178 f1_.CreateOffer(opts, offer1.get()));
1179 ASSERT_TRUE(offer2.get() != NULL);
1180
1181 // Appends video to the offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001182 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
1183 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -08001184 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001185 f1_.CreateOffer(opts, offer2.get()));
1186 ASSERT_TRUE(offer3.get() != NULL);
1187
kwiberg31022942016-03-11 14:18:21 -08001188 std::unique_ptr<SessionDescription> answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001189 f2_.CreateAnswer(offer3.get(), opts, NULL));
1190 ASSERT_TRUE(answer.get() != NULL);
1191 EXPECT_EQ(3u, answer->contents().size());
1192 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1193 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1194 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1195}
1196
ossu075af922016-06-14 03:29:38 -07001197// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1198// answerer settings.
1199
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001200// This test that the media direction is set to send/receive in an answer if
1201// the offer is send receive.
1202TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001203 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1204 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001205}
1206
1207// This test that the media direction is set to receive only in an answer if
1208// the offer is send only.
1209TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001210 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1211 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001212}
1213
1214// This test that the media direction is set to send only in an answer if
1215// the offer is recv only.
1216TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001217 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1218 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001219}
1220
1221// This test that the media direction is set to inactive in an answer if
1222// the offer is inactive.
1223TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001224 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1225 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001226}
1227
1228// Test that a data content with an unknown protocol is rejected in an answer.
1229TEST_F(MediaSessionDescriptionFactoryTest,
1230 CreateDataAnswerToOfferWithUnknownProtocol) {
1231 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001232 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001233 f1_.set_secure(SEC_ENABLED);
1234 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001235 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
terelius8c011e52016-04-26 05:28:11 -07001236 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001237 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001238 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001239 ASSERT_TRUE(dcd_offer != NULL);
1240 std::string protocol = "a weird unknown protocol";
1241 dcd_offer->set_protocol(protocol);
1242
kwiberg31022942016-03-11 14:18:21 -08001243 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001244 f2_.CreateAnswer(offer.get(), opts, NULL));
1245
1246 const ContentInfo* dc_answer = answer->GetContentByName("data");
1247 ASSERT_TRUE(dc_answer != NULL);
1248 EXPECT_TRUE(dc_answer->rejected);
1249 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001250 dc_answer->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001251 ASSERT_TRUE(dcd_answer != NULL);
1252 EXPECT_EQ(protocol, dcd_answer->protocol());
1253}
1254
1255// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1256TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001257 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001258 f1_.set_secure(SEC_DISABLED);
1259 f2_.set_secure(SEC_DISABLED);
1260 tdf1_.set_secure(SEC_DISABLED);
1261 tdf2_.set_secure(SEC_DISABLED);
1262
kwiberg31022942016-03-11 14:18:21 -08001263 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001264 const AudioContentDescription* offer_acd =
1265 GetFirstAudioContentDescription(offer.get());
1266 ASSERT_TRUE(offer_acd != NULL);
1267 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), offer_acd->protocol());
1268
kwiberg31022942016-03-11 14:18:21 -08001269 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001270 f2_.CreateAnswer(offer.get(), opts, NULL));
1271
1272 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1273 ASSERT_TRUE(ac_answer != NULL);
1274 EXPECT_FALSE(ac_answer->rejected);
1275
1276 const AudioContentDescription* answer_acd =
1277 GetFirstAudioContentDescription(answer.get());
1278 ASSERT_TRUE(answer_acd != NULL);
1279 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), answer_acd->protocol());
1280}
1281
1282// Create a video offer and answer and ensure the RTP header extensions
1283// matches what we expect.
1284TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1285 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001286 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001287 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1288 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1289 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1290 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1291
kwiberg31022942016-03-11 14:18:21 -08001292 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001293 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001294 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001295 f2_.CreateAnswer(offer.get(), opts, NULL));
1296
1297 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension1),
1298 GetFirstAudioContentDescription(
1299 offer.get())->rtp_header_extensions());
1300 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtension1),
1301 GetFirstVideoContentDescription(
1302 offer.get())->rtp_header_extensions());
1303 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
1304 GetFirstAudioContentDescription(
1305 answer.get())->rtp_header_extensions());
1306 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
1307 GetFirstVideoContentDescription(
1308 answer.get())->rtp_header_extensions());
1309}
1310
jbauch5869f502017-06-29 12:31:36 -07001311TEST_F(MediaSessionDescriptionFactoryTest,
1312 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
1313 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001314 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001315
1316 f1_.set_enable_encrypted_rtp_header_extensions(true);
1317 f2_.set_enable_encrypted_rtp_header_extensions(true);
1318
1319 f1_.set_audio_rtp_header_extensions(
1320 MAKE_VECTOR(kAudioRtpExtension1));
1321 f1_.set_video_rtp_header_extensions(
1322 MAKE_VECTOR(kVideoRtpExtension1));
1323 f2_.set_audio_rtp_header_extensions(
1324 MAKE_VECTOR(kAudioRtpExtension2));
1325 f2_.set_video_rtp_header_extensions(
1326 MAKE_VECTOR(kVideoRtpExtension2));
1327
1328 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1329 ASSERT_TRUE(offer.get() != NULL);
1330 std::unique_ptr<SessionDescription> answer(
1331 f2_.CreateAnswer(offer.get(), opts, NULL));
1332
1333 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1334 GetFirstAudioContentDescription(
1335 offer.get())->rtp_header_extensions());
1336 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1337 GetFirstVideoContentDescription(
1338 offer.get())->rtp_header_extensions());
1339 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
1340 GetFirstAudioContentDescription(
1341 answer.get())->rtp_header_extensions());
1342 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
1343 GetFirstVideoContentDescription(
1344 answer.get())->rtp_header_extensions());
1345}
1346
1347TEST_F(MediaSessionDescriptionFactoryTest,
1348 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
1349 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001350 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001351
1352 f1_.set_enable_encrypted_rtp_header_extensions(true);
1353
1354 f1_.set_audio_rtp_header_extensions(
1355 MAKE_VECTOR(kAudioRtpExtension1));
1356 f1_.set_video_rtp_header_extensions(
1357 MAKE_VECTOR(kVideoRtpExtension1));
1358 f2_.set_audio_rtp_header_extensions(
1359 MAKE_VECTOR(kAudioRtpExtension2));
1360 f2_.set_video_rtp_header_extensions(
1361 MAKE_VECTOR(kVideoRtpExtension2));
1362
1363 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1364 ASSERT_TRUE(offer.get() != NULL);
1365 std::unique_ptr<SessionDescription> answer(
1366 f2_.CreateAnswer(offer.get(), opts, NULL));
1367
1368 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1369 GetFirstAudioContentDescription(
1370 offer.get())->rtp_header_extensions());
1371 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1372 GetFirstVideoContentDescription(
1373 offer.get())->rtp_header_extensions());
1374 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
1375 GetFirstAudioContentDescription(
1376 answer.get())->rtp_header_extensions());
1377 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
1378 GetFirstVideoContentDescription(
1379 answer.get())->rtp_header_extensions());
1380}
1381
1382TEST_F(MediaSessionDescriptionFactoryTest,
1383 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
1384 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001385 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001386
1387 f2_.set_enable_encrypted_rtp_header_extensions(true);
1388
1389 f1_.set_audio_rtp_header_extensions(
1390 MAKE_VECTOR(kAudioRtpExtension1));
1391 f1_.set_video_rtp_header_extensions(
1392 MAKE_VECTOR(kVideoRtpExtension1));
1393 f2_.set_audio_rtp_header_extensions(
1394 MAKE_VECTOR(kAudioRtpExtension2));
1395 f2_.set_video_rtp_header_extensions(
1396 MAKE_VECTOR(kVideoRtpExtension2));
1397
1398 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1399 ASSERT_TRUE(offer.get() != NULL);
1400 std::unique_ptr<SessionDescription> answer(
1401 f2_.CreateAnswer(offer.get(), opts, NULL));
1402
1403 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension1),
1404 GetFirstAudioContentDescription(
1405 offer.get())->rtp_header_extensions());
1406 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtension1),
1407 GetFirstVideoContentDescription(
1408 offer.get())->rtp_header_extensions());
1409 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
1410 GetFirstAudioContentDescription(
1411 answer.get())->rtp_header_extensions());
1412 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
1413 GetFirstVideoContentDescription(
1414 answer.get())->rtp_header_extensions());
1415}
1416
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001417// Create an audio, video, data answer without legacy StreamParams.
1418TEST_F(MediaSessionDescriptionFactoryTest,
1419 TestCreateAnswerWithoutLegacyStreams) {
1420 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001421 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1422 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
kwiberg31022942016-03-11 14:18:21 -08001423 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001424 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001425 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001426 f2_.CreateAnswer(offer.get(), opts, NULL));
1427 const ContentInfo* ac = answer->GetContentByName("audio");
1428 const ContentInfo* vc = answer->GetContentByName("video");
1429 const ContentInfo* dc = answer->GetContentByName("data");
1430 ASSERT_TRUE(ac != NULL);
1431 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001432 const AudioContentDescription* acd = ac->media_description()->as_audio();
1433 const VideoContentDescription* vcd = vc->media_description()->as_video();
1434 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001435
1436 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1437 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1438 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1439}
1440
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001441// Create a typical video answer, and ensure it matches what we expect.
1442TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1443 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001444 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
1445 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1446 &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001447
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001448 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001449 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
1450 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1451 &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001452
kwiberg31022942016-03-11 14:18:21 -08001453 std::unique_ptr<SessionDescription> offer;
1454 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001455
1456 offer_opts.rtcp_mux_enabled = true;
1457 answer_opts.rtcp_mux_enabled = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001458 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1459 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1460 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1461 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1462 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1463 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1464 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1465 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1466 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1467 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1468 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1469 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1470 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1471 EXPECT_TRUE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1472
1473 offer_opts.rtcp_mux_enabled = true;
1474 answer_opts.rtcp_mux_enabled = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001475 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1476 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1477 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1478 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1479 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1480 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1481 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1482 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1483 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1484 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1485 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1486 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1487 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1488 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1489
1490 offer_opts.rtcp_mux_enabled = false;
1491 answer_opts.rtcp_mux_enabled = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001492 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1493 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1494 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1495 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1496 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1497 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1498 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1499 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1500 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1501 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1502 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1503 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1504 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1505 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1506
1507 offer_opts.rtcp_mux_enabled = false;
1508 answer_opts.rtcp_mux_enabled = false;
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_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1518 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1519 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1520 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1521 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1522 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1523}
1524
1525// Create an audio-only answer to a video offer.
1526TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1527 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001528 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
1529 kActive, &opts);
1530 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
1531 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -08001532 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001533 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001534
1535 opts.media_description_options[1].stopped = true;
kwiberg31022942016-03-11 14:18:21 -08001536 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001537 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001538 const ContentInfo* ac = answer->GetContentByName("audio");
1539 const ContentInfo* vc = answer->GetContentByName("video");
1540 ASSERT_TRUE(ac != NULL);
1541 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001542 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001543 EXPECT_TRUE(vc->rejected);
1544}
1545
1546// Create an audio-only answer to an offer with data.
1547TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001548 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001549 opts.data_channel_type = cricket::DCT_RTP;
Steve Anton4e70a722017-11-28 14:57:10 -08001550 AddMediaSection(MEDIA_TYPE_DATA, "data", RtpTransceiverDirection::kRecvOnly,
1551 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -08001552 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001553 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001554
1555 opts.media_description_options[1].stopped = true;
kwiberg31022942016-03-11 14:18:21 -08001556 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001557 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001558 const ContentInfo* ac = answer->GetContentByName("audio");
1559 const ContentInfo* dc = answer->GetContentByName("data");
1560 ASSERT_TRUE(ac != NULL);
1561 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001562 ASSERT_TRUE(dc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001563 EXPECT_TRUE(dc->rejected);
1564}
1565
1566// Create an answer that rejects the contents which are rejected in the offer.
1567TEST_F(MediaSessionDescriptionFactoryTest,
1568 CreateAnswerToOfferWithRejectedMedia) {
1569 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001570 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1571 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
kwiberg31022942016-03-11 14:18:21 -08001572 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001573 ASSERT_TRUE(offer.get() != NULL);
1574 ContentInfo* ac = offer->GetContentByName("audio");
1575 ContentInfo* vc = offer->GetContentByName("video");
1576 ContentInfo* dc = offer->GetContentByName("data");
1577 ASSERT_TRUE(ac != NULL);
1578 ASSERT_TRUE(vc != NULL);
1579 ASSERT_TRUE(dc != NULL);
1580 ac->rejected = true;
1581 vc->rejected = true;
1582 dc->rejected = true;
kwiberg31022942016-03-11 14:18:21 -08001583 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001584 f2_.CreateAnswer(offer.get(), opts, NULL));
1585 ac = answer->GetContentByName("audio");
1586 vc = answer->GetContentByName("video");
1587 dc = answer->GetContentByName("data");
1588 ASSERT_TRUE(ac != NULL);
1589 ASSERT_TRUE(vc != NULL);
1590 ASSERT_TRUE(dc != NULL);
1591 EXPECT_TRUE(ac->rejected);
1592 EXPECT_TRUE(vc->rejected);
1593 EXPECT_TRUE(dc->rejected);
1594}
1595
1596// Create an audio and video offer with:
1597// - one video track
1598// - two audio tracks
1599// - two data tracks
1600// and ensure it matches what we expect. Also updates the initial offer by
1601// adding a new video track and replaces one of the audio tracks.
1602TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
1603 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001604 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001605 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001606 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001607 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001608 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001609 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001610 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001611
Steve Anton4e70a722017-11-28 14:57:10 -08001612 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001613 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001614 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001615 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001616 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001617
1618 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001619 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001620
1621 ASSERT_TRUE(offer.get() != NULL);
1622 const ContentInfo* ac = offer->GetContentByName("audio");
1623 const ContentInfo* vc = offer->GetContentByName("video");
1624 const ContentInfo* dc = offer->GetContentByName("data");
1625 ASSERT_TRUE(ac != NULL);
1626 ASSERT_TRUE(vc != NULL);
1627 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001628 const AudioContentDescription* acd = ac->media_description()->as_audio();
1629 const VideoContentDescription* vcd = vc->media_description()->as_video();
1630 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001631 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07001632 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001633
1634 const StreamParamsVec& audio_streams = acd->streams();
1635 ASSERT_EQ(2U, audio_streams.size());
1636 EXPECT_EQ(audio_streams[0].cname , audio_streams[1].cname);
1637 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1638 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1639 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1640 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1641 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1642 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1643
1644 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1645 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1646 ASSERT_CRYPTO(acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
1647
1648 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1649 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
1650 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1651
1652 const StreamParamsVec& video_streams = vcd->streams();
1653 ASSERT_EQ(1U, video_streams.size());
1654 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1655 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1656 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1657 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1658
1659 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1660 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
1661 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1662
1663 const StreamParamsVec& data_streams = dcd->streams();
1664 ASSERT_EQ(2U, data_streams.size());
1665 EXPECT_EQ(data_streams[0].cname , data_streams[1].cname);
1666 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1667 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1668 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1669 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1670 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1671 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1672
1673 EXPECT_EQ(cricket::kDataMaxBandwidth,
1674 dcd->bandwidth()); // default bandwidth (auto)
1675 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
1676 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1677
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001678 // Update the offer. Add a new video track that is not synched to the
1679 // other tracks and replace audio track 2 with audio track 3.
zhihuang1c378ed2017-08-17 14:10:50 -07001680 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001681 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001682 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
1683 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001684 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001685 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
1686 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack3,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001687 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08001688 std::unique_ptr<SessionDescription> updated_offer(
1689 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001690
1691 ASSERT_TRUE(updated_offer.get() != NULL);
1692 ac = updated_offer->GetContentByName("audio");
1693 vc = updated_offer->GetContentByName("video");
1694 dc = updated_offer->GetContentByName("data");
1695 ASSERT_TRUE(ac != NULL);
1696 ASSERT_TRUE(vc != NULL);
1697 ASSERT_TRUE(dc != NULL);
1698 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001699 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001700 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001701 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001702 const DataContentDescription* updated_dcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001703 dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001704
1705 EXPECT_EQ(acd->type(), updated_acd->type());
1706 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1707 EXPECT_EQ(vcd->type(), updated_vcd->type());
1708 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1709 EXPECT_EQ(dcd->type(), updated_dcd->type());
1710 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1711 ASSERT_CRYPTO(updated_acd, 2U, CS_AES_CM_128_HMAC_SHA1_32);
1712 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
1713 ASSERT_CRYPTO(updated_vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1714 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
1715 ASSERT_CRYPTO(updated_dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1716 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1717
1718 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1719 ASSERT_EQ(2U, updated_audio_streams.size());
1720 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
1721 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
1722 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
1723 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
1724 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
1725
1726 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1727 ASSERT_EQ(2U, updated_video_streams.size());
1728 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1729 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001730 // All the media streams in one PeerConnection share one RTCP CNAME.
1731 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001732
1733 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1734 ASSERT_EQ(2U, updated_data_streams.size());
1735 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
1736 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
1737 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
1738 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
1739 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07001740 // The stream correctly got the CNAME from the MediaSessionOptions.
1741 // The Expected RTCP CNAME is the default one as we are using the default
1742 // MediaSessionOptions.
1743 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001744}
1745
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001746// Create an offer with simulcast video stream.
1747TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
1748 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001749 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
1750 kActive, &opts);
1751 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
1752 kActive, &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001753 const int num_sim_layers = 3;
zhihuang1c378ed2017-08-17 14:10:50 -07001754 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001755 {kMediaStream1}, num_sim_layers, &opts);
kwiberg31022942016-03-11 14:18:21 -08001756 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001757
1758 ASSERT_TRUE(offer.get() != NULL);
1759 const ContentInfo* vc = offer->GetContentByName("video");
1760 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001761 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001762
1763 const StreamParamsVec& video_streams = vcd->streams();
1764 ASSERT_EQ(1U, video_streams.size());
1765 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1766 const SsrcGroup* sim_ssrc_group =
1767 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
1768 ASSERT_TRUE(sim_ssrc_group != NULL);
1769 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
1770}
1771
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001772// Create an audio and video answer to a standard video offer with:
1773// - one video track
1774// - two audio tracks
1775// - two data tracks
1776// and ensure it matches what we expect. Also updates the initial answer by
1777// adding a new video track and removes one of the audio tracks.
1778TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
1779 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001780 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
1781 kActive, &offer_opts);
1782 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
1783 kActive, &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001784 offer_opts.data_channel_type = cricket::DCT_RTP;
Steve Anton4e70a722017-11-28 14:57:10 -08001785 AddMediaSection(MEDIA_TYPE_DATA, "data", RtpTransceiverDirection::kRecvOnly,
1786 kActive, &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001787 f1_.set_secure(SEC_ENABLED);
1788 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001789 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(offer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001790
zhihuang1c378ed2017-08-17 14:10:50 -07001791 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001792 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kSendRecv,
1793 kActive, &answer_opts);
1794 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
1795 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001796 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001797 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001798 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001799 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001800 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001801 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001802
Steve Anton4e70a722017-11-28 14:57:10 -08001803 AddMediaSection(MEDIA_TYPE_DATA, "data", RtpTransceiverDirection::kSendRecv,
1804 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001805 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001806 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001807 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001808 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001809 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001810
kwiberg31022942016-03-11 14:18:21 -08001811 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001812 f2_.CreateAnswer(offer.get(), answer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001813
1814 ASSERT_TRUE(answer.get() != NULL);
1815 const ContentInfo* ac = answer->GetContentByName("audio");
1816 const ContentInfo* vc = answer->GetContentByName("video");
1817 const ContentInfo* dc = answer->GetContentByName("data");
1818 ASSERT_TRUE(ac != NULL);
1819 ASSERT_TRUE(vc != NULL);
1820 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001821 const AudioContentDescription* acd = ac->media_description()->as_audio();
1822 const VideoContentDescription* vcd = vc->media_description()->as_video();
1823 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001824 ASSERT_CRYPTO(acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1825 ASSERT_CRYPTO(vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1826 ASSERT_CRYPTO(dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1827
1828 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1829 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1830
1831 const StreamParamsVec& audio_streams = acd->streams();
1832 ASSERT_EQ(2U, audio_streams.size());
1833 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
1834 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1835 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1836 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1837 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1838 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1839 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1840
1841 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1842 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1843
1844 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1845 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1846
1847 const StreamParamsVec& video_streams = vcd->streams();
1848 ASSERT_EQ(1U, video_streams.size());
1849 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1850 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1851 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1852 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1853
1854 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1855 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
1856
1857 const StreamParamsVec& data_streams = dcd->streams();
1858 ASSERT_EQ(2U, data_streams.size());
1859 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
1860 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1861 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1862 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1863 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1864 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1865 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1866
1867 EXPECT_EQ(cricket::kDataMaxBandwidth,
1868 dcd->bandwidth()); // default bandwidth (auto)
1869 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
1870
1871 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07001872 // other tracks and remove 1 audio track.
zhihuang1c378ed2017-08-17 14:10:50 -07001873 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001874 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001875 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
1876 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08001877 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001878 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001879
1880 ASSERT_TRUE(updated_answer.get() != NULL);
1881 ac = updated_answer->GetContentByName("audio");
1882 vc = updated_answer->GetContentByName("video");
1883 dc = updated_answer->GetContentByName("data");
1884 ASSERT_TRUE(ac != NULL);
1885 ASSERT_TRUE(vc != NULL);
1886 ASSERT_TRUE(dc != NULL);
1887 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001888 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001889 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001890 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001891 const DataContentDescription* updated_dcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001892 dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001893
1894 ASSERT_CRYPTO(updated_acd, 1U, CS_AES_CM_128_HMAC_SHA1_32);
1895 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
1896 ASSERT_CRYPTO(updated_vcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1897 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
1898 ASSERT_CRYPTO(updated_dcd, 1U, CS_AES_CM_128_HMAC_SHA1_80);
1899 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1900
1901 EXPECT_EQ(acd->type(), updated_acd->type());
1902 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1903 EXPECT_EQ(vcd->type(), updated_vcd->type());
1904 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1905 EXPECT_EQ(dcd->type(), updated_dcd->type());
1906 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1907
1908 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1909 ASSERT_EQ(1U, updated_audio_streams.size());
1910 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
1911
1912 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1913 ASSERT_EQ(2U, updated_video_streams.size());
1914 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1915 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001916 // All media streams in one PeerConnection share one CNAME.
1917 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001918
1919 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1920 ASSERT_EQ(1U, updated_data_streams.size());
1921 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
1922}
1923
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001924// Create an updated offer after creating an answer to the original offer and
1925// verify that the codecs that were part of the original answer are not changed
1926// in the updated offer.
1927TEST_F(MediaSessionDescriptionFactoryTest,
1928 RespondentCreatesOfferAfterCreatingAnswer) {
1929 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001930 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001931
kwiberg31022942016-03-11 14:18:21 -08001932 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1933 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001934 f2_.CreateAnswer(offer.get(), opts, NULL));
1935
1936 const AudioContentDescription* acd =
1937 GetFirstAudioContentDescription(answer.get());
1938 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1939
1940 const VideoContentDescription* vcd =
1941 GetFirstVideoContentDescription(answer.get());
1942 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1943
kwiberg31022942016-03-11 14:18:21 -08001944 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001945 f2_.CreateOffer(opts, answer.get()));
1946
1947 // The expected audio codecs are the common audio codecs from the first
1948 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
1949 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00001950 // TODO(wu): |updated_offer| should not include the codec
1951 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001952 const AudioCodec kUpdatedAudioCodecOffer[] = {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001953 kAudioCodecsAnswer[0],
1954 kAudioCodecsAnswer[1],
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00001955 kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001956 };
1957
1958 // The expected video codecs are the common video codecs from the first
1959 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
1960 // preference order.
1961 const VideoCodec kUpdatedVideoCodecOffer[] = {
1962 kVideoCodecsAnswer[0],
1963 kVideoCodecs2[1],
1964 };
1965
1966 const AudioContentDescription* updated_acd =
1967 GetFirstAudioContentDescription(updated_offer.get());
1968 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioCodecOffer), updated_acd->codecs());
1969
1970 const VideoContentDescription* updated_vcd =
1971 GetFirstVideoContentDescription(updated_offer.get());
1972 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoCodecOffer), updated_vcd->codecs());
1973}
1974
1975// Create an updated offer after creating an answer to the original offer and
1976// verify that the codecs that were part of the original answer are not changed
1977// in the updated offer. In this test Rtx is enabled.
1978TEST_F(MediaSessionDescriptionFactoryTest,
1979 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
1980 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001981 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
1982 kActive, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001983 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001984 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001985 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001986 f1_.set_video_codecs(f1_codecs);
1987
1988 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001989 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001990 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001991 f2_.set_video_codecs(f2_codecs);
1992
kwiberg31022942016-03-11 14:18:21 -08001993 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001994 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001995 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001996 f2_.CreateAnswer(offer.get(), opts, NULL));
1997
1998 const VideoContentDescription* vcd =
1999 GetFirstVideoContentDescription(answer.get());
2000
2001 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002002 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2003 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002004
2005 EXPECT_EQ(expected_codecs, vcd->codecs());
2006
deadbeef67cf2c12016-04-13 10:07:16 -07002007 // Now, make sure we get same result (except for the order) if |f2_| creates
2008 // an updated offer even though the default payload types between |f1_| and
2009 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08002010 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002011 f2_.CreateOffer(opts, answer.get()));
2012 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002013 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002014 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2015
2016 const VideoContentDescription* updated_vcd =
2017 GetFirstVideoContentDescription(updated_answer.get());
2018
2019 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2020}
2021
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002022// Regression test for:
2023// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2024// Existing codecs should always appear before new codecs in re-offers. But
2025// under a specific set of circumstances, the existing RTX codec was ending up
2026// added to the end of the list.
2027TEST_F(MediaSessionDescriptionFactoryTest,
2028 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2029 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002030 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2031 kActive, &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002032 // We specifically choose different preferred payload types for VP8 to
2033 // trigger the issue.
2034 cricket::VideoCodec vp8_offerer(100, "VP8");
2035 cricket::VideoCodec vp8_offerer_rtx =
2036 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
2037 cricket::VideoCodec vp8_answerer(110, "VP8");
2038 cricket::VideoCodec vp8_answerer_rtx =
2039 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
2040 cricket::VideoCodec vp9(120, "VP9");
2041 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
2042
2043 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
2044 // We also specifically cause the answerer to prefer VP9, such that if it
2045 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
2046 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
2047 vp8_answerer_rtx};
2048
2049 f1_.set_video_codecs(f1_codecs);
2050 f2_.set_video_codecs(f2_codecs);
2051 std::vector<AudioCodec> audio_codecs;
2052 f1_.set_audio_codecs(audio_codecs, audio_codecs);
2053 f2_.set_audio_codecs(audio_codecs, audio_codecs);
2054
2055 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
2056 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2057 ASSERT_TRUE(offer.get() != NULL);
2058 std::unique_ptr<SessionDescription> answer(
2059 f2_.CreateAnswer(offer.get(), opts, NULL));
2060
2061 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
2062 // But if the bug is triggered, RTX for VP8 ends up last.
2063 std::unique_ptr<SessionDescription> updated_offer(
2064 f2_.CreateOffer(opts, answer.get()));
2065
2066 const VideoContentDescription* vcd =
2067 GetFirstVideoContentDescription(updated_offer.get());
2068 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
2069 ASSERT_EQ(4u, codecs.size());
2070 EXPECT_EQ(vp8_offerer, codecs[0]);
2071 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
2072 EXPECT_EQ(vp9, codecs[2]);
2073 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002074}
2075
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002076// Create an updated offer that adds video after creating an audio only answer
2077// to the original offer. This test verifies that if a video codec and the RTX
2078// codec have the same default payload type as an audio codec that is already in
2079// use, the added codecs payload types are changed.
2080TEST_F(MediaSessionDescriptionFactoryTest,
2081 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2082 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002083 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002084 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002085 f1_.set_video_codecs(f1_codecs);
2086
2087 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002088 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2089 kActive, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002090
kwiberg31022942016-03-11 14:18:21 -08002091 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2092 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002093 f2_.CreateAnswer(offer.get(), opts, NULL));
2094
2095 const AudioContentDescription* acd =
2096 GetFirstAudioContentDescription(answer.get());
2097 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
2098
2099 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
2100 // reference be the same as an audio codec that was negotiated in the
2101 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002102 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08002103 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002104
2105 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2106 int used_pl_type = acd->codecs()[0].id;
2107 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002108 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002109 f2_.set_video_codecs(f2_codecs);
2110
kwiberg31022942016-03-11 14:18:21 -08002111 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002112 f2_.CreateOffer(opts, answer.get()));
2113 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002114 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002115 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2116
2117 const AudioContentDescription* updated_acd =
2118 GetFirstAudioContentDescription(answer.get());
2119 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), updated_acd->codecs());
2120
2121 const VideoContentDescription* updated_vcd =
2122 GetFirstVideoContentDescription(updated_answer.get());
2123
2124 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
sergeyu@chromium.org32f485b2013-12-05 22:36:21 +00002125 ASSERT_EQ(std::string(cricket::kRtxCodecName), updated_vcd->codecs()[1].name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002126 int new_h264_pl_type = updated_vcd->codecs()[0].id;
2127 EXPECT_NE(used_pl_type, new_h264_pl_type);
2128 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002129 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002130 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
2131 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
2132}
2133
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002134// Create an updated offer with RTX after creating an answer to an offer
2135// without RTX, and with different default payload types.
2136// Verify that the added RTX codec references the correct payload type.
2137TEST_F(MediaSessionDescriptionFactoryTest,
2138 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
2139 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002140 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002141
2142 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2143 // This creates rtx for H264 with the payload type |f2_| uses.
2144 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
2145 f2_.set_video_codecs(f2_codecs);
2146
kwiberg31022942016-03-11 14:18:21 -08002147 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002148 ASSERT_TRUE(offer.get() != nullptr);
kwiberg31022942016-03-11 14:18:21 -08002149 std::unique_ptr<SessionDescription> answer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002150 f2_.CreateAnswer(offer.get(), opts, nullptr));
2151
2152 const VideoContentDescription* vcd =
2153 GetFirstVideoContentDescription(answer.get());
2154
2155 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2156 EXPECT_EQ(expected_codecs, vcd->codecs());
2157
2158 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
2159 // updated offer, even though the default payload types are different from
2160 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08002161 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002162 f2_.CreateOffer(opts, answer.get()));
2163 ASSERT_TRUE(updated_offer);
2164
2165 const VideoContentDescription* updated_vcd =
2166 GetFirstVideoContentDescription(updated_offer.get());
2167
2168 // New offer should attempt to add H263, and RTX for H264.
2169 expected_codecs.push_back(kVideoCodecs2[1]);
2170 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
2171 &expected_codecs);
2172 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2173}
2174
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002175// Test that RTX is ignored when there is no associated payload type parameter.
2176TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
2177 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002178 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2179 kActive, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002180 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002181 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07002182 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002183 f1_.set_video_codecs(f1_codecs);
2184
2185 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002186 // This creates RTX for H264 with the payload type |f2_| uses.
2187 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002188 f2_.set_video_codecs(f2_codecs);
2189
kwiberg31022942016-03-11 14:18:21 -08002190 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002191 ASSERT_TRUE(offer.get() != NULL);
2192 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
2193 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
2194 // is possible to test that that RTX is dropped when
2195 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08002196 MediaContentDescription* media_desc =
2197 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2198 ASSERT_TRUE(media_desc);
2199 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002200 std::vector<VideoCodec> codecs = desc->codecs();
2201 for (std::vector<VideoCodec>::iterator iter = codecs.begin();
2202 iter != codecs.end(); ++iter) {
2203 if (iter->name.find(cricket::kRtxCodecName) == 0) {
2204 iter->params.clear();
2205 }
2206 }
2207 desc->set_codecs(codecs);
2208
kwiberg31022942016-03-11 14:18:21 -08002209 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002210 f2_.CreateAnswer(offer.get(), opts, NULL));
2211
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002212 std::vector<std::string> codec_names =
2213 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
2214 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
2215 cricket::kRtxCodecName));
2216}
2217
2218// Test that RTX will be filtered out in the answer if its associated payload
2219// type doesn't match the local value.
2220TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
2221 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002222 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2223 kActive, &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002224 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2225 // This creates RTX for H264 in sender.
2226 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2227 f1_.set_video_codecs(f1_codecs);
2228
2229 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2230 // This creates RTX for H263 in receiver.
2231 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
2232 f2_.set_video_codecs(f2_codecs);
2233
kwiberg31022942016-03-11 14:18:21 -08002234 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002235 ASSERT_TRUE(offer.get() != NULL);
2236 // Associated payload type doesn't match, therefore, RTX codec is removed in
2237 // the answer.
kwiberg31022942016-03-11 14:18:21 -08002238 std::unique_ptr<SessionDescription> answer(
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002239 f2_.CreateAnswer(offer.get(), opts, NULL));
2240
2241 std::vector<std::string> codec_names =
2242 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
2243 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
2244 cricket::kRtxCodecName));
2245}
2246
2247// Test that when multiple RTX codecs are offered, only the matched RTX codec
2248// is added in the answer, and the unsupported RTX codec is filtered out.
2249TEST_F(MediaSessionDescriptionFactoryTest,
2250 FilterOutUnsupportedRtxWhenCreatingAnswer) {
2251 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002252 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2253 kActive, &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002254 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2255 // This creates RTX for H264-SVC in sender.
2256 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2257 f1_.set_video_codecs(f1_codecs);
2258
2259 // This creates RTX for H264 in sender.
2260 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2261 f1_.set_video_codecs(f1_codecs);
2262
2263 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2264 // This creates RTX for H264 in receiver.
2265 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
2266 f2_.set_video_codecs(f2_codecs);
2267
2268 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
2269 // for H264-SVC should also be removed.
kwiberg31022942016-03-11 14:18:21 -08002270 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002271 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002272 std::unique_ptr<SessionDescription> answer(
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002273 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002274 const VideoContentDescription* vcd =
2275 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002276 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2277 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2278 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002279
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002280 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002281}
2282
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002283// Test that after one RTX codec has been negotiated, a new offer can attempt
2284// to add another.
2285TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
2286 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002287 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2288 kActive, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002289 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2290 // This creates RTX for H264 for the offerer.
2291 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2292 f1_.set_video_codecs(f1_codecs);
2293
kwiberg31022942016-03-11 14:18:21 -08002294 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002295 ASSERT_TRUE(offer);
2296 const VideoContentDescription* vcd =
2297 GetFirstVideoContentDescription(offer.get());
2298
2299 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
2300 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2301 &expected_codecs);
2302 EXPECT_EQ(expected_codecs, vcd->codecs());
2303
2304 // Now, attempt to add RTX for H264-SVC.
2305 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2306 f1_.set_video_codecs(f1_codecs);
2307
kwiberg31022942016-03-11 14:18:21 -08002308 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002309 f1_.CreateOffer(opts, offer.get()));
2310 ASSERT_TRUE(updated_offer);
2311 vcd = GetFirstVideoContentDescription(updated_offer.get());
2312
2313 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
2314 &expected_codecs);
2315 EXPECT_EQ(expected_codecs, vcd->codecs());
2316}
2317
Noah Richards2e7a0982015-05-18 14:02:54 -07002318// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
2319// generated for each simulcast ssrc and correctly grouped.
2320TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
2321 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002322 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
2323 kActive, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002324 // Add simulcast streams.
zhihuang1c378ed2017-08-17 14:10:50 -07002325 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002326 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002327
2328 // Use a single real codec, and then add RTX for it.
2329 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07002330 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07002331 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
2332 f1_.set_video_codecs(f1_codecs);
2333
2334 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
2335 // is a FID ssrc + grouping for each.
kwiberg31022942016-03-11 14:18:21 -08002336 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
Noah Richards2e7a0982015-05-18 14:02:54 -07002337 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002338 MediaContentDescription* media_desc =
2339 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2340 ASSERT_TRUE(media_desc);
2341 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07002342 const StreamParamsVec& streams = desc->streams();
2343 // Single stream.
2344 ASSERT_EQ(1u, streams.size());
2345 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
2346 EXPECT_EQ(6u, streams[0].ssrcs.size());
2347 // And should have a SIM group for the simulcast.
2348 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2349 // And a FID group for RTX.
2350 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02002351 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002352 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2353 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02002354 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002355 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
2356 EXPECT_EQ(3u, fid_ssrcs.size());
2357}
2358
brandtr03d5fb12016-11-22 03:37:59 -08002359// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
2360// together with a FEC-FR grouping.
2361TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
2362 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002363 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
2364 kActive, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002365 // Add single stream.
zhihuang1c378ed2017-08-17 14:10:50 -07002366 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002367 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002368
2369 // Use a single real codec, and then add FlexFEC for it.
2370 std::vector<VideoCodec> f1_codecs;
2371 f1_codecs.push_back(VideoCodec(97, "H264"));
2372 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2373 f1_.set_video_codecs(f1_codecs);
2374
2375 // Ensure that the offer has a single FlexFEC ssrc and that
2376 // there is no FEC-FR ssrc + grouping for each.
2377 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
2378 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08002379 MediaContentDescription* media_desc =
2380 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2381 ASSERT_TRUE(media_desc);
2382 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08002383 const StreamParamsVec& streams = desc->streams();
2384 // Single stream.
2385 ASSERT_EQ(1u, streams.size());
2386 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
2387 EXPECT_EQ(2u, streams[0].ssrcs.size());
2388 // And should have a FEC-FR group for FlexFEC.
2389 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
2390 std::vector<uint32_t> primary_ssrcs;
2391 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2392 ASSERT_EQ(1u, primary_ssrcs.size());
2393 uint32_t flexfec_ssrc;
2394 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
2395 EXPECT_NE(flexfec_ssrc, 0u);
2396}
2397
2398// Test that FlexFEC is disabled for simulcast.
2399// TODO(brandtr): Remove this test when we support simulcast, either through
2400// multiple FlexfecSenders, or through multistream protection.
2401TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
2402 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002403 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
2404 kActive, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002405 // Add simulcast streams.
zhihuang1c378ed2017-08-17 14:10:50 -07002406 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002407 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002408
2409 // Use a single real codec, and then add FlexFEC for it.
2410 std::vector<VideoCodec> f1_codecs;
2411 f1_codecs.push_back(VideoCodec(97, "H264"));
2412 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2413 f1_.set_video_codecs(f1_codecs);
2414
2415 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
2416 // there is no FEC-FR ssrc + grouping for each.
2417 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
2418 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08002419 MediaContentDescription* media_desc =
2420 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2421 ASSERT_TRUE(media_desc);
2422 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08002423 const StreamParamsVec& streams = desc->streams();
2424 // Single stream.
2425 ASSERT_EQ(1u, streams.size());
2426 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
2427 EXPECT_EQ(3u, streams[0].ssrcs.size());
2428 // And should have a SIM group for the simulcast.
2429 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2430 // And not a FEC-FR group for FlexFEC.
2431 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
2432 std::vector<uint32_t> primary_ssrcs;
2433 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2434 EXPECT_EQ(3u, primary_ssrcs.size());
2435 for (uint32_t primary_ssrc : primary_ssrcs) {
2436 uint32_t flexfec_ssrc;
2437 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
2438 }
2439}
2440
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002441// Create an updated offer after creating an answer to the original offer and
2442// verify that the RTP header extensions that were part of the original answer
2443// are not changed in the updated offer.
2444TEST_F(MediaSessionDescriptionFactoryTest,
2445 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
2446 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002447 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002448
2449 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
2450 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
2451 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
2452 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
2453
kwiberg31022942016-03-11 14:18:21 -08002454 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2455 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002456 f2_.CreateAnswer(offer.get(), opts, NULL));
2457
2458 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
2459 GetFirstAudioContentDescription(
2460 answer.get())->rtp_header_extensions());
2461 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
2462 GetFirstVideoContentDescription(
2463 answer.get())->rtp_header_extensions());
2464
kwiberg31022942016-03-11 14:18:21 -08002465 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002466 f2_.CreateOffer(opts, answer.get()));
2467
2468 // The expected RTP header extensions in the new offer are the resulting
2469 // extensions from the first offer/answer exchange plus the extensions only
2470 // |f2_| offer.
2471 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002472 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07002473 const RtpExtension kUpdatedAudioRtpExtensions[] = {
2474 kAudioRtpExtensionAnswer[0], RtpExtension(kAudioRtpExtension2[1].uri, 13),
2475 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002476 };
2477
2478 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002479 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07002480 const RtpExtension kUpdatedVideoRtpExtensions[] = {
2481 kVideoRtpExtensionAnswer[0], RtpExtension(kVideoRtpExtension2[1].uri, 12),
2482 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002483 };
2484
2485 const AudioContentDescription* updated_acd =
2486 GetFirstAudioContentDescription(updated_offer.get());
2487 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
2488 updated_acd->rtp_header_extensions());
2489
2490 const VideoContentDescription* updated_vcd =
2491 GetFirstVideoContentDescription(updated_offer.get());
2492 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
2493 updated_vcd->rtp_header_extensions());
2494}
2495
deadbeefa5b273a2015-08-20 17:30:13 -07002496// Verify that if the same RTP extension URI is used for audio and video, the
2497// same ID is used. Also verify that the ID isn't changed when creating an
2498// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07002499TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07002500 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002501 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07002502
2503 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
2504 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
2505
kwiberg31022942016-03-11 14:18:21 -08002506 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
deadbeefa5b273a2015-08-20 17:30:13 -07002507
2508 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
2509 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07002510 const RtpExtension kExpectedVideoRtpExtension[] = {
2511 kVideoRtpExtension3[0], kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07002512 };
2513
2514 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
2515 GetFirstAudioContentDescription(
2516 offer.get())->rtp_header_extensions());
2517 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2518 GetFirstVideoContentDescription(
2519 offer.get())->rtp_header_extensions());
2520
2521 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08002522 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07002523 f1_.CreateOffer(opts, offer.get()));
2524
2525 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
2526 GetFirstAudioContentDescription(
2527 updated_offer.get())->rtp_header_extensions());
2528 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2529 GetFirstVideoContentDescription(
2530 updated_offer.get())->rtp_header_extensions());
2531}
2532
jbauch5869f502017-06-29 12:31:36 -07002533// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
2534TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
2535 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002536 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07002537
2538 f1_.set_enable_encrypted_rtp_header_extensions(true);
2539 f2_.set_enable_encrypted_rtp_header_extensions(true);
2540
2541 f1_.set_audio_rtp_header_extensions(
2542 MAKE_VECTOR(kAudioRtpExtension3ForEncryption));
2543 f1_.set_video_rtp_header_extensions(
2544 MAKE_VECTOR(kVideoRtpExtension3ForEncryption));
2545
2546 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2547
2548 // The extensions that are shared between audio and video should use the same
2549 // id.
2550 const RtpExtension kExpectedVideoRtpExtension[] = {
2551 kVideoRtpExtension3ForEncryption[0],
2552 kAudioRtpExtension3ForEncryptionOffer[1],
2553 kAudioRtpExtension3ForEncryptionOffer[2],
2554 };
2555
2556 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
2557 GetFirstAudioContentDescription(
2558 offer.get())->rtp_header_extensions());
2559 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2560 GetFirstVideoContentDescription(
2561 offer.get())->rtp_header_extensions());
2562
2563 // Nothing should change when creating a new offer
2564 std::unique_ptr<SessionDescription> updated_offer(
2565 f1_.CreateOffer(opts, offer.get()));
2566
2567 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
2568 GetFirstAudioContentDescription(
2569 updated_offer.get())->rtp_header_extensions());
2570 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2571 GetFirstVideoContentDescription(
2572 updated_offer.get())->rtp_header_extensions());
2573}
2574
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002575TEST(MediaSessionDescription, CopySessionDescription) {
2576 SessionDescription source;
2577 cricket::ContentGroup group(cricket::CN_AUDIO);
2578 source.AddGroup(group);
2579 AudioContentDescription* acd(new AudioContentDescription());
2580 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
2581 acd->AddLegacyStream(1);
Steve Anton5adfafd2017-12-20 16:34:00 -08002582 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp, acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002583 VideoContentDescription* vcd(new VideoContentDescription());
2584 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
2585 vcd->AddLegacyStream(2);
Steve Anton5adfafd2017-12-20 16:34:00 -08002586 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp, vcd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002587
kwiberg31022942016-03-11 14:18:21 -08002588 std::unique_ptr<SessionDescription> copy(source.Copy());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002589 ASSERT_TRUE(copy.get() != NULL);
2590 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
2591 const ContentInfo* ac = copy->GetContentByName("audio");
2592 const ContentInfo* vc = copy->GetContentByName("video");
2593 ASSERT_TRUE(ac != NULL);
2594 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08002595 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002596 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002597 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
2598 EXPECT_EQ(1u, acd->first_ssrc());
2599
Steve Anton5adfafd2017-12-20 16:34:00 -08002600 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002601 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002602 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
2603 EXPECT_EQ(2u, vcd->first_ssrc());
2604}
2605
2606// The below TestTransportInfoXXX tests create different offers/answers, and
2607// ensure the TransportInfo in the SessionDescription matches what we expect.
2608TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
2609 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002610 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2611 kActive, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002612 TestTransportInfo(true, options, false);
2613}
2614
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002615TEST_F(MediaSessionDescriptionFactoryTest,
2616 TestTransportInfoOfferIceRenomination) {
2617 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002618 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2619 kActive, &options);
zhihuang1c378ed2017-08-17 14:10:50 -07002620 options.media_description_options[0]
2621 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002622 TestTransportInfo(true, options, false);
2623}
2624
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002625TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
2626 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002627 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2628 kActive, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002629 TestTransportInfo(true, options, true);
2630}
2631
2632TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
2633 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002634 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2635 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2636 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002637 TestTransportInfo(true, options, false);
2638}
2639
2640TEST_F(MediaSessionDescriptionFactoryTest,
2641 TestTransportInfoOfferMultimediaCurrent) {
2642 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002643 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2644 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2645 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002646 TestTransportInfo(true, options, true);
2647}
2648
2649TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
2650 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002651 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2652 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2653 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002654 options.bundle_enabled = true;
2655 TestTransportInfo(true, options, false);
2656}
2657
2658TEST_F(MediaSessionDescriptionFactoryTest,
2659 TestTransportInfoOfferBundleCurrent) {
2660 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002661 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2662 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2663 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002664 options.bundle_enabled = true;
2665 TestTransportInfo(true, options, true);
2666}
2667
2668TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
2669 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002670 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2671 kActive, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002672 TestTransportInfo(false, options, false);
2673}
2674
2675TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002676 TestTransportInfoAnswerIceRenomination) {
2677 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002678 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2679 kActive, &options);
zhihuang1c378ed2017-08-17 14:10:50 -07002680 options.media_description_options[0]
2681 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002682 TestTransportInfo(false, options, false);
2683}
2684
2685TEST_F(MediaSessionDescriptionFactoryTest,
2686 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002687 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002688 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2689 kActive, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002690 TestTransportInfo(false, options, true);
2691}
2692
2693TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
2694 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002695 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2696 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2697 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002698 TestTransportInfo(false, options, false);
2699}
2700
2701TEST_F(MediaSessionDescriptionFactoryTest,
2702 TestTransportInfoAnswerMultimediaCurrent) {
2703 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002704 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2705 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2706 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002707 TestTransportInfo(false, options, true);
2708}
2709
2710TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
2711 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002712 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2713 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2714 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002715 options.bundle_enabled = true;
2716 TestTransportInfo(false, options, false);
2717}
2718
2719TEST_F(MediaSessionDescriptionFactoryTest,
2720 TestTransportInfoAnswerBundleCurrent) {
2721 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002722 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2723 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2724 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002725 options.bundle_enabled = true;
2726 TestTransportInfo(false, options, true);
2727}
2728
2729// Create an offer with bundle enabled and verify the crypto parameters are
2730// the common set of the available cryptos.
2731TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
2732 TestCryptoWithBundle(true);
2733}
2734
2735// Create an answer with bundle enabled and verify the crypto parameters are
2736// the common set of the available cryptos.
2737TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
2738 TestCryptoWithBundle(false);
2739}
2740
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002741// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
2742// DTLS is not enabled locally.
2743TEST_F(MediaSessionDescriptionFactoryTest,
2744 TestOfferDtlsSavpfWithoutDtlsFailed) {
2745 f1_.set_secure(SEC_ENABLED);
2746 f2_.set_secure(SEC_ENABLED);
2747 tdf1_.set_secure(SEC_DISABLED);
2748 tdf2_.set_secure(SEC_DISABLED);
2749
kwiberg31022942016-03-11 14:18:21 -08002750 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -07002751 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002752 ASSERT_TRUE(offer.get() != NULL);
2753 ContentInfo* offer_content = offer->GetContentByName("audio");
2754 ASSERT_TRUE(offer_content != NULL);
2755 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08002756 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002757 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2758
kwiberg31022942016-03-11 14:18:21 -08002759 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002760 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002761 ASSERT_TRUE(answer != NULL);
2762 ContentInfo* answer_content = answer->GetContentByName("audio");
2763 ASSERT_TRUE(answer_content != NULL);
2764
2765 ASSERT_TRUE(answer_content->rejected);
2766}
2767
2768// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
2769// UDP/TLS/RTP/SAVPF.
2770TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
2771 f1_.set_secure(SEC_ENABLED);
2772 f2_.set_secure(SEC_ENABLED);
2773 tdf1_.set_secure(SEC_ENABLED);
2774 tdf2_.set_secure(SEC_ENABLED);
2775
kwiberg31022942016-03-11 14:18:21 -08002776 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -07002777 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002778 ASSERT_TRUE(offer.get() != NULL);
2779 ContentInfo* offer_content = offer->GetContentByName("audio");
2780 ASSERT_TRUE(offer_content != NULL);
2781 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08002782 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002783 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2784
kwiberg31022942016-03-11 14:18:21 -08002785 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002786 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002787 ASSERT_TRUE(answer != NULL);
2788
2789 const ContentInfo* answer_content = answer->GetContentByName("audio");
2790 ASSERT_TRUE(answer_content != NULL);
2791 ASSERT_FALSE(answer_content->rejected);
2792
2793 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08002794 answer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002795 EXPECT_EQ(std::string(cricket::kMediaProtocolDtlsSavpf),
2796 answer_audio_desc->protocol());
2797}
2798
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002799// Test that we include both SDES and DTLS in the offer, but only include SDES
2800// in the answer if DTLS isn't negotiated.
2801TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
2802 f1_.set_secure(SEC_ENABLED);
2803 f2_.set_secure(SEC_ENABLED);
2804 tdf1_.set_secure(SEC_ENABLED);
2805 tdf2_.set_secure(SEC_DISABLED);
2806 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002807 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08002808 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002809 const cricket::MediaContentDescription* audio_media_desc;
2810 const cricket::MediaContentDescription* video_media_desc;
2811 const cricket::TransportDescription* audio_trans_desc;
2812 const cricket::TransportDescription* video_trans_desc;
2813
2814 // Generate an offer with SDES and DTLS support.
2815 offer.reset(f1_.CreateOffer(options, NULL));
2816 ASSERT_TRUE(offer.get() != NULL);
2817
Steve Antonb1c1de12017-12-21 15:14:30 -08002818 audio_media_desc = offer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002819 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002820 video_media_desc = offer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002821 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
Steve Antonb1c1de12017-12-21 15:14:30 -08002836 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002837 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002838 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002839 ASSERT_TRUE(video_media_desc != NULL);
2840 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
2841 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2842
2843 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2844 ASSERT_TRUE(audio_trans_desc != NULL);
2845 video_trans_desc = answer->GetTransportDescriptionByName("video");
2846 ASSERT_TRUE(video_trans_desc != NULL);
2847 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
2848 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
2849
2850 // Enable DTLS; the answer should now only have DTLS support.
2851 tdf2_.set_secure(SEC_ENABLED);
2852 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2853 ASSERT_TRUE(answer.get() != NULL);
2854
Steve Antonb1c1de12017-12-21 15:14:30 -08002855 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002856 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002857 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002858 ASSERT_TRUE(video_media_desc != NULL);
2859 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2860 EXPECT_TRUE(video_media_desc->cryptos().empty());
2861 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2862 audio_media_desc->protocol());
2863 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2864 video_media_desc->protocol());
2865
2866 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2867 ASSERT_TRUE(audio_trans_desc != NULL);
2868 video_trans_desc = answer->GetTransportDescriptionByName("video");
2869 ASSERT_TRUE(video_trans_desc != NULL);
2870 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2871 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00002872
2873 // Try creating offer again. DTLS enabled now, crypto's should be empty
2874 // in new offer.
2875 offer.reset(f1_.CreateOffer(options, offer.get()));
2876 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002877 audio_media_desc = offer->GetContentDescriptionByName("audio");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00002878 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002879 video_media_desc = offer->GetContentDescriptionByName("video");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00002880 ASSERT_TRUE(video_media_desc != NULL);
2881 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2882 EXPECT_TRUE(video_media_desc->cryptos().empty());
2883
2884 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2885 ASSERT_TRUE(audio_trans_desc != NULL);
2886 video_trans_desc = offer->GetTransportDescriptionByName("video");
2887 ASSERT_TRUE(video_trans_desc != NULL);
2888 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2889 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002890}
2891
2892// Test that an answer can't be created if cryptos are required but the offer is
2893// unsecure.
2894TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07002895 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002896 f1_.set_secure(SEC_DISABLED);
2897 tdf1_.set_secure(SEC_DISABLED);
2898 f2_.set_secure(SEC_REQUIRED);
2899 tdf1_.set_secure(SEC_ENABLED);
2900
kwiberg31022942016-03-11 14:18:21 -08002901 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002902 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002903 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002904 f2_.CreateAnswer(offer.get(), options, NULL));
2905 EXPECT_TRUE(answer.get() == NULL);
2906}
2907
2908// Test that we accept a DTLS offer without SDES and create an appropriate
2909// answer.
2910TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
2911 f1_.set_secure(SEC_DISABLED);
2912 f2_.set_secure(SEC_ENABLED);
2913 tdf1_.set_secure(SEC_ENABLED);
2914 tdf2_.set_secure(SEC_ENABLED);
2915 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002916 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2917 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2918 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002919
kwiberg31022942016-03-11 14:18:21 -08002920 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002921
2922 // Generate an offer with DTLS but without SDES.
2923 offer.reset(f1_.CreateOffer(options, NULL));
2924 ASSERT_TRUE(offer.get() != NULL);
2925
2926 const AudioContentDescription* audio_offer =
2927 GetFirstAudioContentDescription(offer.get());
2928 ASSERT_TRUE(audio_offer->cryptos().empty());
2929 const VideoContentDescription* video_offer =
2930 GetFirstVideoContentDescription(offer.get());
2931 ASSERT_TRUE(video_offer->cryptos().empty());
2932 const DataContentDescription* data_offer =
2933 GetFirstDataContentDescription(offer.get());
2934 ASSERT_TRUE(data_offer->cryptos().empty());
2935
2936 const cricket::TransportDescription* audio_offer_trans_desc =
2937 offer->GetTransportDescriptionByName("audio");
2938 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
2939 const cricket::TransportDescription* video_offer_trans_desc =
2940 offer->GetTransportDescriptionByName("video");
2941 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
2942 const cricket::TransportDescription* data_offer_trans_desc =
2943 offer->GetTransportDescriptionByName("data");
2944 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
2945
2946 // Generate an answer with DTLS.
2947 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2948 ASSERT_TRUE(answer.get() != NULL);
2949
2950 const cricket::TransportDescription* audio_answer_trans_desc =
2951 answer->GetTransportDescriptionByName("audio");
2952 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
2953 const cricket::TransportDescription* video_answer_trans_desc =
2954 answer->GetTransportDescriptionByName("video");
2955 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
2956 const cricket::TransportDescription* data_answer_trans_desc =
2957 answer->GetTransportDescriptionByName("data");
2958 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
2959}
2960
2961// Verifies if vad_enabled option is set to false, CN codecs are not present in
2962// offer or answer.
2963TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
2964 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002965 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08002966 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002967 ASSERT_TRUE(offer.get() != NULL);
2968 const ContentInfo* audio_content = offer->GetContentByName("audio");
2969 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
2970
2971 options.vad_enabled = false;
2972 offer.reset(f1_.CreateOffer(options, NULL));
2973 ASSERT_TRUE(offer.get() != NULL);
2974 audio_content = offer->GetContentByName("audio");
2975 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
kwiberg31022942016-03-11 14:18:21 -08002976 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002977 f1_.CreateAnswer(offer.get(), options, NULL));
2978 ASSERT_TRUE(answer.get() != NULL);
2979 audio_content = answer->GetContentByName("audio");
2980 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
2981}
deadbeef44f08192015-12-15 16:20:09 -08002982
zhihuang1c378ed2017-08-17 14:10:50 -07002983// Test that the generated MIDs match the existing offer.
2984TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08002985 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002986 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_modified",
2987 RtpTransceiverDirection::kRecvOnly, kActive, &opts);
2988 AddMediaSection(MEDIA_TYPE_VIDEO, "video_modified",
2989 RtpTransceiverDirection::kRecvOnly, kActive, &opts);
deadbeef44f08192015-12-15 16:20:09 -08002990 opts.data_channel_type = cricket::DCT_SCTP;
Steve Anton4e70a722017-11-28 14:57:10 -08002991 AddMediaSection(MEDIA_TYPE_DATA, "data_modified",
2992 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002993 // Create offer.
kwiberg31022942016-03-11 14:18:21 -08002994 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
kwiberg31022942016-03-11 14:18:21 -08002995 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08002996 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07002997
deadbeef44f08192015-12-15 16:20:09 -08002998 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
2999 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3000 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3001 ASSERT_TRUE(audio_content != nullptr);
3002 ASSERT_TRUE(video_content != nullptr);
3003 ASSERT_TRUE(data_content != nullptr);
3004 EXPECT_EQ("audio_modified", audio_content->name);
3005 EXPECT_EQ("video_modified", video_content->name);
3006 EXPECT_EQ("data_modified", data_content->name);
3007}
zhihuangcf5b37c2016-05-05 11:44:35 -07003008
zhihuang1c378ed2017-08-17 14:10:50 -07003009// The following tests verify that the unified plan SDP is supported.
3010// Test that we can create an offer with multiple media sections of same media
3011// type.
3012TEST_F(MediaSessionDescriptionFactoryTest,
3013 CreateOfferWithMultipleAVMediaSections) {
3014 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003015 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_1",
3016 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003017 AttachSenderToMediaSection("audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003018 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003019
Steve Anton4e70a722017-11-28 14:57:10 -08003020 AddMediaSection(MEDIA_TYPE_VIDEO, "video_1",
3021 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003022 AttachSenderToMediaSection("video_1", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003023 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003024
Steve Anton4e70a722017-11-28 14:57:10 -08003025 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_2",
3026 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003027 AttachSenderToMediaSection("audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003028 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003029
Steve Anton4e70a722017-11-28 14:57:10 -08003030 AddMediaSection(MEDIA_TYPE_VIDEO, "video_2",
3031 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003032 AttachSenderToMediaSection("video_2", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003033 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003034 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3035 ASSERT_TRUE(offer);
3036
3037 ASSERT_EQ(4u, offer->contents().size());
3038 EXPECT_FALSE(offer->contents()[0].rejected);
3039 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003040 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003041 ASSERT_EQ(1u, acd->streams().size());
3042 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003043 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003044
3045 EXPECT_FALSE(offer->contents()[1].rejected);
3046 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003047 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003048 ASSERT_EQ(1u, vcd->streams().size());
3049 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003050 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003051
3052 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003053 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003054 ASSERT_EQ(1u, acd->streams().size());
3055 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003056 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003057
3058 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003059 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003060 ASSERT_EQ(1u, vcd->streams().size());
3061 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003062 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003063}
3064
3065// Test that we can create an answer with multiple media sections of same media
3066// type.
3067TEST_F(MediaSessionDescriptionFactoryTest,
3068 CreateAnswerWithMultipleAVMediaSections) {
3069 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003070 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_1",
3071 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003072 AttachSenderToMediaSection("audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003073 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003074
Steve Anton4e70a722017-11-28 14:57:10 -08003075 AddMediaSection(MEDIA_TYPE_VIDEO, "video_1",
3076 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003077 AttachSenderToMediaSection("video_1", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003078 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003079
Steve Anton4e70a722017-11-28 14:57:10 -08003080 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_2",
3081 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003082 AttachSenderToMediaSection("audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003083 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003084
Steve Anton4e70a722017-11-28 14:57:10 -08003085 AddMediaSection(MEDIA_TYPE_VIDEO, "video_2",
3086 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003087 AttachSenderToMediaSection("video_2", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003088 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003089
3090 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3091 ASSERT_TRUE(offer);
3092 std::unique_ptr<SessionDescription> answer(
3093 f2_.CreateAnswer(offer.get(), opts, nullptr));
3094
3095 ASSERT_EQ(4u, answer->contents().size());
3096 EXPECT_FALSE(answer->contents()[0].rejected);
3097 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003098 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003099 ASSERT_EQ(1u, acd->streams().size());
3100 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003101 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003102
3103 EXPECT_FALSE(answer->contents()[1].rejected);
3104 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003105 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003106 ASSERT_EQ(1u, vcd->streams().size());
3107 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003108 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003109
3110 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003111 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003112 ASSERT_EQ(1u, acd->streams().size());
3113 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003114 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003115
3116 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003117 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003118 ASSERT_EQ(1u, vcd->streams().size());
3119 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003120 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003121}
3122
3123// Test that the media section will be rejected in offer if the corresponding
3124// MediaDescriptionOptions is stopped by the offerer.
3125TEST_F(MediaSessionDescriptionFactoryTest,
3126 CreateOfferWithMediaSectionStoppedByOfferer) {
3127 // Create an offer with two audio sections and one of them is stopped.
3128 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003129 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3130 RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
3131 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3132 RtpTransceiverDirection::kInactive, kStopped, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003133 std::unique_ptr<SessionDescription> offer(
3134 f1_.CreateOffer(offer_opts, nullptr));
3135 ASSERT_TRUE(offer);
3136 ASSERT_EQ(2u, offer->contents().size());
3137 EXPECT_FALSE(offer->contents()[0].rejected);
3138 EXPECT_TRUE(offer->contents()[1].rejected);
3139}
3140
3141// Test that the media section will be rejected in answer if the corresponding
3142// MediaDescriptionOptions is stopped by the offerer.
3143TEST_F(MediaSessionDescriptionFactoryTest,
3144 CreateAnswerWithMediaSectionStoppedByOfferer) {
3145 // Create an offer with two audio sections and one of them is stopped.
3146 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003147 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3148 RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
3149 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3150 RtpTransceiverDirection::kInactive, kStopped, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003151 std::unique_ptr<SessionDescription> offer(
3152 f1_.CreateOffer(offer_opts, nullptr));
3153 ASSERT_TRUE(offer);
3154 ASSERT_EQ(2u, offer->contents().size());
3155 EXPECT_FALSE(offer->contents()[0].rejected);
3156 EXPECT_TRUE(offer->contents()[1].rejected);
3157
3158 // Create an answer based on the offer.
3159 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003160 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3161 RtpTransceiverDirection::kSendRecv, kActive, &answer_opts);
3162 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3163 RtpTransceiverDirection::kSendRecv, kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003164 std::unique_ptr<SessionDescription> answer(
3165 f2_.CreateAnswer(offer.get(), answer_opts, nullptr));
3166 ASSERT_EQ(2u, answer->contents().size());
3167 EXPECT_FALSE(answer->contents()[0].rejected);
3168 EXPECT_TRUE(answer->contents()[1].rejected);
3169}
3170
3171// Test that the media section will be rejected in answer if the corresponding
3172// MediaDescriptionOptions is stopped by the answerer.
3173TEST_F(MediaSessionDescriptionFactoryTest,
3174 CreateAnswerWithMediaSectionRejectedByAnswerer) {
3175 // Create an offer with two audio sections.
3176 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003177 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3178 RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
3179 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3180 RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003181 std::unique_ptr<SessionDescription> offer(
3182 f1_.CreateOffer(offer_opts, nullptr));
3183 ASSERT_TRUE(offer);
3184 ASSERT_EQ(2u, offer->contents().size());
3185 ASSERT_FALSE(offer->contents()[0].rejected);
3186 ASSERT_FALSE(offer->contents()[1].rejected);
3187
3188 // The answerer rejects one of the audio sections.
3189 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003190 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3191 RtpTransceiverDirection::kSendRecv, kActive, &answer_opts);
3192 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3193 RtpTransceiverDirection::kInactive, kStopped, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003194 std::unique_ptr<SessionDescription> answer(
3195 f2_.CreateAnswer(offer.get(), answer_opts, nullptr));
3196 ASSERT_EQ(2u, answer->contents().size());
3197 EXPECT_FALSE(answer->contents()[0].rejected);
3198 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08003199
3200 // The TransportInfo of the rejected m= section is expected to be added in the
3201 // answer.
3202 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07003203}
3204
3205// Test the generated media sections has the same order of the
3206// corresponding MediaDescriptionOptions.
3207TEST_F(MediaSessionDescriptionFactoryTest,
3208 CreateOfferRespectsMediaDescriptionOptionsOrder) {
3209 MediaSessionOptions opts;
3210 // This tests put video section first because normally audio comes first by
3211 // default.
Steve Anton4e70a722017-11-28 14:57:10 -08003212 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
3213 kActive, &opts);
3214 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kSendRecv,
3215 kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003216 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3217
3218 ASSERT_TRUE(offer);
3219 ASSERT_EQ(2u, offer->contents().size());
3220 EXPECT_EQ("video", offer->contents()[0].name);
3221 EXPECT_EQ("audio", offer->contents()[1].name);
3222}
3223
3224// Test that different media sections using the same codec have same payload
3225// type.
3226TEST_F(MediaSessionDescriptionFactoryTest,
3227 PayloadTypesSharedByMediaSectionsOfSameType) {
3228 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003229 AddMediaSection(MEDIA_TYPE_VIDEO, "video1",
3230 RtpTransceiverDirection::kSendRecv, kActive, &opts);
3231 AddMediaSection(MEDIA_TYPE_VIDEO, "video2",
3232 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003233 // Create an offer with two video sections using same codecs.
3234 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3235 ASSERT_TRUE(offer);
3236 ASSERT_EQ(2u, offer->contents().size());
3237 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003238 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003239 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003240 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003241 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3242 ASSERT_EQ(2u, vcd1->codecs().size());
3243 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3244 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3245 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
3246 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
3247
3248 // Create answer and negotiate the codecs.
3249 std::unique_ptr<SessionDescription> answer(
3250 f2_.CreateAnswer(offer.get(), opts, nullptr));
3251 ASSERT_TRUE(answer);
3252 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08003253 vcd1 = answer->contents()[0].media_description()->as_video();
3254 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003255 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3256 ASSERT_EQ(1u, vcd1->codecs().size());
3257 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3258 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3259}
3260
3261// Test that the codec preference order per media section is respected in
3262// subsequent offer.
3263TEST_F(MediaSessionDescriptionFactoryTest,
3264 CreateOfferRespectsCodecPreferenceOrder) {
3265 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003266 AddMediaSection(MEDIA_TYPE_VIDEO, "video1",
3267 RtpTransceiverDirection::kSendRecv, kActive, &opts);
3268 AddMediaSection(MEDIA_TYPE_VIDEO, "video2",
3269 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003270 // Create an offer with two video sections using same codecs.
3271 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3272 ASSERT_TRUE(offer);
3273 ASSERT_EQ(2u, offer->contents().size());
3274 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003275 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003276 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003277 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003278 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3279 EXPECT_EQ(video_codecs, vcd1->codecs());
3280 EXPECT_EQ(video_codecs, vcd2->codecs());
3281
3282 // Change the codec preference of the first video section and create a
3283 // follow-up offer.
3284 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3285 vcd1->set_codecs(video_codecs_reverse);
3286 std::unique_ptr<SessionDescription> updated_offer(
3287 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08003288 vcd1 = updated_offer->contents()[0].media_description()->as_video();
3289 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003290 // The video codec preference order should be respected.
3291 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3292 EXPECT_EQ(video_codecs, vcd2->codecs());
3293}
3294
3295// Test that the codec preference order per media section is respected in
3296// the answer.
3297TEST_F(MediaSessionDescriptionFactoryTest,
3298 CreateAnswerRespectsCodecPreferenceOrder) {
3299 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003300 AddMediaSection(MEDIA_TYPE_VIDEO, "video1",
3301 RtpTransceiverDirection::kSendRecv, kActive, &opts);
3302 AddMediaSection(MEDIA_TYPE_VIDEO, "video2",
3303 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003304 // Create an offer with two video sections using same codecs.
3305 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3306 ASSERT_TRUE(offer);
3307 ASSERT_EQ(2u, offer->contents().size());
3308 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003309 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003310 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003311 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003312 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3313 EXPECT_EQ(video_codecs, vcd1->codecs());
3314 EXPECT_EQ(video_codecs, vcd2->codecs());
3315
3316 // Change the codec preference of the first video section and create an
3317 // answer.
3318 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3319 vcd1->set_codecs(video_codecs_reverse);
3320 std::unique_ptr<SessionDescription> answer(
3321 f1_.CreateAnswer(offer.get(), opts, nullptr));
Steve Antonb1c1de12017-12-21 15:14:30 -08003322 vcd1 = answer->contents()[0].media_description()->as_video();
3323 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003324 // The video codec preference order should be respected.
3325 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3326 EXPECT_EQ(video_codecs, vcd2->codecs());
3327}
3328
Zhi Huang6f367472017-11-22 13:20:02 -08003329// Test that when creating an answer, the codecs use local parameters instead of
3330// the remote ones.
3331TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
3332 const std::string audio_param_name = "audio_param";
3333 const std::string audio_value1 = "audio_v1";
3334 const std::string audio_value2 = "audio_v2";
3335 const std::string video_param_name = "video_param";
3336 const std::string video_value1 = "video_v1";
3337 const std::string video_value2 = "video_v2";
3338
3339 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
3340 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
3341 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
3342 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
3343
3344 // Set the parameters for codecs.
3345 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
3346 video_codecs1[0].SetParam(video_param_name, video_value1);
3347 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
3348 video_codecs2[0].SetParam(video_param_name, video_value2);
3349
3350 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
3351 f1_.set_video_codecs(video_codecs1);
3352 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
3353 f2_.set_video_codecs(video_codecs2);
3354
3355 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003356 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kSendRecv,
3357 kActive, &opts);
3358 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
3359 kActive, &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08003360
3361 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3362 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08003363 auto offer_acd = offer->contents()[0].media_description()->as_audio();
3364 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08003365 std::string value;
3366 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
3367 EXPECT_EQ(audio_value1, value);
3368 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
3369 EXPECT_EQ(video_value1, value);
3370
3371 std::unique_ptr<SessionDescription> answer(
3372 f2_.CreateAnswer(offer.get(), opts, nullptr));
3373 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08003374 auto answer_acd = answer->contents()[0].media_description()->as_audio();
3375 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08003376 // Use the parameters from the local codecs.
3377 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
3378 EXPECT_EQ(audio_value2, value);
3379 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
3380 EXPECT_EQ(video_value2, value);
3381}
3382
zhihuangcf5b37c2016-05-05 11:44:35 -07003383class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
3384 public:
3385 MediaProtocolTest() : f1_(&tdf1_), f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -07003386 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
3387 MAKE_VECTOR(kAudioCodecs1));
zhihuangcf5b37c2016-05-05 11:44:35 -07003388 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
3389 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07003390 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
3391 MAKE_VECTOR(kAudioCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07003392 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
3393 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
3394 f1_.set_secure(SEC_ENABLED);
3395 f2_.set_secure(SEC_ENABLED);
3396 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07003397 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07003398 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07003399 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07003400 tdf1_.set_secure(SEC_ENABLED);
3401 tdf2_.set_secure(SEC_ENABLED);
3402 }
3403
3404 protected:
3405 MediaSessionDescriptionFactory f1_;
3406 MediaSessionDescriptionFactory f2_;
3407 TransportDescriptionFactory tdf1_;
3408 TransportDescriptionFactory tdf2_;
3409};
3410
3411TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
3412 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003413 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
zhihuangcf5b37c2016-05-05 11:44:35 -07003414 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3415 ASSERT_TRUE(offer.get() != nullptr);
3416 // Set the protocol for all the contents.
3417 for (auto content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08003418 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07003419 }
3420 std::unique_ptr<SessionDescription> answer(
3421 f2_.CreateAnswer(offer.get(), opts, nullptr));
3422 const ContentInfo* ac = answer->GetContentByName("audio");
3423 const ContentInfo* vc = answer->GetContentByName("video");
3424 ASSERT_TRUE(ac != nullptr);
3425 ASSERT_TRUE(vc != nullptr);
3426 EXPECT_FALSE(ac->rejected); // the offer is accepted
3427 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003428 const AudioContentDescription* acd = ac->media_description()->as_audio();
3429 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07003430 EXPECT_EQ(GetParam(), acd->protocol());
3431 EXPECT_EQ(GetParam(), vcd->protocol());
3432}
3433
3434INSTANTIATE_TEST_CASE_P(MediaProtocolPatternTest,
3435 MediaProtocolTest,
3436 ::testing::ValuesIn(kMediaProtocols));
3437INSTANTIATE_TEST_CASE_P(MediaProtocolDtlsPatternTest,
3438 MediaProtocolTest,
3439 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07003440
3441TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
3442 TransportDescriptionFactory tdf;
3443 MediaSessionDescriptionFactory sf(&tdf);
3444 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
3445 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
3446
3447 // The merged list of codecs should contain any send codecs that are also
3448 // nominally in the recieve codecs list. Payload types should be picked from
3449 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
3450 // (set to 1). This equals what happens when the send codecs are used in an
3451 // offer and the receive codecs are used in the following answer.
3452 const std::vector<AudioCodec> sendrecv_codecs =
3453 MAKE_VECTOR(kAudioCodecsAnswer);
3454 const std::vector<AudioCodec> no_codecs;
3455
3456 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
3457 << "Please don't change shared test data!";
3458 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
3459 << "Please don't change shared test data!";
3460 // Alter iLBC send codec to have zero channels, to test that that is handled
3461 // properly.
3462 send_codecs[1].channels = 0;
3463
3464 // Alther iLBC receive codec to be lowercase, to test that case conversions
3465 // are handled properly.
3466 recv_codecs[2].name = "ilbc";
3467
3468 // Test proper merge
3469 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003470 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
3471 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
3472 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003473
3474 // Test empty send codecs list
3475 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003476 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
3477 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
3478 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003479
3480 // Test empty recv codecs list
3481 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003482 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
3483 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
3484 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003485
3486 // Test all empty codec lists
3487 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003488 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
3489 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
3490 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003491}
3492
3493namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07003494// Compare the two vectors of codecs ignoring the payload type.
3495template <class Codec>
3496bool CodecsMatch(const std::vector<Codec>& codecs1,
3497 const std::vector<Codec>& codecs2) {
3498 if (codecs1.size() != codecs2.size()) {
3499 return false;
3500 }
3501
3502 for (size_t i = 0; i < codecs1.size(); ++i) {
3503 if (!codecs1[i].Matches(codecs2[i])) {
3504 return false;
3505 }
3506 }
3507 return true;
3508}
3509
Steve Anton4e70a722017-11-28 14:57:10 -08003510void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07003511 TransportDescriptionFactory tdf;
3512 MediaSessionDescriptionFactory sf(&tdf);
3513 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
3514 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
3515 const std::vector<AudioCodec> sendrecv_codecs =
3516 MAKE_VECTOR(kAudioCodecsAnswer);
3517 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07003518
3519 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003520 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", direction, kActive, &opts);
3521
Steve Anton4e70a722017-11-28 14:57:10 -08003522 if (direction == RtpTransceiverDirection::kSendRecv ||
3523 direction == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003524 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003525 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003526 }
ossu075af922016-06-14 03:29:38 -07003527
3528 std::unique_ptr<SessionDescription> offer(sf.CreateOffer(opts, NULL));
3529 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003530 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07003531
3532 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07003533 // that the codecs put in are right. This happens when we neither want to
3534 // send nor receive audio. The checks are still in place if at some point
3535 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07003536 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08003537 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003538 // sendrecv and inactive should both present lists as if the channel was
3539 // to be used for sending and receiving. Inactive essentially means it
3540 // might eventually be used anything, but we don't know more at this
3541 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08003542 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003543 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08003544 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003545 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07003546 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07003547 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07003548 }
3549 }
3550}
3551
3552static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07003553 AudioCodec(0, "codec0", 16000, -1, 1),
3554 AudioCodec(1, "codec1", 8000, 13300, 1),
3555 AudioCodec(2, "codec2", 8000, 64000, 1),
3556 AudioCodec(3, "codec3", 8000, 64000, 1),
3557 AudioCodec(4, "codec4", 8000, 0, 2),
3558 AudioCodec(5, "codec5", 32000, 0, 1),
3559 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07003560
zhihuang1c378ed2017-08-17 14:10:50 -07003561/* The codecs groups below are chosen as per the matrix below. The objective
3562 * is to have different sets of codecs in the inputs, to get unique sets of
3563 * codecs after negotiation, depending on offer and answer communication
3564 * directions. One-way directions in the offer should either result in the
3565 * opposite direction in the answer, or an inactive answer. Regardless, the
3566 * choice of codecs should be as if the answer contained the opposite
3567 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07003568 *
3569 * | Offer | Answer | Result
3570 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
3571 * 0 | x - - | - x - | x - - - -
3572 * 1 | x x x | - x - | x - - x -
3573 * 2 | - x - | x - - | - x - - -
3574 * 3 | x x x | x - - | - x x - -
3575 * 4 | - x - | x x x | - x - - -
3576 * 5 | x - - | x x x | x - - - -
3577 * 6 | x x x | x x x | x x x x x
3578 */
3579// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07003580static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
3581static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07003582// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
3583// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07003584static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
3585static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07003586// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07003587static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
3588static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
3589static const int kResultSendrecv_SendCodecs[] = {3, 6};
3590static const int kResultSendrecv_RecvCodecs[] = {1, 6};
3591static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07003592
3593template <typename T, int IDXS>
3594std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
3595 std::vector<T> out;
3596 out.reserve(IDXS);
3597 for (int idx : indices)
3598 out.push_back(array[idx]);
3599
3600 return out;
3601}
3602
Steve Anton4e70a722017-11-28 14:57:10 -08003603void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
3604 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07003605 bool add_legacy_stream) {
3606 TransportDescriptionFactory offer_tdf;
3607 TransportDescriptionFactory answer_tdf;
3608 MediaSessionDescriptionFactory offer_factory(&offer_tdf);
3609 MediaSessionDescriptionFactory answer_factory(&answer_tdf);
3610 offer_factory.set_audio_codecs(
3611 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
3612 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
3613 answer_factory.set_audio_codecs(
3614 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
3615 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
3616
ossu075af922016-06-14 03:29:38 -07003617 MediaSessionOptions offer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003618 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", offer_direction, kActive,
3619 &offer_opts);
3620
Steve Anton4e70a722017-11-28 14:57:10 -08003621 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
zhihuang1c378ed2017-08-17 14:10:50 -07003622 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003623 {kMediaStream1}, 1, &offer_opts);
ossu075af922016-06-14 03:29:38 -07003624 }
3625
3626 std::unique_ptr<SessionDescription> offer(
3627 offer_factory.CreateOffer(offer_opts, NULL));
3628 ASSERT_TRUE(offer.get() != NULL);
3629
3630 MediaSessionOptions answer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003631 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", answer_direction, kActive,
3632 &answer_opts);
3633
Steve Anton4e70a722017-11-28 14:57:10 -08003634 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
zhihuang1c378ed2017-08-17 14:10:50 -07003635 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003636 {kMediaStream1}, 1, &answer_opts);
ossu075af922016-06-14 03:29:38 -07003637 }
3638 std::unique_ptr<SessionDescription> answer(
3639 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL));
3640 const ContentInfo* ac = answer->GetContentByName("audio");
3641
zhihuang1c378ed2017-08-17 14:10:50 -07003642 // If the factory didn't add any audio content to the answer, we cannot
3643 // check that the codecs put in are right. This happens when we neither want
3644 // to send nor receive audio. The checks are still in place if at some point
3645 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07003646 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08003647 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
3648 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07003649
ossu075af922016-06-14 03:29:38 -07003650 std::vector<AudioCodec> target_codecs;
3651 // For offers with sendrecv or inactive, we should never reply with more
3652 // codecs than offered, with these codec sets.
3653 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08003654 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07003655 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
3656 kResultSendrecv_SendrecvCodecs);
3657 break;
Steve Anton4e70a722017-11-28 14:57:10 -08003658 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07003659 target_codecs =
3660 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07003661 break;
Steve Anton4e70a722017-11-28 14:57:10 -08003662 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07003663 target_codecs =
3664 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07003665 break;
Steve Anton4e70a722017-11-28 14:57:10 -08003666 case RtpTransceiverDirection::kSendRecv:
3667 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003668 target_codecs =
3669 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08003670 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003671 target_codecs =
3672 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07003673 } else {
3674 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
3675 kResultSendrecv_SendrecvCodecs);
3676 }
3677 break;
3678 }
3679
zhihuang1c378ed2017-08-17 14:10:50 -07003680 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
ossu075af922016-06-14 03:29:38 -07003681 std::stringstream os;
3682 bool first = true;
3683 os << "{";
3684 for (const auto& c : codecs) {
3685 os << (first ? " " : ", ") << c.id;
3686 first = false;
3687 }
3688 os << " }";
3689 return os.str();
3690 };
3691
3692 EXPECT_TRUE(acd->codecs() == target_codecs)
3693 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08003694 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
3695 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07003696 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08003697 << webrtc::RtpTransceiverDirectionToString(answer_direction)
3698 << "; got: "
3699 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07003700 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08003701 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07003702 << "Only inactive offers are allowed to not generate any audio "
3703 "content";
ossu075af922016-06-14 03:29:38 -07003704 }
3705}
brandtr03d5fb12016-11-22 03:37:59 -08003706
3707} // namespace
ossu075af922016-06-14 03:29:38 -07003708
3709class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08003710 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07003711
3712TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003713 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07003714}
3715
3716INSTANTIATE_TEST_CASE_P(MediaSessionDescriptionFactoryTest,
3717 AudioCodecsOfferTest,
Steve Anton4e70a722017-11-28 14:57:10 -08003718 ::testing::Values(RtpTransceiverDirection::kSendOnly,
3719 RtpTransceiverDirection::kRecvOnly,
3720 RtpTransceiverDirection::kSendRecv,
3721 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07003722
3723class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08003724 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
3725 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07003726 bool>> {};
ossu075af922016-06-14 03:29:38 -07003727
3728TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08003729 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
3730 ::testing::get<1>(GetParam()),
3731 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07003732}
3733
zhihuang1c378ed2017-08-17 14:10:50 -07003734INSTANTIATE_TEST_CASE_P(
3735 MediaSessionDescriptionFactoryTest,
3736 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08003737 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
3738 RtpTransceiverDirection::kRecvOnly,
3739 RtpTransceiverDirection::kSendRecv,
3740 RtpTransceiverDirection::kInactive),
3741 ::testing::Values(RtpTransceiverDirection::kSendOnly,
3742 RtpTransceiverDirection::kRecvOnly,
3743 RtpTransceiverDirection::kSendRecv,
3744 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07003745 ::testing::Bool()));