blob: a901dedb706d717c87a8eec046f041b2bafc8030 [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
Jonas Olssona4d87372019-07-05 19:08:33 +020011#include "pc/media_session.h"
12
Amit Hilbuch77938e62018-12-21 09:23:38 -080013#include <algorithm>
kwiberg31022942016-03-11 14:18:21 -080014#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000015#include <string>
Harald Alvestrand1716d392019-06-03 20:35:45 +020016#include <utility>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000017#include <vector>
18
Steve Anton64b626b2019-01-28 17:25:26 -080019#include "absl/algorithm/container.h"
Steve Anton6fe1fba2018-12-11 10:15:23 -080020#include "absl/memory/memory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "media/base/codec.h"
Steve Anton10542f22019-01-11 09:11:00 -080022#include "media/base/test_utils.h"
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +020023#include "media/sctp/sctp_transport_internal.h"
Steve Anton10542f22019-01-11 09:11:00 -080024#include "p2p/base/p2p_constants.h"
25#include "p2p/base/transport_description.h"
26#include "p2p/base/transport_info.h"
Steve Anton10542f22019-01-11 09:11:00 -080027#include "pc/rtp_media_utils.h"
28#include "pc/srtp_filter.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020029#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080030#include "rtc_base/fake_ssl_identity.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020031#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 09:11:00 -080032#include "rtc_base/message_digest.h"
33#include "rtc_base/ssl_adapter.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020034#include "rtc_base/strings/string_builder.h"
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080035#include "rtc_base/unique_id_generator.h"
Steve Antone38a5a12018-11-21 16:05:15 -080036#include "test/gmock.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000037
Yves Gerey665174f2018-06-19 15:03:05 +020038#define ASSERT_CRYPTO(cd, s, cs) \
39 ASSERT_EQ(s, cd->cryptos().size()); \
Steve Antone38a5a12018-11-21 16:05:15 -080040 ASSERT_EQ(cs, cd->cryptos()[0].cipher_suite)
henrike@webrtc.org28e20752013-07-10 00:45:36 +000041
42typedef std::vector<cricket::Candidate> Candidates;
43
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080044using cricket::AudioCodec;
45using cricket::AudioContentDescription;
46using cricket::ContentInfo;
47using cricket::CryptoParamsVec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080048using cricket::GetFirstAudioContent;
49using cricket::GetFirstAudioContentDescription;
50using cricket::GetFirstDataContent;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020051using cricket::GetFirstRtpDataContentDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080052using cricket::GetFirstVideoContent;
53using cricket::GetFirstVideoContentDescription;
54using cricket::kAutoBandwidth;
55using cricket::MEDIA_TYPE_AUDIO;
56using cricket::MEDIA_TYPE_DATA;
57using cricket::MEDIA_TYPE_VIDEO;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000058using cricket::MediaContentDescription;
zhihuang1c378ed2017-08-17 14:10:50 -070059using cricket::MediaDescriptionOptions;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080060using cricket::MediaProtocolType;
61using cricket::MediaSessionDescriptionFactory;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000062using cricket::MediaSessionOptions;
63using cricket::MediaType;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080064using cricket::RidDescription;
65using cricket::RidDirection;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020066using cricket::RtpDataCodec;
67using cricket::RtpDataContentDescription;
68using cricket::SctpDataContentDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080069using cricket::SEC_DISABLED;
70using cricket::SEC_ENABLED;
71using cricket::SEC_REQUIRED;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000072using cricket::SessionDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080073using cricket::SimulcastDescription;
74using cricket::SimulcastLayer;
75using cricket::SimulcastLayerList;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000076using cricket::SsrcGroup;
77using cricket::StreamParams;
78using cricket::StreamParamsVec;
79using cricket::TransportDescription;
80using cricket::TransportDescriptionFactory;
81using cricket::TransportInfo;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000082using cricket::VideoCodec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080083using cricket::VideoContentDescription;
jbauchcb560652016-08-04 05:20:32 -070084using rtc::CS_AEAD_AES_128_GCM;
85using rtc::CS_AEAD_AES_256_GCM;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080086using rtc::CS_AES_CM_128_HMAC_SHA1_32;
87using rtc::CS_AES_CM_128_HMAC_SHA1_80;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080088using rtc::UniqueRandomIdGenerator;
Mirko Bonadei6a489f22019-04-09 15:11:12 +020089using ::testing::Contains;
90using ::testing::Each;
91using ::testing::ElementsAreArray;
92using ::testing::Eq;
93using ::testing::Field;
94using ::testing::IsEmpty;
95using ::testing::IsFalse;
96using ::testing::Ne;
97using ::testing::Not;
98using ::testing::Pointwise;
99using ::testing::SizeIs;
isheriff6f8d6862016-05-26 11:24:55 -0700100using webrtc::RtpExtension;
Steve Anton4e70a722017-11-28 14:57:10 -0800101using webrtc::RtpTransceiverDirection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000102
103static const AudioCodec kAudioCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700104 AudioCodec(103, "ISAC", 16000, -1, 1),
105 AudioCodec(102, "iLBC", 8000, 13300, 1),
106 AudioCodec(0, "PCMU", 8000, 64000, 1),
107 AudioCodec(8, "PCMA", 8000, 64000, 1),
108 AudioCodec(117, "red", 8000, 0, 1),
109 AudioCodec(107, "CN", 48000, 0, 1)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000110
111static const AudioCodec kAudioCodecs2[] = {
Henrik Lundinf8ed5612018-05-07 12:05:57 +0200112 AudioCodec(126, "foo", 16000, 22000, 1),
deadbeef67cf2c12016-04-13 10:07:16 -0700113 AudioCodec(0, "PCMU", 8000, 64000, 1),
114 AudioCodec(127, "iLBC", 8000, 13300, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000115};
116
117static const AudioCodec kAudioCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700118 AudioCodec(102, "iLBC", 8000, 13300, 1),
119 AudioCodec(0, "PCMU", 8000, 64000, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000120};
121
perkj26752742016-10-24 01:21:16 -0700122static const VideoCodec kVideoCodecs1[] = {VideoCodec(96, "H264-SVC"),
123 VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000124
zhihuang1c378ed2017-08-17 14:10:50 -0700125static const VideoCodec kVideoCodecs1Reverse[] = {VideoCodec(97, "H264"),
126 VideoCodec(96, "H264-SVC")};
127
perkj26752742016-10-24 01:21:16 -0700128static const VideoCodec kVideoCodecs2[] = {VideoCodec(126, "H264"),
129 VideoCodec(127, "H263")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000130
perkj26752742016-10-24 01:21:16 -0700131static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000132
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200133static const RtpDataCodec kDataCodecs1[] = {RtpDataCodec(98, "binary-data"),
134 RtpDataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000135
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200136static const RtpDataCodec kDataCodecs2[] = {RtpDataCodec(126, "binary-data"),
137 RtpDataCodec(127, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000138
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200139static const RtpDataCodec kDataCodecsAnswer[] = {
140 RtpDataCodec(98, "binary-data"), RtpDataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000141
isheriff6f8d6862016-05-26 11:24:55 -0700142static const RtpExtension kAudioRtpExtension1[] = {
143 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
144 RtpExtension("http://google.com/testing/audio_something", 10),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000145};
146
jbauch5869f502017-06-29 12:31:36 -0700147static const RtpExtension kAudioRtpExtensionEncrypted1[] = {
148 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
149 RtpExtension("http://google.com/testing/audio_something", 10),
150 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
151};
152
isheriff6f8d6862016-05-26 11:24:55 -0700153static const RtpExtension kAudioRtpExtension2[] = {
154 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
155 RtpExtension("http://google.com/testing/audio_something_else", 8),
156 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000157};
158
isheriff6f8d6862016-05-26 11:24:55 -0700159static const RtpExtension kAudioRtpExtension3[] = {
160 RtpExtension("http://google.com/testing/audio_something", 2),
161 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
deadbeefa5b273a2015-08-20 17:30:13 -0700162};
163
jbauch5869f502017-06-29 12:31:36 -0700164static const RtpExtension kAudioRtpExtension3ForEncryption[] = {
165 RtpExtension("http://google.com/testing/audio_something", 2),
166 // Use RTP extension that supports encryption.
167 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
168};
169
170static const RtpExtension kAudioRtpExtension3ForEncryptionOffer[] = {
171 RtpExtension("http://google.com/testing/audio_something", 2),
172 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
173 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14, true),
174};
175
isheriff6f8d6862016-05-26 11:24:55 -0700176static const RtpExtension kAudioRtpExtensionAnswer[] = {
177 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000178};
179
jbauch5869f502017-06-29 12:31:36 -0700180static const RtpExtension kAudioRtpExtensionEncryptedAnswer[] = {
181 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
182};
183
isheriff6f8d6862016-05-26 11:24:55 -0700184static const RtpExtension kVideoRtpExtension1[] = {
185 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
186 RtpExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000187};
188
jbauch5869f502017-06-29 12:31:36 -0700189static const RtpExtension kVideoRtpExtensionEncrypted1[] = {
190 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
191 RtpExtension("http://google.com/testing/video_something", 13),
192 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
193};
194
isheriff6f8d6862016-05-26 11:24:55 -0700195static const RtpExtension kVideoRtpExtension2[] = {
196 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
197 RtpExtension("http://google.com/testing/video_something_else", 14),
198 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000199};
200
isheriff6f8d6862016-05-26 11:24:55 -0700201static const RtpExtension kVideoRtpExtension3[] = {
202 RtpExtension("http://google.com/testing/video_something", 4),
203 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
deadbeefa5b273a2015-08-20 17:30:13 -0700204};
205
jbauch5869f502017-06-29 12:31:36 -0700206static const RtpExtension kVideoRtpExtension3ForEncryption[] = {
207 RtpExtension("http://google.com/testing/video_something", 4),
208 // Use RTP extension that supports encryption.
209 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 5),
210};
211
isheriff6f8d6862016-05-26 11:24:55 -0700212static const RtpExtension kVideoRtpExtensionAnswer[] = {
213 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000214};
215
jbauch5869f502017-06-29 12:31:36 -0700216static const RtpExtension kVideoRtpExtensionEncryptedAnswer[] = {
217 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
218};
219
Johannes Kronce8e8672019-02-22 13:06:44 +0100220static const RtpExtension kRtpExtensionTransportSequenceNumber01[] = {
221 RtpExtension("http://www.ietf.org/id/"
222 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
223 1),
224};
225
226static const RtpExtension kRtpExtensionTransportSequenceNumber01And02[] = {
227 RtpExtension("http://www.ietf.org/id/"
228 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
229 1),
Johannes Kron8cc711a2019-03-07 22:36:35 +0100230 RtpExtension(
231 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
232 2),
Johannes Kronce8e8672019-02-22 13:06:44 +0100233};
234
235static const RtpExtension kRtpExtensionTransportSequenceNumber02[] = {
Johannes Kron8cc711a2019-03-07 22:36:35 +0100236 RtpExtension(
237 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
238 2),
Johannes Kronce8e8672019-02-22 13:06:44 +0100239};
240
Peter Boström0c4e06b2015-10-07 12:23:21 +0200241static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
242static const uint32_t kSimSsrc[] = {10, 20, 30};
243static const uint32_t kFec1Ssrc[] = {10, 11};
244static const uint32_t kFec2Ssrc[] = {20, 21};
245static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000246
247static const char kMediaStream1[] = "stream_1";
248static const char kMediaStream2[] = "stream_2";
249static const char kVideoTrack1[] = "video_1";
250static const char kVideoTrack2[] = "video_2";
251static const char kAudioTrack1[] = "audio_1";
252static const char kAudioTrack2[] = "audio_2";
253static const char kAudioTrack3[] = "audio_3";
254static const char kDataTrack1[] = "data_1";
255static const char kDataTrack2[] = "data_2";
256static const char kDataTrack3[] = "data_3";
257
zhihuangcf5b37c2016-05-05 11:44:35 -0700258static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
259 "RTP/SAVPF"};
260static const char* kMediaProtocolsDtls[] = {
261 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
262 "UDP/TLS/RTP/SAVP"};
263
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700264// SRTP cipher name negotiated by the tests. This must be updated if the
265// default changes.
266static const char* kDefaultSrtpCryptoSuite = CS_AES_CM_128_HMAC_SHA1_80;
267static const char* kDefaultSrtpCryptoSuiteGcm = CS_AEAD_AES_256_GCM;
268
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800269// These constants are used to make the code using "AddMediaDescriptionOptions"
270// more readable.
zhihuang1c378ed2017-08-17 14:10:50 -0700271static constexpr bool kStopped = true;
272static constexpr bool kActive = false;
273
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000274static bool IsMediaContentOfType(const ContentInfo* content,
275 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800276 RTC_DCHECK(content);
277 return content->media_description()->type() == media_type;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000278}
279
Steve Anton4e70a722017-11-28 14:57:10 -0800280static RtpTransceiverDirection GetMediaDirection(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800281 RTC_DCHECK(content);
282 return content->media_description()->direction();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000283}
284
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000285static void AddRtxCodec(const VideoCodec& rtx_codec,
286 std::vector<VideoCodec>* codecs) {
magjedb05fa242016-11-11 04:00:16 -0800287 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000288 codecs->push_back(rtx_codec);
289}
290
291template <class T>
292static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
293 std::vector<std::string> codec_names;
Mirko Bonadei649a4c22019-01-29 10:11:53 +0100294 codec_names.reserve(codecs.size());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000295 for (const auto& codec : codecs) {
296 codec_names.push_back(codec.name);
297 }
298 return codec_names;
299}
300
zhihuang1c378ed2017-08-17 14:10:50 -0700301// This is used for test only. MIDs are not the identification of the
302// MediaDescriptionOptions since some end points may not support MID and the SDP
303// may not contain 'mid'.
304std::vector<MediaDescriptionOptions>::iterator FindFirstMediaDescriptionByMid(
305 const std::string& mid,
306 MediaSessionOptions* opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800307 return absl::c_find_if(
308 opts->media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700309 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
310}
311
312std::vector<MediaDescriptionOptions>::const_iterator
313FindFirstMediaDescriptionByMid(const std::string& mid,
314 const MediaSessionOptions& opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800315 return absl::c_find_if(
316 opts.media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700317 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
zhihuang1c378ed2017-08-17 14:10:50 -0700318}
319
320// Add a media section to the |session_options|.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800321static void AddMediaDescriptionOptions(MediaType type,
322 const std::string& mid,
323 RtpTransceiverDirection direction,
324 bool stopped,
325 MediaSessionOptions* opts) {
Steve Anton4e70a722017-11-28 14:57:10 -0800326 opts->media_description_options.push_back(
327 MediaDescriptionOptions(type, mid, direction, stopped));
zhihuang1c378ed2017-08-17 14:10:50 -0700328}
329
Steve Anton4e70a722017-11-28 14:57:10 -0800330static void AddAudioVideoSections(RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700331 MediaSessionOptions* opts) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800332 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
333 opts);
334 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video", direction, kActive,
335 opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700336}
337
338static void AddDataSection(cricket::DataChannelType dct,
Steve Anton4e70a722017-11-28 14:57:10 -0800339 RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700340 MediaSessionOptions* opts) {
341 opts->data_channel_type = dct;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800342 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700343}
344
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800345static void AttachSenderToMediaDescriptionOptions(
Steve Anton8ffb9c32017-08-31 15:45:38 -0700346 const std::string& mid,
347 MediaType type,
348 const std::string& track_id,
349 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800350 const std::vector<RidDescription>& rids,
351 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700352 int num_sim_layer,
353 MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -0700354 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
355 switch (type) {
356 case MEDIA_TYPE_AUDIO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700357 it->AddAudioSender(track_id, stream_ids);
zhihuang1c378ed2017-08-17 14:10:50 -0700358 break;
359 case MEDIA_TYPE_VIDEO:
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800360 it->AddVideoSender(track_id, stream_ids, rids, simulcast_layers,
361 num_sim_layer);
zhihuang1c378ed2017-08-17 14:10:50 -0700362 break;
363 case MEDIA_TYPE_DATA:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700364 RTC_CHECK(stream_ids.size() == 1U);
365 it->AddRtpDataChannel(track_id, stream_ids[0]);
zhihuang1c378ed2017-08-17 14:10:50 -0700366 break;
367 default:
368 RTC_NOTREACHED();
369 }
370}
371
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800372static void AttachSenderToMediaDescriptionOptions(
373 const std::string& mid,
374 MediaType type,
375 const std::string& track_id,
376 const std::vector<std::string>& stream_ids,
377 int num_sim_layer,
378 MediaSessionOptions* session_options) {
379 AttachSenderToMediaDescriptionOptions(mid, type, track_id, stream_ids, {},
380 SimulcastLayerList(), num_sim_layer,
381 session_options);
382}
383
zhihuang1c378ed2017-08-17 14:10:50 -0700384static void DetachSenderFromMediaSection(const std::string& mid,
385 const std::string& track_id,
386 MediaSessionOptions* session_options) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700387 std::vector<cricket::SenderOptions>& sender_options_list =
388 FindFirstMediaDescriptionByMid(mid, session_options)->sender_options;
389 auto sender_it =
Steve Anton64b626b2019-01-28 17:25:26 -0800390 absl::c_find_if(sender_options_list,
391 [track_id](const cricket::SenderOptions& sender_options) {
392 return sender_options.track_id == track_id;
393 });
Steve Anton3a66edf2018-09-10 12:57:37 -0700394 RTC_DCHECK(sender_it != sender_options_list.end());
395 sender_options_list.erase(sender_it);
zhihuang1c378ed2017-08-17 14:10:50 -0700396}
397
398// Helper function used to create a default MediaSessionOptions for Plan B SDP.
399// (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
400static MediaSessionOptions CreatePlanBMediaSessionOptions() {
401 MediaSessionOptions session_options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800402 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
403 RtpTransceiverDirection::kRecvOnly, kActive,
404 &session_options);
zhihuang1c378ed2017-08-17 14:10:50 -0700405 return session_options;
406}
407
408// TODO(zhihuang): Most of these tests were written while MediaSessionOptions
409// was designed for Plan B SDP, where only one audio "m=" section and one video
410// "m=" section could be generated, and ordering couldn't be controlled. Many of
411// these tests may be obsolete as a result, and should be refactored or removed.
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200412class MediaSessionDescriptionFactoryTest : public ::testing::Test {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000413 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800414 MediaSessionDescriptionFactoryTest()
415 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -0700416 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
417 MAKE_VECTOR(kAudioCodecs1));
Johannes Kron184ea662020-01-29 12:43:36 +0100418 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1),
419 MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200420 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700421 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
422 MAKE_VECTOR(kAudioCodecs2));
Johannes Kron184ea662020-01-29 12:43:36 +0100423 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2),
424 MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200425 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200426 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700427 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200428 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700429 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000430 }
431
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000432 // Create a video StreamParamsVec object with:
433 // - one video stream with 3 simulcast streams and FEC,
434 StreamParamsVec CreateComplexVideoStreamParamsVec() {
435 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
436 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
437 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
438 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
439
440 std::vector<SsrcGroup> ssrc_groups;
441 ssrc_groups.push_back(sim_group);
442 ssrc_groups.push_back(fec_group1);
443 ssrc_groups.push_back(fec_group2);
444 ssrc_groups.push_back(fec_group3);
445
446 StreamParams simulcast_params;
447 simulcast_params.id = kVideoTrack1;
448 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
449 simulcast_params.ssrc_groups = ssrc_groups;
450 simulcast_params.cname = "Video_SIM_FEC";
Seth Hampson845e8782018-03-02 11:34:10 -0800451 simulcast_params.set_stream_ids({kMediaStream1});
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000452
453 StreamParamsVec video_streams;
454 video_streams.push_back(simulcast_params);
455
456 return video_streams;
457 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000458
459 bool CompareCryptoParams(const CryptoParamsVec& c1,
460 const CryptoParamsVec& c2) {
461 if (c1.size() != c2.size())
462 return false;
463 for (size_t i = 0; i < c1.size(); ++i)
464 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
465 c1[i].key_params != c2[i].key_params ||
466 c1[i].session_params != c2[i].session_params)
467 return false;
468 return true;
469 }
470
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700471 // Returns true if the transport info contains "renomination" as an
472 // ICE option.
473 bool GetIceRenomination(const TransportInfo* transport_info) {
Steve Anton64b626b2019-01-28 17:25:26 -0800474 return absl::c_linear_search(transport_info->description.transport_options,
475 "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700476 }
477
zhihuang1c378ed2017-08-17 14:10:50 -0700478 void TestTransportInfo(bool offer,
Steve Anton36b29d12017-10-30 09:57:42 -0700479 const MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000480 bool has_current_desc) {
481 const std::string current_audio_ufrag = "current_audio_ufrag";
482 const std::string current_audio_pwd = "current_audio_pwd";
483 const std::string current_video_ufrag = "current_video_ufrag";
484 const std::string current_video_pwd = "current_video_pwd";
485 const std::string current_data_ufrag = "current_data_ufrag";
486 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800487 std::unique_ptr<SessionDescription> current_desc;
488 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000489 if (has_current_desc) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200490 current_desc = std::make_unique<SessionDescription>();
Steve Anton06817cd2018-12-18 15:55:30 -0800491 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200492 "audio",
Steve Anton06817cd2018-12-18 15:55:30 -0800493 TransportDescription(current_audio_ufrag, current_audio_pwd)));
494 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200495 "video",
Steve Anton06817cd2018-12-18 15:55:30 -0800496 TransportDescription(current_video_ufrag, current_video_pwd)));
497 current_desc->AddTransportInfo(TransportInfo(
498 "data", TransportDescription(current_data_ufrag, current_data_pwd)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000499 }
500 if (offer) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800501 desc = f1_.CreateOffer(options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000502 } else {
kwiberg31022942016-03-11 14:18:21 -0800503 std::unique_ptr<SessionDescription> offer;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800504 offer = f1_.CreateOffer(options, NULL);
505 desc = f1_.CreateAnswer(offer.get(), options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000506 }
507 ASSERT_TRUE(desc.get() != NULL);
508 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000509 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000510 EXPECT_TRUE(ti_audio != NULL);
511 if (has_current_desc) {
512 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
513 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
514 } else {
515 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
516 ti_audio->description.ice_ufrag.size());
517 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
518 ti_audio->description.ice_pwd.size());
519 }
zhihuang1c378ed2017-08-17 14:10:50 -0700520 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700521 FindFirstMediaDescriptionByMid("audio", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700522 EXPECT_EQ(
523 media_desc_options_it->transport_options.enable_ice_renomination,
524 GetIceRenomination(ti_audio));
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700525 EXPECT_EQ(media_desc_options_it->transport_options.opaque_parameters,
526 ti_audio->description.opaque_parameters);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000527
528 } else {
529 EXPECT_TRUE(ti_audio == NULL);
530 }
531 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000532 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000533 EXPECT_TRUE(ti_video != NULL);
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700534 auto media_desc_options_it =
535 FindFirstMediaDescriptionByMid("video", options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000536 if (options.bundle_enabled) {
537 EXPECT_EQ(ti_audio->description.ice_ufrag,
538 ti_video->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200539 EXPECT_EQ(ti_audio->description.ice_pwd, ti_video->description.ice_pwd);
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700540 EXPECT_EQ(ti_audio->description.opaque_parameters,
541 ti_video->description.opaque_parameters);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000542 } else {
543 if (has_current_desc) {
544 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
545 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
546 } else {
547 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
548 ti_video->description.ice_ufrag.size());
549 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
550 ti_video->description.ice_pwd.size());
551 }
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700552 EXPECT_EQ(media_desc_options_it->transport_options.opaque_parameters,
553 ti_video->description.opaque_parameters);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000554 }
zhihuang1c378ed2017-08-17 14:10:50 -0700555 EXPECT_EQ(
556 media_desc_options_it->transport_options.enable_ice_renomination,
557 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000558 } else {
559 EXPECT_TRUE(ti_video == NULL);
560 }
561 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
562 if (options.has_data()) {
563 EXPECT_TRUE(ti_data != NULL);
564 if (options.bundle_enabled) {
565 EXPECT_EQ(ti_audio->description.ice_ufrag,
566 ti_data->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200567 EXPECT_EQ(ti_audio->description.ice_pwd, ti_data->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000568 } else {
569 if (has_current_desc) {
570 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
571 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
572 } else {
573 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
574 ti_data->description.ice_ufrag.size());
575 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
576 ti_data->description.ice_pwd.size());
577 }
578 }
zhihuang1c378ed2017-08-17 14:10:50 -0700579 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700580 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700581 EXPECT_EQ(
582 media_desc_options_it->transport_options.enable_ice_renomination,
583 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700584
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000585 } else {
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700586 EXPECT_TRUE(ti_data == NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000587 }
588 }
589
590 void TestCryptoWithBundle(bool offer) {
591 f1_.set_secure(SEC_ENABLED);
592 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -0800593 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
594 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
595 &options);
kwiberg31022942016-03-11 14:18:21 -0800596 std::unique_ptr<SessionDescription> ref_desc;
597 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000598 if (offer) {
599 options.bundle_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800600 ref_desc = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000601 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800602 desc = f1_.CreateOffer(options, ref_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000603 } else {
604 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800605 ref_desc = f1_.CreateOffer(options, NULL);
606 desc = f1_.CreateAnswer(ref_desc.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000607 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800608 ASSERT_TRUE(desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000609 const cricket::MediaContentDescription* audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800610 desc->GetContentDescriptionByName("audio");
611 ASSERT_TRUE(audio_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000612 const cricket::MediaContentDescription* video_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800613 desc->GetContentDescriptionByName("video");
614 ASSERT_TRUE(video_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000615 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
616 video_media_desc->cryptos()));
617 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
Steve Antone38a5a12018-11-21 16:05:15 -0800618 EXPECT_EQ(kDefaultSrtpCryptoSuite,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000619 audio_media_desc->cryptos()[0].cipher_suite);
620
621 // Verify the selected crypto is one from the reference audio
622 // media content.
623 const cricket::MediaContentDescription* ref_audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800624 ref_desc->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000625 bool found = false;
626 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
627 if (ref_audio_media_desc->cryptos()[i].Matches(
Yves Gerey665174f2018-06-19 15:03:05 +0200628 audio_media_desc->cryptos()[0])) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000629 found = true;
630 break;
631 }
632 }
633 EXPECT_TRUE(found);
634 }
635
636 // This test that the audio and video media direction is set to
637 // |expected_direction_in_answer| in an answer if the offer direction is set
zhihuang1c378ed2017-08-17 14:10:50 -0700638 // to |direction_in_offer| and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000639 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800640 RtpTransceiverDirection direction_in_offer,
641 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700642 MediaSessionOptions offer_opts;
643 AddAudioVideoSections(direction_in_offer, &offer_opts);
644
Steve Anton6fe1fba2018-12-11 10:15:23 -0800645 std::unique_ptr<SessionDescription> offer =
646 f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000647 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700648 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000649 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700650 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000651 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000652
zhihuang1c378ed2017-08-17 14:10:50 -0700653 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800654 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800655 std::unique_ptr<SessionDescription> answer =
656 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000657 const AudioContentDescription* acd_answer =
658 GetFirstAudioContentDescription(answer.get());
659 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
660 const VideoContentDescription* vcd_answer =
661 GetFirstVideoContentDescription(answer.get());
662 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
663 }
664
665 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800666 RTC_DCHECK(content);
667 RTC_CHECK(content->media_description());
668 const cricket::AudioContentDescription* audio_desc =
669 content->media_description()->as_audio();
670 RTC_CHECK(audio_desc);
671 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
672 if (codec.name == "CN") {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000673 return false;
Steve Antonb1c1de12017-12-21 15:14:30 -0800674 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000675 }
676 return true;
677 }
678
jbauchcb560652016-08-04 05:20:32 -0700679 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
680 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800681 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700682 offer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_offer;
zhihuang1c378ed2017-08-17 14:10:50 -0700683
jbauchcb560652016-08-04 05:20:32 -0700684 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800685 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700686 answer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_answer;
zhihuang1c378ed2017-08-17 14:10:50 -0700687
jbauchcb560652016-08-04 05:20:32 -0700688 f1_.set_secure(SEC_ENABLED);
689 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800690 std::unique_ptr<SessionDescription> offer =
691 f1_.CreateOffer(offer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700692 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800693 std::unique_ptr<SessionDescription> answer =
694 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700695 const ContentInfo* ac = answer->GetContentByName("audio");
696 const ContentInfo* vc = answer->GetContentByName("video");
697 ASSERT_TRUE(ac != NULL);
698 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800699 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
700 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800701 const AudioContentDescription* acd = ac->media_description()->as_audio();
702 const VideoContentDescription* vcd = vc->media_description()->as_video();
jbauchcb560652016-08-04 05:20:32 -0700703 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800704 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -0700705 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700706 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700707 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
708 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700709 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700710 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700711 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700712 }
713 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800714 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +0200715 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
716 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
jbauchcb560652016-08-04 05:20:32 -0700717 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700718 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700719 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700720 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700721 }
Steve Antone38a5a12018-11-21 16:05:15 -0800722 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
jbauchcb560652016-08-04 05:20:32 -0700723 }
724
Johannes Kronce8e8672019-02-22 13:06:44 +0100725 void TestTransportSequenceNumberNegotiation(
726 const cricket::RtpHeaderExtensions& local,
727 const cricket::RtpHeaderExtensions& offered,
728 const cricket::RtpHeaderExtensions& expectedAnswer) {
729 MediaSessionOptions opts;
730 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
731 f1_.set_audio_rtp_header_extensions(offered);
732 f1_.set_video_rtp_header_extensions(offered);
733 f2_.set_audio_rtp_header_extensions(local);
734 f2_.set_video_rtp_header_extensions(local);
735
736 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
737 ASSERT_TRUE(offer.get() != NULL);
738 std::unique_ptr<SessionDescription> answer =
739 f2_.CreateAnswer(offer.get(), opts, NULL);
740
741 EXPECT_EQ(
742 expectedAnswer,
743 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
744 EXPECT_EQ(
745 expectedAnswer,
746 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
747 }
748
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000749 protected:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800750 UniqueRandomIdGenerator ssrc_generator1;
751 UniqueRandomIdGenerator ssrc_generator2;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000752 MediaSessionDescriptionFactory f1_;
753 MediaSessionDescriptionFactory f2_;
754 TransportDescriptionFactory tdf1_;
755 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000756};
757
758// Create a typical audio offer, and ensure it matches what we expect.
759TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
760 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800761 std::unique_ptr<SessionDescription> offer =
762 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000763 ASSERT_TRUE(offer.get() != NULL);
764 const ContentInfo* ac = offer->GetContentByName("audio");
765 const ContentInfo* vc = offer->GetContentByName("video");
766 ASSERT_TRUE(ac != NULL);
767 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800768 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800769 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000770 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700771 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700772 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000773 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
774 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700775 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800776 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000777}
778
779// Create a typical video offer, and ensure it matches what we expect.
780TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
781 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800782 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000783 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800784 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000785 ASSERT_TRUE(offer.get() != NULL);
786 const ContentInfo* ac = offer->GetContentByName("audio");
787 const ContentInfo* vc = offer->GetContentByName("video");
788 ASSERT_TRUE(ac != NULL);
789 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800790 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
791 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800792 const AudioContentDescription* acd = ac->media_description()->as_audio();
793 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000794 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700795 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700796 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000797 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
798 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700799 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800800 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000801 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Johannes Kron184ea662020-01-29 12:43:36 +0100802 EXPECT_EQ(f1_.video_sendrecv_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700803 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000804 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
805 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700806 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800807 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000808}
809
810// Test creating an offer with bundle where the Codecs have the same dynamic
811// RTP playlod type. The test verifies that the offer don't contain the
812// duplicate RTP payload types.
813TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
Johannes Kron184ea662020-01-29 12:43:36 +0100814 const VideoCodec& offered_video_codec = f2_.video_sendrecv_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700815 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200816 const RtpDataCodec& offered_data_codec = f2_.rtp_data_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000817 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
818 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
819
820 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800821 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
822 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000823 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800824 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000825 const VideoContentDescription* vcd =
826 GetFirstVideoContentDescription(offer.get());
827 const AudioContentDescription* acd =
828 GetFirstAudioContentDescription(offer.get());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200829 const RtpDataContentDescription* dcd =
830 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000831 ASSERT_TRUE(NULL != vcd);
832 ASSERT_TRUE(NULL != acd);
833 ASSERT_TRUE(NULL != dcd);
834 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
835 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
836 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
837 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
838 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
839 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
840}
841
zhihuang1c378ed2017-08-17 14:10:50 -0700842// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000843// after an audio only session has been negotiated.
844TEST_F(MediaSessionDescriptionFactoryTest,
845 TestCreateUpdatedVideoOfferWithBundle) {
846 f1_.set_secure(SEC_ENABLED);
847 f2_.set_secure(SEC_ENABLED);
848 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800849 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
850 RtpTransceiverDirection::kRecvOnly, kActive,
851 &opts);
852 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
853 RtpTransceiverDirection::kInactive, kStopped,
854 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000855 opts.data_channel_type = cricket::DCT_NONE;
856 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800857 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
858 std::unique_ptr<SessionDescription> answer =
859 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000860
861 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800862 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
863 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
864 &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000865 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800866 std::unique_ptr<SessionDescription> updated_offer(
867 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000868
869 const AudioContentDescription* acd =
870 GetFirstAudioContentDescription(updated_offer.get());
871 const VideoContentDescription* vcd =
872 GetFirstVideoContentDescription(updated_offer.get());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200873 const RtpDataContentDescription* dcd =
874 GetFirstRtpDataContentDescription(updated_offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000875 EXPECT_TRUE(NULL != vcd);
876 EXPECT_TRUE(NULL != acd);
877 EXPECT_TRUE(NULL != dcd);
878
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700879 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800880 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700881 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800882 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700883 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800884 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000885}
deadbeef44f08192015-12-15 16:20:09 -0800886
wu@webrtc.org78187522013-10-07 23:32:02 +0000887// Create a RTP data offer, and ensure it matches what we expect.
888TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000889 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800890 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
891 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000892 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800893 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000894 ASSERT_TRUE(offer.get() != NULL);
895 const ContentInfo* ac = offer->GetContentByName("audio");
896 const ContentInfo* dc = offer->GetContentByName("data");
897 ASSERT_TRUE(ac != NULL);
898 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800899 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
900 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800901 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200902 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000903 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700904 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700905 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000906 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
907 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700908 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800909 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000910 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200911 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700912 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000913 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +0200914 dcd->bandwidth()); // default bandwidth (auto)
915 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700916 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800917 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000918}
919
wu@webrtc.org78187522013-10-07 23:32:02 +0000920// Create an SCTP data offer with bundle without error.
921TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
922 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000923 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800924 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
wu@webrtc.org78187522013-10-07 23:32:02 +0000925 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800926 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.org78187522013-10-07 23:32:02 +0000927 EXPECT_TRUE(offer.get() != NULL);
928 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
Guido Urdanetacecf87f2019-05-31 10:17:38 +0000929 auto dcd = GetFirstSctpDataContentDescription(offer.get());
930 ASSERT_TRUE(dcd);
931 // Since this transport is insecure, the protocol should be "SCTP".
932 EXPECT_EQ(cricket::kMediaProtocolSctp, dcd->protocol());
933}
934
935// Create an SCTP data offer with bundle without error.
936TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSecureSctpDataOffer) {
937 MediaSessionOptions opts;
938 opts.bundle_enabled = true;
939 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
940 f1_.set_secure(SEC_ENABLED);
941 tdf1_.set_secure(SEC_ENABLED);
942 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
943 EXPECT_TRUE(offer.get() != NULL);
944 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
945 auto dcd = GetFirstSctpDataContentDescription(offer.get());
946 ASSERT_TRUE(dcd);
947 // The protocol should now be "UDP/DTLS/SCTP"
948 EXPECT_EQ(cricket::kMediaProtocolUdpDtlsSctp, dcd->protocol());
wu@webrtc.org78187522013-10-07 23:32:02 +0000949}
950
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000951// Test creating an sctp data channel from an already generated offer.
952TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
953 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000954 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800955 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000956 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800957 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000958 ASSERT_TRUE(offer1.get() != NULL);
959 const ContentInfo* data = offer1->GetContentByName("data");
960 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800961 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000962
963 // Now set data_channel_type to 'none' (default) and make sure that the
964 // datachannel type that gets generated from the previous offer, is of the
965 // same type.
966 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800967 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000968 f1_.CreateOffer(opts, offer1.get()));
969 data = offer2->GetContentByName("data");
970 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800971 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000972}
973
Steve Anton2bed3972019-01-04 17:04:30 -0800974// Test that if BUNDLE is enabled and all media sections are rejected then the
975// BUNDLE group is not present in the re-offer.
976TEST_F(MediaSessionDescriptionFactoryTest, ReOfferNoBundleGroupIfAllRejected) {
977 MediaSessionOptions opts;
978 opts.bundle_enabled = true;
979 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
980 RtpTransceiverDirection::kSendRecv, kActive,
981 &opts);
982 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
983
984 opts.media_description_options[0].stopped = true;
985 std::unique_ptr<SessionDescription> reoffer =
986 f1_.CreateOffer(opts, offer.get());
987
988 EXPECT_FALSE(reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
989}
990
991// Test that if BUNDLE is enabled and the remote re-offer does not include a
992// BUNDLE group since all media sections are rejected, then the re-answer also
993// does not include a BUNDLE group.
994TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerNoBundleGroupIfAllRejected) {
995 MediaSessionOptions opts;
996 opts.bundle_enabled = true;
997 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
998 RtpTransceiverDirection::kSendRecv, kActive,
999 &opts);
1000 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1001 std::unique_ptr<SessionDescription> answer =
1002 f2_.CreateAnswer(offer.get(), opts, nullptr);
1003
1004 opts.media_description_options[0].stopped = true;
1005 std::unique_ptr<SessionDescription> reoffer =
1006 f1_.CreateOffer(opts, offer.get());
1007 std::unique_ptr<SessionDescription> reanswer =
1008 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1009
1010 EXPECT_FALSE(reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
1011}
1012
1013// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1014// was rejected then the new offerer-tagged media section is the non-rejected
1015// media section.
1016TEST_F(MediaSessionDescriptionFactoryTest, ReOfferChangeBundleOffererTagged) {
1017 MediaSessionOptions opts;
1018 opts.bundle_enabled = true;
1019 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1020 RtpTransceiverDirection::kSendRecv, kActive,
1021 &opts);
1022 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1023
1024 // Reject the audio m= section and add a video m= section.
1025 opts.media_description_options[0].stopped = true;
1026 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1027 RtpTransceiverDirection::kSendRecv, kActive,
1028 &opts);
1029 std::unique_ptr<SessionDescription> reoffer =
1030 f1_.CreateOffer(opts, offer.get());
1031
1032 const cricket::ContentGroup* bundle_group =
1033 reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1034 ASSERT_TRUE(bundle_group);
1035 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1036 EXPECT_TRUE(bundle_group->HasContentName("video"));
1037}
1038
1039// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1040// was rejected and a new media section is added, then the re-answer BUNDLE
1041// group will contain only the non-rejected media section.
1042TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerChangedBundleOffererTagged) {
1043 MediaSessionOptions opts;
1044 opts.bundle_enabled = true;
1045 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1046 RtpTransceiverDirection::kSendRecv, kActive,
1047 &opts);
1048 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1049 std::unique_ptr<SessionDescription> answer =
1050 f2_.CreateAnswer(offer.get(), opts, nullptr);
1051
1052 // Reject the audio m= section and add a video m= section.
1053 opts.media_description_options[0].stopped = true;
1054 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1055 RtpTransceiverDirection::kSendRecv, kActive,
1056 &opts);
1057 std::unique_ptr<SessionDescription> reoffer =
1058 f1_.CreateOffer(opts, offer.get());
1059 std::unique_ptr<SessionDescription> reanswer =
1060 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1061
1062 const cricket::ContentGroup* bundle_group =
1063 reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1064 ASSERT_TRUE(bundle_group);
1065 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1066 EXPECT_TRUE(bundle_group->HasContentName("video"));
1067}
1068
1069// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1070// and there is still a non-rejected media section that was in the initial
1071// offer, then the ICE credentials do not change in the reoffer offerer-tagged
1072// media section.
1073TEST_F(MediaSessionDescriptionFactoryTest,
1074 ReOfferChangeBundleOffererTaggedKeepsIceCredentials) {
1075 MediaSessionOptions opts;
1076 opts.bundle_enabled = true;
1077 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1078 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1079 std::unique_ptr<SessionDescription> answer =
1080 f2_.CreateAnswer(offer.get(), opts, nullptr);
1081
1082 // Reject the audio m= section.
1083 opts.media_description_options[0].stopped = true;
1084 std::unique_ptr<SessionDescription> reoffer =
1085 f1_.CreateOffer(opts, offer.get());
1086
1087 const TransportDescription* offer_tagged =
1088 offer->GetTransportDescriptionByName("audio");
1089 ASSERT_TRUE(offer_tagged);
1090 const TransportDescription* reoffer_tagged =
1091 reoffer->GetTransportDescriptionByName("video");
1092 ASSERT_TRUE(reoffer_tagged);
1093 EXPECT_EQ(offer_tagged->ice_ufrag, reoffer_tagged->ice_ufrag);
1094 EXPECT_EQ(offer_tagged->ice_pwd, reoffer_tagged->ice_pwd);
1095}
1096
1097// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1098// and there is still a non-rejected media section that was in the initial
1099// offer, then the ICE credentials do not change in the reanswer answerer-tagged
1100// media section.
1101TEST_F(MediaSessionDescriptionFactoryTest,
1102 ReAnswerChangeBundleOffererTaggedKeepsIceCredentials) {
1103 MediaSessionOptions opts;
1104 opts.bundle_enabled = true;
1105 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1106 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1107 std::unique_ptr<SessionDescription> answer =
1108 f2_.CreateAnswer(offer.get(), opts, nullptr);
1109
1110 // Reject the audio m= section.
1111 opts.media_description_options[0].stopped = true;
1112 std::unique_ptr<SessionDescription> reoffer =
1113 f1_.CreateOffer(opts, offer.get());
1114 std::unique_ptr<SessionDescription> reanswer =
1115 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1116
1117 const TransportDescription* answer_tagged =
1118 answer->GetTransportDescriptionByName("audio");
1119 ASSERT_TRUE(answer_tagged);
1120 const TransportDescription* reanswer_tagged =
1121 reanswer->GetTransportDescriptionByName("video");
1122 ASSERT_TRUE(reanswer_tagged);
1123 EXPECT_EQ(answer_tagged->ice_ufrag, reanswer_tagged->ice_ufrag);
1124 EXPECT_EQ(answer_tagged->ice_pwd, reanswer_tagged->ice_pwd);
1125}
1126
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001127// Create an audio, video offer without legacy StreamParams.
1128TEST_F(MediaSessionDescriptionFactoryTest,
1129 TestCreateOfferWithoutLegacyStreams) {
1130 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001131 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001132 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001133 ASSERT_TRUE(offer.get() != NULL);
1134 const ContentInfo* ac = offer->GetContentByName("audio");
1135 const ContentInfo* vc = offer->GetContentByName("video");
1136 ASSERT_TRUE(ac != NULL);
1137 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001138 const AudioContentDescription* acd = ac->media_description()->as_audio();
1139 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001140
Yves Gerey665174f2018-06-19 15:03:05 +02001141 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1142 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001143}
1144
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001145// Creates an audio+video sendonly offer.
1146TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001147 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001148 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001149 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1150 {kMediaStream1}, 1, &opts);
1151 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1152 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001153
Steve Anton6fe1fba2018-12-11 10:15:23 -08001154 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001155 ASSERT_TRUE(offer.get() != NULL);
1156 EXPECT_EQ(2u, offer->contents().size());
1157 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
1158 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
1159
Steve Anton4e70a722017-11-28 14:57:10 -08001160 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1161 GetMediaDirection(&offer->contents()[0]));
1162 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1163 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001164}
1165
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001166// Verifies that the order of the media contents in the current
1167// SessionDescription is preserved in the new SessionDescription.
1168TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
1169 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001170 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001171
kwiberg31022942016-03-11 14:18:21 -08001172 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001173 ASSERT_TRUE(offer1.get() != NULL);
1174 EXPECT_EQ(1u, offer1->contents().size());
1175 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
1176
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001177 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1178 RtpTransceiverDirection::kRecvOnly, kActive,
1179 &opts);
kwiberg31022942016-03-11 14:18:21 -08001180 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001181 f1_.CreateOffer(opts, offer1.get()));
1182 ASSERT_TRUE(offer2.get() != NULL);
1183 EXPECT_EQ(2u, offer2->contents().size());
1184 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
1185 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
1186
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001187 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1188 RtpTransceiverDirection::kRecvOnly, kActive,
1189 &opts);
kwiberg31022942016-03-11 14:18:21 -08001190 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001191 f1_.CreateOffer(opts, offer2.get()));
1192 ASSERT_TRUE(offer3.get() != NULL);
1193 EXPECT_EQ(3u, offer3->contents().size());
1194 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
1195 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
1196 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001197}
1198
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001199// Create a typical audio answer, and ensure it matches what we expect.
1200TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
1201 f1_.set_secure(SEC_ENABLED);
1202 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001203 std::unique_ptr<SessionDescription> offer =
1204 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001205 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001206 std::unique_ptr<SessionDescription> answer =
1207 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001208 const ContentInfo* ac = answer->GetContentByName("audio");
1209 const ContentInfo* vc = answer->GetContentByName("video");
1210 ASSERT_TRUE(ac != NULL);
1211 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001212 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001213 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001214 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001215 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001216 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001217 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1218 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001219 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001220 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001221}
1222
jbauchcb560652016-08-04 05:20:32 -07001223// Create a typical audio answer with GCM ciphers enabled, and ensure it
1224// matches what we expect.
1225TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
1226 f1_.set_secure(SEC_ENABLED);
1227 f2_.set_secure(SEC_ENABLED);
zhihuang1c378ed2017-08-17 14:10:50 -07001228 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001229 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001230 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001231 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001232 std::unique_ptr<SessionDescription> answer =
1233 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001234 const ContentInfo* ac = answer->GetContentByName("audio");
1235 const ContentInfo* vc = answer->GetContentByName("video");
1236 ASSERT_TRUE(ac != NULL);
1237 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001238 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001239 const AudioContentDescription* acd = ac->media_description()->as_audio();
jbauchcb560652016-08-04 05:20:32 -07001240 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001241 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001242 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001243 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1244 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001245 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001246 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
jbauchcb560652016-08-04 05:20:32 -07001247}
1248
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001249// Create a typical video answer, and ensure it matches what we expect.
1250TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
1251 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001252 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001253 f1_.set_secure(SEC_ENABLED);
1254 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001255 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001256 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001257 std::unique_ptr<SessionDescription> answer =
1258 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001259 const ContentInfo* ac = answer->GetContentByName("audio");
1260 const ContentInfo* vc = answer->GetContentByName("video");
1261 ASSERT_TRUE(ac != NULL);
1262 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001263 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1264 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001265 const AudioContentDescription* acd = ac->media_description()->as_audio();
1266 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001267 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001268 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001269 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001270 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001271 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001272 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001273 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001274 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +02001275 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
1276 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001277 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001278 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001279}
1280
jbauchcb560652016-08-04 05:20:32 -07001281// Create a typical video answer with GCM ciphers enabled, and ensure it
1282// matches what we expect.
1283TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1284 TestVideoGcmCipher(true, true);
1285}
1286
1287// Create a typical video answer with GCM ciphers enabled for the offer only,
1288// and ensure it matches what we expect.
1289TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1290 TestVideoGcmCipher(true, false);
1291}
1292
1293// Create a typical video answer with GCM ciphers enabled for the answer only,
1294// and ensure it matches what we expect.
1295TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1296 TestVideoGcmCipher(false, true);
1297}
1298
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001299TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001300 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001301 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001302 f1_.set_secure(SEC_ENABLED);
1303 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001304 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001305 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001306 std::unique_ptr<SessionDescription> answer =
1307 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001308 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001309 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001310 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001311 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001312 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1313 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001314 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001315 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001316 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001317 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001318 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001319 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001320 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001321 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
zstein4b2e0822017-02-17 19:48:38 -08001322 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001323 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001324 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001325 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001326 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001327 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001328}
1329
jbauchcb560652016-08-04 05:20:32 -07001330TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
zhihuang1c378ed2017-08-17 14:10:50 -07001331 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001332 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001333 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
jbauchcb560652016-08-04 05:20:32 -07001334 f1_.set_secure(SEC_ENABLED);
1335 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001336 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001337 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001338 std::unique_ptr<SessionDescription> answer =
1339 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001340 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001341 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -07001342 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001343 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001344 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1345 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001346 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001347 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
jbauchcb560652016-08-04 05:20:32 -07001348 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001349 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -07001350 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001351 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001352 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001353 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
zstein4b2e0822017-02-17 19:48:38 -08001354 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001355 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001356 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001357 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001358 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001359 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
zstein4b2e0822017-02-17 19:48:38 -08001360}
1361
Harald Alvestrandc5effc22019-06-11 11:46:59 +02001362// The use_sctpmap flag should be set in an Sctp DataContentDescription by
1363// default. The answer's use_sctpmap flag should match the offer's.
zstein4b2e0822017-02-17 19:48:38 -08001364TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1365 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001366 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001367 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001368 ASSERT_TRUE(offer.get() != NULL);
1369 ContentInfo* dc_offer = offer->GetContentByName("data");
1370 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001371 SctpDataContentDescription* dcd_offer =
1372 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001373 EXPECT_TRUE(dcd_offer->use_sctpmap());
1374
Steve Anton6fe1fba2018-12-11 10:15:23 -08001375 std::unique_ptr<SessionDescription> answer =
1376 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001377 const ContentInfo* dc_answer = answer->GetContentByName("data");
1378 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001379 const SctpDataContentDescription* dcd_answer =
1380 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001381 EXPECT_TRUE(dcd_answer->use_sctpmap());
1382}
1383
1384// The answer's use_sctpmap flag should match the offer's.
1385TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1386 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001387 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001388 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001389 ASSERT_TRUE(offer.get() != NULL);
1390 ContentInfo* dc_offer = offer->GetContentByName("data");
1391 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001392 SctpDataContentDescription* dcd_offer =
1393 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001394 dcd_offer->set_use_sctpmap(false);
1395
Steve Anton6fe1fba2018-12-11 10:15:23 -08001396 std::unique_ptr<SessionDescription> answer =
1397 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001398 const ContentInfo* dc_answer = answer->GetContentByName("data");
1399 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001400 const SctpDataContentDescription* dcd_answer =
1401 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001402 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001403}
1404
deadbeef8b7e9ad2017-05-25 09:38:55 -07001405// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1406// and "TCP/DTLS/SCTP" offers.
1407TEST_F(MediaSessionDescriptionFactoryTest,
1408 TestCreateDataAnswerToDifferentOfferedProtos) {
1409 // Need to enable DTLS offer/answer generation (disabled by default in this
1410 // test).
1411 f1_.set_secure(SEC_ENABLED);
1412 f2_.set_secure(SEC_ENABLED);
1413 tdf1_.set_secure(SEC_ENABLED);
1414 tdf2_.set_secure(SEC_ENABLED);
1415
1416 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001417 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001418 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001419 ASSERT_TRUE(offer.get() != nullptr);
1420 ContentInfo* dc_offer = offer->GetContentByName("data");
1421 ASSERT_TRUE(dc_offer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001422 SctpDataContentDescription* dcd_offer =
1423 dc_offer->media_description()->as_sctp();
1424 ASSERT_TRUE(dcd_offer);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001425
1426 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1427 "TCP/DTLS/SCTP"};
1428 for (const std::string& proto : protos) {
1429 dcd_offer->set_protocol(proto);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001430 std::unique_ptr<SessionDescription> answer =
1431 f2_.CreateAnswer(offer.get(), opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001432 const ContentInfo* dc_answer = answer->GetContentByName("data");
1433 ASSERT_TRUE(dc_answer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001434 const SctpDataContentDescription* dcd_answer =
1435 dc_answer->media_description()->as_sctp();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001436 EXPECT_FALSE(dc_answer->rejected);
1437 EXPECT_EQ(proto, dcd_answer->protocol());
1438 }
1439}
1440
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001441TEST_F(MediaSessionDescriptionFactoryTest,
1442 TestCreateDataAnswerToOfferWithDefinedMessageSize) {
1443 // Need to enable DTLS offer/answer generation (disabled by default in this
1444 // test).
1445 f1_.set_secure(SEC_ENABLED);
1446 f2_.set_secure(SEC_ENABLED);
1447 tdf1_.set_secure(SEC_ENABLED);
1448 tdf2_.set_secure(SEC_ENABLED);
1449
1450 MediaSessionOptions opts;
1451 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
1452 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1453 ASSERT_TRUE(offer.get() != nullptr);
1454 ContentInfo* dc_offer = offer->GetContentByName("data");
1455 ASSERT_TRUE(dc_offer != nullptr);
1456 SctpDataContentDescription* dcd_offer =
1457 dc_offer->media_description()->as_sctp();
1458 ASSERT_TRUE(dcd_offer);
1459 dcd_offer->set_max_message_size(1234);
1460 std::unique_ptr<SessionDescription> answer =
1461 f2_.CreateAnswer(offer.get(), opts, nullptr);
1462 const ContentInfo* dc_answer = answer->GetContentByName("data");
1463 ASSERT_TRUE(dc_answer != nullptr);
1464 const SctpDataContentDescription* dcd_answer =
1465 dc_answer->media_description()->as_sctp();
1466 EXPECT_FALSE(dc_answer->rejected);
1467 EXPECT_EQ(1234, dcd_answer->max_message_size());
1468}
1469
1470TEST_F(MediaSessionDescriptionFactoryTest,
1471 TestCreateDataAnswerToOfferWithZeroMessageSize) {
1472 // Need to enable DTLS offer/answer generation (disabled by default in this
1473 // test).
1474 f1_.set_secure(SEC_ENABLED);
1475 f2_.set_secure(SEC_ENABLED);
1476 tdf1_.set_secure(SEC_ENABLED);
1477 tdf2_.set_secure(SEC_ENABLED);
1478
1479 MediaSessionOptions opts;
1480 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
1481 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1482 ASSERT_TRUE(offer.get() != nullptr);
1483 ContentInfo* dc_offer = offer->GetContentByName("data");
1484 ASSERT_TRUE(dc_offer != nullptr);
1485 SctpDataContentDescription* dcd_offer =
1486 dc_offer->media_description()->as_sctp();
1487 ASSERT_TRUE(dcd_offer);
1488 dcd_offer->set_max_message_size(0);
1489 std::unique_ptr<SessionDescription> answer =
1490 f2_.CreateAnswer(offer.get(), opts, nullptr);
1491 const ContentInfo* dc_answer = answer->GetContentByName("data");
1492 ASSERT_TRUE(dc_answer != nullptr);
1493 const SctpDataContentDescription* dcd_answer =
1494 dc_answer->media_description()->as_sctp();
1495 EXPECT_FALSE(dc_answer->rejected);
1496 EXPECT_EQ(cricket::kSctpSendBufferSize, dcd_answer->max_message_size());
1497}
1498
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001499// Verifies that the order of the media contents in the offer is preserved in
1500// the answer.
1501TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1502 MediaSessionOptions opts;
1503
1504 // Creates a data only offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001505 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001506 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001507 ASSERT_TRUE(offer1.get() != NULL);
1508
1509 // Appends audio to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001510 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1511 RtpTransceiverDirection::kRecvOnly, kActive,
1512 &opts);
kwiberg31022942016-03-11 14:18:21 -08001513 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001514 f1_.CreateOffer(opts, offer1.get()));
1515 ASSERT_TRUE(offer2.get() != NULL);
1516
1517 // Appends video to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001518 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1519 RtpTransceiverDirection::kRecvOnly, kActive,
1520 &opts);
kwiberg31022942016-03-11 14:18:21 -08001521 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001522 f1_.CreateOffer(opts, offer2.get()));
1523 ASSERT_TRUE(offer3.get() != NULL);
1524
Steve Anton6fe1fba2018-12-11 10:15:23 -08001525 std::unique_ptr<SessionDescription> answer =
1526 f2_.CreateAnswer(offer3.get(), opts, NULL);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001527 ASSERT_TRUE(answer.get() != NULL);
1528 EXPECT_EQ(3u, answer->contents().size());
1529 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1530 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1531 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1532}
1533
ossu075af922016-06-14 03:29:38 -07001534// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1535// answerer settings.
1536
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001537// This test that the media direction is set to send/receive in an answer if
1538// the offer is send receive.
1539TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001540 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1541 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001542}
1543
1544// This test that the media direction is set to receive only in an answer if
1545// the offer is send only.
1546TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001547 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1548 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001549}
1550
1551// This test that the media direction is set to send only in an answer if
1552// the offer is recv only.
1553TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001554 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1555 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001556}
1557
1558// This test that the media direction is set to inactive in an answer if
1559// the offer is inactive.
1560TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001561 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1562 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001563}
1564
1565// Test that a data content with an unknown protocol is rejected in an answer.
1566TEST_F(MediaSessionDescriptionFactoryTest,
1567 CreateDataAnswerToOfferWithUnknownProtocol) {
1568 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001569 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001570 f1_.set_secure(SEC_ENABLED);
1571 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001572 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
terelius8c011e52016-04-26 05:28:11 -07001573 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001574 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001575 RtpDataContentDescription* dcd_offer =
1576 dc_offer->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001577 ASSERT_TRUE(dcd_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001578 // Offer must be acceptable as an RTP protocol in order to be set.
1579 std::string protocol = "RTP/a weird unknown protocol";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001580 dcd_offer->set_protocol(protocol);
1581
Steve Anton6fe1fba2018-12-11 10:15:23 -08001582 std::unique_ptr<SessionDescription> answer =
1583 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001584
1585 const ContentInfo* dc_answer = answer->GetContentByName("data");
1586 ASSERT_TRUE(dc_answer != NULL);
1587 EXPECT_TRUE(dc_answer->rejected);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001588 const RtpDataContentDescription* dcd_answer =
1589 dc_answer->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001590 ASSERT_TRUE(dcd_answer != NULL);
1591 EXPECT_EQ(protocol, dcd_answer->protocol());
1592}
1593
1594// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1595TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001596 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001597 f1_.set_secure(SEC_DISABLED);
1598 f2_.set_secure(SEC_DISABLED);
1599 tdf1_.set_secure(SEC_DISABLED);
1600 tdf2_.set_secure(SEC_DISABLED);
1601
Steve Anton6fe1fba2018-12-11 10:15:23 -08001602 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001603 const AudioContentDescription* offer_acd =
1604 GetFirstAudioContentDescription(offer.get());
1605 ASSERT_TRUE(offer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001606 EXPECT_EQ(cricket::kMediaProtocolAvpf, offer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001607
Steve Anton6fe1fba2018-12-11 10:15:23 -08001608 std::unique_ptr<SessionDescription> answer =
1609 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001610
1611 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1612 ASSERT_TRUE(ac_answer != NULL);
1613 EXPECT_FALSE(ac_answer->rejected);
1614
1615 const AudioContentDescription* answer_acd =
1616 GetFirstAudioContentDescription(answer.get());
1617 ASSERT_TRUE(answer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001618 EXPECT_EQ(cricket::kMediaProtocolAvpf, answer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001619}
1620
1621// Create a video offer and answer and ensure the RTP header extensions
1622// matches what we expect.
1623TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1624 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001625 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001626 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1627 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1628 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1629 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1630
Steve Anton6fe1fba2018-12-11 10:15:23 -08001631 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001632 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001633 std::unique_ptr<SessionDescription> answer =
1634 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001635
Yves Gerey665174f2018-06-19 15:03:05 +02001636 EXPECT_EQ(
1637 MAKE_VECTOR(kAudioRtpExtension1),
1638 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1639 EXPECT_EQ(
1640 MAKE_VECTOR(kVideoRtpExtension1),
1641 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1642 EXPECT_EQ(
1643 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1644 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1645 EXPECT_EQ(
1646 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1647 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001648}
1649
Johannes Kronce8e8672019-02-22 13:06:44 +01001650// Create a audio/video offer and answer and ensure that the
1651// TransportSequenceNumber RTP header extensions are handled correctly. 02 is
1652// supported and should take precedence even though not listed among locally
1653// supported extensions.
1654TEST_F(MediaSessionDescriptionFactoryTest,
1655 TestOfferAnswerWithTransportSequenceNumberInOffer) {
1656 TestTransportSequenceNumberNegotiation(
1657 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1658 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Offer.
1659 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01)); // Expected answer.
1660}
1661TEST_F(MediaSessionDescriptionFactoryTest,
1662 TestOfferAnswerWithTransportSequenceNumber01And02InOffer) {
1663 TestTransportSequenceNumberNegotiation(
1664 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1665 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01And02), // Offer.
1666 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1667}
1668TEST_F(MediaSessionDescriptionFactoryTest,
1669 TestOfferAnswerWithTransportSequenceNumber02InOffer) {
1670 TestTransportSequenceNumberNegotiation(
1671 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1672 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02), // Offer.
1673 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1674}
1675
jbauch5869f502017-06-29 12:31:36 -07001676TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001677 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
jbauch5869f502017-06-29 12:31:36 -07001678 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001679 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001680
1681 f1_.set_enable_encrypted_rtp_header_extensions(true);
1682 f2_.set_enable_encrypted_rtp_header_extensions(true);
1683
Yves Gerey665174f2018-06-19 15:03:05 +02001684 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1685 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1686 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1687 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001688
Steve Anton6fe1fba2018-12-11 10:15:23 -08001689 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001690 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001691 std::unique_ptr<SessionDescription> answer =
1692 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001693
Yves Gerey665174f2018-06-19 15:03:05 +02001694 EXPECT_EQ(
1695 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1696 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1697 EXPECT_EQ(
1698 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1699 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1700 EXPECT_EQ(
1701 MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
1702 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1703 EXPECT_EQ(
1704 MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
1705 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001706}
1707
1708TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001709 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
jbauch5869f502017-06-29 12:31:36 -07001710 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001711 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001712
1713 f1_.set_enable_encrypted_rtp_header_extensions(true);
1714
Yves Gerey665174f2018-06-19 15:03:05 +02001715 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1716 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1717 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1718 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001719
Steve Anton6fe1fba2018-12-11 10:15:23 -08001720 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001721 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001722 std::unique_ptr<SessionDescription> answer =
1723 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001724
Yves Gerey665174f2018-06-19 15:03:05 +02001725 EXPECT_EQ(
1726 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1727 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1728 EXPECT_EQ(
1729 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1730 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1731 EXPECT_EQ(
1732 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1733 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1734 EXPECT_EQ(
1735 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1736 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001737}
1738
1739TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001740 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
jbauch5869f502017-06-29 12:31:36 -07001741 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001742 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001743
1744 f2_.set_enable_encrypted_rtp_header_extensions(true);
1745
Yves Gerey665174f2018-06-19 15:03:05 +02001746 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1747 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1748 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1749 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001750
Steve Anton6fe1fba2018-12-11 10:15:23 -08001751 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001752 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001753 std::unique_ptr<SessionDescription> answer =
1754 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001755
Yves Gerey665174f2018-06-19 15:03:05 +02001756 EXPECT_EQ(
1757 MAKE_VECTOR(kAudioRtpExtension1),
1758 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1759 EXPECT_EQ(
1760 MAKE_VECTOR(kVideoRtpExtension1),
1761 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1762 EXPECT_EQ(
1763 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1764 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1765 EXPECT_EQ(
1766 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1767 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001768}
1769
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001770// Create an audio, video, data answer without legacy StreamParams.
1771TEST_F(MediaSessionDescriptionFactoryTest,
1772 TestCreateAnswerWithoutLegacyStreams) {
1773 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001774 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1775 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001776 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001777 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001778 std::unique_ptr<SessionDescription> answer =
1779 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001780 const ContentInfo* ac = answer->GetContentByName("audio");
1781 const ContentInfo* vc = answer->GetContentByName("video");
1782 const ContentInfo* dc = answer->GetContentByName("data");
1783 ASSERT_TRUE(ac != NULL);
1784 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001785 const AudioContentDescription* acd = ac->media_description()->as_audio();
1786 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001787 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001788
1789 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1790 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1791 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1792}
1793
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001794// Create a typical video answer, and ensure it matches what we expect.
1795TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1796 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001797 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
1798 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1799 &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001800
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001801 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001802 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
1803 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1804 &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001805
kwiberg31022942016-03-11 14:18:21 -08001806 std::unique_ptr<SessionDescription> offer;
1807 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001808
1809 offer_opts.rtcp_mux_enabled = true;
1810 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001811 offer = f1_.CreateOffer(offer_opts, NULL);
1812 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001813 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1814 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001815 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001816 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1817 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001818 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001819 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1820 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001821 EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001822 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1823 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001824 EXPECT_TRUE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001825
1826 offer_opts.rtcp_mux_enabled = true;
1827 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001828 offer = f1_.CreateOffer(offer_opts, NULL);
1829 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001830 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1831 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001832 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001833 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1834 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001835 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001836 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1837 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001838 EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001839 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1840 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001841 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001842
1843 offer_opts.rtcp_mux_enabled = false;
1844 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001845 offer = f1_.CreateOffer(offer_opts, NULL);
1846 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001847 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1848 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001849 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001850 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1851 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001852 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001853 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1854 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001855 EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001856 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1857 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001858 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001859
1860 offer_opts.rtcp_mux_enabled = false;
1861 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001862 offer = f1_.CreateOffer(offer_opts, NULL);
1863 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001864 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1865 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001866 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001867 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1868 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001869 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001870 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1871 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001872 EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001873 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1874 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001875 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001876}
1877
1878// Create an audio-only answer to a video offer.
1879TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1880 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001881 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1882 RtpTransceiverDirection::kRecvOnly, kActive,
1883 &opts);
1884 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1885 RtpTransceiverDirection::kRecvOnly, kActive,
1886 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001887 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001888 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001889
1890 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001891 std::unique_ptr<SessionDescription> answer =
1892 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001893 const ContentInfo* ac = answer->GetContentByName("audio");
1894 const ContentInfo* vc = answer->GetContentByName("video");
1895 ASSERT_TRUE(ac != NULL);
1896 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001897 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001898 EXPECT_TRUE(vc->rejected);
1899}
1900
1901// Create an audio-only answer to an offer with data.
1902TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001903 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001904 opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001905 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
1906 RtpTransceiverDirection::kRecvOnly, kActive,
1907 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001908 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001909 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001910
1911 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001912 std::unique_ptr<SessionDescription> answer =
1913 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001914 const ContentInfo* ac = answer->GetContentByName("audio");
1915 const ContentInfo* dc = answer->GetContentByName("data");
1916 ASSERT_TRUE(ac != NULL);
1917 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001918 ASSERT_TRUE(dc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001919 EXPECT_TRUE(dc->rejected);
1920}
1921
1922// Create an answer that rejects the contents which are rejected in the offer.
1923TEST_F(MediaSessionDescriptionFactoryTest,
1924 CreateAnswerToOfferWithRejectedMedia) {
1925 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001926 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1927 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001928 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001929 ASSERT_TRUE(offer.get() != NULL);
1930 ContentInfo* ac = offer->GetContentByName("audio");
1931 ContentInfo* vc = offer->GetContentByName("video");
1932 ContentInfo* dc = offer->GetContentByName("data");
1933 ASSERT_TRUE(ac != NULL);
1934 ASSERT_TRUE(vc != NULL);
1935 ASSERT_TRUE(dc != NULL);
1936 ac->rejected = true;
1937 vc->rejected = true;
1938 dc->rejected = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001939 std::unique_ptr<SessionDescription> answer =
1940 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001941 ac = answer->GetContentByName("audio");
1942 vc = answer->GetContentByName("video");
1943 dc = answer->GetContentByName("data");
1944 ASSERT_TRUE(ac != NULL);
1945 ASSERT_TRUE(vc != NULL);
1946 ASSERT_TRUE(dc != NULL);
1947 EXPECT_TRUE(ac->rejected);
1948 EXPECT_TRUE(vc->rejected);
1949 EXPECT_TRUE(dc->rejected);
1950}
1951
Johannes Kron0854eb62018-10-10 22:33:20 +02001952TEST_F(MediaSessionDescriptionFactoryTest,
1953 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensions) {
1954 MediaSessionOptions opts;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001955 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02001956 // Offer without request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001957 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02001958 ASSERT_TRUE(offer.get() != NULL);
1959 std::unique_ptr<SessionDescription> answer_no_support(
1960 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001961 EXPECT_FALSE(answer_no_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001962
1963 // Offer with request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001964 offer->set_extmap_allow_mixed(true);
Johannes Kron0854eb62018-10-10 22:33:20 +02001965 ASSERT_TRUE(offer.get() != NULL);
1966 std::unique_ptr<SessionDescription> answer_support(
1967 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001968 EXPECT_TRUE(answer_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001969}
1970
1971TEST_F(MediaSessionDescriptionFactoryTest,
1972 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensionsOnMediaLevel) {
1973 MediaSessionOptions opts;
1974 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001975 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02001976 MediaContentDescription* video_offer =
1977 offer->GetContentDescriptionByName("video");
1978 ASSERT_TRUE(video_offer);
1979 MediaContentDescription* audio_offer =
1980 offer->GetContentDescriptionByName("audio");
1981 ASSERT_TRUE(audio_offer);
1982
1983 // Explicit disable of mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001984 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
1985 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
Johannes Kron0854eb62018-10-10 22:33:20 +02001986
1987 ASSERT_TRUE(offer.get() != NULL);
1988 std::unique_ptr<SessionDescription> answer_no_support(
1989 f2_.CreateAnswer(offer.get(), opts, NULL));
1990 MediaContentDescription* video_answer =
1991 answer_no_support->GetContentDescriptionByName("video");
1992 MediaContentDescription* audio_answer =
1993 answer_no_support->GetContentDescriptionByName("audio");
1994 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001995 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001996 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001997 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001998
1999 // Enable mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02002000 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
2001 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
Johannes Kron0854eb62018-10-10 22:33:20 +02002002 ASSERT_TRUE(offer.get() != NULL);
2003 std::unique_ptr<SessionDescription> answer_support(
2004 f2_.CreateAnswer(offer.get(), opts, NULL));
2005 video_answer = answer_support->GetContentDescriptionByName("video");
2006 audio_answer = answer_support->GetContentDescriptionByName("audio");
2007 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02002008 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002009 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02002010 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002011}
2012
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002013// Create an audio and video offer with:
2014// - one video track
2015// - two audio tracks
2016// - two data tracks
2017// and ensure it matches what we expect. Also updates the initial offer by
2018// adding a new video track and replaces one of the audio tracks.
2019TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
2020 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002021 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002022 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2023 {kMediaStream1}, 1, &opts);
2024 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2025 {kMediaStream1}, 1, &opts);
2026 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2027 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002028
Steve Anton4e70a722017-11-28 14:57:10 -08002029 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002030 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2031 {kMediaStream1}, 1, &opts);
2032 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2033 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002034
2035 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002036 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002037
2038 ASSERT_TRUE(offer.get() != NULL);
2039 const ContentInfo* ac = offer->GetContentByName("audio");
2040 const ContentInfo* vc = offer->GetContentByName("video");
2041 const ContentInfo* dc = offer->GetContentByName("data");
2042 ASSERT_TRUE(ac != NULL);
2043 ASSERT_TRUE(vc != NULL);
2044 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002045 const AudioContentDescription* acd = ac->media_description()->as_audio();
2046 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002047 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002048 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07002049 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002050
2051 const StreamParamsVec& audio_streams = acd->streams();
2052 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002053 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002054 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2055 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2056 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2057 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2058 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2059 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2060
2061 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2062 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002063 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002064
2065 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Johannes Kron184ea662020-01-29 12:43:36 +01002066 EXPECT_EQ(f1_.video_sendrecv_codecs(), vcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002067 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002068
2069 const StreamParamsVec& video_streams = vcd->streams();
2070 ASSERT_EQ(1U, video_streams.size());
2071 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2072 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2073 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2074 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2075
2076 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002077 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002078 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002079
2080 const StreamParamsVec& data_streams = dcd->streams();
2081 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002082 EXPECT_EQ(data_streams[0].cname, data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002083 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2084 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2085 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2086 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2087 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2088 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2089
2090 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002091 dcd->bandwidth()); // default bandwidth (auto)
2092 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002093 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002094
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002095 // Update the offer. Add a new video track that is not synched to the
2096 // other tracks and replace audio track 2 with audio track 3.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002097 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2098 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002099 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002100 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
2101 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002102 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002103 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack3,
2104 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08002105 std::unique_ptr<SessionDescription> updated_offer(
2106 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002107
2108 ASSERT_TRUE(updated_offer.get() != NULL);
2109 ac = updated_offer->GetContentByName("audio");
2110 vc = updated_offer->GetContentByName("video");
2111 dc = updated_offer->GetContentByName("data");
2112 ASSERT_TRUE(ac != NULL);
2113 ASSERT_TRUE(vc != NULL);
2114 ASSERT_TRUE(dc != NULL);
2115 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002116 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002117 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002118 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002119 const RtpDataContentDescription* updated_dcd =
2120 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002121
2122 EXPECT_EQ(acd->type(), updated_acd->type());
2123 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2124 EXPECT_EQ(vcd->type(), updated_vcd->type());
2125 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2126 EXPECT_EQ(dcd->type(), updated_dcd->type());
2127 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002128 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002129 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002130 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002131 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002132 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002133 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2134
2135 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2136 ASSERT_EQ(2U, updated_audio_streams.size());
2137 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
2138 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
2139 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
2140 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
2141 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
2142
2143 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2144 ASSERT_EQ(2U, updated_video_streams.size());
2145 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2146 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002147 // All the media streams in one PeerConnection share one RTCP CNAME.
2148 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002149
2150 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2151 ASSERT_EQ(2U, updated_data_streams.size());
2152 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
2153 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
2154 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
2155 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
2156 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07002157 // The stream correctly got the CNAME from the MediaSessionOptions.
2158 // The Expected RTCP CNAME is the default one as we are using the default
2159 // MediaSessionOptions.
2160 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002161}
2162
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002163// Create an offer with simulcast video stream.
2164TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
2165 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002166 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2167 RtpTransceiverDirection::kRecvOnly, kActive,
2168 &opts);
2169 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2170 RtpTransceiverDirection::kSendRecv, kActive,
2171 &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002172 const int num_sim_layers = 3;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002173 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2174 {kMediaStream1}, num_sim_layers, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002175 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002176
2177 ASSERT_TRUE(offer.get() != NULL);
2178 const ContentInfo* vc = offer->GetContentByName("video");
2179 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002180 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002181
2182 const StreamParamsVec& video_streams = vcd->streams();
2183 ASSERT_EQ(1U, video_streams.size());
2184 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2185 const SsrcGroup* sim_ssrc_group =
2186 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
2187 ASSERT_TRUE(sim_ssrc_group != NULL);
2188 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
2189}
2190
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002191MATCHER(RidDescriptionEquals, "Verifies that two RidDescriptions are equal.") {
2192 const RidDescription& rid1 = ::testing::get<0>(arg);
2193 const RidDescription& rid2 = ::testing::get<1>(arg);
2194 return rid1.rid == rid2.rid && rid1.direction == rid2.direction;
2195}
2196
2197static void CheckSimulcastInSessionDescription(
2198 const SessionDescription* description,
2199 const std::string& content_name,
2200 const std::vector<RidDescription>& send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002201 const SimulcastLayerList& send_layers) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002202 ASSERT_NE(description, nullptr);
2203 const ContentInfo* content = description->GetContentByName(content_name);
2204 ASSERT_NE(content, nullptr);
2205 const MediaContentDescription* cd = content->media_description();
2206 ASSERT_NE(cd, nullptr);
2207 const StreamParamsVec& streams = cd->streams();
2208 ASSERT_THAT(streams, SizeIs(1));
2209 const StreamParams& stream = streams[0];
2210 ASSERT_THAT(stream.ssrcs, IsEmpty());
2211 EXPECT_TRUE(stream.has_rids());
2212 const std::vector<RidDescription> rids = stream.rids();
2213
2214 EXPECT_THAT(rids, Pointwise(RidDescriptionEquals(), send_rids));
2215
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002216 EXPECT_TRUE(cd->HasSimulcast());
2217 const SimulcastDescription& simulcast = cd->simulcast_description();
2218 EXPECT_THAT(simulcast.send_layers(), SizeIs(send_layers.size()));
2219 EXPECT_THAT(simulcast.send_layers(), Pointwise(Eq(), send_layers));
2220
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002221 ASSERT_THAT(simulcast.receive_layers().GetAllLayers(), SizeIs(0));
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002222}
2223
2224// Create an offer with spec-compliant simulcast video stream.
2225TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastOffer) {
2226 MediaSessionOptions opts;
2227 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2228 RtpTransceiverDirection::kSendRecv, kActive,
2229 &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002230 std::vector<RidDescription> send_rids;
2231 send_rids.push_back(RidDescription("f", RidDirection::kSend));
2232 send_rids.push_back(RidDescription("h", RidDirection::kSend));
2233 send_rids.push_back(RidDescription("q", RidDirection::kSend));
2234 SimulcastLayerList simulcast_layers;
2235 simulcast_layers.AddLayer(SimulcastLayer(send_rids[0].rid, false));
2236 simulcast_layers.AddLayer(SimulcastLayer(send_rids[1].rid, true));
2237 simulcast_layers.AddLayer(SimulcastLayer(send_rids[2].rid, false));
2238 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2239 {kMediaStream1}, send_rids,
2240 simulcast_layers, 0, &opts);
2241 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2242
2243 CheckSimulcastInSessionDescription(offer.get(), "video", send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002244 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002245}
2246
2247// Create an offer that signals RIDs (not SSRCs) without Simulcast.
2248// In this scenario, RIDs do not need to be negotiated (there is only one).
2249TEST_F(MediaSessionDescriptionFactoryTest, TestOfferWithRidsNoSimulcast) {
2250 MediaSessionOptions opts;
2251 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2252 RtpTransceiverDirection::kSendRecv, kActive,
2253 &opts);
2254 RidDescription rid("f", RidDirection::kSend);
2255 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2256 {kMediaStream1}, {rid},
2257 SimulcastLayerList(), 0, &opts);
2258 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2259
2260 ASSERT_NE(offer.get(), nullptr);
2261 const ContentInfo* content = offer->GetContentByName("video");
2262 ASSERT_NE(content, nullptr);
2263 const MediaContentDescription* cd = content->media_description();
2264 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002265 const StreamParamsVec& streams = cd->streams();
2266 ASSERT_THAT(streams, SizeIs(1));
2267 const StreamParams& stream = streams[0];
2268 ASSERT_THAT(stream.ssrcs, IsEmpty());
2269 EXPECT_FALSE(stream.has_rids());
2270 EXPECT_FALSE(cd->HasSimulcast());
2271}
2272
2273// Create an answer with spec-compliant simulcast video stream.
2274// In this scenario, the SFU is the caller requesting that we send Simulcast.
2275TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastAnswer) {
2276 MediaSessionOptions offer_opts;
2277 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2278 RtpTransceiverDirection::kSendRecv, kActive,
2279 &offer_opts);
2280 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2281 {kMediaStream1}, 1, &offer_opts);
2282 std::unique_ptr<SessionDescription> offer =
2283 f1_.CreateOffer(offer_opts, nullptr);
2284
2285 MediaSessionOptions answer_opts;
2286 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2287 RtpTransceiverDirection::kSendRecv, kActive,
2288 &answer_opts);
2289
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002290 std::vector<RidDescription> rid_descriptions{
2291 RidDescription("f", RidDirection::kSend),
2292 RidDescription("h", RidDirection::kSend),
2293 RidDescription("q", RidDirection::kSend),
2294 };
2295 SimulcastLayerList simulcast_layers;
2296 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[0].rid, false));
2297 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[1].rid, true));
2298 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[2].rid, false));
2299 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2300 {kMediaStream1}, rid_descriptions,
2301 simulcast_layers, 0, &answer_opts);
2302 std::unique_ptr<SessionDescription> answer =
2303 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2304
2305 CheckSimulcastInSessionDescription(answer.get(), "video", rid_descriptions,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002306 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002307}
2308
2309// Create an answer that signals RIDs (not SSRCs) without Simulcast.
2310// In this scenario, RIDs do not need to be negotiated (there is only one).
2311// Note that RID Direction is not the same as the transceiver direction.
2312TEST_F(MediaSessionDescriptionFactoryTest, TestAnswerWithRidsNoSimulcast) {
2313 MediaSessionOptions offer_opts;
2314 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2315 RtpTransceiverDirection::kSendRecv, kActive,
2316 &offer_opts);
2317 RidDescription rid_offer("f", RidDirection::kSend);
2318 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2319 {kMediaStream1}, {rid_offer},
2320 SimulcastLayerList(), 0, &offer_opts);
2321 std::unique_ptr<SessionDescription> offer =
2322 f1_.CreateOffer(offer_opts, nullptr);
2323
2324 MediaSessionOptions answer_opts;
2325 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2326 RtpTransceiverDirection::kSendRecv, kActive,
2327 &answer_opts);
2328
2329 RidDescription rid_answer("f", RidDirection::kReceive);
2330 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2331 {kMediaStream1}, {rid_answer},
2332 SimulcastLayerList(), 0, &answer_opts);
2333 std::unique_ptr<SessionDescription> answer =
2334 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2335
2336 ASSERT_NE(answer.get(), nullptr);
2337 const ContentInfo* content = offer->GetContentByName("video");
2338 ASSERT_NE(content, nullptr);
2339 const MediaContentDescription* cd = content->media_description();
2340 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002341 const StreamParamsVec& streams = cd->streams();
2342 ASSERT_THAT(streams, SizeIs(1));
2343 const StreamParams& stream = streams[0];
2344 ASSERT_THAT(stream.ssrcs, IsEmpty());
2345 EXPECT_FALSE(stream.has_rids());
2346 EXPECT_FALSE(cd->HasSimulcast());
2347}
2348
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002349// Create an audio and video answer to a standard video offer with:
2350// - one video track
2351// - two audio tracks
2352// - two data tracks
2353// and ensure it matches what we expect. Also updates the initial answer by
2354// adding a new video track and removes one of the audio tracks.
2355TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
2356 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002357 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2358 RtpTransceiverDirection::kRecvOnly, kActive,
2359 &offer_opts);
2360 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2361 RtpTransceiverDirection::kRecvOnly, kActive,
2362 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002363 offer_opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002364 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2365 RtpTransceiverDirection::kRecvOnly, kActive,
2366 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002367 f1_.set_secure(SEC_ENABLED);
2368 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002369 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002370
zhihuang1c378ed2017-08-17 14:10:50 -07002371 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002372 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2373 RtpTransceiverDirection::kSendRecv, kActive,
2374 &answer_opts);
2375 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2376 RtpTransceiverDirection::kSendRecv, kActive,
2377 &answer_opts);
2378 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2379 {kMediaStream1}, 1, &answer_opts);
2380 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2381 {kMediaStream1}, 1, &answer_opts);
2382 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2383 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002384
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002385 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2386 RtpTransceiverDirection::kSendRecv, kActive,
2387 &answer_opts);
2388 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2389 {kMediaStream1}, 1, &answer_opts);
2390 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2391 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002392 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002393
Steve Anton6fe1fba2018-12-11 10:15:23 -08002394 std::unique_ptr<SessionDescription> answer =
2395 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002396
2397 ASSERT_TRUE(answer.get() != NULL);
2398 const ContentInfo* ac = answer->GetContentByName("audio");
2399 const ContentInfo* vc = answer->GetContentByName("video");
2400 const ContentInfo* dc = answer->GetContentByName("data");
2401 ASSERT_TRUE(ac != NULL);
2402 ASSERT_TRUE(vc != NULL);
2403 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002404 const AudioContentDescription* acd = ac->media_description()->as_audio();
2405 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002406 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002407 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
2408 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
2409 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002410
2411 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002412 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002413
2414 const StreamParamsVec& audio_streams = acd->streams();
2415 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002416 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002417 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2418 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2419 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2420 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2421 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2422 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2423
2424 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2425 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
2426
2427 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002428 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002429
2430 const StreamParamsVec& video_streams = vcd->streams();
2431 ASSERT_EQ(1U, video_streams.size());
2432 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2433 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2434 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2435 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2436
2437 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002438 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002439
2440 const StreamParamsVec& data_streams = dcd->streams();
2441 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002442 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002443 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2444 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2445 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2446 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2447 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2448 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2449
2450 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002451 dcd->bandwidth()); // default bandwidth (auto)
2452 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002453
2454 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07002455 // other tracks and remove 1 audio track.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002456 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2457 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002458 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
2459 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08002460 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002461 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002462
2463 ASSERT_TRUE(updated_answer.get() != NULL);
2464 ac = updated_answer->GetContentByName("audio");
2465 vc = updated_answer->GetContentByName("video");
2466 dc = updated_answer->GetContentByName("data");
2467 ASSERT_TRUE(ac != NULL);
2468 ASSERT_TRUE(vc != NULL);
2469 ASSERT_TRUE(dc != NULL);
2470 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002471 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002472 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002473 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002474 const RtpDataContentDescription* updated_dcd =
2475 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002476
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002477 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002478 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002479 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002480 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002481 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002482 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2483
2484 EXPECT_EQ(acd->type(), updated_acd->type());
2485 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2486 EXPECT_EQ(vcd->type(), updated_vcd->type());
2487 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2488 EXPECT_EQ(dcd->type(), updated_dcd->type());
2489 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
2490
2491 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2492 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002493 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002494
2495 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2496 ASSERT_EQ(2U, updated_video_streams.size());
2497 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2498 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002499 // All media streams in one PeerConnection share one CNAME.
2500 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002501
2502 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2503 ASSERT_EQ(1U, updated_data_streams.size());
2504 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
2505}
2506
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002507// Create an updated offer after creating an answer to the original offer and
2508// verify that the codecs that were part of the original answer are not changed
2509// in the updated offer.
2510TEST_F(MediaSessionDescriptionFactoryTest,
2511 RespondentCreatesOfferAfterCreatingAnswer) {
2512 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002513 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002514
Steve Anton6fe1fba2018-12-11 10:15:23 -08002515 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2516 std::unique_ptr<SessionDescription> answer =
2517 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002518
2519 const AudioContentDescription* acd =
2520 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002521 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002522
2523 const VideoContentDescription* vcd =
2524 GetFirstVideoContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002525 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002526
kwiberg31022942016-03-11 14:18:21 -08002527 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002528 f2_.CreateOffer(opts, answer.get()));
2529
2530 // The expected audio codecs are the common audio codecs from the first
2531 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
2532 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002533 // TODO(wu): |updated_offer| should not include the codec
2534 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002535 const AudioCodec kUpdatedAudioCodecOffer[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002536 kAudioCodecsAnswer[0],
2537 kAudioCodecsAnswer[1],
2538 kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002539 };
2540
2541 // The expected video codecs are the common video codecs from the first
2542 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
2543 // preference order.
2544 const VideoCodec kUpdatedVideoCodecOffer[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002545 kVideoCodecsAnswer[0],
2546 kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002547 };
2548
2549 const AudioContentDescription* updated_acd =
2550 GetFirstAudioContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002551 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kUpdatedAudioCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002552
2553 const VideoContentDescription* updated_vcd =
2554 GetFirstVideoContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002555 EXPECT_THAT(updated_vcd->codecs(), ElementsAreArray(kUpdatedVideoCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002556}
2557
Steve Anton5c72e712018-12-10 14:25:30 -08002558// Test that a reoffer does not reuse audio codecs from a previous media section
2559// that is being recycled.
2560TEST_F(MediaSessionDescriptionFactoryTest,
2561 ReOfferDoesNotReUseRecycledAudioCodecs) {
Johannes Kron184ea662020-01-29 12:43:36 +01002562 f1_.set_video_codecs({}, {});
2563 f2_.set_video_codecs({}, {});
Steve Anton5c72e712018-12-10 14:25:30 -08002564
2565 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002566 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2567 RtpTransceiverDirection::kSendRecv, kActive,
2568 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002569 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2570 std::unique_ptr<SessionDescription> answer =
2571 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002572
2573 // Recycle the media section by changing its mid.
2574 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002575 std::unique_ptr<SessionDescription> reoffer =
2576 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002577
2578 // Expect that the results of the first negotiation are ignored. If the m=
2579 // section was not recycled the payload types would match the initial offerer.
2580 const AudioContentDescription* acd =
2581 GetFirstAudioContentDescription(reoffer.get());
2582 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecs2));
2583}
2584
2585// Test that a reoffer does not reuse video codecs from a previous media section
2586// that is being recycled.
2587TEST_F(MediaSessionDescriptionFactoryTest,
2588 ReOfferDoesNotReUseRecycledVideoCodecs) {
2589 f1_.set_audio_codecs({}, {});
2590 f2_.set_audio_codecs({}, {});
2591
2592 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002593 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2594 RtpTransceiverDirection::kSendRecv, kActive,
2595 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002596 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2597 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002598
2599 // Recycle the media section by changing its mid.
2600 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002601 std::unique_ptr<SessionDescription> reoffer =
2602 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002603
2604 // Expect that the results of the first negotiation are ignored. If the m=
2605 // section was not recycled the payload types would match the initial offerer.
2606 const VideoContentDescription* vcd =
2607 GetFirstVideoContentDescription(reoffer.get());
2608 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecs2));
2609}
2610
2611// Test that a reanswer does not reuse audio codecs from a previous media
2612// section that is being recycled.
2613TEST_F(MediaSessionDescriptionFactoryTest,
2614 ReAnswerDoesNotReUseRecycledAudioCodecs) {
Johannes Kron184ea662020-01-29 12:43:36 +01002615 f1_.set_video_codecs({}, {});
2616 f2_.set_video_codecs({}, {});
Steve Anton5c72e712018-12-10 14:25:30 -08002617
2618 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2619 // second offer/answer is forward (|f1_| as offerer).
2620 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002621 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2622 RtpTransceiverDirection::kSendRecv, kActive,
2623 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002624 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2625 std::unique_ptr<SessionDescription> answer =
2626 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002627
2628 // Recycle the media section by changing its mid.
2629 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002630 std::unique_ptr<SessionDescription> reoffer =
2631 f1_.CreateOffer(opts, answer.get());
2632 std::unique_ptr<SessionDescription> reanswer =
2633 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002634
2635 // Expect that the results of the first negotiation are ignored. If the m=
2636 // section was not recycled the payload types would match the initial offerer.
2637 const AudioContentDescription* acd =
2638 GetFirstAudioContentDescription(reanswer.get());
2639 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
2640}
2641
2642// Test that a reanswer does not reuse video codecs from a previous media
2643// section that is being recycled.
2644TEST_F(MediaSessionDescriptionFactoryTest,
2645 ReAnswerDoesNotReUseRecycledVideoCodecs) {
2646 f1_.set_audio_codecs({}, {});
2647 f2_.set_audio_codecs({}, {});
2648
2649 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2650 // second offer/answer is forward (|f1_| as offerer).
2651 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002652 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2653 RtpTransceiverDirection::kSendRecv, kActive,
2654 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002655 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2656 std::unique_ptr<SessionDescription> answer =
2657 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002658
2659 // Recycle the media section by changing its mid.
2660 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002661 std::unique_ptr<SessionDescription> reoffer =
2662 f1_.CreateOffer(opts, answer.get());
2663 std::unique_ptr<SessionDescription> reanswer =
2664 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002665
2666 // Expect that the results of the first negotiation are ignored. If the m=
2667 // section was not recycled the payload types would match the initial offerer.
2668 const VideoContentDescription* vcd =
2669 GetFirstVideoContentDescription(reanswer.get());
2670 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
2671}
2672
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002673// Create an updated offer after creating an answer to the original offer and
2674// verify that the codecs that were part of the original answer are not changed
2675// in the updated offer. In this test Rtx is enabled.
2676TEST_F(MediaSessionDescriptionFactoryTest,
2677 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2678 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002679 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2680 RtpTransceiverDirection::kRecvOnly, kActive,
2681 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002682 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002683 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002684 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron184ea662020-01-29 12:43:36 +01002685 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002686
2687 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002688 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002689 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron184ea662020-01-29 12:43:36 +01002690 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002691
Steve Anton6fe1fba2018-12-11 10:15:23 -08002692 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002693 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002694 std::unique_ptr<SessionDescription> answer =
2695 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002696
2697 const VideoContentDescription* vcd =
2698 GetFirstVideoContentDescription(answer.get());
2699
2700 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002701 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2702 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002703
2704 EXPECT_EQ(expected_codecs, vcd->codecs());
2705
deadbeef67cf2c12016-04-13 10:07:16 -07002706 // Now, make sure we get same result (except for the order) if |f2_| creates
2707 // an updated offer even though the default payload types between |f1_| and
2708 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08002709 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002710 f2_.CreateOffer(opts, answer.get()));
2711 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002712 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002713 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2714
2715 const VideoContentDescription* updated_vcd =
2716 GetFirstVideoContentDescription(updated_answer.get());
2717
2718 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2719}
2720
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002721// Regression test for:
2722// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2723// Existing codecs should always appear before new codecs in re-offers. But
2724// under a specific set of circumstances, the existing RTX codec was ending up
2725// added to the end of the list.
2726TEST_F(MediaSessionDescriptionFactoryTest,
2727 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2728 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002729 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2730 RtpTransceiverDirection::kRecvOnly, kActive,
2731 &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002732 // We specifically choose different preferred payload types for VP8 to
2733 // trigger the issue.
2734 cricket::VideoCodec vp8_offerer(100, "VP8");
2735 cricket::VideoCodec vp8_offerer_rtx =
2736 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
2737 cricket::VideoCodec vp8_answerer(110, "VP8");
2738 cricket::VideoCodec vp8_answerer_rtx =
2739 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
2740 cricket::VideoCodec vp9(120, "VP9");
2741 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
2742
2743 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
2744 // We also specifically cause the answerer to prefer VP9, such that if it
2745 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
2746 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
2747 vp8_answerer_rtx};
2748
Johannes Kron184ea662020-01-29 12:43:36 +01002749 f1_.set_video_codecs(f1_codecs, f1_codecs);
2750 f2_.set_video_codecs(f2_codecs, f2_codecs);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002751 std::vector<AudioCodec> audio_codecs;
2752 f1_.set_audio_codecs(audio_codecs, audio_codecs);
2753 f2_.set_audio_codecs(audio_codecs, audio_codecs);
2754
2755 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002756 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002757 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002758 std::unique_ptr<SessionDescription> answer =
2759 f2_.CreateAnswer(offer.get(), opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002760
2761 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
2762 // But if the bug is triggered, RTX for VP8 ends up last.
2763 std::unique_ptr<SessionDescription> updated_offer(
2764 f2_.CreateOffer(opts, answer.get()));
2765
2766 const VideoContentDescription* vcd =
2767 GetFirstVideoContentDescription(updated_offer.get());
2768 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
2769 ASSERT_EQ(4u, codecs.size());
2770 EXPECT_EQ(vp8_offerer, codecs[0]);
2771 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
2772 EXPECT_EQ(vp9, codecs[2]);
2773 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002774}
2775
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002776// Create an updated offer that adds video after creating an audio only answer
2777// to the original offer. This test verifies that if a video codec and the RTX
2778// codec have the same default payload type as an audio codec that is already in
2779// use, the added codecs payload types are changed.
2780TEST_F(MediaSessionDescriptionFactoryTest,
2781 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2782 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002783 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002784 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron184ea662020-01-29 12:43:36 +01002785 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002786
2787 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002788 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2789 RtpTransceiverDirection::kRecvOnly, kActive,
2790 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002791
Steve Anton6fe1fba2018-12-11 10:15:23 -08002792 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2793 std::unique_ptr<SessionDescription> answer =
2794 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002795
2796 const AudioContentDescription* acd =
2797 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002798 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002799
2800 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
2801 // reference be the same as an audio codec that was negotiated in the
2802 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002803 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08002804 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002805
2806 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2807 int used_pl_type = acd->codecs()[0].id;
2808 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002809 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
Johannes Kron184ea662020-01-29 12:43:36 +01002810 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002811
kwiberg31022942016-03-11 14:18:21 -08002812 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002813 f2_.CreateOffer(opts, answer.get()));
2814 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002815 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002816 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2817
2818 const AudioContentDescription* updated_acd =
2819 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002820 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002821
2822 const VideoContentDescription* updated_vcd =
2823 GetFirstVideoContentDescription(updated_answer.get());
2824
2825 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
Steve Antone38a5a12018-11-21 16:05:15 -08002826 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02002827 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002828 EXPECT_NE(used_pl_type, new_h264_pl_type);
2829 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002830 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002831 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
2832 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
2833}
2834
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002835// Create an updated offer with RTX after creating an answer to an offer
2836// without RTX, and with different default payload types.
2837// Verify that the added RTX codec references the correct payload type.
2838TEST_F(MediaSessionDescriptionFactoryTest,
2839 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
2840 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002841 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002842
2843 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2844 // This creates rtx for H264 with the payload type |f2_| uses.
2845 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron184ea662020-01-29 12:43:36 +01002846 f2_.set_video_codecs(f2_codecs, f2_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002847
Steve Anton6fe1fba2018-12-11 10:15:23 -08002848 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002849 ASSERT_TRUE(offer.get() != nullptr);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002850 std::unique_ptr<SessionDescription> answer =
2851 f2_.CreateAnswer(offer.get(), opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002852
2853 const VideoContentDescription* vcd =
2854 GetFirstVideoContentDescription(answer.get());
2855
2856 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2857 EXPECT_EQ(expected_codecs, vcd->codecs());
2858
2859 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
2860 // updated offer, even though the default payload types are different from
2861 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08002862 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002863 f2_.CreateOffer(opts, answer.get()));
2864 ASSERT_TRUE(updated_offer);
2865
2866 const VideoContentDescription* updated_vcd =
2867 GetFirstVideoContentDescription(updated_offer.get());
2868
2869 // New offer should attempt to add H263, and RTX for H264.
2870 expected_codecs.push_back(kVideoCodecs2[1]);
2871 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
2872 &expected_codecs);
2873 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2874}
2875
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002876// Test that RTX is ignored when there is no associated payload type parameter.
2877TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
2878 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002879 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2880 RtpTransceiverDirection::kRecvOnly, kActive,
2881 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002882 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002883 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07002884 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
Johannes Kron184ea662020-01-29 12:43:36 +01002885 f1_.set_video_codecs(f1_codecs, f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002886
2887 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002888 // This creates RTX for H264 with the payload type |f2_| uses.
2889 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron184ea662020-01-29 12:43:36 +01002890 f2_.set_video_codecs(f2_codecs, f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002891
Steve Anton6fe1fba2018-12-11 10:15:23 -08002892 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002893 ASSERT_TRUE(offer.get() != NULL);
2894 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
2895 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
2896 // is possible to test that that RTX is dropped when
2897 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08002898 MediaContentDescription* media_desc =
2899 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2900 ASSERT_TRUE(media_desc);
2901 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002902 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07002903 for (VideoCodec& codec : codecs) {
2904 if (codec.name.find(cricket::kRtxCodecName) == 0) {
2905 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002906 }
2907 }
2908 desc->set_codecs(codecs);
2909
Steve Anton6fe1fba2018-12-11 10:15:23 -08002910 std::unique_ptr<SessionDescription> answer =
2911 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002912
Steve Anton64b626b2019-01-28 17:25:26 -08002913 EXPECT_THAT(
2914 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
2915 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002916}
2917
2918// Test that RTX will be filtered out in the answer if its associated payload
2919// type doesn't match the local value.
2920TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
2921 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002922 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2923 RtpTransceiverDirection::kRecvOnly, kActive,
2924 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002925 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2926 // This creates RTX for H264 in sender.
2927 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron184ea662020-01-29 12:43:36 +01002928 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002929
2930 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2931 // This creates RTX for H263 in receiver.
2932 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
Johannes Kron184ea662020-01-29 12:43:36 +01002933 f2_.set_video_codecs(f2_codecs, f2_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002934
Steve Anton6fe1fba2018-12-11 10:15:23 -08002935 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002936 ASSERT_TRUE(offer.get() != NULL);
2937 // Associated payload type doesn't match, therefore, RTX codec is removed in
2938 // the answer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002939 std::unique_ptr<SessionDescription> answer =
2940 f2_.CreateAnswer(offer.get(), opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002941
Steve Anton64b626b2019-01-28 17:25:26 -08002942 EXPECT_THAT(
2943 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
2944 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002945}
2946
2947// Test that when multiple RTX codecs are offered, only the matched RTX codec
2948// is added in the answer, and the unsupported RTX codec is filtered out.
2949TEST_F(MediaSessionDescriptionFactoryTest,
2950 FilterOutUnsupportedRtxWhenCreatingAnswer) {
2951 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002952 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2953 RtpTransceiverDirection::kRecvOnly, kActive,
2954 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002955 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2956 // This creates RTX for H264-SVC in sender.
2957 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
Johannes Kron184ea662020-01-29 12:43:36 +01002958 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002959
2960 // This creates RTX for H264 in sender.
2961 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron184ea662020-01-29 12:43:36 +01002962 f1_.set_video_codecs(f1_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002963
2964 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2965 // This creates RTX for H264 in receiver.
2966 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
Johannes Kron184ea662020-01-29 12:43:36 +01002967 f2_.set_video_codecs(f2_codecs, f1_codecs);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002968
2969 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
2970 // for H264-SVC should also be removed.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002971 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002972 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002973 std::unique_ptr<SessionDescription> answer =
2974 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002975 const VideoContentDescription* vcd =
2976 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002977 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2978 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2979 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002980
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002981 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002982}
2983
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002984// Test that after one RTX codec has been negotiated, a new offer can attempt
2985// to add another.
2986TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
2987 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002988 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2989 RtpTransceiverDirection::kRecvOnly, kActive,
2990 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002991 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2992 // This creates RTX for H264 for the offerer.
2993 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
Johannes Kron184ea662020-01-29 12:43:36 +01002994 f1_.set_video_codecs(f1_codecs, f1_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002995
Steve Anton6fe1fba2018-12-11 10:15:23 -08002996 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002997 ASSERT_TRUE(offer);
2998 const VideoContentDescription* vcd =
2999 GetFirstVideoContentDescription(offer.get());
3000
3001 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
3002 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3003 &expected_codecs);
3004 EXPECT_EQ(expected_codecs, vcd->codecs());
3005
3006 // Now, attempt to add RTX for H264-SVC.
3007 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
Johannes Kron184ea662020-01-29 12:43:36 +01003008 f1_.set_video_codecs(f1_codecs, f1_codecs);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003009
kwiberg31022942016-03-11 14:18:21 -08003010 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003011 f1_.CreateOffer(opts, offer.get()));
3012 ASSERT_TRUE(updated_offer);
3013 vcd = GetFirstVideoContentDescription(updated_offer.get());
3014
3015 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
3016 &expected_codecs);
3017 EXPECT_EQ(expected_codecs, vcd->codecs());
3018}
3019
Noah Richards2e7a0982015-05-18 14:02:54 -07003020// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
3021// generated for each simulcast ssrc and correctly grouped.
3022TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
3023 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003024 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3025 RtpTransceiverDirection::kSendRecv, kActive,
3026 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003027 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003028 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3029 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003030
3031 // Use a single real codec, and then add RTX for it.
3032 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07003033 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07003034 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
Johannes Kron184ea662020-01-29 12:43:36 +01003035 f1_.set_video_codecs(f1_codecs, f1_codecs);
Noah Richards2e7a0982015-05-18 14:02:54 -07003036
3037 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
3038 // is a FID ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003039 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Noah Richards2e7a0982015-05-18 14:02:54 -07003040 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003041 MediaContentDescription* media_desc =
3042 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3043 ASSERT_TRUE(media_desc);
3044 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07003045 const StreamParamsVec& streams = desc->streams();
3046 // Single stream.
3047 ASSERT_EQ(1u, streams.size());
3048 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
3049 EXPECT_EQ(6u, streams[0].ssrcs.size());
3050 // And should have a SIM group for the simulcast.
3051 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3052 // And a FID group for RTX.
3053 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02003054 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003055 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3056 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02003057 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003058 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
3059 EXPECT_EQ(3u, fid_ssrcs.size());
3060}
3061
brandtr03d5fb12016-11-22 03:37:59 -08003062// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
3063// together with a FEC-FR grouping.
3064TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
3065 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003066 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3067 RtpTransceiverDirection::kSendRecv, kActive,
3068 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003069 // Add single stream.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003070 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3071 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003072
3073 // Use a single real codec, and then add FlexFEC for it.
3074 std::vector<VideoCodec> f1_codecs;
3075 f1_codecs.push_back(VideoCodec(97, "H264"));
3076 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
Johannes Kron184ea662020-01-29 12:43:36 +01003077 f1_.set_video_codecs(f1_codecs, f1_codecs);
brandtr03d5fb12016-11-22 03:37:59 -08003078
3079 // Ensure that the offer has a single FlexFEC ssrc and that
3080 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003081 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003082 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003083 MediaContentDescription* media_desc =
3084 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3085 ASSERT_TRUE(media_desc);
3086 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003087 const StreamParamsVec& streams = desc->streams();
3088 // Single stream.
3089 ASSERT_EQ(1u, streams.size());
3090 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
3091 EXPECT_EQ(2u, streams[0].ssrcs.size());
3092 // And should have a FEC-FR group for FlexFEC.
3093 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
3094 std::vector<uint32_t> primary_ssrcs;
3095 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3096 ASSERT_EQ(1u, primary_ssrcs.size());
3097 uint32_t flexfec_ssrc;
3098 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
3099 EXPECT_NE(flexfec_ssrc, 0u);
3100}
3101
3102// Test that FlexFEC is disabled for simulcast.
3103// TODO(brandtr): Remove this test when we support simulcast, either through
3104// multiple FlexfecSenders, or through multistream protection.
3105TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
3106 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003107 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3108 RtpTransceiverDirection::kSendRecv, kActive,
3109 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003110 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003111 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3112 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003113
3114 // Use a single real codec, and then add FlexFEC for it.
3115 std::vector<VideoCodec> f1_codecs;
3116 f1_codecs.push_back(VideoCodec(97, "H264"));
3117 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
Johannes Kron184ea662020-01-29 12:43:36 +01003118 f1_.set_video_codecs(f1_codecs, f1_codecs);
brandtr03d5fb12016-11-22 03:37:59 -08003119
3120 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
3121 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003122 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003123 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003124 MediaContentDescription* media_desc =
3125 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3126 ASSERT_TRUE(media_desc);
3127 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003128 const StreamParamsVec& streams = desc->streams();
3129 // Single stream.
3130 ASSERT_EQ(1u, streams.size());
3131 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
3132 EXPECT_EQ(3u, streams[0].ssrcs.size());
3133 // And should have a SIM group for the simulcast.
3134 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3135 // And not a FEC-FR group for FlexFEC.
3136 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
3137 std::vector<uint32_t> primary_ssrcs;
3138 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3139 EXPECT_EQ(3u, primary_ssrcs.size());
3140 for (uint32_t primary_ssrc : primary_ssrcs) {
3141 uint32_t flexfec_ssrc;
3142 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
3143 }
3144}
3145
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003146// Create an updated offer after creating an answer to the original offer and
3147// verify that the RTP header extensions that were part of the original answer
3148// are not changed in the updated offer.
3149TEST_F(MediaSessionDescriptionFactoryTest,
3150 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
3151 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003152 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003153
3154 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
3155 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
3156 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
3157 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
3158
Steve Anton6fe1fba2018-12-11 10:15:23 -08003159 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
3160 std::unique_ptr<SessionDescription> answer =
3161 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003162
Yves Gerey665174f2018-06-19 15:03:05 +02003163 EXPECT_EQ(
3164 MAKE_VECTOR(kAudioRtpExtensionAnswer),
3165 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
3166 EXPECT_EQ(
3167 MAKE_VECTOR(kVideoRtpExtensionAnswer),
3168 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003169
kwiberg31022942016-03-11 14:18:21 -08003170 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003171 f2_.CreateOffer(opts, answer.get()));
3172
3173 // The expected RTP header extensions in the new offer are the resulting
3174 // extensions from the first offer/answer exchange plus the extensions only
3175 // |f2_| offer.
3176 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003177 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07003178 const RtpExtension kUpdatedAudioRtpExtensions[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003179 kAudioRtpExtensionAnswer[0],
3180 RtpExtension(kAudioRtpExtension2[1].uri, 13),
isheriff6f8d6862016-05-26 11:24:55 -07003181 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003182 };
3183
3184 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003185 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07003186 const RtpExtension kUpdatedVideoRtpExtensions[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003187 kVideoRtpExtensionAnswer[0],
3188 RtpExtension(kVideoRtpExtension2[1].uri, 12),
isheriff6f8d6862016-05-26 11:24:55 -07003189 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003190 };
3191
3192 const AudioContentDescription* updated_acd =
3193 GetFirstAudioContentDescription(updated_offer.get());
3194 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
3195 updated_acd->rtp_header_extensions());
3196
3197 const VideoContentDescription* updated_vcd =
3198 GetFirstVideoContentDescription(updated_offer.get());
3199 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
3200 updated_vcd->rtp_header_extensions());
3201}
3202
deadbeefa5b273a2015-08-20 17:30:13 -07003203// Verify that if the same RTP extension URI is used for audio and video, the
3204// same ID is used. Also verify that the ID isn't changed when creating an
3205// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07003206TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07003207 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003208 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07003209
3210 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
3211 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
3212
Steve Anton6fe1fba2018-12-11 10:15:23 -08003213 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
deadbeefa5b273a2015-08-20 17:30:13 -07003214
3215 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
3216 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07003217 const RtpExtension kExpectedVideoRtpExtension[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003218 kVideoRtpExtension3[0],
3219 kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07003220 };
3221
Yves Gerey665174f2018-06-19 15:03:05 +02003222 EXPECT_EQ(
3223 MAKE_VECTOR(kAudioRtpExtension3),
3224 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3225 EXPECT_EQ(
3226 MAKE_VECTOR(kExpectedVideoRtpExtension),
3227 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003228
3229 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08003230 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07003231 f1_.CreateOffer(opts, offer.get()));
3232
3233 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02003234 GetFirstAudioContentDescription(updated_offer.get())
3235 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003236 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003237 GetFirstVideoContentDescription(updated_offer.get())
3238 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003239}
3240
jbauch5869f502017-06-29 12:31:36 -07003241// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
3242TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
3243 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003244 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07003245
3246 f1_.set_enable_encrypted_rtp_header_extensions(true);
3247 f2_.set_enable_encrypted_rtp_header_extensions(true);
3248
3249 f1_.set_audio_rtp_header_extensions(
3250 MAKE_VECTOR(kAudioRtpExtension3ForEncryption));
3251 f1_.set_video_rtp_header_extensions(
3252 MAKE_VECTOR(kVideoRtpExtension3ForEncryption));
3253
Steve Anton6fe1fba2018-12-11 10:15:23 -08003254 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07003255
3256 // The extensions that are shared between audio and video should use the same
3257 // id.
3258 const RtpExtension kExpectedVideoRtpExtension[] = {
3259 kVideoRtpExtension3ForEncryption[0],
3260 kAudioRtpExtension3ForEncryptionOffer[1],
3261 kAudioRtpExtension3ForEncryptionOffer[2],
3262 };
3263
Yves Gerey665174f2018-06-19 15:03:05 +02003264 EXPECT_EQ(
3265 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
3266 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3267 EXPECT_EQ(
3268 MAKE_VECTOR(kExpectedVideoRtpExtension),
3269 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003270
3271 // Nothing should change when creating a new offer
3272 std::unique_ptr<SessionDescription> updated_offer(
3273 f1_.CreateOffer(opts, offer.get()));
3274
3275 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003276 GetFirstAudioContentDescription(updated_offer.get())
3277 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003278 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003279 GetFirstVideoContentDescription(updated_offer.get())
3280 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003281}
3282
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003283TEST(MediaSessionDescription, CopySessionDescription) {
3284 SessionDescription source;
3285 cricket::ContentGroup group(cricket::CN_AUDIO);
3286 source.AddGroup(group);
Harald Alvestrand1716d392019-06-03 20:35:45 +02003287 std::unique_ptr<AudioContentDescription> acd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003288 std::make_unique<AudioContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003289 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
3290 acd->AddLegacyStream(1);
Harald Alvestrand1716d392019-06-03 20:35:45 +02003291 std::unique_ptr<AudioContentDescription> acd_passed =
3292 absl::WrapUnique(acd->Copy());
3293 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp,
3294 std::move(acd_passed));
3295 std::unique_ptr<VideoContentDescription> vcd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003296 std::make_unique<VideoContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003297 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
3298 vcd->AddLegacyStream(2);
Harald Alvestrand1716d392019-06-03 20:35:45 +02003299 std::unique_ptr<VideoContentDescription> vcd_passed =
3300 absl::WrapUnique(vcd->Copy());
3301 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp,
3302 std::move(vcd_passed));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003303
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003304 std::unique_ptr<SessionDescription> copy = source.Clone();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003305 ASSERT_TRUE(copy.get() != NULL);
3306 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
3307 const ContentInfo* ac = copy->GetContentByName("audio");
3308 const ContentInfo* vc = copy->GetContentByName("video");
3309 ASSERT_TRUE(ac != NULL);
3310 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08003311 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003312 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003313 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
3314 EXPECT_EQ(1u, acd->first_ssrc());
3315
Steve Anton5adfafd2017-12-20 16:34:00 -08003316 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003317 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003318 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
3319 EXPECT_EQ(2u, vcd->first_ssrc());
3320}
3321
3322// The below TestTransportInfoXXX tests create different offers/answers, and
3323// ensure the TransportInfo in the SessionDescription matches what we expect.
3324TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
3325 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003326 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3327 RtpTransceiverDirection::kRecvOnly, kActive,
3328 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003329 TestTransportInfo(true, options, false);
3330}
3331
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003332TEST_F(MediaSessionDescriptionFactoryTest,
3333 TestTransportInfoOfferIceRenomination) {
3334 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003335 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3336 RtpTransceiverDirection::kRecvOnly, kActive,
3337 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003338 options.media_description_options[0]
3339 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003340 TestTransportInfo(true, options, false);
3341}
3342
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003343TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
3344 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003345 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3346 RtpTransceiverDirection::kRecvOnly, kActive,
3347 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003348 TestTransportInfo(true, options, true);
3349}
3350
3351TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
3352 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003353 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3354 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3355 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003356 TestTransportInfo(true, options, false);
3357}
3358
3359TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003360 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003361 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003362 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3363 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3364 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003365 TestTransportInfo(true, options, true);
3366}
3367
3368TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
3369 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003370 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3371 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3372 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003373 options.bundle_enabled = true;
3374 TestTransportInfo(true, options, false);
3375}
3376
3377TEST_F(MediaSessionDescriptionFactoryTest,
3378 TestTransportInfoOfferBundleCurrent) {
3379 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003380 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3381 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3382 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003383 options.bundle_enabled = true;
3384 TestTransportInfo(true, options, true);
3385}
3386
3387TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
3388 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003389 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3390 RtpTransceiverDirection::kRecvOnly, kActive,
3391 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003392 TestTransportInfo(false, options, false);
3393}
3394
3395TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003396 TestTransportInfoAnswerIceRenomination) {
3397 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003398 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3399 RtpTransceiverDirection::kRecvOnly, kActive,
3400 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003401 options.media_description_options[0]
3402 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003403 TestTransportInfo(false, options, false);
3404}
3405
3406TEST_F(MediaSessionDescriptionFactoryTest,
3407 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003408 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003409 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3410 RtpTransceiverDirection::kRecvOnly, kActive,
3411 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003412 TestTransportInfo(false, options, true);
3413}
3414
3415TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
3416 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003417 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3418 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3419 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003420 TestTransportInfo(false, options, false);
3421}
3422
3423TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003424 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003425 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003426 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3427 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3428 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003429 TestTransportInfo(false, options, true);
3430}
3431
3432TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
3433 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003434 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3435 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3436 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003437 options.bundle_enabled = true;
3438 TestTransportInfo(false, options, false);
3439}
3440
3441TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003442 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003443 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003444 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3445 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3446 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003447 options.bundle_enabled = true;
3448 TestTransportInfo(false, options, true);
3449}
3450
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07003451TEST_F(MediaSessionDescriptionFactoryTest,
3452 TestTransportInfoOfferBundlesTransportOptions) {
3453 MediaSessionOptions options;
3454 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3455
3456 cricket::OpaqueTransportParameters audio_params;
3457 audio_params.protocol = "audio-transport";
3458 audio_params.parameters = "audio-params";
3459 FindFirstMediaDescriptionByMid("audio", &options)
3460 ->transport_options.opaque_parameters = audio_params;
3461
3462 cricket::OpaqueTransportParameters video_params;
3463 video_params.protocol = "video-transport";
3464 video_params.parameters = "video-params";
3465 FindFirstMediaDescriptionByMid("video", &options)
3466 ->transport_options.opaque_parameters = video_params;
3467
3468 TestTransportInfo(/*offer=*/true, options, /*has_current_desc=*/false);
3469}
3470
3471TEST_F(MediaSessionDescriptionFactoryTest,
3472 TestTransportInfoAnswerBundlesTransportOptions) {
3473 MediaSessionOptions options;
3474 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3475
3476 cricket::OpaqueTransportParameters audio_params;
3477 audio_params.protocol = "audio-transport";
3478 audio_params.parameters = "audio-params";
3479 FindFirstMediaDescriptionByMid("audio", &options)
3480 ->transport_options.opaque_parameters = audio_params;
3481
3482 cricket::OpaqueTransportParameters video_params;
3483 video_params.protocol = "video-transport";
3484 video_params.parameters = "video-params";
3485 FindFirstMediaDescriptionByMid("video", &options)
3486 ->transport_options.opaque_parameters = video_params;
3487
3488 TestTransportInfo(/*offer=*/false, options, /*has_current_desc=*/false);
3489}
3490
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -07003491TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolAddedToOffer) {
3492 MediaSessionOptions options;
3493 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3494 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3495 &options);
3496
3497 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3498 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3499 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3500
3501 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3502
3503 EXPECT_EQ(offer->GetContentDescriptionByName("audio")->alt_protocol(), "foo");
3504 EXPECT_EQ(offer->GetContentDescriptionByName("video")->alt_protocol(), "bar");
3505 EXPECT_EQ(offer->GetContentDescriptionByName("data")->alt_protocol(), "baz");
3506}
3507
3508TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolAddedToAnswer) {
3509 MediaSessionOptions options;
3510 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3511 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3512 &options);
3513
3514 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3515 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3516 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3517
3518 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3519 std::unique_ptr<SessionDescription> answer =
3520 f1_.CreateAnswer(offer.get(), options, nullptr);
3521
3522 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3523 "foo");
3524 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3525 "bar");
3526 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(), "baz");
3527}
3528
3529TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolNotInOffer) {
3530 MediaSessionOptions options;
3531 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3532 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3533 &options);
3534
3535 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3536
3537 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3538 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3539 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3540
3541 std::unique_ptr<SessionDescription> answer =
3542 f1_.CreateAnswer(offer.get(), options, nullptr);
3543
3544 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3545 absl::nullopt);
3546 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3547 absl::nullopt);
3548 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(),
3549 absl::nullopt);
3550}
3551
3552TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolDifferentInOffer) {
3553 MediaSessionOptions options;
3554 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3555 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3556 &options);
3557
3558 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "not-foo";
3559 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "not-bar";
3560 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "not-baz";
3561
3562 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3563
3564 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3565 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3566 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3567
3568 std::unique_ptr<SessionDescription> answer =
3569 f1_.CreateAnswer(offer.get(), options, nullptr);
3570
3571 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3572 absl::nullopt);
3573 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3574 absl::nullopt);
3575 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(),
3576 absl::nullopt);
3577}
3578
3579TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolNotInAnswer) {
3580 MediaSessionOptions options;
3581 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3582 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3583 &options);
3584
3585 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3586 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3587 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3588
3589 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3590
3591 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol =
3592 absl::nullopt;
3593 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol =
3594 absl::nullopt;
3595 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol =
3596 absl::nullopt;
3597
3598 std::unique_ptr<SessionDescription> answer =
3599 f1_.CreateAnswer(offer.get(), options, nullptr);
3600
3601 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3602 absl::nullopt);
3603 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3604 absl::nullopt);
3605 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(),
3606 absl::nullopt);
3607}
3608
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003609// Create an offer with bundle enabled and verify the crypto parameters are
3610// the common set of the available cryptos.
3611TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
3612 TestCryptoWithBundle(true);
3613}
3614
3615// Create an answer with bundle enabled and verify the crypto parameters are
3616// the common set of the available cryptos.
3617TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
3618 TestCryptoWithBundle(false);
3619}
3620
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003621// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
3622// DTLS is not enabled locally.
3623TEST_F(MediaSessionDescriptionFactoryTest,
3624 TestOfferDtlsSavpfWithoutDtlsFailed) {
3625 f1_.set_secure(SEC_ENABLED);
3626 f2_.set_secure(SEC_ENABLED);
3627 tdf1_.set_secure(SEC_DISABLED);
3628 tdf2_.set_secure(SEC_DISABLED);
3629
Steve Anton6fe1fba2018-12-11 10:15:23 -08003630 std::unique_ptr<SessionDescription> offer =
3631 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003632 ASSERT_TRUE(offer.get() != NULL);
3633 ContentInfo* offer_content = offer->GetContentByName("audio");
3634 ASSERT_TRUE(offer_content != NULL);
3635 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003636 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003637 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3638
Steve Anton6fe1fba2018-12-11 10:15:23 -08003639 std::unique_ptr<SessionDescription> answer =
3640 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003641 ASSERT_TRUE(answer != NULL);
3642 ContentInfo* answer_content = answer->GetContentByName("audio");
3643 ASSERT_TRUE(answer_content != NULL);
3644
3645 ASSERT_TRUE(answer_content->rejected);
3646}
3647
3648// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
3649// UDP/TLS/RTP/SAVPF.
3650TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
3651 f1_.set_secure(SEC_ENABLED);
3652 f2_.set_secure(SEC_ENABLED);
3653 tdf1_.set_secure(SEC_ENABLED);
3654 tdf2_.set_secure(SEC_ENABLED);
3655
Steve Anton6fe1fba2018-12-11 10:15:23 -08003656 std::unique_ptr<SessionDescription> offer =
3657 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003658 ASSERT_TRUE(offer.get() != NULL);
3659 ContentInfo* offer_content = offer->GetContentByName("audio");
3660 ASSERT_TRUE(offer_content != NULL);
3661 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003662 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003663 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3664
Steve Anton6fe1fba2018-12-11 10:15:23 -08003665 std::unique_ptr<SessionDescription> answer =
3666 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003667 ASSERT_TRUE(answer != NULL);
3668
3669 const ContentInfo* answer_content = answer->GetContentByName("audio");
3670 ASSERT_TRUE(answer_content != NULL);
3671 ASSERT_FALSE(answer_content->rejected);
3672
3673 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003674 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08003675 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003676}
3677
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003678// Test that we include both SDES and DTLS in the offer, but only include SDES
3679// in the answer if DTLS isn't negotiated.
3680TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
3681 f1_.set_secure(SEC_ENABLED);
3682 f2_.set_secure(SEC_ENABLED);
3683 tdf1_.set_secure(SEC_ENABLED);
3684 tdf2_.set_secure(SEC_DISABLED);
3685 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003686 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08003687 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003688 const cricket::MediaContentDescription* audio_media_desc;
3689 const cricket::MediaContentDescription* video_media_desc;
3690 const cricket::TransportDescription* audio_trans_desc;
3691 const cricket::TransportDescription* video_trans_desc;
3692
3693 // Generate an offer with SDES and DTLS support.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003694 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003695 ASSERT_TRUE(offer.get() != NULL);
3696
Steve Antonb1c1de12017-12-21 15:14:30 -08003697 audio_media_desc = offer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003698 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003699 video_media_desc = offer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003700 ASSERT_TRUE(video_media_desc != NULL);
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07003701 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003702 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3703
3704 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3705 ASSERT_TRUE(audio_trans_desc != NULL);
3706 video_trans_desc = offer->GetTransportDescriptionByName("video");
3707 ASSERT_TRUE(video_trans_desc != NULL);
3708 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3709 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3710
3711 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003712 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003713 ASSERT_TRUE(answer.get() != NULL);
3714
Steve Antonb1c1de12017-12-21 15:14:30 -08003715 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003716 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003717 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003718 ASSERT_TRUE(video_media_desc != NULL);
3719 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3720 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3721
3722 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3723 ASSERT_TRUE(audio_trans_desc != NULL);
3724 video_trans_desc = answer->GetTransportDescriptionByName("video");
3725 ASSERT_TRUE(video_trans_desc != NULL);
3726 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
3727 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
3728
3729 // Enable DTLS; the answer should now only have DTLS support.
3730 tdf2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003731 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003732 ASSERT_TRUE(answer.get() != NULL);
3733
Steve Antonb1c1de12017-12-21 15:14:30 -08003734 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003735 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003736 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003737 ASSERT_TRUE(video_media_desc != NULL);
3738 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3739 EXPECT_TRUE(video_media_desc->cryptos().empty());
Steve Antone38a5a12018-11-21 16:05:15 -08003740 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
3741 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003742
3743 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3744 ASSERT_TRUE(audio_trans_desc != NULL);
3745 video_trans_desc = answer->GetTransportDescriptionByName("video");
3746 ASSERT_TRUE(video_trans_desc != NULL);
3747 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3748 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003749
3750 // Try creating offer again. DTLS enabled now, crypto's should be empty
3751 // in new offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003752 offer = f1_.CreateOffer(options, offer.get());
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003753 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003754 audio_media_desc = offer->GetContentDescriptionByName("audio");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003755 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003756 video_media_desc = offer->GetContentDescriptionByName("video");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003757 ASSERT_TRUE(video_media_desc != NULL);
3758 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3759 EXPECT_TRUE(video_media_desc->cryptos().empty());
3760
3761 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3762 ASSERT_TRUE(audio_trans_desc != NULL);
3763 video_trans_desc = offer->GetTransportDescriptionByName("video");
3764 ASSERT_TRUE(video_trans_desc != NULL);
3765 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3766 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003767}
3768
3769// Test that an answer can't be created if cryptos are required but the offer is
3770// unsecure.
3771TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003772 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003773 f1_.set_secure(SEC_DISABLED);
3774 tdf1_.set_secure(SEC_DISABLED);
3775 f2_.set_secure(SEC_REQUIRED);
3776 tdf1_.set_secure(SEC_ENABLED);
3777
Steve Anton6fe1fba2018-12-11 10:15:23 -08003778 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003779 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003780 std::unique_ptr<SessionDescription> answer =
3781 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003782 EXPECT_TRUE(answer.get() == NULL);
3783}
3784
3785// Test that we accept a DTLS offer without SDES and create an appropriate
3786// answer.
3787TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
3788 f1_.set_secure(SEC_DISABLED);
3789 f2_.set_secure(SEC_ENABLED);
3790 tdf1_.set_secure(SEC_ENABLED);
3791 tdf2_.set_secure(SEC_ENABLED);
3792 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003793 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3794 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3795 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003796
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003797 // Generate an offer with DTLS but without SDES.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003798 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003799 ASSERT_TRUE(offer.get() != NULL);
3800
3801 const AudioContentDescription* audio_offer =
3802 GetFirstAudioContentDescription(offer.get());
3803 ASSERT_TRUE(audio_offer->cryptos().empty());
3804 const VideoContentDescription* video_offer =
3805 GetFirstVideoContentDescription(offer.get());
3806 ASSERT_TRUE(video_offer->cryptos().empty());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02003807 const RtpDataContentDescription* data_offer =
3808 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003809 ASSERT_TRUE(data_offer->cryptos().empty());
3810
3811 const cricket::TransportDescription* audio_offer_trans_desc =
3812 offer->GetTransportDescriptionByName("audio");
3813 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
3814 const cricket::TransportDescription* video_offer_trans_desc =
3815 offer->GetTransportDescriptionByName("video");
3816 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
3817 const cricket::TransportDescription* data_offer_trans_desc =
3818 offer->GetTransportDescriptionByName("data");
3819 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
3820
3821 // Generate an answer with DTLS.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003822 std::unique_ptr<SessionDescription> answer =
3823 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003824 ASSERT_TRUE(answer.get() != NULL);
3825
3826 const cricket::TransportDescription* audio_answer_trans_desc =
3827 answer->GetTransportDescriptionByName("audio");
3828 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3829 const cricket::TransportDescription* video_answer_trans_desc =
3830 answer->GetTransportDescriptionByName("video");
3831 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
3832 const cricket::TransportDescription* data_answer_trans_desc =
3833 answer->GetTransportDescriptionByName("data");
3834 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
3835}
3836
3837// Verifies if vad_enabled option is set to false, CN codecs are not present in
3838// offer or answer.
3839TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3840 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003841 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003842 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003843 ASSERT_TRUE(offer.get() != NULL);
3844 const ContentInfo* audio_content = offer->GetContentByName("audio");
3845 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
3846
3847 options.vad_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08003848 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003849 ASSERT_TRUE(offer.get() != NULL);
3850 audio_content = offer->GetContentByName("audio");
3851 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
Steve Anton6fe1fba2018-12-11 10:15:23 -08003852 std::unique_ptr<SessionDescription> answer =
3853 f1_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003854 ASSERT_TRUE(answer.get() != NULL);
3855 audio_content = answer->GetContentByName("audio");
3856 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
3857}
deadbeef44f08192015-12-15 16:20:09 -08003858
zhihuang1c378ed2017-08-17 14:10:50 -07003859// Test that the generated MIDs match the existing offer.
3860TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08003861 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003862 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_modified",
3863 RtpTransceiverDirection::kRecvOnly, kActive,
3864 &opts);
3865 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_modified",
3866 RtpTransceiverDirection::kRecvOnly, kActive,
3867 &opts);
deadbeef44f08192015-12-15 16:20:09 -08003868 opts.data_channel_type = cricket::DCT_SCTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003869 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data_modified",
3870 RtpTransceiverDirection::kSendRecv, kActive,
3871 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003872 // Create offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003873 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
kwiberg31022942016-03-11 14:18:21 -08003874 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08003875 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003876
deadbeef44f08192015-12-15 16:20:09 -08003877 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3878 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3879 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3880 ASSERT_TRUE(audio_content != nullptr);
3881 ASSERT_TRUE(video_content != nullptr);
3882 ASSERT_TRUE(data_content != nullptr);
3883 EXPECT_EQ("audio_modified", audio_content->name);
3884 EXPECT_EQ("video_modified", video_content->name);
3885 EXPECT_EQ("data_modified", data_content->name);
3886}
zhihuangcf5b37c2016-05-05 11:44:35 -07003887
zhihuang1c378ed2017-08-17 14:10:50 -07003888// The following tests verify that the unified plan SDP is supported.
3889// Test that we can create an offer with multiple media sections of same media
3890// type.
3891TEST_F(MediaSessionDescriptionFactoryTest,
3892 CreateOfferWithMultipleAVMediaSections) {
3893 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003894 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3895 RtpTransceiverDirection::kSendRecv, kActive,
3896 &opts);
3897 AttachSenderToMediaDescriptionOptions(
3898 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003899
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003900 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3901 RtpTransceiverDirection::kSendRecv, kActive,
3902 &opts);
3903 AttachSenderToMediaDescriptionOptions(
3904 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003905
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003906 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3907 RtpTransceiverDirection::kSendRecv, kActive,
3908 &opts);
3909 AttachSenderToMediaDescriptionOptions(
3910 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003911
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003912 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3913 RtpTransceiverDirection::kSendRecv, kActive,
3914 &opts);
3915 AttachSenderToMediaDescriptionOptions(
3916 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003917 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003918 ASSERT_TRUE(offer);
3919
3920 ASSERT_EQ(4u, offer->contents().size());
3921 EXPECT_FALSE(offer->contents()[0].rejected);
3922 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003923 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003924 ASSERT_EQ(1u, acd->streams().size());
3925 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003926 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003927
3928 EXPECT_FALSE(offer->contents()[1].rejected);
3929 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003930 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003931 ASSERT_EQ(1u, vcd->streams().size());
3932 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003933 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003934
3935 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003936 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003937 ASSERT_EQ(1u, acd->streams().size());
3938 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003939 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003940
3941 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003942 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003943 ASSERT_EQ(1u, vcd->streams().size());
3944 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003945 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003946}
3947
3948// Test that we can create an answer with multiple media sections of same media
3949// type.
3950TEST_F(MediaSessionDescriptionFactoryTest,
3951 CreateAnswerWithMultipleAVMediaSections) {
3952 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003953 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3954 RtpTransceiverDirection::kSendRecv, kActive,
3955 &opts);
3956 AttachSenderToMediaDescriptionOptions(
3957 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003958
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003959 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3960 RtpTransceiverDirection::kSendRecv, kActive,
3961 &opts);
3962 AttachSenderToMediaDescriptionOptions(
3963 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003964
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003965 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3966 RtpTransceiverDirection::kSendRecv, kActive,
3967 &opts);
3968 AttachSenderToMediaDescriptionOptions(
3969 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003970
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003971 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3972 RtpTransceiverDirection::kSendRecv, kActive,
3973 &opts);
3974 AttachSenderToMediaDescriptionOptions(
3975 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003976
Steve Anton6fe1fba2018-12-11 10:15:23 -08003977 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003978 ASSERT_TRUE(offer);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003979 std::unique_ptr<SessionDescription> answer =
3980 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003981
3982 ASSERT_EQ(4u, answer->contents().size());
3983 EXPECT_FALSE(answer->contents()[0].rejected);
3984 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003985 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003986 ASSERT_EQ(1u, acd->streams().size());
3987 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003988 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003989
3990 EXPECT_FALSE(answer->contents()[1].rejected);
3991 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003992 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003993 ASSERT_EQ(1u, vcd->streams().size());
3994 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003995 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003996
3997 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003998 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003999 ASSERT_EQ(1u, acd->streams().size());
4000 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004001 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004002
4003 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004004 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004005 ASSERT_EQ(1u, vcd->streams().size());
4006 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004007 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004008}
4009
4010// Test that the media section will be rejected in offer if the corresponding
4011// MediaDescriptionOptions is stopped by the offerer.
4012TEST_F(MediaSessionDescriptionFactoryTest,
4013 CreateOfferWithMediaSectionStoppedByOfferer) {
4014 // Create an offer with two audio sections and one of them is stopped.
4015 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004016 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4017 RtpTransceiverDirection::kSendRecv, kActive,
4018 &offer_opts);
4019 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4020 RtpTransceiverDirection::kInactive, kStopped,
4021 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004022 std::unique_ptr<SessionDescription> offer =
4023 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004024 ASSERT_TRUE(offer);
4025 ASSERT_EQ(2u, offer->contents().size());
4026 EXPECT_FALSE(offer->contents()[0].rejected);
4027 EXPECT_TRUE(offer->contents()[1].rejected);
4028}
4029
4030// Test that the media section will be rejected in answer if the corresponding
4031// MediaDescriptionOptions is stopped by the offerer.
4032TEST_F(MediaSessionDescriptionFactoryTest,
4033 CreateAnswerWithMediaSectionStoppedByOfferer) {
4034 // Create an offer with two audio sections and one of them is stopped.
4035 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004036 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4037 RtpTransceiverDirection::kSendRecv, kActive,
4038 &offer_opts);
4039 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4040 RtpTransceiverDirection::kInactive, kStopped,
4041 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004042 std::unique_ptr<SessionDescription> offer =
4043 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004044 ASSERT_TRUE(offer);
4045 ASSERT_EQ(2u, offer->contents().size());
4046 EXPECT_FALSE(offer->contents()[0].rejected);
4047 EXPECT_TRUE(offer->contents()[1].rejected);
4048
4049 // Create an answer based on the offer.
4050 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004051 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4052 RtpTransceiverDirection::kSendRecv, kActive,
4053 &answer_opts);
4054 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4055 RtpTransceiverDirection::kSendRecv, kActive,
4056 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004057 std::unique_ptr<SessionDescription> answer =
4058 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004059 ASSERT_EQ(2u, answer->contents().size());
4060 EXPECT_FALSE(answer->contents()[0].rejected);
4061 EXPECT_TRUE(answer->contents()[1].rejected);
4062}
4063
4064// Test that the media section will be rejected in answer if the corresponding
4065// MediaDescriptionOptions is stopped by the answerer.
4066TEST_F(MediaSessionDescriptionFactoryTest,
4067 CreateAnswerWithMediaSectionRejectedByAnswerer) {
4068 // Create an offer with two audio sections.
4069 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004070 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4071 RtpTransceiverDirection::kSendRecv, kActive,
4072 &offer_opts);
4073 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4074 RtpTransceiverDirection::kSendRecv, kActive,
4075 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004076 std::unique_ptr<SessionDescription> offer =
4077 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004078 ASSERT_TRUE(offer);
4079 ASSERT_EQ(2u, offer->contents().size());
4080 ASSERT_FALSE(offer->contents()[0].rejected);
4081 ASSERT_FALSE(offer->contents()[1].rejected);
4082
4083 // The answerer rejects one of the audio sections.
4084 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004085 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4086 RtpTransceiverDirection::kSendRecv, kActive,
4087 &answer_opts);
4088 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4089 RtpTransceiverDirection::kInactive, kStopped,
4090 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004091 std::unique_ptr<SessionDescription> answer =
4092 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004093 ASSERT_EQ(2u, answer->contents().size());
4094 EXPECT_FALSE(answer->contents()[0].rejected);
4095 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08004096
4097 // The TransportInfo of the rejected m= section is expected to be added in the
4098 // answer.
4099 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07004100}
4101
4102// Test the generated media sections has the same order of the
4103// corresponding MediaDescriptionOptions.
4104TEST_F(MediaSessionDescriptionFactoryTest,
4105 CreateOfferRespectsMediaDescriptionOptionsOrder) {
4106 MediaSessionOptions opts;
4107 // This tests put video section first because normally audio comes first by
4108 // default.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004109 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4110 RtpTransceiverDirection::kSendRecv, kActive,
4111 &opts);
4112 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4113 RtpTransceiverDirection::kSendRecv, kActive,
4114 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004115 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004116
4117 ASSERT_TRUE(offer);
4118 ASSERT_EQ(2u, offer->contents().size());
4119 EXPECT_EQ("video", offer->contents()[0].name);
4120 EXPECT_EQ("audio", offer->contents()[1].name);
4121}
4122
4123// Test that different media sections using the same codec have same payload
4124// type.
4125TEST_F(MediaSessionDescriptionFactoryTest,
4126 PayloadTypesSharedByMediaSectionsOfSameType) {
4127 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004128 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4129 RtpTransceiverDirection::kSendRecv, kActive,
4130 &opts);
4131 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4132 RtpTransceiverDirection::kSendRecv, kActive,
4133 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004134 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004135 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004136 ASSERT_TRUE(offer);
4137 ASSERT_EQ(2u, offer->contents().size());
4138 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004139 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004140 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004141 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004142 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4143 ASSERT_EQ(2u, vcd1->codecs().size());
4144 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4145 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4146 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
4147 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
4148
4149 // Create answer and negotiate the codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004150 std::unique_ptr<SessionDescription> answer =
4151 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004152 ASSERT_TRUE(answer);
4153 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08004154 vcd1 = answer->contents()[0].media_description()->as_video();
4155 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004156 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4157 ASSERT_EQ(1u, vcd1->codecs().size());
4158 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4159 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4160}
4161
4162// Test that the codec preference order per media section is respected in
4163// subsequent offer.
4164TEST_F(MediaSessionDescriptionFactoryTest,
4165 CreateOfferRespectsCodecPreferenceOrder) {
4166 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004167 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4168 RtpTransceiverDirection::kSendRecv, kActive,
4169 &opts);
4170 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4171 RtpTransceiverDirection::kSendRecv, kActive,
4172 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004173 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004174 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004175 ASSERT_TRUE(offer);
4176 ASSERT_EQ(2u, offer->contents().size());
4177 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004178 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004179 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004180 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004181 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4182 EXPECT_EQ(video_codecs, vcd1->codecs());
4183 EXPECT_EQ(video_codecs, vcd2->codecs());
4184
4185 // Change the codec preference of the first video section and create a
4186 // follow-up offer.
4187 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4188 vcd1->set_codecs(video_codecs_reverse);
4189 std::unique_ptr<SessionDescription> updated_offer(
4190 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08004191 vcd1 = updated_offer->contents()[0].media_description()->as_video();
4192 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004193 // The video codec preference order should be respected.
4194 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4195 EXPECT_EQ(video_codecs, vcd2->codecs());
4196}
4197
4198// Test that the codec preference order per media section is respected in
4199// the answer.
4200TEST_F(MediaSessionDescriptionFactoryTest,
4201 CreateAnswerRespectsCodecPreferenceOrder) {
4202 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004203 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4204 RtpTransceiverDirection::kSendRecv, kActive,
4205 &opts);
4206 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4207 RtpTransceiverDirection::kSendRecv, kActive,
4208 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004209 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004210 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004211 ASSERT_TRUE(offer);
4212 ASSERT_EQ(2u, offer->contents().size());
4213 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004214 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004215 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004216 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004217 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4218 EXPECT_EQ(video_codecs, vcd1->codecs());
4219 EXPECT_EQ(video_codecs, vcd2->codecs());
4220
4221 // Change the codec preference of the first video section and create an
4222 // answer.
4223 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4224 vcd1->set_codecs(video_codecs_reverse);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004225 std::unique_ptr<SessionDescription> answer =
4226 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08004227 vcd1 = answer->contents()[0].media_description()->as_video();
4228 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004229 // The video codec preference order should be respected.
4230 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4231 EXPECT_EQ(video_codecs, vcd2->codecs());
4232}
4233
Zhi Huang6f367472017-11-22 13:20:02 -08004234// Test that when creating an answer, the codecs use local parameters instead of
4235// the remote ones.
4236TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
4237 const std::string audio_param_name = "audio_param";
4238 const std::string audio_value1 = "audio_v1";
4239 const std::string audio_value2 = "audio_v2";
4240 const std::string video_param_name = "video_param";
4241 const std::string video_value1 = "video_v1";
4242 const std::string video_value2 = "video_v2";
4243
4244 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
4245 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
4246 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
4247 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
4248
4249 // Set the parameters for codecs.
4250 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
4251 video_codecs1[0].SetParam(video_param_name, video_value1);
4252 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
4253 video_codecs2[0].SetParam(video_param_name, video_value2);
4254
4255 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
Johannes Kron184ea662020-01-29 12:43:36 +01004256 f1_.set_video_codecs(video_codecs1, video_codecs1);
Zhi Huang6f367472017-11-22 13:20:02 -08004257 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
Johannes Kron184ea662020-01-29 12:43:36 +01004258 f2_.set_video_codecs(video_codecs2, video_codecs2);
Zhi Huang6f367472017-11-22 13:20:02 -08004259
4260 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004261 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4262 RtpTransceiverDirection::kSendRecv, kActive,
4263 &opts);
4264 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4265 RtpTransceiverDirection::kSendRecv, kActive,
4266 &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08004267
Steve Anton6fe1fba2018-12-11 10:15:23 -08004268 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004269 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004270 auto offer_acd = offer->contents()[0].media_description()->as_audio();
4271 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004272 std::string value;
4273 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
4274 EXPECT_EQ(audio_value1, value);
4275 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
4276 EXPECT_EQ(video_value1, value);
4277
Steve Anton6fe1fba2018-12-11 10:15:23 -08004278 std::unique_ptr<SessionDescription> answer =
4279 f2_.CreateAnswer(offer.get(), opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004280 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004281 auto answer_acd = answer->contents()[0].media_description()->as_audio();
4282 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004283 // Use the parameters from the local codecs.
4284 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
4285 EXPECT_EQ(audio_value2, value);
4286 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
4287 EXPECT_EQ(video_value2, value);
4288}
4289
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004290// Test that matching packetization-mode is part of the criteria for matching
4291// H264 codecs (in addition to profile-level-id). Previously, this was not the
4292// case, so the first H264 codec with the same profile-level-id would match and
4293// the payload type in the answer would be incorrect.
4294// This is a regression test for bugs.webrtc.org/8808
4295TEST_F(MediaSessionDescriptionFactoryTest,
4296 H264MatchCriteriaIncludesPacketizationMode) {
4297 // Create two H264 codecs with the same profile level ID and different
4298 // packetization modes.
4299 VideoCodec h264_pm0(96, "H264");
4300 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4301 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
4302 VideoCodec h264_pm1(97, "H264");
4303 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4304 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
4305
4306 // Offerer will send both codecs, answerer should choose the one with matching
4307 // packetization mode (and not the first one it sees).
Johannes Kron184ea662020-01-29 12:43:36 +01004308 f1_.set_video_codecs({h264_pm0, h264_pm1}, {h264_pm0, h264_pm1});
4309 f2_.set_video_codecs({h264_pm1}, {h264_pm1});
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004310
4311 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004312 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4313 RtpTransceiverDirection::kSendRecv, kActive,
4314 &opts);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004315
Steve Anton6fe1fba2018-12-11 10:15:23 -08004316 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004317 ASSERT_TRUE(offer);
4318
Steve Anton6fe1fba2018-12-11 10:15:23 -08004319 std::unique_ptr<SessionDescription> answer =
4320 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004321 ASSERT_TRUE(answer);
4322
4323 // Answer should have one negotiated codec with packetization-mode=1 using the
4324 // offered payload type.
4325 ASSERT_EQ(1u, answer->contents().size());
4326 auto answer_vcd = answer->contents()[0].media_description()->as_video();
4327 ASSERT_EQ(1u, answer_vcd->codecs().size());
4328 auto answer_codec = answer_vcd->codecs()[0];
4329 EXPECT_EQ(h264_pm1.id, answer_codec.id);
4330}
4331
zhihuangcf5b37c2016-05-05 11:44:35 -07004332class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
4333 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004334 MediaProtocolTest()
4335 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -07004336 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
4337 MAKE_VECTOR(kAudioCodecs1));
Johannes Kron184ea662020-01-29 12:43:36 +01004338 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1),
4339 MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004340 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07004341 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
4342 MAKE_VECTOR(kAudioCodecs2));
Johannes Kron184ea662020-01-29 12:43:36 +01004343 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2),
4344 MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004345 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07004346 f1_.set_secure(SEC_ENABLED);
4347 f2_.set_secure(SEC_ENABLED);
4348 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004349 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004350 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004351 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004352 tdf1_.set_secure(SEC_ENABLED);
4353 tdf2_.set_secure(SEC_ENABLED);
4354 }
4355
4356 protected:
4357 MediaSessionDescriptionFactory f1_;
4358 MediaSessionDescriptionFactory f2_;
4359 TransportDescriptionFactory tdf1_;
4360 TransportDescriptionFactory tdf2_;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004361 UniqueRandomIdGenerator ssrc_generator1;
4362 UniqueRandomIdGenerator ssrc_generator2;
zhihuangcf5b37c2016-05-05 11:44:35 -07004363};
4364
4365TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
4366 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08004367 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004368 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004369 ASSERT_TRUE(offer.get() != nullptr);
4370 // Set the protocol for all the contents.
Harald Alvestrand1716d392019-06-03 20:35:45 +02004371 for (auto& content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004372 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07004373 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004374 std::unique_ptr<SessionDescription> answer =
4375 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004376 const ContentInfo* ac = answer->GetContentByName("audio");
4377 const ContentInfo* vc = answer->GetContentByName("video");
4378 ASSERT_TRUE(ac != nullptr);
4379 ASSERT_TRUE(vc != nullptr);
4380 EXPECT_FALSE(ac->rejected); // the offer is accepted
4381 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004382 const AudioContentDescription* acd = ac->media_description()->as_audio();
4383 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07004384 EXPECT_EQ(GetParam(), acd->protocol());
4385 EXPECT_EQ(GetParam(), vcd->protocol());
4386}
4387
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004388INSTANTIATE_TEST_SUITE_P(MediaProtocolPatternTest,
4389 MediaProtocolTest,
4390 ::testing::ValuesIn(kMediaProtocols));
4391INSTANTIATE_TEST_SUITE_P(MediaProtocolDtlsPatternTest,
4392 MediaProtocolTest,
4393 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07004394
4395TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
4396 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004397 UniqueRandomIdGenerator ssrc_generator;
4398 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004399 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4400 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4401
4402 // The merged list of codecs should contain any send codecs that are also
4403 // nominally in the recieve codecs list. Payload types should be picked from
4404 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
4405 // (set to 1). This equals what happens when the send codecs are used in an
4406 // offer and the receive codecs are used in the following answer.
4407 const std::vector<AudioCodec> sendrecv_codecs =
4408 MAKE_VECTOR(kAudioCodecsAnswer);
4409 const std::vector<AudioCodec> no_codecs;
4410
4411 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
4412 << "Please don't change shared test data!";
4413 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
4414 << "Please don't change shared test data!";
4415 // Alter iLBC send codec to have zero channels, to test that that is handled
4416 // properly.
4417 send_codecs[1].channels = 0;
4418
4419 // Alther iLBC receive codec to be lowercase, to test that case conversions
4420 // are handled properly.
4421 recv_codecs[2].name = "ilbc";
4422
4423 // Test proper merge
4424 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004425 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4426 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4427 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004428
4429 // Test empty send codecs list
4430 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004431 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4432 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4433 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004434
4435 // Test empty recv codecs list
4436 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004437 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4438 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4439 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004440
4441 // Test all empty codec lists
4442 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004443 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4444 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4445 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004446}
4447
4448namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07004449// Compare the two vectors of codecs ignoring the payload type.
4450template <class Codec>
4451bool CodecsMatch(const std::vector<Codec>& codecs1,
4452 const std::vector<Codec>& codecs2) {
4453 if (codecs1.size() != codecs2.size()) {
4454 return false;
4455 }
4456
4457 for (size_t i = 0; i < codecs1.size(); ++i) {
4458 if (!codecs1[i].Matches(codecs2[i])) {
4459 return false;
4460 }
4461 }
4462 return true;
4463}
4464
Steve Anton4e70a722017-11-28 14:57:10 -08004465void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07004466 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004467 UniqueRandomIdGenerator ssrc_generator;
4468 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004469 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4470 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4471 const std::vector<AudioCodec> sendrecv_codecs =
4472 MAKE_VECTOR(kAudioCodecsAnswer);
4473 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07004474
4475 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004476 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
4477 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004478
Steve Anton4e70a722017-11-28 14:57:10 -08004479 if (direction == RtpTransceiverDirection::kSendRecv ||
4480 direction == RtpTransceiverDirection::kSendOnly) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004481 AttachSenderToMediaDescriptionOptions(
4482 "audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004483 }
ossu075af922016-06-14 03:29:38 -07004484
Steve Anton6fe1fba2018-12-11 10:15:23 -08004485 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
ossu075af922016-06-14 03:29:38 -07004486 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004487 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07004488
4489 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07004490 // that the codecs put in are right. This happens when we neither want to
4491 // send nor receive audio. The checks are still in place if at some point
4492 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004493 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004494 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004495 // sendrecv and inactive should both present lists as if the channel was
4496 // to be used for sending and receiving. Inactive essentially means it
4497 // might eventually be used anything, but we don't know more at this
4498 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08004499 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004500 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08004501 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004502 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004503 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07004504 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004505 }
4506 }
4507}
4508
4509static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07004510 AudioCodec(0, "codec0", 16000, -1, 1),
4511 AudioCodec(1, "codec1", 8000, 13300, 1),
4512 AudioCodec(2, "codec2", 8000, 64000, 1),
4513 AudioCodec(3, "codec3", 8000, 64000, 1),
4514 AudioCodec(4, "codec4", 8000, 0, 2),
4515 AudioCodec(5, "codec5", 32000, 0, 1),
4516 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07004517
zhihuang1c378ed2017-08-17 14:10:50 -07004518/* The codecs groups below are chosen as per the matrix below. The objective
4519 * is to have different sets of codecs in the inputs, to get unique sets of
4520 * codecs after negotiation, depending on offer and answer communication
4521 * directions. One-way directions in the offer should either result in the
4522 * opposite direction in the answer, or an inactive answer. Regardless, the
4523 * choice of codecs should be as if the answer contained the opposite
4524 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07004525 *
4526 * | Offer | Answer | Result
4527 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
4528 * 0 | x - - | - x - | x - - - -
4529 * 1 | x x x | - x - | x - - x -
4530 * 2 | - x - | x - - | - x - - -
4531 * 3 | x x x | x - - | - x x - -
4532 * 4 | - x - | x x x | - x - - -
4533 * 5 | x - - | x x x | x - - - -
4534 * 6 | x x x | x x x | x x x x x
4535 */
4536// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004537static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
4538static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07004539// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
4540// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07004541static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
4542static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07004543// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004544static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
4545static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
4546static const int kResultSendrecv_SendCodecs[] = {3, 6};
4547static const int kResultSendrecv_RecvCodecs[] = {1, 6};
4548static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07004549
4550template <typename T, int IDXS>
4551std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
4552 std::vector<T> out;
4553 out.reserve(IDXS);
4554 for (int idx : indices)
4555 out.push_back(array[idx]);
4556
4557 return out;
4558}
4559
Steve Anton4e70a722017-11-28 14:57:10 -08004560void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
4561 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07004562 bool add_legacy_stream) {
4563 TransportDescriptionFactory offer_tdf;
4564 TransportDescriptionFactory answer_tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004565 UniqueRandomIdGenerator ssrc_generator1, ssrc_generator2;
4566 MediaSessionDescriptionFactory offer_factory(&offer_tdf, &ssrc_generator1);
4567 MediaSessionDescriptionFactory answer_factory(&answer_tdf, &ssrc_generator2);
ossu075af922016-06-14 03:29:38 -07004568 offer_factory.set_audio_codecs(
4569 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
4570 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
4571 answer_factory.set_audio_codecs(
4572 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
4573 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
4574
ossu075af922016-06-14 03:29:38 -07004575 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004576 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", offer_direction,
4577 kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004578
Steve Anton4e70a722017-11-28 14:57:10 -08004579 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004580 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4581 kAudioTrack1, {kMediaStream1}, 1,
4582 &offer_opts);
ossu075af922016-06-14 03:29:38 -07004583 }
4584
Steve Anton6fe1fba2018-12-11 10:15:23 -08004585 std::unique_ptr<SessionDescription> offer =
4586 offer_factory.CreateOffer(offer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004587 ASSERT_TRUE(offer.get() != NULL);
4588
4589 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004590 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", answer_direction,
4591 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004592
Steve Anton4e70a722017-11-28 14:57:10 -08004593 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004594 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4595 kAudioTrack1, {kMediaStream1}, 1,
4596 &answer_opts);
ossu075af922016-06-14 03:29:38 -07004597 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004598 std::unique_ptr<SessionDescription> answer =
4599 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004600 const ContentInfo* ac = answer->GetContentByName("audio");
4601
zhihuang1c378ed2017-08-17 14:10:50 -07004602 // If the factory didn't add any audio content to the answer, we cannot
4603 // check that the codecs put in are right. This happens when we neither want
4604 // to send nor receive audio. The checks are still in place if at some point
4605 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004606 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004607 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
4608 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07004609
ossu075af922016-06-14 03:29:38 -07004610 std::vector<AudioCodec> target_codecs;
4611 // For offers with sendrecv or inactive, we should never reply with more
4612 // codecs than offered, with these codec sets.
4613 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08004614 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07004615 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4616 kResultSendrecv_SendrecvCodecs);
4617 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004618 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004619 target_codecs =
4620 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004621 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004622 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004623 target_codecs =
4624 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07004625 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004626 case RtpTransceiverDirection::kSendRecv:
4627 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004628 target_codecs =
4629 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08004630 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004631 target_codecs =
4632 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004633 } else {
4634 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4635 kResultSendrecv_SendrecvCodecs);
4636 }
4637 break;
4638 }
4639
zhihuang1c378ed2017-08-17 14:10:50 -07004640 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02004641 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07004642 bool first = true;
4643 os << "{";
4644 for (const auto& c : codecs) {
4645 os << (first ? " " : ", ") << c.id;
4646 first = false;
4647 }
4648 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02004649 return os.Release();
ossu075af922016-06-14 03:29:38 -07004650 };
4651
4652 EXPECT_TRUE(acd->codecs() == target_codecs)
4653 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08004654 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
4655 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07004656 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08004657 << webrtc::RtpTransceiverDirectionToString(answer_direction)
4658 << "; got: "
4659 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07004660 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08004661 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07004662 << "Only inactive offers are allowed to not generate any audio "
4663 "content";
ossu075af922016-06-14 03:29:38 -07004664 }
4665}
brandtr03d5fb12016-11-22 03:37:59 -08004666
4667} // namespace
ossu075af922016-06-14 03:29:38 -07004668
4669class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08004670 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07004671
4672TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004673 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07004674}
4675
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004676INSTANTIATE_TEST_SUITE_P(MediaSessionDescriptionFactoryTest,
4677 AudioCodecsOfferTest,
4678 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4679 RtpTransceiverDirection::kRecvOnly,
4680 RtpTransceiverDirection::kSendRecv,
4681 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07004682
4683class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08004684 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
4685 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07004686 bool>> {};
ossu075af922016-06-14 03:29:38 -07004687
4688TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08004689 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
4690 ::testing::get<1>(GetParam()),
4691 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07004692}
4693
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004694INSTANTIATE_TEST_SUITE_P(
zhihuang1c378ed2017-08-17 14:10:50 -07004695 MediaSessionDescriptionFactoryTest,
4696 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004697 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
4698 RtpTransceiverDirection::kRecvOnly,
4699 RtpTransceiverDirection::kSendRecv,
4700 RtpTransceiverDirection::kInactive),
4701 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4702 RtpTransceiverDirection::kRecvOnly,
4703 RtpTransceiverDirection::kSendRecv,
4704 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07004705 ::testing::Bool()));