blob: a2416c4dccc8cf3a7b1908f0165f78af8cf89dcd [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
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -07003489TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolAddedToOffer) {
3490 MediaSessionOptions options;
3491 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3492 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3493 &options);
3494
3495 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3496 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3497 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3498
3499 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3500
3501 EXPECT_EQ(offer->GetContentDescriptionByName("audio")->alt_protocol(), "foo");
3502 EXPECT_EQ(offer->GetContentDescriptionByName("video")->alt_protocol(), "bar");
3503 EXPECT_EQ(offer->GetContentDescriptionByName("data")->alt_protocol(), "baz");
3504}
3505
3506TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolAddedToAnswer) {
3507 MediaSessionOptions options;
3508 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3509 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3510 &options);
3511
3512 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3513 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3514 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3515
3516 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3517 std::unique_ptr<SessionDescription> answer =
3518 f1_.CreateAnswer(offer.get(), options, nullptr);
3519
3520 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3521 "foo");
3522 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3523 "bar");
3524 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(), "baz");
3525}
3526
3527TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolNotInOffer) {
3528 MediaSessionOptions options;
3529 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3530 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3531 &options);
3532
3533 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3534
3535 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3536 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3537 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3538
3539 std::unique_ptr<SessionDescription> answer =
3540 f1_.CreateAnswer(offer.get(), options, nullptr);
3541
3542 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3543 absl::nullopt);
3544 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3545 absl::nullopt);
3546 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(),
3547 absl::nullopt);
3548}
3549
3550TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolDifferentInOffer) {
3551 MediaSessionOptions options;
3552 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3553 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3554 &options);
3555
3556 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "not-foo";
3557 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "not-bar";
3558 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "not-baz";
3559
3560 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3561
3562 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3563 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3564 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3565
3566 std::unique_ptr<SessionDescription> answer =
3567 f1_.CreateAnswer(offer.get(), options, nullptr);
3568
3569 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3570 absl::nullopt);
3571 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3572 absl::nullopt);
3573 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(),
3574 absl::nullopt);
3575}
3576
3577TEST_F(MediaSessionDescriptionFactoryTest, AltProtocolNotInAnswer) {
3578 MediaSessionOptions options;
3579 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3580 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kRecvOnly,
3581 &options);
3582
3583 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol = "foo";
3584 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol = "bar";
3585 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol = "baz";
3586
3587 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, nullptr);
3588
3589 FindFirstMediaDescriptionByMid("audio", &options)->alt_protocol =
3590 absl::nullopt;
3591 FindFirstMediaDescriptionByMid("video", &options)->alt_protocol =
3592 absl::nullopt;
3593 FindFirstMediaDescriptionByMid("data", &options)->alt_protocol =
3594 absl::nullopt;
3595
3596 std::unique_ptr<SessionDescription> answer =
3597 f1_.CreateAnswer(offer.get(), options, nullptr);
3598
3599 EXPECT_EQ(answer->GetContentDescriptionByName("audio")->alt_protocol(),
3600 absl::nullopt);
3601 EXPECT_EQ(answer->GetContentDescriptionByName("video")->alt_protocol(),
3602 absl::nullopt);
3603 EXPECT_EQ(answer->GetContentDescriptionByName("data")->alt_protocol(),
3604 absl::nullopt);
3605}
3606
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003607// Create an offer with bundle enabled and verify the crypto parameters are
3608// the common set of the available cryptos.
3609TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
3610 TestCryptoWithBundle(true);
3611}
3612
3613// Create an answer with bundle enabled and verify the crypto parameters are
3614// the common set of the available cryptos.
3615TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
3616 TestCryptoWithBundle(false);
3617}
3618
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003619// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
3620// DTLS is not enabled locally.
3621TEST_F(MediaSessionDescriptionFactoryTest,
3622 TestOfferDtlsSavpfWithoutDtlsFailed) {
3623 f1_.set_secure(SEC_ENABLED);
3624 f2_.set_secure(SEC_ENABLED);
3625 tdf1_.set_secure(SEC_DISABLED);
3626 tdf2_.set_secure(SEC_DISABLED);
3627
Steve Anton6fe1fba2018-12-11 10:15:23 -08003628 std::unique_ptr<SessionDescription> offer =
3629 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003630 ASSERT_TRUE(offer.get() != NULL);
3631 ContentInfo* offer_content = offer->GetContentByName("audio");
3632 ASSERT_TRUE(offer_content != NULL);
3633 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003634 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003635 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3636
Steve Anton6fe1fba2018-12-11 10:15:23 -08003637 std::unique_ptr<SessionDescription> answer =
3638 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003639 ASSERT_TRUE(answer != NULL);
3640 ContentInfo* answer_content = answer->GetContentByName("audio");
3641 ASSERT_TRUE(answer_content != NULL);
3642
3643 ASSERT_TRUE(answer_content->rejected);
3644}
3645
3646// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
3647// UDP/TLS/RTP/SAVPF.
3648TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
3649 f1_.set_secure(SEC_ENABLED);
3650 f2_.set_secure(SEC_ENABLED);
3651 tdf1_.set_secure(SEC_ENABLED);
3652 tdf2_.set_secure(SEC_ENABLED);
3653
Steve Anton6fe1fba2018-12-11 10:15:23 -08003654 std::unique_ptr<SessionDescription> offer =
3655 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003656 ASSERT_TRUE(offer.get() != NULL);
3657 ContentInfo* offer_content = offer->GetContentByName("audio");
3658 ASSERT_TRUE(offer_content != NULL);
3659 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003660 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003661 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3662
Steve Anton6fe1fba2018-12-11 10:15:23 -08003663 std::unique_ptr<SessionDescription> answer =
3664 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003665 ASSERT_TRUE(answer != NULL);
3666
3667 const ContentInfo* answer_content = answer->GetContentByName("audio");
3668 ASSERT_TRUE(answer_content != NULL);
3669 ASSERT_FALSE(answer_content->rejected);
3670
3671 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003672 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08003673 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003674}
3675
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003676// Test that we include both SDES and DTLS in the offer, but only include SDES
3677// in the answer if DTLS isn't negotiated.
3678TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
3679 f1_.set_secure(SEC_ENABLED);
3680 f2_.set_secure(SEC_ENABLED);
3681 tdf1_.set_secure(SEC_ENABLED);
3682 tdf2_.set_secure(SEC_DISABLED);
3683 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003684 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08003685 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003686 const cricket::MediaContentDescription* audio_media_desc;
3687 const cricket::MediaContentDescription* video_media_desc;
3688 const cricket::TransportDescription* audio_trans_desc;
3689 const cricket::TransportDescription* video_trans_desc;
3690
3691 // Generate an offer with SDES and DTLS support.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003692 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003693 ASSERT_TRUE(offer.get() != NULL);
3694
Steve Antonb1c1de12017-12-21 15:14:30 -08003695 audio_media_desc = offer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003696 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003697 video_media_desc = offer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003698 ASSERT_TRUE(video_media_desc != NULL);
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07003699 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003700 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3701
3702 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3703 ASSERT_TRUE(audio_trans_desc != NULL);
3704 video_trans_desc = offer->GetTransportDescriptionByName("video");
3705 ASSERT_TRUE(video_trans_desc != NULL);
3706 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3707 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3708
3709 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003710 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003711 ASSERT_TRUE(answer.get() != NULL);
3712
Steve Antonb1c1de12017-12-21 15:14:30 -08003713 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003714 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003715 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003716 ASSERT_TRUE(video_media_desc != NULL);
3717 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3718 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3719
3720 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3721 ASSERT_TRUE(audio_trans_desc != NULL);
3722 video_trans_desc = answer->GetTransportDescriptionByName("video");
3723 ASSERT_TRUE(video_trans_desc != NULL);
3724 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
3725 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
3726
3727 // Enable DTLS; the answer should now only have DTLS support.
3728 tdf2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003729 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003730 ASSERT_TRUE(answer.get() != NULL);
3731
Steve Antonb1c1de12017-12-21 15:14:30 -08003732 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003733 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003734 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003735 ASSERT_TRUE(video_media_desc != NULL);
3736 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3737 EXPECT_TRUE(video_media_desc->cryptos().empty());
Steve Antone38a5a12018-11-21 16:05:15 -08003738 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
3739 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003740
3741 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3742 ASSERT_TRUE(audio_trans_desc != NULL);
3743 video_trans_desc = answer->GetTransportDescriptionByName("video");
3744 ASSERT_TRUE(video_trans_desc != NULL);
3745 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3746 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003747
3748 // Try creating offer again. DTLS enabled now, crypto's should be empty
3749 // in new offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003750 offer = f1_.CreateOffer(options, offer.get());
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003751 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003752 audio_media_desc = offer->GetContentDescriptionByName("audio");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003753 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003754 video_media_desc = offer->GetContentDescriptionByName("video");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003755 ASSERT_TRUE(video_media_desc != NULL);
3756 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3757 EXPECT_TRUE(video_media_desc->cryptos().empty());
3758
3759 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3760 ASSERT_TRUE(audio_trans_desc != NULL);
3761 video_trans_desc = offer->GetTransportDescriptionByName("video");
3762 ASSERT_TRUE(video_trans_desc != NULL);
3763 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3764 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003765}
3766
3767// Test that an answer can't be created if cryptos are required but the offer is
3768// unsecure.
3769TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003770 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003771 f1_.set_secure(SEC_DISABLED);
3772 tdf1_.set_secure(SEC_DISABLED);
3773 f2_.set_secure(SEC_REQUIRED);
3774 tdf1_.set_secure(SEC_ENABLED);
3775
Steve Anton6fe1fba2018-12-11 10:15:23 -08003776 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003777 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003778 std::unique_ptr<SessionDescription> answer =
3779 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003780 EXPECT_TRUE(answer.get() == NULL);
3781}
3782
3783// Test that we accept a DTLS offer without SDES and create an appropriate
3784// answer.
3785TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
3786 f1_.set_secure(SEC_DISABLED);
3787 f2_.set_secure(SEC_ENABLED);
3788 tdf1_.set_secure(SEC_ENABLED);
3789 tdf2_.set_secure(SEC_ENABLED);
3790 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003791 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3792 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3793 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003794
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003795 // Generate an offer with DTLS but without SDES.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003796 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003797 ASSERT_TRUE(offer.get() != NULL);
3798
3799 const AudioContentDescription* audio_offer =
3800 GetFirstAudioContentDescription(offer.get());
3801 ASSERT_TRUE(audio_offer->cryptos().empty());
3802 const VideoContentDescription* video_offer =
3803 GetFirstVideoContentDescription(offer.get());
3804 ASSERT_TRUE(video_offer->cryptos().empty());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02003805 const RtpDataContentDescription* data_offer =
3806 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003807 ASSERT_TRUE(data_offer->cryptos().empty());
3808
3809 const cricket::TransportDescription* audio_offer_trans_desc =
3810 offer->GetTransportDescriptionByName("audio");
3811 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
3812 const cricket::TransportDescription* video_offer_trans_desc =
3813 offer->GetTransportDescriptionByName("video");
3814 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
3815 const cricket::TransportDescription* data_offer_trans_desc =
3816 offer->GetTransportDescriptionByName("data");
3817 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
3818
3819 // Generate an answer with DTLS.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003820 std::unique_ptr<SessionDescription> answer =
3821 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003822 ASSERT_TRUE(answer.get() != NULL);
3823
3824 const cricket::TransportDescription* audio_answer_trans_desc =
3825 answer->GetTransportDescriptionByName("audio");
3826 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3827 const cricket::TransportDescription* video_answer_trans_desc =
3828 answer->GetTransportDescriptionByName("video");
3829 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
3830 const cricket::TransportDescription* data_answer_trans_desc =
3831 answer->GetTransportDescriptionByName("data");
3832 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
3833}
3834
3835// Verifies if vad_enabled option is set to false, CN codecs are not present in
3836// offer or answer.
3837TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3838 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003839 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003840 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003841 ASSERT_TRUE(offer.get() != NULL);
3842 const ContentInfo* audio_content = offer->GetContentByName("audio");
3843 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
3844
3845 options.vad_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08003846 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003847 ASSERT_TRUE(offer.get() != NULL);
3848 audio_content = offer->GetContentByName("audio");
3849 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
Steve Anton6fe1fba2018-12-11 10:15:23 -08003850 std::unique_ptr<SessionDescription> answer =
3851 f1_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003852 ASSERT_TRUE(answer.get() != NULL);
3853 audio_content = answer->GetContentByName("audio");
3854 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
3855}
deadbeef44f08192015-12-15 16:20:09 -08003856
zhihuang1c378ed2017-08-17 14:10:50 -07003857// Test that the generated MIDs match the existing offer.
3858TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08003859 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003860 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_modified",
3861 RtpTransceiverDirection::kRecvOnly, kActive,
3862 &opts);
3863 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_modified",
3864 RtpTransceiverDirection::kRecvOnly, kActive,
3865 &opts);
deadbeef44f08192015-12-15 16:20:09 -08003866 opts.data_channel_type = cricket::DCT_SCTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003867 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data_modified",
3868 RtpTransceiverDirection::kSendRecv, kActive,
3869 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003870 // Create offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003871 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
kwiberg31022942016-03-11 14:18:21 -08003872 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08003873 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003874
deadbeef44f08192015-12-15 16:20:09 -08003875 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3876 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3877 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3878 ASSERT_TRUE(audio_content != nullptr);
3879 ASSERT_TRUE(video_content != nullptr);
3880 ASSERT_TRUE(data_content != nullptr);
3881 EXPECT_EQ("audio_modified", audio_content->name);
3882 EXPECT_EQ("video_modified", video_content->name);
3883 EXPECT_EQ("data_modified", data_content->name);
3884}
zhihuangcf5b37c2016-05-05 11:44:35 -07003885
zhihuang1c378ed2017-08-17 14:10:50 -07003886// The following tests verify that the unified plan SDP is supported.
3887// Test that we can create an offer with multiple media sections of same media
3888// type.
3889TEST_F(MediaSessionDescriptionFactoryTest,
3890 CreateOfferWithMultipleAVMediaSections) {
3891 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003892 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3893 RtpTransceiverDirection::kSendRecv, kActive,
3894 &opts);
3895 AttachSenderToMediaDescriptionOptions(
3896 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003897
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003898 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3899 RtpTransceiverDirection::kSendRecv, kActive,
3900 &opts);
3901 AttachSenderToMediaDescriptionOptions(
3902 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003903
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003904 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3905 RtpTransceiverDirection::kSendRecv, kActive,
3906 &opts);
3907 AttachSenderToMediaDescriptionOptions(
3908 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003909
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003910 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3911 RtpTransceiverDirection::kSendRecv, kActive,
3912 &opts);
3913 AttachSenderToMediaDescriptionOptions(
3914 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003915 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003916 ASSERT_TRUE(offer);
3917
3918 ASSERT_EQ(4u, offer->contents().size());
3919 EXPECT_FALSE(offer->contents()[0].rejected);
3920 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003921 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003922 ASSERT_EQ(1u, acd->streams().size());
3923 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003924 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003925
3926 EXPECT_FALSE(offer->contents()[1].rejected);
3927 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003928 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003929 ASSERT_EQ(1u, vcd->streams().size());
3930 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003931 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003932
3933 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003934 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003935 ASSERT_EQ(1u, acd->streams().size());
3936 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003937 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003938
3939 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003940 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003941 ASSERT_EQ(1u, vcd->streams().size());
3942 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003943 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003944}
3945
3946// Test that we can create an answer with multiple media sections of same media
3947// type.
3948TEST_F(MediaSessionDescriptionFactoryTest,
3949 CreateAnswerWithMultipleAVMediaSections) {
3950 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003951 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3952 RtpTransceiverDirection::kSendRecv, kActive,
3953 &opts);
3954 AttachSenderToMediaDescriptionOptions(
3955 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003956
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003957 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3958 RtpTransceiverDirection::kSendRecv, kActive,
3959 &opts);
3960 AttachSenderToMediaDescriptionOptions(
3961 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003962
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003963 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3964 RtpTransceiverDirection::kSendRecv, kActive,
3965 &opts);
3966 AttachSenderToMediaDescriptionOptions(
3967 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003968
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003969 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3970 RtpTransceiverDirection::kSendRecv, kActive,
3971 &opts);
3972 AttachSenderToMediaDescriptionOptions(
3973 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003974
Steve Anton6fe1fba2018-12-11 10:15:23 -08003975 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003976 ASSERT_TRUE(offer);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003977 std::unique_ptr<SessionDescription> answer =
3978 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003979
3980 ASSERT_EQ(4u, answer->contents().size());
3981 EXPECT_FALSE(answer->contents()[0].rejected);
3982 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003983 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003984 ASSERT_EQ(1u, acd->streams().size());
3985 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003986 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003987
3988 EXPECT_FALSE(answer->contents()[1].rejected);
3989 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003990 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003991 ASSERT_EQ(1u, vcd->streams().size());
3992 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003993 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003994
3995 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003996 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003997 ASSERT_EQ(1u, acd->streams().size());
3998 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003999 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004000
4001 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004002 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004003 ASSERT_EQ(1u, vcd->streams().size());
4004 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08004005 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07004006}
4007
4008// Test that the media section will be rejected in offer if the corresponding
4009// MediaDescriptionOptions is stopped by the offerer.
4010TEST_F(MediaSessionDescriptionFactoryTest,
4011 CreateOfferWithMediaSectionStoppedByOfferer) {
4012 // Create an offer with two audio sections and one of them is stopped.
4013 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004014 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4015 RtpTransceiverDirection::kSendRecv, kActive,
4016 &offer_opts);
4017 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4018 RtpTransceiverDirection::kInactive, kStopped,
4019 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004020 std::unique_ptr<SessionDescription> offer =
4021 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004022 ASSERT_TRUE(offer);
4023 ASSERT_EQ(2u, offer->contents().size());
4024 EXPECT_FALSE(offer->contents()[0].rejected);
4025 EXPECT_TRUE(offer->contents()[1].rejected);
4026}
4027
4028// Test that the media section will be rejected in answer if the corresponding
4029// MediaDescriptionOptions is stopped by the offerer.
4030TEST_F(MediaSessionDescriptionFactoryTest,
4031 CreateAnswerWithMediaSectionStoppedByOfferer) {
4032 // Create an offer with two audio sections and one of them is stopped.
4033 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004034 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4035 RtpTransceiverDirection::kSendRecv, kActive,
4036 &offer_opts);
4037 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4038 RtpTransceiverDirection::kInactive, kStopped,
4039 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004040 std::unique_ptr<SessionDescription> offer =
4041 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004042 ASSERT_TRUE(offer);
4043 ASSERT_EQ(2u, offer->contents().size());
4044 EXPECT_FALSE(offer->contents()[0].rejected);
4045 EXPECT_TRUE(offer->contents()[1].rejected);
4046
4047 // Create an answer based on the offer.
4048 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004049 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4050 RtpTransceiverDirection::kSendRecv, kActive,
4051 &answer_opts);
4052 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4053 RtpTransceiverDirection::kSendRecv, kActive,
4054 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004055 std::unique_ptr<SessionDescription> answer =
4056 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004057 ASSERT_EQ(2u, answer->contents().size());
4058 EXPECT_FALSE(answer->contents()[0].rejected);
4059 EXPECT_TRUE(answer->contents()[1].rejected);
4060}
4061
4062// Test that the media section will be rejected in answer if the corresponding
4063// MediaDescriptionOptions is stopped by the answerer.
4064TEST_F(MediaSessionDescriptionFactoryTest,
4065 CreateAnswerWithMediaSectionRejectedByAnswerer) {
4066 // Create an offer with two audio sections.
4067 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004068 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4069 RtpTransceiverDirection::kSendRecv, kActive,
4070 &offer_opts);
4071 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4072 RtpTransceiverDirection::kSendRecv, kActive,
4073 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004074 std::unique_ptr<SessionDescription> offer =
4075 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004076 ASSERT_TRUE(offer);
4077 ASSERT_EQ(2u, offer->contents().size());
4078 ASSERT_FALSE(offer->contents()[0].rejected);
4079 ASSERT_FALSE(offer->contents()[1].rejected);
4080
4081 // The answerer rejects one of the audio sections.
4082 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004083 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
4084 RtpTransceiverDirection::kSendRecv, kActive,
4085 &answer_opts);
4086 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
4087 RtpTransceiverDirection::kInactive, kStopped,
4088 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004089 std::unique_ptr<SessionDescription> answer =
4090 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004091 ASSERT_EQ(2u, answer->contents().size());
4092 EXPECT_FALSE(answer->contents()[0].rejected);
4093 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08004094
4095 // The TransportInfo of the rejected m= section is expected to be added in the
4096 // answer.
4097 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07004098}
4099
4100// Test the generated media sections has the same order of the
4101// corresponding MediaDescriptionOptions.
4102TEST_F(MediaSessionDescriptionFactoryTest,
4103 CreateOfferRespectsMediaDescriptionOptionsOrder) {
4104 MediaSessionOptions opts;
4105 // This tests put video section first because normally audio comes first by
4106 // default.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004107 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4108 RtpTransceiverDirection::kSendRecv, kActive,
4109 &opts);
4110 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4111 RtpTransceiverDirection::kSendRecv, kActive,
4112 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004113 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004114
4115 ASSERT_TRUE(offer);
4116 ASSERT_EQ(2u, offer->contents().size());
4117 EXPECT_EQ("video", offer->contents()[0].name);
4118 EXPECT_EQ("audio", offer->contents()[1].name);
4119}
4120
4121// Test that different media sections using the same codec have same payload
4122// type.
4123TEST_F(MediaSessionDescriptionFactoryTest,
4124 PayloadTypesSharedByMediaSectionsOfSameType) {
4125 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004126 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4127 RtpTransceiverDirection::kSendRecv, kActive,
4128 &opts);
4129 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4130 RtpTransceiverDirection::kSendRecv, kActive,
4131 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004132 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004133 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004134 ASSERT_TRUE(offer);
4135 ASSERT_EQ(2u, offer->contents().size());
4136 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004137 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004138 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004139 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004140 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4141 ASSERT_EQ(2u, vcd1->codecs().size());
4142 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4143 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4144 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
4145 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
4146
4147 // Create answer and negotiate the codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004148 std::unique_ptr<SessionDescription> answer =
4149 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004150 ASSERT_TRUE(answer);
4151 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08004152 vcd1 = answer->contents()[0].media_description()->as_video();
4153 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004154 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
4155 ASSERT_EQ(1u, vcd1->codecs().size());
4156 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
4157 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
4158}
4159
4160// Test that the codec preference order per media section is respected in
4161// subsequent offer.
4162TEST_F(MediaSessionDescriptionFactoryTest,
4163 CreateOfferRespectsCodecPreferenceOrder) {
4164 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004165 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4166 RtpTransceiverDirection::kSendRecv, kActive,
4167 &opts);
4168 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4169 RtpTransceiverDirection::kSendRecv, kActive,
4170 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004171 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004172 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004173 ASSERT_TRUE(offer);
4174 ASSERT_EQ(2u, offer->contents().size());
4175 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004176 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004177 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004178 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004179 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4180 EXPECT_EQ(video_codecs, vcd1->codecs());
4181 EXPECT_EQ(video_codecs, vcd2->codecs());
4182
4183 // Change the codec preference of the first video section and create a
4184 // follow-up offer.
4185 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4186 vcd1->set_codecs(video_codecs_reverse);
4187 std::unique_ptr<SessionDescription> updated_offer(
4188 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08004189 vcd1 = updated_offer->contents()[0].media_description()->as_video();
4190 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004191 // The video codec preference order should be respected.
4192 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4193 EXPECT_EQ(video_codecs, vcd2->codecs());
4194}
4195
4196// Test that the codec preference order per media section is respected in
4197// the answer.
4198TEST_F(MediaSessionDescriptionFactoryTest,
4199 CreateAnswerRespectsCodecPreferenceOrder) {
4200 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004201 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4202 RtpTransceiverDirection::kSendRecv, kActive,
4203 &opts);
4204 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4205 RtpTransceiverDirection::kSendRecv, kActive,
4206 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004207 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004208 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004209 ASSERT_TRUE(offer);
4210 ASSERT_EQ(2u, offer->contents().size());
4211 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004212 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004213 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004214 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004215 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4216 EXPECT_EQ(video_codecs, vcd1->codecs());
4217 EXPECT_EQ(video_codecs, vcd2->codecs());
4218
4219 // Change the codec preference of the first video section and create an
4220 // answer.
4221 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4222 vcd1->set_codecs(video_codecs_reverse);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004223 std::unique_ptr<SessionDescription> answer =
4224 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08004225 vcd1 = answer->contents()[0].media_description()->as_video();
4226 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004227 // The video codec preference order should be respected.
4228 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4229 EXPECT_EQ(video_codecs, vcd2->codecs());
4230}
4231
Zhi Huang6f367472017-11-22 13:20:02 -08004232// Test that when creating an answer, the codecs use local parameters instead of
4233// the remote ones.
4234TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
4235 const std::string audio_param_name = "audio_param";
4236 const std::string audio_value1 = "audio_v1";
4237 const std::string audio_value2 = "audio_v2";
4238 const std::string video_param_name = "video_param";
4239 const std::string video_value1 = "video_v1";
4240 const std::string video_value2 = "video_v2";
4241
4242 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
4243 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
4244 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
4245 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
4246
4247 // Set the parameters for codecs.
4248 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
4249 video_codecs1[0].SetParam(video_param_name, video_value1);
4250 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
4251 video_codecs2[0].SetParam(video_param_name, video_value2);
4252
4253 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
4254 f1_.set_video_codecs(video_codecs1);
4255 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
4256 f2_.set_video_codecs(video_codecs2);
4257
4258 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004259 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4260 RtpTransceiverDirection::kSendRecv, kActive,
4261 &opts);
4262 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4263 RtpTransceiverDirection::kSendRecv, kActive,
4264 &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08004265
Steve Anton6fe1fba2018-12-11 10:15:23 -08004266 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004267 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004268 auto offer_acd = offer->contents()[0].media_description()->as_audio();
4269 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004270 std::string value;
4271 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
4272 EXPECT_EQ(audio_value1, value);
4273 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
4274 EXPECT_EQ(video_value1, value);
4275
Steve Anton6fe1fba2018-12-11 10:15:23 -08004276 std::unique_ptr<SessionDescription> answer =
4277 f2_.CreateAnswer(offer.get(), opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004278 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004279 auto answer_acd = answer->contents()[0].media_description()->as_audio();
4280 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004281 // Use the parameters from the local codecs.
4282 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
4283 EXPECT_EQ(audio_value2, value);
4284 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
4285 EXPECT_EQ(video_value2, value);
4286}
4287
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004288// Test that matching packetization-mode is part of the criteria for matching
4289// H264 codecs (in addition to profile-level-id). Previously, this was not the
4290// case, so the first H264 codec with the same profile-level-id would match and
4291// the payload type in the answer would be incorrect.
4292// This is a regression test for bugs.webrtc.org/8808
4293TEST_F(MediaSessionDescriptionFactoryTest,
4294 H264MatchCriteriaIncludesPacketizationMode) {
4295 // Create two H264 codecs with the same profile level ID and different
4296 // packetization modes.
4297 VideoCodec h264_pm0(96, "H264");
4298 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4299 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
4300 VideoCodec h264_pm1(97, "H264");
4301 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4302 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
4303
4304 // Offerer will send both codecs, answerer should choose the one with matching
4305 // packetization mode (and not the first one it sees).
4306 f1_.set_video_codecs({h264_pm0, h264_pm1});
4307 f2_.set_video_codecs({h264_pm1});
4308
4309 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004310 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4311 RtpTransceiverDirection::kSendRecv, kActive,
4312 &opts);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004313
Steve Anton6fe1fba2018-12-11 10:15:23 -08004314 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004315 ASSERT_TRUE(offer);
4316
Steve Anton6fe1fba2018-12-11 10:15:23 -08004317 std::unique_ptr<SessionDescription> answer =
4318 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004319 ASSERT_TRUE(answer);
4320
4321 // Answer should have one negotiated codec with packetization-mode=1 using the
4322 // offered payload type.
4323 ASSERT_EQ(1u, answer->contents().size());
4324 auto answer_vcd = answer->contents()[0].media_description()->as_video();
4325 ASSERT_EQ(1u, answer_vcd->codecs().size());
4326 auto answer_codec = answer_vcd->codecs()[0];
4327 EXPECT_EQ(h264_pm1.id, answer_codec.id);
4328}
4329
zhihuangcf5b37c2016-05-05 11:44:35 -07004330class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
4331 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004332 MediaProtocolTest()
4333 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -07004334 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
4335 MAKE_VECTOR(kAudioCodecs1));
zhihuangcf5b37c2016-05-05 11:44:35 -07004336 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004337 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07004338 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
4339 MAKE_VECTOR(kAudioCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07004340 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004341 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07004342 f1_.set_secure(SEC_ENABLED);
4343 f2_.set_secure(SEC_ENABLED);
4344 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004345 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004346 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004347 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004348 tdf1_.set_secure(SEC_ENABLED);
4349 tdf2_.set_secure(SEC_ENABLED);
4350 }
4351
4352 protected:
4353 MediaSessionDescriptionFactory f1_;
4354 MediaSessionDescriptionFactory f2_;
4355 TransportDescriptionFactory tdf1_;
4356 TransportDescriptionFactory tdf2_;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004357 UniqueRandomIdGenerator ssrc_generator1;
4358 UniqueRandomIdGenerator ssrc_generator2;
zhihuangcf5b37c2016-05-05 11:44:35 -07004359};
4360
4361TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
4362 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08004363 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004364 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004365 ASSERT_TRUE(offer.get() != nullptr);
4366 // Set the protocol for all the contents.
Harald Alvestrand1716d392019-06-03 20:35:45 +02004367 for (auto& content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004368 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07004369 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004370 std::unique_ptr<SessionDescription> answer =
4371 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004372 const ContentInfo* ac = answer->GetContentByName("audio");
4373 const ContentInfo* vc = answer->GetContentByName("video");
4374 ASSERT_TRUE(ac != nullptr);
4375 ASSERT_TRUE(vc != nullptr);
4376 EXPECT_FALSE(ac->rejected); // the offer is accepted
4377 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004378 const AudioContentDescription* acd = ac->media_description()->as_audio();
4379 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07004380 EXPECT_EQ(GetParam(), acd->protocol());
4381 EXPECT_EQ(GetParam(), vcd->protocol());
4382}
4383
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004384INSTANTIATE_TEST_SUITE_P(MediaProtocolPatternTest,
4385 MediaProtocolTest,
4386 ::testing::ValuesIn(kMediaProtocols));
4387INSTANTIATE_TEST_SUITE_P(MediaProtocolDtlsPatternTest,
4388 MediaProtocolTest,
4389 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07004390
4391TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
4392 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004393 UniqueRandomIdGenerator ssrc_generator;
4394 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004395 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4396 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4397
4398 // The merged list of codecs should contain any send codecs that are also
4399 // nominally in the recieve codecs list. Payload types should be picked from
4400 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
4401 // (set to 1). This equals what happens when the send codecs are used in an
4402 // offer and the receive codecs are used in the following answer.
4403 const std::vector<AudioCodec> sendrecv_codecs =
4404 MAKE_VECTOR(kAudioCodecsAnswer);
4405 const std::vector<AudioCodec> no_codecs;
4406
4407 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
4408 << "Please don't change shared test data!";
4409 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
4410 << "Please don't change shared test data!";
4411 // Alter iLBC send codec to have zero channels, to test that that is handled
4412 // properly.
4413 send_codecs[1].channels = 0;
4414
4415 // Alther iLBC receive codec to be lowercase, to test that case conversions
4416 // are handled properly.
4417 recv_codecs[2].name = "ilbc";
4418
4419 // Test proper merge
4420 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004421 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4422 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4423 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004424
4425 // Test empty send codecs list
4426 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004427 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4428 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4429 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004430
4431 // Test empty recv codecs list
4432 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004433 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4434 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4435 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004436
4437 // Test all empty codec lists
4438 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004439 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4440 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4441 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004442}
4443
4444namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07004445// Compare the two vectors of codecs ignoring the payload type.
4446template <class Codec>
4447bool CodecsMatch(const std::vector<Codec>& codecs1,
4448 const std::vector<Codec>& codecs2) {
4449 if (codecs1.size() != codecs2.size()) {
4450 return false;
4451 }
4452
4453 for (size_t i = 0; i < codecs1.size(); ++i) {
4454 if (!codecs1[i].Matches(codecs2[i])) {
4455 return false;
4456 }
4457 }
4458 return true;
4459}
4460
Steve Anton4e70a722017-11-28 14:57:10 -08004461void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07004462 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004463 UniqueRandomIdGenerator ssrc_generator;
4464 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004465 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4466 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4467 const std::vector<AudioCodec> sendrecv_codecs =
4468 MAKE_VECTOR(kAudioCodecsAnswer);
4469 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07004470
4471 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004472 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
4473 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004474
Steve Anton4e70a722017-11-28 14:57:10 -08004475 if (direction == RtpTransceiverDirection::kSendRecv ||
4476 direction == RtpTransceiverDirection::kSendOnly) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004477 AttachSenderToMediaDescriptionOptions(
4478 "audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004479 }
ossu075af922016-06-14 03:29:38 -07004480
Steve Anton6fe1fba2018-12-11 10:15:23 -08004481 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
ossu075af922016-06-14 03:29:38 -07004482 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004483 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07004484
4485 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07004486 // that the codecs put in are right. This happens when we neither want to
4487 // send nor receive audio. The checks are still in place if at some point
4488 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004489 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004490 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004491 // sendrecv and inactive should both present lists as if the channel was
4492 // to be used for sending and receiving. Inactive essentially means it
4493 // might eventually be used anything, but we don't know more at this
4494 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08004495 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004496 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08004497 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004498 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004499 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07004500 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004501 }
4502 }
4503}
4504
4505static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07004506 AudioCodec(0, "codec0", 16000, -1, 1),
4507 AudioCodec(1, "codec1", 8000, 13300, 1),
4508 AudioCodec(2, "codec2", 8000, 64000, 1),
4509 AudioCodec(3, "codec3", 8000, 64000, 1),
4510 AudioCodec(4, "codec4", 8000, 0, 2),
4511 AudioCodec(5, "codec5", 32000, 0, 1),
4512 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07004513
zhihuang1c378ed2017-08-17 14:10:50 -07004514/* The codecs groups below are chosen as per the matrix below. The objective
4515 * is to have different sets of codecs in the inputs, to get unique sets of
4516 * codecs after negotiation, depending on offer and answer communication
4517 * directions. One-way directions in the offer should either result in the
4518 * opposite direction in the answer, or an inactive answer. Regardless, the
4519 * choice of codecs should be as if the answer contained the opposite
4520 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07004521 *
4522 * | Offer | Answer | Result
4523 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
4524 * 0 | x - - | - x - | x - - - -
4525 * 1 | x x x | - x - | x - - x -
4526 * 2 | - x - | x - - | - x - - -
4527 * 3 | x x x | x - - | - x x - -
4528 * 4 | - x - | x x x | - x - - -
4529 * 5 | x - - | x x x | x - - - -
4530 * 6 | x x x | x x x | x x x x x
4531 */
4532// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004533static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
4534static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07004535// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
4536// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07004537static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
4538static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07004539// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004540static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
4541static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
4542static const int kResultSendrecv_SendCodecs[] = {3, 6};
4543static const int kResultSendrecv_RecvCodecs[] = {1, 6};
4544static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07004545
4546template <typename T, int IDXS>
4547std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
4548 std::vector<T> out;
4549 out.reserve(IDXS);
4550 for (int idx : indices)
4551 out.push_back(array[idx]);
4552
4553 return out;
4554}
4555
Steve Anton4e70a722017-11-28 14:57:10 -08004556void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
4557 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07004558 bool add_legacy_stream) {
4559 TransportDescriptionFactory offer_tdf;
4560 TransportDescriptionFactory answer_tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004561 UniqueRandomIdGenerator ssrc_generator1, ssrc_generator2;
4562 MediaSessionDescriptionFactory offer_factory(&offer_tdf, &ssrc_generator1);
4563 MediaSessionDescriptionFactory answer_factory(&answer_tdf, &ssrc_generator2);
ossu075af922016-06-14 03:29:38 -07004564 offer_factory.set_audio_codecs(
4565 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
4566 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
4567 answer_factory.set_audio_codecs(
4568 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
4569 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
4570
ossu075af922016-06-14 03:29:38 -07004571 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004572 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", offer_direction,
4573 kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004574
Steve Anton4e70a722017-11-28 14:57:10 -08004575 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004576 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4577 kAudioTrack1, {kMediaStream1}, 1,
4578 &offer_opts);
ossu075af922016-06-14 03:29:38 -07004579 }
4580
Steve Anton6fe1fba2018-12-11 10:15:23 -08004581 std::unique_ptr<SessionDescription> offer =
4582 offer_factory.CreateOffer(offer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004583 ASSERT_TRUE(offer.get() != NULL);
4584
4585 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004586 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", answer_direction,
4587 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004588
Steve Anton4e70a722017-11-28 14:57:10 -08004589 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004590 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4591 kAudioTrack1, {kMediaStream1}, 1,
4592 &answer_opts);
ossu075af922016-06-14 03:29:38 -07004593 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004594 std::unique_ptr<SessionDescription> answer =
4595 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004596 const ContentInfo* ac = answer->GetContentByName("audio");
4597
zhihuang1c378ed2017-08-17 14:10:50 -07004598 // If the factory didn't add any audio content to the answer, we cannot
4599 // check that the codecs put in are right. This happens when we neither want
4600 // to send nor receive audio. The checks are still in place if at some point
4601 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004602 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004603 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
4604 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07004605
ossu075af922016-06-14 03:29:38 -07004606 std::vector<AudioCodec> target_codecs;
4607 // For offers with sendrecv or inactive, we should never reply with more
4608 // codecs than offered, with these codec sets.
4609 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08004610 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07004611 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4612 kResultSendrecv_SendrecvCodecs);
4613 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004614 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004615 target_codecs =
4616 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004617 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004618 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004619 target_codecs =
4620 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07004621 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004622 case RtpTransceiverDirection::kSendRecv:
4623 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004624 target_codecs =
4625 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08004626 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004627 target_codecs =
4628 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004629 } else {
4630 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4631 kResultSendrecv_SendrecvCodecs);
4632 }
4633 break;
4634 }
4635
zhihuang1c378ed2017-08-17 14:10:50 -07004636 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02004637 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07004638 bool first = true;
4639 os << "{";
4640 for (const auto& c : codecs) {
4641 os << (first ? " " : ", ") << c.id;
4642 first = false;
4643 }
4644 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02004645 return os.Release();
ossu075af922016-06-14 03:29:38 -07004646 };
4647
4648 EXPECT_TRUE(acd->codecs() == target_codecs)
4649 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08004650 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
4651 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07004652 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08004653 << webrtc::RtpTransceiverDirectionToString(answer_direction)
4654 << "; got: "
4655 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07004656 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08004657 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07004658 << "Only inactive offers are allowed to not generate any audio "
4659 "content";
ossu075af922016-06-14 03:29:38 -07004660 }
4661}
brandtr03d5fb12016-11-22 03:37:59 -08004662
4663} // namespace
ossu075af922016-06-14 03:29:38 -07004664
4665class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08004666 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07004667
4668TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004669 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07004670}
4671
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004672INSTANTIATE_TEST_SUITE_P(MediaSessionDescriptionFactoryTest,
4673 AudioCodecsOfferTest,
4674 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4675 RtpTransceiverDirection::kRecvOnly,
4676 RtpTransceiverDirection::kSendRecv,
4677 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07004678
4679class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08004680 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
4681 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07004682 bool>> {};
ossu075af922016-06-14 03:29:38 -07004683
4684TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08004685 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
4686 ::testing::get<1>(GetParam()),
4687 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07004688}
4689
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004690INSTANTIATE_TEST_SUITE_P(
zhihuang1c378ed2017-08-17 14:10:50 -07004691 MediaSessionDescriptionFactoryTest,
4692 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004693 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
4694 RtpTransceiverDirection::kRecvOnly,
4695 RtpTransceiverDirection::kSendRecv,
4696 RtpTransceiverDirection::kInactive),
4697 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4698 RtpTransceiverDirection::kRecvOnly,
4699 RtpTransceiverDirection::kSendRecv,
4700 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07004701 ::testing::Bool()));