blob: 076ad12a5b34980c00c31209749a1eb536fc34d4 [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"
Jonas Olsson366a50c2018-09-06 13:41:30 +020028#include "rtc_base/strings/string_builder.h"
Steve Antone38a5a12018-11-21 16:05:15 -080029#include "test/gmock.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000030
Yves Gerey665174f2018-06-19 15:03:05 +020031#define ASSERT_CRYPTO(cd, s, cs) \
32 ASSERT_EQ(s, cd->cryptos().size()); \
Steve Antone38a5a12018-11-21 16:05:15 -080033 ASSERT_EQ(cs, cd->cryptos()[0].cipher_suite)
henrike@webrtc.org28e20752013-07-10 00:45:36 +000034
35typedef std::vector<cricket::Candidate> Candidates;
36
37using cricket::MediaContentDescription;
38using cricket::MediaSessionDescriptionFactory;
zhihuang1c378ed2017-08-17 14:10:50 -070039using cricket::MediaDescriptionOptions;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000040using cricket::MediaSessionOptions;
41using cricket::MediaType;
Steve Anton5adfafd2017-12-20 16:34:00 -080042using cricket::MediaProtocolType;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000043using cricket::SessionDescription;
44using cricket::SsrcGroup;
45using cricket::StreamParams;
46using cricket::StreamParamsVec;
47using cricket::TransportDescription;
48using cricket::TransportDescriptionFactory;
49using cricket::TransportInfo;
50using cricket::ContentInfo;
51using cricket::CryptoParamsVec;
52using cricket::AudioContentDescription;
53using cricket::VideoContentDescription;
54using cricket::DataContentDescription;
deadbeef44f08192015-12-15 16:20:09 -080055using cricket::GetFirstAudioContent;
56using cricket::GetFirstVideoContent;
57using cricket::GetFirstDataContent;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000058using cricket::GetFirstAudioContentDescription;
59using cricket::GetFirstVideoContentDescription;
60using cricket::GetFirstDataContentDescription;
61using cricket::kAutoBandwidth;
62using cricket::AudioCodec;
63using cricket::VideoCodec;
64using cricket::DataCodec;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000065using cricket::MEDIA_TYPE_AUDIO;
66using cricket::MEDIA_TYPE_VIDEO;
67using cricket::MEDIA_TYPE_DATA;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000068using cricket::SEC_DISABLED;
69using cricket::SEC_ENABLED;
70using cricket::SEC_REQUIRED;
Guo-wei Shieh456696a2015-09-30 21:48:54 -070071using rtc::CS_AES_CM_128_HMAC_SHA1_32;
72using rtc::CS_AES_CM_128_HMAC_SHA1_80;
jbauchcb560652016-08-04 05:20:32 -070073using rtc::CS_AEAD_AES_128_GCM;
74using rtc::CS_AEAD_AES_256_GCM;
Steve Antone38a5a12018-11-21 16:05:15 -080075using testing::ElementsAreArray;
isheriff6f8d6862016-05-26 11:24:55 -070076using webrtc::RtpExtension;
Steve Anton4e70a722017-11-28 14:57:10 -080077using webrtc::RtpTransceiverDirection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000078
79static const AudioCodec kAudioCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070080 AudioCodec(103, "ISAC", 16000, -1, 1),
81 AudioCodec(102, "iLBC", 8000, 13300, 1),
82 AudioCodec(0, "PCMU", 8000, 64000, 1),
83 AudioCodec(8, "PCMA", 8000, 64000, 1),
84 AudioCodec(117, "red", 8000, 0, 1),
85 AudioCodec(107, "CN", 48000, 0, 1)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +000086
87static const AudioCodec kAudioCodecs2[] = {
Henrik Lundinf8ed5612018-05-07 12:05:57 +020088 AudioCodec(126, "foo", 16000, 22000, 1),
deadbeef67cf2c12016-04-13 10:07:16 -070089 AudioCodec(0, "PCMU", 8000, 64000, 1),
90 AudioCodec(127, "iLBC", 8000, 13300, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +000091};
92
93static const AudioCodec kAudioCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070094 AudioCodec(102, "iLBC", 8000, 13300, 1),
95 AudioCodec(0, "PCMU", 8000, 64000, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +000096};
97
perkj26752742016-10-24 01:21:16 -070098static const VideoCodec kVideoCodecs1[] = {VideoCodec(96, "H264-SVC"),
99 VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000100
zhihuang1c378ed2017-08-17 14:10:50 -0700101static const VideoCodec kVideoCodecs1Reverse[] = {VideoCodec(97, "H264"),
102 VideoCodec(96, "H264-SVC")};
103
perkj26752742016-10-24 01:21:16 -0700104static const VideoCodec kVideoCodecs2[] = {VideoCodec(126, "H264"),
105 VideoCodec(127, "H263")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000106
perkj26752742016-10-24 01:21:16 -0700107static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000108
deadbeef67cf2c12016-04-13 10:07:16 -0700109static const DataCodec kDataCodecs1[] = {DataCodec(98, "binary-data"),
110 DataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000111
deadbeef67cf2c12016-04-13 10:07:16 -0700112static const DataCodec kDataCodecs2[] = {DataCodec(126, "binary-data"),
113 DataCodec(127, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000114
deadbeef67cf2c12016-04-13 10:07:16 -0700115static const DataCodec kDataCodecsAnswer[] = {DataCodec(98, "binary-data"),
116 DataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000117
isheriff6f8d6862016-05-26 11:24:55 -0700118static const RtpExtension kAudioRtpExtension1[] = {
119 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
120 RtpExtension("http://google.com/testing/audio_something", 10),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000121};
122
jbauch5869f502017-06-29 12:31:36 -0700123static const RtpExtension kAudioRtpExtensionEncrypted1[] = {
124 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
125 RtpExtension("http://google.com/testing/audio_something", 10),
126 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
127};
128
isheriff6f8d6862016-05-26 11:24:55 -0700129static const RtpExtension kAudioRtpExtension2[] = {
130 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
131 RtpExtension("http://google.com/testing/audio_something_else", 8),
132 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000133};
134
isheriff6f8d6862016-05-26 11:24:55 -0700135static const RtpExtension kAudioRtpExtension3[] = {
136 RtpExtension("http://google.com/testing/audio_something", 2),
137 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
deadbeefa5b273a2015-08-20 17:30:13 -0700138};
139
jbauch5869f502017-06-29 12:31:36 -0700140static const RtpExtension kAudioRtpExtension3ForEncryption[] = {
141 RtpExtension("http://google.com/testing/audio_something", 2),
142 // Use RTP extension that supports encryption.
143 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
144};
145
146static const RtpExtension kAudioRtpExtension3ForEncryptionOffer[] = {
147 RtpExtension("http://google.com/testing/audio_something", 2),
148 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
149 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14, true),
150};
151
isheriff6f8d6862016-05-26 11:24:55 -0700152static const RtpExtension kAudioRtpExtensionAnswer[] = {
153 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000154};
155
jbauch5869f502017-06-29 12:31:36 -0700156static const RtpExtension kAudioRtpExtensionEncryptedAnswer[] = {
157 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
158};
159
isheriff6f8d6862016-05-26 11:24:55 -0700160static const RtpExtension kVideoRtpExtension1[] = {
161 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
162 RtpExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000163};
164
jbauch5869f502017-06-29 12:31:36 -0700165static const RtpExtension kVideoRtpExtensionEncrypted1[] = {
166 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
167 RtpExtension("http://google.com/testing/video_something", 13),
168 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
169};
170
isheriff6f8d6862016-05-26 11:24:55 -0700171static const RtpExtension kVideoRtpExtension2[] = {
172 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
173 RtpExtension("http://google.com/testing/video_something_else", 14),
174 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000175};
176
isheriff6f8d6862016-05-26 11:24:55 -0700177static const RtpExtension kVideoRtpExtension3[] = {
178 RtpExtension("http://google.com/testing/video_something", 4),
179 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
deadbeefa5b273a2015-08-20 17:30:13 -0700180};
181
jbauch5869f502017-06-29 12:31:36 -0700182static const RtpExtension kVideoRtpExtension3ForEncryption[] = {
183 RtpExtension("http://google.com/testing/video_something", 4),
184 // Use RTP extension that supports encryption.
185 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 5),
186};
187
isheriff6f8d6862016-05-26 11:24:55 -0700188static const RtpExtension kVideoRtpExtensionAnswer[] = {
189 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000190};
191
jbauch5869f502017-06-29 12:31:36 -0700192static const RtpExtension kVideoRtpExtensionEncryptedAnswer[] = {
193 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
194};
195
Peter Boström0c4e06b2015-10-07 12:23:21 +0200196static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
197static const uint32_t kSimSsrc[] = {10, 20, 30};
198static const uint32_t kFec1Ssrc[] = {10, 11};
199static const uint32_t kFec2Ssrc[] = {20, 21};
200static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000201
202static const char kMediaStream1[] = "stream_1";
203static const char kMediaStream2[] = "stream_2";
204static const char kVideoTrack1[] = "video_1";
205static const char kVideoTrack2[] = "video_2";
206static const char kAudioTrack1[] = "audio_1";
207static const char kAudioTrack2[] = "audio_2";
208static const char kAudioTrack3[] = "audio_3";
209static const char kDataTrack1[] = "data_1";
210static const char kDataTrack2[] = "data_2";
211static const char kDataTrack3[] = "data_3";
212
zhihuangcf5b37c2016-05-05 11:44:35 -0700213static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
214 "RTP/SAVPF"};
215static const char* kMediaProtocolsDtls[] = {
216 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
217 "UDP/TLS/RTP/SAVP"};
218
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700219// SRTP cipher name negotiated by the tests. This must be updated if the
220// default changes.
221static const char* kDefaultSrtpCryptoSuite = CS_AES_CM_128_HMAC_SHA1_80;
222static const char* kDefaultSrtpCryptoSuiteGcm = CS_AEAD_AES_256_GCM;
223
zhihuang1c378ed2017-08-17 14:10:50 -0700224// These constants are used to make the code using "AddMediaSection" more
225// readable.
226static constexpr bool kStopped = true;
227static constexpr bool kActive = false;
228
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000229static bool IsMediaContentOfType(const ContentInfo* content,
230 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800231 RTC_DCHECK(content);
232 return content->media_description()->type() == media_type;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000233}
234
Steve Anton4e70a722017-11-28 14:57:10 -0800235static RtpTransceiverDirection GetMediaDirection(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800236 RTC_DCHECK(content);
237 return content->media_description()->direction();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000238}
239
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000240static void AddRtxCodec(const VideoCodec& rtx_codec,
241 std::vector<VideoCodec>* codecs) {
magjedb05fa242016-11-11 04:00:16 -0800242 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000243 codecs->push_back(rtx_codec);
244}
245
246template <class T>
247static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
248 std::vector<std::string> codec_names;
249 for (const auto& codec : codecs) {
250 codec_names.push_back(codec.name);
251 }
252 return codec_names;
253}
254
zhihuang1c378ed2017-08-17 14:10:50 -0700255// This is used for test only. MIDs are not the identification of the
256// MediaDescriptionOptions since some end points may not support MID and the SDP
257// may not contain 'mid'.
258std::vector<MediaDescriptionOptions>::iterator FindFirstMediaDescriptionByMid(
259 const std::string& mid,
260 MediaSessionOptions* opts) {
261 return std::find_if(
262 opts->media_description_options.begin(),
263 opts->media_description_options.end(),
Steve Anton36b29d12017-10-30 09:57:42 -0700264 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
265}
266
267std::vector<MediaDescriptionOptions>::const_iterator
268FindFirstMediaDescriptionByMid(const std::string& mid,
269 const MediaSessionOptions& opts) {
270 return std::find_if(
271 opts.media_description_options.begin(),
272 opts.media_description_options.end(),
273 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
zhihuang1c378ed2017-08-17 14:10:50 -0700274}
275
276// Add a media section to the |session_options|.
277static void AddMediaSection(MediaType type,
278 const std::string& mid,
Steve Anton4e70a722017-11-28 14:57:10 -0800279 RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700280 bool stopped,
281 MediaSessionOptions* opts) {
Steve Anton4e70a722017-11-28 14:57:10 -0800282 opts->media_description_options.push_back(
283 MediaDescriptionOptions(type, mid, direction, stopped));
zhihuang1c378ed2017-08-17 14:10:50 -0700284}
285
Steve Anton4e70a722017-11-28 14:57:10 -0800286static void AddAudioVideoSections(RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700287 MediaSessionOptions* opts) {
288 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", direction, kActive, opts);
289 AddMediaSection(MEDIA_TYPE_VIDEO, "video", direction, kActive, opts);
290}
291
292static void AddDataSection(cricket::DataChannelType dct,
Steve Anton4e70a722017-11-28 14:57:10 -0800293 RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700294 MediaSessionOptions* opts) {
295 opts->data_channel_type = dct;
296 AddMediaSection(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
297}
298
Steve Anton8ffb9c32017-08-31 15:45:38 -0700299static void AttachSenderToMediaSection(
300 const std::string& mid,
301 MediaType type,
302 const std::string& track_id,
303 const std::vector<std::string>& stream_ids,
304 int num_sim_layer,
305 MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -0700306 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
307 switch (type) {
308 case MEDIA_TYPE_AUDIO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700309 it->AddAudioSender(track_id, stream_ids);
zhihuang1c378ed2017-08-17 14:10:50 -0700310 break;
311 case MEDIA_TYPE_VIDEO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700312 it->AddVideoSender(track_id, stream_ids, num_sim_layer);
zhihuang1c378ed2017-08-17 14:10:50 -0700313 break;
314 case MEDIA_TYPE_DATA:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700315 RTC_CHECK(stream_ids.size() == 1U);
316 it->AddRtpDataChannel(track_id, stream_ids[0]);
zhihuang1c378ed2017-08-17 14:10:50 -0700317 break;
318 default:
319 RTC_NOTREACHED();
320 }
321}
322
323static void DetachSenderFromMediaSection(const std::string& mid,
324 const std::string& track_id,
325 MediaSessionOptions* session_options) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700326 std::vector<cricket::SenderOptions>& sender_options_list =
327 FindFirstMediaDescriptionByMid(mid, session_options)->sender_options;
328 auto sender_it =
329 std::find_if(sender_options_list.begin(), sender_options_list.end(),
330 [track_id](const cricket::SenderOptions& sender_options) {
331 return sender_options.track_id == track_id;
332 });
333 RTC_DCHECK(sender_it != sender_options_list.end());
334 sender_options_list.erase(sender_it);
zhihuang1c378ed2017-08-17 14:10:50 -0700335}
336
337// Helper function used to create a default MediaSessionOptions for Plan B SDP.
338// (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
339static MediaSessionOptions CreatePlanBMediaSessionOptions() {
340 MediaSessionOptions session_options;
Steve Anton4e70a722017-11-28 14:57:10 -0800341 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
342 kActive, &session_options);
zhihuang1c378ed2017-08-17 14:10:50 -0700343 return session_options;
344}
345
346// TODO(zhihuang): Most of these tests were written while MediaSessionOptions
347// was designed for Plan B SDP, where only one audio "m=" section and one video
348// "m=" section could be generated, and ordering couldn't be controlled. Many of
349// these tests may be obsolete as a result, and should be refactored or removed.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000350class MediaSessionDescriptionFactoryTest : public testing::Test {
351 public:
zhihuang1c378ed2017-08-17 14:10:50 -0700352 MediaSessionDescriptionFactoryTest() : f1_(&tdf1_), f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -0700353 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
354 MAKE_VECTOR(kAudioCodecs1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000355 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
356 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700357 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
358 MAKE_VECTOR(kAudioCodecs2));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000359 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
360 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200361 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700362 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200363 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700364 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000365 }
366
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000367 // Create a video StreamParamsVec object with:
368 // - one video stream with 3 simulcast streams and FEC,
369 StreamParamsVec CreateComplexVideoStreamParamsVec() {
370 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
371 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
372 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
373 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
374
375 std::vector<SsrcGroup> ssrc_groups;
376 ssrc_groups.push_back(sim_group);
377 ssrc_groups.push_back(fec_group1);
378 ssrc_groups.push_back(fec_group2);
379 ssrc_groups.push_back(fec_group3);
380
381 StreamParams simulcast_params;
382 simulcast_params.id = kVideoTrack1;
383 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
384 simulcast_params.ssrc_groups = ssrc_groups;
385 simulcast_params.cname = "Video_SIM_FEC";
Seth Hampson845e8782018-03-02 11:34:10 -0800386 simulcast_params.set_stream_ids({kMediaStream1});
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000387
388 StreamParamsVec video_streams;
389 video_streams.push_back(simulcast_params);
390
391 return video_streams;
392 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000393
394 bool CompareCryptoParams(const CryptoParamsVec& c1,
395 const CryptoParamsVec& c2) {
396 if (c1.size() != c2.size())
397 return false;
398 for (size_t i = 0; i < c1.size(); ++i)
399 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
400 c1[i].key_params != c2[i].key_params ||
401 c1[i].session_params != c2[i].session_params)
402 return false;
403 return true;
404 }
405
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700406 // Returns true if the transport info contains "renomination" as an
407 // ICE option.
408 bool GetIceRenomination(const TransportInfo* transport_info) {
409 const std::vector<std::string>& ice_options =
410 transport_info->description.transport_options;
deadbeef30952b42017-04-21 02:41:29 -0700411 auto iter =
412 std::find(ice_options.begin(), ice_options.end(), "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700413 return iter != ice_options.end();
414 }
415
zhihuang1c378ed2017-08-17 14:10:50 -0700416 void TestTransportInfo(bool offer,
Steve Anton36b29d12017-10-30 09:57:42 -0700417 const MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000418 bool has_current_desc) {
419 const std::string current_audio_ufrag = "current_audio_ufrag";
420 const std::string current_audio_pwd = "current_audio_pwd";
421 const std::string current_video_ufrag = "current_video_ufrag";
422 const std::string current_video_pwd = "current_video_pwd";
423 const std::string current_data_ufrag = "current_data_ufrag";
424 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800425 std::unique_ptr<SessionDescription> current_desc;
426 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000427 if (has_current_desc) {
428 current_desc.reset(new SessionDescription());
Yves Gerey665174f2018-06-19 15:03:05 +0200429 EXPECT_TRUE(current_desc->AddTransportInfo(TransportInfo(
430 "audio",
431 TransportDescription(current_audio_ufrag, current_audio_pwd))));
432 EXPECT_TRUE(current_desc->AddTransportInfo(TransportInfo(
433 "video",
434 TransportDescription(current_video_ufrag, current_video_pwd))));
435 EXPECT_TRUE(current_desc->AddTransportInfo(TransportInfo(
436 "data", TransportDescription(current_data_ufrag, current_data_pwd))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000437 }
438 if (offer) {
439 desc.reset(f1_.CreateOffer(options, current_desc.get()));
440 } else {
kwiberg31022942016-03-11 14:18:21 -0800441 std::unique_ptr<SessionDescription> offer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000442 offer.reset(f1_.CreateOffer(options, NULL));
443 desc.reset(f1_.CreateAnswer(offer.get(), options, current_desc.get()));
444 }
445 ASSERT_TRUE(desc.get() != NULL);
446 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000447 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000448 EXPECT_TRUE(ti_audio != NULL);
449 if (has_current_desc) {
450 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
451 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
452 } else {
453 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
454 ti_audio->description.ice_ufrag.size());
455 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
456 ti_audio->description.ice_pwd.size());
457 }
zhihuang1c378ed2017-08-17 14:10:50 -0700458 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700459 FindFirstMediaDescriptionByMid("audio", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700460 EXPECT_EQ(
461 media_desc_options_it->transport_options.enable_ice_renomination,
462 GetIceRenomination(ti_audio));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000463
464 } else {
465 EXPECT_TRUE(ti_audio == NULL);
466 }
467 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000468 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000469 EXPECT_TRUE(ti_video != NULL);
470 if (options.bundle_enabled) {
471 EXPECT_EQ(ti_audio->description.ice_ufrag,
472 ti_video->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200473 EXPECT_EQ(ti_audio->description.ice_pwd, ti_video->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000474 } else {
475 if (has_current_desc) {
476 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
477 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
478 } else {
479 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
480 ti_video->description.ice_ufrag.size());
481 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
482 ti_video->description.ice_pwd.size());
483 }
484 }
zhihuang1c378ed2017-08-17 14:10:50 -0700485 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700486 FindFirstMediaDescriptionByMid("video", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700487 EXPECT_EQ(
488 media_desc_options_it->transport_options.enable_ice_renomination,
489 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000490 } else {
491 EXPECT_TRUE(ti_video == NULL);
492 }
493 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
494 if (options.has_data()) {
495 EXPECT_TRUE(ti_data != NULL);
496 if (options.bundle_enabled) {
497 EXPECT_EQ(ti_audio->description.ice_ufrag,
498 ti_data->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200499 EXPECT_EQ(ti_audio->description.ice_pwd, ti_data->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000500 } else {
501 if (has_current_desc) {
502 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
503 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
504 } else {
505 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
506 ti_data->description.ice_ufrag.size());
507 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
508 ti_data->description.ice_pwd.size());
509 }
510 }
zhihuang1c378ed2017-08-17 14:10:50 -0700511 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700512 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700513 EXPECT_EQ(
514 media_desc_options_it->transport_options.enable_ice_renomination,
515 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700516
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000517 } else {
518 EXPECT_TRUE(ti_video == NULL);
519 }
520 }
521
522 void TestCryptoWithBundle(bool offer) {
523 f1_.set_secure(SEC_ENABLED);
524 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -0800525 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
526 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
527 &options);
kwiberg31022942016-03-11 14:18:21 -0800528 std::unique_ptr<SessionDescription> ref_desc;
529 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000530 if (offer) {
531 options.bundle_enabled = false;
532 ref_desc.reset(f1_.CreateOffer(options, NULL));
533 options.bundle_enabled = true;
534 desc.reset(f1_.CreateOffer(options, ref_desc.get()));
535 } else {
536 options.bundle_enabled = true;
537 ref_desc.reset(f1_.CreateOffer(options, NULL));
538 desc.reset(f1_.CreateAnswer(ref_desc.get(), options, NULL));
539 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800540 ASSERT_TRUE(desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000541 const cricket::MediaContentDescription* audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800542 desc->GetContentDescriptionByName("audio");
543 ASSERT_TRUE(audio_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000544 const cricket::MediaContentDescription* video_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800545 desc->GetContentDescriptionByName("video");
546 ASSERT_TRUE(video_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000547 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
548 video_media_desc->cryptos()));
549 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
Steve Antone38a5a12018-11-21 16:05:15 -0800550 EXPECT_EQ(kDefaultSrtpCryptoSuite,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000551 audio_media_desc->cryptos()[0].cipher_suite);
552
553 // Verify the selected crypto is one from the reference audio
554 // media content.
555 const cricket::MediaContentDescription* ref_audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800556 ref_desc->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000557 bool found = false;
558 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
559 if (ref_audio_media_desc->cryptos()[i].Matches(
Yves Gerey665174f2018-06-19 15:03:05 +0200560 audio_media_desc->cryptos()[0])) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000561 found = true;
562 break;
563 }
564 }
565 EXPECT_TRUE(found);
566 }
567
568 // This test that the audio and video media direction is set to
569 // |expected_direction_in_answer| in an answer if the offer direction is set
zhihuang1c378ed2017-08-17 14:10:50 -0700570 // to |direction_in_offer| and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000571 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800572 RtpTransceiverDirection direction_in_offer,
573 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700574 MediaSessionOptions offer_opts;
575 AddAudioVideoSections(direction_in_offer, &offer_opts);
576
577 std::unique_ptr<SessionDescription> offer(
578 f1_.CreateOffer(offer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000579 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700580 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000581 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700582 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000583 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000584
zhihuang1c378ed2017-08-17 14:10:50 -0700585 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800586 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -0800587 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -0700588 f2_.CreateAnswer(offer.get(), answer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000589 const AudioContentDescription* acd_answer =
590 GetFirstAudioContentDescription(answer.get());
591 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
592 const VideoContentDescription* vcd_answer =
593 GetFirstVideoContentDescription(answer.get());
594 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
595 }
596
597 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800598 RTC_DCHECK(content);
599 RTC_CHECK(content->media_description());
600 const cricket::AudioContentDescription* audio_desc =
601 content->media_description()->as_audio();
602 RTC_CHECK(audio_desc);
603 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
604 if (codec.name == "CN") {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000605 return false;
Steve Antonb1c1de12017-12-21 15:14:30 -0800606 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000607 }
608 return true;
609 }
610
jbauchcb560652016-08-04 05:20:32 -0700611 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
612 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800613 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700614 offer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_offer;
zhihuang1c378ed2017-08-17 14:10:50 -0700615
jbauchcb560652016-08-04 05:20:32 -0700616 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800617 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700618 answer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_answer;
zhihuang1c378ed2017-08-17 14:10:50 -0700619
jbauchcb560652016-08-04 05:20:32 -0700620 f1_.set_secure(SEC_ENABLED);
621 f2_.set_secure(SEC_ENABLED);
622 std::unique_ptr<SessionDescription> offer(
623 f1_.CreateOffer(offer_opts, NULL));
624 ASSERT_TRUE(offer.get() != NULL);
625 std::unique_ptr<SessionDescription> answer(
626 f2_.CreateAnswer(offer.get(), answer_opts, NULL));
627 const ContentInfo* ac = answer->GetContentByName("audio");
628 const ContentInfo* vc = answer->GetContentByName("video");
629 ASSERT_TRUE(ac != NULL);
630 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800631 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
632 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800633 const AudioContentDescription* acd = ac->media_description()->as_audio();
634 const VideoContentDescription* vcd = vc->media_description()->as_video();
jbauchcb560652016-08-04 05:20:32 -0700635 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800636 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -0700637 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700638 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700639 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
640 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700641 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700642 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700643 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700644 }
645 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800646 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +0200647 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
648 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
jbauchcb560652016-08-04 05:20:32 -0700649 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700650 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700651 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700652 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700653 }
Steve Antone38a5a12018-11-21 16:05:15 -0800654 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
jbauchcb560652016-08-04 05:20:32 -0700655 }
656
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000657 protected:
658 MediaSessionDescriptionFactory f1_;
659 MediaSessionDescriptionFactory f2_;
660 TransportDescriptionFactory tdf1_;
661 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000662};
663
664// Create a typical audio offer, and ensure it matches what we expect.
665TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
666 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800667 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -0700668 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000669 ASSERT_TRUE(offer.get() != NULL);
670 const ContentInfo* ac = offer->GetContentByName("audio");
671 const ContentInfo* vc = offer->GetContentByName("video");
672 ASSERT_TRUE(ac != NULL);
673 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800674 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800675 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000676 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700677 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700678 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000679 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
680 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700681 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800682 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000683}
684
685// Create a typical video offer, and ensure it matches what we expect.
686TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
687 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800688 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000689 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800690 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000691 ASSERT_TRUE(offer.get() != NULL);
692 const ContentInfo* ac = offer->GetContentByName("audio");
693 const ContentInfo* vc = offer->GetContentByName("video");
694 ASSERT_TRUE(ac != NULL);
695 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800696 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
697 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800698 const AudioContentDescription* acd = ac->media_description()->as_audio();
699 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000700 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700701 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700702 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000703 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
704 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700705 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800706 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000707 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
708 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700709 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000710 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
711 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700712 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800713 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000714}
715
716// Test creating an offer with bundle where the Codecs have the same dynamic
717// RTP playlod type. The test verifies that the offer don't contain the
718// duplicate RTP payload types.
719TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
720 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700721 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000722 const DataCodec& offered_data_codec = f2_.data_codecs()[0];
723 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
724 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
725
726 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800727 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
728 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000729 opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800730 std::unique_ptr<SessionDescription> offer(f2_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000731 const VideoContentDescription* vcd =
732 GetFirstVideoContentDescription(offer.get());
733 const AudioContentDescription* acd =
734 GetFirstAudioContentDescription(offer.get());
735 const DataContentDescription* dcd =
736 GetFirstDataContentDescription(offer.get());
737 ASSERT_TRUE(NULL != vcd);
738 ASSERT_TRUE(NULL != acd);
739 ASSERT_TRUE(NULL != dcd);
740 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
741 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
742 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
743 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
744 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
745 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
746}
747
zhihuang1c378ed2017-08-17 14:10:50 -0700748// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000749// after an audio only session has been negotiated.
750TEST_F(MediaSessionDescriptionFactoryTest,
751 TestCreateUpdatedVideoOfferWithBundle) {
752 f1_.set_secure(SEC_ENABLED);
753 f2_.set_secure(SEC_ENABLED);
754 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800755 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
756 kActive, &opts);
757 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kInactive,
758 kStopped, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000759 opts.data_channel_type = cricket::DCT_NONE;
760 opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800761 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
762 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000763 f2_.CreateAnswer(offer.get(), opts, NULL));
764
765 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800766 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
767 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
768 &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000769 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800770 std::unique_ptr<SessionDescription> updated_offer(
771 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000772
773 const AudioContentDescription* acd =
774 GetFirstAudioContentDescription(updated_offer.get());
775 const VideoContentDescription* vcd =
776 GetFirstVideoContentDescription(updated_offer.get());
777 const DataContentDescription* dcd =
778 GetFirstDataContentDescription(updated_offer.get());
779 EXPECT_TRUE(NULL != vcd);
780 EXPECT_TRUE(NULL != acd);
781 EXPECT_TRUE(NULL != dcd);
782
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700783 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800784 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700785 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800786 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700787 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800788 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000789}
deadbeef44f08192015-12-15 16:20:09 -0800790
wu@webrtc.org78187522013-10-07 23:32:02 +0000791// Create a RTP data offer, and ensure it matches what we expect.
792TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000793 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800794 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
795 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000796 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800797 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000798 ASSERT_TRUE(offer.get() != NULL);
799 const ContentInfo* ac = offer->GetContentByName("audio");
800 const ContentInfo* dc = offer->GetContentByName("data");
801 ASSERT_TRUE(ac != NULL);
802 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800803 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
804 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800805 const AudioContentDescription* acd = ac->media_description()->as_audio();
806 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000807 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700808 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700809 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000810 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
811 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700812 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800813 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000814 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
815 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700816 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000817 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +0200818 dcd->bandwidth()); // default bandwidth (auto)
819 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700820 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800821 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000822}
823
wu@webrtc.org78187522013-10-07 23:32:02 +0000824// Create an SCTP data offer with bundle without error.
825TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
826 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000827 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800828 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
wu@webrtc.org78187522013-10-07 23:32:02 +0000829 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800830 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
wu@webrtc.org78187522013-10-07 23:32:02 +0000831 EXPECT_TRUE(offer.get() != NULL);
832 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
833}
834
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000835// Test creating an sctp data channel from an already generated offer.
836TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
837 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000838 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800839 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000840 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800841 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000842 ASSERT_TRUE(offer1.get() != NULL);
843 const ContentInfo* data = offer1->GetContentByName("data");
844 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800845 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000846
847 // Now set data_channel_type to 'none' (default) and make sure that the
848 // datachannel type that gets generated from the previous offer, is of the
849 // same type.
850 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800851 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000852 f1_.CreateOffer(opts, offer1.get()));
853 data = offer2->GetContentByName("data");
854 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800855 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000856}
857
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000858// Create an audio, video offer without legacy StreamParams.
859TEST_F(MediaSessionDescriptionFactoryTest,
860 TestCreateOfferWithoutLegacyStreams) {
861 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800862 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
kwiberg31022942016-03-11 14:18:21 -0800863 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000864 ASSERT_TRUE(offer.get() != NULL);
865 const ContentInfo* ac = offer->GetContentByName("audio");
866 const ContentInfo* vc = offer->GetContentByName("video");
867 ASSERT_TRUE(ac != NULL);
868 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800869 const AudioContentDescription* acd = ac->media_description()->as_audio();
870 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000871
Yves Gerey665174f2018-06-19 15:03:05 +0200872 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
873 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000874}
875
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000876// Creates an audio+video sendonly offer.
877TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700878 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800879 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700880 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700881 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700882 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700883 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000884
zhihuang1c378ed2017-08-17 14:10:50 -0700885 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000886 ASSERT_TRUE(offer.get() != NULL);
887 EXPECT_EQ(2u, offer->contents().size());
888 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
889 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
890
Steve Anton4e70a722017-11-28 14:57:10 -0800891 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
892 GetMediaDirection(&offer->contents()[0]));
893 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
894 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000895}
896
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000897// Verifies that the order of the media contents in the current
898// SessionDescription is preserved in the new SessionDescription.
899TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
900 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800901 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000902
kwiberg31022942016-03-11 14:18:21 -0800903 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000904 ASSERT_TRUE(offer1.get() != NULL);
905 EXPECT_EQ(1u, offer1->contents().size());
906 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
907
Steve Anton4e70a722017-11-28 14:57:10 -0800908 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
909 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -0800910 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000911 f1_.CreateOffer(opts, offer1.get()));
912 ASSERT_TRUE(offer2.get() != NULL);
913 EXPECT_EQ(2u, offer2->contents().size());
914 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
915 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
916
Steve Anton4e70a722017-11-28 14:57:10 -0800917 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
918 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -0800919 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000920 f1_.CreateOffer(opts, offer2.get()));
921 ASSERT_TRUE(offer3.get() != NULL);
922 EXPECT_EQ(3u, offer3->contents().size());
923 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
924 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
925 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000926}
927
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000928// Create a typical audio answer, and ensure it matches what we expect.
929TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
930 f1_.set_secure(SEC_ENABLED);
931 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800932 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -0700933 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000934 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800935 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -0700936 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000937 const ContentInfo* ac = answer->GetContentByName("audio");
938 const ContentInfo* vc = answer->GetContentByName("video");
939 ASSERT_TRUE(ac != NULL);
940 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800941 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800942 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000943 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800944 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -0700945 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000946 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
947 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700948 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800949 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000950}
951
jbauchcb560652016-08-04 05:20:32 -0700952// Create a typical audio answer with GCM ciphers enabled, and ensure it
953// matches what we expect.
954TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
955 f1_.set_secure(SEC_ENABLED);
956 f2_.set_secure(SEC_ENABLED);
zhihuang1c378ed2017-08-17 14:10:50 -0700957 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700958 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
zhihuang1c378ed2017-08-17 14:10:50 -0700959 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
jbauchcb560652016-08-04 05:20:32 -0700960 ASSERT_TRUE(offer.get() != NULL);
961 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -0700962 f2_.CreateAnswer(offer.get(), opts, NULL));
jbauchcb560652016-08-04 05:20:32 -0700963 const ContentInfo* ac = answer->GetContentByName("audio");
964 const ContentInfo* vc = answer->GetContentByName("video");
965 ASSERT_TRUE(ac != NULL);
966 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800967 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800968 const AudioContentDescription* acd = ac->media_description()->as_audio();
jbauchcb560652016-08-04 05:20:32 -0700969 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800970 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -0700971 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700972 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
973 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700974 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -0800975 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
jbauchcb560652016-08-04 05:20:32 -0700976}
977
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000978// Create a typical video answer, and ensure it matches what we expect.
979TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
980 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800981 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000982 f1_.set_secure(SEC_ENABLED);
983 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800984 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000985 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -0800986 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000987 f2_.CreateAnswer(offer.get(), opts, NULL));
988 const ContentInfo* ac = answer->GetContentByName("audio");
989 const ContentInfo* vc = answer->GetContentByName("video");
990 ASSERT_TRUE(ac != NULL);
991 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800992 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
993 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800994 const AudioContentDescription* acd = ac->media_description()->as_audio();
995 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000996 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800997 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000998 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700999 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001000 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001001 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001002 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001003 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +02001004 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
1005 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001006 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001007 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001008}
1009
jbauchcb560652016-08-04 05:20:32 -07001010// Create a typical video answer with GCM ciphers enabled, and ensure it
1011// matches what we expect.
1012TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1013 TestVideoGcmCipher(true, true);
1014}
1015
1016// Create a typical video answer with GCM ciphers enabled for the offer only,
1017// and ensure it matches what we expect.
1018TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1019 TestVideoGcmCipher(true, false);
1020}
1021
1022// Create a typical video answer with GCM ciphers enabled for the answer only,
1023// and ensure it matches what we expect.
1024TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1025 TestVideoGcmCipher(false, true);
1026}
1027
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001028TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001029 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001030 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001031 f1_.set_secure(SEC_ENABLED);
1032 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001033 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001034 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001035 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001036 f2_.CreateAnswer(offer.get(), opts, NULL));
1037 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001038 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001039 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001040 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001041 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1042 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001043 const AudioContentDescription* acd = ac->media_description()->as_audio();
1044 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001045 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001046 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001047 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001048 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001049 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001050 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
zstein4b2e0822017-02-17 19:48:38 -08001051 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001052 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001053 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001054 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001055 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001056 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001057}
1058
jbauchcb560652016-08-04 05:20:32 -07001059TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
zhihuang1c378ed2017-08-17 14:10:50 -07001060 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001061 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001062 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
jbauchcb560652016-08-04 05:20:32 -07001063 f1_.set_secure(SEC_ENABLED);
1064 f2_.set_secure(SEC_ENABLED);
1065 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1066 ASSERT_TRUE(offer.get() != NULL);
1067 std::unique_ptr<SessionDescription> answer(
1068 f2_.CreateAnswer(offer.get(), opts, NULL));
1069 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001070 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -07001071 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001072 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001073 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1074 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001075 const AudioContentDescription* acd = ac->media_description()->as_audio();
1076 const DataContentDescription* dcd = dc->media_description()->as_data();
jbauchcb560652016-08-04 05:20:32 -07001077 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001078 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -07001079 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001080 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001081 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001082 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
zstein4b2e0822017-02-17 19:48:38 -08001083 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001084 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001085 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001086 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001087 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001088 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
zstein4b2e0822017-02-17 19:48:38 -08001089}
1090
1091// The use_sctpmap flag should be set in a DataContentDescription by default.
1092// The answer's use_sctpmap flag should match the offer's.
1093TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1094 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001095 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
zstein4b2e0822017-02-17 19:48:38 -08001096 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1097 ASSERT_TRUE(offer.get() != NULL);
1098 ContentInfo* dc_offer = offer->GetContentByName("data");
1099 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001100 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001101 EXPECT_TRUE(dcd_offer->use_sctpmap());
1102
1103 std::unique_ptr<SessionDescription> answer(
1104 f2_.CreateAnswer(offer.get(), opts, NULL));
1105 const ContentInfo* dc_answer = answer->GetContentByName("data");
1106 ASSERT_TRUE(dc_answer != NULL);
1107 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001108 dc_answer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001109 EXPECT_TRUE(dcd_answer->use_sctpmap());
1110}
1111
1112// The answer's use_sctpmap flag should match the offer's.
1113TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1114 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001115 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
zstein4b2e0822017-02-17 19:48:38 -08001116 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1117 ASSERT_TRUE(offer.get() != NULL);
1118 ContentInfo* dc_offer = offer->GetContentByName("data");
1119 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001120 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001121 dcd_offer->set_use_sctpmap(false);
1122
1123 std::unique_ptr<SessionDescription> answer(
1124 f2_.CreateAnswer(offer.get(), opts, NULL));
1125 const ContentInfo* dc_answer = answer->GetContentByName("data");
1126 ASSERT_TRUE(dc_answer != NULL);
1127 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001128 dc_answer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001129 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001130}
1131
deadbeef8b7e9ad2017-05-25 09:38:55 -07001132// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1133// and "TCP/DTLS/SCTP" offers.
1134TEST_F(MediaSessionDescriptionFactoryTest,
1135 TestCreateDataAnswerToDifferentOfferedProtos) {
1136 // Need to enable DTLS offer/answer generation (disabled by default in this
1137 // test).
1138 f1_.set_secure(SEC_ENABLED);
1139 f2_.set_secure(SEC_ENABLED);
1140 tdf1_.set_secure(SEC_ENABLED);
1141 tdf2_.set_secure(SEC_ENABLED);
1142
1143 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001144 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001145 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
1146 ASSERT_TRUE(offer.get() != nullptr);
1147 ContentInfo* dc_offer = offer->GetContentByName("data");
1148 ASSERT_TRUE(dc_offer != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08001149 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001150
1151 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1152 "TCP/DTLS/SCTP"};
1153 for (const std::string& proto : protos) {
1154 dcd_offer->set_protocol(proto);
1155 std::unique_ptr<SessionDescription> answer(
1156 f2_.CreateAnswer(offer.get(), opts, nullptr));
1157 const ContentInfo* dc_answer = answer->GetContentByName("data");
1158 ASSERT_TRUE(dc_answer != nullptr);
1159 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001160 dc_answer->media_description()->as_data();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001161 EXPECT_FALSE(dc_answer->rejected);
1162 EXPECT_EQ(proto, dcd_answer->protocol());
1163 }
1164}
1165
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001166// Verifies that the order of the media contents in the offer is preserved in
1167// the answer.
1168TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1169 MediaSessionOptions opts;
1170
1171 // Creates a data only offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001172 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001173 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001174 ASSERT_TRUE(offer1.get() != NULL);
1175
1176 // Appends audio to the offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001177 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
1178 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -08001179 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001180 f1_.CreateOffer(opts, offer1.get()));
1181 ASSERT_TRUE(offer2.get() != NULL);
1182
1183 // Appends video to the offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001184 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
1185 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -08001186 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001187 f1_.CreateOffer(opts, offer2.get()));
1188 ASSERT_TRUE(offer3.get() != NULL);
1189
kwiberg31022942016-03-11 14:18:21 -08001190 std::unique_ptr<SessionDescription> answer(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001191 f2_.CreateAnswer(offer3.get(), opts, NULL));
1192 ASSERT_TRUE(answer.get() != NULL);
1193 EXPECT_EQ(3u, answer->contents().size());
1194 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1195 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1196 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1197}
1198
ossu075af922016-06-14 03:29:38 -07001199// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1200// answerer settings.
1201
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001202// This test that the media direction is set to send/receive in an answer if
1203// the offer is send receive.
1204TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001205 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1206 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001207}
1208
1209// This test that the media direction is set to receive only in an answer if
1210// the offer is send only.
1211TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001212 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1213 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001214}
1215
1216// This test that the media direction is set to send only in an answer if
1217// the offer is recv only.
1218TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001219 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1220 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001221}
1222
1223// This test that the media direction is set to inactive in an answer if
1224// the offer is inactive.
1225TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001226 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1227 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001228}
1229
1230// Test that a data content with an unknown protocol is rejected in an answer.
1231TEST_F(MediaSessionDescriptionFactoryTest,
1232 CreateDataAnswerToOfferWithUnknownProtocol) {
1233 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001234 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001235 f1_.set_secure(SEC_ENABLED);
1236 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001237 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
terelius8c011e52016-04-26 05:28:11 -07001238 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001239 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001240 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001241 ASSERT_TRUE(dcd_offer != NULL);
1242 std::string protocol = "a weird unknown protocol";
1243 dcd_offer->set_protocol(protocol);
1244
kwiberg31022942016-03-11 14:18:21 -08001245 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001246 f2_.CreateAnswer(offer.get(), opts, NULL));
1247
1248 const ContentInfo* dc_answer = answer->GetContentByName("data");
1249 ASSERT_TRUE(dc_answer != NULL);
1250 EXPECT_TRUE(dc_answer->rejected);
1251 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001252 dc_answer->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001253 ASSERT_TRUE(dcd_answer != NULL);
1254 EXPECT_EQ(protocol, dcd_answer->protocol());
1255}
1256
1257// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1258TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001259 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001260 f1_.set_secure(SEC_DISABLED);
1261 f2_.set_secure(SEC_DISABLED);
1262 tdf1_.set_secure(SEC_DISABLED);
1263 tdf2_.set_secure(SEC_DISABLED);
1264
kwiberg31022942016-03-11 14:18:21 -08001265 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001266 const AudioContentDescription* offer_acd =
1267 GetFirstAudioContentDescription(offer.get());
1268 ASSERT_TRUE(offer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001269 EXPECT_EQ(cricket::kMediaProtocolAvpf, offer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001270
kwiberg31022942016-03-11 14:18:21 -08001271 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001272 f2_.CreateAnswer(offer.get(), opts, NULL));
1273
1274 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1275 ASSERT_TRUE(ac_answer != NULL);
1276 EXPECT_FALSE(ac_answer->rejected);
1277
1278 const AudioContentDescription* answer_acd =
1279 GetFirstAudioContentDescription(answer.get());
1280 ASSERT_TRUE(answer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001281 EXPECT_EQ(cricket::kMediaProtocolAvpf, answer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001282}
1283
1284// Create a video offer and answer and ensure the RTP header extensions
1285// matches what we expect.
1286TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1287 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001288 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001289 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1290 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1291 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1292 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1293
kwiberg31022942016-03-11 14:18:21 -08001294 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001295 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001296 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001297 f2_.CreateAnswer(offer.get(), opts, NULL));
1298
Yves Gerey665174f2018-06-19 15:03:05 +02001299 EXPECT_EQ(
1300 MAKE_VECTOR(kAudioRtpExtension1),
1301 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1302 EXPECT_EQ(
1303 MAKE_VECTOR(kVideoRtpExtension1),
1304 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1305 EXPECT_EQ(
1306 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1307 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1308 EXPECT_EQ(
1309 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1310 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001311}
1312
jbauch5869f502017-06-29 12:31:36 -07001313TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001314 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
jbauch5869f502017-06-29 12:31:36 -07001315 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001316 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001317
1318 f1_.set_enable_encrypted_rtp_header_extensions(true);
1319 f2_.set_enable_encrypted_rtp_header_extensions(true);
1320
Yves Gerey665174f2018-06-19 15:03:05 +02001321 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1322 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1323 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1324 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001325
1326 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1327 ASSERT_TRUE(offer.get() != NULL);
1328 std::unique_ptr<SessionDescription> answer(
1329 f2_.CreateAnswer(offer.get(), opts, NULL));
1330
Yves Gerey665174f2018-06-19 15:03:05 +02001331 EXPECT_EQ(
1332 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1333 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1334 EXPECT_EQ(
1335 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1336 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1337 EXPECT_EQ(
1338 MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
1339 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1340 EXPECT_EQ(
1341 MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
1342 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001343}
1344
1345TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001346 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
jbauch5869f502017-06-29 12:31:36 -07001347 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001348 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001349
1350 f1_.set_enable_encrypted_rtp_header_extensions(true);
1351
Yves Gerey665174f2018-06-19 15:03:05 +02001352 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1353 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1354 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1355 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001356
1357 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1358 ASSERT_TRUE(offer.get() != NULL);
1359 std::unique_ptr<SessionDescription> answer(
1360 f2_.CreateAnswer(offer.get(), opts, NULL));
1361
Yves Gerey665174f2018-06-19 15:03:05 +02001362 EXPECT_EQ(
1363 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1364 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1365 EXPECT_EQ(
1366 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1367 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1368 EXPECT_EQ(
1369 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1370 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1371 EXPECT_EQ(
1372 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1373 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001374}
1375
1376TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001377 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
jbauch5869f502017-06-29 12:31:36 -07001378 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001379 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001380
1381 f2_.set_enable_encrypted_rtp_header_extensions(true);
1382
Yves Gerey665174f2018-06-19 15:03:05 +02001383 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1384 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1385 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1386 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001387
1388 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1389 ASSERT_TRUE(offer.get() != NULL);
1390 std::unique_ptr<SessionDescription> answer(
1391 f2_.CreateAnswer(offer.get(), opts, NULL));
1392
Yves Gerey665174f2018-06-19 15:03:05 +02001393 EXPECT_EQ(
1394 MAKE_VECTOR(kAudioRtpExtension1),
1395 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1396 EXPECT_EQ(
1397 MAKE_VECTOR(kVideoRtpExtension1),
1398 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1399 EXPECT_EQ(
1400 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1401 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1402 EXPECT_EQ(
1403 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1404 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001405}
1406
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001407// Create an audio, video, data answer without legacy StreamParams.
1408TEST_F(MediaSessionDescriptionFactoryTest,
1409 TestCreateAnswerWithoutLegacyStreams) {
1410 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001411 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1412 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
kwiberg31022942016-03-11 14:18:21 -08001413 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001414 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08001415 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001416 f2_.CreateAnswer(offer.get(), opts, NULL));
1417 const ContentInfo* ac = answer->GetContentByName("audio");
1418 const ContentInfo* vc = answer->GetContentByName("video");
1419 const ContentInfo* dc = answer->GetContentByName("data");
1420 ASSERT_TRUE(ac != NULL);
1421 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001422 const AudioContentDescription* acd = ac->media_description()->as_audio();
1423 const VideoContentDescription* vcd = vc->media_description()->as_video();
1424 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001425
1426 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1427 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1428 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1429}
1430
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001431// Create a typical video answer, and ensure it matches what we expect.
1432TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1433 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001434 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
1435 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1436 &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001437
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001438 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001439 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
1440 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1441 &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001442
kwiberg31022942016-03-11 14:18:21 -08001443 std::unique_ptr<SessionDescription> offer;
1444 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001445
1446 offer_opts.rtcp_mux_enabled = true;
1447 answer_opts.rtcp_mux_enabled = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001448 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1449 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1450 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1451 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1452 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1453 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1454 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1455 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1456 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1457 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1458 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1459 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1460 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1461 EXPECT_TRUE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1462
1463 offer_opts.rtcp_mux_enabled = true;
1464 answer_opts.rtcp_mux_enabled = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001465 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1466 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1467 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1468 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1469 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1470 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1471 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1472 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1473 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1474 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1475 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1476 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1477 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1478 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1479
1480 offer_opts.rtcp_mux_enabled = false;
1481 answer_opts.rtcp_mux_enabled = true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001482 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1483 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1484 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1485 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1486 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1487 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1488 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1489 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1490 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1491 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1492 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1493 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1494 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1495 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1496
1497 offer_opts.rtcp_mux_enabled = false;
1498 answer_opts.rtcp_mux_enabled = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001499 offer.reset(f1_.CreateOffer(offer_opts, NULL));
1500 answer.reset(f2_.CreateAnswer(offer.get(), answer_opts, NULL));
1501 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1502 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1503 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1504 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1505 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1506 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1507 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1508 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1509 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1510 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1511 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1512 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1513}
1514
1515// Create an audio-only answer to a video offer.
1516TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1517 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001518 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
1519 kActive, &opts);
1520 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
1521 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -08001522 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001523 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001524
1525 opts.media_description_options[1].stopped = true;
kwiberg31022942016-03-11 14:18:21 -08001526 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001527 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001528 const ContentInfo* ac = answer->GetContentByName("audio");
1529 const ContentInfo* vc = answer->GetContentByName("video");
1530 ASSERT_TRUE(ac != NULL);
1531 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001532 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001533 EXPECT_TRUE(vc->rejected);
1534}
1535
1536// Create an audio-only answer to an offer with data.
1537TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001538 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001539 opts.data_channel_type = cricket::DCT_RTP;
Steve Anton4e70a722017-11-28 14:57:10 -08001540 AddMediaSection(MEDIA_TYPE_DATA, "data", RtpTransceiverDirection::kRecvOnly,
1541 kActive, &opts);
kwiberg31022942016-03-11 14:18:21 -08001542 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001543 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001544
1545 opts.media_description_options[1].stopped = true;
kwiberg31022942016-03-11 14:18:21 -08001546 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001547 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001548 const ContentInfo* ac = answer->GetContentByName("audio");
1549 const ContentInfo* dc = answer->GetContentByName("data");
1550 ASSERT_TRUE(ac != NULL);
1551 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001552 ASSERT_TRUE(dc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001553 EXPECT_TRUE(dc->rejected);
1554}
1555
1556// Create an answer that rejects the contents which are rejected in the offer.
1557TEST_F(MediaSessionDescriptionFactoryTest,
1558 CreateAnswerToOfferWithRejectedMedia) {
1559 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001560 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1561 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
kwiberg31022942016-03-11 14:18:21 -08001562 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001563 ASSERT_TRUE(offer.get() != NULL);
1564 ContentInfo* ac = offer->GetContentByName("audio");
1565 ContentInfo* vc = offer->GetContentByName("video");
1566 ContentInfo* dc = offer->GetContentByName("data");
1567 ASSERT_TRUE(ac != NULL);
1568 ASSERT_TRUE(vc != NULL);
1569 ASSERT_TRUE(dc != NULL);
1570 ac->rejected = true;
1571 vc->rejected = true;
1572 dc->rejected = true;
kwiberg31022942016-03-11 14:18:21 -08001573 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001574 f2_.CreateAnswer(offer.get(), opts, NULL));
1575 ac = answer->GetContentByName("audio");
1576 vc = answer->GetContentByName("video");
1577 dc = answer->GetContentByName("data");
1578 ASSERT_TRUE(ac != NULL);
1579 ASSERT_TRUE(vc != NULL);
1580 ASSERT_TRUE(dc != NULL);
1581 EXPECT_TRUE(ac->rejected);
1582 EXPECT_TRUE(vc->rejected);
1583 EXPECT_TRUE(dc->rejected);
1584}
1585
Johannes Kron0854eb62018-10-10 22:33:20 +02001586TEST_F(MediaSessionDescriptionFactoryTest,
1587 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensions) {
1588 MediaSessionOptions opts;
1589 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1590 // Offer without request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001591 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02001592 ASSERT_TRUE(offer.get() != NULL);
1593 std::unique_ptr<SessionDescription> answer_no_support(
1594 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001595 EXPECT_FALSE(answer_no_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001596
1597 // Offer with request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001598 offer->set_extmap_allow_mixed(true);
Johannes Kron0854eb62018-10-10 22:33:20 +02001599 ASSERT_TRUE(offer.get() != NULL);
1600 std::unique_ptr<SessionDescription> answer_support(
1601 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001602 EXPECT_TRUE(answer_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001603}
1604
1605TEST_F(MediaSessionDescriptionFactoryTest,
1606 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensionsOnMediaLevel) {
1607 MediaSessionOptions opts;
1608 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1609 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1610 MediaContentDescription* video_offer =
1611 offer->GetContentDescriptionByName("video");
1612 ASSERT_TRUE(video_offer);
1613 MediaContentDescription* audio_offer =
1614 offer->GetContentDescriptionByName("audio");
1615 ASSERT_TRUE(audio_offer);
1616
1617 // Explicit disable of mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001618 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
1619 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
Johannes Kron0854eb62018-10-10 22:33:20 +02001620
1621 ASSERT_TRUE(offer.get() != NULL);
1622 std::unique_ptr<SessionDescription> answer_no_support(
1623 f2_.CreateAnswer(offer.get(), opts, NULL));
1624 MediaContentDescription* video_answer =
1625 answer_no_support->GetContentDescriptionByName("video");
1626 MediaContentDescription* audio_answer =
1627 answer_no_support->GetContentDescriptionByName("audio");
1628 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001629 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001630 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001631 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001632
1633 // Enable mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001634 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
1635 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
Johannes Kron0854eb62018-10-10 22:33:20 +02001636 ASSERT_TRUE(offer.get() != NULL);
1637 std::unique_ptr<SessionDescription> answer_support(
1638 f2_.CreateAnswer(offer.get(), opts, NULL));
1639 video_answer = answer_support->GetContentDescriptionByName("video");
1640 audio_answer = answer_support->GetContentDescriptionByName("audio");
1641 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02001642 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001643 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02001644 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001645}
1646
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001647// Create an audio and video offer with:
1648// - one video track
1649// - two audio tracks
1650// - two data tracks
1651// and ensure it matches what we expect. Also updates the initial offer by
1652// adding a new video track and replaces one of the audio tracks.
1653TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
1654 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001655 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001656 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001657 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001658 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001659 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001660 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001661 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001662
Steve Anton4e70a722017-11-28 14:57:10 -08001663 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001664 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001665 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001666 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001667 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001668
1669 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001670 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001671
1672 ASSERT_TRUE(offer.get() != NULL);
1673 const ContentInfo* ac = offer->GetContentByName("audio");
1674 const ContentInfo* vc = offer->GetContentByName("video");
1675 const ContentInfo* dc = offer->GetContentByName("data");
1676 ASSERT_TRUE(ac != NULL);
1677 ASSERT_TRUE(vc != NULL);
1678 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001679 const AudioContentDescription* acd = ac->media_description()->as_audio();
1680 const VideoContentDescription* vcd = vc->media_description()->as_video();
1681 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001682 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07001683 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001684
1685 const StreamParamsVec& audio_streams = acd->streams();
1686 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001687 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001688 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1689 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1690 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1691 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1692 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1693 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1694
1695 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1696 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001697 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001698
1699 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1700 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001701 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001702
1703 const StreamParamsVec& video_streams = vcd->streams();
1704 ASSERT_EQ(1U, video_streams.size());
1705 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1706 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1707 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1708 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1709
1710 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1711 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001712 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001713
1714 const StreamParamsVec& data_streams = dcd->streams();
1715 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001716 EXPECT_EQ(data_streams[0].cname, data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001717 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1718 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1719 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1720 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1721 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1722 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1723
1724 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02001725 dcd->bandwidth()); // default bandwidth (auto)
1726 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001727 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001728
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001729 // Update the offer. Add a new video track that is not synched to the
1730 // other tracks and replace audio track 2 with audio track 3.
zhihuang1c378ed2017-08-17 14:10:50 -07001731 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001732 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001733 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
1734 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001735 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001736 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
1737 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack3,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001738 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08001739 std::unique_ptr<SessionDescription> updated_offer(
1740 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001741
1742 ASSERT_TRUE(updated_offer.get() != NULL);
1743 ac = updated_offer->GetContentByName("audio");
1744 vc = updated_offer->GetContentByName("video");
1745 dc = updated_offer->GetContentByName("data");
1746 ASSERT_TRUE(ac != NULL);
1747 ASSERT_TRUE(vc != NULL);
1748 ASSERT_TRUE(dc != NULL);
1749 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001750 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001751 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001752 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001753 const DataContentDescription* updated_dcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001754 dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001755
1756 EXPECT_EQ(acd->type(), updated_acd->type());
1757 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1758 EXPECT_EQ(vcd->type(), updated_vcd->type());
1759 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1760 EXPECT_EQ(dcd->type(), updated_dcd->type());
1761 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001762 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001763 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001764 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001765 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001766 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001767 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1768
1769 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1770 ASSERT_EQ(2U, updated_audio_streams.size());
1771 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
1772 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
1773 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
1774 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
1775 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
1776
1777 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1778 ASSERT_EQ(2U, updated_video_streams.size());
1779 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1780 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001781 // All the media streams in one PeerConnection share one RTCP CNAME.
1782 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001783
1784 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1785 ASSERT_EQ(2U, updated_data_streams.size());
1786 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
1787 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
1788 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
1789 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
1790 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07001791 // The stream correctly got the CNAME from the MediaSessionOptions.
1792 // The Expected RTCP CNAME is the default one as we are using the default
1793 // MediaSessionOptions.
1794 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001795}
1796
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001797// Create an offer with simulcast video stream.
1798TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
1799 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001800 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
1801 kActive, &opts);
1802 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
1803 kActive, &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001804 const int num_sim_layers = 3;
zhihuang1c378ed2017-08-17 14:10:50 -07001805 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001806 {kMediaStream1}, num_sim_layers, &opts);
kwiberg31022942016-03-11 14:18:21 -08001807 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001808
1809 ASSERT_TRUE(offer.get() != NULL);
1810 const ContentInfo* vc = offer->GetContentByName("video");
1811 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001812 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001813
1814 const StreamParamsVec& video_streams = vcd->streams();
1815 ASSERT_EQ(1U, video_streams.size());
1816 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1817 const SsrcGroup* sim_ssrc_group =
1818 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
1819 ASSERT_TRUE(sim_ssrc_group != NULL);
1820 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
1821}
1822
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001823// Create an audio and video answer to a standard video offer with:
1824// - one video track
1825// - two audio tracks
1826// - two data tracks
1827// and ensure it matches what we expect. Also updates the initial answer by
1828// adding a new video track and removes one of the audio tracks.
1829TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
1830 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001831 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
1832 kActive, &offer_opts);
1833 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
1834 kActive, &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001835 offer_opts.data_channel_type = cricket::DCT_RTP;
Steve Anton4e70a722017-11-28 14:57:10 -08001836 AddMediaSection(MEDIA_TYPE_DATA, "data", RtpTransceiverDirection::kRecvOnly,
1837 kActive, &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001838 f1_.set_secure(SEC_ENABLED);
1839 f2_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -08001840 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(offer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001841
zhihuang1c378ed2017-08-17 14:10:50 -07001842 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001843 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kSendRecv,
1844 kActive, &answer_opts);
1845 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
1846 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001847 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001848 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001849 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001850 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001851 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001852 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001853
Steve Anton4e70a722017-11-28 14:57:10 -08001854 AddMediaSection(MEDIA_TYPE_DATA, "data", RtpTransceiverDirection::kSendRecv,
1855 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001856 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001857 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001858 AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001859 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001860 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001861
kwiberg31022942016-03-11 14:18:21 -08001862 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001863 f2_.CreateAnswer(offer.get(), answer_opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001864
1865 ASSERT_TRUE(answer.get() != NULL);
1866 const ContentInfo* ac = answer->GetContentByName("audio");
1867 const ContentInfo* vc = answer->GetContentByName("video");
1868 const ContentInfo* dc = answer->GetContentByName("data");
1869 ASSERT_TRUE(ac != NULL);
1870 ASSERT_TRUE(vc != NULL);
1871 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001872 const AudioContentDescription* acd = ac->media_description()->as_audio();
1873 const VideoContentDescription* vcd = vc->media_description()->as_video();
1874 const DataContentDescription* dcd = dc->media_description()->as_data();
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001875 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
1876 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
1877 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001878
1879 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001880 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001881
1882 const StreamParamsVec& audio_streams = acd->streams();
1883 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001884 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001885 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1886 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1887 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1888 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1889 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1890 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1891
1892 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1893 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
1894
1895 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001896 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001897
1898 const StreamParamsVec& video_streams = vcd->streams();
1899 ASSERT_EQ(1U, video_streams.size());
1900 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1901 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1902 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1903 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1904
1905 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001906 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001907
1908 const StreamParamsVec& data_streams = dcd->streams();
1909 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001910 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001911 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1912 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1913 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1914 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1915 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1916 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1917
1918 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02001919 dcd->bandwidth()); // default bandwidth (auto)
1920 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001921
1922 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07001923 // other tracks and remove 1 audio track.
zhihuang1c378ed2017-08-17 14:10:50 -07001924 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07001925 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001926 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
1927 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08001928 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07001929 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001930
1931 ASSERT_TRUE(updated_answer.get() != NULL);
1932 ac = updated_answer->GetContentByName("audio");
1933 vc = updated_answer->GetContentByName("video");
1934 dc = updated_answer->GetContentByName("data");
1935 ASSERT_TRUE(ac != NULL);
1936 ASSERT_TRUE(vc != NULL);
1937 ASSERT_TRUE(dc != NULL);
1938 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001939 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001940 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001941 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001942 const DataContentDescription* updated_dcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001943 dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001944
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001945 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001946 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001947 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001948 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001949 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001950 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1951
1952 EXPECT_EQ(acd->type(), updated_acd->type());
1953 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1954 EXPECT_EQ(vcd->type(), updated_vcd->type());
1955 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1956 EXPECT_EQ(dcd->type(), updated_dcd->type());
1957 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
1958
1959 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1960 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001961 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001962
1963 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1964 ASSERT_EQ(2U, updated_video_streams.size());
1965 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1966 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001967 // All media streams in one PeerConnection share one CNAME.
1968 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001969
1970 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1971 ASSERT_EQ(1U, updated_data_streams.size());
1972 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
1973}
1974
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001975// Create an updated offer after creating an answer to the original offer and
1976// verify that the codecs that were part of the original answer are not changed
1977// in the updated offer.
1978TEST_F(MediaSessionDescriptionFactoryTest,
1979 RespondentCreatesOfferAfterCreatingAnswer) {
1980 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001981 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001982
kwiberg31022942016-03-11 14:18:21 -08001983 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
1984 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001985 f2_.CreateAnswer(offer.get(), opts, NULL));
1986
1987 const AudioContentDescription* acd =
1988 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08001989 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001990
1991 const VideoContentDescription* vcd =
1992 GetFirstVideoContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08001993 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001994
kwiberg31022942016-03-11 14:18:21 -08001995 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001996 f2_.CreateOffer(opts, answer.get()));
1997
1998 // The expected audio codecs are the common audio codecs from the first
1999 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
2000 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002001 // TODO(wu): |updated_offer| should not include the codec
2002 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002003 const AudioCodec kUpdatedAudioCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02002004 kAudioCodecsAnswer[0], kAudioCodecsAnswer[1], kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002005 };
2006
2007 // The expected video codecs are the common video codecs from the first
2008 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
2009 // preference order.
2010 const VideoCodec kUpdatedVideoCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02002011 kVideoCodecsAnswer[0], kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002012 };
2013
2014 const AudioContentDescription* updated_acd =
2015 GetFirstAudioContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002016 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kUpdatedAudioCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002017
2018 const VideoContentDescription* updated_vcd =
2019 GetFirstVideoContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002020 EXPECT_THAT(updated_vcd->codecs(), ElementsAreArray(kUpdatedVideoCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002021}
2022
2023// Create an updated offer after creating an answer to the original offer and
2024// verify that the codecs that were part of the original answer are not changed
2025// in the updated offer. In this test Rtx is enabled.
2026TEST_F(MediaSessionDescriptionFactoryTest,
2027 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2028 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002029 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2030 kActive, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002031 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002032 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002033 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002034 f1_.set_video_codecs(f1_codecs);
2035
2036 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002037 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002038 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002039 f2_.set_video_codecs(f2_codecs);
2040
kwiberg31022942016-03-11 14:18:21 -08002041 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002042 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002043 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002044 f2_.CreateAnswer(offer.get(), opts, NULL));
2045
2046 const VideoContentDescription* vcd =
2047 GetFirstVideoContentDescription(answer.get());
2048
2049 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002050 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2051 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002052
2053 EXPECT_EQ(expected_codecs, vcd->codecs());
2054
deadbeef67cf2c12016-04-13 10:07:16 -07002055 // Now, make sure we get same result (except for the order) if |f2_| creates
2056 // an updated offer even though the default payload types between |f1_| and
2057 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08002058 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002059 f2_.CreateOffer(opts, answer.get()));
2060 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002061 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002062 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2063
2064 const VideoContentDescription* updated_vcd =
2065 GetFirstVideoContentDescription(updated_answer.get());
2066
2067 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2068}
2069
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002070// Regression test for:
2071// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2072// Existing codecs should always appear before new codecs in re-offers. But
2073// under a specific set of circumstances, the existing RTX codec was ending up
2074// added to the end of the list.
2075TEST_F(MediaSessionDescriptionFactoryTest,
2076 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2077 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002078 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2079 kActive, &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002080 // We specifically choose different preferred payload types for VP8 to
2081 // trigger the issue.
2082 cricket::VideoCodec vp8_offerer(100, "VP8");
2083 cricket::VideoCodec vp8_offerer_rtx =
2084 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
2085 cricket::VideoCodec vp8_answerer(110, "VP8");
2086 cricket::VideoCodec vp8_answerer_rtx =
2087 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
2088 cricket::VideoCodec vp9(120, "VP9");
2089 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
2090
2091 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
2092 // We also specifically cause the answerer to prefer VP9, such that if it
2093 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
2094 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
2095 vp8_answerer_rtx};
2096
2097 f1_.set_video_codecs(f1_codecs);
2098 f2_.set_video_codecs(f2_codecs);
2099 std::vector<AudioCodec> audio_codecs;
2100 f1_.set_audio_codecs(audio_codecs, audio_codecs);
2101 f2_.set_audio_codecs(audio_codecs, audio_codecs);
2102
2103 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
2104 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2105 ASSERT_TRUE(offer.get() != NULL);
2106 std::unique_ptr<SessionDescription> answer(
2107 f2_.CreateAnswer(offer.get(), opts, NULL));
2108
2109 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
2110 // But if the bug is triggered, RTX for VP8 ends up last.
2111 std::unique_ptr<SessionDescription> updated_offer(
2112 f2_.CreateOffer(opts, answer.get()));
2113
2114 const VideoContentDescription* vcd =
2115 GetFirstVideoContentDescription(updated_offer.get());
2116 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
2117 ASSERT_EQ(4u, codecs.size());
2118 EXPECT_EQ(vp8_offerer, codecs[0]);
2119 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
2120 EXPECT_EQ(vp9, codecs[2]);
2121 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002122}
2123
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002124// Create an updated offer that adds video after creating an audio only answer
2125// to the original offer. This test verifies that if a video codec and the RTX
2126// codec have the same default payload type as an audio codec that is already in
2127// use, the added codecs payload types are changed.
2128TEST_F(MediaSessionDescriptionFactoryTest,
2129 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2130 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002131 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002132 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002133 f1_.set_video_codecs(f1_codecs);
2134
2135 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002136 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2137 kActive, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002138
kwiberg31022942016-03-11 14:18:21 -08002139 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2140 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002141 f2_.CreateAnswer(offer.get(), opts, NULL));
2142
2143 const AudioContentDescription* acd =
2144 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002145 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002146
2147 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
2148 // reference be the same as an audio codec that was negotiated in the
2149 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002150 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08002151 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002152
2153 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2154 int used_pl_type = acd->codecs()[0].id;
2155 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002156 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002157 f2_.set_video_codecs(f2_codecs);
2158
kwiberg31022942016-03-11 14:18:21 -08002159 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002160 f2_.CreateOffer(opts, answer.get()));
2161 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002162 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002163 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2164
2165 const AudioContentDescription* updated_acd =
2166 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002167 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002168
2169 const VideoContentDescription* updated_vcd =
2170 GetFirstVideoContentDescription(updated_answer.get());
2171
2172 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
Steve Antone38a5a12018-11-21 16:05:15 -08002173 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02002174 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002175 EXPECT_NE(used_pl_type, new_h264_pl_type);
2176 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002177 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002178 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
2179 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
2180}
2181
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002182// Create an updated offer with RTX after creating an answer to an offer
2183// without RTX, and with different default payload types.
2184// Verify that the added RTX codec references the correct payload type.
2185TEST_F(MediaSessionDescriptionFactoryTest,
2186 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
2187 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002188 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002189
2190 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2191 // This creates rtx for H264 with the payload type |f2_| uses.
2192 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
2193 f2_.set_video_codecs(f2_codecs);
2194
kwiberg31022942016-03-11 14:18:21 -08002195 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002196 ASSERT_TRUE(offer.get() != nullptr);
kwiberg31022942016-03-11 14:18:21 -08002197 std::unique_ptr<SessionDescription> answer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002198 f2_.CreateAnswer(offer.get(), opts, nullptr));
2199
2200 const VideoContentDescription* vcd =
2201 GetFirstVideoContentDescription(answer.get());
2202
2203 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2204 EXPECT_EQ(expected_codecs, vcd->codecs());
2205
2206 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
2207 // updated offer, even though the default payload types are different from
2208 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08002209 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002210 f2_.CreateOffer(opts, answer.get()));
2211 ASSERT_TRUE(updated_offer);
2212
2213 const VideoContentDescription* updated_vcd =
2214 GetFirstVideoContentDescription(updated_offer.get());
2215
2216 // New offer should attempt to add H263, and RTX for H264.
2217 expected_codecs.push_back(kVideoCodecs2[1]);
2218 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
2219 &expected_codecs);
2220 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2221}
2222
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002223// Test that RTX is ignored when there is no associated payload type parameter.
2224TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
2225 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002226 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2227 kActive, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002228 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002229 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07002230 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002231 f1_.set_video_codecs(f1_codecs);
2232
2233 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002234 // This creates RTX for H264 with the payload type |f2_| uses.
2235 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002236 f2_.set_video_codecs(f2_codecs);
2237
kwiberg31022942016-03-11 14:18:21 -08002238 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002239 ASSERT_TRUE(offer.get() != NULL);
2240 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
2241 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
2242 // is possible to test that that RTX is dropped when
2243 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08002244 MediaContentDescription* media_desc =
2245 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2246 ASSERT_TRUE(media_desc);
2247 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002248 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07002249 for (VideoCodec& codec : codecs) {
2250 if (codec.name.find(cricket::kRtxCodecName) == 0) {
2251 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002252 }
2253 }
2254 desc->set_codecs(codecs);
2255
kwiberg31022942016-03-11 14:18:21 -08002256 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002257 f2_.CreateAnswer(offer.get(), opts, NULL));
2258
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002259 std::vector<std::string> codec_names =
2260 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
2261 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
2262 cricket::kRtxCodecName));
2263}
2264
2265// Test that RTX will be filtered out in the answer if its associated payload
2266// type doesn't match the local value.
2267TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
2268 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002269 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2270 kActive, &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002271 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2272 // This creates RTX for H264 in sender.
2273 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2274 f1_.set_video_codecs(f1_codecs);
2275
2276 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2277 // This creates RTX for H263 in receiver.
2278 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
2279 f2_.set_video_codecs(f2_codecs);
2280
kwiberg31022942016-03-11 14:18:21 -08002281 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002282 ASSERT_TRUE(offer.get() != NULL);
2283 // Associated payload type doesn't match, therefore, RTX codec is removed in
2284 // the answer.
kwiberg31022942016-03-11 14:18:21 -08002285 std::unique_ptr<SessionDescription> answer(
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002286 f2_.CreateAnswer(offer.get(), opts, NULL));
2287
2288 std::vector<std::string> codec_names =
2289 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
2290 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
2291 cricket::kRtxCodecName));
2292}
2293
2294// Test that when multiple RTX codecs are offered, only the matched RTX codec
2295// is added in the answer, and the unsupported RTX codec is filtered out.
2296TEST_F(MediaSessionDescriptionFactoryTest,
2297 FilterOutUnsupportedRtxWhenCreatingAnswer) {
2298 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002299 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2300 kActive, &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002301 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2302 // This creates RTX for H264-SVC in sender.
2303 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2304 f1_.set_video_codecs(f1_codecs);
2305
2306 // This creates RTX for H264 in sender.
2307 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2308 f1_.set_video_codecs(f1_codecs);
2309
2310 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2311 // This creates RTX for H264 in receiver.
2312 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
2313 f2_.set_video_codecs(f2_codecs);
2314
2315 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
2316 // for H264-SVC should also be removed.
kwiberg31022942016-03-11 14:18:21 -08002317 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002318 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002319 std::unique_ptr<SessionDescription> answer(
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002320 f2_.CreateAnswer(offer.get(), opts, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002321 const VideoContentDescription* vcd =
2322 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002323 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2324 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2325 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002326
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002327 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002328}
2329
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002330// Test that after one RTX codec has been negotiated, a new offer can attempt
2331// to add another.
2332TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
2333 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002334 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
2335 kActive, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002336 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2337 // This creates RTX for H264 for the offerer.
2338 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2339 f1_.set_video_codecs(f1_codecs);
2340
kwiberg31022942016-03-11 14:18:21 -08002341 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002342 ASSERT_TRUE(offer);
2343 const VideoContentDescription* vcd =
2344 GetFirstVideoContentDescription(offer.get());
2345
2346 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
2347 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2348 &expected_codecs);
2349 EXPECT_EQ(expected_codecs, vcd->codecs());
2350
2351 // Now, attempt to add RTX for H264-SVC.
2352 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2353 f1_.set_video_codecs(f1_codecs);
2354
kwiberg31022942016-03-11 14:18:21 -08002355 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002356 f1_.CreateOffer(opts, offer.get()));
2357 ASSERT_TRUE(updated_offer);
2358 vcd = GetFirstVideoContentDescription(updated_offer.get());
2359
2360 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
2361 &expected_codecs);
2362 EXPECT_EQ(expected_codecs, vcd->codecs());
2363}
2364
Noah Richards2e7a0982015-05-18 14:02:54 -07002365// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
2366// generated for each simulcast ssrc and correctly grouped.
2367TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
2368 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002369 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
2370 kActive, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002371 // Add simulcast streams.
zhihuang1c378ed2017-08-17 14:10:50 -07002372 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002373 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002374
2375 // Use a single real codec, and then add RTX for it.
2376 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07002377 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07002378 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
2379 f1_.set_video_codecs(f1_codecs);
2380
2381 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
2382 // is a FID ssrc + grouping for each.
kwiberg31022942016-03-11 14:18:21 -08002383 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
Noah Richards2e7a0982015-05-18 14:02:54 -07002384 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002385 MediaContentDescription* media_desc =
2386 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2387 ASSERT_TRUE(media_desc);
2388 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07002389 const StreamParamsVec& streams = desc->streams();
2390 // Single stream.
2391 ASSERT_EQ(1u, streams.size());
2392 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
2393 EXPECT_EQ(6u, streams[0].ssrcs.size());
2394 // And should have a SIM group for the simulcast.
2395 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2396 // And a FID group for RTX.
2397 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02002398 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002399 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2400 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02002401 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002402 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
2403 EXPECT_EQ(3u, fid_ssrcs.size());
2404}
2405
brandtr03d5fb12016-11-22 03:37:59 -08002406// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
2407// together with a FEC-FR grouping.
2408TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
2409 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002410 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
2411 kActive, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002412 // Add single stream.
zhihuang1c378ed2017-08-17 14:10:50 -07002413 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002414 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002415
2416 // Use a single real codec, and then add FlexFEC for it.
2417 std::vector<VideoCodec> f1_codecs;
2418 f1_codecs.push_back(VideoCodec(97, "H264"));
2419 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2420 f1_.set_video_codecs(f1_codecs);
2421
2422 // Ensure that the offer has a single FlexFEC ssrc and that
2423 // there is no FEC-FR ssrc + grouping for each.
2424 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
2425 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08002426 MediaContentDescription* media_desc =
2427 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2428 ASSERT_TRUE(media_desc);
2429 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08002430 const StreamParamsVec& streams = desc->streams();
2431 // Single stream.
2432 ASSERT_EQ(1u, streams.size());
2433 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
2434 EXPECT_EQ(2u, streams[0].ssrcs.size());
2435 // And should have a FEC-FR group for FlexFEC.
2436 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
2437 std::vector<uint32_t> primary_ssrcs;
2438 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2439 ASSERT_EQ(1u, primary_ssrcs.size());
2440 uint32_t flexfec_ssrc;
2441 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
2442 EXPECT_NE(flexfec_ssrc, 0u);
2443}
2444
2445// Test that FlexFEC is disabled for simulcast.
2446// TODO(brandtr): Remove this test when we support simulcast, either through
2447// multiple FlexfecSenders, or through multistream protection.
2448TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
2449 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002450 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
2451 kActive, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002452 // Add simulcast streams.
zhihuang1c378ed2017-08-17 14:10:50 -07002453 AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
Steve Anton8ffb9c32017-08-31 15:45:38 -07002454 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002455
2456 // Use a single real codec, and then add FlexFEC for it.
2457 std::vector<VideoCodec> f1_codecs;
2458 f1_codecs.push_back(VideoCodec(97, "H264"));
2459 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2460 f1_.set_video_codecs(f1_codecs);
2461
2462 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
2463 // there is no FEC-FR ssrc + grouping for each.
2464 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
2465 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08002466 MediaContentDescription* media_desc =
2467 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2468 ASSERT_TRUE(media_desc);
2469 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08002470 const StreamParamsVec& streams = desc->streams();
2471 // Single stream.
2472 ASSERT_EQ(1u, streams.size());
2473 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
2474 EXPECT_EQ(3u, streams[0].ssrcs.size());
2475 // And should have a SIM group for the simulcast.
2476 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2477 // And not a FEC-FR group for FlexFEC.
2478 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
2479 std::vector<uint32_t> primary_ssrcs;
2480 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2481 EXPECT_EQ(3u, primary_ssrcs.size());
2482 for (uint32_t primary_ssrc : primary_ssrcs) {
2483 uint32_t flexfec_ssrc;
2484 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
2485 }
2486}
2487
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002488// Create an updated offer after creating an answer to the original offer and
2489// verify that the RTP header extensions that were part of the original answer
2490// are not changed in the updated offer.
2491TEST_F(MediaSessionDescriptionFactoryTest,
2492 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
2493 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002494 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002495
2496 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
2497 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
2498 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
2499 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
2500
kwiberg31022942016-03-11 14:18:21 -08002501 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2502 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002503 f2_.CreateAnswer(offer.get(), opts, NULL));
2504
Yves Gerey665174f2018-06-19 15:03:05 +02002505 EXPECT_EQ(
2506 MAKE_VECTOR(kAudioRtpExtensionAnswer),
2507 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2508 EXPECT_EQ(
2509 MAKE_VECTOR(kVideoRtpExtensionAnswer),
2510 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002511
kwiberg31022942016-03-11 14:18:21 -08002512 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002513 f2_.CreateOffer(opts, answer.get()));
2514
2515 // The expected RTP header extensions in the new offer are the resulting
2516 // extensions from the first offer/answer exchange plus the extensions only
2517 // |f2_| offer.
2518 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002519 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07002520 const RtpExtension kUpdatedAudioRtpExtensions[] = {
2521 kAudioRtpExtensionAnswer[0], RtpExtension(kAudioRtpExtension2[1].uri, 13),
2522 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002523 };
2524
2525 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00002526 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07002527 const RtpExtension kUpdatedVideoRtpExtensions[] = {
2528 kVideoRtpExtensionAnswer[0], RtpExtension(kVideoRtpExtension2[1].uri, 12),
2529 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002530 };
2531
2532 const AudioContentDescription* updated_acd =
2533 GetFirstAudioContentDescription(updated_offer.get());
2534 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
2535 updated_acd->rtp_header_extensions());
2536
2537 const VideoContentDescription* updated_vcd =
2538 GetFirstVideoContentDescription(updated_offer.get());
2539 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
2540 updated_vcd->rtp_header_extensions());
2541}
2542
deadbeefa5b273a2015-08-20 17:30:13 -07002543// Verify that if the same RTP extension URI is used for audio and video, the
2544// same ID is used. Also verify that the ID isn't changed when creating an
2545// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07002546TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07002547 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002548 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07002549
2550 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
2551 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
2552
kwiberg31022942016-03-11 14:18:21 -08002553 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
deadbeefa5b273a2015-08-20 17:30:13 -07002554
2555 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
2556 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07002557 const RtpExtension kExpectedVideoRtpExtension[] = {
2558 kVideoRtpExtension3[0], kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07002559 };
2560
Yves Gerey665174f2018-06-19 15:03:05 +02002561 EXPECT_EQ(
2562 MAKE_VECTOR(kAudioRtpExtension3),
2563 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2564 EXPECT_EQ(
2565 MAKE_VECTOR(kExpectedVideoRtpExtension),
2566 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07002567
2568 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08002569 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07002570 f1_.CreateOffer(opts, offer.get()));
2571
2572 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02002573 GetFirstAudioContentDescription(updated_offer.get())
2574 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07002575 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02002576 GetFirstVideoContentDescription(updated_offer.get())
2577 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07002578}
2579
jbauch5869f502017-06-29 12:31:36 -07002580// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
2581TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
2582 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002583 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07002584
2585 f1_.set_enable_encrypted_rtp_header_extensions(true);
2586 f2_.set_enable_encrypted_rtp_header_extensions(true);
2587
2588 f1_.set_audio_rtp_header_extensions(
2589 MAKE_VECTOR(kAudioRtpExtension3ForEncryption));
2590 f1_.set_video_rtp_header_extensions(
2591 MAKE_VECTOR(kVideoRtpExtension3ForEncryption));
2592
2593 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
2594
2595 // The extensions that are shared between audio and video should use the same
2596 // id.
2597 const RtpExtension kExpectedVideoRtpExtension[] = {
2598 kVideoRtpExtension3ForEncryption[0],
2599 kAudioRtpExtension3ForEncryptionOffer[1],
2600 kAudioRtpExtension3ForEncryptionOffer[2],
2601 };
2602
Yves Gerey665174f2018-06-19 15:03:05 +02002603 EXPECT_EQ(
2604 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
2605 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
2606 EXPECT_EQ(
2607 MAKE_VECTOR(kExpectedVideoRtpExtension),
2608 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002609
2610 // Nothing should change when creating a new offer
2611 std::unique_ptr<SessionDescription> updated_offer(
2612 f1_.CreateOffer(opts, offer.get()));
2613
2614 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02002615 GetFirstAudioContentDescription(updated_offer.get())
2616 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002617 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02002618 GetFirstVideoContentDescription(updated_offer.get())
2619 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07002620}
2621
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002622TEST(MediaSessionDescription, CopySessionDescription) {
2623 SessionDescription source;
2624 cricket::ContentGroup group(cricket::CN_AUDIO);
2625 source.AddGroup(group);
2626 AudioContentDescription* acd(new AudioContentDescription());
2627 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
2628 acd->AddLegacyStream(1);
Steve Anton5adfafd2017-12-20 16:34:00 -08002629 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp, acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002630 VideoContentDescription* vcd(new VideoContentDescription());
2631 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
2632 vcd->AddLegacyStream(2);
Steve Anton5adfafd2017-12-20 16:34:00 -08002633 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp, vcd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002634
kwiberg31022942016-03-11 14:18:21 -08002635 std::unique_ptr<SessionDescription> copy(source.Copy());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002636 ASSERT_TRUE(copy.get() != NULL);
2637 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
2638 const ContentInfo* ac = copy->GetContentByName("audio");
2639 const ContentInfo* vc = copy->GetContentByName("video");
2640 ASSERT_TRUE(ac != NULL);
2641 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08002642 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002643 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002644 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
2645 EXPECT_EQ(1u, acd->first_ssrc());
2646
Steve Anton5adfafd2017-12-20 16:34:00 -08002647 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08002648 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002649 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
2650 EXPECT_EQ(2u, vcd->first_ssrc());
2651}
2652
2653// The below TestTransportInfoXXX tests create different offers/answers, and
2654// ensure the TransportInfo in the SessionDescription matches what we expect.
2655TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
2656 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002657 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2658 kActive, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002659 TestTransportInfo(true, options, false);
2660}
2661
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002662TEST_F(MediaSessionDescriptionFactoryTest,
2663 TestTransportInfoOfferIceRenomination) {
2664 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002665 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2666 kActive, &options);
zhihuang1c378ed2017-08-17 14:10:50 -07002667 options.media_description_options[0]
2668 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002669 TestTransportInfo(true, options, false);
2670}
2671
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002672TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
2673 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002674 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2675 kActive, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002676 TestTransportInfo(true, options, true);
2677}
2678
2679TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
2680 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002681 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2682 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2683 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002684 TestTransportInfo(true, options, false);
2685}
2686
2687TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002688 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002689 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002690 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2691 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2692 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002693 TestTransportInfo(true, options, true);
2694}
2695
2696TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
2697 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002698 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2699 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2700 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002701 options.bundle_enabled = true;
2702 TestTransportInfo(true, options, false);
2703}
2704
2705TEST_F(MediaSessionDescriptionFactoryTest,
2706 TestTransportInfoOfferBundleCurrent) {
2707 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002708 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2709 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2710 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002711 options.bundle_enabled = true;
2712 TestTransportInfo(true, options, true);
2713}
2714
2715TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
2716 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002717 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2718 kActive, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002719 TestTransportInfo(false, options, false);
2720}
2721
2722TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002723 TestTransportInfoAnswerIceRenomination) {
2724 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002725 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2726 kActive, &options);
zhihuang1c378ed2017-08-17 14:10:50 -07002727 options.media_description_options[0]
2728 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002729 TestTransportInfo(false, options, false);
2730}
2731
2732TEST_F(MediaSessionDescriptionFactoryTest,
2733 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002734 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002735 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
2736 kActive, &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002737 TestTransportInfo(false, options, true);
2738}
2739
2740TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
2741 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002742 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2743 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2744 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002745 TestTransportInfo(false, options, false);
2746}
2747
2748TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002749 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002750 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002751 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2752 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2753 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002754 TestTransportInfo(false, options, true);
2755}
2756
2757TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
2758 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002759 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2760 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2761 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002762 options.bundle_enabled = true;
2763 TestTransportInfo(false, options, false);
2764}
2765
2766TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02002767 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002768 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002769 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2770 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2771 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002772 options.bundle_enabled = true;
2773 TestTransportInfo(false, options, true);
2774}
2775
2776// Create an offer with bundle enabled and verify the crypto parameters are
2777// the common set of the available cryptos.
2778TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
2779 TestCryptoWithBundle(true);
2780}
2781
2782// Create an answer with bundle enabled and verify the crypto parameters are
2783// the common set of the available cryptos.
2784TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
2785 TestCryptoWithBundle(false);
2786}
2787
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002788// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
2789// DTLS is not enabled locally.
2790TEST_F(MediaSessionDescriptionFactoryTest,
2791 TestOfferDtlsSavpfWithoutDtlsFailed) {
2792 f1_.set_secure(SEC_ENABLED);
2793 f2_.set_secure(SEC_ENABLED);
2794 tdf1_.set_secure(SEC_DISABLED);
2795 tdf2_.set_secure(SEC_DISABLED);
2796
kwiberg31022942016-03-11 14:18:21 -08002797 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -07002798 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002799 ASSERT_TRUE(offer.get() != NULL);
2800 ContentInfo* offer_content = offer->GetContentByName("audio");
2801 ASSERT_TRUE(offer_content != NULL);
2802 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08002803 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002804 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2805
kwiberg31022942016-03-11 14:18:21 -08002806 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002807 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002808 ASSERT_TRUE(answer != NULL);
2809 ContentInfo* answer_content = answer->GetContentByName("audio");
2810 ASSERT_TRUE(answer_content != NULL);
2811
2812 ASSERT_TRUE(answer_content->rejected);
2813}
2814
2815// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
2816// UDP/TLS/RTP/SAVPF.
2817TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
2818 f1_.set_secure(SEC_ENABLED);
2819 f2_.set_secure(SEC_ENABLED);
2820 tdf1_.set_secure(SEC_ENABLED);
2821 tdf2_.set_secure(SEC_ENABLED);
2822
kwiberg31022942016-03-11 14:18:21 -08002823 std::unique_ptr<SessionDescription> offer(
zhihuang1c378ed2017-08-17 14:10:50 -07002824 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002825 ASSERT_TRUE(offer.get() != NULL);
2826 ContentInfo* offer_content = offer->GetContentByName("audio");
2827 ASSERT_TRUE(offer_content != NULL);
2828 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08002829 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002830 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
2831
kwiberg31022942016-03-11 14:18:21 -08002832 std::unique_ptr<SessionDescription> answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002833 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL));
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002834 ASSERT_TRUE(answer != NULL);
2835
2836 const ContentInfo* answer_content = answer->GetContentByName("audio");
2837 ASSERT_TRUE(answer_content != NULL);
2838 ASSERT_FALSE(answer_content->rejected);
2839
2840 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08002841 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08002842 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00002843}
2844
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002845// Test that we include both SDES and DTLS in the offer, but only include SDES
2846// in the answer if DTLS isn't negotiated.
2847TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
2848 f1_.set_secure(SEC_ENABLED);
2849 f2_.set_secure(SEC_ENABLED);
2850 tdf1_.set_secure(SEC_ENABLED);
2851 tdf2_.set_secure(SEC_DISABLED);
2852 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002853 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08002854 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002855 const cricket::MediaContentDescription* audio_media_desc;
2856 const cricket::MediaContentDescription* video_media_desc;
2857 const cricket::TransportDescription* audio_trans_desc;
2858 const cricket::TransportDescription* video_trans_desc;
2859
2860 // Generate an offer with SDES and DTLS support.
2861 offer.reset(f1_.CreateOffer(options, NULL));
2862 ASSERT_TRUE(offer.get() != NULL);
2863
Steve Antonb1c1de12017-12-21 15:14:30 -08002864 audio_media_desc = offer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002865 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002866 video_media_desc = offer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002867 ASSERT_TRUE(video_media_desc != NULL);
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002868 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002869 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2870
2871 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2872 ASSERT_TRUE(audio_trans_desc != NULL);
2873 video_trans_desc = offer->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);
2877
2878 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
2879 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2880 ASSERT_TRUE(answer.get() != NULL);
2881
Steve Antonb1c1de12017-12-21 15:14:30 -08002882 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002883 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002884 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002885 ASSERT_TRUE(video_media_desc != NULL);
2886 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
2887 EXPECT_EQ(1u, video_media_desc->cryptos().size());
2888
2889 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2890 ASSERT_TRUE(audio_trans_desc != NULL);
2891 video_trans_desc = answer->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);
2895
2896 // Enable DTLS; the answer should now only have DTLS support.
2897 tdf2_.set_secure(SEC_ENABLED);
2898 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2899 ASSERT_TRUE(answer.get() != NULL);
2900
Steve Antonb1c1de12017-12-21 15:14:30 -08002901 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002902 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002903 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002904 ASSERT_TRUE(video_media_desc != NULL);
2905 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2906 EXPECT_TRUE(video_media_desc->cryptos().empty());
Steve Antone38a5a12018-11-21 16:05:15 -08002907 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
2908 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002909
2910 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
2911 ASSERT_TRUE(audio_trans_desc != NULL);
2912 video_trans_desc = answer->GetTransportDescriptionByName("video");
2913 ASSERT_TRUE(video_trans_desc != NULL);
2914 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2915 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00002916
2917 // Try creating offer again. DTLS enabled now, crypto's should be empty
2918 // in new offer.
2919 offer.reset(f1_.CreateOffer(options, offer.get()));
2920 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002921 audio_media_desc = offer->GetContentDescriptionByName("audio");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00002922 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002923 video_media_desc = offer->GetContentDescriptionByName("video");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00002924 ASSERT_TRUE(video_media_desc != NULL);
2925 EXPECT_TRUE(audio_media_desc->cryptos().empty());
2926 EXPECT_TRUE(video_media_desc->cryptos().empty());
2927
2928 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
2929 ASSERT_TRUE(audio_trans_desc != NULL);
2930 video_trans_desc = offer->GetTransportDescriptionByName("video");
2931 ASSERT_TRUE(video_trans_desc != NULL);
2932 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
2933 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002934}
2935
2936// Test that an answer can't be created if cryptos are required but the offer is
2937// unsecure.
2938TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07002939 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002940 f1_.set_secure(SEC_DISABLED);
2941 tdf1_.set_secure(SEC_DISABLED);
2942 f2_.set_secure(SEC_REQUIRED);
2943 tdf1_.set_secure(SEC_ENABLED);
2944
kwiberg31022942016-03-11 14:18:21 -08002945 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002946 ASSERT_TRUE(offer.get() != NULL);
kwiberg31022942016-03-11 14:18:21 -08002947 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002948 f2_.CreateAnswer(offer.get(), options, NULL));
2949 EXPECT_TRUE(answer.get() == NULL);
2950}
2951
2952// Test that we accept a DTLS offer without SDES and create an appropriate
2953// answer.
2954TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
2955 f1_.set_secure(SEC_DISABLED);
2956 f2_.set_secure(SEC_ENABLED);
2957 tdf1_.set_secure(SEC_ENABLED);
2958 tdf2_.set_secure(SEC_ENABLED);
2959 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08002960 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
2961 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
2962 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002963
kwiberg31022942016-03-11 14:18:21 -08002964 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002965
2966 // Generate an offer with DTLS but without SDES.
2967 offer.reset(f1_.CreateOffer(options, NULL));
2968 ASSERT_TRUE(offer.get() != NULL);
2969
2970 const AudioContentDescription* audio_offer =
2971 GetFirstAudioContentDescription(offer.get());
2972 ASSERT_TRUE(audio_offer->cryptos().empty());
2973 const VideoContentDescription* video_offer =
2974 GetFirstVideoContentDescription(offer.get());
2975 ASSERT_TRUE(video_offer->cryptos().empty());
2976 const DataContentDescription* data_offer =
2977 GetFirstDataContentDescription(offer.get());
2978 ASSERT_TRUE(data_offer->cryptos().empty());
2979
2980 const cricket::TransportDescription* audio_offer_trans_desc =
2981 offer->GetTransportDescriptionByName("audio");
2982 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
2983 const cricket::TransportDescription* video_offer_trans_desc =
2984 offer->GetTransportDescriptionByName("video");
2985 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
2986 const cricket::TransportDescription* data_offer_trans_desc =
2987 offer->GetTransportDescriptionByName("data");
2988 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
2989
2990 // Generate an answer with DTLS.
2991 answer.reset(f2_.CreateAnswer(offer.get(), options, NULL));
2992 ASSERT_TRUE(answer.get() != NULL);
2993
2994 const cricket::TransportDescription* audio_answer_trans_desc =
2995 answer->GetTransportDescriptionByName("audio");
2996 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
2997 const cricket::TransportDescription* video_answer_trans_desc =
2998 answer->GetTransportDescriptionByName("video");
2999 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
3000 const cricket::TransportDescription* data_answer_trans_desc =
3001 answer->GetTransportDescriptionByName("data");
3002 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
3003}
3004
3005// Verifies if vad_enabled option is set to false, CN codecs are not present in
3006// offer or answer.
3007TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3008 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003009 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08003010 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003011 ASSERT_TRUE(offer.get() != NULL);
3012 const ContentInfo* audio_content = offer->GetContentByName("audio");
3013 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
3014
3015 options.vad_enabled = false;
3016 offer.reset(f1_.CreateOffer(options, NULL));
3017 ASSERT_TRUE(offer.get() != NULL);
3018 audio_content = offer->GetContentByName("audio");
3019 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
kwiberg31022942016-03-11 14:18:21 -08003020 std::unique_ptr<SessionDescription> answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003021 f1_.CreateAnswer(offer.get(), options, NULL));
3022 ASSERT_TRUE(answer.get() != NULL);
3023 audio_content = answer->GetContentByName("audio");
3024 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
3025}
deadbeef44f08192015-12-15 16:20:09 -08003026
zhihuang1c378ed2017-08-17 14:10:50 -07003027// Test that the generated MIDs match the existing offer.
3028TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08003029 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003030 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_modified",
3031 RtpTransceiverDirection::kRecvOnly, kActive, &opts);
3032 AddMediaSection(MEDIA_TYPE_VIDEO, "video_modified",
3033 RtpTransceiverDirection::kRecvOnly, kActive, &opts);
deadbeef44f08192015-12-15 16:20:09 -08003034 opts.data_channel_type = cricket::DCT_SCTP;
Steve Anton4e70a722017-11-28 14:57:10 -08003035 AddMediaSection(MEDIA_TYPE_DATA, "data_modified",
3036 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003037 // Create offer.
kwiberg31022942016-03-11 14:18:21 -08003038 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
kwiberg31022942016-03-11 14:18:21 -08003039 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08003040 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003041
deadbeef44f08192015-12-15 16:20:09 -08003042 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3043 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3044 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3045 ASSERT_TRUE(audio_content != nullptr);
3046 ASSERT_TRUE(video_content != nullptr);
3047 ASSERT_TRUE(data_content != nullptr);
3048 EXPECT_EQ("audio_modified", audio_content->name);
3049 EXPECT_EQ("video_modified", video_content->name);
3050 EXPECT_EQ("data_modified", data_content->name);
3051}
zhihuangcf5b37c2016-05-05 11:44:35 -07003052
zhihuang1c378ed2017-08-17 14:10:50 -07003053// The following tests verify that the unified plan SDP is supported.
3054// Test that we can create an offer with multiple media sections of same media
3055// type.
3056TEST_F(MediaSessionDescriptionFactoryTest,
3057 CreateOfferWithMultipleAVMediaSections) {
3058 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003059 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_1",
3060 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003061 AttachSenderToMediaSection("audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003062 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003063
Steve Anton4e70a722017-11-28 14:57:10 -08003064 AddMediaSection(MEDIA_TYPE_VIDEO, "video_1",
3065 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003066 AttachSenderToMediaSection("video_1", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003067 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003068
Steve Anton4e70a722017-11-28 14:57:10 -08003069 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_2",
3070 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003071 AttachSenderToMediaSection("audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003072 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003073
Steve Anton4e70a722017-11-28 14:57:10 -08003074 AddMediaSection(MEDIA_TYPE_VIDEO, "video_2",
3075 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003076 AttachSenderToMediaSection("video_2", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003077 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003078 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3079 ASSERT_TRUE(offer);
3080
3081 ASSERT_EQ(4u, offer->contents().size());
3082 EXPECT_FALSE(offer->contents()[0].rejected);
3083 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003084 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003085 ASSERT_EQ(1u, acd->streams().size());
3086 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003087 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003088
3089 EXPECT_FALSE(offer->contents()[1].rejected);
3090 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003091 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003092 ASSERT_EQ(1u, vcd->streams().size());
3093 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003094 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003095
3096 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003097 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003098 ASSERT_EQ(1u, acd->streams().size());
3099 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003100 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003101
3102 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003103 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003104 ASSERT_EQ(1u, vcd->streams().size());
3105 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003106 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003107}
3108
3109// Test that we can create an answer with multiple media sections of same media
3110// type.
3111TEST_F(MediaSessionDescriptionFactoryTest,
3112 CreateAnswerWithMultipleAVMediaSections) {
3113 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003114 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_1",
3115 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003116 AttachSenderToMediaSection("audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003117 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003118
Steve Anton4e70a722017-11-28 14:57:10 -08003119 AddMediaSection(MEDIA_TYPE_VIDEO, "video_1",
3120 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003121 AttachSenderToMediaSection("video_1", MEDIA_TYPE_VIDEO, kVideoTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003122 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003123
Steve Anton4e70a722017-11-28 14:57:10 -08003124 AddMediaSection(MEDIA_TYPE_AUDIO, "audio_2",
3125 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003126 AttachSenderToMediaSection("audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003127 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003128
Steve Anton4e70a722017-11-28 14:57:10 -08003129 AddMediaSection(MEDIA_TYPE_VIDEO, "video_2",
3130 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003131 AttachSenderToMediaSection("video_2", MEDIA_TYPE_VIDEO, kVideoTrack2,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003132 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003133
3134 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3135 ASSERT_TRUE(offer);
3136 std::unique_ptr<SessionDescription> answer(
3137 f2_.CreateAnswer(offer.get(), opts, nullptr));
3138
3139 ASSERT_EQ(4u, answer->contents().size());
3140 EXPECT_FALSE(answer->contents()[0].rejected);
3141 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003142 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003143 ASSERT_EQ(1u, acd->streams().size());
3144 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003145 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003146
3147 EXPECT_FALSE(answer->contents()[1].rejected);
3148 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003149 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003150 ASSERT_EQ(1u, vcd->streams().size());
3151 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003152 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003153
3154 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003155 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003156 ASSERT_EQ(1u, acd->streams().size());
3157 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003158 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003159
3160 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003161 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003162 ASSERT_EQ(1u, vcd->streams().size());
3163 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003164 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003165}
3166
3167// Test that the media section will be rejected in offer if the corresponding
3168// MediaDescriptionOptions is stopped by the offerer.
3169TEST_F(MediaSessionDescriptionFactoryTest,
3170 CreateOfferWithMediaSectionStoppedByOfferer) {
3171 // Create an offer with two audio sections and one of them is stopped.
3172 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003173 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3174 RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
3175 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3176 RtpTransceiverDirection::kInactive, kStopped, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003177 std::unique_ptr<SessionDescription> offer(
3178 f1_.CreateOffer(offer_opts, nullptr));
3179 ASSERT_TRUE(offer);
3180 ASSERT_EQ(2u, offer->contents().size());
3181 EXPECT_FALSE(offer->contents()[0].rejected);
3182 EXPECT_TRUE(offer->contents()[1].rejected);
3183}
3184
3185// Test that the media section will be rejected in answer if the corresponding
3186// MediaDescriptionOptions is stopped by the offerer.
3187TEST_F(MediaSessionDescriptionFactoryTest,
3188 CreateAnswerWithMediaSectionStoppedByOfferer) {
3189 // Create an offer with two audio sections and one of them is stopped.
3190 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003191 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3192 RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
3193 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3194 RtpTransceiverDirection::kInactive, kStopped, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003195 std::unique_ptr<SessionDescription> offer(
3196 f1_.CreateOffer(offer_opts, nullptr));
3197 ASSERT_TRUE(offer);
3198 ASSERT_EQ(2u, offer->contents().size());
3199 EXPECT_FALSE(offer->contents()[0].rejected);
3200 EXPECT_TRUE(offer->contents()[1].rejected);
3201
3202 // Create an answer based on the offer.
3203 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003204 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3205 RtpTransceiverDirection::kSendRecv, kActive, &answer_opts);
3206 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3207 RtpTransceiverDirection::kSendRecv, kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003208 std::unique_ptr<SessionDescription> answer(
3209 f2_.CreateAnswer(offer.get(), answer_opts, nullptr));
3210 ASSERT_EQ(2u, answer->contents().size());
3211 EXPECT_FALSE(answer->contents()[0].rejected);
3212 EXPECT_TRUE(answer->contents()[1].rejected);
3213}
3214
3215// Test that the media section will be rejected in answer if the corresponding
3216// MediaDescriptionOptions is stopped by the answerer.
3217TEST_F(MediaSessionDescriptionFactoryTest,
3218 CreateAnswerWithMediaSectionRejectedByAnswerer) {
3219 // Create an offer with two audio sections.
3220 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003221 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3222 RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
3223 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3224 RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003225 std::unique_ptr<SessionDescription> offer(
3226 f1_.CreateOffer(offer_opts, nullptr));
3227 ASSERT_TRUE(offer);
3228 ASSERT_EQ(2u, offer->contents().size());
3229 ASSERT_FALSE(offer->contents()[0].rejected);
3230 ASSERT_FALSE(offer->contents()[1].rejected);
3231
3232 // The answerer rejects one of the audio sections.
3233 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003234 AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
3235 RtpTransceiverDirection::kSendRecv, kActive, &answer_opts);
3236 AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
3237 RtpTransceiverDirection::kInactive, kStopped, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003238 std::unique_ptr<SessionDescription> answer(
3239 f2_.CreateAnswer(offer.get(), answer_opts, nullptr));
3240 ASSERT_EQ(2u, answer->contents().size());
3241 EXPECT_FALSE(answer->contents()[0].rejected);
3242 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08003243
3244 // The TransportInfo of the rejected m= section is expected to be added in the
3245 // answer.
3246 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07003247}
3248
3249// Test the generated media sections has the same order of the
3250// corresponding MediaDescriptionOptions.
3251TEST_F(MediaSessionDescriptionFactoryTest,
3252 CreateOfferRespectsMediaDescriptionOptionsOrder) {
3253 MediaSessionOptions opts;
3254 // This tests put video section first because normally audio comes first by
3255 // default.
Steve Anton4e70a722017-11-28 14:57:10 -08003256 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
3257 kActive, &opts);
3258 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kSendRecv,
3259 kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003260 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3261
3262 ASSERT_TRUE(offer);
3263 ASSERT_EQ(2u, offer->contents().size());
3264 EXPECT_EQ("video", offer->contents()[0].name);
3265 EXPECT_EQ("audio", offer->contents()[1].name);
3266}
3267
3268// Test that different media sections using the same codec have same payload
3269// type.
3270TEST_F(MediaSessionDescriptionFactoryTest,
3271 PayloadTypesSharedByMediaSectionsOfSameType) {
3272 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003273 AddMediaSection(MEDIA_TYPE_VIDEO, "video1",
3274 RtpTransceiverDirection::kSendRecv, kActive, &opts);
3275 AddMediaSection(MEDIA_TYPE_VIDEO, "video2",
3276 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003277 // Create an offer with two video sections using same codecs.
3278 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3279 ASSERT_TRUE(offer);
3280 ASSERT_EQ(2u, offer->contents().size());
3281 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003282 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003283 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003284 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003285 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3286 ASSERT_EQ(2u, vcd1->codecs().size());
3287 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3288 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3289 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
3290 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
3291
3292 // Create answer and negotiate the codecs.
3293 std::unique_ptr<SessionDescription> answer(
3294 f2_.CreateAnswer(offer.get(), opts, nullptr));
3295 ASSERT_TRUE(answer);
3296 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08003297 vcd1 = answer->contents()[0].media_description()->as_video();
3298 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003299 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3300 ASSERT_EQ(1u, vcd1->codecs().size());
3301 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3302 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3303}
3304
3305// Test that the codec preference order per media section is respected in
3306// subsequent offer.
3307TEST_F(MediaSessionDescriptionFactoryTest,
3308 CreateOfferRespectsCodecPreferenceOrder) {
3309 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003310 AddMediaSection(MEDIA_TYPE_VIDEO, "video1",
3311 RtpTransceiverDirection::kSendRecv, kActive, &opts);
3312 AddMediaSection(MEDIA_TYPE_VIDEO, "video2",
3313 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003314 // Create an offer with two video sections using same codecs.
3315 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3316 ASSERT_TRUE(offer);
3317 ASSERT_EQ(2u, offer->contents().size());
3318 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003319 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003320 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003321 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003322 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3323 EXPECT_EQ(video_codecs, vcd1->codecs());
3324 EXPECT_EQ(video_codecs, vcd2->codecs());
3325
3326 // Change the codec preference of the first video section and create a
3327 // follow-up offer.
3328 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3329 vcd1->set_codecs(video_codecs_reverse);
3330 std::unique_ptr<SessionDescription> updated_offer(
3331 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08003332 vcd1 = updated_offer->contents()[0].media_description()->as_video();
3333 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003334 // The video codec preference order should be respected.
3335 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3336 EXPECT_EQ(video_codecs, vcd2->codecs());
3337}
3338
3339// Test that the codec preference order per media section is respected in
3340// the answer.
3341TEST_F(MediaSessionDescriptionFactoryTest,
3342 CreateAnswerRespectsCodecPreferenceOrder) {
3343 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003344 AddMediaSection(MEDIA_TYPE_VIDEO, "video1",
3345 RtpTransceiverDirection::kSendRecv, kActive, &opts);
3346 AddMediaSection(MEDIA_TYPE_VIDEO, "video2",
3347 RtpTransceiverDirection::kSendRecv, kActive, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003348 // Create an offer with two video sections using same codecs.
3349 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3350 ASSERT_TRUE(offer);
3351 ASSERT_EQ(2u, offer->contents().size());
3352 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003353 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003354 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003355 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003356 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3357 EXPECT_EQ(video_codecs, vcd1->codecs());
3358 EXPECT_EQ(video_codecs, vcd2->codecs());
3359
3360 // Change the codec preference of the first video section and create an
3361 // answer.
3362 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3363 vcd1->set_codecs(video_codecs_reverse);
3364 std::unique_ptr<SessionDescription> answer(
3365 f1_.CreateAnswer(offer.get(), opts, nullptr));
Steve Antonb1c1de12017-12-21 15:14:30 -08003366 vcd1 = answer->contents()[0].media_description()->as_video();
3367 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003368 // The video codec preference order should be respected.
3369 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3370 EXPECT_EQ(video_codecs, vcd2->codecs());
3371}
3372
Zhi Huang6f367472017-11-22 13:20:02 -08003373// Test that when creating an answer, the codecs use local parameters instead of
3374// the remote ones.
3375TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
3376 const std::string audio_param_name = "audio_param";
3377 const std::string audio_value1 = "audio_v1";
3378 const std::string audio_value2 = "audio_v2";
3379 const std::string video_param_name = "video_param";
3380 const std::string video_value1 = "video_v1";
3381 const std::string video_value2 = "video_v2";
3382
3383 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
3384 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
3385 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
3386 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
3387
3388 // Set the parameters for codecs.
3389 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
3390 video_codecs1[0].SetParam(video_param_name, video_value1);
3391 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
3392 video_codecs2[0].SetParam(video_param_name, video_value2);
3393
3394 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
3395 f1_.set_video_codecs(video_codecs1);
3396 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
3397 f2_.set_video_codecs(video_codecs2);
3398
3399 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003400 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kSendRecv,
3401 kActive, &opts);
3402 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
3403 kActive, &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08003404
3405 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3406 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08003407 auto offer_acd = offer->contents()[0].media_description()->as_audio();
3408 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08003409 std::string value;
3410 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
3411 EXPECT_EQ(audio_value1, value);
3412 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
3413 EXPECT_EQ(video_value1, value);
3414
3415 std::unique_ptr<SessionDescription> answer(
3416 f2_.CreateAnswer(offer.get(), opts, nullptr));
3417 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08003418 auto answer_acd = answer->contents()[0].media_description()->as_audio();
3419 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08003420 // Use the parameters from the local codecs.
3421 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
3422 EXPECT_EQ(audio_value2, value);
3423 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
3424 EXPECT_EQ(video_value2, value);
3425}
3426
Steve Anton9c1fb1e2018-02-26 15:09:41 -08003427// Test that matching packetization-mode is part of the criteria for matching
3428// H264 codecs (in addition to profile-level-id). Previously, this was not the
3429// case, so the first H264 codec with the same profile-level-id would match and
3430// the payload type in the answer would be incorrect.
3431// This is a regression test for bugs.webrtc.org/8808
3432TEST_F(MediaSessionDescriptionFactoryTest,
3433 H264MatchCriteriaIncludesPacketizationMode) {
3434 // Create two H264 codecs with the same profile level ID and different
3435 // packetization modes.
3436 VideoCodec h264_pm0(96, "H264");
3437 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
3438 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
3439 VideoCodec h264_pm1(97, "H264");
3440 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
3441 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
3442
3443 // Offerer will send both codecs, answerer should choose the one with matching
3444 // packetization mode (and not the first one it sees).
3445 f1_.set_video_codecs({h264_pm0, h264_pm1});
3446 f2_.set_video_codecs({h264_pm1});
3447
3448 MediaSessionOptions opts;
3449 AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
3450 kActive, &opts);
3451
3452 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3453 ASSERT_TRUE(offer);
3454
3455 std::unique_ptr<SessionDescription> answer(
3456 f2_.CreateAnswer(offer.get(), opts, nullptr));
3457 ASSERT_TRUE(answer);
3458
3459 // Answer should have one negotiated codec with packetization-mode=1 using the
3460 // offered payload type.
3461 ASSERT_EQ(1u, answer->contents().size());
3462 auto answer_vcd = answer->contents()[0].media_description()->as_video();
3463 ASSERT_EQ(1u, answer_vcd->codecs().size());
3464 auto answer_codec = answer_vcd->codecs()[0];
3465 EXPECT_EQ(h264_pm1.id, answer_codec.id);
3466}
3467
zhihuangcf5b37c2016-05-05 11:44:35 -07003468class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
3469 public:
3470 MediaProtocolTest() : f1_(&tdf1_), f2_(&tdf2_) {
ossu075af922016-06-14 03:29:38 -07003471 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
3472 MAKE_VECTOR(kAudioCodecs1));
zhihuangcf5b37c2016-05-05 11:44:35 -07003473 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
3474 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07003475 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
3476 MAKE_VECTOR(kAudioCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07003477 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
3478 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
3479 f1_.set_secure(SEC_ENABLED);
3480 f2_.set_secure(SEC_ENABLED);
3481 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07003482 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07003483 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07003484 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07003485 tdf1_.set_secure(SEC_ENABLED);
3486 tdf2_.set_secure(SEC_ENABLED);
3487 }
3488
3489 protected:
3490 MediaSessionDescriptionFactory f1_;
3491 MediaSessionDescriptionFactory f2_;
3492 TransportDescriptionFactory tdf1_;
3493 TransportDescriptionFactory tdf2_;
3494};
3495
3496TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
3497 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003498 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
zhihuangcf5b37c2016-05-05 11:44:35 -07003499 std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
3500 ASSERT_TRUE(offer.get() != nullptr);
3501 // Set the protocol for all the contents.
3502 for (auto content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08003503 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07003504 }
3505 std::unique_ptr<SessionDescription> answer(
3506 f2_.CreateAnswer(offer.get(), opts, nullptr));
3507 const ContentInfo* ac = answer->GetContentByName("audio");
3508 const ContentInfo* vc = answer->GetContentByName("video");
3509 ASSERT_TRUE(ac != nullptr);
3510 ASSERT_TRUE(vc != nullptr);
3511 EXPECT_FALSE(ac->rejected); // the offer is accepted
3512 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003513 const AudioContentDescription* acd = ac->media_description()->as_audio();
3514 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07003515 EXPECT_EQ(GetParam(), acd->protocol());
3516 EXPECT_EQ(GetParam(), vcd->protocol());
3517}
3518
3519INSTANTIATE_TEST_CASE_P(MediaProtocolPatternTest,
3520 MediaProtocolTest,
3521 ::testing::ValuesIn(kMediaProtocols));
3522INSTANTIATE_TEST_CASE_P(MediaProtocolDtlsPatternTest,
3523 MediaProtocolTest,
3524 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07003525
3526TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
3527 TransportDescriptionFactory tdf;
3528 MediaSessionDescriptionFactory sf(&tdf);
3529 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
3530 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
3531
3532 // The merged list of codecs should contain any send codecs that are also
3533 // nominally in the recieve codecs list. Payload types should be picked from
3534 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
3535 // (set to 1). This equals what happens when the send codecs are used in an
3536 // offer and the receive codecs are used in the following answer.
3537 const std::vector<AudioCodec> sendrecv_codecs =
3538 MAKE_VECTOR(kAudioCodecsAnswer);
3539 const std::vector<AudioCodec> no_codecs;
3540
3541 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
3542 << "Please don't change shared test data!";
3543 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
3544 << "Please don't change shared test data!";
3545 // Alter iLBC send codec to have zero channels, to test that that is handled
3546 // properly.
3547 send_codecs[1].channels = 0;
3548
3549 // Alther iLBC receive codec to be lowercase, to test that case conversions
3550 // are handled properly.
3551 recv_codecs[2].name = "ilbc";
3552
3553 // Test proper merge
3554 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003555 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
3556 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
3557 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003558
3559 // Test empty send codecs list
3560 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003561 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
3562 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
3563 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003564
3565 // Test empty recv codecs list
3566 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003567 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
3568 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
3569 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003570
3571 // Test all empty codec lists
3572 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07003573 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
3574 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
3575 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07003576}
3577
3578namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07003579// Compare the two vectors of codecs ignoring the payload type.
3580template <class Codec>
3581bool CodecsMatch(const std::vector<Codec>& codecs1,
3582 const std::vector<Codec>& codecs2) {
3583 if (codecs1.size() != codecs2.size()) {
3584 return false;
3585 }
3586
3587 for (size_t i = 0; i < codecs1.size(); ++i) {
3588 if (!codecs1[i].Matches(codecs2[i])) {
3589 return false;
3590 }
3591 }
3592 return true;
3593}
3594
Steve Anton4e70a722017-11-28 14:57:10 -08003595void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07003596 TransportDescriptionFactory tdf;
3597 MediaSessionDescriptionFactory sf(&tdf);
3598 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
3599 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
3600 const std::vector<AudioCodec> sendrecv_codecs =
3601 MAKE_VECTOR(kAudioCodecsAnswer);
3602 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07003603
3604 MediaSessionOptions opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003605 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", direction, kActive, &opts);
3606
Steve Anton4e70a722017-11-28 14:57:10 -08003607 if (direction == RtpTransceiverDirection::kSendRecv ||
3608 direction == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003609 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003610 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003611 }
ossu075af922016-06-14 03:29:38 -07003612
3613 std::unique_ptr<SessionDescription> offer(sf.CreateOffer(opts, NULL));
3614 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003615 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07003616
3617 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07003618 // that the codecs put in are right. This happens when we neither want to
3619 // send nor receive audio. The checks are still in place if at some point
3620 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07003621 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08003622 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003623 // sendrecv and inactive should both present lists as if the channel was
3624 // to be used for sending and receiving. Inactive essentially means it
3625 // might eventually be used anything, but we don't know more at this
3626 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08003627 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003628 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08003629 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003630 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07003631 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07003632 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07003633 }
3634 }
3635}
3636
3637static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07003638 AudioCodec(0, "codec0", 16000, -1, 1),
3639 AudioCodec(1, "codec1", 8000, 13300, 1),
3640 AudioCodec(2, "codec2", 8000, 64000, 1),
3641 AudioCodec(3, "codec3", 8000, 64000, 1),
3642 AudioCodec(4, "codec4", 8000, 0, 2),
3643 AudioCodec(5, "codec5", 32000, 0, 1),
3644 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07003645
zhihuang1c378ed2017-08-17 14:10:50 -07003646/* The codecs groups below are chosen as per the matrix below. The objective
3647 * is to have different sets of codecs in the inputs, to get unique sets of
3648 * codecs after negotiation, depending on offer and answer communication
3649 * directions. One-way directions in the offer should either result in the
3650 * opposite direction in the answer, or an inactive answer. Regardless, the
3651 * choice of codecs should be as if the answer contained the opposite
3652 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07003653 *
3654 * | Offer | Answer | Result
3655 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
3656 * 0 | x - - | - x - | x - - - -
3657 * 1 | x x x | - x - | x - - x -
3658 * 2 | - x - | x - - | - x - - -
3659 * 3 | x x x | x - - | - x x - -
3660 * 4 | - x - | x x x | - x - - -
3661 * 5 | x - - | x x x | x - - - -
3662 * 6 | x x x | x x x | x x x x x
3663 */
3664// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07003665static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
3666static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07003667// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
3668// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07003669static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
3670static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07003671// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07003672static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
3673static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
3674static const int kResultSendrecv_SendCodecs[] = {3, 6};
3675static const int kResultSendrecv_RecvCodecs[] = {1, 6};
3676static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07003677
3678template <typename T, int IDXS>
3679std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
3680 std::vector<T> out;
3681 out.reserve(IDXS);
3682 for (int idx : indices)
3683 out.push_back(array[idx]);
3684
3685 return out;
3686}
3687
Steve Anton4e70a722017-11-28 14:57:10 -08003688void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
3689 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07003690 bool add_legacy_stream) {
3691 TransportDescriptionFactory offer_tdf;
3692 TransportDescriptionFactory answer_tdf;
3693 MediaSessionDescriptionFactory offer_factory(&offer_tdf);
3694 MediaSessionDescriptionFactory answer_factory(&answer_tdf);
3695 offer_factory.set_audio_codecs(
3696 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
3697 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
3698 answer_factory.set_audio_codecs(
3699 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
3700 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
3701
ossu075af922016-06-14 03:29:38 -07003702 MediaSessionOptions offer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003703 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", offer_direction, kActive,
3704 &offer_opts);
3705
Steve Anton4e70a722017-11-28 14:57:10 -08003706 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
zhihuang1c378ed2017-08-17 14:10:50 -07003707 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003708 {kMediaStream1}, 1, &offer_opts);
ossu075af922016-06-14 03:29:38 -07003709 }
3710
3711 std::unique_ptr<SessionDescription> offer(
3712 offer_factory.CreateOffer(offer_opts, NULL));
3713 ASSERT_TRUE(offer.get() != NULL);
3714
3715 MediaSessionOptions answer_opts;
zhihuang1c378ed2017-08-17 14:10:50 -07003716 AddMediaSection(MEDIA_TYPE_AUDIO, "audio", answer_direction, kActive,
3717 &answer_opts);
3718
Steve Anton4e70a722017-11-28 14:57:10 -08003719 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
zhihuang1c378ed2017-08-17 14:10:50 -07003720 AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
Steve Anton8ffb9c32017-08-31 15:45:38 -07003721 {kMediaStream1}, 1, &answer_opts);
ossu075af922016-06-14 03:29:38 -07003722 }
3723 std::unique_ptr<SessionDescription> answer(
3724 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL));
3725 const ContentInfo* ac = answer->GetContentByName("audio");
3726
zhihuang1c378ed2017-08-17 14:10:50 -07003727 // If the factory didn't add any audio content to the answer, we cannot
3728 // check that the codecs put in are right. This happens when we neither want
3729 // to send nor receive audio. The checks are still in place if at some point
3730 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07003731 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08003732 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
3733 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07003734
ossu075af922016-06-14 03:29:38 -07003735 std::vector<AudioCodec> target_codecs;
3736 // For offers with sendrecv or inactive, we should never reply with more
3737 // codecs than offered, with these codec sets.
3738 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08003739 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07003740 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
3741 kResultSendrecv_SendrecvCodecs);
3742 break;
Steve Anton4e70a722017-11-28 14:57:10 -08003743 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07003744 target_codecs =
3745 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07003746 break;
Steve Anton4e70a722017-11-28 14:57:10 -08003747 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07003748 target_codecs =
3749 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07003750 break;
Steve Anton4e70a722017-11-28 14:57:10 -08003751 case RtpTransceiverDirection::kSendRecv:
3752 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003753 target_codecs =
3754 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08003755 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07003756 target_codecs =
3757 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07003758 } else {
3759 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
3760 kResultSendrecv_SendrecvCodecs);
3761 }
3762 break;
3763 }
3764
zhihuang1c378ed2017-08-17 14:10:50 -07003765 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02003766 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07003767 bool first = true;
3768 os << "{";
3769 for (const auto& c : codecs) {
3770 os << (first ? " " : ", ") << c.id;
3771 first = false;
3772 }
3773 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02003774 return os.Release();
ossu075af922016-06-14 03:29:38 -07003775 };
3776
3777 EXPECT_TRUE(acd->codecs() == target_codecs)
3778 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08003779 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
3780 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07003781 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08003782 << webrtc::RtpTransceiverDirectionToString(answer_direction)
3783 << "; got: "
3784 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07003785 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08003786 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07003787 << "Only inactive offers are allowed to not generate any audio "
3788 "content";
ossu075af922016-06-14 03:29:38 -07003789 }
3790}
brandtr03d5fb12016-11-22 03:37:59 -08003791
3792} // namespace
ossu075af922016-06-14 03:29:38 -07003793
3794class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08003795 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07003796
3797TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003798 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07003799}
3800
3801INSTANTIATE_TEST_CASE_P(MediaSessionDescriptionFactoryTest,
3802 AudioCodecsOfferTest,
Steve Anton4e70a722017-11-28 14:57:10 -08003803 ::testing::Values(RtpTransceiverDirection::kSendOnly,
3804 RtpTransceiverDirection::kRecvOnly,
3805 RtpTransceiverDirection::kSendRecv,
3806 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07003807
3808class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08003809 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
3810 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07003811 bool>> {};
ossu075af922016-06-14 03:29:38 -07003812
3813TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08003814 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
3815 ::testing::get<1>(GetParam()),
3816 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07003817}
3818
zhihuang1c378ed2017-08-17 14:10:50 -07003819INSTANTIATE_TEST_CASE_P(
3820 MediaSessionDescriptionFactoryTest,
3821 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08003822 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
3823 RtpTransceiverDirection::kRecvOnly,
3824 RtpTransceiverDirection::kSendRecv,
3825 RtpTransceiverDirection::kInactive),
3826 ::testing::Values(RtpTransceiverDirection::kSendOnly,
3827 RtpTransceiverDirection::kRecvOnly,
3828 RtpTransceiverDirection::kSendRecv,
3829 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07003830 ::testing::Bool()));