blob: acc18506f1c887f0e5d6d1f3c8f6f4bdb1b6f6ee [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[] = {
Henrik Lundinf8ed5612018-05-07 12:05:57 +020085 AudioCodec(126, "foo", 16000, 22000, 1),
deadbeef67cf2c12016-04-13 10:07:16 -070086 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
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700216// SRTP cipher name negotiated by the tests. This must be updated if the
217// default changes.
218static const char* kDefaultSrtpCryptoSuite = CS_AES_CM_128_HMAC_SHA1_80;
219static const char* kDefaultSrtpCryptoSuiteGcm = CS_AEAD_AES_256_GCM;
220
zhihuang1c378ed2017-08-17 14:10:50 -0700221// These constants are used to make the code using "AddMediaSection" more
222// readable.
223static constexpr bool kStopped = true;
224static constexpr bool kActive = false;
225
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000226static bool IsMediaContentOfType(const ContentInfo* content,
227 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800228 RTC_DCHECK(content);
229 return content->media_description()->type() == media_type;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000230}
231
Steve Anton4e70a722017-11-28 14:57:10 -0800232static RtpTransceiverDirection GetMediaDirection(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800233 RTC_DCHECK(content);
234 return content->media_description()->direction();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000235}
236
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000237static void AddRtxCodec(const VideoCodec& rtx_codec,
238 std::vector<VideoCodec>* codecs) {
magjedb05fa242016-11-11 04:00:16 -0800239 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000240 codecs->push_back(rtx_codec);
241}
242
243template <class T>
244static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
245 std::vector<std::string> codec_names;
246 for (const auto& codec : codecs) {
247 codec_names.push_back(codec.name);
248 }
249 return codec_names;
250}
251
zhihuang1c378ed2017-08-17 14:10:50 -0700252// This is used for test only. MIDs are not the identification of the
253// MediaDescriptionOptions since some end points may not support MID and the SDP
254// may not contain 'mid'.
255std::vector<MediaDescriptionOptions>::iterator FindFirstMediaDescriptionByMid(
256 const std::string& mid,
257 MediaSessionOptions* opts) {
258 return std::find_if(
259 opts->media_description_options.begin(),
260 opts->media_description_options.end(),
Steve Anton36b29d12017-10-30 09:57:42 -0700261 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
262}
263
264std::vector<MediaDescriptionOptions>::const_iterator
265FindFirstMediaDescriptionByMid(const std::string& mid,
266 const MediaSessionOptions& opts) {
267 return std::find_if(
268 opts.media_description_options.begin(),
269 opts.media_description_options.end(),
270 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
zhihuang1c378ed2017-08-17 14:10:50 -0700271}
272
273// Add a media section to the |session_options|.
274static void AddMediaSection(MediaType type,
275 const std::string& mid,
Steve Anton4e70a722017-11-28 14:57:10 -0800276 RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700277 bool stopped,
278 MediaSessionOptions* opts) {
Steve Anton4e70a722017-11-28 14:57:10 -0800279 opts->media_description_options.push_back(
280 MediaDescriptionOptions(type, mid, direction, stopped));
zhihuang1c378ed2017-08-17 14:10:50 -0700281}
282
Steve Anton4e70a722017-11-28 14:57:10 -0800283static void AddAudioVideoSections(RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700284 MediaSessionOptions* opts) {
285 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", direction, kActive, opts);
286 AddMediaSection(MEDIA_TYPE_VIDEO, "video", direction, kActive, opts);
287}
288
289static void AddDataSection(cricket::DataChannelType dct,
Steve Anton4e70a722017-11-28 14:57:10 -0800290 RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700291 MediaSessionOptions* opts) {
292 opts->data_channel_type = dct;
293 AddMediaSection(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
294}
295
Steve Anton8ffb9c32017-08-31 15:45:38 -0700296static void AttachSenderToMediaSection(
297 const std::string& mid,
298 MediaType type,
299 const std::string& track_id,
300 const std::vector<std::string>& stream_ids,
301 int num_sim_layer,
302 MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -0700303 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
304 switch (type) {
305 case MEDIA_TYPE_AUDIO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700306 it->AddAudioSender(track_id, stream_ids);
zhihuang1c378ed2017-08-17 14:10:50 -0700307 break;
308 case MEDIA_TYPE_VIDEO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700309 it->AddVideoSender(track_id, stream_ids, num_sim_layer);
zhihuang1c378ed2017-08-17 14:10:50 -0700310 break;
311 case MEDIA_TYPE_DATA:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700312 RTC_CHECK(stream_ids.size() == 1U);
313 it->AddRtpDataChannel(track_id, stream_ids[0]);
zhihuang1c378ed2017-08-17 14:10:50 -0700314 break;
315 default:
316 RTC_NOTREACHED();
317 }
318}
319
320static void DetachSenderFromMediaSection(const std::string& mid,
321 const std::string& track_id,
322 MediaSessionOptions* session_options) {
323 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
324 auto sender_it = it->sender_options.begin();
325 for (; sender_it != it->sender_options.end(); ++sender_it) {
326 if (sender_it->track_id == track_id) {
327 it->sender_options.erase(sender_it);
328 return;
329 }
330 }
331 RTC_NOTREACHED();
332}
333
334// Helper function used to create a default MediaSessionOptions for Plan B SDP.
335// (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
336static MediaSessionOptions CreatePlanBMediaSessionOptions() {
337 MediaSessionOptions session_options;
Steve Anton4e70a722017-11-28 14:57:10 -0800338 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
339 kActive, &session_options);
zhihuang1c378ed2017-08-17 14:10:50 -0700340 return session_options;
341}
342
343// TODO(zhihuang): Most of these tests were written while MediaSessionOptions
344// was designed for Plan B SDP, where only one audio "m=" section and one video
345// "m=" section could be generated, and ordering couldn't be controlled. Many of
346// these tests may be obsolete as a result, and should be refactored or removed.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000347class MediaSessionDescriptionFactoryTest : public testing::Test {
348 public:
zhihuang1c378ed2017-08-17 14:10:50 -0700349 MediaSessionDescriptionFactoryTest() : f1_(&tdf1_), f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -0700350 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
351 MAKE_VECTOR(kAudioCodecs1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000352 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
353 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700354 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
355 MAKE_VECTOR(kAudioCodecs2));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000356 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
357 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200358 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700359 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200360 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700361 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000362 }
363
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000364 // Create a video StreamParamsVec object with:
365 // - one video stream with 3 simulcast streams and FEC,
366 StreamParamsVec CreateComplexVideoStreamParamsVec() {
367 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
368 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
369 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
370 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
371
372 std::vector<SsrcGroup> ssrc_groups;
373 ssrc_groups.push_back(sim_group);
374 ssrc_groups.push_back(fec_group1);
375 ssrc_groups.push_back(fec_group2);
376 ssrc_groups.push_back(fec_group3);
377
378 StreamParams simulcast_params;
379 simulcast_params.id = kVideoTrack1;
380 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
381 simulcast_params.ssrc_groups = ssrc_groups;
382 simulcast_params.cname = "Video_SIM_FEC";
Seth Hampson845e8782018-03-02 11:34:10 -0800383 simulcast_params.set_stream_ids({kMediaStream1});
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000384
385 StreamParamsVec video_streams;
386 video_streams.push_back(simulcast_params);
387
388 return video_streams;
389 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000390
391 bool CompareCryptoParams(const CryptoParamsVec& c1,
392 const CryptoParamsVec& c2) {
393 if (c1.size() != c2.size())
394 return false;
395 for (size_t i = 0; i < c1.size(); ++i)
396 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
397 c1[i].key_params != c2[i].key_params ||
398 c1[i].session_params != c2[i].session_params)
399 return false;
400 return true;
401 }
402
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700403 // Returns true if the transport info contains "renomination" as an
404 // ICE option.
405 bool GetIceRenomination(const TransportInfo* transport_info) {
406 const std::vector<std::string>& ice_options =
407 transport_info->description.transport_options;
deadbeef30952b42017-04-21 02:41:29 -0700408 auto iter =
409 std::find(ice_options.begin(), ice_options.end(), "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700410 return iter != ice_options.end();
411 }
412
zhihuang1c378ed2017-08-17 14:10:50 -0700413 void TestTransportInfo(bool offer,
Steve Anton36b29d12017-10-30 09:57:42 -0700414 const MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000415 bool has_current_desc) {
416 const std::string current_audio_ufrag = "current_audio_ufrag";
417 const std::string current_audio_pwd = "current_audio_pwd";
418 const std::string current_video_ufrag = "current_video_ufrag";
419 const std::string current_video_pwd = "current_video_pwd";
420 const std::string current_data_ufrag = "current_data_ufrag";
421 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800422 std::unique_ptr<SessionDescription> current_desc;
423 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000424 if (has_current_desc) {
425 current_desc.reset(new SessionDescription());
426 EXPECT_TRUE(current_desc->AddTransportInfo(
427 TransportInfo("audio",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700428 TransportDescription(current_audio_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000429 current_audio_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000430 EXPECT_TRUE(current_desc->AddTransportInfo(
431 TransportInfo("video",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700432 TransportDescription(current_video_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000433 current_video_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000434 EXPECT_TRUE(current_desc->AddTransportInfo(
435 TransportInfo("data",
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700436 TransportDescription(current_data_ufrag,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000437 current_data_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000438 }
439 if (offer) {
440 desc.reset(f1_.CreateOffer(options, current_desc.get()));
441 } else {
kwiberg31022942016-03-11 14:18:21 -0800442 std::unique_ptr<SessionDescription> offer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000443 offer.reset(f1_.CreateOffer(options, NULL));
444 desc.reset(f1_.CreateAnswer(offer.get(), options, current_desc.get()));
445 }
446 ASSERT_TRUE(desc.get() != NULL);
447 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000448 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000449 EXPECT_TRUE(ti_audio != NULL);
450 if (has_current_desc) {
451 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
452 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
453 } else {
454 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
455 ti_audio->description.ice_ufrag.size());
456 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
457 ti_audio->description.ice_pwd.size());
458 }
zhihuang1c378ed2017-08-17 14:10:50 -0700459 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700460 FindFirstMediaDescriptionByMid("audio", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700461 EXPECT_EQ(
462 media_desc_options_it->transport_options.enable_ice_renomination,
463 GetIceRenomination(ti_audio));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000464
465 } else {
466 EXPECT_TRUE(ti_audio == NULL);
467 }
468 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000469 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000470 EXPECT_TRUE(ti_video != NULL);
471 if (options.bundle_enabled) {
472 EXPECT_EQ(ti_audio->description.ice_ufrag,
473 ti_video->description.ice_ufrag);
474 EXPECT_EQ(ti_audio->description.ice_pwd,
475 ti_video->description.ice_pwd);
476 } else {
477 if (has_current_desc) {
478 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
479 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
480 } else {
481 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
482 ti_video->description.ice_ufrag.size());
483 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
484 ti_video->description.ice_pwd.size());
485 }
486 }
zhihuang1c378ed2017-08-17 14:10:50 -0700487 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700488 FindFirstMediaDescriptionByMid("video", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700489 EXPECT_EQ(
490 media_desc_options_it->transport_options.enable_ice_renomination,
491 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000492 } else {
493 EXPECT_TRUE(ti_video == NULL);
494 }
495 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
496 if (options.has_data()) {
497 EXPECT_TRUE(ti_data != NULL);
498 if (options.bundle_enabled) {
499 EXPECT_EQ(ti_audio->description.ice_ufrag,
500 ti_data->description.ice_ufrag);
501 EXPECT_EQ(ti_audio->description.ice_pwd,
502 ti_data->description.ice_pwd);
503 } else {
504 if (has_current_desc) {
505 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
506 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
507 } else {
508 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
509 ti_data->description.ice_ufrag.size());
510 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
511 ti_data->description.ice_pwd.size());
512 }
513 }
zhihuang1c378ed2017-08-17 14:10:50 -0700514 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700515 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700516 EXPECT_EQ(
517 media_desc_options_it->transport_options.enable_ice_renomination,
518 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700519
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000520 } else {
521 EXPECT_TRUE(ti_video == NULL);
522 }
523 }
524
525 void TestCryptoWithBundle(bool offer) {
526 f1_.set_secure(SEC_ENABLED);
527 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -0800528 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
529 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
530 &options);
kwiberg31022942016-03-11 14:18:21 -0800531 std::unique_ptr<SessionDescription> ref_desc;
532 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000533 if (offer) {
534 options.bundle_enabled = false;
535 ref_desc.reset(f1_.CreateOffer(options, NULL));
536 options.bundle_enabled = true;
537 desc.reset(f1_.CreateOffer(options, ref_desc.get()));
538 } else {
539 options.bundle_enabled = true;
540 ref_desc.reset(f1_.CreateOffer(options, NULL));
541 desc.reset(f1_.CreateAnswer(ref_desc.get(), options, NULL));
542 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800543 ASSERT_TRUE(desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000544 const cricket::MediaContentDescription* audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800545 desc->GetContentDescriptionByName("audio");
546 ASSERT_TRUE(audio_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000547 const cricket::MediaContentDescription* video_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800548 desc->GetContentDescriptionByName("video");
549 ASSERT_TRUE(video_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000550 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
551 video_media_desc->cryptos()));
552 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700553 EXPECT_EQ(std::string(kDefaultSrtpCryptoSuite),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000554 audio_media_desc->cryptos()[0].cipher_suite);
555
556 // Verify the selected crypto is one from the reference audio
557 // media content.
558 const cricket::MediaContentDescription* ref_audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800559 ref_desc->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000560 bool found = false;
561 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
562 if (ref_audio_media_desc->cryptos()[i].Matches(
563 audio_media_desc->cryptos()[0])) {
564 found = true;
565 break;
566 }
567 }
568 EXPECT_TRUE(found);
569 }
570
571 // This test that the audio and video media direction is set to
572 // |expected_direction_in_answer| in an answer if the offer direction is set
zhihuang1c378ed2017-08-17 14:10:50 -0700573 // to |direction_in_offer| and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000574 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800575 RtpTransceiverDirection direction_in_offer,
576 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700577 MediaSessionOptions offer_opts;
578 AddAudioVideoSections(direction_in_offer, &offer_opts);
579
580 std::unique_ptr<SessionDescription> offer(
581 f1_.CreateOffer(offer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000582 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700583 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000584 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700585 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000586 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000587
zhihuang1c378ed2017-08-17 14:10:50 -0700588 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800589 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -0800590 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -0700591 f2_.CreateAnswer(offer.get(), answer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000592 const AudioContentDescription* acd_answer =
593 GetFirstAudioContentDescription(answer.get());
594 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
595 const VideoContentDescription* vcd_answer =
596 GetFirstVideoContentDescription(answer.get());
597 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
598 }
599
600 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800601 RTC_DCHECK(content);
602 RTC_CHECK(content->media_description());
603 const cricket::AudioContentDescription* audio_desc =
604 content->media_description()->as_audio();
605 RTC_CHECK(audio_desc);
606 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
607 if (codec.name == "CN") {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000608 return false;
Steve Antonb1c1de12017-12-21 15:14:30 -0800609 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000610 }
611 return true;
612 }
613
jbauchcb560652016-08-04 05:20:32 -0700614 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
615 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800616 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
jbauchcb560652016-08-04 05:20:32 -0700617 offer_opts.crypto_options.enable_gcm_crypto_suites = gcm_offer;
zhihuang1c378ed2017-08-17 14:10:50 -0700618
jbauchcb560652016-08-04 05:20:32 -0700619 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800620 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
jbauchcb560652016-08-04 05:20:32 -0700621 answer_opts.crypto_options.enable_gcm_crypto_suites = gcm_answer;
zhihuang1c378ed2017-08-17 14:10:50 -0700622
jbauchcb560652016-08-04 05:20:32 -0700623 f1_.set_secure(SEC_ENABLED);
624 f2_.set_secure(SEC_ENABLED);
625 std::unique_ptr<SessionDescription> offer(
626 f1_.CreateOffer(offer_opts, NULL));
627 ASSERT_TRUE(offer.get() != NULL);
628 std::unique_ptr<SessionDescription> answer(
629 f2_.CreateAnswer(offer.get(), answer_opts, NULL));
630 const ContentInfo* ac = answer->GetContentByName("audio");
631 const ContentInfo* vc = answer->GetContentByName("video");
632 ASSERT_TRUE(ac != NULL);
633 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800634 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
635 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800636 const AudioContentDescription* acd = ac->media_description()->as_audio();
637 const VideoContentDescription* vcd = vc->media_description()->as_video();
jbauchcb560652016-08-04 05:20:32 -0700638 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
639 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
640 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700641 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700642 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
643 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700644 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700645 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700646 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700647 }
648 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
649 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700650 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700651 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
652 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700653 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700654 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700655 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700656 }
657 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
658 }
659
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000660 protected:
661 MediaSessionDescriptionFactory f1_;
662 MediaSessionDescriptionFactory f2_;
663 TransportDescriptionFactory tdf1_;
664 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000665};
666
667// Create a typical audio offer, and ensure it matches what we expect.
668TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
669 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800670 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -0700671 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000672 ASSERT_TRUE(offer.get() != NULL);
673 const ContentInfo* ac = offer->GetContentByName("audio");
674 const ContentInfo* vc = offer->GetContentByName("video");
675 ASSERT_TRUE(ac != NULL);
676 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800677 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800678 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000679 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700680 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700681 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000682 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
683 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700684 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000685 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
686}
687
688// Create a typical video offer, and ensure it matches what we expect.
689TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
690 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800691 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000692 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800693 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000694 ASSERT_TRUE(offer.get() != NULL);
695 const ContentInfo* ac = offer->GetContentByName("audio");
696 const ContentInfo* vc = offer->GetContentByName("video");
697 ASSERT_TRUE(ac != NULL);
698 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800699 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
700 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800701 const AudioContentDescription* acd = ac->media_description()->as_audio();
702 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000703 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700704 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700705 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000706 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
707 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700708 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000709 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
710 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
711 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700712 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000713 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
714 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700715 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000716 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
717}
718
719// Test creating an offer with bundle where the Codecs have the same dynamic
720// RTP playlod type. The test verifies that the offer don't contain the
721// duplicate RTP payload types.
722TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
723 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700724 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000725 const DataCodec& offered_data_codec = f2_.data_codecs()[0];
726 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
727 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
728
729 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800730 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
731 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000732 opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800733 std::unique_ptr<SessionDescription> offer(f2_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000734 const VideoContentDescription* vcd =
735 GetFirstVideoContentDescription(offer.get());
736 const AudioContentDescription* acd =
737 GetFirstAudioContentDescription(offer.get());
738 const DataContentDescription* dcd =
739 GetFirstDataContentDescription(offer.get());
740 ASSERT_TRUE(NULL != vcd);
741 ASSERT_TRUE(NULL != acd);
742 ASSERT_TRUE(NULL != dcd);
743 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
744 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
745 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
746 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
747 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
748 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
749}
750
zhihuang1c378ed2017-08-17 14:10:50 -0700751// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000752// after an audio only session has been negotiated.
753TEST_F(MediaSessionDescriptionFactoryTest,
754 TestCreateUpdatedVideoOfferWithBundle) {
755 f1_.set_secure(SEC_ENABLED);
756 f2_.set_secure(SEC_ENABLED);
757 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800758 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
759 kActive, &opts);
760 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kInactive,
761 kStopped, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000762 opts.data_channel_type = cricket::DCT_NONE;
763 opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800764 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
765 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000766 f2_.CreateAnswer(offer.get(), opts, NULL));
767
768 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800769 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
770 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
771 &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000772 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800773 std::unique_ptr<SessionDescription> updated_offer(
774 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000775
776 const AudioContentDescription* acd =
777 GetFirstAudioContentDescription(updated_offer.get());
778 const VideoContentDescription* vcd =
779 GetFirstVideoContentDescription(updated_offer.get());
780 const DataContentDescription* dcd =
781 GetFirstDataContentDescription(updated_offer.get());
782 EXPECT_TRUE(NULL != vcd);
783 EXPECT_TRUE(NULL != acd);
784 EXPECT_TRUE(NULL != dcd);
785
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700786 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000787 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700788 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000789 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700790 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000791 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
792}
deadbeef44f08192015-12-15 16:20:09 -0800793
wu@webrtc.org78187522013-10-07 23:32:02 +0000794// Create a RTP data offer, and ensure it matches what we expect.
795TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000796 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800797 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
798 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000799 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800800 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000801 ASSERT_TRUE(offer.get() != NULL);
802 const ContentInfo* ac = offer->GetContentByName("audio");
803 const ContentInfo* dc = offer->GetContentByName("data");
804 ASSERT_TRUE(ac != NULL);
805 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800806 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
807 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800808 const AudioContentDescription* acd = ac->media_description()->as_audio();
809 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000810 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700811 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700812 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000813 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
814 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700815 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000816 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
817 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
818 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700819 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000820 EXPECT_EQ(cricket::kDataMaxBandwidth,
821 dcd->bandwidth()); // default bandwidth (auto)
822 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700823 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000824 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
825}
826
wu@webrtc.org78187522013-10-07 23:32:02 +0000827// Create an SCTP data offer with bundle without error.
828TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
829 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000830 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800831 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
wu@webrtc.org78187522013-10-07 23:32:02 +0000832 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800833 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
wu@webrtc.org78187522013-10-07 23:32:02 +0000834 EXPECT_TRUE(offer.get() != NULL);
835 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
836}
837
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000838// Test creating an sctp data channel from an already generated offer.
839TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
840 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000841 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800842 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000843 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800844 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000845 ASSERT_TRUE(offer1.get() != NULL);
846 const ContentInfo* data = offer1->GetContentByName("data");
847 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800848 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000849
850 // Now set data_channel_type to 'none' (default) and make sure that the
851 // datachannel type that gets generated from the previous offer, is of the
852 // same type.
853 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800854 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000855 f1_.CreateOffer(opts, offer1.get()));
856 data = offer2->GetContentByName("data");
857 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800858 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000859}
860
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000861// Create an audio, video offer without legacy StreamParams.
862TEST_F(MediaSessionDescriptionFactoryTest,
863 TestCreateOfferWithoutLegacyStreams) {
864 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800865 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
kwiberg31022942016-03-11 14:18:21 -0800866 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000867 ASSERT_TRUE(offer.get() != NULL);
868 const ContentInfo* ac = offer->GetContentByName("audio");
869 const ContentInfo* vc = offer->GetContentByName("video");
870 ASSERT_TRUE(ac != NULL);
871 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800872 const AudioContentDescription* acd = ac->media_description()->as_audio();
873 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000874
875 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
876 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
877}
878
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000879// Creates an audio+video sendonly offer.
880TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700881 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800882 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700883 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700884 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700885 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700886 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000887
zhihuang1c378ed2017-08-17 14:10:50 -0700888 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000889 ASSERT_TRUE(offer.get() != NULL);
890 EXPECT_EQ(2u, offer->contents().size());
891 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
892 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
893
Steve Anton4e70a722017-11-28 14:57:10 -0800894 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
895 GetMediaDirection(&offer->contents()[0]));
896 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
897 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000898}
899
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000900// Verifies that the order of the media contents in the current
901// SessionDescription is preserved in the new SessionDescription.
902TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
903 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800904 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000905
kwiberg31022942016-03-11 14:18:21 -0800906 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000907 ASSERT_TRUE(offer1.get() != NULL);
908 EXPECT_EQ(1u, offer1->contents().size());
909 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
910
Steve Anton4e70a722017-11-28 14:57:10 -0800911 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
912 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -0800913 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000914 f1_.CreateOffer(opts, offer1.get()));
915 ASSERT_TRUE(offer2.get() != NULL);
916 EXPECT_EQ(2u, offer2->contents().size());
917 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
918 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
919
Steve Anton4e70a722017-11-28 14:57:10 -0800920 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
921 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -0800922 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000923 f1_.CreateOffer(opts, offer2.get()));
924 ASSERT_TRUE(offer3.get() != NULL);
925 EXPECT_EQ(3u, offer3->contents().size());
926 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
927 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
928 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000929}
930
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000931// Create a typical audio answer, and ensure it matches what we expect.
932TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
933 f1_.set_secure(SEC_ENABLED);
934 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800935 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -0700936 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000937 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800938 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -0700939 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000940 const ContentInfo* ac = answer->GetContentByName("audio");
941 const ContentInfo* vc = answer->GetContentByName("video");
942 ASSERT_TRUE(ac != NULL);
943 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800944 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800945 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000946 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
947 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700948 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000949 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
950 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700951 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000952 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
953}
954
jbauchcb560652016-08-04 05:20:32 -0700955// Create a typical audio answer with GCM ciphers enabled, and ensure it
956// matches what we expect.
957TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
958 f1_.set_secure(SEC_ENABLED);
959 f2_.set_secure(SEC_ENABLED);
zhihuang1c378ed2017-08-17 14:10:50 -0700960 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
961 opts.crypto_options.enable_gcm_crypto_suites = true;
962 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
jbauchcb560652016-08-04 05:20:32 -0700963 ASSERT_TRUE(offer.get() != NULL);
964 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -0700965 f2_.CreateAnswer(offer.get(), opts, NULL));
jbauchcb560652016-08-04 05:20:32 -0700966 const ContentInfo* ac = answer->GetContentByName("audio");
967 const ContentInfo* vc = answer->GetContentByName("video");
968 ASSERT_TRUE(ac != NULL);
969 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800970 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800971 const AudioContentDescription* acd = ac->media_description()->as_audio();
jbauchcb560652016-08-04 05:20:32 -0700972 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
973 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700974 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700975 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
976 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700977 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700978 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), acd->protocol());
979}
980
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000981// Create a typical video answer, and ensure it matches what we expect.
982TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
983 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800984 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000985 f1_.set_secure(SEC_ENABLED);
986 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800987 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000988 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800989 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000990 f2_.CreateAnswer(offer.get(), opts, NULL));
991 const ContentInfo* ac = answer->GetContentByName("audio");
992 const ContentInfo* vc = answer->GetContentByName("video");
993 ASSERT_TRUE(ac != NULL);
994 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800995 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
996 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800997 const AudioContentDescription* acd = ac->media_description()->as_audio();
998 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000999 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1000 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1001 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001002 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001003 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001004 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001005 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1006 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -07001007 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001008 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001009 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001010 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), vcd->protocol());
1011}
1012
jbauchcb560652016-08-04 05:20:32 -07001013// Create a typical video answer with GCM ciphers enabled, and ensure it
1014// matches what we expect.
1015TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1016 TestVideoGcmCipher(true, true);
1017}
1018
1019// Create a typical video answer with GCM ciphers enabled for the offer only,
1020// and ensure it matches what we expect.
1021TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1022 TestVideoGcmCipher(true, false);
1023}
1024
1025// Create a typical video answer with GCM ciphers enabled for the answer only,
1026// and ensure it matches what we expect.
1027TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1028 TestVideoGcmCipher(false, true);
1029}
1030
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001031TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001032 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001033 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001034 f1_.set_secure(SEC_ENABLED);
1035 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001036 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001037 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001038 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001039 f2_.CreateAnswer(offer.get(), opts, NULL));
1040 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001041 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001042 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001043 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001044 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1045 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001046 const AudioContentDescription* acd = ac->media_description()->as_audio();
1047 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001048 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1049 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1050 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001051 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001052 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001053 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
zstein4b2e0822017-02-17 19:48:38 -08001054 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1055 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -07001056 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001057 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001058 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
zstein4b2e0822017-02-17 19:48:38 -08001059 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001060}
1061
jbauchcb560652016-08-04 05:20:32 -07001062TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
zhihuang1c378ed2017-08-17 14:10:50 -07001063 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001064 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
jbauchcb560652016-08-04 05:20:32 -07001065 opts.crypto_options.enable_gcm_crypto_suites = true;
1066 f1_.set_secure(SEC_ENABLED);
1067 f2_.set_secure(SEC_ENABLED);
1068 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1069 ASSERT_TRUE(offer.get() != NULL);
1070 std::unique_ptr<SessionDescription> answer(
1071 f2_.CreateAnswer(offer.get(), opts, NULL));
1072 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001073 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -07001074 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001075 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001076 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1077 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001078 const AudioContentDescription* acd = ac->media_description()->as_audio();
1079 const DataContentDescription* dcd = dc->media_description()->as_data();
jbauchcb560652016-08-04 05:20:32 -07001080 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1081 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1082 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001083 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001084 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001085 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
zstein4b2e0822017-02-17 19:48:38 -08001086 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1087 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -07001088 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001089 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001090 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuiteGcm);
zstein4b2e0822017-02-17 19:48:38 -08001091 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf), dcd->protocol());
1092}
1093
1094// The use_sctpmap flag should be set in a DataContentDescription by default.
1095// The answer's use_sctpmap flag should match the offer's.
1096TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1097 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001098 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
zstein4b2e0822017-02-17 19:48:38 -08001099 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1100 ASSERT_TRUE(offer.get() != NULL);
1101 ContentInfo* dc_offer = offer->GetContentByName("data");
1102 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001103 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001104 EXPECT_TRUE(dcd_offer->use_sctpmap());
1105
1106 std::unique_ptr<SessionDescription> answer(
1107 f2_.CreateAnswer(offer.get(), opts, NULL));
1108 const ContentInfo* dc_answer = answer->GetContentByName("data");
1109 ASSERT_TRUE(dc_answer != NULL);
1110 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001111 dc_answer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001112 EXPECT_TRUE(dcd_answer->use_sctpmap());
1113}
1114
1115// The answer's use_sctpmap flag should match the offer's.
1116TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1117 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001118 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
zstein4b2e0822017-02-17 19:48:38 -08001119 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1120 ASSERT_TRUE(offer.get() != NULL);
1121 ContentInfo* dc_offer = offer->GetContentByName("data");
1122 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001123 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001124 dcd_offer->set_use_sctpmap(false);
1125
1126 std::unique_ptr<SessionDescription> answer(
1127 f2_.CreateAnswer(offer.get(), opts, NULL));
1128 const ContentInfo* dc_answer = answer->GetContentByName("data");
1129 ASSERT_TRUE(dc_answer != NULL);
1130 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001131 dc_answer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001132 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001133}
1134
deadbeef8b7e9ad2017-05-25 09:38:55 -07001135// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1136// and "TCP/DTLS/SCTP" offers.
1137TEST_F(MediaSessionDescriptionFactoryTest,
1138 TestCreateDataAnswerToDifferentOfferedProtos) {
1139 // Need to enable DTLS offer/answer generation (disabled by default in this
1140 // test).
1141 f1_.set_secure(SEC_ENABLED);
1142 f2_.set_secure(SEC_ENABLED);
1143 tdf1_.set_secure(SEC_ENABLED);
1144 tdf2_.set_secure(SEC_ENABLED);
1145
1146 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001147 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001148 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
1149 ASSERT_TRUE(offer.get() != nullptr);
1150 ContentInfo* dc_offer = offer->GetContentByName("data");
1151 ASSERT_TRUE(dc_offer != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08001152 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001153
1154 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1155 "TCP/DTLS/SCTP"};
1156 for (const std::string& proto : protos) {
1157 dcd_offer->set_protocol(proto);
1158 std::unique_ptr<SessionDescription> answer(
1159 f2_.CreateAnswer(offer.get(), opts, nullptr));
1160 const ContentInfo* dc_answer = answer->GetContentByName("data");
1161 ASSERT_TRUE(dc_answer != nullptr);
1162 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001163 dc_answer->media_description()->as_data();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001164 EXPECT_FALSE(dc_answer->rejected);
1165 EXPECT_EQ(proto, dcd_answer->protocol());
1166 }
1167}
1168
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001169// Verifies that the order of the media contents in the offer is preserved in
1170// the answer.
1171TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1172 MediaSessionOptions opts;
1173
1174 // Creates a data only offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001175 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001176 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001177 ASSERT_TRUE(offer1.get() != NULL);
1178
1179 // Appends audio to the offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001180 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
1181 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -08001182 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001183 f1_.CreateOffer(opts, offer1.get()));
1184 ASSERT_TRUE(offer2.get() != NULL);
1185
1186 // Appends video to the offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001187 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
1188 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -08001189 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001190 f1_.CreateOffer(opts, offer2.get()));
1191 ASSERT_TRUE(offer3.get() != NULL);
1192
kwiberg31022942016-03-11 14:18:21 -08001193 std::unique_ptr<SessionDescription> answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001194 f2_.CreateAnswer(offer3.get(), opts, NULL));
1195 ASSERT_TRUE(answer.get() != NULL);
1196 EXPECT_EQ(3u, answer->contents().size());
1197 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1198 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1199 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1200}
1201
ossu075af922016-06-14 03:29:38 -07001202// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1203// answerer settings.
1204
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001205// This test that the media direction is set to send/receive in an answer if
1206// the offer is send receive.
1207TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001208 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1209 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001210}
1211
1212// This test that the media direction is set to receive only in an answer if
1213// the offer is send only.
1214TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001215 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1216 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001217}
1218
1219// This test that the media direction is set to send only in an answer if
1220// the offer is recv only.
1221TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001222 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1223 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001224}
1225
1226// This test that the media direction is set to inactive in an answer if
1227// the offer is inactive.
1228TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001229 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1230 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001231}
1232
1233// Test that a data content with an unknown protocol is rejected in an answer.
1234TEST_F(MediaSessionDescriptionFactoryTest,
1235 CreateDataAnswerToOfferWithUnknownProtocol) {
1236 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001237 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001238 f1_.set_secure(SEC_ENABLED);
1239 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001240 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
terelius8c011e52016-04-26 05:28:11 -07001241 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001242 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001243 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001244 ASSERT_TRUE(dcd_offer != NULL);
1245 std::string protocol = "a weird unknown protocol";
1246 dcd_offer->set_protocol(protocol);
1247
kwiberg31022942016-03-11 14:18:21 -08001248 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001249 f2_.CreateAnswer(offer.get(), opts, NULL));
1250
1251 const ContentInfo* dc_answer = answer->GetContentByName("data");
1252 ASSERT_TRUE(dc_answer != NULL);
1253 EXPECT_TRUE(dc_answer->rejected);
1254 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001255 dc_answer->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001256 ASSERT_TRUE(dcd_answer != NULL);
1257 EXPECT_EQ(protocol, dcd_answer->protocol());
1258}
1259
1260// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1261TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001262 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001263 f1_.set_secure(SEC_DISABLED);
1264 f2_.set_secure(SEC_DISABLED);
1265 tdf1_.set_secure(SEC_DISABLED);
1266 tdf2_.set_secure(SEC_DISABLED);
1267
kwiberg31022942016-03-11 14:18:21 -08001268 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001269 const AudioContentDescription* offer_acd =
1270 GetFirstAudioContentDescription(offer.get());
1271 ASSERT_TRUE(offer_acd != NULL);
1272 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), offer_acd->protocol());
1273
kwiberg31022942016-03-11 14:18:21 -08001274 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001275 f2_.CreateAnswer(offer.get(), opts, NULL));
1276
1277 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1278 ASSERT_TRUE(ac_answer != NULL);
1279 EXPECT_FALSE(ac_answer->rejected);
1280
1281 const AudioContentDescription* answer_acd =
1282 GetFirstAudioContentDescription(answer.get());
1283 ASSERT_TRUE(answer_acd != NULL);
1284 EXPECT_EQ(std::string(cricket::kMediaProtocolAvpf), answer_acd->protocol());
1285}
1286
1287// Create a video offer and answer and ensure the RTP header extensions
1288// matches what we expect.
1289TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1290 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001291 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001292 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1293 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1294 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1295 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1296
kwiberg31022942016-03-11 14:18:21 -08001297 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001298 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001299 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001300 f2_.CreateAnswer(offer.get(), opts, NULL));
1301
1302 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension1),
1303 GetFirstAudioContentDescription(
1304 offer.get())->rtp_header_extensions());
1305 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtension1),
1306 GetFirstVideoContentDescription(
1307 offer.get())->rtp_header_extensions());
1308 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
1309 GetFirstAudioContentDescription(
1310 answer.get())->rtp_header_extensions());
1311 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
1312 GetFirstVideoContentDescription(
1313 answer.get())->rtp_header_extensions());
1314}
1315
jbauch5869f502017-06-29 12:31:36 -07001316TEST_F(MediaSessionDescriptionFactoryTest,
1317 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
1318 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001319 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001320
1321 f1_.set_enable_encrypted_rtp_header_extensions(true);
1322 f2_.set_enable_encrypted_rtp_header_extensions(true);
1323
1324 f1_.set_audio_rtp_header_extensions(
1325 MAKE_VECTOR(kAudioRtpExtension1));
1326 f1_.set_video_rtp_header_extensions(
1327 MAKE_VECTOR(kVideoRtpExtension1));
1328 f2_.set_audio_rtp_header_extensions(
1329 MAKE_VECTOR(kAudioRtpExtension2));
1330 f2_.set_video_rtp_header_extensions(
1331 MAKE_VECTOR(kVideoRtpExtension2));
1332
1333 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1334 ASSERT_TRUE(offer.get() != NULL);
1335 std::unique_ptr<SessionDescription> answer(
1336 f2_.CreateAnswer(offer.get(), opts, NULL));
1337
1338 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1339 GetFirstAudioContentDescription(
1340 offer.get())->rtp_header_extensions());
1341 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1342 GetFirstVideoContentDescription(
1343 offer.get())->rtp_header_extensions());
1344 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
1345 GetFirstAudioContentDescription(
1346 answer.get())->rtp_header_extensions());
1347 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
1348 GetFirstVideoContentDescription(
1349 answer.get())->rtp_header_extensions());
1350}
1351
1352TEST_F(MediaSessionDescriptionFactoryTest,
1353 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
1354 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001355 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001356
1357 f1_.set_enable_encrypted_rtp_header_extensions(true);
1358
1359 f1_.set_audio_rtp_header_extensions(
1360 MAKE_VECTOR(kAudioRtpExtension1));
1361 f1_.set_video_rtp_header_extensions(
1362 MAKE_VECTOR(kVideoRtpExtension1));
1363 f2_.set_audio_rtp_header_extensions(
1364 MAKE_VECTOR(kAudioRtpExtension2));
1365 f2_.set_video_rtp_header_extensions(
1366 MAKE_VECTOR(kVideoRtpExtension2));
1367
1368 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1369 ASSERT_TRUE(offer.get() != NULL);
1370 std::unique_ptr<SessionDescription> answer(
1371 f2_.CreateAnswer(offer.get(), opts, NULL));
1372
1373 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1374 GetFirstAudioContentDescription(
1375 offer.get())->rtp_header_extensions());
1376 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1377 GetFirstVideoContentDescription(
1378 offer.get())->rtp_header_extensions());
1379 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
1380 GetFirstAudioContentDescription(
1381 answer.get())->rtp_header_extensions());
1382 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
1383 GetFirstVideoContentDescription(
1384 answer.get())->rtp_header_extensions());
1385}
1386
1387TEST_F(MediaSessionDescriptionFactoryTest,
1388 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
1389 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001390 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001391
1392 f2_.set_enable_encrypted_rtp_header_extensions(true);
1393
1394 f1_.set_audio_rtp_header_extensions(
1395 MAKE_VECTOR(kAudioRtpExtension1));
1396 f1_.set_video_rtp_header_extensions(
1397 MAKE_VECTOR(kVideoRtpExtension1));
1398 f2_.set_audio_rtp_header_extensions(
1399 MAKE_VECTOR(kAudioRtpExtension2));
1400 f2_.set_video_rtp_header_extensions(
1401 MAKE_VECTOR(kVideoRtpExtension2));
1402
1403 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1404 ASSERT_TRUE(offer.get() != NULL);
1405 std::unique_ptr<SessionDescription> answer(
1406 f2_.CreateAnswer(offer.get(), opts, NULL));
1407
1408 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension1),
1409 GetFirstAudioContentDescription(
1410 offer.get())->rtp_header_extensions());
1411 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtension1),
1412 GetFirstVideoContentDescription(
1413 offer.get())->rtp_header_extensions());
1414 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
1415 GetFirstAudioContentDescription(
1416 answer.get())->rtp_header_extensions());
1417 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
1418 GetFirstVideoContentDescription(
1419 answer.get())->rtp_header_extensions());
1420}
1421
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001422// Create an audio, video, data answer without legacy StreamParams.
1423TEST_F(MediaSessionDescriptionFactoryTest,
1424 TestCreateAnswerWithoutLegacyStreams) {
1425 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001426 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1427 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
kwiberg31022942016-03-11 14:18:21 -08001428 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001429 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001430 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001431 f2_.CreateAnswer(offer.get(), opts, NULL));
1432 const ContentInfo* ac = answer->GetContentByName("audio");
1433 const ContentInfo* vc = answer->GetContentByName("video");
1434 const ContentInfo* dc = answer->GetContentByName("data");
1435 ASSERT_TRUE(ac != NULL);
1436 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001437 const AudioContentDescription* acd = ac->media_description()->as_audio();
1438 const VideoContentDescription* vcd = vc->media_description()->as_video();
1439 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001440
1441 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1442 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1443 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1444}
1445
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001446// Create a typical video answer, and ensure it matches what we expect.
1447TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1448 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001449 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
1450 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1451 &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001452
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001453 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001454 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
1455 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1456 &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001457
kwiberg31022942016-03-11 14:18:21 -08001458 std::unique_ptr<SessionDescription> offer;
1459 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001460
1461 offer_opts.rtcp_mux_enabled = true;
1462 answer_opts.rtcp_mux_enabled = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001463 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1464 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1465 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1466 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1467 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1468 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1469 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1470 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1471 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1472 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1473 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1474 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1475 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1476 EXPECT_TRUE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1477
1478 offer_opts.rtcp_mux_enabled = true;
1479 answer_opts.rtcp_mux_enabled = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001480 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1481 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1482 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1483 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1484 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1485 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1486 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1487 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1488 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1489 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1490 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1491 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1492 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1493 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1494
1495 offer_opts.rtcp_mux_enabled = false;
1496 answer_opts.rtcp_mux_enabled = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001497 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1498 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1499 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1500 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1501 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1502 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1503 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1504 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1505 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1506 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1507 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1508 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1509 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1510 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1511
1512 offer_opts.rtcp_mux_enabled = false;
1513 answer_opts.rtcp_mux_enabled = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001514 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1515 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1516 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1517 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1518 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1519 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1520 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1521 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1522 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1523 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1524 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1525 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1526 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1527 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1528}
1529
1530// Create an audio-only answer to a video offer.
1531TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1532 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001533 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
1534 kActive, &opts);
1535 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
1536 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -08001537 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001538 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001539
1540 opts.media_description_options[1].stopped = true;
kwiberg31022942016-03-11 14:18:21 -08001541 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001542 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001543 const ContentInfo* ac = answer->GetContentByName("audio");
1544 const ContentInfo* vc = answer->GetContentByName("video");
1545 ASSERT_TRUE(ac != NULL);
1546 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001547 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001548 EXPECT_TRUE(vc->rejected);
1549}
1550
1551// Create an audio-only answer to an offer with data.
1552TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001553 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001554 opts.data_channel_type = cricket::DCT_RTP;
Steve Anton4e70a722017-11-28 14:57:10 -08001555 AddMediaSection(MEDIA_TYPE_DATA, "data", RtpTransceiverDirection::kRecvOnly,
1556 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -08001557 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001558 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001559
1560 opts.media_description_options[1].stopped = true;
kwiberg31022942016-03-11 14:18:21 -08001561 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001562 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001563 const ContentInfo* ac = answer->GetContentByName("audio");
1564 const ContentInfo* dc = answer->GetContentByName("data");
1565 ASSERT_TRUE(ac != NULL);
1566 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001567 ASSERT_TRUE(dc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001568 EXPECT_TRUE(dc->rejected);
1569}
1570
1571// Create an answer that rejects the contents which are rejected in the offer.
1572TEST_F(MediaSessionDescriptionFactoryTest,
1573 CreateAnswerToOfferWithRejectedMedia) {
1574 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001575 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1576 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
kwiberg31022942016-03-11 14:18:21 -08001577 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001578 ASSERT_TRUE(offer.get() != NULL);
1579 ContentInfo* ac = offer->GetContentByName("audio");
1580 ContentInfo* vc = offer->GetContentByName("video");
1581 ContentInfo* dc = offer->GetContentByName("data");
1582 ASSERT_TRUE(ac != NULL);
1583 ASSERT_TRUE(vc != NULL);
1584 ASSERT_TRUE(dc != NULL);
1585 ac->rejected = true;
1586 vc->rejected = true;
1587 dc->rejected = true;
kwiberg31022942016-03-11 14:18:21 -08001588 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001589 f2_.CreateAnswer(offer.get(), opts, NULL));
1590 ac = answer->GetContentByName("audio");
1591 vc = answer->GetContentByName("video");
1592 dc = answer->GetContentByName("data");
1593 ASSERT_TRUE(ac != NULL);
1594 ASSERT_TRUE(vc != NULL);
1595 ASSERT_TRUE(dc != NULL);
1596 EXPECT_TRUE(ac->rejected);
1597 EXPECT_TRUE(vc->rejected);
1598 EXPECT_TRUE(dc->rejected);
1599}
1600
1601// Create an audio and video offer with:
1602// - one video track
1603// - two audio tracks
1604// - two data tracks
1605// and ensure it matches what we expect. Also updates the initial offer by
1606// adding a new video track and replaces one of the audio tracks.
1607TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
1608 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001609 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001610 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001611 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001612 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001613 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001614 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001615 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001616
Steve Anton4e70a722017-11-28 14:57:10 -08001617 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001618 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001619 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001620 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001621 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001622
1623 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001624 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001625
1626 ASSERT_TRUE(offer.get() != NULL);
1627 const ContentInfo* ac = offer->GetContentByName("audio");
1628 const ContentInfo* vc = offer->GetContentByName("video");
1629 const ContentInfo* dc = offer->GetContentByName("data");
1630 ASSERT_TRUE(ac != NULL);
1631 ASSERT_TRUE(vc != NULL);
1632 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001633 const AudioContentDescription* acd = ac->media_description()->as_audio();
1634 const VideoContentDescription* vcd = vc->media_description()->as_video();
1635 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001636 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07001637 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001638
1639 const StreamParamsVec& audio_streams = acd->streams();
1640 ASSERT_EQ(2U, audio_streams.size());
1641 EXPECT_EQ(audio_streams[0].cname , audio_streams[1].cname);
1642 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1643 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1644 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1645 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1646 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1647 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1648
1649 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1650 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001651 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001652
1653 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1654 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001655 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001656
1657 const StreamParamsVec& video_streams = vcd->streams();
1658 ASSERT_EQ(1U, video_streams.size());
1659 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1660 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1661 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1662 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1663
1664 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1665 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001666 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001667
1668 const StreamParamsVec& data_streams = dcd->streams();
1669 ASSERT_EQ(2U, data_streams.size());
1670 EXPECT_EQ(data_streams[0].cname , data_streams[1].cname);
1671 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1672 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1673 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1674 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1675 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1676 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1677
1678 EXPECT_EQ(cricket::kDataMaxBandwidth,
1679 dcd->bandwidth()); // default bandwidth (auto)
1680 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001681 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001682
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001683 // Update the offer. Add a new video track that is not synched to the
1684 // other tracks and replace audio track 2 with audio track 3.
zhihuang1c378ed2017-08-17 14:10:50 -07001685 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001686 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001687 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
1688 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001689 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001690 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
1691 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack3,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001692 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08001693 std::unique_ptr<SessionDescription> updated_offer(
1694 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001695
1696 ASSERT_TRUE(updated_offer.get() != NULL);
1697 ac = updated_offer->GetContentByName("audio");
1698 vc = updated_offer->GetContentByName("video");
1699 dc = updated_offer->GetContentByName("data");
1700 ASSERT_TRUE(ac != NULL);
1701 ASSERT_TRUE(vc != NULL);
1702 ASSERT_TRUE(dc != NULL);
1703 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001704 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001705 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001706 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001707 const DataContentDescription* updated_dcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001708 dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001709
1710 EXPECT_EQ(acd->type(), updated_acd->type());
1711 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1712 EXPECT_EQ(vcd->type(), updated_vcd->type());
1713 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1714 EXPECT_EQ(dcd->type(), updated_dcd->type());
1715 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001716 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001717 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001718 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001719 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001720 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001721 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1722
1723 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1724 ASSERT_EQ(2U, updated_audio_streams.size());
1725 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
1726 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
1727 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
1728 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
1729 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
1730
1731 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1732 ASSERT_EQ(2U, updated_video_streams.size());
1733 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1734 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001735 // All the media streams in one PeerConnection share one RTCP CNAME.
1736 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001737
1738 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1739 ASSERT_EQ(2U, updated_data_streams.size());
1740 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
1741 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
1742 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
1743 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
1744 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07001745 // The stream correctly got the CNAME from the MediaSessionOptions.
1746 // The Expected RTCP CNAME is the default one as we are using the default
1747 // MediaSessionOptions.
1748 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001749}
1750
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001751// Create an offer with simulcast video stream.
1752TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
1753 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001754 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
1755 kActive, &opts);
1756 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
1757 kActive, &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001758 const int num_sim_layers = 3;
zhihuang1c378ed2017-08-17 14:10:50 -07001759 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001760 {kMediaStream1}, num_sim_layers, &opts);
kwiberg31022942016-03-11 14:18:21 -08001761 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001762
1763 ASSERT_TRUE(offer.get() != NULL);
1764 const ContentInfo* vc = offer->GetContentByName("video");
1765 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001766 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001767
1768 const StreamParamsVec& video_streams = vcd->streams();
1769 ASSERT_EQ(1U, video_streams.size());
1770 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1771 const SsrcGroup* sim_ssrc_group =
1772 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
1773 ASSERT_TRUE(sim_ssrc_group != NULL);
1774 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
1775}
1776
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001777// Create an audio and video answer to a standard video offer with:
1778// - one video track
1779// - two audio tracks
1780// - two data tracks
1781// and ensure it matches what we expect. Also updates the initial answer by
1782// adding a new video track and removes one of the audio tracks.
1783TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
1784 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001785 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
1786 kActive, &offer_opts);
1787 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
1788 kActive, &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001789 offer_opts.data_channel_type = cricket::DCT_RTP;
Steve Anton4e70a722017-11-28 14:57:10 -08001790 AddMediaSection(MEDIA_TYPE_DATA, "data", RtpTransceiverDirection::kRecvOnly,
1791 kActive, &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001792 f1_.set_secure(SEC_ENABLED);
1793 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001794 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(offer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001795
zhihuang1c378ed2017-08-17 14:10:50 -07001796 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001797 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kSendRecv,
1798 kActive, &answer_opts);
1799 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
1800 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001801 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001802 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001803 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001804 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001805 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001806 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001807
Steve Anton4e70a722017-11-28 14:57:10 -08001808 AddMediaSection(MEDIA_TYPE_DATA, "data", RtpTransceiverDirection::kSendRecv,
1809 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001810 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001811 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001812 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001813 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001814 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001815
kwiberg31022942016-03-11 14:18:21 -08001816 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001817 f2_.CreateAnswer(offer.get(), answer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001818
1819 ASSERT_TRUE(answer.get() != NULL);
1820 const ContentInfo* ac = answer->GetContentByName("audio");
1821 const ContentInfo* vc = answer->GetContentByName("video");
1822 const ContentInfo* dc = answer->GetContentByName("data");
1823 ASSERT_TRUE(ac != NULL);
1824 ASSERT_TRUE(vc != NULL);
1825 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001826 const AudioContentDescription* acd = ac->media_description()->as_audio();
1827 const VideoContentDescription* vcd = vc->media_description()->as_video();
1828 const DataContentDescription* dcd = dc->media_description()->as_data();
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001829 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
1830 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
1831 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001832
1833 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
1834 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1835
1836 const StreamParamsVec& audio_streams = acd->streams();
1837 ASSERT_EQ(2U, audio_streams.size());
1838 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
1839 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1840 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1841 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1842 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1843 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1844 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1845
1846 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1847 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1848
1849 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1850 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1851
1852 const StreamParamsVec& video_streams = vcd->streams();
1853 ASSERT_EQ(1U, video_streams.size());
1854 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1855 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1856 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1857 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1858
1859 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1860 EXPECT_EQ(MAKE_VECTOR(kDataCodecsAnswer), dcd->codecs());
1861
1862 const StreamParamsVec& data_streams = dcd->streams();
1863 ASSERT_EQ(2U, data_streams.size());
1864 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
1865 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1866 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1867 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1868 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1869 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1870 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1871
1872 EXPECT_EQ(cricket::kDataMaxBandwidth,
1873 dcd->bandwidth()); // default bandwidth (auto)
1874 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
1875
1876 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07001877 // other tracks and remove 1 audio track.
zhihuang1c378ed2017-08-17 14:10:50 -07001878 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001879 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001880 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
1881 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08001882 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001883 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001884
1885 ASSERT_TRUE(updated_answer.get() != NULL);
1886 ac = updated_answer->GetContentByName("audio");
1887 vc = updated_answer->GetContentByName("video");
1888 dc = updated_answer->GetContentByName("data");
1889 ASSERT_TRUE(ac != NULL);
1890 ASSERT_TRUE(vc != NULL);
1891 ASSERT_TRUE(dc != NULL);
1892 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001893 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001894 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001895 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001896 const DataContentDescription* updated_dcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001897 dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001898
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001899 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001900 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001901 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001902 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001903 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001904 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1905
1906 EXPECT_EQ(acd->type(), updated_acd->type());
1907 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1908 EXPECT_EQ(vcd->type(), updated_vcd->type());
1909 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1910 EXPECT_EQ(dcd->type(), updated_dcd->type());
1911 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1912
1913 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1914 ASSERT_EQ(1U, updated_audio_streams.size());
1915 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
1916
1917 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1918 ASSERT_EQ(2U, updated_video_streams.size());
1919 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1920 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001921 // All media streams in one PeerConnection share one CNAME.
1922 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001923
1924 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1925 ASSERT_EQ(1U, updated_data_streams.size());
1926 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
1927}
1928
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001929// Create an updated offer after creating an answer to the original offer and
1930// verify that the codecs that were part of the original answer are not changed
1931// in the updated offer.
1932TEST_F(MediaSessionDescriptionFactoryTest,
1933 RespondentCreatesOfferAfterCreatingAnswer) {
1934 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001935 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001936
kwiberg31022942016-03-11 14:18:21 -08001937 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1938 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001939 f2_.CreateAnswer(offer.get(), opts, NULL));
1940
1941 const AudioContentDescription* acd =
1942 GetFirstAudioContentDescription(answer.get());
1943 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
1944
1945 const VideoContentDescription* vcd =
1946 GetFirstVideoContentDescription(answer.get());
1947 EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
1948
kwiberg31022942016-03-11 14:18:21 -08001949 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001950 f2_.CreateOffer(opts, answer.get()));
1951
1952 // The expected audio codecs are the common audio codecs from the first
1953 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
1954 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00001955 // TODO(wu): |updated_offer| should not include the codec
1956 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001957 const AudioCodec kUpdatedAudioCodecOffer[] = {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001958 kAudioCodecsAnswer[0],
1959 kAudioCodecsAnswer[1],
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00001960 kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001961 };
1962
1963 // The expected video codecs are the common video codecs from the first
1964 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
1965 // preference order.
1966 const VideoCodec kUpdatedVideoCodecOffer[] = {
1967 kVideoCodecsAnswer[0],
1968 kVideoCodecs2[1],
1969 };
1970
1971 const AudioContentDescription* updated_acd =
1972 GetFirstAudioContentDescription(updated_offer.get());
1973 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioCodecOffer), updated_acd->codecs());
1974
1975 const VideoContentDescription* updated_vcd =
1976 GetFirstVideoContentDescription(updated_offer.get());
1977 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoCodecOffer), updated_vcd->codecs());
1978}
1979
1980// Create an updated offer after creating an answer to the original offer and
1981// verify that the codecs that were part of the original answer are not changed
1982// in the updated offer. In this test Rtx is enabled.
1983TEST_F(MediaSessionDescriptionFactoryTest,
1984 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
1985 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001986 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
1987 kActive, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001988 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001989 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001990 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001991 f1_.set_video_codecs(f1_codecs);
1992
1993 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001994 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00001995 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001996 f2_.set_video_codecs(f2_codecs);
1997
kwiberg31022942016-03-11 14:18:21 -08001998 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001999 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002000 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002001 f2_.CreateAnswer(offer.get(), opts, NULL));
2002
2003 const VideoContentDescription* vcd =
2004 GetFirstVideoContentDescription(answer.get());
2005
2006 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002007 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2008 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002009
2010 EXPECT_EQ(expected_codecs, vcd->codecs());
2011
deadbeef67cf2c12016-04-13 10:07:16 -07002012 // Now, make sure we get same result (except for the order) if |f2_| creates
2013 // an updated offer even though the default payload types between |f1_| and
2014 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08002015 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002016 f2_.CreateOffer(opts, answer.get()));
2017 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002018 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002019 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2020
2021 const VideoContentDescription* updated_vcd =
2022 GetFirstVideoContentDescription(updated_answer.get());
2023
2024 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2025}
2026
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002027// Regression test for:
2028// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2029// Existing codecs should always appear before new codecs in re-offers. But
2030// under a specific set of circumstances, the existing RTX codec was ending up
2031// added to the end of the list.
2032TEST_F(MediaSessionDescriptionFactoryTest,
2033 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2034 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002035 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2036 kActive, &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002037 // We specifically choose different preferred payload types for VP8 to
2038 // trigger the issue.
2039 cricket::VideoCodec vp8_offerer(100, "VP8");
2040 cricket::VideoCodec vp8_offerer_rtx =
2041 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
2042 cricket::VideoCodec vp8_answerer(110, "VP8");
2043 cricket::VideoCodec vp8_answerer_rtx =
2044 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
2045 cricket::VideoCodec vp9(120, "VP9");
2046 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
2047
2048 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
2049 // We also specifically cause the answerer to prefer VP9, such that if it
2050 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
2051 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
2052 vp8_answerer_rtx};
2053
2054 f1_.set_video_codecs(f1_codecs);
2055 f2_.set_video_codecs(f2_codecs);
2056 std::vector<AudioCodec> audio_codecs;
2057 f1_.set_audio_codecs(audio_codecs, audio_codecs);
2058 f2_.set_audio_codecs(audio_codecs, audio_codecs);
2059
2060 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
2061 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2062 ASSERT_TRUE(offer.get() != NULL);
2063 std::unique_ptr<SessionDescription> answer(
2064 f2_.CreateAnswer(offer.get(), opts, NULL));
2065
2066 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
2067 // But if the bug is triggered, RTX for VP8 ends up last.
2068 std::unique_ptr<SessionDescription> updated_offer(
2069 f2_.CreateOffer(opts, answer.get()));
2070
2071 const VideoContentDescription* vcd =
2072 GetFirstVideoContentDescription(updated_offer.get());
2073 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
2074 ASSERT_EQ(4u, codecs.size());
2075 EXPECT_EQ(vp8_offerer, codecs[0]);
2076 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
2077 EXPECT_EQ(vp9, codecs[2]);
2078 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002079}
2080
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002081// Create an updated offer that adds video after creating an audio only answer
2082// to the original offer. This test verifies that if a video codec and the RTX
2083// codec have the same default payload type as an audio codec that is already in
2084// use, the added codecs payload types are changed.
2085TEST_F(MediaSessionDescriptionFactoryTest,
2086 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2087 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002088 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002089 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002090 f1_.set_video_codecs(f1_codecs);
2091
2092 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002093 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2094 kActive, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002095
kwiberg31022942016-03-11 14:18:21 -08002096 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2097 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002098 f2_.CreateAnswer(offer.get(), opts, NULL));
2099
2100 const AudioContentDescription* acd =
2101 GetFirstAudioContentDescription(answer.get());
2102 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
2103
2104 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
2105 // reference be the same as an audio codec that was negotiated in the
2106 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002107 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08002108 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002109
2110 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2111 int used_pl_type = acd->codecs()[0].id;
2112 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002113 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002114 f2_.set_video_codecs(f2_codecs);
2115
kwiberg31022942016-03-11 14:18:21 -08002116 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002117 f2_.CreateOffer(opts, answer.get()));
2118 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002119 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002120 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2121
2122 const AudioContentDescription* updated_acd =
2123 GetFirstAudioContentDescription(answer.get());
2124 EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), updated_acd->codecs());
2125
2126 const VideoContentDescription* updated_vcd =
2127 GetFirstVideoContentDescription(updated_answer.get());
2128
2129 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
sergeyu@chromium.org32f485b2013-12-05 22:36:21 +00002130 ASSERT_EQ(std::string(cricket::kRtxCodecName), updated_vcd->codecs()[1].name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002131 int new_h264_pl_type = updated_vcd->codecs()[0].id;
2132 EXPECT_NE(used_pl_type, new_h264_pl_type);
2133 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002134 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002135 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
2136 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
2137}
2138
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002139// Create an updated offer with RTX after creating an answer to an offer
2140// without RTX, and with different default payload types.
2141// Verify that the added RTX codec references the correct payload type.
2142TEST_F(MediaSessionDescriptionFactoryTest,
2143 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
2144 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002145 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002146
2147 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2148 // This creates rtx for H264 with the payload type |f2_| uses.
2149 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
2150 f2_.set_video_codecs(f2_codecs);
2151
kwiberg31022942016-03-11 14:18:21 -08002152 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002153 ASSERT_TRUE(offer.get() != nullptr);
kwiberg31022942016-03-11 14:18:21 -08002154 std::unique_ptr<SessionDescription> answer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002155 f2_.CreateAnswer(offer.get(), opts, nullptr));
2156
2157 const VideoContentDescription* vcd =
2158 GetFirstVideoContentDescription(answer.get());
2159
2160 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2161 EXPECT_EQ(expected_codecs, vcd->codecs());
2162
2163 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
2164 // updated offer, even though the default payload types are different from
2165 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08002166 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002167 f2_.CreateOffer(opts, answer.get()));
2168 ASSERT_TRUE(updated_offer);
2169
2170 const VideoContentDescription* updated_vcd =
2171 GetFirstVideoContentDescription(updated_offer.get());
2172
2173 // New offer should attempt to add H263, and RTX for H264.
2174 expected_codecs.push_back(kVideoCodecs2[1]);
2175 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
2176 &expected_codecs);
2177 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2178}
2179
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002180// Test that RTX is ignored when there is no associated payload type parameter.
2181TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
2182 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002183 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2184 kActive, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002185 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002186 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07002187 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002188 f1_.set_video_codecs(f1_codecs);
2189
2190 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002191 // This creates RTX for H264 with the payload type |f2_| uses.
2192 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002193 f2_.set_video_codecs(f2_codecs);
2194
kwiberg31022942016-03-11 14:18:21 -08002195 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002196 ASSERT_TRUE(offer.get() != NULL);
2197 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
2198 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
2199 // is possible to test that that RTX is dropped when
2200 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08002201 MediaContentDescription* media_desc =
2202 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2203 ASSERT_TRUE(media_desc);
2204 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002205 std::vector<VideoCodec> codecs = desc->codecs();
2206 for (std::vector<VideoCodec>::iterator iter = codecs.begin();
2207 iter != codecs.end(); ++iter) {
2208 if (iter->name.find(cricket::kRtxCodecName) == 0) {
2209 iter->params.clear();
2210 }
2211 }
2212 desc->set_codecs(codecs);
2213
kwiberg31022942016-03-11 14:18:21 -08002214 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002215 f2_.CreateAnswer(offer.get(), opts, NULL));
2216
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002217 std::vector<std::string> codec_names =
2218 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
2219 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
2220 cricket::kRtxCodecName));
2221}
2222
2223// Test that RTX will be filtered out in the answer if its associated payload
2224// type doesn't match the local value.
2225TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
2226 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002227 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2228 kActive, &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002229 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2230 // This creates RTX for H264 in sender.
2231 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2232 f1_.set_video_codecs(f1_codecs);
2233
2234 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2235 // This creates RTX for H263 in receiver.
2236 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
2237 f2_.set_video_codecs(f2_codecs);
2238
kwiberg31022942016-03-11 14:18:21 -08002239 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002240 ASSERT_TRUE(offer.get() != NULL);
2241 // Associated payload type doesn't match, therefore, RTX codec is removed in
2242 // the answer.
kwiberg31022942016-03-11 14:18:21 -08002243 std::unique_ptr<SessionDescription> answer(
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002244 f2_.CreateAnswer(offer.get(), opts, NULL));
2245
2246 std::vector<std::string> codec_names =
2247 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
2248 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
2249 cricket::kRtxCodecName));
2250}
2251
2252// Test that when multiple RTX codecs are offered, only the matched RTX codec
2253// is added in the answer, and the unsupported RTX codec is filtered out.
2254TEST_F(MediaSessionDescriptionFactoryTest,
2255 FilterOutUnsupportedRtxWhenCreatingAnswer) {
2256 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002257 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2258 kActive, &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002259 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2260 // This creates RTX for H264-SVC in sender.
2261 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2262 f1_.set_video_codecs(f1_codecs);
2263
2264 // This creates RTX for H264 in sender.
2265 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2266 f1_.set_video_codecs(f1_codecs);
2267
2268 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2269 // This creates RTX for H264 in receiver.
2270 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
2271 f2_.set_video_codecs(f2_codecs);
2272
2273 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
2274 // for H264-SVC should also be removed.
kwiberg31022942016-03-11 14:18:21 -08002275 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002276 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002277 std::unique_ptr<SessionDescription> answer(
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002278 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002279 const VideoContentDescription* vcd =
2280 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002281 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2282 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2283 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002284
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002285 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002286}
2287
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002288// Test that after one RTX codec has been negotiated, a new offer can attempt
2289// to add another.
2290TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
2291 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002292 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2293 kActive, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002294 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2295 // This creates RTX for H264 for the offerer.
2296 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2297 f1_.set_video_codecs(f1_codecs);
2298
kwiberg31022942016-03-11 14:18:21 -08002299 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002300 ASSERT_TRUE(offer);
2301 const VideoContentDescription* vcd =
2302 GetFirstVideoContentDescription(offer.get());
2303
2304 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
2305 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2306 &expected_codecs);
2307 EXPECT_EQ(expected_codecs, vcd->codecs());
2308
2309 // Now, attempt to add RTX for H264-SVC.
2310 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2311 f1_.set_video_codecs(f1_codecs);
2312
kwiberg31022942016-03-11 14:18:21 -08002313 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002314 f1_.CreateOffer(opts, offer.get()));
2315 ASSERT_TRUE(updated_offer);
2316 vcd = GetFirstVideoContentDescription(updated_offer.get());
2317
2318 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
2319 &expected_codecs);
2320 EXPECT_EQ(expected_codecs, vcd->codecs());
2321}
2322
Noah Richards2e7a0982015-05-18 14:02:54 -07002323// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
2324// generated for each simulcast ssrc and correctly grouped.
2325TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
2326 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002327 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
2328 kActive, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002329 // Add simulcast streams.
zhihuang1c378ed2017-08-17 14:10:50 -07002330 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002331 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002332
2333 // Use a single real codec, and then add RTX for it.
2334 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07002335 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07002336 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
2337 f1_.set_video_codecs(f1_codecs);
2338
2339 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
2340 // is a FID ssrc + grouping for each.
kwiberg31022942016-03-11 14:18:21 -08002341 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
Noah Richards2e7a0982015-05-18 14:02:54 -07002342 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002343 MediaContentDescription* media_desc =
2344 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2345 ASSERT_TRUE(media_desc);
2346 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07002347 const StreamParamsVec& streams = desc->streams();
2348 // Single stream.
2349 ASSERT_EQ(1u, streams.size());
2350 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
2351 EXPECT_EQ(6u, streams[0].ssrcs.size());
2352 // And should have a SIM group for the simulcast.
2353 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2354 // And a FID group for RTX.
2355 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02002356 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002357 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2358 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02002359 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002360 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
2361 EXPECT_EQ(3u, fid_ssrcs.size());
2362}
2363
brandtr03d5fb12016-11-22 03:37:59 -08002364// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
2365// together with a FEC-FR grouping.
2366TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
2367 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002368 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
2369 kActive, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002370 // Add single stream.
zhihuang1c378ed2017-08-17 14:10:50 -07002371 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002372 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002373
2374 // Use a single real codec, and then add FlexFEC for it.
2375 std::vector<VideoCodec> f1_codecs;
2376 f1_codecs.push_back(VideoCodec(97, "H264"));
2377 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2378 f1_.set_video_codecs(f1_codecs);
2379
2380 // Ensure that the offer has a single FlexFEC ssrc and that
2381 // there is no FEC-FR ssrc + grouping for each.
2382 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
2383 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08002384 MediaContentDescription* media_desc =
2385 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2386 ASSERT_TRUE(media_desc);
2387 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08002388 const StreamParamsVec& streams = desc->streams();
2389 // Single stream.
2390 ASSERT_EQ(1u, streams.size());
2391 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
2392 EXPECT_EQ(2u, streams[0].ssrcs.size());
2393 // And should have a FEC-FR group for FlexFEC.
2394 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
2395 std::vector<uint32_t> primary_ssrcs;
2396 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2397 ASSERT_EQ(1u, primary_ssrcs.size());
2398 uint32_t flexfec_ssrc;
2399 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
2400 EXPECT_NE(flexfec_ssrc, 0u);
2401}
2402
2403// Test that FlexFEC is disabled for simulcast.
2404// TODO(brandtr): Remove this test when we support simulcast, either through
2405// multiple FlexfecSenders, or through multistream protection.
2406TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
2407 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002408 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
2409 kActive, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002410 // Add simulcast streams.
zhihuang1c378ed2017-08-17 14:10:50 -07002411 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002412 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002413
2414 // Use a single real codec, and then add FlexFEC for it.
2415 std::vector<VideoCodec> f1_codecs;
2416 f1_codecs.push_back(VideoCodec(97, "H264"));
2417 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2418 f1_.set_video_codecs(f1_codecs);
2419
2420 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
2421 // there is no FEC-FR ssrc + grouping for each.
2422 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
2423 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08002424 MediaContentDescription* media_desc =
2425 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2426 ASSERT_TRUE(media_desc);
2427 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08002428 const StreamParamsVec& streams = desc->streams();
2429 // Single stream.
2430 ASSERT_EQ(1u, streams.size());
2431 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
2432 EXPECT_EQ(3u, streams[0].ssrcs.size());
2433 // And should have a SIM group for the simulcast.
2434 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2435 // And not a FEC-FR group for FlexFEC.
2436 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
2437 std::vector<uint32_t> primary_ssrcs;
2438 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2439 EXPECT_EQ(3u, primary_ssrcs.size());
2440 for (uint32_t primary_ssrc : primary_ssrcs) {
2441 uint32_t flexfec_ssrc;
2442 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
2443 }
2444}
2445
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002446// Create an updated offer after creating an answer to the original offer and
2447// verify that the RTP header extensions that were part of the original answer
2448// are not changed in the updated offer.
2449TEST_F(MediaSessionDescriptionFactoryTest,
2450 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
2451 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002452 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002453
2454 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
2455 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
2456 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
2457 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
2458
kwiberg31022942016-03-11 14:18:21 -08002459 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2460 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002461 f2_.CreateAnswer(offer.get(), opts, NULL));
2462
2463 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtensionAnswer),
2464 GetFirstAudioContentDescription(
2465 answer.get())->rtp_header_extensions());
2466 EXPECT_EQ(MAKE_VECTOR(kVideoRtpExtensionAnswer),
2467 GetFirstVideoContentDescription(
2468 answer.get())->rtp_header_extensions());
2469
kwiberg31022942016-03-11 14:18:21 -08002470 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002471 f2_.CreateOffer(opts, answer.get()));
2472
2473 // The expected RTP header extensions in the new offer are the resulting
2474 // extensions from the first offer/answer exchange plus the extensions only
2475 // |f2_| offer.
2476 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002477 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07002478 const RtpExtension kUpdatedAudioRtpExtensions[] = {
2479 kAudioRtpExtensionAnswer[0], RtpExtension(kAudioRtpExtension2[1].uri, 13),
2480 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002481 };
2482
2483 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002484 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07002485 const RtpExtension kUpdatedVideoRtpExtensions[] = {
2486 kVideoRtpExtensionAnswer[0], RtpExtension(kVideoRtpExtension2[1].uri, 12),
2487 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002488 };
2489
2490 const AudioContentDescription* updated_acd =
2491 GetFirstAudioContentDescription(updated_offer.get());
2492 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
2493 updated_acd->rtp_header_extensions());
2494
2495 const VideoContentDescription* updated_vcd =
2496 GetFirstVideoContentDescription(updated_offer.get());
2497 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
2498 updated_vcd->rtp_header_extensions());
2499}
2500
deadbeefa5b273a2015-08-20 17:30:13 -07002501// Verify that if the same RTP extension URI is used for audio and video, the
2502// same ID is used. Also verify that the ID isn't changed when creating an
2503// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07002504TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07002505 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002506 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07002507
2508 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
2509 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
2510
kwiberg31022942016-03-11 14:18:21 -08002511 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
deadbeefa5b273a2015-08-20 17:30:13 -07002512
2513 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
2514 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07002515 const RtpExtension kExpectedVideoRtpExtension[] = {
2516 kVideoRtpExtension3[0], kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07002517 };
2518
2519 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
2520 GetFirstAudioContentDescription(
2521 offer.get())->rtp_header_extensions());
2522 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2523 GetFirstVideoContentDescription(
2524 offer.get())->rtp_header_extensions());
2525
2526 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08002527 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07002528 f1_.CreateOffer(opts, offer.get()));
2529
2530 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
2531 GetFirstAudioContentDescription(
2532 updated_offer.get())->rtp_header_extensions());
2533 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2534 GetFirstVideoContentDescription(
2535 updated_offer.get())->rtp_header_extensions());
2536}
2537
jbauch5869f502017-06-29 12:31:36 -07002538// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
2539TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
2540 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002541 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07002542
2543 f1_.set_enable_encrypted_rtp_header_extensions(true);
2544 f2_.set_enable_encrypted_rtp_header_extensions(true);
2545
2546 f1_.set_audio_rtp_header_extensions(
2547 MAKE_VECTOR(kAudioRtpExtension3ForEncryption));
2548 f1_.set_video_rtp_header_extensions(
2549 MAKE_VECTOR(kVideoRtpExtension3ForEncryption));
2550
2551 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2552
2553 // The extensions that are shared between audio and video should use the same
2554 // id.
2555 const RtpExtension kExpectedVideoRtpExtension[] = {
2556 kVideoRtpExtension3ForEncryption[0],
2557 kAudioRtpExtension3ForEncryptionOffer[1],
2558 kAudioRtpExtension3ForEncryptionOffer[2],
2559 };
2560
2561 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
2562 GetFirstAudioContentDescription(
2563 offer.get())->rtp_header_extensions());
2564 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2565 GetFirstVideoContentDescription(
2566 offer.get())->rtp_header_extensions());
2567
2568 // Nothing should change when creating a new offer
2569 std::unique_ptr<SessionDescription> updated_offer(
2570 f1_.CreateOffer(opts, offer.get()));
2571
2572 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
2573 GetFirstAudioContentDescription(
2574 updated_offer.get())->rtp_header_extensions());
2575 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
2576 GetFirstVideoContentDescription(
2577 updated_offer.get())->rtp_header_extensions());
2578}
2579
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002580TEST(MediaSessionDescription, CopySessionDescription) {
2581 SessionDescription source;
2582 cricket::ContentGroup group(cricket::CN_AUDIO);
2583 source.AddGroup(group);
2584 AudioContentDescription* acd(new AudioContentDescription());
2585 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
2586 acd->AddLegacyStream(1);
Steve Anton5adfafd2017-12-20 16:34:00 -08002587 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp, acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002588 VideoContentDescription* vcd(new VideoContentDescription());
2589 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
2590 vcd->AddLegacyStream(2);
Steve Anton5adfafd2017-12-20 16:34:00 -08002591 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp, vcd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002592
kwiberg31022942016-03-11 14:18:21 -08002593 std::unique_ptr<SessionDescription> copy(source.Copy());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002594 ASSERT_TRUE(copy.get() != NULL);
2595 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
2596 const ContentInfo* ac = copy->GetContentByName("audio");
2597 const ContentInfo* vc = copy->GetContentByName("video");
2598 ASSERT_TRUE(ac != NULL);
2599 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08002600 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002601 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002602 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
2603 EXPECT_EQ(1u, acd->first_ssrc());
2604
Steve Anton5adfafd2017-12-20 16:34:00 -08002605 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002606 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002607 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
2608 EXPECT_EQ(2u, vcd->first_ssrc());
2609}
2610
2611// The below TestTransportInfoXXX tests create different offers/answers, and
2612// ensure the TransportInfo in the SessionDescription matches what we expect.
2613TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
2614 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002615 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2616 kActive, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002617 TestTransportInfo(true, options, false);
2618}
2619
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002620TEST_F(MediaSessionDescriptionFactoryTest,
2621 TestTransportInfoOfferIceRenomination) {
2622 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002623 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2624 kActive, &options);
zhihuang1c378ed2017-08-17 14:10:50 -07002625 options.media_description_options[0]
2626 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002627 TestTransportInfo(true, options, false);
2628}
2629
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002630TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
2631 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002632 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2633 kActive, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002634 TestTransportInfo(true, options, true);
2635}
2636
2637TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
2638 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002639 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2640 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2641 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002642 TestTransportInfo(true, options, false);
2643}
2644
2645TEST_F(MediaSessionDescriptionFactoryTest,
2646 TestTransportInfoOfferMultimediaCurrent) {
2647 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002648 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2649 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2650 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002651 TestTransportInfo(true, options, true);
2652}
2653
2654TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
2655 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002656 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2657 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2658 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002659 options.bundle_enabled = true;
2660 TestTransportInfo(true, options, false);
2661}
2662
2663TEST_F(MediaSessionDescriptionFactoryTest,
2664 TestTransportInfoOfferBundleCurrent) {
2665 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002666 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2667 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2668 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002669 options.bundle_enabled = true;
2670 TestTransportInfo(true, options, true);
2671}
2672
2673TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
2674 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002675 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2676 kActive, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002677 TestTransportInfo(false, options, false);
2678}
2679
2680TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002681 TestTransportInfoAnswerIceRenomination) {
2682 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002683 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2684 kActive, &options);
zhihuang1c378ed2017-08-17 14:10:50 -07002685 options.media_description_options[0]
2686 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002687 TestTransportInfo(false, options, false);
2688}
2689
2690TEST_F(MediaSessionDescriptionFactoryTest,
2691 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002692 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002693 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2694 kActive, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002695 TestTransportInfo(false, options, true);
2696}
2697
2698TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
2699 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002700 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2701 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2702 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002703 TestTransportInfo(false, options, false);
2704}
2705
2706TEST_F(MediaSessionDescriptionFactoryTest,
2707 TestTransportInfoAnswerMultimediaCurrent) {
2708 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002709 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2710 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2711 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002712 TestTransportInfo(false, options, true);
2713}
2714
2715TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
2716 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002717 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2718 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2719 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002720 options.bundle_enabled = true;
2721 TestTransportInfo(false, options, false);
2722}
2723
2724TEST_F(MediaSessionDescriptionFactoryTest,
2725 TestTransportInfoAnswerBundleCurrent) {
2726 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002727 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2728 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2729 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002730 options.bundle_enabled = true;
2731 TestTransportInfo(false, options, true);
2732}
2733
2734// Create an offer with bundle enabled and verify the crypto parameters are
2735// the common set of the available cryptos.
2736TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
2737 TestCryptoWithBundle(true);
2738}
2739
2740// Create an answer with bundle enabled and verify the crypto parameters are
2741// the common set of the available cryptos.
2742TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
2743 TestCryptoWithBundle(false);
2744}
2745
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002746// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
2747// DTLS is not enabled locally.
2748TEST_F(MediaSessionDescriptionFactoryTest,
2749 TestOfferDtlsSavpfWithoutDtlsFailed) {
2750 f1_.set_secure(SEC_ENABLED);
2751 f2_.set_secure(SEC_ENABLED);
2752 tdf1_.set_secure(SEC_DISABLED);
2753 tdf2_.set_secure(SEC_DISABLED);
2754
kwiberg31022942016-03-11 14:18:21 -08002755 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -07002756 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002757 ASSERT_TRUE(offer.get() != NULL);
2758 ContentInfo* offer_content = offer->GetContentByName("audio");
2759 ASSERT_TRUE(offer_content != NULL);
2760 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08002761 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002762 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2763
kwiberg31022942016-03-11 14:18:21 -08002764 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002765 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002766 ASSERT_TRUE(answer != NULL);
2767 ContentInfo* answer_content = answer->GetContentByName("audio");
2768 ASSERT_TRUE(answer_content != NULL);
2769
2770 ASSERT_TRUE(answer_content->rejected);
2771}
2772
2773// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
2774// UDP/TLS/RTP/SAVPF.
2775TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
2776 f1_.set_secure(SEC_ENABLED);
2777 f2_.set_secure(SEC_ENABLED);
2778 tdf1_.set_secure(SEC_ENABLED);
2779 tdf2_.set_secure(SEC_ENABLED);
2780
kwiberg31022942016-03-11 14:18:21 -08002781 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -07002782 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002783 ASSERT_TRUE(offer.get() != NULL);
2784 ContentInfo* offer_content = offer->GetContentByName("audio");
2785 ASSERT_TRUE(offer_content != NULL);
2786 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08002787 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002788 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2789
kwiberg31022942016-03-11 14:18:21 -08002790 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002791 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002792 ASSERT_TRUE(answer != NULL);
2793
2794 const ContentInfo* answer_content = answer->GetContentByName("audio");
2795 ASSERT_TRUE(answer_content != NULL);
2796 ASSERT_FALSE(answer_content->rejected);
2797
2798 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08002799 answer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002800 EXPECT_EQ(std::string(cricket::kMediaProtocolDtlsSavpf),
2801 answer_audio_desc->protocol());
2802}
2803
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002804// Test that we include both SDES and DTLS in the offer, but only include SDES
2805// in the answer if DTLS isn't negotiated.
2806TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
2807 f1_.set_secure(SEC_ENABLED);
2808 f2_.set_secure(SEC_ENABLED);
2809 tdf1_.set_secure(SEC_ENABLED);
2810 tdf2_.set_secure(SEC_DISABLED);
2811 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002812 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08002813 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002814 const cricket::MediaContentDescription* audio_media_desc;
2815 const cricket::MediaContentDescription* video_media_desc;
2816 const cricket::TransportDescription* audio_trans_desc;
2817 const cricket::TransportDescription* video_trans_desc;
2818
2819 // Generate an offer with SDES and DTLS support.
2820 offer.reset(f1_.CreateOffer(options, NULL));
2821 ASSERT_TRUE(offer.get() != NULL);
2822
Steve Antonb1c1de12017-12-21 15:14:30 -08002823 audio_media_desc = offer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002824 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002825 video_media_desc = offer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002826 ASSERT_TRUE(video_media_desc != NULL);
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002827 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002828 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2829
2830 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2831 ASSERT_TRUE(audio_trans_desc != NULL);
2832 video_trans_desc = offer->GetTransportDescriptionByName("video");
2833 ASSERT_TRUE(video_trans_desc != NULL);
2834 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2835 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
2836
2837 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
2838 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2839 ASSERT_TRUE(answer.get() != NULL);
2840
Steve Antonb1c1de12017-12-21 15:14:30 -08002841 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002842 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002843 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002844 ASSERT_TRUE(video_media_desc != NULL);
2845 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
2846 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2847
2848 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2849 ASSERT_TRUE(audio_trans_desc != NULL);
2850 video_trans_desc = answer->GetTransportDescriptionByName("video");
2851 ASSERT_TRUE(video_trans_desc != NULL);
2852 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
2853 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
2854
2855 // Enable DTLS; the answer should now only have DTLS support.
2856 tdf2_.set_secure(SEC_ENABLED);
2857 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2858 ASSERT_TRUE(answer.get() != NULL);
2859
Steve Antonb1c1de12017-12-21 15:14:30 -08002860 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002861 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002862 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002863 ASSERT_TRUE(video_media_desc != NULL);
2864 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2865 EXPECT_TRUE(video_media_desc->cryptos().empty());
2866 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2867 audio_media_desc->protocol());
2868 EXPECT_EQ(std::string(cricket::kMediaProtocolSavpf),
2869 video_media_desc->protocol());
2870
2871 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2872 ASSERT_TRUE(audio_trans_desc != NULL);
2873 video_trans_desc = answer->GetTransportDescriptionByName("video");
2874 ASSERT_TRUE(video_trans_desc != NULL);
2875 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2876 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00002877
2878 // Try creating offer again. DTLS enabled now, crypto's should be empty
2879 // in new offer.
2880 offer.reset(f1_.CreateOffer(options, offer.get()));
2881 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002882 audio_media_desc = offer->GetContentDescriptionByName("audio");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00002883 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002884 video_media_desc = offer->GetContentDescriptionByName("video");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00002885 ASSERT_TRUE(video_media_desc != NULL);
2886 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2887 EXPECT_TRUE(video_media_desc->cryptos().empty());
2888
2889 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2890 ASSERT_TRUE(audio_trans_desc != NULL);
2891 video_trans_desc = offer->GetTransportDescriptionByName("video");
2892 ASSERT_TRUE(video_trans_desc != NULL);
2893 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2894 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002895}
2896
2897// Test that an answer can't be created if cryptos are required but the offer is
2898// unsecure.
2899TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07002900 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002901 f1_.set_secure(SEC_DISABLED);
2902 tdf1_.set_secure(SEC_DISABLED);
2903 f2_.set_secure(SEC_REQUIRED);
2904 tdf1_.set_secure(SEC_ENABLED);
2905
kwiberg31022942016-03-11 14:18:21 -08002906 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002907 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002908 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002909 f2_.CreateAnswer(offer.get(), options, NULL));
2910 EXPECT_TRUE(answer.get() == NULL);
2911}
2912
2913// Test that we accept a DTLS offer without SDES and create an appropriate
2914// answer.
2915TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
2916 f1_.set_secure(SEC_DISABLED);
2917 f2_.set_secure(SEC_ENABLED);
2918 tdf1_.set_secure(SEC_ENABLED);
2919 tdf2_.set_secure(SEC_ENABLED);
2920 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002921 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2922 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2923 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002924
kwiberg31022942016-03-11 14:18:21 -08002925 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002926
2927 // Generate an offer with DTLS but without SDES.
2928 offer.reset(f1_.CreateOffer(options, NULL));
2929 ASSERT_TRUE(offer.get() != NULL);
2930
2931 const AudioContentDescription* audio_offer =
2932 GetFirstAudioContentDescription(offer.get());
2933 ASSERT_TRUE(audio_offer->cryptos().empty());
2934 const VideoContentDescription* video_offer =
2935 GetFirstVideoContentDescription(offer.get());
2936 ASSERT_TRUE(video_offer->cryptos().empty());
2937 const DataContentDescription* data_offer =
2938 GetFirstDataContentDescription(offer.get());
2939 ASSERT_TRUE(data_offer->cryptos().empty());
2940
2941 const cricket::TransportDescription* audio_offer_trans_desc =
2942 offer->GetTransportDescriptionByName("audio");
2943 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
2944 const cricket::TransportDescription* video_offer_trans_desc =
2945 offer->GetTransportDescriptionByName("video");
2946 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
2947 const cricket::TransportDescription* data_offer_trans_desc =
2948 offer->GetTransportDescriptionByName("data");
2949 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
2950
2951 // Generate an answer with DTLS.
2952 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2953 ASSERT_TRUE(answer.get() != NULL);
2954
2955 const cricket::TransportDescription* audio_answer_trans_desc =
2956 answer->GetTransportDescriptionByName("audio");
2957 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
2958 const cricket::TransportDescription* video_answer_trans_desc =
2959 answer->GetTransportDescriptionByName("video");
2960 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
2961 const cricket::TransportDescription* data_answer_trans_desc =
2962 answer->GetTransportDescriptionByName("data");
2963 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
2964}
2965
2966// Verifies if vad_enabled option is set to false, CN codecs are not present in
2967// offer or answer.
2968TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
2969 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002970 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08002971 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002972 ASSERT_TRUE(offer.get() != NULL);
2973 const ContentInfo* audio_content = offer->GetContentByName("audio");
2974 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
2975
2976 options.vad_enabled = false;
2977 offer.reset(f1_.CreateOffer(options, NULL));
2978 ASSERT_TRUE(offer.get() != NULL);
2979 audio_content = offer->GetContentByName("audio");
2980 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
kwiberg31022942016-03-11 14:18:21 -08002981 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002982 f1_.CreateAnswer(offer.get(), options, NULL));
2983 ASSERT_TRUE(answer.get() != NULL);
2984 audio_content = answer->GetContentByName("audio");
2985 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
2986}
deadbeef44f08192015-12-15 16:20:09 -08002987
zhihuang1c378ed2017-08-17 14:10:50 -07002988// Test that the generated MIDs match the existing offer.
2989TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08002990 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002991 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_modified",
2992 RtpTransceiverDirection::kRecvOnly, kActive, &opts);
2993 AddMediaSection(MEDIA_TYPE_VIDEO, "video_modified",
2994 RtpTransceiverDirection::kRecvOnly, kActive, &opts);
deadbeef44f08192015-12-15 16:20:09 -08002995 opts.data_channel_type = cricket::DCT_SCTP;
Steve Anton4e70a722017-11-28 14:57:10 -08002996 AddMediaSection(MEDIA_TYPE_DATA, "data_modified",
2997 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002998 // Create offer.
kwiberg31022942016-03-11 14:18:21 -08002999 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
kwiberg31022942016-03-11 14:18:21 -08003000 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08003001 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003002
deadbeef44f08192015-12-15 16:20:09 -08003003 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3004 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3005 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3006 ASSERT_TRUE(audio_content != nullptr);
3007 ASSERT_TRUE(video_content != nullptr);
3008 ASSERT_TRUE(data_content != nullptr);
3009 EXPECT_EQ("audio_modified", audio_content->name);
3010 EXPECT_EQ("video_modified", video_content->name);
3011 EXPECT_EQ("data_modified", data_content->name);
3012}
zhihuangcf5b37c2016-05-05 11:44:35 -07003013
zhihuang1c378ed2017-08-17 14:10:50 -07003014// The following tests verify that the unified plan SDP is supported.
3015// Test that we can create an offer with multiple media sections of same media
3016// type.
3017TEST_F(MediaSessionDescriptionFactoryTest,
3018 CreateOfferWithMultipleAVMediaSections) {
3019 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003020 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_1",
3021 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003022 AttachSenderToMediaSection("audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003023 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003024
Steve Anton4e70a722017-11-28 14:57:10 -08003025 AddMediaSection(MEDIA_TYPE_VIDEO, "video_1",
3026 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003027 AttachSenderToMediaSection("video_1", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003028 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003029
Steve Anton4e70a722017-11-28 14:57:10 -08003030 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_2",
3031 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003032 AttachSenderToMediaSection("audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003033 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003034
Steve Anton4e70a722017-11-28 14:57:10 -08003035 AddMediaSection(MEDIA_TYPE_VIDEO, "video_2",
3036 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003037 AttachSenderToMediaSection("video_2", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003038 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003039 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3040 ASSERT_TRUE(offer);
3041
3042 ASSERT_EQ(4u, offer->contents().size());
3043 EXPECT_FALSE(offer->contents()[0].rejected);
3044 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003045 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003046 ASSERT_EQ(1u, acd->streams().size());
3047 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003048 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003049
3050 EXPECT_FALSE(offer->contents()[1].rejected);
3051 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003052 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003053 ASSERT_EQ(1u, vcd->streams().size());
3054 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003055 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003056
3057 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003058 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003059 ASSERT_EQ(1u, acd->streams().size());
3060 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003061 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003062
3063 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003064 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003065 ASSERT_EQ(1u, vcd->streams().size());
3066 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003067 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003068}
3069
3070// Test that we can create an answer with multiple media sections of same media
3071// type.
3072TEST_F(MediaSessionDescriptionFactoryTest,
3073 CreateAnswerWithMultipleAVMediaSections) {
3074 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003075 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_1",
3076 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003077 AttachSenderToMediaSection("audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1,
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_VIDEO, "video_1",
3081 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003082 AttachSenderToMediaSection("video_1", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003083 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003084
Steve Anton4e70a722017-11-28 14:57:10 -08003085 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_2",
3086 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003087 AttachSenderToMediaSection("audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003088 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003089
Steve Anton4e70a722017-11-28 14:57:10 -08003090 AddMediaSection(MEDIA_TYPE_VIDEO, "video_2",
3091 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003092 AttachSenderToMediaSection("video_2", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003093 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003094
3095 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3096 ASSERT_TRUE(offer);
3097 std::unique_ptr<SessionDescription> answer(
3098 f2_.CreateAnswer(offer.get(), opts, nullptr));
3099
3100 ASSERT_EQ(4u, answer->contents().size());
3101 EXPECT_FALSE(answer->contents()[0].rejected);
3102 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003103 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003104 ASSERT_EQ(1u, acd->streams().size());
3105 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003106 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003107
3108 EXPECT_FALSE(answer->contents()[1].rejected);
3109 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003110 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003111 ASSERT_EQ(1u, vcd->streams().size());
3112 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003113 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003114
3115 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003116 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003117 ASSERT_EQ(1u, acd->streams().size());
3118 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003119 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003120
3121 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003122 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003123 ASSERT_EQ(1u, vcd->streams().size());
3124 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003125 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003126}
3127
3128// Test that the media section will be rejected in offer if the corresponding
3129// MediaDescriptionOptions is stopped by the offerer.
3130TEST_F(MediaSessionDescriptionFactoryTest,
3131 CreateOfferWithMediaSectionStoppedByOfferer) {
3132 // Create an offer with two audio sections and one of them is stopped.
3133 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003134 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3135 RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
3136 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3137 RtpTransceiverDirection::kInactive, kStopped, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003138 std::unique_ptr<SessionDescription> offer(
3139 f1_.CreateOffer(offer_opts, nullptr));
3140 ASSERT_TRUE(offer);
3141 ASSERT_EQ(2u, offer->contents().size());
3142 EXPECT_FALSE(offer->contents()[0].rejected);
3143 EXPECT_TRUE(offer->contents()[1].rejected);
3144}
3145
3146// Test that the media section will be rejected in answer if the corresponding
3147// MediaDescriptionOptions is stopped by the offerer.
3148TEST_F(MediaSessionDescriptionFactoryTest,
3149 CreateAnswerWithMediaSectionStoppedByOfferer) {
3150 // Create an offer with two audio sections and one of them is stopped.
3151 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003152 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3153 RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
3154 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3155 RtpTransceiverDirection::kInactive, kStopped, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003156 std::unique_ptr<SessionDescription> offer(
3157 f1_.CreateOffer(offer_opts, nullptr));
3158 ASSERT_TRUE(offer);
3159 ASSERT_EQ(2u, offer->contents().size());
3160 EXPECT_FALSE(offer->contents()[0].rejected);
3161 EXPECT_TRUE(offer->contents()[1].rejected);
3162
3163 // Create an answer based on the offer.
3164 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003165 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3166 RtpTransceiverDirection::kSendRecv, kActive, &answer_opts);
3167 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3168 RtpTransceiverDirection::kSendRecv, kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003169 std::unique_ptr<SessionDescription> answer(
3170 f2_.CreateAnswer(offer.get(), answer_opts, nullptr));
3171 ASSERT_EQ(2u, answer->contents().size());
3172 EXPECT_FALSE(answer->contents()[0].rejected);
3173 EXPECT_TRUE(answer->contents()[1].rejected);
3174}
3175
3176// Test that the media section will be rejected in answer if the corresponding
3177// MediaDescriptionOptions is stopped by the answerer.
3178TEST_F(MediaSessionDescriptionFactoryTest,
3179 CreateAnswerWithMediaSectionRejectedByAnswerer) {
3180 // Create an offer with two audio sections.
3181 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003182 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3183 RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
3184 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3185 RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003186 std::unique_ptr<SessionDescription> offer(
3187 f1_.CreateOffer(offer_opts, nullptr));
3188 ASSERT_TRUE(offer);
3189 ASSERT_EQ(2u, offer->contents().size());
3190 ASSERT_FALSE(offer->contents()[0].rejected);
3191 ASSERT_FALSE(offer->contents()[1].rejected);
3192
3193 // The answerer rejects one of the audio sections.
3194 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003195 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3196 RtpTransceiverDirection::kSendRecv, kActive, &answer_opts);
3197 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3198 RtpTransceiverDirection::kInactive, kStopped, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003199 std::unique_ptr<SessionDescription> answer(
3200 f2_.CreateAnswer(offer.get(), answer_opts, nullptr));
3201 ASSERT_EQ(2u, answer->contents().size());
3202 EXPECT_FALSE(answer->contents()[0].rejected);
3203 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08003204
3205 // The TransportInfo of the rejected m= section is expected to be added in the
3206 // answer.
3207 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07003208}
3209
3210// Test the generated media sections has the same order of the
3211// corresponding MediaDescriptionOptions.
3212TEST_F(MediaSessionDescriptionFactoryTest,
3213 CreateOfferRespectsMediaDescriptionOptionsOrder) {
3214 MediaSessionOptions opts;
3215 // This tests put video section first because normally audio comes first by
3216 // default.
Steve Anton4e70a722017-11-28 14:57:10 -08003217 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
3218 kActive, &opts);
3219 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kSendRecv,
3220 kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003221 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3222
3223 ASSERT_TRUE(offer);
3224 ASSERT_EQ(2u, offer->contents().size());
3225 EXPECT_EQ("video", offer->contents()[0].name);
3226 EXPECT_EQ("audio", offer->contents()[1].name);
3227}
3228
3229// Test that different media sections using the same codec have same payload
3230// type.
3231TEST_F(MediaSessionDescriptionFactoryTest,
3232 PayloadTypesSharedByMediaSectionsOfSameType) {
3233 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003234 AddMediaSection(MEDIA_TYPE_VIDEO, "video1",
3235 RtpTransceiverDirection::kSendRecv, kActive, &opts);
3236 AddMediaSection(MEDIA_TYPE_VIDEO, "video2",
3237 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003238 // Create an offer with two video sections using same codecs.
3239 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3240 ASSERT_TRUE(offer);
3241 ASSERT_EQ(2u, offer->contents().size());
3242 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003243 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003244 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003245 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003246 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3247 ASSERT_EQ(2u, vcd1->codecs().size());
3248 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3249 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3250 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
3251 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
3252
3253 // Create answer and negotiate the codecs.
3254 std::unique_ptr<SessionDescription> answer(
3255 f2_.CreateAnswer(offer.get(), opts, nullptr));
3256 ASSERT_TRUE(answer);
3257 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08003258 vcd1 = answer->contents()[0].media_description()->as_video();
3259 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003260 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3261 ASSERT_EQ(1u, vcd1->codecs().size());
3262 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3263 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3264}
3265
3266// Test that the codec preference order per media section is respected in
3267// subsequent offer.
3268TEST_F(MediaSessionDescriptionFactoryTest,
3269 CreateOfferRespectsCodecPreferenceOrder) {
3270 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003271 AddMediaSection(MEDIA_TYPE_VIDEO, "video1",
3272 RtpTransceiverDirection::kSendRecv, kActive, &opts);
3273 AddMediaSection(MEDIA_TYPE_VIDEO, "video2",
3274 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003275 // Create an offer with two video sections using same codecs.
3276 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3277 ASSERT_TRUE(offer);
3278 ASSERT_EQ(2u, offer->contents().size());
3279 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003280 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003281 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003282 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003283 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3284 EXPECT_EQ(video_codecs, vcd1->codecs());
3285 EXPECT_EQ(video_codecs, vcd2->codecs());
3286
3287 // Change the codec preference of the first video section and create a
3288 // follow-up offer.
3289 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3290 vcd1->set_codecs(video_codecs_reverse);
3291 std::unique_ptr<SessionDescription> updated_offer(
3292 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08003293 vcd1 = updated_offer->contents()[0].media_description()->as_video();
3294 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003295 // The video codec preference order should be respected.
3296 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3297 EXPECT_EQ(video_codecs, vcd2->codecs());
3298}
3299
3300// Test that the codec preference order per media section is respected in
3301// the answer.
3302TEST_F(MediaSessionDescriptionFactoryTest,
3303 CreateAnswerRespectsCodecPreferenceOrder) {
3304 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003305 AddMediaSection(MEDIA_TYPE_VIDEO, "video1",
3306 RtpTransceiverDirection::kSendRecv, kActive, &opts);
3307 AddMediaSection(MEDIA_TYPE_VIDEO, "video2",
3308 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003309 // Create an offer with two video sections using same codecs.
3310 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3311 ASSERT_TRUE(offer);
3312 ASSERT_EQ(2u, offer->contents().size());
3313 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003314 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003315 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003316 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003317 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3318 EXPECT_EQ(video_codecs, vcd1->codecs());
3319 EXPECT_EQ(video_codecs, vcd2->codecs());
3320
3321 // Change the codec preference of the first video section and create an
3322 // answer.
3323 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3324 vcd1->set_codecs(video_codecs_reverse);
3325 std::unique_ptr<SessionDescription> answer(
3326 f1_.CreateAnswer(offer.get(), opts, nullptr));
Steve Antonb1c1de12017-12-21 15:14:30 -08003327 vcd1 = answer->contents()[0].media_description()->as_video();
3328 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003329 // The video codec preference order should be respected.
3330 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3331 EXPECT_EQ(video_codecs, vcd2->codecs());
3332}
3333
Zhi Huang6f367472017-11-22 13:20:02 -08003334// Test that when creating an answer, the codecs use local parameters instead of
3335// the remote ones.
3336TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
3337 const std::string audio_param_name = "audio_param";
3338 const std::string audio_value1 = "audio_v1";
3339 const std::string audio_value2 = "audio_v2";
3340 const std::string video_param_name = "video_param";
3341 const std::string video_value1 = "video_v1";
3342 const std::string video_value2 = "video_v2";
3343
3344 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
3345 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
3346 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
3347 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
3348
3349 // Set the parameters for codecs.
3350 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
3351 video_codecs1[0].SetParam(video_param_name, video_value1);
3352 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
3353 video_codecs2[0].SetParam(video_param_name, video_value2);
3354
3355 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
3356 f1_.set_video_codecs(video_codecs1);
3357 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
3358 f2_.set_video_codecs(video_codecs2);
3359
3360 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003361 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kSendRecv,
3362 kActive, &opts);
3363 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
3364 kActive, &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08003365
3366 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3367 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08003368 auto offer_acd = offer->contents()[0].media_description()->as_audio();
3369 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08003370 std::string value;
3371 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
3372 EXPECT_EQ(audio_value1, value);
3373 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
3374 EXPECT_EQ(video_value1, value);
3375
3376 std::unique_ptr<SessionDescription> answer(
3377 f2_.CreateAnswer(offer.get(), opts, nullptr));
3378 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08003379 auto answer_acd = answer->contents()[0].media_description()->as_audio();
3380 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08003381 // Use the parameters from the local codecs.
3382 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
3383 EXPECT_EQ(audio_value2, value);
3384 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
3385 EXPECT_EQ(video_value2, value);
3386}
3387
Steve Anton9c1fb1e2018-02-26 15:09:41 -08003388// Test that matching packetization-mode is part of the criteria for matching
3389// H264 codecs (in addition to profile-level-id). Previously, this was not the
3390// case, so the first H264 codec with the same profile-level-id would match and
3391// the payload type in the answer would be incorrect.
3392// This is a regression test for bugs.webrtc.org/8808
3393TEST_F(MediaSessionDescriptionFactoryTest,
3394 H264MatchCriteriaIncludesPacketizationMode) {
3395 // Create two H264 codecs with the same profile level ID and different
3396 // packetization modes.
3397 VideoCodec h264_pm0(96, "H264");
3398 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
3399 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
3400 VideoCodec h264_pm1(97, "H264");
3401 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
3402 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
3403
3404 // Offerer will send both codecs, answerer should choose the one with matching
3405 // packetization mode (and not the first one it sees).
3406 f1_.set_video_codecs({h264_pm0, h264_pm1});
3407 f2_.set_video_codecs({h264_pm1});
3408
3409 MediaSessionOptions opts;
3410 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
3411 kActive, &opts);
3412
3413 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3414 ASSERT_TRUE(offer);
3415
3416 std::unique_ptr<SessionDescription> answer(
3417 f2_.CreateAnswer(offer.get(), opts, nullptr));
3418 ASSERT_TRUE(answer);
3419
3420 // Answer should have one negotiated codec with packetization-mode=1 using the
3421 // offered payload type.
3422 ASSERT_EQ(1u, answer->contents().size());
3423 auto answer_vcd = answer->contents()[0].media_description()->as_video();
3424 ASSERT_EQ(1u, answer_vcd->codecs().size());
3425 auto answer_codec = answer_vcd->codecs()[0];
3426 EXPECT_EQ(h264_pm1.id, answer_codec.id);
3427}
3428
zhihuangcf5b37c2016-05-05 11:44:35 -07003429class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
3430 public:
3431 MediaProtocolTest() : f1_(&tdf1_), f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -07003432 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
3433 MAKE_VECTOR(kAudioCodecs1));
zhihuangcf5b37c2016-05-05 11:44:35 -07003434 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
3435 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07003436 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
3437 MAKE_VECTOR(kAudioCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07003438 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
3439 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
3440 f1_.set_secure(SEC_ENABLED);
3441 f2_.set_secure(SEC_ENABLED);
3442 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07003443 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07003444 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07003445 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07003446 tdf1_.set_secure(SEC_ENABLED);
3447 tdf2_.set_secure(SEC_ENABLED);
3448 }
3449
3450 protected:
3451 MediaSessionDescriptionFactory f1_;
3452 MediaSessionDescriptionFactory f2_;
3453 TransportDescriptionFactory tdf1_;
3454 TransportDescriptionFactory tdf2_;
3455};
3456
3457TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
3458 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003459 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
zhihuangcf5b37c2016-05-05 11:44:35 -07003460 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3461 ASSERT_TRUE(offer.get() != nullptr);
3462 // Set the protocol for all the contents.
3463 for (auto content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08003464 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07003465 }
3466 std::unique_ptr<SessionDescription> answer(
3467 f2_.CreateAnswer(offer.get(), opts, nullptr));
3468 const ContentInfo* ac = answer->GetContentByName("audio");
3469 const ContentInfo* vc = answer->GetContentByName("video");
3470 ASSERT_TRUE(ac != nullptr);
3471 ASSERT_TRUE(vc != nullptr);
3472 EXPECT_FALSE(ac->rejected); // the offer is accepted
3473 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003474 const AudioContentDescription* acd = ac->media_description()->as_audio();
3475 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07003476 EXPECT_EQ(GetParam(), acd->protocol());
3477 EXPECT_EQ(GetParam(), vcd->protocol());
3478}
3479
3480INSTANTIATE_TEST_CASE_P(MediaProtocolPatternTest,
3481 MediaProtocolTest,
3482 ::testing::ValuesIn(kMediaProtocols));
3483INSTANTIATE_TEST_CASE_P(MediaProtocolDtlsPatternTest,
3484 MediaProtocolTest,
3485 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07003486
3487TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
3488 TransportDescriptionFactory tdf;
3489 MediaSessionDescriptionFactory sf(&tdf);
3490 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
3491 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
3492
3493 // The merged list of codecs should contain any send codecs that are also
3494 // nominally in the recieve codecs list. Payload types should be picked from
3495 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
3496 // (set to 1). This equals what happens when the send codecs are used in an
3497 // offer and the receive codecs are used in the following answer.
3498 const std::vector<AudioCodec> sendrecv_codecs =
3499 MAKE_VECTOR(kAudioCodecsAnswer);
3500 const std::vector<AudioCodec> no_codecs;
3501
3502 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
3503 << "Please don't change shared test data!";
3504 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
3505 << "Please don't change shared test data!";
3506 // Alter iLBC send codec to have zero channels, to test that that is handled
3507 // properly.
3508 send_codecs[1].channels = 0;
3509
3510 // Alther iLBC receive codec to be lowercase, to test that case conversions
3511 // are handled properly.
3512 recv_codecs[2].name = "ilbc";
3513
3514 // Test proper merge
3515 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003516 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
3517 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
3518 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003519
3520 // Test empty send codecs list
3521 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003522 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
3523 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
3524 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003525
3526 // Test empty recv codecs list
3527 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003528 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
3529 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
3530 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003531
3532 // Test all empty codec lists
3533 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003534 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
3535 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
3536 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003537}
3538
3539namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07003540// Compare the two vectors of codecs ignoring the payload type.
3541template <class Codec>
3542bool CodecsMatch(const std::vector<Codec>& codecs1,
3543 const std::vector<Codec>& codecs2) {
3544 if (codecs1.size() != codecs2.size()) {
3545 return false;
3546 }
3547
3548 for (size_t i = 0; i < codecs1.size(); ++i) {
3549 if (!codecs1[i].Matches(codecs2[i])) {
3550 return false;
3551 }
3552 }
3553 return true;
3554}
3555
Steve Anton4e70a722017-11-28 14:57:10 -08003556void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07003557 TransportDescriptionFactory tdf;
3558 MediaSessionDescriptionFactory sf(&tdf);
3559 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
3560 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
3561 const std::vector<AudioCodec> sendrecv_codecs =
3562 MAKE_VECTOR(kAudioCodecsAnswer);
3563 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07003564
3565 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003566 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", direction, kActive, &opts);
3567
Steve Anton4e70a722017-11-28 14:57:10 -08003568 if (direction == RtpTransceiverDirection::kSendRecv ||
3569 direction == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003570 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003571 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003572 }
ossu075af922016-06-14 03:29:38 -07003573
3574 std::unique_ptr<SessionDescription> offer(sf.CreateOffer(opts, NULL));
3575 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003576 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07003577
3578 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07003579 // that the codecs put in are right. This happens when we neither want to
3580 // send nor receive audio. The checks are still in place if at some point
3581 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07003582 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08003583 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003584 // sendrecv and inactive should both present lists as if the channel was
3585 // to be used for sending and receiving. Inactive essentially means it
3586 // might eventually be used anything, but we don't know more at this
3587 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08003588 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003589 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08003590 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003591 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07003592 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07003593 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07003594 }
3595 }
3596}
3597
3598static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07003599 AudioCodec(0, "codec0", 16000, -1, 1),
3600 AudioCodec(1, "codec1", 8000, 13300, 1),
3601 AudioCodec(2, "codec2", 8000, 64000, 1),
3602 AudioCodec(3, "codec3", 8000, 64000, 1),
3603 AudioCodec(4, "codec4", 8000, 0, 2),
3604 AudioCodec(5, "codec5", 32000, 0, 1),
3605 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07003606
zhihuang1c378ed2017-08-17 14:10:50 -07003607/* The codecs groups below are chosen as per the matrix below. The objective
3608 * is to have different sets of codecs in the inputs, to get unique sets of
3609 * codecs after negotiation, depending on offer and answer communication
3610 * directions. One-way directions in the offer should either result in the
3611 * opposite direction in the answer, or an inactive answer. Regardless, the
3612 * choice of codecs should be as if the answer contained the opposite
3613 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07003614 *
3615 * | Offer | Answer | Result
3616 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
3617 * 0 | x - - | - x - | x - - - -
3618 * 1 | x x x | - x - | x - - x -
3619 * 2 | - x - | x - - | - x - - -
3620 * 3 | x x x | x - - | - x x - -
3621 * 4 | - x - | x x x | - x - - -
3622 * 5 | x - - | x x x | x - - - -
3623 * 6 | x x x | x x x | x x x x x
3624 */
3625// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07003626static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
3627static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07003628// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
3629// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07003630static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
3631static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07003632// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07003633static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
3634static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
3635static const int kResultSendrecv_SendCodecs[] = {3, 6};
3636static const int kResultSendrecv_RecvCodecs[] = {1, 6};
3637static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07003638
3639template <typename T, int IDXS>
3640std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
3641 std::vector<T> out;
3642 out.reserve(IDXS);
3643 for (int idx : indices)
3644 out.push_back(array[idx]);
3645
3646 return out;
3647}
3648
Steve Anton4e70a722017-11-28 14:57:10 -08003649void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
3650 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07003651 bool add_legacy_stream) {
3652 TransportDescriptionFactory offer_tdf;
3653 TransportDescriptionFactory answer_tdf;
3654 MediaSessionDescriptionFactory offer_factory(&offer_tdf);
3655 MediaSessionDescriptionFactory answer_factory(&answer_tdf);
3656 offer_factory.set_audio_codecs(
3657 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
3658 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
3659 answer_factory.set_audio_codecs(
3660 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
3661 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
3662
ossu075af922016-06-14 03:29:38 -07003663 MediaSessionOptions offer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003664 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", offer_direction, kActive,
3665 &offer_opts);
3666
Steve Anton4e70a722017-11-28 14:57:10 -08003667 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
zhihuang1c378ed2017-08-17 14:10:50 -07003668 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003669 {kMediaStream1}, 1, &offer_opts);
ossu075af922016-06-14 03:29:38 -07003670 }
3671
3672 std::unique_ptr<SessionDescription> offer(
3673 offer_factory.CreateOffer(offer_opts, NULL));
3674 ASSERT_TRUE(offer.get() != NULL);
3675
3676 MediaSessionOptions answer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003677 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", answer_direction, kActive,
3678 &answer_opts);
3679
Steve Anton4e70a722017-11-28 14:57:10 -08003680 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
zhihuang1c378ed2017-08-17 14:10:50 -07003681 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003682 {kMediaStream1}, 1, &answer_opts);
ossu075af922016-06-14 03:29:38 -07003683 }
3684 std::unique_ptr<SessionDescription> answer(
3685 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL));
3686 const ContentInfo* ac = answer->GetContentByName("audio");
3687
zhihuang1c378ed2017-08-17 14:10:50 -07003688 // If the factory didn't add any audio content to the answer, we cannot
3689 // check that the codecs put in are right. This happens when we neither want
3690 // to send nor receive audio. The checks are still in place if at some point
3691 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07003692 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08003693 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
3694 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07003695
ossu075af922016-06-14 03:29:38 -07003696 std::vector<AudioCodec> target_codecs;
3697 // For offers with sendrecv or inactive, we should never reply with more
3698 // codecs than offered, with these codec sets.
3699 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08003700 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07003701 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
3702 kResultSendrecv_SendrecvCodecs);
3703 break;
Steve Anton4e70a722017-11-28 14:57:10 -08003704 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07003705 target_codecs =
3706 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07003707 break;
Steve Anton4e70a722017-11-28 14:57:10 -08003708 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07003709 target_codecs =
3710 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07003711 break;
Steve Anton4e70a722017-11-28 14:57:10 -08003712 case RtpTransceiverDirection::kSendRecv:
3713 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003714 target_codecs =
3715 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08003716 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003717 target_codecs =
3718 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07003719 } else {
3720 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
3721 kResultSendrecv_SendrecvCodecs);
3722 }
3723 break;
3724 }
3725
zhihuang1c378ed2017-08-17 14:10:50 -07003726 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
ossu075af922016-06-14 03:29:38 -07003727 std::stringstream os;
3728 bool first = true;
3729 os << "{";
3730 for (const auto& c : codecs) {
3731 os << (first ? " " : ", ") << c.id;
3732 first = false;
3733 }
3734 os << " }";
3735 return os.str();
3736 };
3737
3738 EXPECT_TRUE(acd->codecs() == target_codecs)
3739 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08003740 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
3741 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07003742 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08003743 << webrtc::RtpTransceiverDirectionToString(answer_direction)
3744 << "; got: "
3745 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07003746 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08003747 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07003748 << "Only inactive offers are allowed to not generate any audio "
3749 "content";
ossu075af922016-06-14 03:29:38 -07003750 }
3751}
brandtr03d5fb12016-11-22 03:37:59 -08003752
3753} // namespace
ossu075af922016-06-14 03:29:38 -07003754
3755class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08003756 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07003757
3758TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003759 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07003760}
3761
3762INSTANTIATE_TEST_CASE_P(MediaSessionDescriptionFactoryTest,
3763 AudioCodecsOfferTest,
Steve Anton4e70a722017-11-28 14:57:10 -08003764 ::testing::Values(RtpTransceiverDirection::kSendOnly,
3765 RtpTransceiverDirection::kRecvOnly,
3766 RtpTransceiverDirection::kSendRecv,
3767 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07003768
3769class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08003770 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
3771 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07003772 bool>> {};
ossu075af922016-06-14 03:29:38 -07003773
3774TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08003775 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
3776 ::testing::get<1>(GetParam()),
3777 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07003778}
3779
zhihuang1c378ed2017-08-17 14:10:50 -07003780INSTANTIATE_TEST_CASE_P(
3781 MediaSessionDescriptionFactoryTest,
3782 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08003783 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
3784 RtpTransceiverDirection::kRecvOnly,
3785 RtpTransceiverDirection::kSendRecv,
3786 RtpTransceiverDirection::kInactive),
3787 ::testing::Values(RtpTransceiverDirection::kSendOnly,
3788 RtpTransceiverDirection::kRecvOnly,
3789 RtpTransceiverDirection::kSendRecv,
3790 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07003791 ::testing::Bool()));