blob: 17cc2a758ea68cb7d057b69a246871f1fc626f52 [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
Amit Hilbuch77938e62018-12-21 09:23:38 -080011#include <algorithm>
kwiberg31022942016-03-11 14:18:21 -080012#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000013#include <string>
14#include <vector>
15
Steve Anton64b626b2019-01-28 17:25:26 -080016#include "absl/algorithm/container.h"
Steve Anton6fe1fba2018-12-11 10:15:23 -080017#include "absl/memory/memory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "media/base/codec.h"
Steve Anton10542f22019-01-11 09:11:00 -080019#include "media/base/test_utils.h"
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +020020#include "media/sctp/sctp_transport_internal.h"
Steve Anton10542f22019-01-11 09:11:00 -080021#include "p2p/base/p2p_constants.h"
22#include "p2p/base/transport_description.h"
23#include "p2p/base/transport_info.h"
24#include "pc/media_session.h"
25#include "pc/rtp_media_utils.h"
26#include "pc/srtp_filter.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020027#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080028#include "rtc_base/fake_ssl_identity.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020029#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 09:11:00 -080030#include "rtc_base/message_digest.h"
31#include "rtc_base/ssl_adapter.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020032#include "rtc_base/strings/string_builder.h"
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080033#include "rtc_base/unique_id_generator.h"
Steve Antone38a5a12018-11-21 16:05:15 -080034#include "test/gmock.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000035
Yves Gerey665174f2018-06-19 15:03:05 +020036#define ASSERT_CRYPTO(cd, s, cs) \
37 ASSERT_EQ(s, cd->cryptos().size()); \
Steve Antone38a5a12018-11-21 16:05:15 -080038 ASSERT_EQ(cs, cd->cryptos()[0].cipher_suite)
henrike@webrtc.org28e20752013-07-10 00:45:36 +000039
40typedef std::vector<cricket::Candidate> Candidates;
41
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080042using cricket::AudioCodec;
43using cricket::AudioContentDescription;
44using cricket::ContentInfo;
45using cricket::CryptoParamsVec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080046using cricket::GetFirstAudioContent;
47using cricket::GetFirstAudioContentDescription;
48using cricket::GetFirstDataContent;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020049using cricket::GetFirstRtpDataContentDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080050using cricket::GetFirstVideoContent;
51using cricket::GetFirstVideoContentDescription;
52using cricket::kAutoBandwidth;
53using cricket::MEDIA_TYPE_AUDIO;
54using cricket::MEDIA_TYPE_DATA;
55using cricket::MEDIA_TYPE_VIDEO;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000056using cricket::MediaContentDescription;
zhihuang1c378ed2017-08-17 14:10:50 -070057using cricket::MediaDescriptionOptions;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080058using cricket::MediaProtocolType;
59using cricket::MediaSessionDescriptionFactory;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000060using cricket::MediaSessionOptions;
61using cricket::MediaType;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080062using cricket::RidDescription;
63using cricket::RidDirection;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020064using cricket::RtpDataCodec;
65using cricket::RtpDataContentDescription;
66using cricket::SctpDataContentDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080067using cricket::SEC_DISABLED;
68using cricket::SEC_ENABLED;
69using cricket::SEC_REQUIRED;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000070using cricket::SessionDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080071using cricket::SimulcastDescription;
72using cricket::SimulcastLayer;
73using cricket::SimulcastLayerList;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000074using cricket::SsrcGroup;
75using cricket::StreamParams;
76using cricket::StreamParamsVec;
77using cricket::TransportDescription;
78using cricket::TransportDescriptionFactory;
79using cricket::TransportInfo;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000080using cricket::VideoCodec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080081using cricket::VideoContentDescription;
jbauchcb560652016-08-04 05:20:32 -070082using rtc::CS_AEAD_AES_128_GCM;
83using rtc::CS_AEAD_AES_256_GCM;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080084using rtc::CS_AES_CM_128_HMAC_SHA1_32;
85using rtc::CS_AES_CM_128_HMAC_SHA1_80;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080086using rtc::UniqueRandomIdGenerator;
Mirko Bonadei6a489f22019-04-09 15:11:12 +020087using ::testing::Contains;
88using ::testing::Each;
89using ::testing::ElementsAreArray;
90using ::testing::Eq;
91using ::testing::Field;
92using ::testing::IsEmpty;
93using ::testing::IsFalse;
94using ::testing::Ne;
95using ::testing::Not;
96using ::testing::Pointwise;
97using ::testing::SizeIs;
isheriff6f8d6862016-05-26 11:24:55 -070098using webrtc::RtpExtension;
Steve Anton4e70a722017-11-28 14:57:10 -080099using webrtc::RtpTransceiverDirection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000100
101static const AudioCodec kAudioCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700102 AudioCodec(103, "ISAC", 16000, -1, 1),
103 AudioCodec(102, "iLBC", 8000, 13300, 1),
104 AudioCodec(0, "PCMU", 8000, 64000, 1),
105 AudioCodec(8, "PCMA", 8000, 64000, 1),
106 AudioCodec(117, "red", 8000, 0, 1),
107 AudioCodec(107, "CN", 48000, 0, 1)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000108
109static const AudioCodec kAudioCodecs2[] = {
Henrik Lundinf8ed5612018-05-07 12:05:57 +0200110 AudioCodec(126, "foo", 16000, 22000, 1),
deadbeef67cf2c12016-04-13 10:07:16 -0700111 AudioCodec(0, "PCMU", 8000, 64000, 1),
112 AudioCodec(127, "iLBC", 8000, 13300, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000113};
114
115static const AudioCodec kAudioCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700116 AudioCodec(102, "iLBC", 8000, 13300, 1),
117 AudioCodec(0, "PCMU", 8000, 64000, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000118};
119
perkj26752742016-10-24 01:21:16 -0700120static const VideoCodec kVideoCodecs1[] = {VideoCodec(96, "H264-SVC"),
121 VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000122
zhihuang1c378ed2017-08-17 14:10:50 -0700123static const VideoCodec kVideoCodecs1Reverse[] = {VideoCodec(97, "H264"),
124 VideoCodec(96, "H264-SVC")};
125
perkj26752742016-10-24 01:21:16 -0700126static const VideoCodec kVideoCodecs2[] = {VideoCodec(126, "H264"),
127 VideoCodec(127, "H263")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000128
perkj26752742016-10-24 01:21:16 -0700129static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000130
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200131static const RtpDataCodec kDataCodecs1[] = {RtpDataCodec(98, "binary-data"),
132 RtpDataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000133
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200134static const RtpDataCodec kDataCodecs2[] = {RtpDataCodec(126, "binary-data"),
135 RtpDataCodec(127, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000136
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200137static const RtpDataCodec kDataCodecsAnswer[] = {
138 RtpDataCodec(98, "binary-data"), RtpDataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000139
isheriff6f8d6862016-05-26 11:24:55 -0700140static const RtpExtension kAudioRtpExtension1[] = {
141 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
142 RtpExtension("http://google.com/testing/audio_something", 10),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000143};
144
jbauch5869f502017-06-29 12:31:36 -0700145static const RtpExtension kAudioRtpExtensionEncrypted1[] = {
146 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
147 RtpExtension("http://google.com/testing/audio_something", 10),
148 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
149};
150
isheriff6f8d6862016-05-26 11:24:55 -0700151static const RtpExtension kAudioRtpExtension2[] = {
152 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
153 RtpExtension("http://google.com/testing/audio_something_else", 8),
154 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000155};
156
isheriff6f8d6862016-05-26 11:24:55 -0700157static const RtpExtension kAudioRtpExtension3[] = {
158 RtpExtension("http://google.com/testing/audio_something", 2),
159 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
deadbeefa5b273a2015-08-20 17:30:13 -0700160};
161
jbauch5869f502017-06-29 12:31:36 -0700162static const RtpExtension kAudioRtpExtension3ForEncryption[] = {
163 RtpExtension("http://google.com/testing/audio_something", 2),
164 // Use RTP extension that supports encryption.
165 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
166};
167
168static const RtpExtension kAudioRtpExtension3ForEncryptionOffer[] = {
169 RtpExtension("http://google.com/testing/audio_something", 2),
170 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
171 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14, true),
172};
173
isheriff6f8d6862016-05-26 11:24:55 -0700174static const RtpExtension kAudioRtpExtensionAnswer[] = {
175 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000176};
177
jbauch5869f502017-06-29 12:31:36 -0700178static const RtpExtension kAudioRtpExtensionEncryptedAnswer[] = {
179 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
180};
181
isheriff6f8d6862016-05-26 11:24:55 -0700182static const RtpExtension kVideoRtpExtension1[] = {
183 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
184 RtpExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000185};
186
jbauch5869f502017-06-29 12:31:36 -0700187static const RtpExtension kVideoRtpExtensionEncrypted1[] = {
188 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
189 RtpExtension("http://google.com/testing/video_something", 13),
190 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
191};
192
isheriff6f8d6862016-05-26 11:24:55 -0700193static const RtpExtension kVideoRtpExtension2[] = {
194 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
195 RtpExtension("http://google.com/testing/video_something_else", 14),
196 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000197};
198
isheriff6f8d6862016-05-26 11:24:55 -0700199static const RtpExtension kVideoRtpExtension3[] = {
200 RtpExtension("http://google.com/testing/video_something", 4),
201 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
deadbeefa5b273a2015-08-20 17:30:13 -0700202};
203
jbauch5869f502017-06-29 12:31:36 -0700204static const RtpExtension kVideoRtpExtension3ForEncryption[] = {
205 RtpExtension("http://google.com/testing/video_something", 4),
206 // Use RTP extension that supports encryption.
207 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 5),
208};
209
isheriff6f8d6862016-05-26 11:24:55 -0700210static const RtpExtension kVideoRtpExtensionAnswer[] = {
211 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000212};
213
jbauch5869f502017-06-29 12:31:36 -0700214static const RtpExtension kVideoRtpExtensionEncryptedAnswer[] = {
215 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
216};
217
Johannes Kronce8e8672019-02-22 13:06:44 +0100218static const RtpExtension kRtpExtensionTransportSequenceNumber01[] = {
219 RtpExtension("http://www.ietf.org/id/"
220 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
221 1),
222};
223
224static const RtpExtension kRtpExtensionTransportSequenceNumber01And02[] = {
225 RtpExtension("http://www.ietf.org/id/"
226 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
227 1),
Johannes Kron8cc711a2019-03-07 22:36:35 +0100228 RtpExtension(
229 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
230 2),
Johannes Kronce8e8672019-02-22 13:06:44 +0100231};
232
233static const RtpExtension kRtpExtensionTransportSequenceNumber02[] = {
Johannes Kron8cc711a2019-03-07 22:36:35 +0100234 RtpExtension(
235 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
236 2),
Johannes Kronce8e8672019-02-22 13:06:44 +0100237};
238
Peter Boström0c4e06b2015-10-07 12:23:21 +0200239static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
240static const uint32_t kSimSsrc[] = {10, 20, 30};
241static const uint32_t kFec1Ssrc[] = {10, 11};
242static const uint32_t kFec2Ssrc[] = {20, 21};
243static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000244
245static const char kMediaStream1[] = "stream_1";
246static const char kMediaStream2[] = "stream_2";
247static const char kVideoTrack1[] = "video_1";
248static const char kVideoTrack2[] = "video_2";
249static const char kAudioTrack1[] = "audio_1";
250static const char kAudioTrack2[] = "audio_2";
251static const char kAudioTrack3[] = "audio_3";
252static const char kDataTrack1[] = "data_1";
253static const char kDataTrack2[] = "data_2";
254static const char kDataTrack3[] = "data_3";
255
zhihuangcf5b37c2016-05-05 11:44:35 -0700256static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
257 "RTP/SAVPF"};
258static const char* kMediaProtocolsDtls[] = {
259 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
260 "UDP/TLS/RTP/SAVP"};
261
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700262// SRTP cipher name negotiated by the tests. This must be updated if the
263// default changes.
264static const char* kDefaultSrtpCryptoSuite = CS_AES_CM_128_HMAC_SHA1_80;
265static const char* kDefaultSrtpCryptoSuiteGcm = CS_AEAD_AES_256_GCM;
266
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800267// These constants are used to make the code using "AddMediaDescriptionOptions"
268// more readable.
zhihuang1c378ed2017-08-17 14:10:50 -0700269static constexpr bool kStopped = true;
270static constexpr bool kActive = false;
271
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000272static bool IsMediaContentOfType(const ContentInfo* content,
273 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800274 RTC_DCHECK(content);
275 return content->media_description()->type() == media_type;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000276}
277
Steve Anton4e70a722017-11-28 14:57:10 -0800278static RtpTransceiverDirection GetMediaDirection(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800279 RTC_DCHECK(content);
280 return content->media_description()->direction();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000281}
282
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000283static void AddRtxCodec(const VideoCodec& rtx_codec,
284 std::vector<VideoCodec>* codecs) {
magjedb05fa242016-11-11 04:00:16 -0800285 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000286 codecs->push_back(rtx_codec);
287}
288
289template <class T>
290static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
291 std::vector<std::string> codec_names;
Mirko Bonadei649a4c22019-01-29 10:11:53 +0100292 codec_names.reserve(codecs.size());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000293 for (const auto& codec : codecs) {
294 codec_names.push_back(codec.name);
295 }
296 return codec_names;
297}
298
zhihuang1c378ed2017-08-17 14:10:50 -0700299// This is used for test only. MIDs are not the identification of the
300// MediaDescriptionOptions since some end points may not support MID and the SDP
301// may not contain 'mid'.
302std::vector<MediaDescriptionOptions>::iterator FindFirstMediaDescriptionByMid(
303 const std::string& mid,
304 MediaSessionOptions* opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800305 return absl::c_find_if(
306 opts->media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700307 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
308}
309
310std::vector<MediaDescriptionOptions>::const_iterator
311FindFirstMediaDescriptionByMid(const std::string& mid,
312 const MediaSessionOptions& opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800313 return absl::c_find_if(
314 opts.media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700315 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
zhihuang1c378ed2017-08-17 14:10:50 -0700316}
317
318// Add a media section to the |session_options|.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800319static void AddMediaDescriptionOptions(MediaType type,
320 const std::string& mid,
321 RtpTransceiverDirection direction,
322 bool stopped,
323 MediaSessionOptions* opts) {
Steve Anton4e70a722017-11-28 14:57:10 -0800324 opts->media_description_options.push_back(
325 MediaDescriptionOptions(type, mid, direction, stopped));
zhihuang1c378ed2017-08-17 14:10:50 -0700326}
327
Steve Anton4e70a722017-11-28 14:57:10 -0800328static void AddAudioVideoSections(RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700329 MediaSessionOptions* opts) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800330 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
331 opts);
332 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video", direction, kActive,
333 opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700334}
335
336static void AddDataSection(cricket::DataChannelType dct,
Steve Anton4e70a722017-11-28 14:57:10 -0800337 RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700338 MediaSessionOptions* opts) {
339 opts->data_channel_type = dct;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800340 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700341}
342
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800343static void AttachSenderToMediaDescriptionOptions(
Steve Anton8ffb9c32017-08-31 15:45:38 -0700344 const std::string& mid,
345 MediaType type,
346 const std::string& track_id,
347 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800348 const std::vector<RidDescription>& rids,
349 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700350 int num_sim_layer,
351 MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -0700352 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
353 switch (type) {
354 case MEDIA_TYPE_AUDIO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700355 it->AddAudioSender(track_id, stream_ids);
zhihuang1c378ed2017-08-17 14:10:50 -0700356 break;
357 case MEDIA_TYPE_VIDEO:
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800358 it->AddVideoSender(track_id, stream_ids, rids, simulcast_layers,
359 num_sim_layer);
zhihuang1c378ed2017-08-17 14:10:50 -0700360 break;
361 case MEDIA_TYPE_DATA:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700362 RTC_CHECK(stream_ids.size() == 1U);
363 it->AddRtpDataChannel(track_id, stream_ids[0]);
zhihuang1c378ed2017-08-17 14:10:50 -0700364 break;
365 default:
366 RTC_NOTREACHED();
367 }
368}
369
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800370static void AttachSenderToMediaDescriptionOptions(
371 const std::string& mid,
372 MediaType type,
373 const std::string& track_id,
374 const std::vector<std::string>& stream_ids,
375 int num_sim_layer,
376 MediaSessionOptions* session_options) {
377 AttachSenderToMediaDescriptionOptions(mid, type, track_id, stream_ids, {},
378 SimulcastLayerList(), num_sim_layer,
379 session_options);
380}
381
zhihuang1c378ed2017-08-17 14:10:50 -0700382static void DetachSenderFromMediaSection(const std::string& mid,
383 const std::string& track_id,
384 MediaSessionOptions* session_options) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700385 std::vector<cricket::SenderOptions>& sender_options_list =
386 FindFirstMediaDescriptionByMid(mid, session_options)->sender_options;
387 auto sender_it =
Steve Anton64b626b2019-01-28 17:25:26 -0800388 absl::c_find_if(sender_options_list,
389 [track_id](const cricket::SenderOptions& sender_options) {
390 return sender_options.track_id == track_id;
391 });
Steve Anton3a66edf2018-09-10 12:57:37 -0700392 RTC_DCHECK(sender_it != sender_options_list.end());
393 sender_options_list.erase(sender_it);
zhihuang1c378ed2017-08-17 14:10:50 -0700394}
395
396// Helper function used to create a default MediaSessionOptions for Plan B SDP.
397// (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
398static MediaSessionOptions CreatePlanBMediaSessionOptions() {
399 MediaSessionOptions session_options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800400 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
401 RtpTransceiverDirection::kRecvOnly, kActive,
402 &session_options);
zhihuang1c378ed2017-08-17 14:10:50 -0700403 return session_options;
404}
405
406// TODO(zhihuang): Most of these tests were written while MediaSessionOptions
407// was designed for Plan B SDP, where only one audio "m=" section and one video
408// "m=" section could be generated, and ordering couldn't be controlled. Many of
409// these tests may be obsolete as a result, and should be refactored or removed.
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200410class MediaSessionDescriptionFactoryTest : public ::testing::Test {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000411 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800412 MediaSessionDescriptionFactoryTest()
413 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -0700414 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
415 MAKE_VECTOR(kAudioCodecs1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000416 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200417 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700418 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
419 MAKE_VECTOR(kAudioCodecs2));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000420 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200421 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200422 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700423 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200424 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700425 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000426 }
427
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000428 // Create a video StreamParamsVec object with:
429 // - one video stream with 3 simulcast streams and FEC,
430 StreamParamsVec CreateComplexVideoStreamParamsVec() {
431 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
432 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
433 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
434 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
435
436 std::vector<SsrcGroup> ssrc_groups;
437 ssrc_groups.push_back(sim_group);
438 ssrc_groups.push_back(fec_group1);
439 ssrc_groups.push_back(fec_group2);
440 ssrc_groups.push_back(fec_group3);
441
442 StreamParams simulcast_params;
443 simulcast_params.id = kVideoTrack1;
444 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
445 simulcast_params.ssrc_groups = ssrc_groups;
446 simulcast_params.cname = "Video_SIM_FEC";
Seth Hampson845e8782018-03-02 11:34:10 -0800447 simulcast_params.set_stream_ids({kMediaStream1});
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000448
449 StreamParamsVec video_streams;
450 video_streams.push_back(simulcast_params);
451
452 return video_streams;
453 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000454
455 bool CompareCryptoParams(const CryptoParamsVec& c1,
456 const CryptoParamsVec& c2) {
457 if (c1.size() != c2.size())
458 return false;
459 for (size_t i = 0; i < c1.size(); ++i)
460 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
461 c1[i].key_params != c2[i].key_params ||
462 c1[i].session_params != c2[i].session_params)
463 return false;
464 return true;
465 }
466
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700467 // Returns true if the transport info contains "renomination" as an
468 // ICE option.
469 bool GetIceRenomination(const TransportInfo* transport_info) {
Steve Anton64b626b2019-01-28 17:25:26 -0800470 return absl::c_linear_search(transport_info->description.transport_options,
471 "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700472 }
473
zhihuang1c378ed2017-08-17 14:10:50 -0700474 void TestTransportInfo(bool offer,
Steve Anton36b29d12017-10-30 09:57:42 -0700475 const MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000476 bool has_current_desc) {
477 const std::string current_audio_ufrag = "current_audio_ufrag";
478 const std::string current_audio_pwd = "current_audio_pwd";
479 const std::string current_video_ufrag = "current_video_ufrag";
480 const std::string current_video_pwd = "current_video_pwd";
481 const std::string current_data_ufrag = "current_data_ufrag";
482 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800483 std::unique_ptr<SessionDescription> current_desc;
484 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000485 if (has_current_desc) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800486 current_desc = absl::make_unique<SessionDescription>();
Steve Anton06817cd2018-12-18 15:55:30 -0800487 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200488 "audio",
Steve Anton06817cd2018-12-18 15:55:30 -0800489 TransportDescription(current_audio_ufrag, current_audio_pwd)));
490 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200491 "video",
Steve Anton06817cd2018-12-18 15:55:30 -0800492 TransportDescription(current_video_ufrag, current_video_pwd)));
493 current_desc->AddTransportInfo(TransportInfo(
494 "data", TransportDescription(current_data_ufrag, current_data_pwd)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000495 }
496 if (offer) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800497 desc = f1_.CreateOffer(options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000498 } else {
kwiberg31022942016-03-11 14:18:21 -0800499 std::unique_ptr<SessionDescription> offer;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800500 offer = f1_.CreateOffer(options, NULL);
501 desc = f1_.CreateAnswer(offer.get(), options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000502 }
503 ASSERT_TRUE(desc.get() != NULL);
504 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000505 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000506 EXPECT_TRUE(ti_audio != NULL);
507 if (has_current_desc) {
508 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
509 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
510 } else {
511 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
512 ti_audio->description.ice_ufrag.size());
513 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
514 ti_audio->description.ice_pwd.size());
515 }
zhihuang1c378ed2017-08-17 14:10:50 -0700516 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700517 FindFirstMediaDescriptionByMid("audio", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700518 EXPECT_EQ(
519 media_desc_options_it->transport_options.enable_ice_renomination,
520 GetIceRenomination(ti_audio));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000521
522 } else {
523 EXPECT_TRUE(ti_audio == NULL);
524 }
525 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000526 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000527 EXPECT_TRUE(ti_video != NULL);
528 if (options.bundle_enabled) {
529 EXPECT_EQ(ti_audio->description.ice_ufrag,
530 ti_video->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200531 EXPECT_EQ(ti_audio->description.ice_pwd, ti_video->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000532 } else {
533 if (has_current_desc) {
534 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
535 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
536 } else {
537 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
538 ti_video->description.ice_ufrag.size());
539 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
540 ti_video->description.ice_pwd.size());
541 }
542 }
zhihuang1c378ed2017-08-17 14:10:50 -0700543 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700544 FindFirstMediaDescriptionByMid("video", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700545 EXPECT_EQ(
546 media_desc_options_it->transport_options.enable_ice_renomination,
547 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000548 } else {
549 EXPECT_TRUE(ti_video == NULL);
550 }
551 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
552 if (options.has_data()) {
553 EXPECT_TRUE(ti_data != NULL);
554 if (options.bundle_enabled) {
555 EXPECT_EQ(ti_audio->description.ice_ufrag,
556 ti_data->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200557 EXPECT_EQ(ti_audio->description.ice_pwd, ti_data->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000558 } else {
559 if (has_current_desc) {
560 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
561 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
562 } else {
563 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
564 ti_data->description.ice_ufrag.size());
565 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
566 ti_data->description.ice_pwd.size());
567 }
568 }
zhihuang1c378ed2017-08-17 14:10:50 -0700569 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700570 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700571 EXPECT_EQ(
572 media_desc_options_it->transport_options.enable_ice_renomination,
573 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700574
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000575 } else {
576 EXPECT_TRUE(ti_video == NULL);
577 }
578 }
579
580 void TestCryptoWithBundle(bool offer) {
581 f1_.set_secure(SEC_ENABLED);
582 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -0800583 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
584 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
585 &options);
kwiberg31022942016-03-11 14:18:21 -0800586 std::unique_ptr<SessionDescription> ref_desc;
587 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000588 if (offer) {
589 options.bundle_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800590 ref_desc = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000591 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800592 desc = f1_.CreateOffer(options, ref_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000593 } else {
594 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800595 ref_desc = f1_.CreateOffer(options, NULL);
596 desc = f1_.CreateAnswer(ref_desc.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000597 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800598 ASSERT_TRUE(desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000599 const cricket::MediaContentDescription* audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800600 desc->GetContentDescriptionByName("audio");
601 ASSERT_TRUE(audio_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000602 const cricket::MediaContentDescription* video_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800603 desc->GetContentDescriptionByName("video");
604 ASSERT_TRUE(video_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000605 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
606 video_media_desc->cryptos()));
607 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
Steve Antone38a5a12018-11-21 16:05:15 -0800608 EXPECT_EQ(kDefaultSrtpCryptoSuite,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000609 audio_media_desc->cryptos()[0].cipher_suite);
610
611 // Verify the selected crypto is one from the reference audio
612 // media content.
613 const cricket::MediaContentDescription* ref_audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800614 ref_desc->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000615 bool found = false;
616 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
617 if (ref_audio_media_desc->cryptos()[i].Matches(
Yves Gerey665174f2018-06-19 15:03:05 +0200618 audio_media_desc->cryptos()[0])) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000619 found = true;
620 break;
621 }
622 }
623 EXPECT_TRUE(found);
624 }
625
626 // This test that the audio and video media direction is set to
627 // |expected_direction_in_answer| in an answer if the offer direction is set
zhihuang1c378ed2017-08-17 14:10:50 -0700628 // to |direction_in_offer| and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000629 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800630 RtpTransceiverDirection direction_in_offer,
631 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700632 MediaSessionOptions offer_opts;
633 AddAudioVideoSections(direction_in_offer, &offer_opts);
634
Steve Anton6fe1fba2018-12-11 10:15:23 -0800635 std::unique_ptr<SessionDescription> offer =
636 f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000637 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700638 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000639 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700640 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000641 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000642
zhihuang1c378ed2017-08-17 14:10:50 -0700643 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800644 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800645 std::unique_ptr<SessionDescription> answer =
646 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000647 const AudioContentDescription* acd_answer =
648 GetFirstAudioContentDescription(answer.get());
649 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
650 const VideoContentDescription* vcd_answer =
651 GetFirstVideoContentDescription(answer.get());
652 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
653 }
654
655 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800656 RTC_DCHECK(content);
657 RTC_CHECK(content->media_description());
658 const cricket::AudioContentDescription* audio_desc =
659 content->media_description()->as_audio();
660 RTC_CHECK(audio_desc);
661 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
662 if (codec.name == "CN") {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000663 return false;
Steve Antonb1c1de12017-12-21 15:14:30 -0800664 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000665 }
666 return true;
667 }
668
jbauchcb560652016-08-04 05:20:32 -0700669 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
670 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800671 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700672 offer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_offer;
zhihuang1c378ed2017-08-17 14:10:50 -0700673
jbauchcb560652016-08-04 05:20:32 -0700674 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800675 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700676 answer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_answer;
zhihuang1c378ed2017-08-17 14:10:50 -0700677
jbauchcb560652016-08-04 05:20:32 -0700678 f1_.set_secure(SEC_ENABLED);
679 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800680 std::unique_ptr<SessionDescription> offer =
681 f1_.CreateOffer(offer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700682 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800683 std::unique_ptr<SessionDescription> answer =
684 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700685 const ContentInfo* ac = answer->GetContentByName("audio");
686 const ContentInfo* vc = answer->GetContentByName("video");
687 ASSERT_TRUE(ac != NULL);
688 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800689 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
690 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800691 const AudioContentDescription* acd = ac->media_description()->as_audio();
692 const VideoContentDescription* vcd = vc->media_description()->as_video();
jbauchcb560652016-08-04 05:20:32 -0700693 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800694 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -0700695 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700696 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700697 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
698 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700699 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700700 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700701 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700702 }
703 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800704 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +0200705 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
706 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
jbauchcb560652016-08-04 05:20:32 -0700707 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700708 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700709 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700710 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700711 }
Steve Antone38a5a12018-11-21 16:05:15 -0800712 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
jbauchcb560652016-08-04 05:20:32 -0700713 }
714
Johannes Kronce8e8672019-02-22 13:06:44 +0100715 void TestTransportSequenceNumberNegotiation(
716 const cricket::RtpHeaderExtensions& local,
717 const cricket::RtpHeaderExtensions& offered,
718 const cricket::RtpHeaderExtensions& expectedAnswer) {
719 MediaSessionOptions opts;
720 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
721 f1_.set_audio_rtp_header_extensions(offered);
722 f1_.set_video_rtp_header_extensions(offered);
723 f2_.set_audio_rtp_header_extensions(local);
724 f2_.set_video_rtp_header_extensions(local);
725
726 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
727 ASSERT_TRUE(offer.get() != NULL);
728 std::unique_ptr<SessionDescription> answer =
729 f2_.CreateAnswer(offer.get(), opts, NULL);
730
731 EXPECT_EQ(
732 expectedAnswer,
733 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
734 EXPECT_EQ(
735 expectedAnswer,
736 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
737 }
738
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000739 protected:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800740 UniqueRandomIdGenerator ssrc_generator1;
741 UniqueRandomIdGenerator ssrc_generator2;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000742 MediaSessionDescriptionFactory f1_;
743 MediaSessionDescriptionFactory f2_;
744 TransportDescriptionFactory tdf1_;
745 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000746};
747
748// Create a typical audio offer, and ensure it matches what we expect.
749TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
750 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800751 std::unique_ptr<SessionDescription> offer =
752 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000753 ASSERT_TRUE(offer.get() != NULL);
754 const ContentInfo* ac = offer->GetContentByName("audio");
755 const ContentInfo* vc = offer->GetContentByName("video");
756 ASSERT_TRUE(ac != NULL);
757 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800758 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800759 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000760 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700761 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700762 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000763 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
764 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700765 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800766 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000767}
768
769// Create a typical video offer, and ensure it matches what we expect.
770TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
771 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800772 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000773 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800774 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000775 ASSERT_TRUE(offer.get() != NULL);
776 const ContentInfo* ac = offer->GetContentByName("audio");
777 const ContentInfo* vc = offer->GetContentByName("video");
778 ASSERT_TRUE(ac != NULL);
779 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800780 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
781 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800782 const AudioContentDescription* acd = ac->media_description()->as_audio();
783 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000784 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700785 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700786 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000787 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
788 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700789 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800790 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000791 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
792 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700793 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000794 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
795 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700796 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800797 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000798}
799
800// Test creating an offer with bundle where the Codecs have the same dynamic
801// RTP playlod type. The test verifies that the offer don't contain the
802// duplicate RTP payload types.
803TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
804 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700805 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200806 const RtpDataCodec& offered_data_codec = f2_.rtp_data_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000807 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
808 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
809
810 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800811 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
812 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000813 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800814 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000815 const VideoContentDescription* vcd =
816 GetFirstVideoContentDescription(offer.get());
817 const AudioContentDescription* acd =
818 GetFirstAudioContentDescription(offer.get());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200819 const RtpDataContentDescription* dcd =
820 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000821 ASSERT_TRUE(NULL != vcd);
822 ASSERT_TRUE(NULL != acd);
823 ASSERT_TRUE(NULL != dcd);
824 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
825 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
826 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
827 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
828 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
829 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
830}
831
zhihuang1c378ed2017-08-17 14:10:50 -0700832// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000833// after an audio only session has been negotiated.
834TEST_F(MediaSessionDescriptionFactoryTest,
835 TestCreateUpdatedVideoOfferWithBundle) {
836 f1_.set_secure(SEC_ENABLED);
837 f2_.set_secure(SEC_ENABLED);
838 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800839 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
840 RtpTransceiverDirection::kRecvOnly, kActive,
841 &opts);
842 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
843 RtpTransceiverDirection::kInactive, kStopped,
844 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000845 opts.data_channel_type = cricket::DCT_NONE;
846 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800847 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
848 std::unique_ptr<SessionDescription> answer =
849 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000850
851 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800852 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
853 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
854 &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000855 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800856 std::unique_ptr<SessionDescription> updated_offer(
857 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000858
859 const AudioContentDescription* acd =
860 GetFirstAudioContentDescription(updated_offer.get());
861 const VideoContentDescription* vcd =
862 GetFirstVideoContentDescription(updated_offer.get());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200863 const RtpDataContentDescription* dcd =
864 GetFirstRtpDataContentDescription(updated_offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000865 EXPECT_TRUE(NULL != vcd);
866 EXPECT_TRUE(NULL != acd);
867 EXPECT_TRUE(NULL != dcd);
868
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700869 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800870 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700871 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800872 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700873 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800874 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000875}
deadbeef44f08192015-12-15 16:20:09 -0800876
wu@webrtc.org78187522013-10-07 23:32:02 +0000877// Create a RTP data offer, and ensure it matches what we expect.
878TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000879 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800880 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
881 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000882 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800883 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000884 ASSERT_TRUE(offer.get() != NULL);
885 const ContentInfo* ac = offer->GetContentByName("audio");
886 const ContentInfo* dc = offer->GetContentByName("data");
887 ASSERT_TRUE(ac != NULL);
888 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800889 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
890 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800891 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200892 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000893 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700894 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700895 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000896 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
897 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700898 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800899 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000900 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200901 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700902 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000903 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +0200904 dcd->bandwidth()); // default bandwidth (auto)
905 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700906 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800907 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000908}
909
wu@webrtc.org78187522013-10-07 23:32:02 +0000910// Create an SCTP data offer with bundle without error.
911TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
912 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000913 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800914 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
wu@webrtc.org78187522013-10-07 23:32:02 +0000915 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800916 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.org78187522013-10-07 23:32:02 +0000917 EXPECT_TRUE(offer.get() != NULL);
918 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
919}
920
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000921// Test creating an sctp data channel from an already generated offer.
922TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
923 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000924 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800925 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000926 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800927 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000928 ASSERT_TRUE(offer1.get() != NULL);
929 const ContentInfo* data = offer1->GetContentByName("data");
930 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800931 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000932
933 // Now set data_channel_type to 'none' (default) and make sure that the
934 // datachannel type that gets generated from the previous offer, is of the
935 // same type.
936 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800937 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000938 f1_.CreateOffer(opts, offer1.get()));
939 data = offer2->GetContentByName("data");
940 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800941 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000942}
943
Steve Anton2bed3972019-01-04 17:04:30 -0800944// Test that if BUNDLE is enabled and all media sections are rejected then the
945// BUNDLE group is not present in the re-offer.
946TEST_F(MediaSessionDescriptionFactoryTest, ReOfferNoBundleGroupIfAllRejected) {
947 MediaSessionOptions opts;
948 opts.bundle_enabled = true;
949 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
950 RtpTransceiverDirection::kSendRecv, kActive,
951 &opts);
952 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
953
954 opts.media_description_options[0].stopped = true;
955 std::unique_ptr<SessionDescription> reoffer =
956 f1_.CreateOffer(opts, offer.get());
957
958 EXPECT_FALSE(reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
959}
960
961// Test that if BUNDLE is enabled and the remote re-offer does not include a
962// BUNDLE group since all media sections are rejected, then the re-answer also
963// does not include a BUNDLE group.
964TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerNoBundleGroupIfAllRejected) {
965 MediaSessionOptions opts;
966 opts.bundle_enabled = true;
967 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
968 RtpTransceiverDirection::kSendRecv, kActive,
969 &opts);
970 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
971 std::unique_ptr<SessionDescription> answer =
972 f2_.CreateAnswer(offer.get(), opts, nullptr);
973
974 opts.media_description_options[0].stopped = true;
975 std::unique_ptr<SessionDescription> reoffer =
976 f1_.CreateOffer(opts, offer.get());
977 std::unique_ptr<SessionDescription> reanswer =
978 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
979
980 EXPECT_FALSE(reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
981}
982
983// Test that if BUNDLE is enabled and the previous offerer-tagged media section
984// was rejected then the new offerer-tagged media section is the non-rejected
985// media section.
986TEST_F(MediaSessionDescriptionFactoryTest, ReOfferChangeBundleOffererTagged) {
987 MediaSessionOptions opts;
988 opts.bundle_enabled = true;
989 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
990 RtpTransceiverDirection::kSendRecv, kActive,
991 &opts);
992 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
993
994 // Reject the audio m= section and add a video m= section.
995 opts.media_description_options[0].stopped = true;
996 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
997 RtpTransceiverDirection::kSendRecv, kActive,
998 &opts);
999 std::unique_ptr<SessionDescription> reoffer =
1000 f1_.CreateOffer(opts, offer.get());
1001
1002 const cricket::ContentGroup* bundle_group =
1003 reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1004 ASSERT_TRUE(bundle_group);
1005 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1006 EXPECT_TRUE(bundle_group->HasContentName("video"));
1007}
1008
1009// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1010// was rejected and a new media section is added, then the re-answer BUNDLE
1011// group will contain only the non-rejected media section.
1012TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerChangedBundleOffererTagged) {
1013 MediaSessionOptions opts;
1014 opts.bundle_enabled = true;
1015 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1016 RtpTransceiverDirection::kSendRecv, kActive,
1017 &opts);
1018 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1019 std::unique_ptr<SessionDescription> answer =
1020 f2_.CreateAnswer(offer.get(), 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 std::unique_ptr<SessionDescription> reanswer =
1030 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1031
1032 const cricket::ContentGroup* bundle_group =
1033 reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1034 ASSERT_TRUE(bundle_group);
1035 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1036 EXPECT_TRUE(bundle_group->HasContentName("video"));
1037}
1038
1039// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1040// and there is still a non-rejected media section that was in the initial
1041// offer, then the ICE credentials do not change in the reoffer offerer-tagged
1042// media section.
1043TEST_F(MediaSessionDescriptionFactoryTest,
1044 ReOfferChangeBundleOffererTaggedKeepsIceCredentials) {
1045 MediaSessionOptions opts;
1046 opts.bundle_enabled = true;
1047 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1048 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1049 std::unique_ptr<SessionDescription> answer =
1050 f2_.CreateAnswer(offer.get(), opts, nullptr);
1051
1052 // Reject the audio m= section.
1053 opts.media_description_options[0].stopped = true;
1054 std::unique_ptr<SessionDescription> reoffer =
1055 f1_.CreateOffer(opts, offer.get());
1056
1057 const TransportDescription* offer_tagged =
1058 offer->GetTransportDescriptionByName("audio");
1059 ASSERT_TRUE(offer_tagged);
1060 const TransportDescription* reoffer_tagged =
1061 reoffer->GetTransportDescriptionByName("video");
1062 ASSERT_TRUE(reoffer_tagged);
1063 EXPECT_EQ(offer_tagged->ice_ufrag, reoffer_tagged->ice_ufrag);
1064 EXPECT_EQ(offer_tagged->ice_pwd, reoffer_tagged->ice_pwd);
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 reanswer answerer-tagged
1070// media section.
1071TEST_F(MediaSessionDescriptionFactoryTest,
1072 ReAnswerChangeBundleOffererTaggedKeepsIceCredentials) {
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 std::unique_ptr<SessionDescription> reanswer =
1085 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1086
1087 const TransportDescription* answer_tagged =
1088 answer->GetTransportDescriptionByName("audio");
1089 ASSERT_TRUE(answer_tagged);
1090 const TransportDescription* reanswer_tagged =
1091 reanswer->GetTransportDescriptionByName("video");
1092 ASSERT_TRUE(reanswer_tagged);
1093 EXPECT_EQ(answer_tagged->ice_ufrag, reanswer_tagged->ice_ufrag);
1094 EXPECT_EQ(answer_tagged->ice_pwd, reanswer_tagged->ice_pwd);
1095}
1096
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001097// Create an audio, video offer without legacy StreamParams.
1098TEST_F(MediaSessionDescriptionFactoryTest,
1099 TestCreateOfferWithoutLegacyStreams) {
1100 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001101 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001102 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001103 ASSERT_TRUE(offer.get() != NULL);
1104 const ContentInfo* ac = offer->GetContentByName("audio");
1105 const ContentInfo* vc = offer->GetContentByName("video");
1106 ASSERT_TRUE(ac != NULL);
1107 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001108 const AudioContentDescription* acd = ac->media_description()->as_audio();
1109 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001110
Yves Gerey665174f2018-06-19 15:03:05 +02001111 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1112 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001113}
1114
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001115// Creates an audio+video sendonly offer.
1116TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001117 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001118 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001119 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1120 {kMediaStream1}, 1, &opts);
1121 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1122 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001123
Steve Anton6fe1fba2018-12-11 10:15:23 -08001124 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001125 ASSERT_TRUE(offer.get() != NULL);
1126 EXPECT_EQ(2u, offer->contents().size());
1127 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
1128 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
1129
Steve Anton4e70a722017-11-28 14:57:10 -08001130 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1131 GetMediaDirection(&offer->contents()[0]));
1132 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1133 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001134}
1135
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001136// Verifies that the order of the media contents in the current
1137// SessionDescription is preserved in the new SessionDescription.
1138TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
1139 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001140 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001141
kwiberg31022942016-03-11 14:18:21 -08001142 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001143 ASSERT_TRUE(offer1.get() != NULL);
1144 EXPECT_EQ(1u, offer1->contents().size());
1145 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
1146
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001147 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1148 RtpTransceiverDirection::kRecvOnly, kActive,
1149 &opts);
kwiberg31022942016-03-11 14:18:21 -08001150 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001151 f1_.CreateOffer(opts, offer1.get()));
1152 ASSERT_TRUE(offer2.get() != NULL);
1153 EXPECT_EQ(2u, offer2->contents().size());
1154 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
1155 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
1156
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001157 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1158 RtpTransceiverDirection::kRecvOnly, kActive,
1159 &opts);
kwiberg31022942016-03-11 14:18:21 -08001160 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001161 f1_.CreateOffer(opts, offer2.get()));
1162 ASSERT_TRUE(offer3.get() != NULL);
1163 EXPECT_EQ(3u, offer3->contents().size());
1164 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
1165 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
1166 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001167}
1168
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001169// Create a typical audio answer, and ensure it matches what we expect.
1170TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
1171 f1_.set_secure(SEC_ENABLED);
1172 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001173 std::unique_ptr<SessionDescription> offer =
1174 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001175 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001176 std::unique_ptr<SessionDescription> answer =
1177 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001178 const ContentInfo* ac = answer->GetContentByName("audio");
1179 const ContentInfo* vc = answer->GetContentByName("video");
1180 ASSERT_TRUE(ac != NULL);
1181 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001182 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001183 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001184 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001185 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001186 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001187 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1188 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001189 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001190 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001191}
1192
jbauchcb560652016-08-04 05:20:32 -07001193// Create a typical audio answer with GCM ciphers enabled, and ensure it
1194// matches what we expect.
1195TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
1196 f1_.set_secure(SEC_ENABLED);
1197 f2_.set_secure(SEC_ENABLED);
zhihuang1c378ed2017-08-17 14:10:50 -07001198 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001199 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001200 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001201 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001202 std::unique_ptr<SessionDescription> answer =
1203 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001204 const ContentInfo* ac = answer->GetContentByName("audio");
1205 const ContentInfo* vc = answer->GetContentByName("video");
1206 ASSERT_TRUE(ac != NULL);
1207 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001208 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001209 const AudioContentDescription* acd = ac->media_description()->as_audio();
jbauchcb560652016-08-04 05:20:32 -07001210 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001211 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001212 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001213 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1214 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001215 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001216 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
jbauchcb560652016-08-04 05:20:32 -07001217}
1218
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001219// Create a typical video answer, and ensure it matches what we expect.
1220TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
1221 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001222 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001223 f1_.set_secure(SEC_ENABLED);
1224 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001225 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001226 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001227 std::unique_ptr<SessionDescription> answer =
1228 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001229 const ContentInfo* ac = answer->GetContentByName("audio");
1230 const ContentInfo* vc = answer->GetContentByName("video");
1231 ASSERT_TRUE(ac != NULL);
1232 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001233 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1234 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001235 const AudioContentDescription* acd = ac->media_description()->as_audio();
1236 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001237 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001238 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001239 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001240 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001241 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001242 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001243 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001244 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +02001245 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
1246 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001247 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001248 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001249}
1250
jbauchcb560652016-08-04 05:20:32 -07001251// Create a typical video answer with GCM ciphers enabled, and ensure it
1252// matches what we expect.
1253TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1254 TestVideoGcmCipher(true, true);
1255}
1256
1257// Create a typical video answer with GCM ciphers enabled for the offer only,
1258// and ensure it matches what we expect.
1259TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1260 TestVideoGcmCipher(true, false);
1261}
1262
1263// Create a typical video answer with GCM ciphers enabled for the answer only,
1264// and ensure it matches what we expect.
1265TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1266 TestVideoGcmCipher(false, true);
1267}
1268
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001269TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001270 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001271 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001272 f1_.set_secure(SEC_ENABLED);
1273 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001274 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001275 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001276 std::unique_ptr<SessionDescription> answer =
1277 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001278 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001279 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001280 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001281 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001282 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1283 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001284 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001285 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001286 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001287 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001288 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001289 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001290 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001291 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
zstein4b2e0822017-02-17 19:48:38 -08001292 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001293 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001294 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001295 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001296 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001297 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001298}
1299
jbauchcb560652016-08-04 05:20:32 -07001300TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
zhihuang1c378ed2017-08-17 14:10:50 -07001301 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001302 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001303 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
jbauchcb560652016-08-04 05:20:32 -07001304 f1_.set_secure(SEC_ENABLED);
1305 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001306 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001307 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001308 std::unique_ptr<SessionDescription> answer =
1309 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001310 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001311 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -07001312 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001313 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001314 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1315 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001316 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001317 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
jbauchcb560652016-08-04 05:20:32 -07001318 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001319 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -07001320 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001321 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001322 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001323 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
zstein4b2e0822017-02-17 19:48:38 -08001324 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001325 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001326 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001327 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001328 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001329 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
zstein4b2e0822017-02-17 19:48:38 -08001330}
1331
1332// The use_sctpmap flag should be set in a DataContentDescription by default.
1333// The answer's use_sctpmap flag should match the offer's.
1334TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1335 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001336 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001337 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001338 ASSERT_TRUE(offer.get() != NULL);
1339 ContentInfo* dc_offer = offer->GetContentByName("data");
1340 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001341 SctpDataContentDescription* dcd_offer =
1342 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001343 EXPECT_TRUE(dcd_offer->use_sctpmap());
1344
Steve Anton6fe1fba2018-12-11 10:15:23 -08001345 std::unique_ptr<SessionDescription> answer =
1346 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001347 const ContentInfo* dc_answer = answer->GetContentByName("data");
1348 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001349 const SctpDataContentDescription* dcd_answer =
1350 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001351 EXPECT_TRUE(dcd_answer->use_sctpmap());
1352}
1353
1354// The answer's use_sctpmap flag should match the offer's.
1355TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1356 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001357 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001358 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001359 ASSERT_TRUE(offer.get() != NULL);
1360 ContentInfo* dc_offer = offer->GetContentByName("data");
1361 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001362 SctpDataContentDescription* dcd_offer =
1363 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001364 dcd_offer->set_use_sctpmap(false);
1365
Steve Anton6fe1fba2018-12-11 10:15:23 -08001366 std::unique_ptr<SessionDescription> answer =
1367 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001368 const ContentInfo* dc_answer = answer->GetContentByName("data");
1369 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001370 const SctpDataContentDescription* dcd_answer =
1371 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001372 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001373}
1374
deadbeef8b7e9ad2017-05-25 09:38:55 -07001375// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1376// and "TCP/DTLS/SCTP" offers.
1377TEST_F(MediaSessionDescriptionFactoryTest,
1378 TestCreateDataAnswerToDifferentOfferedProtos) {
1379 // Need to enable DTLS offer/answer generation (disabled by default in this
1380 // test).
1381 f1_.set_secure(SEC_ENABLED);
1382 f2_.set_secure(SEC_ENABLED);
1383 tdf1_.set_secure(SEC_ENABLED);
1384 tdf2_.set_secure(SEC_ENABLED);
1385
1386 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001387 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001388 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001389 ASSERT_TRUE(offer.get() != nullptr);
1390 ContentInfo* dc_offer = offer->GetContentByName("data");
1391 ASSERT_TRUE(dc_offer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001392 SctpDataContentDescription* dcd_offer =
1393 dc_offer->media_description()->as_sctp();
1394 ASSERT_TRUE(dcd_offer);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001395
1396 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1397 "TCP/DTLS/SCTP"};
1398 for (const std::string& proto : protos) {
1399 dcd_offer->set_protocol(proto);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001400 std::unique_ptr<SessionDescription> answer =
1401 f2_.CreateAnswer(offer.get(), opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001402 const ContentInfo* dc_answer = answer->GetContentByName("data");
1403 ASSERT_TRUE(dc_answer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001404 const SctpDataContentDescription* dcd_answer =
1405 dc_answer->media_description()->as_sctp();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001406 EXPECT_FALSE(dc_answer->rejected);
1407 EXPECT_EQ(proto, dcd_answer->protocol());
1408 }
1409}
1410
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +02001411TEST_F(MediaSessionDescriptionFactoryTest,
1412 TestCreateDataAnswerToOfferWithDefinedMessageSize) {
1413 // Need to enable DTLS offer/answer generation (disabled by default in this
1414 // test).
1415 f1_.set_secure(SEC_ENABLED);
1416 f2_.set_secure(SEC_ENABLED);
1417 tdf1_.set_secure(SEC_ENABLED);
1418 tdf2_.set_secure(SEC_ENABLED);
1419
1420 MediaSessionOptions opts;
1421 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
1422 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1423 ASSERT_TRUE(offer.get() != nullptr);
1424 ContentInfo* dc_offer = offer->GetContentByName("data");
1425 ASSERT_TRUE(dc_offer != nullptr);
1426 SctpDataContentDescription* dcd_offer =
1427 dc_offer->media_description()->as_sctp();
1428 ASSERT_TRUE(dcd_offer);
1429 dcd_offer->set_max_message_size(1234);
1430 std::unique_ptr<SessionDescription> answer =
1431 f2_.CreateAnswer(offer.get(), opts, nullptr);
1432 const ContentInfo* dc_answer = answer->GetContentByName("data");
1433 ASSERT_TRUE(dc_answer != nullptr);
1434 const SctpDataContentDescription* dcd_answer =
1435 dc_answer->media_description()->as_sctp();
1436 EXPECT_FALSE(dc_answer->rejected);
1437 EXPECT_EQ(1234, dcd_answer->max_message_size());
1438}
1439
1440TEST_F(MediaSessionDescriptionFactoryTest,
1441 TestCreateDataAnswerToOfferWithZeroMessageSize) {
1442 // Need to enable DTLS offer/answer generation (disabled by default in this
1443 // test).
1444 f1_.set_secure(SEC_ENABLED);
1445 f2_.set_secure(SEC_ENABLED);
1446 tdf1_.set_secure(SEC_ENABLED);
1447 tdf2_.set_secure(SEC_ENABLED);
1448
1449 MediaSessionOptions opts;
1450 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
1451 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1452 ASSERT_TRUE(offer.get() != nullptr);
1453 ContentInfo* dc_offer = offer->GetContentByName("data");
1454 ASSERT_TRUE(dc_offer != nullptr);
1455 SctpDataContentDescription* dcd_offer =
1456 dc_offer->media_description()->as_sctp();
1457 ASSERT_TRUE(dcd_offer);
1458 dcd_offer->set_max_message_size(0);
1459 std::unique_ptr<SessionDescription> answer =
1460 f2_.CreateAnswer(offer.get(), opts, nullptr);
1461 const ContentInfo* dc_answer = answer->GetContentByName("data");
1462 ASSERT_TRUE(dc_answer != nullptr);
1463 const SctpDataContentDescription* dcd_answer =
1464 dc_answer->media_description()->as_sctp();
1465 EXPECT_FALSE(dc_answer->rejected);
1466 EXPECT_EQ(cricket::kSctpSendBufferSize, dcd_answer->max_message_size());
1467}
1468
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001469// Verifies that the order of the media contents in the offer is preserved in
1470// the answer.
1471TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1472 MediaSessionOptions opts;
1473
1474 // Creates a data only offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001475 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001476 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001477 ASSERT_TRUE(offer1.get() != NULL);
1478
1479 // Appends audio to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001480 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1481 RtpTransceiverDirection::kRecvOnly, kActive,
1482 &opts);
kwiberg31022942016-03-11 14:18:21 -08001483 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001484 f1_.CreateOffer(opts, offer1.get()));
1485 ASSERT_TRUE(offer2.get() != NULL);
1486
1487 // Appends video to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001488 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1489 RtpTransceiverDirection::kRecvOnly, kActive,
1490 &opts);
kwiberg31022942016-03-11 14:18:21 -08001491 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001492 f1_.CreateOffer(opts, offer2.get()));
1493 ASSERT_TRUE(offer3.get() != NULL);
1494
Steve Anton6fe1fba2018-12-11 10:15:23 -08001495 std::unique_ptr<SessionDescription> answer =
1496 f2_.CreateAnswer(offer3.get(), opts, NULL);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001497 ASSERT_TRUE(answer.get() != NULL);
1498 EXPECT_EQ(3u, answer->contents().size());
1499 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1500 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1501 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1502}
1503
ossu075af922016-06-14 03:29:38 -07001504// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1505// answerer settings.
1506
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001507// This test that the media direction is set to send/receive in an answer if
1508// the offer is send receive.
1509TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001510 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1511 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001512}
1513
1514// This test that the media direction is set to receive only in an answer if
1515// the offer is send only.
1516TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001517 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1518 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001519}
1520
1521// This test that the media direction is set to send only in an answer if
1522// the offer is recv only.
1523TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001524 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1525 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001526}
1527
1528// This test that the media direction is set to inactive in an answer if
1529// the offer is inactive.
1530TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001531 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1532 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001533}
1534
1535// Test that a data content with an unknown protocol is rejected in an answer.
1536TEST_F(MediaSessionDescriptionFactoryTest,
1537 CreateDataAnswerToOfferWithUnknownProtocol) {
1538 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001539 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001540 f1_.set_secure(SEC_ENABLED);
1541 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001542 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
terelius8c011e52016-04-26 05:28:11 -07001543 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001544 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001545 RtpDataContentDescription* dcd_offer =
1546 dc_offer->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001547 ASSERT_TRUE(dcd_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001548 // Offer must be acceptable as an RTP protocol in order to be set.
1549 std::string protocol = "RTP/a weird unknown protocol";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001550 dcd_offer->set_protocol(protocol);
1551
Steve Anton6fe1fba2018-12-11 10:15:23 -08001552 std::unique_ptr<SessionDescription> answer =
1553 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001554
1555 const ContentInfo* dc_answer = answer->GetContentByName("data");
1556 ASSERT_TRUE(dc_answer != NULL);
1557 EXPECT_TRUE(dc_answer->rejected);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001558 const RtpDataContentDescription* dcd_answer =
1559 dc_answer->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001560 ASSERT_TRUE(dcd_answer != NULL);
1561 EXPECT_EQ(protocol, dcd_answer->protocol());
1562}
1563
1564// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1565TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001566 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001567 f1_.set_secure(SEC_DISABLED);
1568 f2_.set_secure(SEC_DISABLED);
1569 tdf1_.set_secure(SEC_DISABLED);
1570 tdf2_.set_secure(SEC_DISABLED);
1571
Steve Anton6fe1fba2018-12-11 10:15:23 -08001572 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001573 const AudioContentDescription* offer_acd =
1574 GetFirstAudioContentDescription(offer.get());
1575 ASSERT_TRUE(offer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001576 EXPECT_EQ(cricket::kMediaProtocolAvpf, offer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001577
Steve Anton6fe1fba2018-12-11 10:15:23 -08001578 std::unique_ptr<SessionDescription> answer =
1579 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001580
1581 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1582 ASSERT_TRUE(ac_answer != NULL);
1583 EXPECT_FALSE(ac_answer->rejected);
1584
1585 const AudioContentDescription* answer_acd =
1586 GetFirstAudioContentDescription(answer.get());
1587 ASSERT_TRUE(answer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001588 EXPECT_EQ(cricket::kMediaProtocolAvpf, answer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001589}
1590
1591// Create a video offer and answer and ensure the RTP header extensions
1592// matches what we expect.
1593TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1594 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001595 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001596 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1597 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1598 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1599 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1600
Steve Anton6fe1fba2018-12-11 10:15:23 -08001601 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001602 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001603 std::unique_ptr<SessionDescription> answer =
1604 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001605
Yves Gerey665174f2018-06-19 15:03:05 +02001606 EXPECT_EQ(
1607 MAKE_VECTOR(kAudioRtpExtension1),
1608 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1609 EXPECT_EQ(
1610 MAKE_VECTOR(kVideoRtpExtension1),
1611 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1612 EXPECT_EQ(
1613 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1614 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1615 EXPECT_EQ(
1616 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1617 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001618}
1619
Johannes Kronce8e8672019-02-22 13:06:44 +01001620// Create a audio/video offer and answer and ensure that the
1621// TransportSequenceNumber RTP header extensions are handled correctly. 02 is
1622// supported and should take precedence even though not listed among locally
1623// supported extensions.
1624TEST_F(MediaSessionDescriptionFactoryTest,
1625 TestOfferAnswerWithTransportSequenceNumberInOffer) {
1626 TestTransportSequenceNumberNegotiation(
1627 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1628 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Offer.
1629 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01)); // Expected answer.
1630}
1631TEST_F(MediaSessionDescriptionFactoryTest,
1632 TestOfferAnswerWithTransportSequenceNumber01And02InOffer) {
1633 TestTransportSequenceNumberNegotiation(
1634 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1635 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01And02), // Offer.
1636 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1637}
1638TEST_F(MediaSessionDescriptionFactoryTest,
1639 TestOfferAnswerWithTransportSequenceNumber02InOffer) {
1640 TestTransportSequenceNumberNegotiation(
1641 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1642 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02), // Offer.
1643 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1644}
1645
jbauch5869f502017-06-29 12:31:36 -07001646TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001647 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
jbauch5869f502017-06-29 12:31:36 -07001648 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001649 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001650
1651 f1_.set_enable_encrypted_rtp_header_extensions(true);
1652 f2_.set_enable_encrypted_rtp_header_extensions(true);
1653
Yves Gerey665174f2018-06-19 15:03:05 +02001654 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1655 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1656 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1657 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001658
Steve Anton6fe1fba2018-12-11 10:15:23 -08001659 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001660 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001661 std::unique_ptr<SessionDescription> answer =
1662 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001663
Yves Gerey665174f2018-06-19 15:03:05 +02001664 EXPECT_EQ(
1665 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1666 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1667 EXPECT_EQ(
1668 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1669 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1670 EXPECT_EQ(
1671 MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
1672 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1673 EXPECT_EQ(
1674 MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
1675 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001676}
1677
1678TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001679 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
jbauch5869f502017-06-29 12:31:36 -07001680 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001681 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001682
1683 f1_.set_enable_encrypted_rtp_header_extensions(true);
1684
Yves Gerey665174f2018-06-19 15:03:05 +02001685 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1686 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1687 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1688 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001689
Steve Anton6fe1fba2018-12-11 10:15:23 -08001690 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001691 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001692 std::unique_ptr<SessionDescription> answer =
1693 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001694
Yves Gerey665174f2018-06-19 15:03:05 +02001695 EXPECT_EQ(
1696 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1697 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1698 EXPECT_EQ(
1699 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1700 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1701 EXPECT_EQ(
1702 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1703 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1704 EXPECT_EQ(
1705 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1706 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001707}
1708
1709TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001710 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
jbauch5869f502017-06-29 12:31:36 -07001711 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001712 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001713
1714 f2_.set_enable_encrypted_rtp_header_extensions(true);
1715
Yves Gerey665174f2018-06-19 15:03:05 +02001716 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1717 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1718 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1719 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001720
Steve Anton6fe1fba2018-12-11 10:15:23 -08001721 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001722 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001723 std::unique_ptr<SessionDescription> answer =
1724 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001725
Yves Gerey665174f2018-06-19 15:03:05 +02001726 EXPECT_EQ(
1727 MAKE_VECTOR(kAudioRtpExtension1),
1728 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1729 EXPECT_EQ(
1730 MAKE_VECTOR(kVideoRtpExtension1),
1731 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1732 EXPECT_EQ(
1733 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1734 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1735 EXPECT_EQ(
1736 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1737 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001738}
1739
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001740// Create an audio, video, data answer without legacy StreamParams.
1741TEST_F(MediaSessionDescriptionFactoryTest,
1742 TestCreateAnswerWithoutLegacyStreams) {
1743 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001744 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1745 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001746 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001747 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001748 std::unique_ptr<SessionDescription> answer =
1749 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001750 const ContentInfo* ac = answer->GetContentByName("audio");
1751 const ContentInfo* vc = answer->GetContentByName("video");
1752 const ContentInfo* dc = answer->GetContentByName("data");
1753 ASSERT_TRUE(ac != NULL);
1754 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001755 const AudioContentDescription* acd = ac->media_description()->as_audio();
1756 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001757 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001758
1759 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1760 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1761 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1762}
1763
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001764// Create a typical video answer, and ensure it matches what we expect.
1765TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1766 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001767 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
1768 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1769 &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001770
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001771 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001772 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
1773 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1774 &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001775
kwiberg31022942016-03-11 14:18:21 -08001776 std::unique_ptr<SessionDescription> offer;
1777 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001778
1779 offer_opts.rtcp_mux_enabled = true;
1780 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001781 offer = f1_.CreateOffer(offer_opts, NULL);
1782 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001783 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1784 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001785 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001786 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1787 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001788 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001789 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1790 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001791 EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001792 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1793 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001794 EXPECT_TRUE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001795
1796 offer_opts.rtcp_mux_enabled = true;
1797 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001798 offer = f1_.CreateOffer(offer_opts, NULL);
1799 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001800 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1801 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001802 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001803 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1804 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001805 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001806 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1807 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001808 EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001809 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1810 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001811 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001812
1813 offer_opts.rtcp_mux_enabled = false;
1814 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001815 offer = f1_.CreateOffer(offer_opts, NULL);
1816 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001817 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1818 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001819 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001820 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1821 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001822 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001823 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1824 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001825 EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001826 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1827 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001828 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001829
1830 offer_opts.rtcp_mux_enabled = false;
1831 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001832 offer = f1_.CreateOffer(offer_opts, NULL);
1833 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001834 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1835 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001836 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001837 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1838 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001839 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001840 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1841 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001842 EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001843 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1844 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001845 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001846}
1847
1848// Create an audio-only answer to a video offer.
1849TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1850 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001851 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1852 RtpTransceiverDirection::kRecvOnly, kActive,
1853 &opts);
1854 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1855 RtpTransceiverDirection::kRecvOnly, kActive,
1856 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001857 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001858 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001859
1860 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001861 std::unique_ptr<SessionDescription> answer =
1862 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001863 const ContentInfo* ac = answer->GetContentByName("audio");
1864 const ContentInfo* vc = answer->GetContentByName("video");
1865 ASSERT_TRUE(ac != NULL);
1866 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001867 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001868 EXPECT_TRUE(vc->rejected);
1869}
1870
1871// Create an audio-only answer to an offer with data.
1872TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001873 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001874 opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001875 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
1876 RtpTransceiverDirection::kRecvOnly, kActive,
1877 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001878 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001879 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001880
1881 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001882 std::unique_ptr<SessionDescription> answer =
1883 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001884 const ContentInfo* ac = answer->GetContentByName("audio");
1885 const ContentInfo* dc = answer->GetContentByName("data");
1886 ASSERT_TRUE(ac != NULL);
1887 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001888 ASSERT_TRUE(dc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001889 EXPECT_TRUE(dc->rejected);
1890}
1891
1892// Create an answer that rejects the contents which are rejected in the offer.
1893TEST_F(MediaSessionDescriptionFactoryTest,
1894 CreateAnswerToOfferWithRejectedMedia) {
1895 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001896 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1897 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001898 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001899 ASSERT_TRUE(offer.get() != NULL);
1900 ContentInfo* ac = offer->GetContentByName("audio");
1901 ContentInfo* vc = offer->GetContentByName("video");
1902 ContentInfo* dc = offer->GetContentByName("data");
1903 ASSERT_TRUE(ac != NULL);
1904 ASSERT_TRUE(vc != NULL);
1905 ASSERT_TRUE(dc != NULL);
1906 ac->rejected = true;
1907 vc->rejected = true;
1908 dc->rejected = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001909 std::unique_ptr<SessionDescription> answer =
1910 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001911 ac = answer->GetContentByName("audio");
1912 vc = answer->GetContentByName("video");
1913 dc = answer->GetContentByName("data");
1914 ASSERT_TRUE(ac != NULL);
1915 ASSERT_TRUE(vc != NULL);
1916 ASSERT_TRUE(dc != NULL);
1917 EXPECT_TRUE(ac->rejected);
1918 EXPECT_TRUE(vc->rejected);
1919 EXPECT_TRUE(dc->rejected);
1920}
1921
Johannes Kron0854eb62018-10-10 22:33:20 +02001922TEST_F(MediaSessionDescriptionFactoryTest,
1923 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensions) {
1924 MediaSessionOptions opts;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001925 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02001926 // Offer without request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001927 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02001928 ASSERT_TRUE(offer.get() != NULL);
1929 std::unique_ptr<SessionDescription> answer_no_support(
1930 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001931 EXPECT_FALSE(answer_no_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001932
1933 // Offer with request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001934 offer->set_extmap_allow_mixed(true);
Johannes Kron0854eb62018-10-10 22:33:20 +02001935 ASSERT_TRUE(offer.get() != NULL);
1936 std::unique_ptr<SessionDescription> answer_support(
1937 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001938 EXPECT_TRUE(answer_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001939}
1940
1941TEST_F(MediaSessionDescriptionFactoryTest,
1942 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensionsOnMediaLevel) {
1943 MediaSessionOptions opts;
1944 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001945 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02001946 MediaContentDescription* video_offer =
1947 offer->GetContentDescriptionByName("video");
1948 ASSERT_TRUE(video_offer);
1949 MediaContentDescription* audio_offer =
1950 offer->GetContentDescriptionByName("audio");
1951 ASSERT_TRUE(audio_offer);
1952
1953 // Explicit disable of mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001954 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
1955 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
Johannes Kron0854eb62018-10-10 22:33:20 +02001956
1957 ASSERT_TRUE(offer.get() != NULL);
1958 std::unique_ptr<SessionDescription> answer_no_support(
1959 f2_.CreateAnswer(offer.get(), opts, NULL));
1960 MediaContentDescription* video_answer =
1961 answer_no_support->GetContentDescriptionByName("video");
1962 MediaContentDescription* audio_answer =
1963 answer_no_support->GetContentDescriptionByName("audio");
1964 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001965 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001966 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001967 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001968
1969 // Enable mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001970 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
1971 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
Johannes Kron0854eb62018-10-10 22:33:20 +02001972 ASSERT_TRUE(offer.get() != NULL);
1973 std::unique_ptr<SessionDescription> answer_support(
1974 f2_.CreateAnswer(offer.get(), opts, NULL));
1975 video_answer = answer_support->GetContentDescriptionByName("video");
1976 audio_answer = answer_support->GetContentDescriptionByName("audio");
1977 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02001978 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001979 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02001980 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001981}
1982
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001983// Create an audio and video offer with:
1984// - one video track
1985// - two audio tracks
1986// - two data tracks
1987// and ensure it matches what we expect. Also updates the initial offer by
1988// adding a new video track and replaces one of the audio tracks.
1989TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
1990 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001991 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001992 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1993 {kMediaStream1}, 1, &opts);
1994 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1995 {kMediaStream1}, 1, &opts);
1996 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
1997 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001998
Steve Anton4e70a722017-11-28 14:57:10 -08001999 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002000 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2001 {kMediaStream1}, 1, &opts);
2002 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2003 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002004
2005 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002006 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002007
2008 ASSERT_TRUE(offer.get() != NULL);
2009 const ContentInfo* ac = offer->GetContentByName("audio");
2010 const ContentInfo* vc = offer->GetContentByName("video");
2011 const ContentInfo* dc = offer->GetContentByName("data");
2012 ASSERT_TRUE(ac != NULL);
2013 ASSERT_TRUE(vc != NULL);
2014 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002015 const AudioContentDescription* acd = ac->media_description()->as_audio();
2016 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002017 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002018 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07002019 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002020
2021 const StreamParamsVec& audio_streams = acd->streams();
2022 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002023 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002024 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2025 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2026 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2027 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2028 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2029 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2030
2031 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2032 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002033 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002034
2035 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
2036 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002037 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002038
2039 const StreamParamsVec& video_streams = vcd->streams();
2040 ASSERT_EQ(1U, video_streams.size());
2041 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2042 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2043 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2044 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2045
2046 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002047 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002048 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002049
2050 const StreamParamsVec& data_streams = dcd->streams();
2051 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002052 EXPECT_EQ(data_streams[0].cname, data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002053 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2054 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2055 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2056 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2057 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2058 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2059
2060 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002061 dcd->bandwidth()); // default bandwidth (auto)
2062 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002063 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002064
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002065 // Update the offer. Add a new video track that is not synched to the
2066 // other tracks and replace audio track 2 with audio track 3.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002067 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2068 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002069 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002070 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
2071 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002072 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002073 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack3,
2074 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08002075 std::unique_ptr<SessionDescription> updated_offer(
2076 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002077
2078 ASSERT_TRUE(updated_offer.get() != NULL);
2079 ac = updated_offer->GetContentByName("audio");
2080 vc = updated_offer->GetContentByName("video");
2081 dc = updated_offer->GetContentByName("data");
2082 ASSERT_TRUE(ac != NULL);
2083 ASSERT_TRUE(vc != NULL);
2084 ASSERT_TRUE(dc != NULL);
2085 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002086 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002087 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002088 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002089 const RtpDataContentDescription* updated_dcd =
2090 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002091
2092 EXPECT_EQ(acd->type(), updated_acd->type());
2093 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2094 EXPECT_EQ(vcd->type(), updated_vcd->type());
2095 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2096 EXPECT_EQ(dcd->type(), updated_dcd->type());
2097 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002098 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002099 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002100 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002101 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002102 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002103 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2104
2105 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2106 ASSERT_EQ(2U, updated_audio_streams.size());
2107 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
2108 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
2109 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
2110 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
2111 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
2112
2113 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2114 ASSERT_EQ(2U, updated_video_streams.size());
2115 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2116 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002117 // All the media streams in one PeerConnection share one RTCP CNAME.
2118 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002119
2120 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2121 ASSERT_EQ(2U, updated_data_streams.size());
2122 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
2123 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
2124 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
2125 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
2126 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07002127 // The stream correctly got the CNAME from the MediaSessionOptions.
2128 // The Expected RTCP CNAME is the default one as we are using the default
2129 // MediaSessionOptions.
2130 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002131}
2132
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002133// Create an offer with simulcast video stream.
2134TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
2135 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002136 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2137 RtpTransceiverDirection::kRecvOnly, kActive,
2138 &opts);
2139 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2140 RtpTransceiverDirection::kSendRecv, kActive,
2141 &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002142 const int num_sim_layers = 3;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002143 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2144 {kMediaStream1}, num_sim_layers, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002145 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002146
2147 ASSERT_TRUE(offer.get() != NULL);
2148 const ContentInfo* vc = offer->GetContentByName("video");
2149 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002150 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002151
2152 const StreamParamsVec& video_streams = vcd->streams();
2153 ASSERT_EQ(1U, video_streams.size());
2154 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2155 const SsrcGroup* sim_ssrc_group =
2156 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
2157 ASSERT_TRUE(sim_ssrc_group != NULL);
2158 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
2159}
2160
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002161MATCHER(RidDescriptionEquals, "Verifies that two RidDescriptions are equal.") {
2162 const RidDescription& rid1 = ::testing::get<0>(arg);
2163 const RidDescription& rid2 = ::testing::get<1>(arg);
2164 return rid1.rid == rid2.rid && rid1.direction == rid2.direction;
2165}
2166
2167static void CheckSimulcastInSessionDescription(
2168 const SessionDescription* description,
2169 const std::string& content_name,
2170 const std::vector<RidDescription>& send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002171 const SimulcastLayerList& send_layers) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002172 ASSERT_NE(description, nullptr);
2173 const ContentInfo* content = description->GetContentByName(content_name);
2174 ASSERT_NE(content, nullptr);
2175 const MediaContentDescription* cd = content->media_description();
2176 ASSERT_NE(cd, nullptr);
2177 const StreamParamsVec& streams = cd->streams();
2178 ASSERT_THAT(streams, SizeIs(1));
2179 const StreamParams& stream = streams[0];
2180 ASSERT_THAT(stream.ssrcs, IsEmpty());
2181 EXPECT_TRUE(stream.has_rids());
2182 const std::vector<RidDescription> rids = stream.rids();
2183
2184 EXPECT_THAT(rids, Pointwise(RidDescriptionEquals(), send_rids));
2185
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002186 EXPECT_TRUE(cd->HasSimulcast());
2187 const SimulcastDescription& simulcast = cd->simulcast_description();
2188 EXPECT_THAT(simulcast.send_layers(), SizeIs(send_layers.size()));
2189 EXPECT_THAT(simulcast.send_layers(), Pointwise(Eq(), send_layers));
2190
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002191 ASSERT_THAT(simulcast.receive_layers().GetAllLayers(), SizeIs(0));
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002192}
2193
2194// Create an offer with spec-compliant simulcast video stream.
2195TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastOffer) {
2196 MediaSessionOptions opts;
2197 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2198 RtpTransceiverDirection::kSendRecv, kActive,
2199 &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002200 std::vector<RidDescription> send_rids;
2201 send_rids.push_back(RidDescription("f", RidDirection::kSend));
2202 send_rids.push_back(RidDescription("h", RidDirection::kSend));
2203 send_rids.push_back(RidDescription("q", RidDirection::kSend));
2204 SimulcastLayerList simulcast_layers;
2205 simulcast_layers.AddLayer(SimulcastLayer(send_rids[0].rid, false));
2206 simulcast_layers.AddLayer(SimulcastLayer(send_rids[1].rid, true));
2207 simulcast_layers.AddLayer(SimulcastLayer(send_rids[2].rid, false));
2208 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2209 {kMediaStream1}, send_rids,
2210 simulcast_layers, 0, &opts);
2211 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2212
2213 CheckSimulcastInSessionDescription(offer.get(), "video", send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002214 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002215}
2216
2217// Create an offer that signals RIDs (not SSRCs) without Simulcast.
2218// In this scenario, RIDs do not need to be negotiated (there is only one).
2219TEST_F(MediaSessionDescriptionFactoryTest, TestOfferWithRidsNoSimulcast) {
2220 MediaSessionOptions opts;
2221 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2222 RtpTransceiverDirection::kSendRecv, kActive,
2223 &opts);
2224 RidDescription rid("f", RidDirection::kSend);
2225 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2226 {kMediaStream1}, {rid},
2227 SimulcastLayerList(), 0, &opts);
2228 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2229
2230 ASSERT_NE(offer.get(), nullptr);
2231 const ContentInfo* content = offer->GetContentByName("video");
2232 ASSERT_NE(content, nullptr);
2233 const MediaContentDescription* cd = content->media_description();
2234 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002235 const StreamParamsVec& streams = cd->streams();
2236 ASSERT_THAT(streams, SizeIs(1));
2237 const StreamParams& stream = streams[0];
2238 ASSERT_THAT(stream.ssrcs, IsEmpty());
2239 EXPECT_FALSE(stream.has_rids());
2240 EXPECT_FALSE(cd->HasSimulcast());
2241}
2242
2243// Create an answer with spec-compliant simulcast video stream.
2244// In this scenario, the SFU is the caller requesting that we send Simulcast.
2245TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastAnswer) {
2246 MediaSessionOptions offer_opts;
2247 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2248 RtpTransceiverDirection::kSendRecv, kActive,
2249 &offer_opts);
2250 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2251 {kMediaStream1}, 1, &offer_opts);
2252 std::unique_ptr<SessionDescription> offer =
2253 f1_.CreateOffer(offer_opts, nullptr);
2254
2255 MediaSessionOptions answer_opts;
2256 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2257 RtpTransceiverDirection::kSendRecv, kActive,
2258 &answer_opts);
2259
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002260 std::vector<RidDescription> rid_descriptions{
2261 RidDescription("f", RidDirection::kSend),
2262 RidDescription("h", RidDirection::kSend),
2263 RidDescription("q", RidDirection::kSend),
2264 };
2265 SimulcastLayerList simulcast_layers;
2266 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[0].rid, false));
2267 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[1].rid, true));
2268 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[2].rid, false));
2269 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2270 {kMediaStream1}, rid_descriptions,
2271 simulcast_layers, 0, &answer_opts);
2272 std::unique_ptr<SessionDescription> answer =
2273 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2274
2275 CheckSimulcastInSessionDescription(answer.get(), "video", rid_descriptions,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002276 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002277}
2278
2279// Create an answer that signals RIDs (not SSRCs) without Simulcast.
2280// In this scenario, RIDs do not need to be negotiated (there is only one).
2281// Note that RID Direction is not the same as the transceiver direction.
2282TEST_F(MediaSessionDescriptionFactoryTest, TestAnswerWithRidsNoSimulcast) {
2283 MediaSessionOptions offer_opts;
2284 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2285 RtpTransceiverDirection::kSendRecv, kActive,
2286 &offer_opts);
2287 RidDescription rid_offer("f", RidDirection::kSend);
2288 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2289 {kMediaStream1}, {rid_offer},
2290 SimulcastLayerList(), 0, &offer_opts);
2291 std::unique_ptr<SessionDescription> offer =
2292 f1_.CreateOffer(offer_opts, nullptr);
2293
2294 MediaSessionOptions answer_opts;
2295 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2296 RtpTransceiverDirection::kSendRecv, kActive,
2297 &answer_opts);
2298
2299 RidDescription rid_answer("f", RidDirection::kReceive);
2300 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2301 {kMediaStream1}, {rid_answer},
2302 SimulcastLayerList(), 0, &answer_opts);
2303 std::unique_ptr<SessionDescription> answer =
2304 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2305
2306 ASSERT_NE(answer.get(), nullptr);
2307 const ContentInfo* content = offer->GetContentByName("video");
2308 ASSERT_NE(content, nullptr);
2309 const MediaContentDescription* cd = content->media_description();
2310 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002311 const StreamParamsVec& streams = cd->streams();
2312 ASSERT_THAT(streams, SizeIs(1));
2313 const StreamParams& stream = streams[0];
2314 ASSERT_THAT(stream.ssrcs, IsEmpty());
2315 EXPECT_FALSE(stream.has_rids());
2316 EXPECT_FALSE(cd->HasSimulcast());
2317}
2318
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002319// Create an audio and video answer to a standard video offer with:
2320// - one video track
2321// - two audio tracks
2322// - two data tracks
2323// and ensure it matches what we expect. Also updates the initial answer by
2324// adding a new video track and removes one of the audio tracks.
2325TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
2326 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002327 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2328 RtpTransceiverDirection::kRecvOnly, kActive,
2329 &offer_opts);
2330 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2331 RtpTransceiverDirection::kRecvOnly, kActive,
2332 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002333 offer_opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002334 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2335 RtpTransceiverDirection::kRecvOnly, kActive,
2336 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002337 f1_.set_secure(SEC_ENABLED);
2338 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002339 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002340
zhihuang1c378ed2017-08-17 14:10:50 -07002341 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002342 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2343 RtpTransceiverDirection::kSendRecv, kActive,
2344 &answer_opts);
2345 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2346 RtpTransceiverDirection::kSendRecv, kActive,
2347 &answer_opts);
2348 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2349 {kMediaStream1}, 1, &answer_opts);
2350 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2351 {kMediaStream1}, 1, &answer_opts);
2352 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2353 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002354
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002355 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2356 RtpTransceiverDirection::kSendRecv, kActive,
2357 &answer_opts);
2358 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2359 {kMediaStream1}, 1, &answer_opts);
2360 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2361 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002362 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002363
Steve Anton6fe1fba2018-12-11 10:15:23 -08002364 std::unique_ptr<SessionDescription> answer =
2365 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002366
2367 ASSERT_TRUE(answer.get() != NULL);
2368 const ContentInfo* ac = answer->GetContentByName("audio");
2369 const ContentInfo* vc = answer->GetContentByName("video");
2370 const ContentInfo* dc = answer->GetContentByName("data");
2371 ASSERT_TRUE(ac != NULL);
2372 ASSERT_TRUE(vc != NULL);
2373 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002374 const AudioContentDescription* acd = ac->media_description()->as_audio();
2375 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002376 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002377 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
2378 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
2379 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002380
2381 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002382 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002383
2384 const StreamParamsVec& audio_streams = acd->streams();
2385 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002386 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002387 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2388 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2389 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2390 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2391 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2392 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2393
2394 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2395 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
2396
2397 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002398 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002399
2400 const StreamParamsVec& video_streams = vcd->streams();
2401 ASSERT_EQ(1U, video_streams.size());
2402 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2403 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2404 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2405 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2406
2407 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002408 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002409
2410 const StreamParamsVec& data_streams = dcd->streams();
2411 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002412 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002413 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2414 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2415 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2416 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2417 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2418 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2419
2420 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002421 dcd->bandwidth()); // default bandwidth (auto)
2422 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002423
2424 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07002425 // other tracks and remove 1 audio track.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002426 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2427 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002428 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
2429 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08002430 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002431 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002432
2433 ASSERT_TRUE(updated_answer.get() != NULL);
2434 ac = updated_answer->GetContentByName("audio");
2435 vc = updated_answer->GetContentByName("video");
2436 dc = updated_answer->GetContentByName("data");
2437 ASSERT_TRUE(ac != NULL);
2438 ASSERT_TRUE(vc != NULL);
2439 ASSERT_TRUE(dc != NULL);
2440 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002441 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002442 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002443 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002444 const RtpDataContentDescription* updated_dcd =
2445 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002446
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002447 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002448 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002449 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002450 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002451 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002452 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2453
2454 EXPECT_EQ(acd->type(), updated_acd->type());
2455 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2456 EXPECT_EQ(vcd->type(), updated_vcd->type());
2457 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2458 EXPECT_EQ(dcd->type(), updated_dcd->type());
2459 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
2460
2461 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2462 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002463 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002464
2465 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2466 ASSERT_EQ(2U, updated_video_streams.size());
2467 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2468 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002469 // All media streams in one PeerConnection share one CNAME.
2470 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002471
2472 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2473 ASSERT_EQ(1U, updated_data_streams.size());
2474 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
2475}
2476
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002477// Create an updated offer after creating an answer to the original offer and
2478// verify that the codecs that were part of the original answer are not changed
2479// in the updated offer.
2480TEST_F(MediaSessionDescriptionFactoryTest,
2481 RespondentCreatesOfferAfterCreatingAnswer) {
2482 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002483 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002484
Steve Anton6fe1fba2018-12-11 10:15:23 -08002485 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2486 std::unique_ptr<SessionDescription> answer =
2487 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002488
2489 const AudioContentDescription* acd =
2490 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002491 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002492
2493 const VideoContentDescription* vcd =
2494 GetFirstVideoContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002495 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002496
kwiberg31022942016-03-11 14:18:21 -08002497 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002498 f2_.CreateOffer(opts, answer.get()));
2499
2500 // The expected audio codecs are the common audio codecs from the first
2501 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
2502 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002503 // TODO(wu): |updated_offer| should not include the codec
2504 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002505 const AudioCodec kUpdatedAudioCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02002506 kAudioCodecsAnswer[0], kAudioCodecsAnswer[1], kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002507 };
2508
2509 // The expected video codecs are the common video codecs from the first
2510 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
2511 // preference order.
2512 const VideoCodec kUpdatedVideoCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02002513 kVideoCodecsAnswer[0], kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002514 };
2515
2516 const AudioContentDescription* updated_acd =
2517 GetFirstAudioContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002518 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kUpdatedAudioCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002519
2520 const VideoContentDescription* updated_vcd =
2521 GetFirstVideoContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002522 EXPECT_THAT(updated_vcd->codecs(), ElementsAreArray(kUpdatedVideoCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002523}
2524
Steve Anton5c72e712018-12-10 14:25:30 -08002525// Test that a reoffer does not reuse audio codecs from a previous media section
2526// that is being recycled.
2527TEST_F(MediaSessionDescriptionFactoryTest,
2528 ReOfferDoesNotReUseRecycledAudioCodecs) {
2529 f1_.set_video_codecs({});
2530 f2_.set_video_codecs({});
2531
2532 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002533 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2534 RtpTransceiverDirection::kSendRecv, kActive,
2535 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002536 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2537 std::unique_ptr<SessionDescription> answer =
2538 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002539
2540 // Recycle the media section by changing its mid.
2541 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002542 std::unique_ptr<SessionDescription> reoffer =
2543 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002544
2545 // Expect that the results of the first negotiation are ignored. If the m=
2546 // section was not recycled the payload types would match the initial offerer.
2547 const AudioContentDescription* acd =
2548 GetFirstAudioContentDescription(reoffer.get());
2549 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecs2));
2550}
2551
2552// Test that a reoffer does not reuse video codecs from a previous media section
2553// that is being recycled.
2554TEST_F(MediaSessionDescriptionFactoryTest,
2555 ReOfferDoesNotReUseRecycledVideoCodecs) {
2556 f1_.set_audio_codecs({}, {});
2557 f2_.set_audio_codecs({}, {});
2558
2559 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002560 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2561 RtpTransceiverDirection::kSendRecv, kActive,
2562 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002563 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2564 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002565
2566 // Recycle the media section by changing its mid.
2567 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002568 std::unique_ptr<SessionDescription> reoffer =
2569 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002570
2571 // Expect that the results of the first negotiation are ignored. If the m=
2572 // section was not recycled the payload types would match the initial offerer.
2573 const VideoContentDescription* vcd =
2574 GetFirstVideoContentDescription(reoffer.get());
2575 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecs2));
2576}
2577
2578// Test that a reanswer does not reuse audio codecs from a previous media
2579// section that is being recycled.
2580TEST_F(MediaSessionDescriptionFactoryTest,
2581 ReAnswerDoesNotReUseRecycledAudioCodecs) {
2582 f1_.set_video_codecs({});
2583 f2_.set_video_codecs({});
2584
2585 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2586 // second offer/answer is forward (|f1_| as offerer).
2587 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002588 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2589 RtpTransceiverDirection::kSendRecv, kActive,
2590 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002591 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2592 std::unique_ptr<SessionDescription> answer =
2593 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002594
2595 // Recycle the media section by changing its mid.
2596 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002597 std::unique_ptr<SessionDescription> reoffer =
2598 f1_.CreateOffer(opts, answer.get());
2599 std::unique_ptr<SessionDescription> reanswer =
2600 f2_.CreateAnswer(reoffer.get(), opts, offer.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 AudioContentDescription* acd =
2605 GetFirstAudioContentDescription(reanswer.get());
2606 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
2607}
2608
2609// Test that a reanswer does not reuse video codecs from a previous media
2610// section that is being recycled.
2611TEST_F(MediaSessionDescriptionFactoryTest,
2612 ReAnswerDoesNotReUseRecycledVideoCodecs) {
2613 f1_.set_audio_codecs({}, {});
2614 f2_.set_audio_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_VIDEO, "v0",
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 = "v1";
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 VideoContentDescription* vcd =
2636 GetFirstVideoContentDescription(reanswer.get());
2637 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
2638}
2639
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002640// Create an updated offer after creating an answer to the original offer and
2641// verify that the codecs that were part of the original answer are not changed
2642// in the updated offer. In this test Rtx is enabled.
2643TEST_F(MediaSessionDescriptionFactoryTest,
2644 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2645 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002646 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2647 RtpTransceiverDirection::kRecvOnly, kActive,
2648 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002649 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002650 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002651 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002652 f1_.set_video_codecs(f1_codecs);
2653
2654 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002655 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002656 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002657 f2_.set_video_codecs(f2_codecs);
2658
Steve Anton6fe1fba2018-12-11 10:15:23 -08002659 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002660 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002661 std::unique_ptr<SessionDescription> answer =
2662 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002663
2664 const VideoContentDescription* vcd =
2665 GetFirstVideoContentDescription(answer.get());
2666
2667 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002668 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2669 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002670
2671 EXPECT_EQ(expected_codecs, vcd->codecs());
2672
deadbeef67cf2c12016-04-13 10:07:16 -07002673 // Now, make sure we get same result (except for the order) if |f2_| creates
2674 // an updated offer even though the default payload types between |f1_| and
2675 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08002676 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002677 f2_.CreateOffer(opts, answer.get()));
2678 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002679 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002680 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2681
2682 const VideoContentDescription* updated_vcd =
2683 GetFirstVideoContentDescription(updated_answer.get());
2684
2685 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2686}
2687
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002688// Regression test for:
2689// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2690// Existing codecs should always appear before new codecs in re-offers. But
2691// under a specific set of circumstances, the existing RTX codec was ending up
2692// added to the end of the list.
2693TEST_F(MediaSessionDescriptionFactoryTest,
2694 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2695 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002696 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2697 RtpTransceiverDirection::kRecvOnly, kActive,
2698 &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002699 // We specifically choose different preferred payload types for VP8 to
2700 // trigger the issue.
2701 cricket::VideoCodec vp8_offerer(100, "VP8");
2702 cricket::VideoCodec vp8_offerer_rtx =
2703 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
2704 cricket::VideoCodec vp8_answerer(110, "VP8");
2705 cricket::VideoCodec vp8_answerer_rtx =
2706 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
2707 cricket::VideoCodec vp9(120, "VP9");
2708 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
2709
2710 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
2711 // We also specifically cause the answerer to prefer VP9, such that if it
2712 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
2713 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
2714 vp8_answerer_rtx};
2715
2716 f1_.set_video_codecs(f1_codecs);
2717 f2_.set_video_codecs(f2_codecs);
2718 std::vector<AudioCodec> audio_codecs;
2719 f1_.set_audio_codecs(audio_codecs, audio_codecs);
2720 f2_.set_audio_codecs(audio_codecs, audio_codecs);
2721
2722 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002723 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002724 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002725 std::unique_ptr<SessionDescription> answer =
2726 f2_.CreateAnswer(offer.get(), opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002727
2728 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
2729 // But if the bug is triggered, RTX for VP8 ends up last.
2730 std::unique_ptr<SessionDescription> updated_offer(
2731 f2_.CreateOffer(opts, answer.get()));
2732
2733 const VideoContentDescription* vcd =
2734 GetFirstVideoContentDescription(updated_offer.get());
2735 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
2736 ASSERT_EQ(4u, codecs.size());
2737 EXPECT_EQ(vp8_offerer, codecs[0]);
2738 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
2739 EXPECT_EQ(vp9, codecs[2]);
2740 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002741}
2742
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002743// Create an updated offer that adds video after creating an audio only answer
2744// to the original offer. This test verifies that if a video codec and the RTX
2745// codec have the same default payload type as an audio codec that is already in
2746// use, the added codecs payload types are changed.
2747TEST_F(MediaSessionDescriptionFactoryTest,
2748 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2749 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002750 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002751 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002752 f1_.set_video_codecs(f1_codecs);
2753
2754 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002755 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2756 RtpTransceiverDirection::kRecvOnly, kActive,
2757 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002758
Steve Anton6fe1fba2018-12-11 10:15:23 -08002759 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2760 std::unique_ptr<SessionDescription> answer =
2761 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002762
2763 const AudioContentDescription* acd =
2764 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002765 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002766
2767 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
2768 // reference be the same as an audio codec that was negotiated in the
2769 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002770 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08002771 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002772
2773 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2774 int used_pl_type = acd->codecs()[0].id;
2775 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002776 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002777 f2_.set_video_codecs(f2_codecs);
2778
kwiberg31022942016-03-11 14:18:21 -08002779 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002780 f2_.CreateOffer(opts, answer.get()));
2781 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002782 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002783 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2784
2785 const AudioContentDescription* updated_acd =
2786 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002787 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002788
2789 const VideoContentDescription* updated_vcd =
2790 GetFirstVideoContentDescription(updated_answer.get());
2791
2792 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
Steve Antone38a5a12018-11-21 16:05:15 -08002793 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02002794 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002795 EXPECT_NE(used_pl_type, new_h264_pl_type);
2796 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002797 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002798 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
2799 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
2800}
2801
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002802// Create an updated offer with RTX after creating an answer to an offer
2803// without RTX, and with different default payload types.
2804// Verify that the added RTX codec references the correct payload type.
2805TEST_F(MediaSessionDescriptionFactoryTest,
2806 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
2807 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002808 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002809
2810 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2811 // This creates rtx for H264 with the payload type |f2_| uses.
2812 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
2813 f2_.set_video_codecs(f2_codecs);
2814
Steve Anton6fe1fba2018-12-11 10:15:23 -08002815 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002816 ASSERT_TRUE(offer.get() != nullptr);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002817 std::unique_ptr<SessionDescription> answer =
2818 f2_.CreateAnswer(offer.get(), opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002819
2820 const VideoContentDescription* vcd =
2821 GetFirstVideoContentDescription(answer.get());
2822
2823 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2824 EXPECT_EQ(expected_codecs, vcd->codecs());
2825
2826 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
2827 // updated offer, even though the default payload types are different from
2828 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08002829 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002830 f2_.CreateOffer(opts, answer.get()));
2831 ASSERT_TRUE(updated_offer);
2832
2833 const VideoContentDescription* updated_vcd =
2834 GetFirstVideoContentDescription(updated_offer.get());
2835
2836 // New offer should attempt to add H263, and RTX for H264.
2837 expected_codecs.push_back(kVideoCodecs2[1]);
2838 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
2839 &expected_codecs);
2840 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2841}
2842
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002843// Test that RTX is ignored when there is no associated payload type parameter.
2844TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
2845 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002846 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2847 RtpTransceiverDirection::kRecvOnly, kActive,
2848 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002849 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002850 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07002851 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002852 f1_.set_video_codecs(f1_codecs);
2853
2854 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002855 // This creates RTX for H264 with the payload type |f2_| uses.
2856 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002857 f2_.set_video_codecs(f2_codecs);
2858
Steve Anton6fe1fba2018-12-11 10:15:23 -08002859 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002860 ASSERT_TRUE(offer.get() != NULL);
2861 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
2862 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
2863 // is possible to test that that RTX is dropped when
2864 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08002865 MediaContentDescription* media_desc =
2866 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2867 ASSERT_TRUE(media_desc);
2868 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002869 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07002870 for (VideoCodec& codec : codecs) {
2871 if (codec.name.find(cricket::kRtxCodecName) == 0) {
2872 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002873 }
2874 }
2875 desc->set_codecs(codecs);
2876
Steve Anton6fe1fba2018-12-11 10:15:23 -08002877 std::unique_ptr<SessionDescription> answer =
2878 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002879
Steve Anton64b626b2019-01-28 17:25:26 -08002880 EXPECT_THAT(
2881 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
2882 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002883}
2884
2885// Test that RTX will be filtered out in the answer if its associated payload
2886// type doesn't match the local value.
2887TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
2888 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002889 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2890 RtpTransceiverDirection::kRecvOnly, kActive,
2891 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002892 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2893 // This creates RTX for H264 in sender.
2894 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2895 f1_.set_video_codecs(f1_codecs);
2896
2897 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2898 // This creates RTX for H263 in receiver.
2899 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
2900 f2_.set_video_codecs(f2_codecs);
2901
Steve Anton6fe1fba2018-12-11 10:15:23 -08002902 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002903 ASSERT_TRUE(offer.get() != NULL);
2904 // Associated payload type doesn't match, therefore, RTX codec is removed in
2905 // the answer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002906 std::unique_ptr<SessionDescription> answer =
2907 f2_.CreateAnswer(offer.get(), opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002908
Steve Anton64b626b2019-01-28 17:25:26 -08002909 EXPECT_THAT(
2910 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
2911 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002912}
2913
2914// Test that when multiple RTX codecs are offered, only the matched RTX codec
2915// is added in the answer, and the unsupported RTX codec is filtered out.
2916TEST_F(MediaSessionDescriptionFactoryTest,
2917 FilterOutUnsupportedRtxWhenCreatingAnswer) {
2918 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002919 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2920 RtpTransceiverDirection::kRecvOnly, kActive,
2921 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002922 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2923 // This creates RTX for H264-SVC in sender.
2924 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2925 f1_.set_video_codecs(f1_codecs);
2926
2927 // This creates RTX for H264 in sender.
2928 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2929 f1_.set_video_codecs(f1_codecs);
2930
2931 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2932 // This creates RTX for H264 in receiver.
2933 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
2934 f2_.set_video_codecs(f2_codecs);
2935
2936 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
2937 // for H264-SVC should also be removed.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002938 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002939 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002940 std::unique_ptr<SessionDescription> answer =
2941 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002942 const VideoContentDescription* vcd =
2943 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002944 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2945 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2946 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002947
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002948 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002949}
2950
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002951// Test that after one RTX codec has been negotiated, a new offer can attempt
2952// to add another.
2953TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
2954 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002955 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2956 RtpTransceiverDirection::kRecvOnly, kActive,
2957 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002958 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2959 // This creates RTX for H264 for the offerer.
2960 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2961 f1_.set_video_codecs(f1_codecs);
2962
Steve Anton6fe1fba2018-12-11 10:15:23 -08002963 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002964 ASSERT_TRUE(offer);
2965 const VideoContentDescription* vcd =
2966 GetFirstVideoContentDescription(offer.get());
2967
2968 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
2969 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2970 &expected_codecs);
2971 EXPECT_EQ(expected_codecs, vcd->codecs());
2972
2973 // Now, attempt to add RTX for H264-SVC.
2974 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2975 f1_.set_video_codecs(f1_codecs);
2976
kwiberg31022942016-03-11 14:18:21 -08002977 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002978 f1_.CreateOffer(opts, offer.get()));
2979 ASSERT_TRUE(updated_offer);
2980 vcd = GetFirstVideoContentDescription(updated_offer.get());
2981
2982 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
2983 &expected_codecs);
2984 EXPECT_EQ(expected_codecs, vcd->codecs());
2985}
2986
Noah Richards2e7a0982015-05-18 14:02:54 -07002987// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
2988// generated for each simulcast ssrc and correctly grouped.
2989TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
2990 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002991 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2992 RtpTransceiverDirection::kSendRecv, kActive,
2993 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002994 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002995 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
2996 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002997
2998 // Use a single real codec, and then add RTX for it.
2999 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07003000 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07003001 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
3002 f1_.set_video_codecs(f1_codecs);
3003
3004 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
3005 // is a FID ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003006 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Noah Richards2e7a0982015-05-18 14:02:54 -07003007 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003008 MediaContentDescription* media_desc =
3009 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3010 ASSERT_TRUE(media_desc);
3011 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07003012 const StreamParamsVec& streams = desc->streams();
3013 // Single stream.
3014 ASSERT_EQ(1u, streams.size());
3015 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
3016 EXPECT_EQ(6u, streams[0].ssrcs.size());
3017 // And should have a SIM group for the simulcast.
3018 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3019 // And a FID group for RTX.
3020 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02003021 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003022 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3023 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02003024 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07003025 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
3026 EXPECT_EQ(3u, fid_ssrcs.size());
3027}
3028
brandtr03d5fb12016-11-22 03:37:59 -08003029// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
3030// together with a FEC-FR grouping.
3031TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
3032 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003033 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3034 RtpTransceiverDirection::kSendRecv, kActive,
3035 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003036 // Add single stream.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003037 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3038 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003039
3040 // Use a single real codec, and then add FlexFEC for it.
3041 std::vector<VideoCodec> f1_codecs;
3042 f1_codecs.push_back(VideoCodec(97, "H264"));
3043 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
3044 f1_.set_video_codecs(f1_codecs);
3045
3046 // Ensure that the offer has a single FlexFEC ssrc and that
3047 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003048 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003049 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003050 MediaContentDescription* media_desc =
3051 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3052 ASSERT_TRUE(media_desc);
3053 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003054 const StreamParamsVec& streams = desc->streams();
3055 // Single stream.
3056 ASSERT_EQ(1u, streams.size());
3057 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
3058 EXPECT_EQ(2u, streams[0].ssrcs.size());
3059 // And should have a FEC-FR group for FlexFEC.
3060 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
3061 std::vector<uint32_t> primary_ssrcs;
3062 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3063 ASSERT_EQ(1u, primary_ssrcs.size());
3064 uint32_t flexfec_ssrc;
3065 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
3066 EXPECT_NE(flexfec_ssrc, 0u);
3067}
3068
3069// Test that FlexFEC is disabled for simulcast.
3070// TODO(brandtr): Remove this test when we support simulcast, either through
3071// multiple FlexfecSenders, or through multistream protection.
3072TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
3073 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003074 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3075 RtpTransceiverDirection::kSendRecv, kActive,
3076 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003077 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003078 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3079 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003080
3081 // Use a single real codec, and then add FlexFEC for it.
3082 std::vector<VideoCodec> f1_codecs;
3083 f1_codecs.push_back(VideoCodec(97, "H264"));
3084 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
3085 f1_.set_video_codecs(f1_codecs);
3086
3087 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
3088 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003089 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003090 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003091 MediaContentDescription* media_desc =
3092 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3093 ASSERT_TRUE(media_desc);
3094 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003095 const StreamParamsVec& streams = desc->streams();
3096 // Single stream.
3097 ASSERT_EQ(1u, streams.size());
3098 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
3099 EXPECT_EQ(3u, streams[0].ssrcs.size());
3100 // And should have a SIM group for the simulcast.
3101 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3102 // And not a FEC-FR group for FlexFEC.
3103 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
3104 std::vector<uint32_t> primary_ssrcs;
3105 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3106 EXPECT_EQ(3u, primary_ssrcs.size());
3107 for (uint32_t primary_ssrc : primary_ssrcs) {
3108 uint32_t flexfec_ssrc;
3109 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
3110 }
3111}
3112
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003113// Create an updated offer after creating an answer to the original offer and
3114// verify that the RTP header extensions that were part of the original answer
3115// are not changed in the updated offer.
3116TEST_F(MediaSessionDescriptionFactoryTest,
3117 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
3118 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003119 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003120
3121 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
3122 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
3123 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
3124 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
3125
Steve Anton6fe1fba2018-12-11 10:15:23 -08003126 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
3127 std::unique_ptr<SessionDescription> answer =
3128 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003129
Yves Gerey665174f2018-06-19 15:03:05 +02003130 EXPECT_EQ(
3131 MAKE_VECTOR(kAudioRtpExtensionAnswer),
3132 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
3133 EXPECT_EQ(
3134 MAKE_VECTOR(kVideoRtpExtensionAnswer),
3135 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003136
kwiberg31022942016-03-11 14:18:21 -08003137 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003138 f2_.CreateOffer(opts, answer.get()));
3139
3140 // The expected RTP header extensions in the new offer are the resulting
3141 // extensions from the first offer/answer exchange plus the extensions only
3142 // |f2_| offer.
3143 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003144 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07003145 const RtpExtension kUpdatedAudioRtpExtensions[] = {
3146 kAudioRtpExtensionAnswer[0], RtpExtension(kAudioRtpExtension2[1].uri, 13),
3147 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003148 };
3149
3150 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003151 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07003152 const RtpExtension kUpdatedVideoRtpExtensions[] = {
3153 kVideoRtpExtensionAnswer[0], RtpExtension(kVideoRtpExtension2[1].uri, 12),
3154 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003155 };
3156
3157 const AudioContentDescription* updated_acd =
3158 GetFirstAudioContentDescription(updated_offer.get());
3159 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
3160 updated_acd->rtp_header_extensions());
3161
3162 const VideoContentDescription* updated_vcd =
3163 GetFirstVideoContentDescription(updated_offer.get());
3164 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
3165 updated_vcd->rtp_header_extensions());
3166}
3167
deadbeefa5b273a2015-08-20 17:30:13 -07003168// Verify that if the same RTP extension URI is used for audio and video, the
3169// same ID is used. Also verify that the ID isn't changed when creating an
3170// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07003171TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07003172 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003173 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07003174
3175 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
3176 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
3177
Steve Anton6fe1fba2018-12-11 10:15:23 -08003178 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
deadbeefa5b273a2015-08-20 17:30:13 -07003179
3180 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
3181 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07003182 const RtpExtension kExpectedVideoRtpExtension[] = {
3183 kVideoRtpExtension3[0], kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07003184 };
3185
Yves Gerey665174f2018-06-19 15:03:05 +02003186 EXPECT_EQ(
3187 MAKE_VECTOR(kAudioRtpExtension3),
3188 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3189 EXPECT_EQ(
3190 MAKE_VECTOR(kExpectedVideoRtpExtension),
3191 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003192
3193 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08003194 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07003195 f1_.CreateOffer(opts, offer.get()));
3196
3197 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02003198 GetFirstAudioContentDescription(updated_offer.get())
3199 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003200 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003201 GetFirstVideoContentDescription(updated_offer.get())
3202 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003203}
3204
jbauch5869f502017-06-29 12:31:36 -07003205// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
3206TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
3207 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003208 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07003209
3210 f1_.set_enable_encrypted_rtp_header_extensions(true);
3211 f2_.set_enable_encrypted_rtp_header_extensions(true);
3212
3213 f1_.set_audio_rtp_header_extensions(
3214 MAKE_VECTOR(kAudioRtpExtension3ForEncryption));
3215 f1_.set_video_rtp_header_extensions(
3216 MAKE_VECTOR(kVideoRtpExtension3ForEncryption));
3217
Steve Anton6fe1fba2018-12-11 10:15:23 -08003218 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07003219
3220 // The extensions that are shared between audio and video should use the same
3221 // id.
3222 const RtpExtension kExpectedVideoRtpExtension[] = {
3223 kVideoRtpExtension3ForEncryption[0],
3224 kAudioRtpExtension3ForEncryptionOffer[1],
3225 kAudioRtpExtension3ForEncryptionOffer[2],
3226 };
3227
Yves Gerey665174f2018-06-19 15:03:05 +02003228 EXPECT_EQ(
3229 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
3230 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3231 EXPECT_EQ(
3232 MAKE_VECTOR(kExpectedVideoRtpExtension),
3233 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003234
3235 // Nothing should change when creating a new offer
3236 std::unique_ptr<SessionDescription> updated_offer(
3237 f1_.CreateOffer(opts, offer.get()));
3238
3239 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003240 GetFirstAudioContentDescription(updated_offer.get())
3241 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003242 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003243 GetFirstVideoContentDescription(updated_offer.get())
3244 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003245}
3246
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003247TEST(MediaSessionDescription, CopySessionDescription) {
3248 SessionDescription source;
3249 cricket::ContentGroup group(cricket::CN_AUDIO);
3250 source.AddGroup(group);
3251 AudioContentDescription* acd(new AudioContentDescription());
3252 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
3253 acd->AddLegacyStream(1);
Steve Anton5adfafd2017-12-20 16:34:00 -08003254 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp, acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003255 VideoContentDescription* vcd(new VideoContentDescription());
3256 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
3257 vcd->AddLegacyStream(2);
Steve Anton5adfafd2017-12-20 16:34:00 -08003258 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp, vcd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003259
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003260 std::unique_ptr<SessionDescription> copy = source.Clone();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003261 ASSERT_TRUE(copy.get() != NULL);
3262 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
3263 const ContentInfo* ac = copy->GetContentByName("audio");
3264 const ContentInfo* vc = copy->GetContentByName("video");
3265 ASSERT_TRUE(ac != NULL);
3266 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08003267 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003268 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003269 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
3270 EXPECT_EQ(1u, acd->first_ssrc());
3271
Steve Anton5adfafd2017-12-20 16:34:00 -08003272 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003273 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003274 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
3275 EXPECT_EQ(2u, vcd->first_ssrc());
3276}
3277
3278// The below TestTransportInfoXXX tests create different offers/answers, and
3279// ensure the TransportInfo in the SessionDescription matches what we expect.
3280TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
3281 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003282 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3283 RtpTransceiverDirection::kRecvOnly, kActive,
3284 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003285 TestTransportInfo(true, options, false);
3286}
3287
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003288TEST_F(MediaSessionDescriptionFactoryTest,
3289 TestTransportInfoOfferIceRenomination) {
3290 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003291 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3292 RtpTransceiverDirection::kRecvOnly, kActive,
3293 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003294 options.media_description_options[0]
3295 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003296 TestTransportInfo(true, options, false);
3297}
3298
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003299TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
3300 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003301 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3302 RtpTransceiverDirection::kRecvOnly, kActive,
3303 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003304 TestTransportInfo(true, options, true);
3305}
3306
3307TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
3308 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003309 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3310 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3311 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003312 TestTransportInfo(true, options, false);
3313}
3314
3315TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003316 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003317 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003318 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3319 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3320 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003321 TestTransportInfo(true, options, true);
3322}
3323
3324TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
3325 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003326 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3327 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3328 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003329 options.bundle_enabled = true;
3330 TestTransportInfo(true, options, false);
3331}
3332
3333TEST_F(MediaSessionDescriptionFactoryTest,
3334 TestTransportInfoOfferBundleCurrent) {
3335 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003336 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3337 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3338 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003339 options.bundle_enabled = true;
3340 TestTransportInfo(true, options, true);
3341}
3342
3343TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
3344 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003345 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3346 RtpTransceiverDirection::kRecvOnly, kActive,
3347 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003348 TestTransportInfo(false, options, false);
3349}
3350
3351TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003352 TestTransportInfoAnswerIceRenomination) {
3353 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003354 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3355 RtpTransceiverDirection::kRecvOnly, kActive,
3356 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003357 options.media_description_options[0]
3358 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003359 TestTransportInfo(false, options, false);
3360}
3361
3362TEST_F(MediaSessionDescriptionFactoryTest,
3363 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003364 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003365 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3366 RtpTransceiverDirection::kRecvOnly, kActive,
3367 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003368 TestTransportInfo(false, options, true);
3369}
3370
3371TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
3372 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003373 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3374 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3375 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003376 TestTransportInfo(false, options, false);
3377}
3378
3379TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003380 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003381 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003382 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3383 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3384 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003385 TestTransportInfo(false, options, true);
3386}
3387
3388TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
3389 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003390 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3391 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3392 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003393 options.bundle_enabled = true;
3394 TestTransportInfo(false, options, false);
3395}
3396
3397TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003398 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003399 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003400 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3401 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3402 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003403 options.bundle_enabled = true;
3404 TestTransportInfo(false, options, true);
3405}
3406
3407// Create an offer with bundle enabled and verify the crypto parameters are
3408// the common set of the available cryptos.
3409TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
3410 TestCryptoWithBundle(true);
3411}
3412
3413// Create an answer with bundle enabled and verify the crypto parameters are
3414// the common set of the available cryptos.
3415TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
3416 TestCryptoWithBundle(false);
3417}
3418
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003419// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
3420// DTLS is not enabled locally.
3421TEST_F(MediaSessionDescriptionFactoryTest,
3422 TestOfferDtlsSavpfWithoutDtlsFailed) {
3423 f1_.set_secure(SEC_ENABLED);
3424 f2_.set_secure(SEC_ENABLED);
3425 tdf1_.set_secure(SEC_DISABLED);
3426 tdf2_.set_secure(SEC_DISABLED);
3427
Steve Anton6fe1fba2018-12-11 10:15:23 -08003428 std::unique_ptr<SessionDescription> offer =
3429 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003430 ASSERT_TRUE(offer.get() != NULL);
3431 ContentInfo* offer_content = offer->GetContentByName("audio");
3432 ASSERT_TRUE(offer_content != NULL);
3433 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003434 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003435 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3436
Steve Anton6fe1fba2018-12-11 10:15:23 -08003437 std::unique_ptr<SessionDescription> answer =
3438 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003439 ASSERT_TRUE(answer != NULL);
3440 ContentInfo* answer_content = answer->GetContentByName("audio");
3441 ASSERT_TRUE(answer_content != NULL);
3442
3443 ASSERT_TRUE(answer_content->rejected);
3444}
3445
3446// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
3447// UDP/TLS/RTP/SAVPF.
3448TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
3449 f1_.set_secure(SEC_ENABLED);
3450 f2_.set_secure(SEC_ENABLED);
3451 tdf1_.set_secure(SEC_ENABLED);
3452 tdf2_.set_secure(SEC_ENABLED);
3453
Steve Anton6fe1fba2018-12-11 10:15:23 -08003454 std::unique_ptr<SessionDescription> offer =
3455 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003456 ASSERT_TRUE(offer.get() != NULL);
3457 ContentInfo* offer_content = offer->GetContentByName("audio");
3458 ASSERT_TRUE(offer_content != NULL);
3459 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003460 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003461 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3462
Steve Anton6fe1fba2018-12-11 10:15:23 -08003463 std::unique_ptr<SessionDescription> answer =
3464 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003465 ASSERT_TRUE(answer != NULL);
3466
3467 const ContentInfo* answer_content = answer->GetContentByName("audio");
3468 ASSERT_TRUE(answer_content != NULL);
3469 ASSERT_FALSE(answer_content->rejected);
3470
3471 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003472 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08003473 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003474}
3475
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003476// Test that we include both SDES and DTLS in the offer, but only include SDES
3477// in the answer if DTLS isn't negotiated.
3478TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
3479 f1_.set_secure(SEC_ENABLED);
3480 f2_.set_secure(SEC_ENABLED);
3481 tdf1_.set_secure(SEC_ENABLED);
3482 tdf2_.set_secure(SEC_DISABLED);
3483 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003484 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08003485 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003486 const cricket::MediaContentDescription* audio_media_desc;
3487 const cricket::MediaContentDescription* video_media_desc;
3488 const cricket::TransportDescription* audio_trans_desc;
3489 const cricket::TransportDescription* video_trans_desc;
3490
3491 // Generate an offer with SDES and DTLS support.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003492 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003493 ASSERT_TRUE(offer.get() != NULL);
3494
Steve Antonb1c1de12017-12-21 15:14:30 -08003495 audio_media_desc = offer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003496 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003497 video_media_desc = offer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003498 ASSERT_TRUE(video_media_desc != NULL);
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07003499 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003500 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3501
3502 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3503 ASSERT_TRUE(audio_trans_desc != NULL);
3504 video_trans_desc = offer->GetTransportDescriptionByName("video");
3505 ASSERT_TRUE(video_trans_desc != NULL);
3506 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3507 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3508
3509 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003510 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003511 ASSERT_TRUE(answer.get() != NULL);
3512
Steve Antonb1c1de12017-12-21 15:14:30 -08003513 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003514 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003515 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003516 ASSERT_TRUE(video_media_desc != NULL);
3517 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3518 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3519
3520 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3521 ASSERT_TRUE(audio_trans_desc != NULL);
3522 video_trans_desc = answer->GetTransportDescriptionByName("video");
3523 ASSERT_TRUE(video_trans_desc != NULL);
3524 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
3525 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
3526
3527 // Enable DTLS; the answer should now only have DTLS support.
3528 tdf2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003529 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003530 ASSERT_TRUE(answer.get() != NULL);
3531
Steve Antonb1c1de12017-12-21 15:14:30 -08003532 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003533 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003534 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003535 ASSERT_TRUE(video_media_desc != NULL);
3536 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3537 EXPECT_TRUE(video_media_desc->cryptos().empty());
Steve Antone38a5a12018-11-21 16:05:15 -08003538 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
3539 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003540
3541 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3542 ASSERT_TRUE(audio_trans_desc != NULL);
3543 video_trans_desc = answer->GetTransportDescriptionByName("video");
3544 ASSERT_TRUE(video_trans_desc != NULL);
3545 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3546 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003547
3548 // Try creating offer again. DTLS enabled now, crypto's should be empty
3549 // in new offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003550 offer = f1_.CreateOffer(options, offer.get());
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003551 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003552 audio_media_desc = offer->GetContentDescriptionByName("audio");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003553 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003554 video_media_desc = offer->GetContentDescriptionByName("video");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003555 ASSERT_TRUE(video_media_desc != NULL);
3556 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3557 EXPECT_TRUE(video_media_desc->cryptos().empty());
3558
3559 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3560 ASSERT_TRUE(audio_trans_desc != NULL);
3561 video_trans_desc = offer->GetTransportDescriptionByName("video");
3562 ASSERT_TRUE(video_trans_desc != NULL);
3563 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3564 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003565}
3566
3567// Test that an answer can't be created if cryptos are required but the offer is
3568// unsecure.
3569TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003570 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003571 f1_.set_secure(SEC_DISABLED);
3572 tdf1_.set_secure(SEC_DISABLED);
3573 f2_.set_secure(SEC_REQUIRED);
3574 tdf1_.set_secure(SEC_ENABLED);
3575
Steve Anton6fe1fba2018-12-11 10:15:23 -08003576 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003577 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003578 std::unique_ptr<SessionDescription> answer =
3579 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003580 EXPECT_TRUE(answer.get() == NULL);
3581}
3582
3583// Test that we accept a DTLS offer without SDES and create an appropriate
3584// answer.
3585TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
3586 f1_.set_secure(SEC_DISABLED);
3587 f2_.set_secure(SEC_ENABLED);
3588 tdf1_.set_secure(SEC_ENABLED);
3589 tdf2_.set_secure(SEC_ENABLED);
3590 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003591 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3592 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3593 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003594
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003595 // Generate an offer with DTLS but without SDES.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003596 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003597 ASSERT_TRUE(offer.get() != NULL);
3598
3599 const AudioContentDescription* audio_offer =
3600 GetFirstAudioContentDescription(offer.get());
3601 ASSERT_TRUE(audio_offer->cryptos().empty());
3602 const VideoContentDescription* video_offer =
3603 GetFirstVideoContentDescription(offer.get());
3604 ASSERT_TRUE(video_offer->cryptos().empty());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02003605 const RtpDataContentDescription* data_offer =
3606 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003607 ASSERT_TRUE(data_offer->cryptos().empty());
3608
3609 const cricket::TransportDescription* audio_offer_trans_desc =
3610 offer->GetTransportDescriptionByName("audio");
3611 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
3612 const cricket::TransportDescription* video_offer_trans_desc =
3613 offer->GetTransportDescriptionByName("video");
3614 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
3615 const cricket::TransportDescription* data_offer_trans_desc =
3616 offer->GetTransportDescriptionByName("data");
3617 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
3618
3619 // Generate an answer with DTLS.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003620 std::unique_ptr<SessionDescription> answer =
3621 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003622 ASSERT_TRUE(answer.get() != NULL);
3623
3624 const cricket::TransportDescription* audio_answer_trans_desc =
3625 answer->GetTransportDescriptionByName("audio");
3626 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3627 const cricket::TransportDescription* video_answer_trans_desc =
3628 answer->GetTransportDescriptionByName("video");
3629 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
3630 const cricket::TransportDescription* data_answer_trans_desc =
3631 answer->GetTransportDescriptionByName("data");
3632 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
3633}
3634
3635// Verifies if vad_enabled option is set to false, CN codecs are not present in
3636// offer or answer.
3637TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3638 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003639 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003640 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003641 ASSERT_TRUE(offer.get() != NULL);
3642 const ContentInfo* audio_content = offer->GetContentByName("audio");
3643 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
3644
3645 options.vad_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08003646 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003647 ASSERT_TRUE(offer.get() != NULL);
3648 audio_content = offer->GetContentByName("audio");
3649 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
Steve Anton6fe1fba2018-12-11 10:15:23 -08003650 std::unique_ptr<SessionDescription> answer =
3651 f1_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003652 ASSERT_TRUE(answer.get() != NULL);
3653 audio_content = answer->GetContentByName("audio");
3654 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
3655}
deadbeef44f08192015-12-15 16:20:09 -08003656
zhihuang1c378ed2017-08-17 14:10:50 -07003657// Test that the generated MIDs match the existing offer.
3658TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08003659 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003660 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_modified",
3661 RtpTransceiverDirection::kRecvOnly, kActive,
3662 &opts);
3663 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_modified",
3664 RtpTransceiverDirection::kRecvOnly, kActive,
3665 &opts);
deadbeef44f08192015-12-15 16:20:09 -08003666 opts.data_channel_type = cricket::DCT_SCTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003667 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data_modified",
3668 RtpTransceiverDirection::kSendRecv, kActive,
3669 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003670 // Create offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003671 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
kwiberg31022942016-03-11 14:18:21 -08003672 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08003673 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003674
deadbeef44f08192015-12-15 16:20:09 -08003675 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3676 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3677 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3678 ASSERT_TRUE(audio_content != nullptr);
3679 ASSERT_TRUE(video_content != nullptr);
3680 ASSERT_TRUE(data_content != nullptr);
3681 EXPECT_EQ("audio_modified", audio_content->name);
3682 EXPECT_EQ("video_modified", video_content->name);
3683 EXPECT_EQ("data_modified", data_content->name);
3684}
zhihuangcf5b37c2016-05-05 11:44:35 -07003685
zhihuang1c378ed2017-08-17 14:10:50 -07003686// The following tests verify that the unified plan SDP is supported.
3687// Test that we can create an offer with multiple media sections of same media
3688// type.
3689TEST_F(MediaSessionDescriptionFactoryTest,
3690 CreateOfferWithMultipleAVMediaSections) {
3691 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003692 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3693 RtpTransceiverDirection::kSendRecv, kActive,
3694 &opts);
3695 AttachSenderToMediaDescriptionOptions(
3696 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003697
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003698 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3699 RtpTransceiverDirection::kSendRecv, kActive,
3700 &opts);
3701 AttachSenderToMediaDescriptionOptions(
3702 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003703
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003704 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3705 RtpTransceiverDirection::kSendRecv, kActive,
3706 &opts);
3707 AttachSenderToMediaDescriptionOptions(
3708 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003709
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003710 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3711 RtpTransceiverDirection::kSendRecv, kActive,
3712 &opts);
3713 AttachSenderToMediaDescriptionOptions(
3714 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003715 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003716 ASSERT_TRUE(offer);
3717
3718 ASSERT_EQ(4u, offer->contents().size());
3719 EXPECT_FALSE(offer->contents()[0].rejected);
3720 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003721 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003722 ASSERT_EQ(1u, acd->streams().size());
3723 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003724 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003725
3726 EXPECT_FALSE(offer->contents()[1].rejected);
3727 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003728 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003729 ASSERT_EQ(1u, vcd->streams().size());
3730 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003731 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003732
3733 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003734 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003735 ASSERT_EQ(1u, acd->streams().size());
3736 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003737 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003738
3739 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003740 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003741 ASSERT_EQ(1u, vcd->streams().size());
3742 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003743 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003744}
3745
3746// Test that we can create an answer with multiple media sections of same media
3747// type.
3748TEST_F(MediaSessionDescriptionFactoryTest,
3749 CreateAnswerWithMultipleAVMediaSections) {
3750 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003751 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3752 RtpTransceiverDirection::kSendRecv, kActive,
3753 &opts);
3754 AttachSenderToMediaDescriptionOptions(
3755 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003756
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003757 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3758 RtpTransceiverDirection::kSendRecv, kActive,
3759 &opts);
3760 AttachSenderToMediaDescriptionOptions(
3761 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003762
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003763 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3764 RtpTransceiverDirection::kSendRecv, kActive,
3765 &opts);
3766 AttachSenderToMediaDescriptionOptions(
3767 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003768
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003769 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3770 RtpTransceiverDirection::kSendRecv, kActive,
3771 &opts);
3772 AttachSenderToMediaDescriptionOptions(
3773 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003774
Steve Anton6fe1fba2018-12-11 10:15:23 -08003775 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003776 ASSERT_TRUE(offer);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003777 std::unique_ptr<SessionDescription> answer =
3778 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003779
3780 ASSERT_EQ(4u, answer->contents().size());
3781 EXPECT_FALSE(answer->contents()[0].rejected);
3782 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003783 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003784 ASSERT_EQ(1u, acd->streams().size());
3785 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003786 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003787
3788 EXPECT_FALSE(answer->contents()[1].rejected);
3789 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003790 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003791 ASSERT_EQ(1u, vcd->streams().size());
3792 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003793 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003794
3795 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003796 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003797 ASSERT_EQ(1u, acd->streams().size());
3798 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003799 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003800
3801 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003802 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003803 ASSERT_EQ(1u, vcd->streams().size());
3804 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003805 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003806}
3807
3808// Test that the media section will be rejected in offer if the corresponding
3809// MediaDescriptionOptions is stopped by the offerer.
3810TEST_F(MediaSessionDescriptionFactoryTest,
3811 CreateOfferWithMediaSectionStoppedByOfferer) {
3812 // Create an offer with two audio sections and one of them is stopped.
3813 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003814 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3815 RtpTransceiverDirection::kSendRecv, kActive,
3816 &offer_opts);
3817 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3818 RtpTransceiverDirection::kInactive, kStopped,
3819 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003820 std::unique_ptr<SessionDescription> offer =
3821 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003822 ASSERT_TRUE(offer);
3823 ASSERT_EQ(2u, offer->contents().size());
3824 EXPECT_FALSE(offer->contents()[0].rejected);
3825 EXPECT_TRUE(offer->contents()[1].rejected);
3826}
3827
3828// Test that the media section will be rejected in answer if the corresponding
3829// MediaDescriptionOptions is stopped by the offerer.
3830TEST_F(MediaSessionDescriptionFactoryTest,
3831 CreateAnswerWithMediaSectionStoppedByOfferer) {
3832 // Create an offer with two audio sections and one of them is stopped.
3833 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003834 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3835 RtpTransceiverDirection::kSendRecv, kActive,
3836 &offer_opts);
3837 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3838 RtpTransceiverDirection::kInactive, kStopped,
3839 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003840 std::unique_ptr<SessionDescription> offer =
3841 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003842 ASSERT_TRUE(offer);
3843 ASSERT_EQ(2u, offer->contents().size());
3844 EXPECT_FALSE(offer->contents()[0].rejected);
3845 EXPECT_TRUE(offer->contents()[1].rejected);
3846
3847 // Create an answer based on the offer.
3848 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003849 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3850 RtpTransceiverDirection::kSendRecv, kActive,
3851 &answer_opts);
3852 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3853 RtpTransceiverDirection::kSendRecv, kActive,
3854 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003855 std::unique_ptr<SessionDescription> answer =
3856 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003857 ASSERT_EQ(2u, answer->contents().size());
3858 EXPECT_FALSE(answer->contents()[0].rejected);
3859 EXPECT_TRUE(answer->contents()[1].rejected);
3860}
3861
3862// Test that the media section will be rejected in answer if the corresponding
3863// MediaDescriptionOptions is stopped by the answerer.
3864TEST_F(MediaSessionDescriptionFactoryTest,
3865 CreateAnswerWithMediaSectionRejectedByAnswerer) {
3866 // Create an offer with two audio sections.
3867 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003868 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3869 RtpTransceiverDirection::kSendRecv, kActive,
3870 &offer_opts);
3871 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3872 RtpTransceiverDirection::kSendRecv, kActive,
3873 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003874 std::unique_ptr<SessionDescription> offer =
3875 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003876 ASSERT_TRUE(offer);
3877 ASSERT_EQ(2u, offer->contents().size());
3878 ASSERT_FALSE(offer->contents()[0].rejected);
3879 ASSERT_FALSE(offer->contents()[1].rejected);
3880
3881 // The answerer rejects one of the audio sections.
3882 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003883 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3884 RtpTransceiverDirection::kSendRecv, kActive,
3885 &answer_opts);
3886 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3887 RtpTransceiverDirection::kInactive, kStopped,
3888 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003889 std::unique_ptr<SessionDescription> answer =
3890 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003891 ASSERT_EQ(2u, answer->contents().size());
3892 EXPECT_FALSE(answer->contents()[0].rejected);
3893 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08003894
3895 // The TransportInfo of the rejected m= section is expected to be added in the
3896 // answer.
3897 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07003898}
3899
3900// Test the generated media sections has the same order of the
3901// corresponding MediaDescriptionOptions.
3902TEST_F(MediaSessionDescriptionFactoryTest,
3903 CreateOfferRespectsMediaDescriptionOptionsOrder) {
3904 MediaSessionOptions opts;
3905 // This tests put video section first because normally audio comes first by
3906 // default.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003907 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3908 RtpTransceiverDirection::kSendRecv, kActive,
3909 &opts);
3910 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3911 RtpTransceiverDirection::kSendRecv, kActive,
3912 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003913 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003914
3915 ASSERT_TRUE(offer);
3916 ASSERT_EQ(2u, offer->contents().size());
3917 EXPECT_EQ("video", offer->contents()[0].name);
3918 EXPECT_EQ("audio", offer->contents()[1].name);
3919}
3920
3921// Test that different media sections using the same codec have same payload
3922// type.
3923TEST_F(MediaSessionDescriptionFactoryTest,
3924 PayloadTypesSharedByMediaSectionsOfSameType) {
3925 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003926 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
3927 RtpTransceiverDirection::kSendRecv, kActive,
3928 &opts);
3929 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
3930 RtpTransceiverDirection::kSendRecv, kActive,
3931 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003932 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003933 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003934 ASSERT_TRUE(offer);
3935 ASSERT_EQ(2u, offer->contents().size());
3936 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003937 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003938 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003939 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003940 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3941 ASSERT_EQ(2u, vcd1->codecs().size());
3942 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3943 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3944 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
3945 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
3946
3947 // Create answer and negotiate the codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003948 std::unique_ptr<SessionDescription> answer =
3949 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003950 ASSERT_TRUE(answer);
3951 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08003952 vcd1 = answer->contents()[0].media_description()->as_video();
3953 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003954 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3955 ASSERT_EQ(1u, vcd1->codecs().size());
3956 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3957 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3958}
3959
3960// Test that the codec preference order per media section is respected in
3961// subsequent offer.
3962TEST_F(MediaSessionDescriptionFactoryTest,
3963 CreateOfferRespectsCodecPreferenceOrder) {
3964 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003965 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
3966 RtpTransceiverDirection::kSendRecv, kActive,
3967 &opts);
3968 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
3969 RtpTransceiverDirection::kSendRecv, kActive,
3970 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003971 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003972 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003973 ASSERT_TRUE(offer);
3974 ASSERT_EQ(2u, offer->contents().size());
3975 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003976 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003977 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003978 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003979 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3980 EXPECT_EQ(video_codecs, vcd1->codecs());
3981 EXPECT_EQ(video_codecs, vcd2->codecs());
3982
3983 // Change the codec preference of the first video section and create a
3984 // follow-up offer.
3985 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3986 vcd1->set_codecs(video_codecs_reverse);
3987 std::unique_ptr<SessionDescription> updated_offer(
3988 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08003989 vcd1 = updated_offer->contents()[0].media_description()->as_video();
3990 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003991 // The video codec preference order should be respected.
3992 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3993 EXPECT_EQ(video_codecs, vcd2->codecs());
3994}
3995
3996// Test that the codec preference order per media section is respected in
3997// the answer.
3998TEST_F(MediaSessionDescriptionFactoryTest,
3999 CreateAnswerRespectsCodecPreferenceOrder) {
4000 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004001 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
4002 RtpTransceiverDirection::kSendRecv, kActive,
4003 &opts);
4004 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
4005 RtpTransceiverDirection::kSendRecv, kActive,
4006 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004007 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08004008 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07004009 ASSERT_TRUE(offer);
4010 ASSERT_EQ(2u, offer->contents().size());
4011 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004012 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004013 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08004014 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004015 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
4016 EXPECT_EQ(video_codecs, vcd1->codecs());
4017 EXPECT_EQ(video_codecs, vcd2->codecs());
4018
4019 // Change the codec preference of the first video section and create an
4020 // answer.
4021 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
4022 vcd1->set_codecs(video_codecs_reverse);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004023 std::unique_ptr<SessionDescription> answer =
4024 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08004025 vcd1 = answer->contents()[0].media_description()->as_video();
4026 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07004027 // The video codec preference order should be respected.
4028 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
4029 EXPECT_EQ(video_codecs, vcd2->codecs());
4030}
4031
Zhi Huang6f367472017-11-22 13:20:02 -08004032// Test that when creating an answer, the codecs use local parameters instead of
4033// the remote ones.
4034TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
4035 const std::string audio_param_name = "audio_param";
4036 const std::string audio_value1 = "audio_v1";
4037 const std::string audio_value2 = "audio_v2";
4038 const std::string video_param_name = "video_param";
4039 const std::string video_value1 = "video_v1";
4040 const std::string video_value2 = "video_v2";
4041
4042 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
4043 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
4044 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
4045 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
4046
4047 // Set the parameters for codecs.
4048 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
4049 video_codecs1[0].SetParam(video_param_name, video_value1);
4050 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
4051 video_codecs2[0].SetParam(video_param_name, video_value2);
4052
4053 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
4054 f1_.set_video_codecs(video_codecs1);
4055 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
4056 f2_.set_video_codecs(video_codecs2);
4057
4058 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004059 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4060 RtpTransceiverDirection::kSendRecv, kActive,
4061 &opts);
4062 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4063 RtpTransceiverDirection::kSendRecv, kActive,
4064 &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08004065
Steve Anton6fe1fba2018-12-11 10:15:23 -08004066 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004067 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004068 auto offer_acd = offer->contents()[0].media_description()->as_audio();
4069 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004070 std::string value;
4071 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
4072 EXPECT_EQ(audio_value1, value);
4073 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
4074 EXPECT_EQ(video_value1, value);
4075
Steve Anton6fe1fba2018-12-11 10:15:23 -08004076 std::unique_ptr<SessionDescription> answer =
4077 f2_.CreateAnswer(offer.get(), opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004078 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004079 auto answer_acd = answer->contents()[0].media_description()->as_audio();
4080 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004081 // Use the parameters from the local codecs.
4082 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
4083 EXPECT_EQ(audio_value2, value);
4084 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
4085 EXPECT_EQ(video_value2, value);
4086}
4087
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004088// Test that matching packetization-mode is part of the criteria for matching
4089// H264 codecs (in addition to profile-level-id). Previously, this was not the
4090// case, so the first H264 codec with the same profile-level-id would match and
4091// the payload type in the answer would be incorrect.
4092// This is a regression test for bugs.webrtc.org/8808
4093TEST_F(MediaSessionDescriptionFactoryTest,
4094 H264MatchCriteriaIncludesPacketizationMode) {
4095 // Create two H264 codecs with the same profile level ID and different
4096 // packetization modes.
4097 VideoCodec h264_pm0(96, "H264");
4098 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4099 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
4100 VideoCodec h264_pm1(97, "H264");
4101 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4102 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
4103
4104 // Offerer will send both codecs, answerer should choose the one with matching
4105 // packetization mode (and not the first one it sees).
4106 f1_.set_video_codecs({h264_pm0, h264_pm1});
4107 f2_.set_video_codecs({h264_pm1});
4108
4109 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004110 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4111 RtpTransceiverDirection::kSendRecv, kActive,
4112 &opts);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004113
Steve Anton6fe1fba2018-12-11 10:15:23 -08004114 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004115 ASSERT_TRUE(offer);
4116
Steve Anton6fe1fba2018-12-11 10:15:23 -08004117 std::unique_ptr<SessionDescription> answer =
4118 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004119 ASSERT_TRUE(answer);
4120
4121 // Answer should have one negotiated codec with packetization-mode=1 using the
4122 // offered payload type.
4123 ASSERT_EQ(1u, answer->contents().size());
4124 auto answer_vcd = answer->contents()[0].media_description()->as_video();
4125 ASSERT_EQ(1u, answer_vcd->codecs().size());
4126 auto answer_codec = answer_vcd->codecs()[0];
4127 EXPECT_EQ(h264_pm1.id, answer_codec.id);
4128}
4129
zhihuangcf5b37c2016-05-05 11:44:35 -07004130class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
4131 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004132 MediaProtocolTest()
4133 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -07004134 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
4135 MAKE_VECTOR(kAudioCodecs1));
zhihuangcf5b37c2016-05-05 11:44:35 -07004136 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004137 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07004138 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
4139 MAKE_VECTOR(kAudioCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07004140 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004141 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07004142 f1_.set_secure(SEC_ENABLED);
4143 f2_.set_secure(SEC_ENABLED);
4144 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004145 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004146 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004147 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004148 tdf1_.set_secure(SEC_ENABLED);
4149 tdf2_.set_secure(SEC_ENABLED);
4150 }
4151
4152 protected:
4153 MediaSessionDescriptionFactory f1_;
4154 MediaSessionDescriptionFactory f2_;
4155 TransportDescriptionFactory tdf1_;
4156 TransportDescriptionFactory tdf2_;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004157 UniqueRandomIdGenerator ssrc_generator1;
4158 UniqueRandomIdGenerator ssrc_generator2;
zhihuangcf5b37c2016-05-05 11:44:35 -07004159};
4160
4161TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
4162 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08004163 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004164 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004165 ASSERT_TRUE(offer.get() != nullptr);
4166 // Set the protocol for all the contents.
4167 for (auto content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004168 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07004169 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004170 std::unique_ptr<SessionDescription> answer =
4171 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004172 const ContentInfo* ac = answer->GetContentByName("audio");
4173 const ContentInfo* vc = answer->GetContentByName("video");
4174 ASSERT_TRUE(ac != nullptr);
4175 ASSERT_TRUE(vc != nullptr);
4176 EXPECT_FALSE(ac->rejected); // the offer is accepted
4177 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004178 const AudioContentDescription* acd = ac->media_description()->as_audio();
4179 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07004180 EXPECT_EQ(GetParam(), acd->protocol());
4181 EXPECT_EQ(GetParam(), vcd->protocol());
4182}
4183
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004184INSTANTIATE_TEST_SUITE_P(MediaProtocolPatternTest,
4185 MediaProtocolTest,
4186 ::testing::ValuesIn(kMediaProtocols));
4187INSTANTIATE_TEST_SUITE_P(MediaProtocolDtlsPatternTest,
4188 MediaProtocolTest,
4189 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07004190
4191TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
4192 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004193 UniqueRandomIdGenerator ssrc_generator;
4194 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004195 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4196 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4197
4198 // The merged list of codecs should contain any send codecs that are also
4199 // nominally in the recieve codecs list. Payload types should be picked from
4200 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
4201 // (set to 1). This equals what happens when the send codecs are used in an
4202 // offer and the receive codecs are used in the following answer.
4203 const std::vector<AudioCodec> sendrecv_codecs =
4204 MAKE_VECTOR(kAudioCodecsAnswer);
4205 const std::vector<AudioCodec> no_codecs;
4206
4207 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
4208 << "Please don't change shared test data!";
4209 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
4210 << "Please don't change shared test data!";
4211 // Alter iLBC send codec to have zero channels, to test that that is handled
4212 // properly.
4213 send_codecs[1].channels = 0;
4214
4215 // Alther iLBC receive codec to be lowercase, to test that case conversions
4216 // are handled properly.
4217 recv_codecs[2].name = "ilbc";
4218
4219 // Test proper merge
4220 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004221 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4222 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4223 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004224
4225 // Test empty send codecs list
4226 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004227 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4228 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4229 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004230
4231 // Test empty recv codecs list
4232 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004233 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4234 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4235 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004236
4237 // Test all empty codec lists
4238 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004239 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4240 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4241 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004242}
4243
Amit Hilbuch77938e62018-12-21 09:23:38 -08004244// Checks that the RID extensions are added to the video RTP header extensions.
4245// Note: This test somewhat shows that |set_video_rtp_header_extensions()| is
4246// not very well defined, as calling set() and immediately get() will yield
4247// an object that is not semantically equivalent to the set object.
4248TEST_F(MediaSessionDescriptionFactoryTest, VideoHasRidExtensionsInUnifiedPlan) {
4249 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004250 UniqueRandomIdGenerator ssrc_generator;
4251 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
Amit Hilbuch77938e62018-12-21 09:23:38 -08004252 sf.set_is_unified_plan(true);
4253 cricket::RtpHeaderExtensions extensions;
4254 sf.set_video_rtp_header_extensions(extensions);
4255 cricket::RtpHeaderExtensions result = sf.video_rtp_header_extensions();
4256 // Check to see that RID extensions were added to the extension list
4257 EXPECT_GE(result.size(), 2u);
Steve Anton64b626b2019-01-28 17:25:26 -08004258 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
Elad Alon157540a2019-02-08 23:37:52 +01004259 RtpExtension::kMidUri)));
4260 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
Steve Anton64b626b2019-01-28 17:25:26 -08004261 RtpExtension::kRidUri)));
4262 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
4263 RtpExtension::kRepairedRidUri)));
Amit Hilbuch77938e62018-12-21 09:23:38 -08004264}
4265
4266// Checks that the RID extensions are added to the audio RTP header extensions.
4267// Note: This test somewhat shows that |set_audio_rtp_header_extensions()| is
4268// not very well defined, as calling set() and immediately get() will yield
4269// an object that is not semantically equivalent to the set object.
4270TEST_F(MediaSessionDescriptionFactoryTest, AudioHasRidExtensionsInUnifiedPlan) {
4271 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004272 UniqueRandomIdGenerator ssrc_generator;
4273 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
Amit Hilbuch77938e62018-12-21 09:23:38 -08004274 sf.set_is_unified_plan(true);
4275 cricket::RtpHeaderExtensions extensions;
4276 sf.set_audio_rtp_header_extensions(extensions);
4277 cricket::RtpHeaderExtensions result = sf.audio_rtp_header_extensions();
4278 // Check to see that RID extensions were added to the extension list
4279 EXPECT_GE(result.size(), 2u);
Steve Anton64b626b2019-01-28 17:25:26 -08004280 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
Elad Alon157540a2019-02-08 23:37:52 +01004281 RtpExtension::kMidUri)));
4282 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
Steve Anton64b626b2019-01-28 17:25:26 -08004283 RtpExtension::kRidUri)));
4284 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
4285 RtpExtension::kRepairedRidUri)));
Amit Hilbuch77938e62018-12-21 09:23:38 -08004286}
4287
ossu075af922016-06-14 03:29:38 -07004288namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07004289// Compare the two vectors of codecs ignoring the payload type.
4290template <class Codec>
4291bool CodecsMatch(const std::vector<Codec>& codecs1,
4292 const std::vector<Codec>& codecs2) {
4293 if (codecs1.size() != codecs2.size()) {
4294 return false;
4295 }
4296
4297 for (size_t i = 0; i < codecs1.size(); ++i) {
4298 if (!codecs1[i].Matches(codecs2[i])) {
4299 return false;
4300 }
4301 }
4302 return true;
4303}
4304
Steve Anton4e70a722017-11-28 14:57:10 -08004305void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07004306 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004307 UniqueRandomIdGenerator ssrc_generator;
4308 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004309 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4310 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4311 const std::vector<AudioCodec> sendrecv_codecs =
4312 MAKE_VECTOR(kAudioCodecsAnswer);
4313 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07004314
4315 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004316 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
4317 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004318
Steve Anton4e70a722017-11-28 14:57:10 -08004319 if (direction == RtpTransceiverDirection::kSendRecv ||
4320 direction == RtpTransceiverDirection::kSendOnly) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004321 AttachSenderToMediaDescriptionOptions(
4322 "audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004323 }
ossu075af922016-06-14 03:29:38 -07004324
Steve Anton6fe1fba2018-12-11 10:15:23 -08004325 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
ossu075af922016-06-14 03:29:38 -07004326 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004327 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07004328
4329 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07004330 // that the codecs put in are right. This happens when we neither want to
4331 // send nor receive audio. The checks are still in place if at some point
4332 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004333 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004334 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004335 // sendrecv and inactive should both present lists as if the channel was
4336 // to be used for sending and receiving. Inactive essentially means it
4337 // might eventually be used anything, but we don't know more at this
4338 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08004339 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004340 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08004341 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004342 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004343 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07004344 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004345 }
4346 }
4347}
4348
4349static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07004350 AudioCodec(0, "codec0", 16000, -1, 1),
4351 AudioCodec(1, "codec1", 8000, 13300, 1),
4352 AudioCodec(2, "codec2", 8000, 64000, 1),
4353 AudioCodec(3, "codec3", 8000, 64000, 1),
4354 AudioCodec(4, "codec4", 8000, 0, 2),
4355 AudioCodec(5, "codec5", 32000, 0, 1),
4356 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07004357
zhihuang1c378ed2017-08-17 14:10:50 -07004358/* The codecs groups below are chosen as per the matrix below. The objective
4359 * is to have different sets of codecs in the inputs, to get unique sets of
4360 * codecs after negotiation, depending on offer and answer communication
4361 * directions. One-way directions in the offer should either result in the
4362 * opposite direction in the answer, or an inactive answer. Regardless, the
4363 * choice of codecs should be as if the answer contained the opposite
4364 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07004365 *
4366 * | Offer | Answer | Result
4367 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
4368 * 0 | x - - | - x - | x - - - -
4369 * 1 | x x x | - x - | x - - x -
4370 * 2 | - x - | x - - | - x - - -
4371 * 3 | x x x | x - - | - x x - -
4372 * 4 | - x - | x x x | - x - - -
4373 * 5 | x - - | x x x | x - - - -
4374 * 6 | x x x | x x x | x x x x x
4375 */
4376// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004377static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
4378static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07004379// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
4380// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07004381static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
4382static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07004383// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004384static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
4385static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
4386static const int kResultSendrecv_SendCodecs[] = {3, 6};
4387static const int kResultSendrecv_RecvCodecs[] = {1, 6};
4388static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07004389
4390template <typename T, int IDXS>
4391std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
4392 std::vector<T> out;
4393 out.reserve(IDXS);
4394 for (int idx : indices)
4395 out.push_back(array[idx]);
4396
4397 return out;
4398}
4399
Steve Anton4e70a722017-11-28 14:57:10 -08004400void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
4401 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07004402 bool add_legacy_stream) {
4403 TransportDescriptionFactory offer_tdf;
4404 TransportDescriptionFactory answer_tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004405 UniqueRandomIdGenerator ssrc_generator1, ssrc_generator2;
4406 MediaSessionDescriptionFactory offer_factory(&offer_tdf, &ssrc_generator1);
4407 MediaSessionDescriptionFactory answer_factory(&answer_tdf, &ssrc_generator2);
ossu075af922016-06-14 03:29:38 -07004408 offer_factory.set_audio_codecs(
4409 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
4410 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
4411 answer_factory.set_audio_codecs(
4412 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
4413 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
4414
ossu075af922016-06-14 03:29:38 -07004415 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004416 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", offer_direction,
4417 kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004418
Steve Anton4e70a722017-11-28 14:57:10 -08004419 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004420 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4421 kAudioTrack1, {kMediaStream1}, 1,
4422 &offer_opts);
ossu075af922016-06-14 03:29:38 -07004423 }
4424
Steve Anton6fe1fba2018-12-11 10:15:23 -08004425 std::unique_ptr<SessionDescription> offer =
4426 offer_factory.CreateOffer(offer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004427 ASSERT_TRUE(offer.get() != NULL);
4428
4429 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004430 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", answer_direction,
4431 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004432
Steve Anton4e70a722017-11-28 14:57:10 -08004433 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004434 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4435 kAudioTrack1, {kMediaStream1}, 1,
4436 &answer_opts);
ossu075af922016-06-14 03:29:38 -07004437 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004438 std::unique_ptr<SessionDescription> answer =
4439 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004440 const ContentInfo* ac = answer->GetContentByName("audio");
4441
zhihuang1c378ed2017-08-17 14:10:50 -07004442 // If the factory didn't add any audio content to the answer, we cannot
4443 // check that the codecs put in are right. This happens when we neither want
4444 // to send nor receive audio. The checks are still in place if at some point
4445 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004446 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004447 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
4448 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07004449
ossu075af922016-06-14 03:29:38 -07004450 std::vector<AudioCodec> target_codecs;
4451 // For offers with sendrecv or inactive, we should never reply with more
4452 // codecs than offered, with these codec sets.
4453 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08004454 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07004455 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4456 kResultSendrecv_SendrecvCodecs);
4457 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004458 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004459 target_codecs =
4460 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004461 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004462 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004463 target_codecs =
4464 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07004465 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004466 case RtpTransceiverDirection::kSendRecv:
4467 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004468 target_codecs =
4469 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08004470 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004471 target_codecs =
4472 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004473 } else {
4474 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4475 kResultSendrecv_SendrecvCodecs);
4476 }
4477 break;
4478 }
4479
zhihuang1c378ed2017-08-17 14:10:50 -07004480 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02004481 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07004482 bool first = true;
4483 os << "{";
4484 for (const auto& c : codecs) {
4485 os << (first ? " " : ", ") << c.id;
4486 first = false;
4487 }
4488 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02004489 return os.Release();
ossu075af922016-06-14 03:29:38 -07004490 };
4491
4492 EXPECT_TRUE(acd->codecs() == target_codecs)
4493 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08004494 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
4495 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07004496 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08004497 << webrtc::RtpTransceiverDirectionToString(answer_direction)
4498 << "; got: "
4499 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07004500 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08004501 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07004502 << "Only inactive offers are allowed to not generate any audio "
4503 "content";
ossu075af922016-06-14 03:29:38 -07004504 }
4505}
brandtr03d5fb12016-11-22 03:37:59 -08004506
4507} // namespace
ossu075af922016-06-14 03:29:38 -07004508
4509class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08004510 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07004511
4512TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004513 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07004514}
4515
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004516INSTANTIATE_TEST_SUITE_P(MediaSessionDescriptionFactoryTest,
4517 AudioCodecsOfferTest,
4518 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4519 RtpTransceiverDirection::kRecvOnly,
4520 RtpTransceiverDirection::kSendRecv,
4521 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07004522
4523class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08004524 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
4525 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07004526 bool>> {};
ossu075af922016-06-14 03:29:38 -07004527
4528TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08004529 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
4530 ::testing::get<1>(GetParam()),
4531 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07004532}
4533
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004534INSTANTIATE_TEST_SUITE_P(
zhihuang1c378ed2017-08-17 14:10:50 -07004535 MediaSessionDescriptionFactoryTest,
4536 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004537 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
4538 RtpTransceiverDirection::kRecvOnly,
4539 RtpTransceiverDirection::kSendRecv,
4540 RtpTransceiverDirection::kInactive),
4541 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4542 RtpTransceiverDirection::kRecvOnly,
4543 RtpTransceiverDirection::kSendRecv,
4544 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07004545 ::testing::Bool()));