blob: e3778d696441dfc1034499e7540951c11db7e4c0 [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));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000418 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200419 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700420 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
421 MAKE_VECTOR(kAudioCodecs2));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000422 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200423 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200424 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700425 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200426 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700427 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000428 }
429
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000430 // Create a video StreamParamsVec object with:
431 // - one video stream with 3 simulcast streams and FEC,
432 StreamParamsVec CreateComplexVideoStreamParamsVec() {
433 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
434 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
435 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
436 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
437
438 std::vector<SsrcGroup> ssrc_groups;
439 ssrc_groups.push_back(sim_group);
440 ssrc_groups.push_back(fec_group1);
441 ssrc_groups.push_back(fec_group2);
442 ssrc_groups.push_back(fec_group3);
443
444 StreamParams simulcast_params;
445 simulcast_params.id = kVideoTrack1;
446 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
447 simulcast_params.ssrc_groups = ssrc_groups;
448 simulcast_params.cname = "Video_SIM_FEC";
Seth Hampson845e8782018-03-02 11:34:10 -0800449 simulcast_params.set_stream_ids({kMediaStream1});
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000450
451 StreamParamsVec video_streams;
452 video_streams.push_back(simulcast_params);
453
454 return video_streams;
455 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000456
457 bool CompareCryptoParams(const CryptoParamsVec& c1,
458 const CryptoParamsVec& c2) {
459 if (c1.size() != c2.size())
460 return false;
461 for (size_t i = 0; i < c1.size(); ++i)
462 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
463 c1[i].key_params != c2[i].key_params ||
464 c1[i].session_params != c2[i].session_params)
465 return false;
466 return true;
467 }
468
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700469 // Returns true if the transport info contains "renomination" as an
470 // ICE option.
471 bool GetIceRenomination(const TransportInfo* transport_info) {
Steve Anton64b626b2019-01-28 17:25:26 -0800472 return absl::c_linear_search(transport_info->description.transport_options,
473 "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700474 }
475
zhihuang1c378ed2017-08-17 14:10:50 -0700476 void TestTransportInfo(bool offer,
Steve Anton36b29d12017-10-30 09:57:42 -0700477 const MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000478 bool has_current_desc) {
479 const std::string current_audio_ufrag = "current_audio_ufrag";
480 const std::string current_audio_pwd = "current_audio_pwd";
481 const std::string current_video_ufrag = "current_video_ufrag";
482 const std::string current_video_pwd = "current_video_pwd";
483 const std::string current_data_ufrag = "current_data_ufrag";
484 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800485 std::unique_ptr<SessionDescription> current_desc;
486 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000487 if (has_current_desc) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200488 current_desc = std::make_unique<SessionDescription>();
Steve Anton06817cd2018-12-18 15:55:30 -0800489 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200490 "audio",
Steve Anton06817cd2018-12-18 15:55:30 -0800491 TransportDescription(current_audio_ufrag, current_audio_pwd)));
492 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200493 "video",
Steve Anton06817cd2018-12-18 15:55:30 -0800494 TransportDescription(current_video_ufrag, current_video_pwd)));
495 current_desc->AddTransportInfo(TransportInfo(
496 "data", TransportDescription(current_data_ufrag, current_data_pwd)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000497 }
498 if (offer) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800499 desc = f1_.CreateOffer(options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000500 } else {
kwiberg31022942016-03-11 14:18:21 -0800501 std::unique_ptr<SessionDescription> offer;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800502 offer = f1_.CreateOffer(options, NULL);
503 desc = f1_.CreateAnswer(offer.get(), options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000504 }
505 ASSERT_TRUE(desc.get() != NULL);
506 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000507 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000508 EXPECT_TRUE(ti_audio != NULL);
509 if (has_current_desc) {
510 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
511 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
512 } else {
513 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
514 ti_audio->description.ice_ufrag.size());
515 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
516 ti_audio->description.ice_pwd.size());
517 }
zhihuang1c378ed2017-08-17 14:10:50 -0700518 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700519 FindFirstMediaDescriptionByMid("audio", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700520 EXPECT_EQ(
521 media_desc_options_it->transport_options.enable_ice_renomination,
522 GetIceRenomination(ti_audio));
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700523 EXPECT_EQ(media_desc_options_it->transport_options.opaque_parameters,
524 ti_audio->description.opaque_parameters);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000525
526 } else {
527 EXPECT_TRUE(ti_audio == NULL);
528 }
529 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000530 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000531 EXPECT_TRUE(ti_video != NULL);
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700532 auto media_desc_options_it =
533 FindFirstMediaDescriptionByMid("video", options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000534 if (options.bundle_enabled) {
535 EXPECT_EQ(ti_audio->description.ice_ufrag,
536 ti_video->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200537 EXPECT_EQ(ti_audio->description.ice_pwd, ti_video->description.ice_pwd);
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700538 EXPECT_EQ(ti_audio->description.opaque_parameters,
539 ti_video->description.opaque_parameters);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000540 } else {
541 if (has_current_desc) {
542 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
543 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
544 } else {
545 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
546 ti_video->description.ice_ufrag.size());
547 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
548 ti_video->description.ice_pwd.size());
549 }
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700550 EXPECT_EQ(media_desc_options_it->transport_options.opaque_parameters,
551 ti_video->description.opaque_parameters);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000552 }
zhihuang1c378ed2017-08-17 14:10:50 -0700553 EXPECT_EQ(
554 media_desc_options_it->transport_options.enable_ice_renomination,
555 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000556 } else {
557 EXPECT_TRUE(ti_video == NULL);
558 }
559 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
560 if (options.has_data()) {
561 EXPECT_TRUE(ti_data != NULL);
562 if (options.bundle_enabled) {
563 EXPECT_EQ(ti_audio->description.ice_ufrag,
564 ti_data->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200565 EXPECT_EQ(ti_audio->description.ice_pwd, ti_data->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000566 } else {
567 if (has_current_desc) {
568 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
569 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
570 } else {
571 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
572 ti_data->description.ice_ufrag.size());
573 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
574 ti_data->description.ice_pwd.size());
575 }
576 }
zhihuang1c378ed2017-08-17 14:10:50 -0700577 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700578 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700579 EXPECT_EQ(
580 media_desc_options_it->transport_options.enable_ice_renomination,
581 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700582
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000583 } else {
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -0700584 EXPECT_TRUE(ti_data == NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000585 }
586 }
587
588 void TestCryptoWithBundle(bool offer) {
589 f1_.set_secure(SEC_ENABLED);
590 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -0800591 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
592 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
593 &options);
kwiberg31022942016-03-11 14:18:21 -0800594 std::unique_ptr<SessionDescription> ref_desc;
595 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000596 if (offer) {
597 options.bundle_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800598 ref_desc = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000599 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800600 desc = f1_.CreateOffer(options, ref_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000601 } else {
602 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800603 ref_desc = f1_.CreateOffer(options, NULL);
604 desc = f1_.CreateAnswer(ref_desc.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000605 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800606 ASSERT_TRUE(desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000607 const cricket::MediaContentDescription* audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800608 desc->GetContentDescriptionByName("audio");
609 ASSERT_TRUE(audio_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000610 const cricket::MediaContentDescription* video_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800611 desc->GetContentDescriptionByName("video");
612 ASSERT_TRUE(video_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000613 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
614 video_media_desc->cryptos()));
615 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
Steve Antone38a5a12018-11-21 16:05:15 -0800616 EXPECT_EQ(kDefaultSrtpCryptoSuite,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000617 audio_media_desc->cryptos()[0].cipher_suite);
618
619 // Verify the selected crypto is one from the reference audio
620 // media content.
621 const cricket::MediaContentDescription* ref_audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800622 ref_desc->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000623 bool found = false;
624 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
625 if (ref_audio_media_desc->cryptos()[i].Matches(
Yves Gerey665174f2018-06-19 15:03:05 +0200626 audio_media_desc->cryptos()[0])) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000627 found = true;
628 break;
629 }
630 }
631 EXPECT_TRUE(found);
632 }
633
634 // This test that the audio and video media direction is set to
635 // |expected_direction_in_answer| in an answer if the offer direction is set
zhihuang1c378ed2017-08-17 14:10:50 -0700636 // to |direction_in_offer| and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000637 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800638 RtpTransceiverDirection direction_in_offer,
639 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700640 MediaSessionOptions offer_opts;
641 AddAudioVideoSections(direction_in_offer, &offer_opts);
642
Steve Anton6fe1fba2018-12-11 10:15:23 -0800643 std::unique_ptr<SessionDescription> offer =
644 f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000645 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700646 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000647 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700648 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000649 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000650
zhihuang1c378ed2017-08-17 14:10:50 -0700651 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800652 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800653 std::unique_ptr<SessionDescription> answer =
654 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000655 const AudioContentDescription* acd_answer =
656 GetFirstAudioContentDescription(answer.get());
657 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
658 const VideoContentDescription* vcd_answer =
659 GetFirstVideoContentDescription(answer.get());
660 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
661 }
662
663 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800664 RTC_DCHECK(content);
665 RTC_CHECK(content->media_description());
666 const cricket::AudioContentDescription* audio_desc =
667 content->media_description()->as_audio();
668 RTC_CHECK(audio_desc);
669 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
670 if (codec.name == "CN") {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000671 return false;
Steve Antonb1c1de12017-12-21 15:14:30 -0800672 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000673 }
674 return true;
675 }
676
jbauchcb560652016-08-04 05:20:32 -0700677 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
678 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800679 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700680 offer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_offer;
zhihuang1c378ed2017-08-17 14:10:50 -0700681
jbauchcb560652016-08-04 05:20:32 -0700682 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800683 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700684 answer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_answer;
zhihuang1c378ed2017-08-17 14:10:50 -0700685
jbauchcb560652016-08-04 05:20:32 -0700686 f1_.set_secure(SEC_ENABLED);
687 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800688 std::unique_ptr<SessionDescription> offer =
689 f1_.CreateOffer(offer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700690 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800691 std::unique_ptr<SessionDescription> answer =
692 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700693 const ContentInfo* ac = answer->GetContentByName("audio");
694 const ContentInfo* vc = answer->GetContentByName("video");
695 ASSERT_TRUE(ac != NULL);
696 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800697 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
698 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800699 const AudioContentDescription* acd = ac->media_description()->as_audio();
700 const VideoContentDescription* vcd = vc->media_description()->as_video();
jbauchcb560652016-08-04 05:20:32 -0700701 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800702 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -0700703 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700704 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700705 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
706 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700707 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700708 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700709 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700710 }
711 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800712 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +0200713 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
714 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
jbauchcb560652016-08-04 05:20:32 -0700715 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700716 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700717 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700718 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700719 }
Steve Antone38a5a12018-11-21 16:05:15 -0800720 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
jbauchcb560652016-08-04 05:20:32 -0700721 }
722
Johannes Kronce8e8672019-02-22 13:06:44 +0100723 void TestTransportSequenceNumberNegotiation(
724 const cricket::RtpHeaderExtensions& local,
725 const cricket::RtpHeaderExtensions& offered,
726 const cricket::RtpHeaderExtensions& expectedAnswer) {
727 MediaSessionOptions opts;
728 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
729 f1_.set_audio_rtp_header_extensions(offered);
730 f1_.set_video_rtp_header_extensions(offered);
731 f2_.set_audio_rtp_header_extensions(local);
732 f2_.set_video_rtp_header_extensions(local);
733
734 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
735 ASSERT_TRUE(offer.get() != NULL);
736 std::unique_ptr<SessionDescription> answer =
737 f2_.CreateAnswer(offer.get(), opts, NULL);
738
739 EXPECT_EQ(
740 expectedAnswer,
741 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
742 EXPECT_EQ(
743 expectedAnswer,
744 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
745 }
746
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000747 protected:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800748 UniqueRandomIdGenerator ssrc_generator1;
749 UniqueRandomIdGenerator ssrc_generator2;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000750 MediaSessionDescriptionFactory f1_;
751 MediaSessionDescriptionFactory f2_;
752 TransportDescriptionFactory tdf1_;
753 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000754};
755
756// Create a typical audio offer, and ensure it matches what we expect.
757TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
758 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800759 std::unique_ptr<SessionDescription> offer =
760 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000761 ASSERT_TRUE(offer.get() != NULL);
762 const ContentInfo* ac = offer->GetContentByName("audio");
763 const ContentInfo* vc = offer->GetContentByName("video");
764 ASSERT_TRUE(ac != NULL);
765 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800766 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800767 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000768 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700769 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700770 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000771 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
772 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700773 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800774 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000775}
776
777// Create a typical video offer, and ensure it matches what we expect.
778TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
779 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800780 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000781 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800782 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000783 ASSERT_TRUE(offer.get() != NULL);
784 const ContentInfo* ac = offer->GetContentByName("audio");
785 const ContentInfo* vc = offer->GetContentByName("video");
786 ASSERT_TRUE(ac != NULL);
787 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800788 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
789 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800790 const AudioContentDescription* acd = ac->media_description()->as_audio();
791 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000792 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700793 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700794 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000795 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
796 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700797 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800798 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000799 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
800 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700801 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000802 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
803 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700804 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800805 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000806}
807
808// Test creating an offer with bundle where the Codecs have the same dynamic
809// RTP playlod type. The test verifies that the offer don't contain the
810// duplicate RTP payload types.
811TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
812 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700813 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200814 const RtpDataCodec& offered_data_codec = f2_.rtp_data_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000815 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
816 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
817
818 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800819 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
820 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000821 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800822 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000823 const VideoContentDescription* vcd =
824 GetFirstVideoContentDescription(offer.get());
825 const AudioContentDescription* acd =
826 GetFirstAudioContentDescription(offer.get());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200827 const RtpDataContentDescription* dcd =
828 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000829 ASSERT_TRUE(NULL != vcd);
830 ASSERT_TRUE(NULL != acd);
831 ASSERT_TRUE(NULL != dcd);
832 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
833 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
834 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
835 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
836 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
837 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
838}
839
zhihuang1c378ed2017-08-17 14:10:50 -0700840// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000841// after an audio only session has been negotiated.
842TEST_F(MediaSessionDescriptionFactoryTest,
843 TestCreateUpdatedVideoOfferWithBundle) {
844 f1_.set_secure(SEC_ENABLED);
845 f2_.set_secure(SEC_ENABLED);
846 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800847 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
848 RtpTransceiverDirection::kRecvOnly, kActive,
849 &opts);
850 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
851 RtpTransceiverDirection::kInactive, kStopped,
852 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000853 opts.data_channel_type = cricket::DCT_NONE;
854 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800855 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
856 std::unique_ptr<SessionDescription> answer =
857 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000858
859 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800860 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
861 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
862 &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000863 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800864 std::unique_ptr<SessionDescription> updated_offer(
865 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000866
867 const AudioContentDescription* acd =
868 GetFirstAudioContentDescription(updated_offer.get());
869 const VideoContentDescription* vcd =
870 GetFirstVideoContentDescription(updated_offer.get());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200871 const RtpDataContentDescription* dcd =
872 GetFirstRtpDataContentDescription(updated_offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000873 EXPECT_TRUE(NULL != vcd);
874 EXPECT_TRUE(NULL != acd);
875 EXPECT_TRUE(NULL != dcd);
876
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700877 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800878 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700879 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800880 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700881 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800882 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000883}
deadbeef44f08192015-12-15 16:20:09 -0800884
wu@webrtc.org78187522013-10-07 23:32:02 +0000885// Create a RTP data offer, and ensure it matches what we expect.
886TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000887 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800888 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
889 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000890 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800891 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000892 ASSERT_TRUE(offer.get() != NULL);
893 const ContentInfo* ac = offer->GetContentByName("audio");
894 const ContentInfo* dc = offer->GetContentByName("data");
895 ASSERT_TRUE(ac != NULL);
896 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800897 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
898 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800899 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200900 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000901 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700902 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700903 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000904 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
905 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700906 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800907 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000908 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200909 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700910 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000911 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +0200912 dcd->bandwidth()); // default bandwidth (auto)
913 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700914 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800915 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000916}
917
wu@webrtc.org78187522013-10-07 23:32:02 +0000918// Create an SCTP data offer with bundle without error.
919TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
920 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000921 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800922 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
wu@webrtc.org78187522013-10-07 23:32:02 +0000923 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800924 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.org78187522013-10-07 23:32:02 +0000925 EXPECT_TRUE(offer.get() != NULL);
926 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
Guido Urdanetacecf87f2019-05-31 10:17:38 +0000927 auto dcd = GetFirstSctpDataContentDescription(offer.get());
928 ASSERT_TRUE(dcd);
929 // Since this transport is insecure, the protocol should be "SCTP".
930 EXPECT_EQ(cricket::kMediaProtocolSctp, dcd->protocol());
931}
932
933// Create an SCTP data offer with bundle without error.
934TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSecureSctpDataOffer) {
935 MediaSessionOptions opts;
936 opts.bundle_enabled = true;
937 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
938 f1_.set_secure(SEC_ENABLED);
939 tdf1_.set_secure(SEC_ENABLED);
940 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
941 EXPECT_TRUE(offer.get() != NULL);
942 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
943 auto dcd = GetFirstSctpDataContentDescription(offer.get());
944 ASSERT_TRUE(dcd);
945 // The protocol should now be "UDP/DTLS/SCTP"
946 EXPECT_EQ(cricket::kMediaProtocolUdpDtlsSctp, dcd->protocol());
wu@webrtc.org78187522013-10-07 23:32:02 +0000947}
948
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000949// Test creating an sctp data channel from an already generated offer.
950TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
951 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000952 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800953 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000954 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800955 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000956 ASSERT_TRUE(offer1.get() != NULL);
957 const ContentInfo* data = offer1->GetContentByName("data");
958 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800959 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000960
961 // Now set data_channel_type to 'none' (default) and make sure that the
962 // datachannel type that gets generated from the previous offer, is of the
963 // same type.
964 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800965 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000966 f1_.CreateOffer(opts, offer1.get()));
967 data = offer2->GetContentByName("data");
968 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800969 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000970}
971
Steve Anton2bed3972019-01-04 17:04:30 -0800972// Test that if BUNDLE is enabled and all media sections are rejected then the
973// BUNDLE group is not present in the re-offer.
974TEST_F(MediaSessionDescriptionFactoryTest, ReOfferNoBundleGroupIfAllRejected) {
975 MediaSessionOptions opts;
976 opts.bundle_enabled = true;
977 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
978 RtpTransceiverDirection::kSendRecv, kActive,
979 &opts);
980 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
981
982 opts.media_description_options[0].stopped = true;
983 std::unique_ptr<SessionDescription> reoffer =
984 f1_.CreateOffer(opts, offer.get());
985
986 EXPECT_FALSE(reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
987}
988
989// Test that if BUNDLE is enabled and the remote re-offer does not include a
990// BUNDLE group since all media sections are rejected, then the re-answer also
991// does not include a BUNDLE group.
992TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerNoBundleGroupIfAllRejected) {
993 MediaSessionOptions opts;
994 opts.bundle_enabled = true;
995 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
996 RtpTransceiverDirection::kSendRecv, kActive,
997 &opts);
998 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
999 std::unique_ptr<SessionDescription> answer =
1000 f2_.CreateAnswer(offer.get(), opts, nullptr);
1001
1002 opts.media_description_options[0].stopped = true;
1003 std::unique_ptr<SessionDescription> reoffer =
1004 f1_.CreateOffer(opts, offer.get());
1005 std::unique_ptr<SessionDescription> reanswer =
1006 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1007
1008 EXPECT_FALSE(reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
1009}
1010
1011// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1012// was rejected then the new offerer-tagged media section is the non-rejected
1013// media section.
1014TEST_F(MediaSessionDescriptionFactoryTest, ReOfferChangeBundleOffererTagged) {
1015 MediaSessionOptions opts;
1016 opts.bundle_enabled = true;
1017 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1018 RtpTransceiverDirection::kSendRecv, kActive,
1019 &opts);
1020 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1021
1022 // Reject the audio m= section and add a video m= section.
1023 opts.media_description_options[0].stopped = true;
1024 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1025 RtpTransceiverDirection::kSendRecv, kActive,
1026 &opts);
1027 std::unique_ptr<SessionDescription> reoffer =
1028 f1_.CreateOffer(opts, offer.get());
1029
1030 const cricket::ContentGroup* bundle_group =
1031 reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1032 ASSERT_TRUE(bundle_group);
1033 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1034 EXPECT_TRUE(bundle_group->HasContentName("video"));
1035}
1036
1037// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1038// was rejected and a new media section is added, then the re-answer BUNDLE
1039// group will contain only the non-rejected media section.
1040TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerChangedBundleOffererTagged) {
1041 MediaSessionOptions opts;
1042 opts.bundle_enabled = true;
1043 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1044 RtpTransceiverDirection::kSendRecv, kActive,
1045 &opts);
1046 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1047 std::unique_ptr<SessionDescription> answer =
1048 f2_.CreateAnswer(offer.get(), opts, nullptr);
1049
1050 // Reject the audio m= section and add a video m= section.
1051 opts.media_description_options[0].stopped = true;
1052 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1053 RtpTransceiverDirection::kSendRecv, kActive,
1054 &opts);
1055 std::unique_ptr<SessionDescription> reoffer =
1056 f1_.CreateOffer(opts, offer.get());
1057 std::unique_ptr<SessionDescription> reanswer =
1058 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1059
1060 const cricket::ContentGroup* bundle_group =
1061 reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1062 ASSERT_TRUE(bundle_group);
1063 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1064 EXPECT_TRUE(bundle_group->HasContentName("video"));
1065}
1066
1067// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1068// and there is still a non-rejected media section that was in the initial
1069// offer, then the ICE credentials do not change in the reoffer offerer-tagged
1070// media section.
1071TEST_F(MediaSessionDescriptionFactoryTest,
1072 ReOfferChangeBundleOffererTaggedKeepsIceCredentials) {
1073 MediaSessionOptions opts;
1074 opts.bundle_enabled = true;
1075 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1076 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1077 std::unique_ptr<SessionDescription> answer =
1078 f2_.CreateAnswer(offer.get(), opts, nullptr);
1079
1080 // Reject the audio m= section.
1081 opts.media_description_options[0].stopped = true;
1082 std::unique_ptr<SessionDescription> reoffer =
1083 f1_.CreateOffer(opts, offer.get());
1084
1085 const TransportDescription* offer_tagged =
1086 offer->GetTransportDescriptionByName("audio");
1087 ASSERT_TRUE(offer_tagged);
1088 const TransportDescription* reoffer_tagged =
1089 reoffer->GetTransportDescriptionByName("video");
1090 ASSERT_TRUE(reoffer_tagged);
1091 EXPECT_EQ(offer_tagged->ice_ufrag, reoffer_tagged->ice_ufrag);
1092 EXPECT_EQ(offer_tagged->ice_pwd, reoffer_tagged->ice_pwd);
1093}
1094
1095// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1096// and there is still a non-rejected media section that was in the initial
1097// offer, then the ICE credentials do not change in the reanswer answerer-tagged
1098// media section.
1099TEST_F(MediaSessionDescriptionFactoryTest,
1100 ReAnswerChangeBundleOffererTaggedKeepsIceCredentials) {
1101 MediaSessionOptions opts;
1102 opts.bundle_enabled = true;
1103 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1104 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1105 std::unique_ptr<SessionDescription> answer =
1106 f2_.CreateAnswer(offer.get(), opts, nullptr);
1107
1108 // Reject the audio m= section.
1109 opts.media_description_options[0].stopped = true;
1110 std::unique_ptr<SessionDescription> reoffer =
1111 f1_.CreateOffer(opts, offer.get());
1112 std::unique_ptr<SessionDescription> reanswer =
1113 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1114
1115 const TransportDescription* answer_tagged =
1116 answer->GetTransportDescriptionByName("audio");
1117 ASSERT_TRUE(answer_tagged);
1118 const TransportDescription* reanswer_tagged =
1119 reanswer->GetTransportDescriptionByName("video");
1120 ASSERT_TRUE(reanswer_tagged);
1121 EXPECT_EQ(answer_tagged->ice_ufrag, reanswer_tagged->ice_ufrag);
1122 EXPECT_EQ(answer_tagged->ice_pwd, reanswer_tagged->ice_pwd);
1123}
1124
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001125// Create an audio, video offer without legacy StreamParams.
1126TEST_F(MediaSessionDescriptionFactoryTest,
1127 TestCreateOfferWithoutLegacyStreams) {
1128 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001129 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001130 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001131 ASSERT_TRUE(offer.get() != NULL);
1132 const ContentInfo* ac = offer->GetContentByName("audio");
1133 const ContentInfo* vc = offer->GetContentByName("video");
1134 ASSERT_TRUE(ac != NULL);
1135 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001136 const AudioContentDescription* acd = ac->media_description()->as_audio();
1137 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001138
Yves Gerey665174f2018-06-19 15:03:05 +02001139 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1140 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001141}
1142
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001143// Creates an audio+video sendonly offer.
1144TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001145 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001146 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001147 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1148 {kMediaStream1}, 1, &opts);
1149 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1150 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001151
Steve Anton6fe1fba2018-12-11 10:15:23 -08001152 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001153 ASSERT_TRUE(offer.get() != NULL);
1154 EXPECT_EQ(2u, offer->contents().size());
1155 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
1156 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
1157
Steve Anton4e70a722017-11-28 14:57:10 -08001158 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1159 GetMediaDirection(&offer->contents()[0]));
1160 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1161 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001162}
1163
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001164// Verifies that the order of the media contents in the current
1165// SessionDescription is preserved in the new SessionDescription.
1166TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
1167 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001168 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001169
kwiberg31022942016-03-11 14:18:21 -08001170 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001171 ASSERT_TRUE(offer1.get() != NULL);
1172 EXPECT_EQ(1u, offer1->contents().size());
1173 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
1174
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001175 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1176 RtpTransceiverDirection::kRecvOnly, kActive,
1177 &opts);
kwiberg31022942016-03-11 14:18:21 -08001178 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001179 f1_.CreateOffer(opts, offer1.get()));
1180 ASSERT_TRUE(offer2.get() != NULL);
1181 EXPECT_EQ(2u, offer2->contents().size());
1182 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
1183 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
1184
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001185 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1186 RtpTransceiverDirection::kRecvOnly, kActive,
1187 &opts);
kwiberg31022942016-03-11 14:18:21 -08001188 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001189 f1_.CreateOffer(opts, offer2.get()));
1190 ASSERT_TRUE(offer3.get() != NULL);
1191 EXPECT_EQ(3u, offer3->contents().size());
1192 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
1193 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
1194 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001195}
1196
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001197// Create a typical audio answer, and ensure it matches what we expect.
1198TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
1199 f1_.set_secure(SEC_ENABLED);
1200 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001201 std::unique_ptr<SessionDescription> offer =
1202 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001203 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001204 std::unique_ptr<SessionDescription> answer =
1205 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001206 const ContentInfo* ac = answer->GetContentByName("audio");
1207 const ContentInfo* vc = answer->GetContentByName("video");
1208 ASSERT_TRUE(ac != NULL);
1209 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001210 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001211 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001212 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001213 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001214 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001215 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1216 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001217 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001218 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001219}
1220
jbauchcb560652016-08-04 05:20:32 -07001221// Create a typical audio answer with GCM ciphers enabled, and ensure it
1222// matches what we expect.
1223TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
1224 f1_.set_secure(SEC_ENABLED);
1225 f2_.set_secure(SEC_ENABLED);
zhihuang1c378ed2017-08-17 14:10:50 -07001226 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001227 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001228 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001229 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001230 std::unique_ptr<SessionDescription> answer =
1231 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001232 const ContentInfo* ac = answer->GetContentByName("audio");
1233 const ContentInfo* vc = answer->GetContentByName("video");
1234 ASSERT_TRUE(ac != NULL);
1235 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001236 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001237 const AudioContentDescription* acd = ac->media_description()->as_audio();
jbauchcb560652016-08-04 05:20:32 -07001238 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001239 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001240 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001241 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1242 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001243 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001244 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
jbauchcb560652016-08-04 05:20:32 -07001245}
1246
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001247// Create a typical video answer, and ensure it matches what we expect.
1248TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
1249 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001250 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001251 f1_.set_secure(SEC_ENABLED);
1252 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001253 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001254 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001255 std::unique_ptr<SessionDescription> answer =
1256 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001257 const ContentInfo* ac = answer->GetContentByName("audio");
1258 const ContentInfo* vc = answer->GetContentByName("video");
1259 ASSERT_TRUE(ac != NULL);
1260 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001261 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1262 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001263 const AudioContentDescription* acd = ac->media_description()->as_audio();
1264 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001265 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001266 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001267 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001268 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001269 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001270 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001271 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001272 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +02001273 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
1274 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001275 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001276 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001277}
1278
jbauchcb560652016-08-04 05:20:32 -07001279// Create a typical video answer with GCM ciphers enabled, and ensure it
1280// matches what we expect.
1281TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1282 TestVideoGcmCipher(true, true);
1283}
1284
1285// Create a typical video answer with GCM ciphers enabled for the offer only,
1286// and ensure it matches what we expect.
1287TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1288 TestVideoGcmCipher(true, false);
1289}
1290
1291// Create a typical video answer with GCM ciphers enabled for the answer only,
1292// and ensure it matches what we expect.
1293TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1294 TestVideoGcmCipher(false, true);
1295}
1296
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001297TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001298 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001299 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001300 f1_.set_secure(SEC_ENABLED);
1301 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001302 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001303 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001304 std::unique_ptr<SessionDescription> answer =
1305 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001306 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001307 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001308 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001309 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001310 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1311 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001312 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001313 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001314 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001315 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001316 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001317 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001318 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001319 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
zstein4b2e0822017-02-17 19:48:38 -08001320 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001321 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001322 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001323 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001324 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001325 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001326}
1327
jbauchcb560652016-08-04 05:20:32 -07001328TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
zhihuang1c378ed2017-08-17 14:10:50 -07001329 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001330 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001331 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
jbauchcb560652016-08-04 05:20:32 -07001332 f1_.set_secure(SEC_ENABLED);
1333 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001334 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001335 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001336 std::unique_ptr<SessionDescription> answer =
1337 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001338 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001339 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -07001340 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001341 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001342 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1343 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001344 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001345 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
jbauchcb560652016-08-04 05:20:32 -07001346 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001347 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -07001348 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001349 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001350 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001351 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
zstein4b2e0822017-02-17 19:48:38 -08001352 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001353 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001354 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001355 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001356 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001357 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
zstein4b2e0822017-02-17 19:48:38 -08001358}
1359
Harald Alvestrandc5effc22019-06-11 11:46:59 +02001360// The use_sctpmap flag should be set in an Sctp DataContentDescription by
1361// default. The answer's use_sctpmap flag should match the offer's.
zstein4b2e0822017-02-17 19:48:38 -08001362TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1363 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001364 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001365 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001366 ASSERT_TRUE(offer.get() != NULL);
1367 ContentInfo* dc_offer = offer->GetContentByName("data");
1368 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001369 SctpDataContentDescription* dcd_offer =
1370 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001371 EXPECT_TRUE(dcd_offer->use_sctpmap());
1372
Steve Anton6fe1fba2018-12-11 10:15:23 -08001373 std::unique_ptr<SessionDescription> answer =
1374 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001375 const ContentInfo* dc_answer = answer->GetContentByName("data");
1376 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001377 const SctpDataContentDescription* dcd_answer =
1378 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001379 EXPECT_TRUE(dcd_answer->use_sctpmap());
1380}
1381
1382// The answer's use_sctpmap flag should match the offer's.
1383TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1384 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001385 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001386 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001387 ASSERT_TRUE(offer.get() != NULL);
1388 ContentInfo* dc_offer = offer->GetContentByName("data");
1389 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001390 SctpDataContentDescription* dcd_offer =
1391 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001392 dcd_offer->set_use_sctpmap(false);
1393
Steve Anton6fe1fba2018-12-11 10:15:23 -08001394 std::unique_ptr<SessionDescription> answer =
1395 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001396 const ContentInfo* dc_answer = answer->GetContentByName("data");
1397 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001398 const SctpDataContentDescription* dcd_answer =
1399 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001400 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001401}
1402
deadbeef8b7e9ad2017-05-25 09:38:55 -07001403// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1404// and "TCP/DTLS/SCTP" offers.
1405TEST_F(MediaSessionDescriptionFactoryTest,
1406 TestCreateDataAnswerToDifferentOfferedProtos) {
1407 // Need to enable DTLS offer/answer generation (disabled by default in this
1408 // test).
1409 f1_.set_secure(SEC_ENABLED);
1410 f2_.set_secure(SEC_ENABLED);
1411 tdf1_.set_secure(SEC_ENABLED);
1412 tdf2_.set_secure(SEC_ENABLED);
1413
1414 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001415 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001416 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001417 ASSERT_TRUE(offer.get() != nullptr);
1418 ContentInfo* dc_offer = offer->GetContentByName("data");
1419 ASSERT_TRUE(dc_offer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001420 SctpDataContentDescription* dcd_offer =
1421 dc_offer->media_description()->as_sctp();
1422 ASSERT_TRUE(dcd_offer);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001423
1424 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1425 "TCP/DTLS/SCTP"};
1426 for (const std::string& proto : protos) {
1427 dcd_offer->set_protocol(proto);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001428 std::unique_ptr<SessionDescription> answer =
1429 f2_.CreateAnswer(offer.get(), opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001430 const ContentInfo* dc_answer = answer->GetContentByName("data");
1431 ASSERT_TRUE(dc_answer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001432 const SctpDataContentDescription* dcd_answer =
1433 dc_answer->media_description()->as_sctp();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001434 EXPECT_FALSE(dc_answer->rejected);
1435 EXPECT_EQ(proto, dcd_answer->protocol());
1436 }
1437}
1438
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001439TEST_F(MediaSessionDescriptionFactoryTest,
1440 TestCreateDataAnswerToOfferWithDefinedMessageSize) {
1441 // Need to enable DTLS offer/answer generation (disabled by default in this
1442 // test).
1443 f1_.set_secure(SEC_ENABLED);
1444 f2_.set_secure(SEC_ENABLED);
1445 tdf1_.set_secure(SEC_ENABLED);
1446 tdf2_.set_secure(SEC_ENABLED);
1447
1448 MediaSessionOptions opts;
1449 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
1450 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1451 ASSERT_TRUE(offer.get() != nullptr);
1452 ContentInfo* dc_offer = offer->GetContentByName("data");
1453 ASSERT_TRUE(dc_offer != nullptr);
1454 SctpDataContentDescription* dcd_offer =
1455 dc_offer->media_description()->as_sctp();
1456 ASSERT_TRUE(dcd_offer);
1457 dcd_offer->set_max_message_size(1234);
1458 std::unique_ptr<SessionDescription> answer =
1459 f2_.CreateAnswer(offer.get(), opts, nullptr);
1460 const ContentInfo* dc_answer = answer->GetContentByName("data");
1461 ASSERT_TRUE(dc_answer != nullptr);
1462 const SctpDataContentDescription* dcd_answer =
1463 dc_answer->media_description()->as_sctp();
1464 EXPECT_FALSE(dc_answer->rejected);
1465 EXPECT_EQ(1234, dcd_answer->max_message_size());
1466}
1467
1468TEST_F(MediaSessionDescriptionFactoryTest,
1469 TestCreateDataAnswerToOfferWithZeroMessageSize) {
1470 // Need to enable DTLS offer/answer generation (disabled by default in this
1471 // test).
1472 f1_.set_secure(SEC_ENABLED);
1473 f2_.set_secure(SEC_ENABLED);
1474 tdf1_.set_secure(SEC_ENABLED);
1475 tdf2_.set_secure(SEC_ENABLED);
1476
1477 MediaSessionOptions opts;
1478 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
1479 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1480 ASSERT_TRUE(offer.get() != nullptr);
1481 ContentInfo* dc_offer = offer->GetContentByName("data");
1482 ASSERT_TRUE(dc_offer != nullptr);
1483 SctpDataContentDescription* dcd_offer =
1484 dc_offer->media_description()->as_sctp();
1485 ASSERT_TRUE(dcd_offer);
1486 dcd_offer->set_max_message_size(0);
1487 std::unique_ptr<SessionDescription> answer =
1488 f2_.CreateAnswer(offer.get(), opts, nullptr);
1489 const ContentInfo* dc_answer = answer->GetContentByName("data");
1490 ASSERT_TRUE(dc_answer != nullptr);
1491 const SctpDataContentDescription* dcd_answer =
1492 dc_answer->media_description()->as_sctp();
1493 EXPECT_FALSE(dc_answer->rejected);
1494 EXPECT_EQ(cricket::kSctpSendBufferSize, dcd_answer->max_message_size());
1495}
1496
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001497// Verifies that the order of the media contents in the offer is preserved in
1498// the answer.
1499TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1500 MediaSessionOptions opts;
1501
1502 // Creates a data only offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001503 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001504 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001505 ASSERT_TRUE(offer1.get() != NULL);
1506
1507 // Appends audio to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001508 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1509 RtpTransceiverDirection::kRecvOnly, kActive,
1510 &opts);
kwiberg31022942016-03-11 14:18:21 -08001511 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001512 f1_.CreateOffer(opts, offer1.get()));
1513 ASSERT_TRUE(offer2.get() != NULL);
1514
1515 // Appends video to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001516 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1517 RtpTransceiverDirection::kRecvOnly, kActive,
1518 &opts);
kwiberg31022942016-03-11 14:18:21 -08001519 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001520 f1_.CreateOffer(opts, offer2.get()));
1521 ASSERT_TRUE(offer3.get() != NULL);
1522
Steve Anton6fe1fba2018-12-11 10:15:23 -08001523 std::unique_ptr<SessionDescription> answer =
1524 f2_.CreateAnswer(offer3.get(), opts, NULL);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001525 ASSERT_TRUE(answer.get() != NULL);
1526 EXPECT_EQ(3u, answer->contents().size());
1527 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1528 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1529 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1530}
1531
ossu075af922016-06-14 03:29:38 -07001532// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1533// answerer settings.
1534
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001535// This test that the media direction is set to send/receive in an answer if
1536// the offer is send receive.
1537TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001538 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1539 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001540}
1541
1542// This test that the media direction is set to receive only in an answer if
1543// the offer is send only.
1544TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001545 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1546 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001547}
1548
1549// This test that the media direction is set to send only in an answer if
1550// the offer is recv only.
1551TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001552 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1553 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001554}
1555
1556// This test that the media direction is set to inactive in an answer if
1557// the offer is inactive.
1558TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001559 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1560 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001561}
1562
1563// Test that a data content with an unknown protocol is rejected in an answer.
1564TEST_F(MediaSessionDescriptionFactoryTest,
1565 CreateDataAnswerToOfferWithUnknownProtocol) {
1566 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001567 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001568 f1_.set_secure(SEC_ENABLED);
1569 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001570 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
terelius8c011e52016-04-26 05:28:11 -07001571 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001572 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001573 RtpDataContentDescription* dcd_offer =
1574 dc_offer->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001575 ASSERT_TRUE(dcd_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001576 // Offer must be acceptable as an RTP protocol in order to be set.
1577 std::string protocol = "RTP/a weird unknown protocol";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001578 dcd_offer->set_protocol(protocol);
1579
Steve Anton6fe1fba2018-12-11 10:15:23 -08001580 std::unique_ptr<SessionDescription> answer =
1581 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001582
1583 const ContentInfo* dc_answer = answer->GetContentByName("data");
1584 ASSERT_TRUE(dc_answer != NULL);
1585 EXPECT_TRUE(dc_answer->rejected);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001586 const RtpDataContentDescription* dcd_answer =
1587 dc_answer->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001588 ASSERT_TRUE(dcd_answer != NULL);
1589 EXPECT_EQ(protocol, dcd_answer->protocol());
1590}
1591
1592// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1593TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001594 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001595 f1_.set_secure(SEC_DISABLED);
1596 f2_.set_secure(SEC_DISABLED);
1597 tdf1_.set_secure(SEC_DISABLED);
1598 tdf2_.set_secure(SEC_DISABLED);
1599
Steve Anton6fe1fba2018-12-11 10:15:23 -08001600 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001601 const AudioContentDescription* offer_acd =
1602 GetFirstAudioContentDescription(offer.get());
1603 ASSERT_TRUE(offer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001604 EXPECT_EQ(cricket::kMediaProtocolAvpf, offer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001605
Steve Anton6fe1fba2018-12-11 10:15:23 -08001606 std::unique_ptr<SessionDescription> answer =
1607 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001608
1609 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1610 ASSERT_TRUE(ac_answer != NULL);
1611 EXPECT_FALSE(ac_answer->rejected);
1612
1613 const AudioContentDescription* answer_acd =
1614 GetFirstAudioContentDescription(answer.get());
1615 ASSERT_TRUE(answer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001616 EXPECT_EQ(cricket::kMediaProtocolAvpf, answer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001617}
1618
1619// Create a video offer and answer and ensure the RTP header extensions
1620// matches what we expect.
1621TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1622 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001623 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001624 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1625 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1626 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1627 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1628
Steve Anton6fe1fba2018-12-11 10:15:23 -08001629 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001630 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001631 std::unique_ptr<SessionDescription> answer =
1632 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001633
Yves Gerey665174f2018-06-19 15:03:05 +02001634 EXPECT_EQ(
1635 MAKE_VECTOR(kAudioRtpExtension1),
1636 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1637 EXPECT_EQ(
1638 MAKE_VECTOR(kVideoRtpExtension1),
1639 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1640 EXPECT_EQ(
1641 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1642 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1643 EXPECT_EQ(
1644 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1645 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001646}
1647
Johannes Kronce8e8672019-02-22 13:06:44 +01001648// Create a audio/video offer and answer and ensure that the
1649// TransportSequenceNumber RTP header extensions are handled correctly. 02 is
1650// supported and should take precedence even though not listed among locally
1651// supported extensions.
1652TEST_F(MediaSessionDescriptionFactoryTest,
1653 TestOfferAnswerWithTransportSequenceNumberInOffer) {
1654 TestTransportSequenceNumberNegotiation(
1655 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1656 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Offer.
1657 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01)); // Expected answer.
1658}
1659TEST_F(MediaSessionDescriptionFactoryTest,
1660 TestOfferAnswerWithTransportSequenceNumber01And02InOffer) {
1661 TestTransportSequenceNumberNegotiation(
1662 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1663 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01And02), // Offer.
1664 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1665}
1666TEST_F(MediaSessionDescriptionFactoryTest,
1667 TestOfferAnswerWithTransportSequenceNumber02InOffer) {
1668 TestTransportSequenceNumberNegotiation(
1669 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1670 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02), // Offer.
1671 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1672}
1673
jbauch5869f502017-06-29 12:31:36 -07001674TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001675 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
jbauch5869f502017-06-29 12:31:36 -07001676 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001677 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001678
1679 f1_.set_enable_encrypted_rtp_header_extensions(true);
1680 f2_.set_enable_encrypted_rtp_header_extensions(true);
1681
Yves Gerey665174f2018-06-19 15:03:05 +02001682 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1683 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1684 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1685 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001686
Steve Anton6fe1fba2018-12-11 10:15:23 -08001687 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001688 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001689 std::unique_ptr<SessionDescription> answer =
1690 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001691
Yves Gerey665174f2018-06-19 15:03:05 +02001692 EXPECT_EQ(
1693 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1694 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1695 EXPECT_EQ(
1696 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1697 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1698 EXPECT_EQ(
1699 MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
1700 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1701 EXPECT_EQ(
1702 MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
1703 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001704}
1705
1706TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001707 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
jbauch5869f502017-06-29 12:31:36 -07001708 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001709 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001710
1711 f1_.set_enable_encrypted_rtp_header_extensions(true);
1712
Yves Gerey665174f2018-06-19 15:03:05 +02001713 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1714 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1715 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1716 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001717
Steve Anton6fe1fba2018-12-11 10:15:23 -08001718 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001719 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001720 std::unique_ptr<SessionDescription> answer =
1721 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001722
Yves Gerey665174f2018-06-19 15:03:05 +02001723 EXPECT_EQ(
1724 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1725 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1726 EXPECT_EQ(
1727 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1728 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1729 EXPECT_EQ(
1730 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1731 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1732 EXPECT_EQ(
1733 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1734 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001735}
1736
1737TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001738 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
jbauch5869f502017-06-29 12:31:36 -07001739 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001740 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001741
1742 f2_.set_enable_encrypted_rtp_header_extensions(true);
1743
Yves Gerey665174f2018-06-19 15:03:05 +02001744 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1745 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1746 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1747 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001748
Steve Anton6fe1fba2018-12-11 10:15:23 -08001749 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001750 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001751 std::unique_ptr<SessionDescription> answer =
1752 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001753
Yves Gerey665174f2018-06-19 15:03:05 +02001754 EXPECT_EQ(
1755 MAKE_VECTOR(kAudioRtpExtension1),
1756 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1757 EXPECT_EQ(
1758 MAKE_VECTOR(kVideoRtpExtension1),
1759 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1760 EXPECT_EQ(
1761 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1762 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1763 EXPECT_EQ(
1764 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1765 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001766}
1767
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001768// Create an audio, video, data answer without legacy StreamParams.
1769TEST_F(MediaSessionDescriptionFactoryTest,
1770 TestCreateAnswerWithoutLegacyStreams) {
1771 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001772 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1773 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001774 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001775 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001776 std::unique_ptr<SessionDescription> answer =
1777 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001778 const ContentInfo* ac = answer->GetContentByName("audio");
1779 const ContentInfo* vc = answer->GetContentByName("video");
1780 const ContentInfo* dc = answer->GetContentByName("data");
1781 ASSERT_TRUE(ac != NULL);
1782 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001783 const AudioContentDescription* acd = ac->media_description()->as_audio();
1784 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001785 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001786
1787 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1788 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1789 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1790}
1791
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001792// Create a typical video answer, and ensure it matches what we expect.
1793TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1794 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001795 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
1796 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1797 &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001798
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001799 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001800 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
1801 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1802 &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001803
kwiberg31022942016-03-11 14:18:21 -08001804 std::unique_ptr<SessionDescription> offer;
1805 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001806
1807 offer_opts.rtcp_mux_enabled = true;
1808 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001809 offer = f1_.CreateOffer(offer_opts, NULL);
1810 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001811 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1812 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001813 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001814 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1815 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001816 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001817 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1818 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001819 EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001820 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1821 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001822 EXPECT_TRUE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001823
1824 offer_opts.rtcp_mux_enabled = true;
1825 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001826 offer = f1_.CreateOffer(offer_opts, NULL);
1827 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001828 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1829 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001830 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001831 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1832 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001833 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001834 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1835 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001836 EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001837 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1838 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001839 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001840
1841 offer_opts.rtcp_mux_enabled = false;
1842 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001843 offer = f1_.CreateOffer(offer_opts, NULL);
1844 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001845 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1846 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001847 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001848 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1849 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001850 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001851 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1852 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001853 EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001854 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1855 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001856 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001857
1858 offer_opts.rtcp_mux_enabled = false;
1859 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001860 offer = f1_.CreateOffer(offer_opts, NULL);
1861 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001862 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1863 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001864 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001865 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1866 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001867 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001868 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1869 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001870 EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001871 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1872 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001873 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001874}
1875
1876// Create an audio-only answer to a video offer.
1877TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1878 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001879 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1880 RtpTransceiverDirection::kRecvOnly, kActive,
1881 &opts);
1882 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1883 RtpTransceiverDirection::kRecvOnly, kActive,
1884 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001885 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001886 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001887
1888 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001889 std::unique_ptr<SessionDescription> answer =
1890 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001891 const ContentInfo* ac = answer->GetContentByName("audio");
1892 const ContentInfo* vc = answer->GetContentByName("video");
1893 ASSERT_TRUE(ac != NULL);
1894 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001895 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001896 EXPECT_TRUE(vc->rejected);
1897}
1898
1899// Create an audio-only answer to an offer with data.
1900TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001901 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001902 opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001903 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
1904 RtpTransceiverDirection::kRecvOnly, kActive,
1905 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001906 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001907 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001908
1909 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001910 std::unique_ptr<SessionDescription> answer =
1911 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001912 const ContentInfo* ac = answer->GetContentByName("audio");
1913 const ContentInfo* dc = answer->GetContentByName("data");
1914 ASSERT_TRUE(ac != NULL);
1915 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001916 ASSERT_TRUE(dc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001917 EXPECT_TRUE(dc->rejected);
1918}
1919
1920// Create an answer that rejects the contents which are rejected in the offer.
1921TEST_F(MediaSessionDescriptionFactoryTest,
1922 CreateAnswerToOfferWithRejectedMedia) {
1923 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001924 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1925 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001926 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001927 ASSERT_TRUE(offer.get() != NULL);
1928 ContentInfo* ac = offer->GetContentByName("audio");
1929 ContentInfo* vc = offer->GetContentByName("video");
1930 ContentInfo* dc = offer->GetContentByName("data");
1931 ASSERT_TRUE(ac != NULL);
1932 ASSERT_TRUE(vc != NULL);
1933 ASSERT_TRUE(dc != NULL);
1934 ac->rejected = true;
1935 vc->rejected = true;
1936 dc->rejected = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001937 std::unique_ptr<SessionDescription> answer =
1938 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001939 ac = answer->GetContentByName("audio");
1940 vc = answer->GetContentByName("video");
1941 dc = answer->GetContentByName("data");
1942 ASSERT_TRUE(ac != NULL);
1943 ASSERT_TRUE(vc != NULL);
1944 ASSERT_TRUE(dc != NULL);
1945 EXPECT_TRUE(ac->rejected);
1946 EXPECT_TRUE(vc->rejected);
1947 EXPECT_TRUE(dc->rejected);
1948}
1949
Johannes Kron0854eb62018-10-10 22:33:20 +02001950TEST_F(MediaSessionDescriptionFactoryTest,
1951 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensions) {
1952 MediaSessionOptions opts;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001953 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02001954 // Offer without request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001955 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02001956 ASSERT_TRUE(offer.get() != NULL);
1957 std::unique_ptr<SessionDescription> answer_no_support(
1958 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001959 EXPECT_FALSE(answer_no_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001960
1961 // Offer with request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001962 offer->set_extmap_allow_mixed(true);
Johannes Kron0854eb62018-10-10 22:33:20 +02001963 ASSERT_TRUE(offer.get() != NULL);
1964 std::unique_ptr<SessionDescription> answer_support(
1965 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001966 EXPECT_TRUE(answer_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001967}
1968
1969TEST_F(MediaSessionDescriptionFactoryTest,
1970 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensionsOnMediaLevel) {
1971 MediaSessionOptions opts;
1972 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001973 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02001974 MediaContentDescription* video_offer =
1975 offer->GetContentDescriptionByName("video");
1976 ASSERT_TRUE(video_offer);
1977 MediaContentDescription* audio_offer =
1978 offer->GetContentDescriptionByName("audio");
1979 ASSERT_TRUE(audio_offer);
1980
1981 // Explicit disable of mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001982 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
1983 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
Johannes Kron0854eb62018-10-10 22:33:20 +02001984
1985 ASSERT_TRUE(offer.get() != NULL);
1986 std::unique_ptr<SessionDescription> answer_no_support(
1987 f2_.CreateAnswer(offer.get(), opts, NULL));
1988 MediaContentDescription* video_answer =
1989 answer_no_support->GetContentDescriptionByName("video");
1990 MediaContentDescription* audio_answer =
1991 answer_no_support->GetContentDescriptionByName("audio");
1992 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001993 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001994 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001995 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001996
1997 // Enable mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001998 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
1999 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
Johannes Kron0854eb62018-10-10 22:33:20 +02002000 ASSERT_TRUE(offer.get() != NULL);
2001 std::unique_ptr<SessionDescription> answer_support(
2002 f2_.CreateAnswer(offer.get(), opts, NULL));
2003 video_answer = answer_support->GetContentDescriptionByName("video");
2004 audio_answer = answer_support->GetContentDescriptionByName("audio");
2005 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02002006 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002007 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02002008 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02002009}
2010
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002011// Create an audio and video offer with:
2012// - one video track
2013// - two audio tracks
2014// - two data tracks
2015// and ensure it matches what we expect. Also updates the initial offer by
2016// adding a new video track and replaces one of the audio tracks.
2017TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
2018 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002019 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002020 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2021 {kMediaStream1}, 1, &opts);
2022 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2023 {kMediaStream1}, 1, &opts);
2024 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2025 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002026
Steve Anton4e70a722017-11-28 14:57:10 -08002027 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002028 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2029 {kMediaStream1}, 1, &opts);
2030 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2031 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002032
2033 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002034 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002035
2036 ASSERT_TRUE(offer.get() != NULL);
2037 const ContentInfo* ac = offer->GetContentByName("audio");
2038 const ContentInfo* vc = offer->GetContentByName("video");
2039 const ContentInfo* dc = offer->GetContentByName("data");
2040 ASSERT_TRUE(ac != NULL);
2041 ASSERT_TRUE(vc != NULL);
2042 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002043 const AudioContentDescription* acd = ac->media_description()->as_audio();
2044 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002045 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002046 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07002047 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002048
2049 const StreamParamsVec& audio_streams = acd->streams();
2050 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002051 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002052 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2053 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2054 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2055 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2056 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2057 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2058
2059 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2060 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002061 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002062
2063 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
2064 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002065 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002066
2067 const StreamParamsVec& video_streams = vcd->streams();
2068 ASSERT_EQ(1U, video_streams.size());
2069 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2070 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2071 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2072 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2073
2074 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002075 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002076 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002077
2078 const StreamParamsVec& data_streams = dcd->streams();
2079 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002080 EXPECT_EQ(data_streams[0].cname, data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002081 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2082 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2083 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2084 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2085 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2086 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2087
2088 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002089 dcd->bandwidth()); // default bandwidth (auto)
2090 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002091 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002092
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002093 // Update the offer. Add a new video track that is not synched to the
2094 // other tracks and replace audio track 2 with audio track 3.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002095 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2096 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002097 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002098 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
2099 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002100 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002101 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack3,
2102 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08002103 std::unique_ptr<SessionDescription> updated_offer(
2104 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002105
2106 ASSERT_TRUE(updated_offer.get() != NULL);
2107 ac = updated_offer->GetContentByName("audio");
2108 vc = updated_offer->GetContentByName("video");
2109 dc = updated_offer->GetContentByName("data");
2110 ASSERT_TRUE(ac != NULL);
2111 ASSERT_TRUE(vc != NULL);
2112 ASSERT_TRUE(dc != NULL);
2113 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002114 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002115 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002116 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002117 const RtpDataContentDescription* updated_dcd =
2118 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002119
2120 EXPECT_EQ(acd->type(), updated_acd->type());
2121 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2122 EXPECT_EQ(vcd->type(), updated_vcd->type());
2123 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2124 EXPECT_EQ(dcd->type(), updated_dcd->type());
2125 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002126 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002127 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002128 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002129 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002130 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002131 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2132
2133 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2134 ASSERT_EQ(2U, updated_audio_streams.size());
2135 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
2136 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
2137 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
2138 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
2139 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
2140
2141 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2142 ASSERT_EQ(2U, updated_video_streams.size());
2143 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2144 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002145 // All the media streams in one PeerConnection share one RTCP CNAME.
2146 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002147
2148 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2149 ASSERT_EQ(2U, updated_data_streams.size());
2150 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
2151 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
2152 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
2153 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
2154 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07002155 // The stream correctly got the CNAME from the MediaSessionOptions.
2156 // The Expected RTCP CNAME is the default one as we are using the default
2157 // MediaSessionOptions.
2158 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002159}
2160
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002161// Create an offer with simulcast video stream.
2162TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
2163 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002164 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2165 RtpTransceiverDirection::kRecvOnly, kActive,
2166 &opts);
2167 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2168 RtpTransceiverDirection::kSendRecv, kActive,
2169 &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002170 const int num_sim_layers = 3;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002171 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2172 {kMediaStream1}, num_sim_layers, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002173 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002174
2175 ASSERT_TRUE(offer.get() != NULL);
2176 const ContentInfo* vc = offer->GetContentByName("video");
2177 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002178 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002179
2180 const StreamParamsVec& video_streams = vcd->streams();
2181 ASSERT_EQ(1U, video_streams.size());
2182 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2183 const SsrcGroup* sim_ssrc_group =
2184 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
2185 ASSERT_TRUE(sim_ssrc_group != NULL);
2186 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
2187}
2188
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002189MATCHER(RidDescriptionEquals, "Verifies that two RidDescriptions are equal.") {
2190 const RidDescription& rid1 = ::testing::get<0>(arg);
2191 const RidDescription& rid2 = ::testing::get<1>(arg);
2192 return rid1.rid == rid2.rid && rid1.direction == rid2.direction;
2193}
2194
2195static void CheckSimulcastInSessionDescription(
2196 const SessionDescription* description,
2197 const std::string& content_name,
2198 const std::vector<RidDescription>& send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002199 const SimulcastLayerList& send_layers) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002200 ASSERT_NE(description, nullptr);
2201 const ContentInfo* content = description->GetContentByName(content_name);
2202 ASSERT_NE(content, nullptr);
2203 const MediaContentDescription* cd = content->media_description();
2204 ASSERT_NE(cd, nullptr);
2205 const StreamParamsVec& streams = cd->streams();
2206 ASSERT_THAT(streams, SizeIs(1));
2207 const StreamParams& stream = streams[0];
2208 ASSERT_THAT(stream.ssrcs, IsEmpty());
2209 EXPECT_TRUE(stream.has_rids());
2210 const std::vector<RidDescription> rids = stream.rids();
2211
2212 EXPECT_THAT(rids, Pointwise(RidDescriptionEquals(), send_rids));
2213
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002214 EXPECT_TRUE(cd->HasSimulcast());
2215 const SimulcastDescription& simulcast = cd->simulcast_description();
2216 EXPECT_THAT(simulcast.send_layers(), SizeIs(send_layers.size()));
2217 EXPECT_THAT(simulcast.send_layers(), Pointwise(Eq(), send_layers));
2218
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002219 ASSERT_THAT(simulcast.receive_layers().GetAllLayers(), SizeIs(0));
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002220}
2221
2222// Create an offer with spec-compliant simulcast video stream.
2223TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastOffer) {
2224 MediaSessionOptions opts;
2225 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2226 RtpTransceiverDirection::kSendRecv, kActive,
2227 &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002228 std::vector<RidDescription> send_rids;
2229 send_rids.push_back(RidDescription("f", RidDirection::kSend));
2230 send_rids.push_back(RidDescription("h", RidDirection::kSend));
2231 send_rids.push_back(RidDescription("q", RidDirection::kSend));
2232 SimulcastLayerList simulcast_layers;
2233 simulcast_layers.AddLayer(SimulcastLayer(send_rids[0].rid, false));
2234 simulcast_layers.AddLayer(SimulcastLayer(send_rids[1].rid, true));
2235 simulcast_layers.AddLayer(SimulcastLayer(send_rids[2].rid, false));
2236 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2237 {kMediaStream1}, send_rids,
2238 simulcast_layers, 0, &opts);
2239 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2240
2241 CheckSimulcastInSessionDescription(offer.get(), "video", send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002242 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002243}
2244
2245// Create an offer that signals RIDs (not SSRCs) without Simulcast.
2246// In this scenario, RIDs do not need to be negotiated (there is only one).
2247TEST_F(MediaSessionDescriptionFactoryTest, TestOfferWithRidsNoSimulcast) {
2248 MediaSessionOptions opts;
2249 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2250 RtpTransceiverDirection::kSendRecv, kActive,
2251 &opts);
2252 RidDescription rid("f", RidDirection::kSend);
2253 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2254 {kMediaStream1}, {rid},
2255 SimulcastLayerList(), 0, &opts);
2256 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2257
2258 ASSERT_NE(offer.get(), nullptr);
2259 const ContentInfo* content = offer->GetContentByName("video");
2260 ASSERT_NE(content, nullptr);
2261 const MediaContentDescription* cd = content->media_description();
2262 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002263 const StreamParamsVec& streams = cd->streams();
2264 ASSERT_THAT(streams, SizeIs(1));
2265 const StreamParams& stream = streams[0];
2266 ASSERT_THAT(stream.ssrcs, IsEmpty());
2267 EXPECT_FALSE(stream.has_rids());
2268 EXPECT_FALSE(cd->HasSimulcast());
2269}
2270
2271// Create an answer with spec-compliant simulcast video stream.
2272// In this scenario, the SFU is the caller requesting that we send Simulcast.
2273TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastAnswer) {
2274 MediaSessionOptions offer_opts;
2275 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2276 RtpTransceiverDirection::kSendRecv, kActive,
2277 &offer_opts);
2278 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2279 {kMediaStream1}, 1, &offer_opts);
2280 std::unique_ptr<SessionDescription> offer =
2281 f1_.CreateOffer(offer_opts, nullptr);
2282
2283 MediaSessionOptions answer_opts;
2284 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2285 RtpTransceiverDirection::kSendRecv, kActive,
2286 &answer_opts);
2287
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002288 std::vector<RidDescription> rid_descriptions{
2289 RidDescription("f", RidDirection::kSend),
2290 RidDescription("h", RidDirection::kSend),
2291 RidDescription("q", RidDirection::kSend),
2292 };
2293 SimulcastLayerList simulcast_layers;
2294 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[0].rid, false));
2295 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[1].rid, true));
2296 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[2].rid, false));
2297 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2298 {kMediaStream1}, rid_descriptions,
2299 simulcast_layers, 0, &answer_opts);
2300 std::unique_ptr<SessionDescription> answer =
2301 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2302
2303 CheckSimulcastInSessionDescription(answer.get(), "video", rid_descriptions,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002304 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002305}
2306
2307// Create an answer that signals RIDs (not SSRCs) without Simulcast.
2308// In this scenario, RIDs do not need to be negotiated (there is only one).
2309// Note that RID Direction is not the same as the transceiver direction.
2310TEST_F(MediaSessionDescriptionFactoryTest, TestAnswerWithRidsNoSimulcast) {
2311 MediaSessionOptions offer_opts;
2312 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2313 RtpTransceiverDirection::kSendRecv, kActive,
2314 &offer_opts);
2315 RidDescription rid_offer("f", RidDirection::kSend);
2316 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2317 {kMediaStream1}, {rid_offer},
2318 SimulcastLayerList(), 0, &offer_opts);
2319 std::unique_ptr<SessionDescription> offer =
2320 f1_.CreateOffer(offer_opts, nullptr);
2321
2322 MediaSessionOptions answer_opts;
2323 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2324 RtpTransceiverDirection::kSendRecv, kActive,
2325 &answer_opts);
2326
2327 RidDescription rid_answer("f", RidDirection::kReceive);
2328 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2329 {kMediaStream1}, {rid_answer},
2330 SimulcastLayerList(), 0, &answer_opts);
2331 std::unique_ptr<SessionDescription> answer =
2332 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2333
2334 ASSERT_NE(answer.get(), nullptr);
2335 const ContentInfo* content = offer->GetContentByName("video");
2336 ASSERT_NE(content, nullptr);
2337 const MediaContentDescription* cd = content->media_description();
2338 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002339 const StreamParamsVec& streams = cd->streams();
2340 ASSERT_THAT(streams, SizeIs(1));
2341 const StreamParams& stream = streams[0];
2342 ASSERT_THAT(stream.ssrcs, IsEmpty());
2343 EXPECT_FALSE(stream.has_rids());
2344 EXPECT_FALSE(cd->HasSimulcast());
2345}
2346
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002347// Create an audio and video answer to a standard video offer with:
2348// - one video track
2349// - two audio tracks
2350// - two data tracks
2351// and ensure it matches what we expect. Also updates the initial answer by
2352// adding a new video track and removes one of the audio tracks.
2353TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
2354 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002355 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2356 RtpTransceiverDirection::kRecvOnly, kActive,
2357 &offer_opts);
2358 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2359 RtpTransceiverDirection::kRecvOnly, kActive,
2360 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002361 offer_opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002362 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2363 RtpTransceiverDirection::kRecvOnly, kActive,
2364 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002365 f1_.set_secure(SEC_ENABLED);
2366 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002367 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002368
zhihuang1c378ed2017-08-17 14:10:50 -07002369 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002370 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2371 RtpTransceiverDirection::kSendRecv, kActive,
2372 &answer_opts);
2373 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2374 RtpTransceiverDirection::kSendRecv, kActive,
2375 &answer_opts);
2376 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2377 {kMediaStream1}, 1, &answer_opts);
2378 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2379 {kMediaStream1}, 1, &answer_opts);
2380 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2381 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002382
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002383 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2384 RtpTransceiverDirection::kSendRecv, kActive,
2385 &answer_opts);
2386 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2387 {kMediaStream1}, 1, &answer_opts);
2388 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2389 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002390 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002391
Steve Anton6fe1fba2018-12-11 10:15:23 -08002392 std::unique_ptr<SessionDescription> answer =
2393 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002394
2395 ASSERT_TRUE(answer.get() != NULL);
2396 const ContentInfo* ac = answer->GetContentByName("audio");
2397 const ContentInfo* vc = answer->GetContentByName("video");
2398 const ContentInfo* dc = answer->GetContentByName("data");
2399 ASSERT_TRUE(ac != NULL);
2400 ASSERT_TRUE(vc != NULL);
2401 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002402 const AudioContentDescription* acd = ac->media_description()->as_audio();
2403 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002404 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002405 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
2406 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
2407 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002408
2409 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002410 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002411
2412 const StreamParamsVec& audio_streams = acd->streams();
2413 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002414 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002415 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2416 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2417 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2418 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2419 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2420 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2421
2422 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2423 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
2424
2425 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002426 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002427
2428 const StreamParamsVec& video_streams = vcd->streams();
2429 ASSERT_EQ(1U, video_streams.size());
2430 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2431 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2432 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2433 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2434
2435 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002436 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002437
2438 const StreamParamsVec& data_streams = dcd->streams();
2439 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002440 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002441 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2442 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2443 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2444 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2445 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2446 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2447
2448 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002449 dcd->bandwidth()); // default bandwidth (auto)
2450 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002451
2452 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07002453 // other tracks and remove 1 audio track.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002454 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2455 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002456 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
2457 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08002458 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002459 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002460
2461 ASSERT_TRUE(updated_answer.get() != NULL);
2462 ac = updated_answer->GetContentByName("audio");
2463 vc = updated_answer->GetContentByName("video");
2464 dc = updated_answer->GetContentByName("data");
2465 ASSERT_TRUE(ac != NULL);
2466 ASSERT_TRUE(vc != NULL);
2467 ASSERT_TRUE(dc != NULL);
2468 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002469 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002470 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002471 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002472 const RtpDataContentDescription* updated_dcd =
2473 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002474
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002475 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002476 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002477 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002478 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002479 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002480 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2481
2482 EXPECT_EQ(acd->type(), updated_acd->type());
2483 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2484 EXPECT_EQ(vcd->type(), updated_vcd->type());
2485 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2486 EXPECT_EQ(dcd->type(), updated_dcd->type());
2487 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
2488
2489 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2490 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002491 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002492
2493 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2494 ASSERT_EQ(2U, updated_video_streams.size());
2495 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2496 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002497 // All media streams in one PeerConnection share one CNAME.
2498 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002499
2500 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2501 ASSERT_EQ(1U, updated_data_streams.size());
2502 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
2503}
2504
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002505// Create an updated offer after creating an answer to the original offer and
2506// verify that the codecs that were part of the original answer are not changed
2507// in the updated offer.
2508TEST_F(MediaSessionDescriptionFactoryTest,
2509 RespondentCreatesOfferAfterCreatingAnswer) {
2510 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002511 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002512
Steve Anton6fe1fba2018-12-11 10:15:23 -08002513 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2514 std::unique_ptr<SessionDescription> answer =
2515 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002516
2517 const AudioContentDescription* acd =
2518 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002519 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002520
2521 const VideoContentDescription* vcd =
2522 GetFirstVideoContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002523 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002524
kwiberg31022942016-03-11 14:18:21 -08002525 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002526 f2_.CreateOffer(opts, answer.get()));
2527
2528 // The expected audio codecs are the common audio codecs from the first
2529 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
2530 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002531 // TODO(wu): |updated_offer| should not include the codec
2532 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002533 const AudioCodec kUpdatedAudioCodecOffer[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002534 kAudioCodecsAnswer[0],
2535 kAudioCodecsAnswer[1],
2536 kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002537 };
2538
2539 // The expected video codecs are the common video codecs from the first
2540 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
2541 // preference order.
2542 const VideoCodec kUpdatedVideoCodecOffer[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002543 kVideoCodecsAnswer[0],
2544 kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002545 };
2546
2547 const AudioContentDescription* updated_acd =
2548 GetFirstAudioContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002549 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kUpdatedAudioCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002550
2551 const VideoContentDescription* updated_vcd =
2552 GetFirstVideoContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002553 EXPECT_THAT(updated_vcd->codecs(), ElementsAreArray(kUpdatedVideoCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002554}
2555
Steve Anton5c72e712018-12-10 14:25:30 -08002556// Test that a reoffer does not reuse audio codecs from a previous media section
2557// that is being recycled.
2558TEST_F(MediaSessionDescriptionFactoryTest,
2559 ReOfferDoesNotReUseRecycledAudioCodecs) {
2560 f1_.set_video_codecs({});
2561 f2_.set_video_codecs({});
2562
2563 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002564 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2565 RtpTransceiverDirection::kSendRecv, kActive,
2566 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002567 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2568 std::unique_ptr<SessionDescription> answer =
2569 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002570
2571 // Recycle the media section by changing its mid.
2572 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002573 std::unique_ptr<SessionDescription> reoffer =
2574 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002575
2576 // Expect that the results of the first negotiation are ignored. If the m=
2577 // section was not recycled the payload types would match the initial offerer.
2578 const AudioContentDescription* acd =
2579 GetFirstAudioContentDescription(reoffer.get());
2580 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecs2));
2581}
2582
2583// Test that a reoffer does not reuse video codecs from a previous media section
2584// that is being recycled.
2585TEST_F(MediaSessionDescriptionFactoryTest,
2586 ReOfferDoesNotReUseRecycledVideoCodecs) {
2587 f1_.set_audio_codecs({}, {});
2588 f2_.set_audio_codecs({}, {});
2589
2590 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002591 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2592 RtpTransceiverDirection::kSendRecv, kActive,
2593 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002594 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2595 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002596
2597 // Recycle the media section by changing its mid.
2598 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002599 std::unique_ptr<SessionDescription> reoffer =
2600 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002601
2602 // Expect that the results of the first negotiation are ignored. If the m=
2603 // section was not recycled the payload types would match the initial offerer.
2604 const VideoContentDescription* vcd =
2605 GetFirstVideoContentDescription(reoffer.get());
2606 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecs2));
2607}
2608
2609// Test that a reanswer does not reuse audio codecs from a previous media
2610// section that is being recycled.
2611TEST_F(MediaSessionDescriptionFactoryTest,
2612 ReAnswerDoesNotReUseRecycledAudioCodecs) {
2613 f1_.set_video_codecs({});
2614 f2_.set_video_codecs({});
2615
2616 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2617 // second offer/answer is forward (|f1_| as offerer).
2618 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002619 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2620 RtpTransceiverDirection::kSendRecv, kActive,
2621 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002622 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2623 std::unique_ptr<SessionDescription> answer =
2624 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002625
2626 // Recycle the media section by changing its mid.
2627 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002628 std::unique_ptr<SessionDescription> reoffer =
2629 f1_.CreateOffer(opts, answer.get());
2630 std::unique_ptr<SessionDescription> reanswer =
2631 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002632
2633 // Expect that the results of the first negotiation are ignored. If the m=
2634 // section was not recycled the payload types would match the initial offerer.
2635 const AudioContentDescription* acd =
2636 GetFirstAudioContentDescription(reanswer.get());
2637 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
2638}
2639
2640// Test that a reanswer does not reuse video codecs from a previous media
2641// section that is being recycled.
2642TEST_F(MediaSessionDescriptionFactoryTest,
2643 ReAnswerDoesNotReUseRecycledVideoCodecs) {
2644 f1_.set_audio_codecs({}, {});
2645 f2_.set_audio_codecs({}, {});
2646
2647 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2648 // second offer/answer is forward (|f1_| as offerer).
2649 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002650 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2651 RtpTransceiverDirection::kSendRecv, kActive,
2652 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002653 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2654 std::unique_ptr<SessionDescription> answer =
2655 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002656
2657 // Recycle the media section by changing its mid.
2658 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002659 std::unique_ptr<SessionDescription> reoffer =
2660 f1_.CreateOffer(opts, answer.get());
2661 std::unique_ptr<SessionDescription> reanswer =
2662 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002663
2664 // Expect that the results of the first negotiation are ignored. If the m=
2665 // section was not recycled the payload types would match the initial offerer.
2666 const VideoContentDescription* vcd =
2667 GetFirstVideoContentDescription(reanswer.get());
2668 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
2669}
2670
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002671// Create an updated offer after creating an answer to the original offer and
2672// verify that the codecs that were part of the original answer are not changed
2673// in the updated offer. In this test Rtx is enabled.
2674TEST_F(MediaSessionDescriptionFactoryTest,
2675 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2676 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002677 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2678 RtpTransceiverDirection::kRecvOnly, kActive,
2679 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002680 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002681 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002682 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002683 f1_.set_video_codecs(f1_codecs);
2684
2685 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002686 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002687 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002688 f2_.set_video_codecs(f2_codecs);
2689
Steve Anton6fe1fba2018-12-11 10:15:23 -08002690 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002691 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002692 std::unique_ptr<SessionDescription> answer =
2693 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002694
2695 const VideoContentDescription* vcd =
2696 GetFirstVideoContentDescription(answer.get());
2697
2698 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002699 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2700 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002701
2702 EXPECT_EQ(expected_codecs, vcd->codecs());
2703
deadbeef67cf2c12016-04-13 10:07:16 -07002704 // Now, make sure we get same result (except for the order) if |f2_| creates
2705 // an updated offer even though the default payload types between |f1_| and
2706 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08002707 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002708 f2_.CreateOffer(opts, answer.get()));
2709 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002710 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002711 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2712
2713 const VideoContentDescription* updated_vcd =
2714 GetFirstVideoContentDescription(updated_answer.get());
2715
2716 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2717}
2718
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002719// Regression test for:
2720// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2721// Existing codecs should always appear before new codecs in re-offers. But
2722// under a specific set of circumstances, the existing RTX codec was ending up
2723// added to the end of the list.
2724TEST_F(MediaSessionDescriptionFactoryTest,
2725 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2726 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002727 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2728 RtpTransceiverDirection::kRecvOnly, kActive,
2729 &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002730 // We specifically choose different preferred payload types for VP8 to
2731 // trigger the issue.
2732 cricket::VideoCodec vp8_offerer(100, "VP8");
2733 cricket::VideoCodec vp8_offerer_rtx =
2734 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
2735 cricket::VideoCodec vp8_answerer(110, "VP8");
2736 cricket::VideoCodec vp8_answerer_rtx =
2737 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
2738 cricket::VideoCodec vp9(120, "VP9");
2739 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
2740
2741 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
2742 // We also specifically cause the answerer to prefer VP9, such that if it
2743 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
2744 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
2745 vp8_answerer_rtx};
2746
2747 f1_.set_video_codecs(f1_codecs);
2748 f2_.set_video_codecs(f2_codecs);
2749 std::vector<AudioCodec> audio_codecs;
2750 f1_.set_audio_codecs(audio_codecs, audio_codecs);
2751 f2_.set_audio_codecs(audio_codecs, audio_codecs);
2752
2753 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002754 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002755 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002756 std::unique_ptr<SessionDescription> answer =
2757 f2_.CreateAnswer(offer.get(), opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002758
2759 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
2760 // But if the bug is triggered, RTX for VP8 ends up last.
2761 std::unique_ptr<SessionDescription> updated_offer(
2762 f2_.CreateOffer(opts, answer.get()));
2763
2764 const VideoContentDescription* vcd =
2765 GetFirstVideoContentDescription(updated_offer.get());
2766 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
2767 ASSERT_EQ(4u, codecs.size());
2768 EXPECT_EQ(vp8_offerer, codecs[0]);
2769 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
2770 EXPECT_EQ(vp9, codecs[2]);
2771 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002772}
2773
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002774// Create an updated offer that adds video after creating an audio only answer
2775// to the original offer. This test verifies that if a video codec and the RTX
2776// codec have the same default payload type as an audio codec that is already in
2777// use, the added codecs payload types are changed.
2778TEST_F(MediaSessionDescriptionFactoryTest,
2779 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2780 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002781 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002782 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002783 f1_.set_video_codecs(f1_codecs);
2784
2785 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002786 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2787 RtpTransceiverDirection::kRecvOnly, kActive,
2788 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002789
Steve Anton6fe1fba2018-12-11 10:15:23 -08002790 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2791 std::unique_ptr<SessionDescription> answer =
2792 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002793
2794 const AudioContentDescription* acd =
2795 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002796 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002797
2798 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
2799 // reference be the same as an audio codec that was negotiated in the
2800 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002801 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08002802 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002803
2804 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2805 int used_pl_type = acd->codecs()[0].id;
2806 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002807 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002808 f2_.set_video_codecs(f2_codecs);
2809
kwiberg31022942016-03-11 14:18:21 -08002810 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002811 f2_.CreateOffer(opts, answer.get()));
2812 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002813 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002814 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2815
2816 const AudioContentDescription* updated_acd =
2817 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002818 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002819
2820 const VideoContentDescription* updated_vcd =
2821 GetFirstVideoContentDescription(updated_answer.get());
2822
2823 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
Steve Antone38a5a12018-11-21 16:05:15 -08002824 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02002825 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002826 EXPECT_NE(used_pl_type, new_h264_pl_type);
2827 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002828 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002829 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
2830 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
2831}
2832
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002833// Create an updated offer with RTX after creating an answer to an offer
2834// without RTX, and with different default payload types.
2835// Verify that the added RTX codec references the correct payload type.
2836TEST_F(MediaSessionDescriptionFactoryTest,
2837 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
2838 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002839 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002840
2841 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2842 // This creates rtx for H264 with the payload type |f2_| uses.
2843 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
2844 f2_.set_video_codecs(f2_codecs);
2845
Steve Anton6fe1fba2018-12-11 10:15:23 -08002846 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002847 ASSERT_TRUE(offer.get() != nullptr);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002848 std::unique_ptr<SessionDescription> answer =
2849 f2_.CreateAnswer(offer.get(), opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002850
2851 const VideoContentDescription* vcd =
2852 GetFirstVideoContentDescription(answer.get());
2853
2854 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2855 EXPECT_EQ(expected_codecs, vcd->codecs());
2856
2857 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
2858 // updated offer, even though the default payload types are different from
2859 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08002860 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002861 f2_.CreateOffer(opts, answer.get()));
2862 ASSERT_TRUE(updated_offer);
2863
2864 const VideoContentDescription* updated_vcd =
2865 GetFirstVideoContentDescription(updated_offer.get());
2866
2867 // New offer should attempt to add H263, and RTX for H264.
2868 expected_codecs.push_back(kVideoCodecs2[1]);
2869 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
2870 &expected_codecs);
2871 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2872}
2873
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002874// Test that RTX is ignored when there is no associated payload type parameter.
2875TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
2876 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002877 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2878 RtpTransceiverDirection::kRecvOnly, kActive,
2879 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002880 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002881 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07002882 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002883 f1_.set_video_codecs(f1_codecs);
2884
2885 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002886 // This creates RTX for H264 with the payload type |f2_| uses.
2887 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002888 f2_.set_video_codecs(f2_codecs);
2889
Steve Anton6fe1fba2018-12-11 10:15:23 -08002890 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002891 ASSERT_TRUE(offer.get() != NULL);
2892 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
2893 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
2894 // is possible to test that that RTX is dropped when
2895 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08002896 MediaContentDescription* media_desc =
2897 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2898 ASSERT_TRUE(media_desc);
2899 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002900 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07002901 for (VideoCodec& codec : codecs) {
2902 if (codec.name.find(cricket::kRtxCodecName) == 0) {
2903 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002904 }
2905 }
2906 desc->set_codecs(codecs);
2907
Steve Anton6fe1fba2018-12-11 10:15:23 -08002908 std::unique_ptr<SessionDescription> answer =
2909 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002910
Steve Anton64b626b2019-01-28 17:25:26 -08002911 EXPECT_THAT(
2912 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
2913 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002914}
2915
2916// Test that RTX will be filtered out in the answer if its associated payload
2917// type doesn't match the local value.
2918TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
2919 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002920 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2921 RtpTransceiverDirection::kRecvOnly, kActive,
2922 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002923 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2924 // This creates RTX for H264 in sender.
2925 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2926 f1_.set_video_codecs(f1_codecs);
2927
2928 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2929 // This creates RTX for H263 in receiver.
2930 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
2931 f2_.set_video_codecs(f2_codecs);
2932
Steve Anton6fe1fba2018-12-11 10:15:23 -08002933 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002934 ASSERT_TRUE(offer.get() != NULL);
2935 // Associated payload type doesn't match, therefore, RTX codec is removed in
2936 // the answer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002937 std::unique_ptr<SessionDescription> answer =
2938 f2_.CreateAnswer(offer.get(), opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002939
Steve Anton64b626b2019-01-28 17:25:26 -08002940 EXPECT_THAT(
2941 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
2942 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002943}
2944
2945// Test that when multiple RTX codecs are offered, only the matched RTX codec
2946// is added in the answer, and the unsupported RTX codec is filtered out.
2947TEST_F(MediaSessionDescriptionFactoryTest,
2948 FilterOutUnsupportedRtxWhenCreatingAnswer) {
2949 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002950 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2951 RtpTransceiverDirection::kRecvOnly, kActive,
2952 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002953 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2954 // This creates RTX for H264-SVC in sender.
2955 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2956 f1_.set_video_codecs(f1_codecs);
2957
2958 // This creates RTX for H264 in sender.
2959 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2960 f1_.set_video_codecs(f1_codecs);
2961
2962 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2963 // This creates RTX for H264 in receiver.
2964 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
2965 f2_.set_video_codecs(f2_codecs);
2966
2967 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
2968 // for H264-SVC should also be removed.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002969 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002970 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002971 std::unique_ptr<SessionDescription> answer =
2972 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002973 const VideoContentDescription* vcd =
2974 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002975 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2976 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2977 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002978
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002979 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002980}
2981
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002982// Test that after one RTX codec has been negotiated, a new offer can attempt
2983// to add another.
2984TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
2985 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002986 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2987 RtpTransceiverDirection::kRecvOnly, kActive,
2988 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002989 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2990 // This creates RTX for H264 for the offerer.
2991 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2992 f1_.set_video_codecs(f1_codecs);
2993
Steve Anton6fe1fba2018-12-11 10:15:23 -08002994 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002995 ASSERT_TRUE(offer);
2996 const VideoContentDescription* vcd =
2997 GetFirstVideoContentDescription(offer.get());
2998
2999 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
3000 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
3001 &expected_codecs);
3002 EXPECT_EQ(expected_codecs, vcd->codecs());
3003
3004 // Now, attempt to add RTX for H264-SVC.
3005 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
3006 f1_.set_video_codecs(f1_codecs);
3007
kwiberg31022942016-03-11 14:18:21 -08003008 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08003009 f1_.CreateOffer(opts, offer.get()));
3010 ASSERT_TRUE(updated_offer);
3011 vcd = GetFirstVideoContentDescription(updated_offer.get());
3012
3013 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
3014 &expected_codecs);
3015 EXPECT_EQ(expected_codecs, vcd->codecs());
3016}
3017
Noah Richards2e7a0982015-05-18 14:02:54 -07003018// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
3019// generated for each simulcast ssrc and correctly grouped.
3020TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
3021 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003022 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3023 RtpTransceiverDirection::kSendRecv, kActive,
3024 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003025 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003026 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3027 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07003028
3029 // Use a single real codec, and then add RTX for it.
3030 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07003031 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07003032 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
3033 f1_.set_video_codecs(f1_codecs);
3034
3035 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
3036 // is a FID ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003037 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Noah Richards2e7a0982015-05-18 14:02:54 -07003038 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003039 MediaContentDescription* media_desc =
3040 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3041 ASSERT_TRUE(media_desc);
3042 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07003043 const StreamParamsVec& streams = desc->streams();
3044 // Single stream.
3045 ASSERT_EQ(1u, streams.size());
3046 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
3047 EXPECT_EQ(6u, streams[0].ssrcs.size());
3048 // And should have a SIM group for the simulcast.
3049 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3050 // And a FID group for RTX.
3051 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02003052 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003053 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3054 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02003055 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003056 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
3057 EXPECT_EQ(3u, fid_ssrcs.size());
3058}
3059
brandtr03d5fb12016-11-22 03:37:59 -08003060// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
3061// together with a FEC-FR grouping.
3062TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
3063 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003064 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3065 RtpTransceiverDirection::kSendRecv, kActive,
3066 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003067 // Add single stream.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003068 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3069 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003070
3071 // Use a single real codec, and then add FlexFEC for it.
3072 std::vector<VideoCodec> f1_codecs;
3073 f1_codecs.push_back(VideoCodec(97, "H264"));
3074 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
3075 f1_.set_video_codecs(f1_codecs);
3076
3077 // Ensure that the offer has a single FlexFEC ssrc and that
3078 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003079 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003080 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003081 MediaContentDescription* media_desc =
3082 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3083 ASSERT_TRUE(media_desc);
3084 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003085 const StreamParamsVec& streams = desc->streams();
3086 // Single stream.
3087 ASSERT_EQ(1u, streams.size());
3088 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
3089 EXPECT_EQ(2u, streams[0].ssrcs.size());
3090 // And should have a FEC-FR group for FlexFEC.
3091 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
3092 std::vector<uint32_t> primary_ssrcs;
3093 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3094 ASSERT_EQ(1u, primary_ssrcs.size());
3095 uint32_t flexfec_ssrc;
3096 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
3097 EXPECT_NE(flexfec_ssrc, 0u);
3098}
3099
3100// Test that FlexFEC is disabled for simulcast.
3101// TODO(brandtr): Remove this test when we support simulcast, either through
3102// multiple FlexfecSenders, or through multistream protection.
3103TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
3104 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003105 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3106 RtpTransceiverDirection::kSendRecv, kActive,
3107 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003108 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003109 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3110 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003111
3112 // Use a single real codec, and then add FlexFEC for it.
3113 std::vector<VideoCodec> f1_codecs;
3114 f1_codecs.push_back(VideoCodec(97, "H264"));
3115 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
3116 f1_.set_video_codecs(f1_codecs);
3117
3118 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
3119 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003120 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003121 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003122 MediaContentDescription* media_desc =
3123 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3124 ASSERT_TRUE(media_desc);
3125 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003126 const StreamParamsVec& streams = desc->streams();
3127 // Single stream.
3128 ASSERT_EQ(1u, streams.size());
3129 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
3130 EXPECT_EQ(3u, streams[0].ssrcs.size());
3131 // And should have a SIM group for the simulcast.
3132 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3133 // And not a FEC-FR group for FlexFEC.
3134 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
3135 std::vector<uint32_t> primary_ssrcs;
3136 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3137 EXPECT_EQ(3u, primary_ssrcs.size());
3138 for (uint32_t primary_ssrc : primary_ssrcs) {
3139 uint32_t flexfec_ssrc;
3140 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
3141 }
3142}
3143
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003144// Create an updated offer after creating an answer to the original offer and
3145// verify that the RTP header extensions that were part of the original answer
3146// are not changed in the updated offer.
3147TEST_F(MediaSessionDescriptionFactoryTest,
3148 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
3149 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003150 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003151
3152 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
3153 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
3154 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
3155 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
3156
Steve Anton6fe1fba2018-12-11 10:15:23 -08003157 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
3158 std::unique_ptr<SessionDescription> answer =
3159 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003160
Yves Gerey665174f2018-06-19 15:03:05 +02003161 EXPECT_EQ(
3162 MAKE_VECTOR(kAudioRtpExtensionAnswer),
3163 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
3164 EXPECT_EQ(
3165 MAKE_VECTOR(kVideoRtpExtensionAnswer),
3166 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003167
kwiberg31022942016-03-11 14:18:21 -08003168 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003169 f2_.CreateOffer(opts, answer.get()));
3170
3171 // The expected RTP header extensions in the new offer are the resulting
3172 // extensions from the first offer/answer exchange plus the extensions only
3173 // |f2_| offer.
3174 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003175 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07003176 const RtpExtension kUpdatedAudioRtpExtensions[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003177 kAudioRtpExtensionAnswer[0],
3178 RtpExtension(kAudioRtpExtension2[1].uri, 13),
isheriff6f8d6862016-05-26 11:24:55 -07003179 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003180 };
3181
3182 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003183 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07003184 const RtpExtension kUpdatedVideoRtpExtensions[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003185 kVideoRtpExtensionAnswer[0],
3186 RtpExtension(kVideoRtpExtension2[1].uri, 12),
isheriff6f8d6862016-05-26 11:24:55 -07003187 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003188 };
3189
3190 const AudioContentDescription* updated_acd =
3191 GetFirstAudioContentDescription(updated_offer.get());
3192 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
3193 updated_acd->rtp_header_extensions());
3194
3195 const VideoContentDescription* updated_vcd =
3196 GetFirstVideoContentDescription(updated_offer.get());
3197 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
3198 updated_vcd->rtp_header_extensions());
3199}
3200
deadbeefa5b273a2015-08-20 17:30:13 -07003201// Verify that if the same RTP extension URI is used for audio and video, the
3202// same ID is used. Also verify that the ID isn't changed when creating an
3203// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07003204TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07003205 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003206 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07003207
3208 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
3209 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
3210
Steve Anton6fe1fba2018-12-11 10:15:23 -08003211 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
deadbeefa5b273a2015-08-20 17:30:13 -07003212
3213 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
3214 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07003215 const RtpExtension kExpectedVideoRtpExtension[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02003216 kVideoRtpExtension3[0],
3217 kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07003218 };
3219
Yves Gerey665174f2018-06-19 15:03:05 +02003220 EXPECT_EQ(
3221 MAKE_VECTOR(kAudioRtpExtension3),
3222 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3223 EXPECT_EQ(
3224 MAKE_VECTOR(kExpectedVideoRtpExtension),
3225 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003226
3227 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08003228 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07003229 f1_.CreateOffer(opts, offer.get()));
3230
3231 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02003232 GetFirstAudioContentDescription(updated_offer.get())
3233 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003234 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003235 GetFirstVideoContentDescription(updated_offer.get())
3236 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003237}
3238
jbauch5869f502017-06-29 12:31:36 -07003239// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
3240TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
3241 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003242 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07003243
3244 f1_.set_enable_encrypted_rtp_header_extensions(true);
3245 f2_.set_enable_encrypted_rtp_header_extensions(true);
3246
3247 f1_.set_audio_rtp_header_extensions(
3248 MAKE_VECTOR(kAudioRtpExtension3ForEncryption));
3249 f1_.set_video_rtp_header_extensions(
3250 MAKE_VECTOR(kVideoRtpExtension3ForEncryption));
3251
Steve Anton6fe1fba2018-12-11 10:15:23 -08003252 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07003253
3254 // The extensions that are shared between audio and video should use the same
3255 // id.
3256 const RtpExtension kExpectedVideoRtpExtension[] = {
3257 kVideoRtpExtension3ForEncryption[0],
3258 kAudioRtpExtension3ForEncryptionOffer[1],
3259 kAudioRtpExtension3ForEncryptionOffer[2],
3260 };
3261
Yves Gerey665174f2018-06-19 15:03:05 +02003262 EXPECT_EQ(
3263 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
3264 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3265 EXPECT_EQ(
3266 MAKE_VECTOR(kExpectedVideoRtpExtension),
3267 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003268
3269 // Nothing should change when creating a new offer
3270 std::unique_ptr<SessionDescription> updated_offer(
3271 f1_.CreateOffer(opts, offer.get()));
3272
3273 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003274 GetFirstAudioContentDescription(updated_offer.get())
3275 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003276 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003277 GetFirstVideoContentDescription(updated_offer.get())
3278 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003279}
3280
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003281TEST(MediaSessionDescription, CopySessionDescription) {
3282 SessionDescription source;
3283 cricket::ContentGroup group(cricket::CN_AUDIO);
3284 source.AddGroup(group);
Harald Alvestrand1716d392019-06-03 20:35:45 +02003285 std::unique_ptr<AudioContentDescription> acd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003286 std::make_unique<AudioContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003287 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
3288 acd->AddLegacyStream(1);
Harald Alvestrand1716d392019-06-03 20:35:45 +02003289 std::unique_ptr<AudioContentDescription> acd_passed =
3290 absl::WrapUnique(acd->Copy());
3291 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp,
3292 std::move(acd_passed));
3293 std::unique_ptr<VideoContentDescription> vcd =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02003294 std::make_unique<VideoContentDescription>();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003295 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
3296 vcd->AddLegacyStream(2);
Harald Alvestrand1716d392019-06-03 20:35:45 +02003297 std::unique_ptr<VideoContentDescription> vcd_passed =
3298 absl::WrapUnique(vcd->Copy());
3299 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp,
3300 std::move(vcd_passed));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003301
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003302 std::unique_ptr<SessionDescription> copy = source.Clone();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003303 ASSERT_TRUE(copy.get() != NULL);
3304 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
3305 const ContentInfo* ac = copy->GetContentByName("audio");
3306 const ContentInfo* vc = copy->GetContentByName("video");
3307 ASSERT_TRUE(ac != NULL);
3308 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08003309 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003310 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003311 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
3312 EXPECT_EQ(1u, acd->first_ssrc());
3313
Steve Anton5adfafd2017-12-20 16:34:00 -08003314 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003315 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003316 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
3317 EXPECT_EQ(2u, vcd->first_ssrc());
3318}
3319
3320// The below TestTransportInfoXXX tests create different offers/answers, and
3321// ensure the TransportInfo in the SessionDescription matches what we expect.
3322TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
3323 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003324 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3325 RtpTransceiverDirection::kRecvOnly, kActive,
3326 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003327 TestTransportInfo(true, options, false);
3328}
3329
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003330TEST_F(MediaSessionDescriptionFactoryTest,
3331 TestTransportInfoOfferIceRenomination) {
3332 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003333 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3334 RtpTransceiverDirection::kRecvOnly, kActive,
3335 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003336 options.media_description_options[0]
3337 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003338 TestTransportInfo(true, options, false);
3339}
3340
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003341TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
3342 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003343 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3344 RtpTransceiverDirection::kRecvOnly, kActive,
3345 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003346 TestTransportInfo(true, options, true);
3347}
3348
3349TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
3350 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003351 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3352 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3353 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003354 TestTransportInfo(true, options, false);
3355}
3356
3357TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003358 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003359 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003360 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3361 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3362 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003363 TestTransportInfo(true, options, true);
3364}
3365
3366TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
3367 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003368 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3369 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3370 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003371 options.bundle_enabled = true;
3372 TestTransportInfo(true, options, false);
3373}
3374
3375TEST_F(MediaSessionDescriptionFactoryTest,
3376 TestTransportInfoOfferBundleCurrent) {
3377 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003378 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3379 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3380 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003381 options.bundle_enabled = true;
3382 TestTransportInfo(true, options, true);
3383}
3384
3385TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
3386 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003387 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3388 RtpTransceiverDirection::kRecvOnly, kActive,
3389 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003390 TestTransportInfo(false, options, false);
3391}
3392
3393TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003394 TestTransportInfoAnswerIceRenomination) {
3395 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003396 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3397 RtpTransceiverDirection::kRecvOnly, kActive,
3398 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003399 options.media_description_options[0]
3400 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003401 TestTransportInfo(false, options, false);
3402}
3403
3404TEST_F(MediaSessionDescriptionFactoryTest,
3405 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003406 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003407 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3408 RtpTransceiverDirection::kRecvOnly, kActive,
3409 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003410 TestTransportInfo(false, options, true);
3411}
3412
3413TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
3414 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003415 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3416 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3417 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003418 TestTransportInfo(false, options, false);
3419}
3420
3421TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003422 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003423 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003424 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3425 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3426 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003427 TestTransportInfo(false, options, true);
3428}
3429
3430TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
3431 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003432 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3433 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3434 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003435 options.bundle_enabled = true;
3436 TestTransportInfo(false, options, false);
3437}
3438
3439TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003440 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003441 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003442 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3443 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3444 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003445 options.bundle_enabled = true;
3446 TestTransportInfo(false, options, true);
3447}
3448
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07003449TEST_F(MediaSessionDescriptionFactoryTest,
3450 TestTransportInfoOfferBundlesTransportOptions) {
3451 MediaSessionOptions options;
3452 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3453
3454 cricket::OpaqueTransportParameters audio_params;
3455 audio_params.protocol = "audio-transport";
3456 audio_params.parameters = "audio-params";
3457 FindFirstMediaDescriptionByMid("audio", &options)
3458 ->transport_options.opaque_parameters = audio_params;
3459
3460 cricket::OpaqueTransportParameters video_params;
3461 video_params.protocol = "video-transport";
3462 video_params.parameters = "video-params";
3463 FindFirstMediaDescriptionByMid("video", &options)
3464 ->transport_options.opaque_parameters = video_params;
3465
3466 TestTransportInfo(/*offer=*/true, options, /*has_current_desc=*/false);
3467}
3468
3469TEST_F(MediaSessionDescriptionFactoryTest,
3470 TestTransportInfoAnswerBundlesTransportOptions) {
3471 MediaSessionOptions options;
3472 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3473
3474 cricket::OpaqueTransportParameters audio_params;
3475 audio_params.protocol = "audio-transport";
3476 audio_params.parameters = "audio-params";
3477 FindFirstMediaDescriptionByMid("audio", &options)
3478 ->transport_options.opaque_parameters = audio_params;
3479
3480 cricket::OpaqueTransportParameters video_params;
3481 video_params.protocol = "video-transport";
3482 video_params.parameters = "video-params";
3483 FindFirstMediaDescriptionByMid("video", &options)
3484 ->transport_options.opaque_parameters = video_params;
3485
3486 TestTransportInfo(/*offer=*/false, options, /*has_current_desc=*/false);
3487}
3488
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003489// Create an offer with bundle enabled and verify the crypto parameters are
3490// the common set of the available cryptos.
3491TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
3492 TestCryptoWithBundle(true);
3493}
3494
3495// Create an answer with bundle enabled and verify the crypto parameters are
3496// the common set of the available cryptos.
3497TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
3498 TestCryptoWithBundle(false);
3499}
3500
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003501// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
3502// DTLS is not enabled locally.
3503TEST_F(MediaSessionDescriptionFactoryTest,
3504 TestOfferDtlsSavpfWithoutDtlsFailed) {
3505 f1_.set_secure(SEC_ENABLED);
3506 f2_.set_secure(SEC_ENABLED);
3507 tdf1_.set_secure(SEC_DISABLED);
3508 tdf2_.set_secure(SEC_DISABLED);
3509
Steve Anton6fe1fba2018-12-11 10:15:23 -08003510 std::unique_ptr<SessionDescription> offer =
3511 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003512 ASSERT_TRUE(offer.get() != NULL);
3513 ContentInfo* offer_content = offer->GetContentByName("audio");
3514 ASSERT_TRUE(offer_content != NULL);
3515 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003516 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003517 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3518
Steve Anton6fe1fba2018-12-11 10:15:23 -08003519 std::unique_ptr<SessionDescription> answer =
3520 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003521 ASSERT_TRUE(answer != NULL);
3522 ContentInfo* answer_content = answer->GetContentByName("audio");
3523 ASSERT_TRUE(answer_content != NULL);
3524
3525 ASSERT_TRUE(answer_content->rejected);
3526}
3527
3528// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
3529// UDP/TLS/RTP/SAVPF.
3530TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
3531 f1_.set_secure(SEC_ENABLED);
3532 f2_.set_secure(SEC_ENABLED);
3533 tdf1_.set_secure(SEC_ENABLED);
3534 tdf2_.set_secure(SEC_ENABLED);
3535
Steve Anton6fe1fba2018-12-11 10:15:23 -08003536 std::unique_ptr<SessionDescription> offer =
3537 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003538 ASSERT_TRUE(offer.get() != NULL);
3539 ContentInfo* offer_content = offer->GetContentByName("audio");
3540 ASSERT_TRUE(offer_content != NULL);
3541 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003542 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003543 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3544
Steve Anton6fe1fba2018-12-11 10:15:23 -08003545 std::unique_ptr<SessionDescription> answer =
3546 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003547 ASSERT_TRUE(answer != NULL);
3548
3549 const ContentInfo* answer_content = answer->GetContentByName("audio");
3550 ASSERT_TRUE(answer_content != NULL);
3551 ASSERT_FALSE(answer_content->rejected);
3552
3553 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003554 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08003555 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003556}
3557
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003558// Test that we include both SDES and DTLS in the offer, but only include SDES
3559// in the answer if DTLS isn't negotiated.
3560TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
3561 f1_.set_secure(SEC_ENABLED);
3562 f2_.set_secure(SEC_ENABLED);
3563 tdf1_.set_secure(SEC_ENABLED);
3564 tdf2_.set_secure(SEC_DISABLED);
3565 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003566 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08003567 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003568 const cricket::MediaContentDescription* audio_media_desc;
3569 const cricket::MediaContentDescription* video_media_desc;
3570 const cricket::TransportDescription* audio_trans_desc;
3571 const cricket::TransportDescription* video_trans_desc;
3572
3573 // Generate an offer with SDES and DTLS support.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003574 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003575 ASSERT_TRUE(offer.get() != NULL);
3576
Steve Antonb1c1de12017-12-21 15:14:30 -08003577 audio_media_desc = offer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003578 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003579 video_media_desc = offer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003580 ASSERT_TRUE(video_media_desc != NULL);
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07003581 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003582 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3583
3584 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3585 ASSERT_TRUE(audio_trans_desc != NULL);
3586 video_trans_desc = offer->GetTransportDescriptionByName("video");
3587 ASSERT_TRUE(video_trans_desc != NULL);
3588 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3589 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3590
3591 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003592 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003593 ASSERT_TRUE(answer.get() != NULL);
3594
Steve Antonb1c1de12017-12-21 15:14:30 -08003595 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003596 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003597 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003598 ASSERT_TRUE(video_media_desc != NULL);
3599 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3600 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3601
3602 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3603 ASSERT_TRUE(audio_trans_desc != NULL);
3604 video_trans_desc = answer->GetTransportDescriptionByName("video");
3605 ASSERT_TRUE(video_trans_desc != NULL);
3606 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
3607 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
3608
3609 // Enable DTLS; the answer should now only have DTLS support.
3610 tdf2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003611 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003612 ASSERT_TRUE(answer.get() != NULL);
3613
Steve Antonb1c1de12017-12-21 15:14:30 -08003614 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003615 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003616 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003617 ASSERT_TRUE(video_media_desc != NULL);
3618 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3619 EXPECT_TRUE(video_media_desc->cryptos().empty());
Steve Antone38a5a12018-11-21 16:05:15 -08003620 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
3621 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003622
3623 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3624 ASSERT_TRUE(audio_trans_desc != NULL);
3625 video_trans_desc = answer->GetTransportDescriptionByName("video");
3626 ASSERT_TRUE(video_trans_desc != NULL);
3627 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3628 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003629
3630 // Try creating offer again. DTLS enabled now, crypto's should be empty
3631 // in new offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003632 offer = f1_.CreateOffer(options, offer.get());
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003633 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003634 audio_media_desc = offer->GetContentDescriptionByName("audio");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003635 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003636 video_media_desc = offer->GetContentDescriptionByName("video");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003637 ASSERT_TRUE(video_media_desc != NULL);
3638 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3639 EXPECT_TRUE(video_media_desc->cryptos().empty());
3640
3641 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3642 ASSERT_TRUE(audio_trans_desc != NULL);
3643 video_trans_desc = offer->GetTransportDescriptionByName("video");
3644 ASSERT_TRUE(video_trans_desc != NULL);
3645 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3646 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003647}
3648
3649// Test that an answer can't be created if cryptos are required but the offer is
3650// unsecure.
3651TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003652 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003653 f1_.set_secure(SEC_DISABLED);
3654 tdf1_.set_secure(SEC_DISABLED);
3655 f2_.set_secure(SEC_REQUIRED);
3656 tdf1_.set_secure(SEC_ENABLED);
3657
Steve Anton6fe1fba2018-12-11 10:15:23 -08003658 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003659 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003660 std::unique_ptr<SessionDescription> answer =
3661 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003662 EXPECT_TRUE(answer.get() == NULL);
3663}
3664
3665// Test that we accept a DTLS offer without SDES and create an appropriate
3666// answer.
3667TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
3668 f1_.set_secure(SEC_DISABLED);
3669 f2_.set_secure(SEC_ENABLED);
3670 tdf1_.set_secure(SEC_ENABLED);
3671 tdf2_.set_secure(SEC_ENABLED);
3672 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003673 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3674 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3675 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003676
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003677 // Generate an offer with DTLS but without SDES.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003678 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003679 ASSERT_TRUE(offer.get() != NULL);
3680
3681 const AudioContentDescription* audio_offer =
3682 GetFirstAudioContentDescription(offer.get());
3683 ASSERT_TRUE(audio_offer->cryptos().empty());
3684 const VideoContentDescription* video_offer =
3685 GetFirstVideoContentDescription(offer.get());
3686 ASSERT_TRUE(video_offer->cryptos().empty());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02003687 const RtpDataContentDescription* data_offer =
3688 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003689 ASSERT_TRUE(data_offer->cryptos().empty());
3690
3691 const cricket::TransportDescription* audio_offer_trans_desc =
3692 offer->GetTransportDescriptionByName("audio");
3693 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
3694 const cricket::TransportDescription* video_offer_trans_desc =
3695 offer->GetTransportDescriptionByName("video");
3696 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
3697 const cricket::TransportDescription* data_offer_trans_desc =
3698 offer->GetTransportDescriptionByName("data");
3699 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
3700
3701 // Generate an answer with DTLS.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003702 std::unique_ptr<SessionDescription> answer =
3703 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003704 ASSERT_TRUE(answer.get() != NULL);
3705
3706 const cricket::TransportDescription* audio_answer_trans_desc =
3707 answer->GetTransportDescriptionByName("audio");
3708 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3709 const cricket::TransportDescription* video_answer_trans_desc =
3710 answer->GetTransportDescriptionByName("video");
3711 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
3712 const cricket::TransportDescription* data_answer_trans_desc =
3713 answer->GetTransportDescriptionByName("data");
3714 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
3715}
3716
3717// Verifies if vad_enabled option is set to false, CN codecs are not present in
3718// offer or answer.
3719TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3720 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003721 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003722 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003723 ASSERT_TRUE(offer.get() != NULL);
3724 const ContentInfo* audio_content = offer->GetContentByName("audio");
3725 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
3726
3727 options.vad_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08003728 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003729 ASSERT_TRUE(offer.get() != NULL);
3730 audio_content = offer->GetContentByName("audio");
3731 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
Steve Anton6fe1fba2018-12-11 10:15:23 -08003732 std::unique_ptr<SessionDescription> answer =
3733 f1_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003734 ASSERT_TRUE(answer.get() != NULL);
3735 audio_content = answer->GetContentByName("audio");
3736 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
3737}
deadbeef44f08192015-12-15 16:20:09 -08003738
zhihuang1c378ed2017-08-17 14:10:50 -07003739// Test that the generated MIDs match the existing offer.
3740TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08003741 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003742 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_modified",
3743 RtpTransceiverDirection::kRecvOnly, kActive,
3744 &opts);
3745 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_modified",
3746 RtpTransceiverDirection::kRecvOnly, kActive,
3747 &opts);
deadbeef44f08192015-12-15 16:20:09 -08003748 opts.data_channel_type = cricket::DCT_SCTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003749 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data_modified",
3750 RtpTransceiverDirection::kSendRecv, kActive,
3751 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003752 // Create offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003753 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
kwiberg31022942016-03-11 14:18:21 -08003754 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08003755 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003756
deadbeef44f08192015-12-15 16:20:09 -08003757 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3758 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3759 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3760 ASSERT_TRUE(audio_content != nullptr);
3761 ASSERT_TRUE(video_content != nullptr);
3762 ASSERT_TRUE(data_content != nullptr);
3763 EXPECT_EQ("audio_modified", audio_content->name);
3764 EXPECT_EQ("video_modified", video_content->name);
3765 EXPECT_EQ("data_modified", data_content->name);
3766}
zhihuangcf5b37c2016-05-05 11:44:35 -07003767
zhihuang1c378ed2017-08-17 14:10:50 -07003768// The following tests verify that the unified plan SDP is supported.
3769// Test that we can create an offer with multiple media sections of same media
3770// type.
3771TEST_F(MediaSessionDescriptionFactoryTest,
3772 CreateOfferWithMultipleAVMediaSections) {
3773 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003774 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3775 RtpTransceiverDirection::kSendRecv, kActive,
3776 &opts);
3777 AttachSenderToMediaDescriptionOptions(
3778 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003779
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003780 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3781 RtpTransceiverDirection::kSendRecv, kActive,
3782 &opts);
3783 AttachSenderToMediaDescriptionOptions(
3784 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003785
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003786 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3787 RtpTransceiverDirection::kSendRecv, kActive,
3788 &opts);
3789 AttachSenderToMediaDescriptionOptions(
3790 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003791
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003792 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3793 RtpTransceiverDirection::kSendRecv, kActive,
3794 &opts);
3795 AttachSenderToMediaDescriptionOptions(
3796 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003797 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003798 ASSERT_TRUE(offer);
3799
3800 ASSERT_EQ(4u, offer->contents().size());
3801 EXPECT_FALSE(offer->contents()[0].rejected);
3802 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003803 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003804 ASSERT_EQ(1u, acd->streams().size());
3805 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003806 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003807
3808 EXPECT_FALSE(offer->contents()[1].rejected);
3809 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003810 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003811 ASSERT_EQ(1u, vcd->streams().size());
3812 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003813 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003814
3815 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003816 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003817 ASSERT_EQ(1u, acd->streams().size());
3818 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003819 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003820
3821 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003822 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003823 ASSERT_EQ(1u, vcd->streams().size());
3824 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003825 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003826}
3827
3828// Test that we can create an answer with multiple media sections of same media
3829// type.
3830TEST_F(MediaSessionDescriptionFactoryTest,
3831 CreateAnswerWithMultipleAVMediaSections) {
3832 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003833 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3834 RtpTransceiverDirection::kSendRecv, kActive,
3835 &opts);
3836 AttachSenderToMediaDescriptionOptions(
3837 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003838
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003839 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3840 RtpTransceiverDirection::kSendRecv, kActive,
3841 &opts);
3842 AttachSenderToMediaDescriptionOptions(
3843 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003844
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003845 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3846 RtpTransceiverDirection::kSendRecv, kActive,
3847 &opts);
3848 AttachSenderToMediaDescriptionOptions(
3849 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003850
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003851 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3852 RtpTransceiverDirection::kSendRecv, kActive,
3853 &opts);
3854 AttachSenderToMediaDescriptionOptions(
3855 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003856
Steve Anton6fe1fba2018-12-11 10:15:23 -08003857 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003858 ASSERT_TRUE(offer);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003859 std::unique_ptr<SessionDescription> answer =
3860 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003861
3862 ASSERT_EQ(4u, answer->contents().size());
3863 EXPECT_FALSE(answer->contents()[0].rejected);
3864 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003865 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003866 ASSERT_EQ(1u, acd->streams().size());
3867 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003868 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003869
3870 EXPECT_FALSE(answer->contents()[1].rejected);
3871 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003872 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003873 ASSERT_EQ(1u, vcd->streams().size());
3874 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003875 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003876
3877 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003878 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003879 ASSERT_EQ(1u, acd->streams().size());
3880 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003881 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003882
3883 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003884 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003885 ASSERT_EQ(1u, vcd->streams().size());
3886 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003887 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003888}
3889
3890// Test that the media section will be rejected in offer if the corresponding
3891// MediaDescriptionOptions is stopped by the offerer.
3892TEST_F(MediaSessionDescriptionFactoryTest,
3893 CreateOfferWithMediaSectionStoppedByOfferer) {
3894 // Create an offer with two audio sections and one of them is stopped.
3895 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003896 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3897 RtpTransceiverDirection::kSendRecv, kActive,
3898 &offer_opts);
3899 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3900 RtpTransceiverDirection::kInactive, kStopped,
3901 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003902 std::unique_ptr<SessionDescription> offer =
3903 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003904 ASSERT_TRUE(offer);
3905 ASSERT_EQ(2u, offer->contents().size());
3906 EXPECT_FALSE(offer->contents()[0].rejected);
3907 EXPECT_TRUE(offer->contents()[1].rejected);
3908}
3909
3910// Test that the media section will be rejected in answer if the corresponding
3911// MediaDescriptionOptions is stopped by the offerer.
3912TEST_F(MediaSessionDescriptionFactoryTest,
3913 CreateAnswerWithMediaSectionStoppedByOfferer) {
3914 // Create an offer with two audio sections and one of them is stopped.
3915 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003916 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3917 RtpTransceiverDirection::kSendRecv, kActive,
3918 &offer_opts);
3919 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3920 RtpTransceiverDirection::kInactive, kStopped,
3921 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003922 std::unique_ptr<SessionDescription> offer =
3923 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003924 ASSERT_TRUE(offer);
3925 ASSERT_EQ(2u, offer->contents().size());
3926 EXPECT_FALSE(offer->contents()[0].rejected);
3927 EXPECT_TRUE(offer->contents()[1].rejected);
3928
3929 // Create an answer based on the offer.
3930 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003931 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3932 RtpTransceiverDirection::kSendRecv, kActive,
3933 &answer_opts);
3934 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3935 RtpTransceiverDirection::kSendRecv, kActive,
3936 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003937 std::unique_ptr<SessionDescription> answer =
3938 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003939 ASSERT_EQ(2u, answer->contents().size());
3940 EXPECT_FALSE(answer->contents()[0].rejected);
3941 EXPECT_TRUE(answer->contents()[1].rejected);
3942}
3943
3944// Test that the media section will be rejected in answer if the corresponding
3945// MediaDescriptionOptions is stopped by the answerer.
3946TEST_F(MediaSessionDescriptionFactoryTest,
3947 CreateAnswerWithMediaSectionRejectedByAnswerer) {
3948 // Create an offer with two audio sections.
3949 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003950 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3951 RtpTransceiverDirection::kSendRecv, kActive,
3952 &offer_opts);
3953 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3954 RtpTransceiverDirection::kSendRecv, kActive,
3955 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003956 std::unique_ptr<SessionDescription> offer =
3957 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003958 ASSERT_TRUE(offer);
3959 ASSERT_EQ(2u, offer->contents().size());
3960 ASSERT_FALSE(offer->contents()[0].rejected);
3961 ASSERT_FALSE(offer->contents()[1].rejected);
3962
3963 // The answerer rejects one of the audio sections.
3964 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003965 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3966 RtpTransceiverDirection::kSendRecv, kActive,
3967 &answer_opts);
3968 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3969 RtpTransceiverDirection::kInactive, kStopped,
3970 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003971 std::unique_ptr<SessionDescription> answer =
3972 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003973 ASSERT_EQ(2u, answer->contents().size());
3974 EXPECT_FALSE(answer->contents()[0].rejected);
3975 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08003976
3977 // The TransportInfo of the rejected m= section is expected to be added in the
3978 // answer.
3979 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07003980}
3981
3982// Test the generated media sections has the same order of the
3983// corresponding MediaDescriptionOptions.
3984TEST_F(MediaSessionDescriptionFactoryTest,
3985 CreateOfferRespectsMediaDescriptionOptionsOrder) {
3986 MediaSessionOptions opts;
3987 // This tests put video section first because normally audio comes first by
3988 // default.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003989 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3990 RtpTransceiverDirection::kSendRecv, kActive,
3991 &opts);
3992 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3993 RtpTransceiverDirection::kSendRecv, kActive,
3994 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003995 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003996
3997 ASSERT_TRUE(offer);
3998 ASSERT_EQ(2u, offer->contents().size());
3999 EXPECT_EQ("video", offer->contents()[0].name);
4000 EXPECT_EQ("audio", offer->contents()[1].name);
4001}
4002
4003// Test that different media sections using the same codec have same payload
4004// type.
4005TEST_F(MediaSessionDescriptionFactoryTest,
4006 PayloadTypesSharedByMediaSectionsOfSameType) {
4007 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004008 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4009 RtpTransceiverDirection::kSendRecv, kActive,
4010 &opts);
4011 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4012 RtpTransceiverDirection::kSendRecv, kActive,
4013 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004014 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004015 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004016 ASSERT_TRUE(offer);
4017 ASSERT_EQ(2u, offer->contents().size());
4018 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004019 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004020 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004021 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004022 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4023 ASSERT_EQ(2u, vcd1->codecs().size());
4024 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4025 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4026 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
4027 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
4028
4029 // Create answer and negotiate the codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004030 std::unique_ptr<SessionDescription> answer =
4031 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004032 ASSERT_TRUE(answer);
4033 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08004034 vcd1 = answer->contents()[0].media_description()->as_video();
4035 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004036 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4037 ASSERT_EQ(1u, vcd1->codecs().size());
4038 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4039 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4040}
4041
4042// Test that the codec preference order per media section is respected in
4043// subsequent offer.
4044TEST_F(MediaSessionDescriptionFactoryTest,
4045 CreateOfferRespectsCodecPreferenceOrder) {
4046 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004047 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4048 RtpTransceiverDirection::kSendRecv, kActive,
4049 &opts);
4050 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4051 RtpTransceiverDirection::kSendRecv, kActive,
4052 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004053 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004054 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004055 ASSERT_TRUE(offer);
4056 ASSERT_EQ(2u, offer->contents().size());
4057 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004058 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004059 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004060 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004061 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4062 EXPECT_EQ(video_codecs, vcd1->codecs());
4063 EXPECT_EQ(video_codecs, vcd2->codecs());
4064
4065 // Change the codec preference of the first video section and create a
4066 // follow-up offer.
4067 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4068 vcd1->set_codecs(video_codecs_reverse);
4069 std::unique_ptr<SessionDescription> updated_offer(
4070 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08004071 vcd1 = updated_offer->contents()[0].media_description()->as_video();
4072 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004073 // The video codec preference order should be respected.
4074 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4075 EXPECT_EQ(video_codecs, vcd2->codecs());
4076}
4077
4078// Test that the codec preference order per media section is respected in
4079// the answer.
4080TEST_F(MediaSessionDescriptionFactoryTest,
4081 CreateAnswerRespectsCodecPreferenceOrder) {
4082 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004083 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4084 RtpTransceiverDirection::kSendRecv, kActive,
4085 &opts);
4086 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4087 RtpTransceiverDirection::kSendRecv, kActive,
4088 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004089 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004090 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004091 ASSERT_TRUE(offer);
4092 ASSERT_EQ(2u, offer->contents().size());
4093 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004094 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004095 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004096 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004097 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4098 EXPECT_EQ(video_codecs, vcd1->codecs());
4099 EXPECT_EQ(video_codecs, vcd2->codecs());
4100
4101 // Change the codec preference of the first video section and create an
4102 // answer.
4103 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4104 vcd1->set_codecs(video_codecs_reverse);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004105 std::unique_ptr<SessionDescription> answer =
4106 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08004107 vcd1 = answer->contents()[0].media_description()->as_video();
4108 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004109 // The video codec preference order should be respected.
4110 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4111 EXPECT_EQ(video_codecs, vcd2->codecs());
4112}
4113
Zhi Huang6f367472017-11-22 13:20:02 -08004114// Test that when creating an answer, the codecs use local parameters instead of
4115// the remote ones.
4116TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
4117 const std::string audio_param_name = "audio_param";
4118 const std::string audio_value1 = "audio_v1";
4119 const std::string audio_value2 = "audio_v2";
4120 const std::string video_param_name = "video_param";
4121 const std::string video_value1 = "video_v1";
4122 const std::string video_value2 = "video_v2";
4123
4124 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
4125 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
4126 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
4127 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
4128
4129 // Set the parameters for codecs.
4130 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
4131 video_codecs1[0].SetParam(video_param_name, video_value1);
4132 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
4133 video_codecs2[0].SetParam(video_param_name, video_value2);
4134
4135 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
4136 f1_.set_video_codecs(video_codecs1);
4137 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
4138 f2_.set_video_codecs(video_codecs2);
4139
4140 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004141 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4142 RtpTransceiverDirection::kSendRecv, kActive,
4143 &opts);
4144 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4145 RtpTransceiverDirection::kSendRecv, kActive,
4146 &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08004147
Steve Anton6fe1fba2018-12-11 10:15:23 -08004148 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004149 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004150 auto offer_acd = offer->contents()[0].media_description()->as_audio();
4151 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004152 std::string value;
4153 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
4154 EXPECT_EQ(audio_value1, value);
4155 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
4156 EXPECT_EQ(video_value1, value);
4157
Steve Anton6fe1fba2018-12-11 10:15:23 -08004158 std::unique_ptr<SessionDescription> answer =
4159 f2_.CreateAnswer(offer.get(), opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004160 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004161 auto answer_acd = answer->contents()[0].media_description()->as_audio();
4162 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004163 // Use the parameters from the local codecs.
4164 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
4165 EXPECT_EQ(audio_value2, value);
4166 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
4167 EXPECT_EQ(video_value2, value);
4168}
4169
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004170// Test that matching packetization-mode is part of the criteria for matching
4171// H264 codecs (in addition to profile-level-id). Previously, this was not the
4172// case, so the first H264 codec with the same profile-level-id would match and
4173// the payload type in the answer would be incorrect.
4174// This is a regression test for bugs.webrtc.org/8808
4175TEST_F(MediaSessionDescriptionFactoryTest,
4176 H264MatchCriteriaIncludesPacketizationMode) {
4177 // Create two H264 codecs with the same profile level ID and different
4178 // packetization modes.
4179 VideoCodec h264_pm0(96, "H264");
4180 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4181 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
4182 VideoCodec h264_pm1(97, "H264");
4183 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4184 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
4185
4186 // Offerer will send both codecs, answerer should choose the one with matching
4187 // packetization mode (and not the first one it sees).
4188 f1_.set_video_codecs({h264_pm0, h264_pm1});
4189 f2_.set_video_codecs({h264_pm1});
4190
4191 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004192 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4193 RtpTransceiverDirection::kSendRecv, kActive,
4194 &opts);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004195
Steve Anton6fe1fba2018-12-11 10:15:23 -08004196 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004197 ASSERT_TRUE(offer);
4198
Steve Anton6fe1fba2018-12-11 10:15:23 -08004199 std::unique_ptr<SessionDescription> answer =
4200 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004201 ASSERT_TRUE(answer);
4202
4203 // Answer should have one negotiated codec with packetization-mode=1 using the
4204 // offered payload type.
4205 ASSERT_EQ(1u, answer->contents().size());
4206 auto answer_vcd = answer->contents()[0].media_description()->as_video();
4207 ASSERT_EQ(1u, answer_vcd->codecs().size());
4208 auto answer_codec = answer_vcd->codecs()[0];
4209 EXPECT_EQ(h264_pm1.id, answer_codec.id);
4210}
4211
zhihuangcf5b37c2016-05-05 11:44:35 -07004212class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
4213 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004214 MediaProtocolTest()
4215 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -07004216 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
4217 MAKE_VECTOR(kAudioCodecs1));
zhihuangcf5b37c2016-05-05 11:44:35 -07004218 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004219 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07004220 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
4221 MAKE_VECTOR(kAudioCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07004222 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004223 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07004224 f1_.set_secure(SEC_ENABLED);
4225 f2_.set_secure(SEC_ENABLED);
4226 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004227 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004228 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004229 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004230 tdf1_.set_secure(SEC_ENABLED);
4231 tdf2_.set_secure(SEC_ENABLED);
4232 }
4233
4234 protected:
4235 MediaSessionDescriptionFactory f1_;
4236 MediaSessionDescriptionFactory f2_;
4237 TransportDescriptionFactory tdf1_;
4238 TransportDescriptionFactory tdf2_;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004239 UniqueRandomIdGenerator ssrc_generator1;
4240 UniqueRandomIdGenerator ssrc_generator2;
zhihuangcf5b37c2016-05-05 11:44:35 -07004241};
4242
4243TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
4244 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08004245 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004246 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004247 ASSERT_TRUE(offer.get() != nullptr);
4248 // Set the protocol for all the contents.
Harald Alvestrand1716d392019-06-03 20:35:45 +02004249 for (auto& content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004250 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07004251 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004252 std::unique_ptr<SessionDescription> answer =
4253 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004254 const ContentInfo* ac = answer->GetContentByName("audio");
4255 const ContentInfo* vc = answer->GetContentByName("video");
4256 ASSERT_TRUE(ac != nullptr);
4257 ASSERT_TRUE(vc != nullptr);
4258 EXPECT_FALSE(ac->rejected); // the offer is accepted
4259 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004260 const AudioContentDescription* acd = ac->media_description()->as_audio();
4261 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07004262 EXPECT_EQ(GetParam(), acd->protocol());
4263 EXPECT_EQ(GetParam(), vcd->protocol());
4264}
4265
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004266INSTANTIATE_TEST_SUITE_P(MediaProtocolPatternTest,
4267 MediaProtocolTest,
4268 ::testing::ValuesIn(kMediaProtocols));
4269INSTANTIATE_TEST_SUITE_P(MediaProtocolDtlsPatternTest,
4270 MediaProtocolTest,
4271 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07004272
4273TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
4274 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004275 UniqueRandomIdGenerator ssrc_generator;
4276 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004277 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4278 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4279
4280 // The merged list of codecs should contain any send codecs that are also
4281 // nominally in the recieve codecs list. Payload types should be picked from
4282 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
4283 // (set to 1). This equals what happens when the send codecs are used in an
4284 // offer and the receive codecs are used in the following answer.
4285 const std::vector<AudioCodec> sendrecv_codecs =
4286 MAKE_VECTOR(kAudioCodecsAnswer);
4287 const std::vector<AudioCodec> no_codecs;
4288
4289 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
4290 << "Please don't change shared test data!";
4291 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
4292 << "Please don't change shared test data!";
4293 // Alter iLBC send codec to have zero channels, to test that that is handled
4294 // properly.
4295 send_codecs[1].channels = 0;
4296
4297 // Alther iLBC receive codec to be lowercase, to test that case conversions
4298 // are handled properly.
4299 recv_codecs[2].name = "ilbc";
4300
4301 // Test proper merge
4302 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004303 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4304 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4305 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004306
4307 // Test empty send codecs list
4308 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004309 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4310 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4311 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004312
4313 // Test empty recv codecs list
4314 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004315 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4316 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4317 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004318
4319 // Test all empty codec lists
4320 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004321 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4322 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4323 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004324}
4325
Amit Hilbuch77938e62018-12-21 09:23:38 -08004326// Checks that the RID extensions are added to the video RTP header extensions.
4327// Note: This test somewhat shows that |set_video_rtp_header_extensions()| is
4328// not very well defined, as calling set() and immediately get() will yield
4329// an object that is not semantically equivalent to the set object.
4330TEST_F(MediaSessionDescriptionFactoryTest, VideoHasRidExtensionsInUnifiedPlan) {
4331 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004332 UniqueRandomIdGenerator ssrc_generator;
4333 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
Amit Hilbuch77938e62018-12-21 09:23:38 -08004334 sf.set_is_unified_plan(true);
4335 cricket::RtpHeaderExtensions extensions;
4336 sf.set_video_rtp_header_extensions(extensions);
4337 cricket::RtpHeaderExtensions result = sf.video_rtp_header_extensions();
4338 // Check to see that RID extensions were added to the extension list
4339 EXPECT_GE(result.size(), 2u);
Steve Anton64b626b2019-01-28 17:25:26 -08004340 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
Elad Alon157540a2019-02-08 23:37:52 +01004341 RtpExtension::kMidUri)));
4342 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
Steve Anton64b626b2019-01-28 17:25:26 -08004343 RtpExtension::kRidUri)));
4344 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
4345 RtpExtension::kRepairedRidUri)));
Amit Hilbuch77938e62018-12-21 09:23:38 -08004346}
4347
4348// Checks that the RID extensions are added to the audio RTP header extensions.
4349// Note: This test somewhat shows that |set_audio_rtp_header_extensions()| is
4350// not very well defined, as calling set() and immediately get() will yield
4351// an object that is not semantically equivalent to the set object.
4352TEST_F(MediaSessionDescriptionFactoryTest, AudioHasRidExtensionsInUnifiedPlan) {
4353 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004354 UniqueRandomIdGenerator ssrc_generator;
4355 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
Amit Hilbuch77938e62018-12-21 09:23:38 -08004356 sf.set_is_unified_plan(true);
4357 cricket::RtpHeaderExtensions extensions;
4358 sf.set_audio_rtp_header_extensions(extensions);
4359 cricket::RtpHeaderExtensions result = sf.audio_rtp_header_extensions();
4360 // Check to see that RID extensions were added to the extension list
4361 EXPECT_GE(result.size(), 2u);
Steve Anton64b626b2019-01-28 17:25:26 -08004362 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
Elad Alon157540a2019-02-08 23:37:52 +01004363 RtpExtension::kMidUri)));
4364 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
Steve Anton64b626b2019-01-28 17:25:26 -08004365 RtpExtension::kRidUri)));
4366 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
4367 RtpExtension::kRepairedRidUri)));
Amit Hilbuch77938e62018-12-21 09:23:38 -08004368}
4369
ossu075af922016-06-14 03:29:38 -07004370namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07004371// Compare the two vectors of codecs ignoring the payload type.
4372template <class Codec>
4373bool CodecsMatch(const std::vector<Codec>& codecs1,
4374 const std::vector<Codec>& codecs2) {
4375 if (codecs1.size() != codecs2.size()) {
4376 return false;
4377 }
4378
4379 for (size_t i = 0; i < codecs1.size(); ++i) {
4380 if (!codecs1[i].Matches(codecs2[i])) {
4381 return false;
4382 }
4383 }
4384 return true;
4385}
4386
Steve Anton4e70a722017-11-28 14:57:10 -08004387void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07004388 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004389 UniqueRandomIdGenerator ssrc_generator;
4390 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004391 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4392 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4393 const std::vector<AudioCodec> sendrecv_codecs =
4394 MAKE_VECTOR(kAudioCodecsAnswer);
4395 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07004396
4397 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004398 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
4399 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004400
Steve Anton4e70a722017-11-28 14:57:10 -08004401 if (direction == RtpTransceiverDirection::kSendRecv ||
4402 direction == RtpTransceiverDirection::kSendOnly) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004403 AttachSenderToMediaDescriptionOptions(
4404 "audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004405 }
ossu075af922016-06-14 03:29:38 -07004406
Steve Anton6fe1fba2018-12-11 10:15:23 -08004407 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
ossu075af922016-06-14 03:29:38 -07004408 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004409 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07004410
4411 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07004412 // that the codecs put in are right. This happens when we neither want to
4413 // send nor receive audio. The checks are still in place if at some point
4414 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004415 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004416 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004417 // sendrecv and inactive should both present lists as if the channel was
4418 // to be used for sending and receiving. Inactive essentially means it
4419 // might eventually be used anything, but we don't know more at this
4420 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08004421 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004422 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08004423 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004424 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004425 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07004426 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004427 }
4428 }
4429}
4430
4431static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07004432 AudioCodec(0, "codec0", 16000, -1, 1),
4433 AudioCodec(1, "codec1", 8000, 13300, 1),
4434 AudioCodec(2, "codec2", 8000, 64000, 1),
4435 AudioCodec(3, "codec3", 8000, 64000, 1),
4436 AudioCodec(4, "codec4", 8000, 0, 2),
4437 AudioCodec(5, "codec5", 32000, 0, 1),
4438 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07004439
zhihuang1c378ed2017-08-17 14:10:50 -07004440/* The codecs groups below are chosen as per the matrix below. The objective
4441 * is to have different sets of codecs in the inputs, to get unique sets of
4442 * codecs after negotiation, depending on offer and answer communication
4443 * directions. One-way directions in the offer should either result in the
4444 * opposite direction in the answer, or an inactive answer. Regardless, the
4445 * choice of codecs should be as if the answer contained the opposite
4446 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07004447 *
4448 * | Offer | Answer | Result
4449 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
4450 * 0 | x - - | - x - | x - - - -
4451 * 1 | x x x | - x - | x - - x -
4452 * 2 | - x - | x - - | - x - - -
4453 * 3 | x x x | x - - | - x x - -
4454 * 4 | - x - | x x x | - x - - -
4455 * 5 | x - - | x x x | x - - - -
4456 * 6 | x x x | x x x | x x x x x
4457 */
4458// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004459static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
4460static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07004461// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
4462// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07004463static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
4464static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07004465// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004466static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
4467static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
4468static const int kResultSendrecv_SendCodecs[] = {3, 6};
4469static const int kResultSendrecv_RecvCodecs[] = {1, 6};
4470static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07004471
4472template <typename T, int IDXS>
4473std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
4474 std::vector<T> out;
4475 out.reserve(IDXS);
4476 for (int idx : indices)
4477 out.push_back(array[idx]);
4478
4479 return out;
4480}
4481
Steve Anton4e70a722017-11-28 14:57:10 -08004482void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
4483 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07004484 bool add_legacy_stream) {
4485 TransportDescriptionFactory offer_tdf;
4486 TransportDescriptionFactory answer_tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004487 UniqueRandomIdGenerator ssrc_generator1, ssrc_generator2;
4488 MediaSessionDescriptionFactory offer_factory(&offer_tdf, &ssrc_generator1);
4489 MediaSessionDescriptionFactory answer_factory(&answer_tdf, &ssrc_generator2);
ossu075af922016-06-14 03:29:38 -07004490 offer_factory.set_audio_codecs(
4491 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
4492 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
4493 answer_factory.set_audio_codecs(
4494 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
4495 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
4496
ossu075af922016-06-14 03:29:38 -07004497 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004498 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", offer_direction,
4499 kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004500
Steve Anton4e70a722017-11-28 14:57:10 -08004501 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004502 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4503 kAudioTrack1, {kMediaStream1}, 1,
4504 &offer_opts);
ossu075af922016-06-14 03:29:38 -07004505 }
4506
Steve Anton6fe1fba2018-12-11 10:15:23 -08004507 std::unique_ptr<SessionDescription> offer =
4508 offer_factory.CreateOffer(offer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004509 ASSERT_TRUE(offer.get() != NULL);
4510
4511 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004512 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", answer_direction,
4513 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004514
Steve Anton4e70a722017-11-28 14:57:10 -08004515 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004516 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4517 kAudioTrack1, {kMediaStream1}, 1,
4518 &answer_opts);
ossu075af922016-06-14 03:29:38 -07004519 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004520 std::unique_ptr<SessionDescription> answer =
4521 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004522 const ContentInfo* ac = answer->GetContentByName("audio");
4523
zhihuang1c378ed2017-08-17 14:10:50 -07004524 // If the factory didn't add any audio content to the answer, we cannot
4525 // check that the codecs put in are right. This happens when we neither want
4526 // to send nor receive audio. The checks are still in place if at some point
4527 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004528 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004529 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
4530 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07004531
ossu075af922016-06-14 03:29:38 -07004532 std::vector<AudioCodec> target_codecs;
4533 // For offers with sendrecv or inactive, we should never reply with more
4534 // codecs than offered, with these codec sets.
4535 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08004536 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07004537 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4538 kResultSendrecv_SendrecvCodecs);
4539 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004540 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004541 target_codecs =
4542 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004543 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004544 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004545 target_codecs =
4546 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07004547 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004548 case RtpTransceiverDirection::kSendRecv:
4549 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004550 target_codecs =
4551 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08004552 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004553 target_codecs =
4554 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004555 } else {
4556 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4557 kResultSendrecv_SendrecvCodecs);
4558 }
4559 break;
4560 }
4561
zhihuang1c378ed2017-08-17 14:10:50 -07004562 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02004563 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07004564 bool first = true;
4565 os << "{";
4566 for (const auto& c : codecs) {
4567 os << (first ? " " : ", ") << c.id;
4568 first = false;
4569 }
4570 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02004571 return os.Release();
ossu075af922016-06-14 03:29:38 -07004572 };
4573
4574 EXPECT_TRUE(acd->codecs() == target_codecs)
4575 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08004576 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
4577 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07004578 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08004579 << webrtc::RtpTransceiverDirectionToString(answer_direction)
4580 << "; got: "
4581 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07004582 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08004583 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07004584 << "Only inactive offers are allowed to not generate any audio "
4585 "content";
ossu075af922016-06-14 03:29:38 -07004586 }
4587}
brandtr03d5fb12016-11-22 03:37:59 -08004588
4589} // namespace
ossu075af922016-06-14 03:29:38 -07004590
4591class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08004592 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07004593
4594TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004595 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07004596}
4597
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004598INSTANTIATE_TEST_SUITE_P(MediaSessionDescriptionFactoryTest,
4599 AudioCodecsOfferTest,
4600 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4601 RtpTransceiverDirection::kRecvOnly,
4602 RtpTransceiverDirection::kSendRecv,
4603 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07004604
4605class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08004606 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
4607 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07004608 bool>> {};
ossu075af922016-06-14 03:29:38 -07004609
4610TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08004611 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
4612 ::testing::get<1>(GetParam()),
4613 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07004614}
4615
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004616INSTANTIATE_TEST_SUITE_P(
zhihuang1c378ed2017-08-17 14:10:50 -07004617 MediaSessionDescriptionFactoryTest,
4618 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004619 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
4620 RtpTransceiverDirection::kRecvOnly,
4621 RtpTransceiverDirection::kSendRecv,
4622 RtpTransceiverDirection::kInactive),
4623 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4624 RtpTransceiverDirection::kRecvOnly,
4625 RtpTransceiverDirection::kSendRecv,
4626 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07004627 ::testing::Bool()));