blob: cb90bbc6d10882bbdad2428dbd514e0a88d00bc9 [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"
20#include "p2p/base/p2p_constants.h"
21#include "p2p/base/transport_description.h"
22#include "p2p/base/transport_info.h"
23#include "pc/media_session.h"
24#include "pc/rtp_media_utils.h"
25#include "pc/srtp_filter.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020026#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080027#include "rtc_base/fake_ssl_identity.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020028#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 09:11:00 -080029#include "rtc_base/message_digest.h"
30#include "rtc_base/ssl_adapter.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020031#include "rtc_base/strings/string_builder.h"
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080032#include "rtc_base/unique_id_generator.h"
Steve Antone38a5a12018-11-21 16:05:15 -080033#include "test/gmock.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000034
Yves Gerey665174f2018-06-19 15:03:05 +020035#define ASSERT_CRYPTO(cd, s, cs) \
36 ASSERT_EQ(s, cd->cryptos().size()); \
Steve Antone38a5a12018-11-21 16:05:15 -080037 ASSERT_EQ(cs, cd->cryptos()[0].cipher_suite)
henrike@webrtc.org28e20752013-07-10 00:45:36 +000038
39typedef std::vector<cricket::Candidate> Candidates;
40
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080041using cricket::AudioCodec;
42using cricket::AudioContentDescription;
43using cricket::ContentInfo;
44using cricket::CryptoParamsVec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080045using cricket::GetFirstAudioContent;
46using cricket::GetFirstAudioContentDescription;
47using cricket::GetFirstDataContent;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020048using cricket::GetFirstRtpDataContentDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080049using cricket::GetFirstVideoContent;
50using cricket::GetFirstVideoContentDescription;
51using cricket::kAutoBandwidth;
52using cricket::MEDIA_TYPE_AUDIO;
53using cricket::MEDIA_TYPE_DATA;
54using cricket::MEDIA_TYPE_VIDEO;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000055using cricket::MediaContentDescription;
zhihuang1c378ed2017-08-17 14:10:50 -070056using cricket::MediaDescriptionOptions;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080057using cricket::MediaProtocolType;
58using cricket::MediaSessionDescriptionFactory;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000059using cricket::MediaSessionOptions;
60using cricket::MediaType;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080061using cricket::RidDescription;
62using cricket::RidDirection;
Harald Alvestrand5fc28b12019-05-13 13:36:16 +020063using cricket::RtpDataCodec;
64using cricket::RtpDataContentDescription;
65using cricket::SctpDataContentDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080066using cricket::SEC_DISABLED;
67using cricket::SEC_ENABLED;
68using cricket::SEC_REQUIRED;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000069using cricket::SessionDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080070using cricket::SimulcastDescription;
71using cricket::SimulcastLayer;
72using cricket::SimulcastLayerList;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000073using cricket::SsrcGroup;
74using cricket::StreamParams;
75using cricket::StreamParamsVec;
76using cricket::TransportDescription;
77using cricket::TransportDescriptionFactory;
78using cricket::TransportInfo;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000079using cricket::VideoCodec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080080using cricket::VideoContentDescription;
jbauchcb560652016-08-04 05:20:32 -070081using rtc::CS_AEAD_AES_128_GCM;
82using rtc::CS_AEAD_AES_256_GCM;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080083using rtc::CS_AES_CM_128_HMAC_SHA1_32;
84using rtc::CS_AES_CM_128_HMAC_SHA1_80;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080085using rtc::UniqueRandomIdGenerator;
Mirko Bonadei6a489f22019-04-09 15:11:12 +020086using ::testing::Contains;
87using ::testing::Each;
88using ::testing::ElementsAreArray;
89using ::testing::Eq;
90using ::testing::Field;
91using ::testing::IsEmpty;
92using ::testing::IsFalse;
93using ::testing::Ne;
94using ::testing::Not;
95using ::testing::Pointwise;
96using ::testing::SizeIs;
isheriff6f8d6862016-05-26 11:24:55 -070097using webrtc::RtpExtension;
Steve Anton4e70a722017-11-28 14:57:10 -080098using webrtc::RtpTransceiverDirection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000099
100static const AudioCodec kAudioCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700101 AudioCodec(103, "ISAC", 16000, -1, 1),
102 AudioCodec(102, "iLBC", 8000, 13300, 1),
103 AudioCodec(0, "PCMU", 8000, 64000, 1),
104 AudioCodec(8, "PCMA", 8000, 64000, 1),
105 AudioCodec(117, "red", 8000, 0, 1),
106 AudioCodec(107, "CN", 48000, 0, 1)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000107
108static const AudioCodec kAudioCodecs2[] = {
Henrik Lundinf8ed5612018-05-07 12:05:57 +0200109 AudioCodec(126, "foo", 16000, 22000, 1),
deadbeef67cf2c12016-04-13 10:07:16 -0700110 AudioCodec(0, "PCMU", 8000, 64000, 1),
111 AudioCodec(127, "iLBC", 8000, 13300, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000112};
113
114static const AudioCodec kAudioCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700115 AudioCodec(102, "iLBC", 8000, 13300, 1),
116 AudioCodec(0, "PCMU", 8000, 64000, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000117};
118
perkj26752742016-10-24 01:21:16 -0700119static const VideoCodec kVideoCodecs1[] = {VideoCodec(96, "H264-SVC"),
120 VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000121
zhihuang1c378ed2017-08-17 14:10:50 -0700122static const VideoCodec kVideoCodecs1Reverse[] = {VideoCodec(97, "H264"),
123 VideoCodec(96, "H264-SVC")};
124
perkj26752742016-10-24 01:21:16 -0700125static const VideoCodec kVideoCodecs2[] = {VideoCodec(126, "H264"),
126 VideoCodec(127, "H263")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000127
perkj26752742016-10-24 01:21:16 -0700128static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000129
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200130static const RtpDataCodec kDataCodecs1[] = {RtpDataCodec(98, "binary-data"),
131 RtpDataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000132
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200133static const RtpDataCodec kDataCodecs2[] = {RtpDataCodec(126, "binary-data"),
134 RtpDataCodec(127, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000135
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200136static const RtpDataCodec kDataCodecsAnswer[] = {
137 RtpDataCodec(98, "binary-data"), RtpDataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000138
isheriff6f8d6862016-05-26 11:24:55 -0700139static const RtpExtension kAudioRtpExtension1[] = {
140 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
141 RtpExtension("http://google.com/testing/audio_something", 10),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000142};
143
jbauch5869f502017-06-29 12:31:36 -0700144static const RtpExtension kAudioRtpExtensionEncrypted1[] = {
145 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
146 RtpExtension("http://google.com/testing/audio_something", 10),
147 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
148};
149
isheriff6f8d6862016-05-26 11:24:55 -0700150static const RtpExtension kAudioRtpExtension2[] = {
151 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
152 RtpExtension("http://google.com/testing/audio_something_else", 8),
153 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000154};
155
isheriff6f8d6862016-05-26 11:24:55 -0700156static const RtpExtension kAudioRtpExtension3[] = {
157 RtpExtension("http://google.com/testing/audio_something", 2),
158 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
deadbeefa5b273a2015-08-20 17:30:13 -0700159};
160
jbauch5869f502017-06-29 12:31:36 -0700161static const RtpExtension kAudioRtpExtension3ForEncryption[] = {
162 RtpExtension("http://google.com/testing/audio_something", 2),
163 // Use RTP extension that supports encryption.
164 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
165};
166
167static const RtpExtension kAudioRtpExtension3ForEncryptionOffer[] = {
168 RtpExtension("http://google.com/testing/audio_something", 2),
169 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
170 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14, true),
171};
172
isheriff6f8d6862016-05-26 11:24:55 -0700173static const RtpExtension kAudioRtpExtensionAnswer[] = {
174 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000175};
176
jbauch5869f502017-06-29 12:31:36 -0700177static const RtpExtension kAudioRtpExtensionEncryptedAnswer[] = {
178 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
179};
180
isheriff6f8d6862016-05-26 11:24:55 -0700181static const RtpExtension kVideoRtpExtension1[] = {
182 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
183 RtpExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000184};
185
jbauch5869f502017-06-29 12:31:36 -0700186static const RtpExtension kVideoRtpExtensionEncrypted1[] = {
187 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
188 RtpExtension("http://google.com/testing/video_something", 13),
189 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
190};
191
isheriff6f8d6862016-05-26 11:24:55 -0700192static const RtpExtension kVideoRtpExtension2[] = {
193 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
194 RtpExtension("http://google.com/testing/video_something_else", 14),
195 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000196};
197
isheriff6f8d6862016-05-26 11:24:55 -0700198static const RtpExtension kVideoRtpExtension3[] = {
199 RtpExtension("http://google.com/testing/video_something", 4),
200 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
deadbeefa5b273a2015-08-20 17:30:13 -0700201};
202
jbauch5869f502017-06-29 12:31:36 -0700203static const RtpExtension kVideoRtpExtension3ForEncryption[] = {
204 RtpExtension("http://google.com/testing/video_something", 4),
205 // Use RTP extension that supports encryption.
206 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 5),
207};
208
isheriff6f8d6862016-05-26 11:24:55 -0700209static const RtpExtension kVideoRtpExtensionAnswer[] = {
210 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000211};
212
jbauch5869f502017-06-29 12:31:36 -0700213static const RtpExtension kVideoRtpExtensionEncryptedAnswer[] = {
214 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
215};
216
Johannes Kronce8e8672019-02-22 13:06:44 +0100217static const RtpExtension kRtpExtensionTransportSequenceNumber01[] = {
218 RtpExtension("http://www.ietf.org/id/"
219 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
220 1),
221};
222
223static const RtpExtension kRtpExtensionTransportSequenceNumber01And02[] = {
224 RtpExtension("http://www.ietf.org/id/"
225 "draft-holmer-rmcat-transport-wide-cc-extensions-01",
226 1),
Johannes Kron8cc711a2019-03-07 22:36:35 +0100227 RtpExtension(
228 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
229 2),
Johannes Kronce8e8672019-02-22 13:06:44 +0100230};
231
232static const RtpExtension kRtpExtensionTransportSequenceNumber02[] = {
Johannes Kron8cc711a2019-03-07 22:36:35 +0100233 RtpExtension(
234 "http://www.webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02",
235 2),
Johannes Kronce8e8672019-02-22 13:06:44 +0100236};
237
Peter Boström0c4e06b2015-10-07 12:23:21 +0200238static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
239static const uint32_t kSimSsrc[] = {10, 20, 30};
240static const uint32_t kFec1Ssrc[] = {10, 11};
241static const uint32_t kFec2Ssrc[] = {20, 21};
242static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000243
244static const char kMediaStream1[] = "stream_1";
245static const char kMediaStream2[] = "stream_2";
246static const char kVideoTrack1[] = "video_1";
247static const char kVideoTrack2[] = "video_2";
248static const char kAudioTrack1[] = "audio_1";
249static const char kAudioTrack2[] = "audio_2";
250static const char kAudioTrack3[] = "audio_3";
251static const char kDataTrack1[] = "data_1";
252static const char kDataTrack2[] = "data_2";
253static const char kDataTrack3[] = "data_3";
254
zhihuangcf5b37c2016-05-05 11:44:35 -0700255static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
256 "RTP/SAVPF"};
257static const char* kMediaProtocolsDtls[] = {
258 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
259 "UDP/TLS/RTP/SAVP"};
260
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700261// SRTP cipher name negotiated by the tests. This must be updated if the
262// default changes.
263static const char* kDefaultSrtpCryptoSuite = CS_AES_CM_128_HMAC_SHA1_80;
264static const char* kDefaultSrtpCryptoSuiteGcm = CS_AEAD_AES_256_GCM;
265
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800266// These constants are used to make the code using "AddMediaDescriptionOptions"
267// more readable.
zhihuang1c378ed2017-08-17 14:10:50 -0700268static constexpr bool kStopped = true;
269static constexpr bool kActive = false;
270
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000271static bool IsMediaContentOfType(const ContentInfo* content,
272 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800273 RTC_DCHECK(content);
274 return content->media_description()->type() == media_type;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000275}
276
Steve Anton4e70a722017-11-28 14:57:10 -0800277static RtpTransceiverDirection GetMediaDirection(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800278 RTC_DCHECK(content);
279 return content->media_description()->direction();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000280}
281
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000282static void AddRtxCodec(const VideoCodec& rtx_codec,
283 std::vector<VideoCodec>* codecs) {
magjedb05fa242016-11-11 04:00:16 -0800284 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000285 codecs->push_back(rtx_codec);
286}
287
288template <class T>
289static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
290 std::vector<std::string> codec_names;
Mirko Bonadei649a4c22019-01-29 10:11:53 +0100291 codec_names.reserve(codecs.size());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000292 for (const auto& codec : codecs) {
293 codec_names.push_back(codec.name);
294 }
295 return codec_names;
296}
297
zhihuang1c378ed2017-08-17 14:10:50 -0700298// This is used for test only. MIDs are not the identification of the
299// MediaDescriptionOptions since some end points may not support MID and the SDP
300// may not contain 'mid'.
301std::vector<MediaDescriptionOptions>::iterator FindFirstMediaDescriptionByMid(
302 const std::string& mid,
303 MediaSessionOptions* opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800304 return absl::c_find_if(
305 opts->media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700306 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
307}
308
309std::vector<MediaDescriptionOptions>::const_iterator
310FindFirstMediaDescriptionByMid(const std::string& mid,
311 const MediaSessionOptions& opts) {
Steve Anton64b626b2019-01-28 17:25:26 -0800312 return absl::c_find_if(
313 opts.media_description_options,
Steve Anton36b29d12017-10-30 09:57:42 -0700314 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
zhihuang1c378ed2017-08-17 14:10:50 -0700315}
316
317// Add a media section to the |session_options|.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800318static void AddMediaDescriptionOptions(MediaType type,
319 const std::string& mid,
320 RtpTransceiverDirection direction,
321 bool stopped,
322 MediaSessionOptions* opts) {
Steve Anton4e70a722017-11-28 14:57:10 -0800323 opts->media_description_options.push_back(
324 MediaDescriptionOptions(type, mid, direction, stopped));
zhihuang1c378ed2017-08-17 14:10:50 -0700325}
326
Steve Anton4e70a722017-11-28 14:57:10 -0800327static void AddAudioVideoSections(RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700328 MediaSessionOptions* opts) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800329 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
330 opts);
331 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video", direction, kActive,
332 opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700333}
334
335static void AddDataSection(cricket::DataChannelType dct,
Steve Anton4e70a722017-11-28 14:57:10 -0800336 RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700337 MediaSessionOptions* opts) {
338 opts->data_channel_type = dct;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800339 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700340}
341
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800342static void AttachSenderToMediaDescriptionOptions(
Steve Anton8ffb9c32017-08-31 15:45:38 -0700343 const std::string& mid,
344 MediaType type,
345 const std::string& track_id,
346 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800347 const std::vector<RidDescription>& rids,
348 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700349 int num_sim_layer,
350 MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -0700351 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
352 switch (type) {
353 case MEDIA_TYPE_AUDIO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700354 it->AddAudioSender(track_id, stream_ids);
zhihuang1c378ed2017-08-17 14:10:50 -0700355 break;
356 case MEDIA_TYPE_VIDEO:
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800357 it->AddVideoSender(track_id, stream_ids, rids, simulcast_layers,
358 num_sim_layer);
zhihuang1c378ed2017-08-17 14:10:50 -0700359 break;
360 case MEDIA_TYPE_DATA:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700361 RTC_CHECK(stream_ids.size() == 1U);
362 it->AddRtpDataChannel(track_id, stream_ids[0]);
zhihuang1c378ed2017-08-17 14:10:50 -0700363 break;
364 default:
365 RTC_NOTREACHED();
366 }
367}
368
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800369static void AttachSenderToMediaDescriptionOptions(
370 const std::string& mid,
371 MediaType type,
372 const std::string& track_id,
373 const std::vector<std::string>& stream_ids,
374 int num_sim_layer,
375 MediaSessionOptions* session_options) {
376 AttachSenderToMediaDescriptionOptions(mid, type, track_id, stream_ids, {},
377 SimulcastLayerList(), num_sim_layer,
378 session_options);
379}
380
zhihuang1c378ed2017-08-17 14:10:50 -0700381static void DetachSenderFromMediaSection(const std::string& mid,
382 const std::string& track_id,
383 MediaSessionOptions* session_options) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700384 std::vector<cricket::SenderOptions>& sender_options_list =
385 FindFirstMediaDescriptionByMid(mid, session_options)->sender_options;
386 auto sender_it =
Steve Anton64b626b2019-01-28 17:25:26 -0800387 absl::c_find_if(sender_options_list,
388 [track_id](const cricket::SenderOptions& sender_options) {
389 return sender_options.track_id == track_id;
390 });
Steve Anton3a66edf2018-09-10 12:57:37 -0700391 RTC_DCHECK(sender_it != sender_options_list.end());
392 sender_options_list.erase(sender_it);
zhihuang1c378ed2017-08-17 14:10:50 -0700393}
394
395// Helper function used to create a default MediaSessionOptions for Plan B SDP.
396// (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
397static MediaSessionOptions CreatePlanBMediaSessionOptions() {
398 MediaSessionOptions session_options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800399 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
400 RtpTransceiverDirection::kRecvOnly, kActive,
401 &session_options);
zhihuang1c378ed2017-08-17 14:10:50 -0700402 return session_options;
403}
404
405// TODO(zhihuang): Most of these tests were written while MediaSessionOptions
406// was designed for Plan B SDP, where only one audio "m=" section and one video
407// "m=" section could be generated, and ordering couldn't be controlled. Many of
408// these tests may be obsolete as a result, and should be refactored or removed.
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200409class MediaSessionDescriptionFactoryTest : public ::testing::Test {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000410 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800411 MediaSessionDescriptionFactoryTest()
412 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -0700413 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
414 MAKE_VECTOR(kAudioCodecs1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000415 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200416 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700417 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
418 MAKE_VECTOR(kAudioCodecs2));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000419 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200420 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200421 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700422 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200423 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700424 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000425 }
426
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000427 // Create a video StreamParamsVec object with:
428 // - one video stream with 3 simulcast streams and FEC,
429 StreamParamsVec CreateComplexVideoStreamParamsVec() {
430 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
431 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
432 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
433 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
434
435 std::vector<SsrcGroup> ssrc_groups;
436 ssrc_groups.push_back(sim_group);
437 ssrc_groups.push_back(fec_group1);
438 ssrc_groups.push_back(fec_group2);
439 ssrc_groups.push_back(fec_group3);
440
441 StreamParams simulcast_params;
442 simulcast_params.id = kVideoTrack1;
443 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
444 simulcast_params.ssrc_groups = ssrc_groups;
445 simulcast_params.cname = "Video_SIM_FEC";
Seth Hampson845e8782018-03-02 11:34:10 -0800446 simulcast_params.set_stream_ids({kMediaStream1});
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000447
448 StreamParamsVec video_streams;
449 video_streams.push_back(simulcast_params);
450
451 return video_streams;
452 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000453
454 bool CompareCryptoParams(const CryptoParamsVec& c1,
455 const CryptoParamsVec& c2) {
456 if (c1.size() != c2.size())
457 return false;
458 for (size_t i = 0; i < c1.size(); ++i)
459 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
460 c1[i].key_params != c2[i].key_params ||
461 c1[i].session_params != c2[i].session_params)
462 return false;
463 return true;
464 }
465
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700466 // Returns true if the transport info contains "renomination" as an
467 // ICE option.
468 bool GetIceRenomination(const TransportInfo* transport_info) {
Steve Anton64b626b2019-01-28 17:25:26 -0800469 return absl::c_linear_search(transport_info->description.transport_options,
470 "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700471 }
472
zhihuang1c378ed2017-08-17 14:10:50 -0700473 void TestTransportInfo(bool offer,
Steve Anton36b29d12017-10-30 09:57:42 -0700474 const MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000475 bool has_current_desc) {
476 const std::string current_audio_ufrag = "current_audio_ufrag";
477 const std::string current_audio_pwd = "current_audio_pwd";
478 const std::string current_video_ufrag = "current_video_ufrag";
479 const std::string current_video_pwd = "current_video_pwd";
480 const std::string current_data_ufrag = "current_data_ufrag";
481 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800482 std::unique_ptr<SessionDescription> current_desc;
483 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000484 if (has_current_desc) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800485 current_desc = absl::make_unique<SessionDescription>();
Steve Anton06817cd2018-12-18 15:55:30 -0800486 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200487 "audio",
Steve Anton06817cd2018-12-18 15:55:30 -0800488 TransportDescription(current_audio_ufrag, current_audio_pwd)));
489 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200490 "video",
Steve Anton06817cd2018-12-18 15:55:30 -0800491 TransportDescription(current_video_ufrag, current_video_pwd)));
492 current_desc->AddTransportInfo(TransportInfo(
493 "data", TransportDescription(current_data_ufrag, current_data_pwd)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000494 }
495 if (offer) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800496 desc = f1_.CreateOffer(options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000497 } else {
kwiberg31022942016-03-11 14:18:21 -0800498 std::unique_ptr<SessionDescription> offer;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800499 offer = f1_.CreateOffer(options, NULL);
500 desc = f1_.CreateAnswer(offer.get(), options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000501 }
502 ASSERT_TRUE(desc.get() != NULL);
503 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000504 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000505 EXPECT_TRUE(ti_audio != NULL);
506 if (has_current_desc) {
507 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
508 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
509 } else {
510 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
511 ti_audio->description.ice_ufrag.size());
512 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
513 ti_audio->description.ice_pwd.size());
514 }
zhihuang1c378ed2017-08-17 14:10:50 -0700515 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700516 FindFirstMediaDescriptionByMid("audio", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700517 EXPECT_EQ(
518 media_desc_options_it->transport_options.enable_ice_renomination,
519 GetIceRenomination(ti_audio));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000520
521 } else {
522 EXPECT_TRUE(ti_audio == NULL);
523 }
524 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000525 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000526 EXPECT_TRUE(ti_video != NULL);
527 if (options.bundle_enabled) {
528 EXPECT_EQ(ti_audio->description.ice_ufrag,
529 ti_video->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200530 EXPECT_EQ(ti_audio->description.ice_pwd, ti_video->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000531 } else {
532 if (has_current_desc) {
533 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
534 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
535 } else {
536 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
537 ti_video->description.ice_ufrag.size());
538 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
539 ti_video->description.ice_pwd.size());
540 }
541 }
zhihuang1c378ed2017-08-17 14:10:50 -0700542 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700543 FindFirstMediaDescriptionByMid("video", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700544 EXPECT_EQ(
545 media_desc_options_it->transport_options.enable_ice_renomination,
546 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000547 } else {
548 EXPECT_TRUE(ti_video == NULL);
549 }
550 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
551 if (options.has_data()) {
552 EXPECT_TRUE(ti_data != NULL);
553 if (options.bundle_enabled) {
554 EXPECT_EQ(ti_audio->description.ice_ufrag,
555 ti_data->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200556 EXPECT_EQ(ti_audio->description.ice_pwd, ti_data->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000557 } else {
558 if (has_current_desc) {
559 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
560 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
561 } else {
562 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
563 ti_data->description.ice_ufrag.size());
564 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
565 ti_data->description.ice_pwd.size());
566 }
567 }
zhihuang1c378ed2017-08-17 14:10:50 -0700568 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700569 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700570 EXPECT_EQ(
571 media_desc_options_it->transport_options.enable_ice_renomination,
572 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700573
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000574 } else {
575 EXPECT_TRUE(ti_video == NULL);
576 }
577 }
578
579 void TestCryptoWithBundle(bool offer) {
580 f1_.set_secure(SEC_ENABLED);
581 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -0800582 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
583 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
584 &options);
kwiberg31022942016-03-11 14:18:21 -0800585 std::unique_ptr<SessionDescription> ref_desc;
586 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000587 if (offer) {
588 options.bundle_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800589 ref_desc = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000590 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800591 desc = f1_.CreateOffer(options, ref_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000592 } else {
593 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800594 ref_desc = f1_.CreateOffer(options, NULL);
595 desc = f1_.CreateAnswer(ref_desc.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000596 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800597 ASSERT_TRUE(desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000598 const cricket::MediaContentDescription* audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800599 desc->GetContentDescriptionByName("audio");
600 ASSERT_TRUE(audio_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000601 const cricket::MediaContentDescription* video_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800602 desc->GetContentDescriptionByName("video");
603 ASSERT_TRUE(video_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000604 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
605 video_media_desc->cryptos()));
606 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
Steve Antone38a5a12018-11-21 16:05:15 -0800607 EXPECT_EQ(kDefaultSrtpCryptoSuite,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000608 audio_media_desc->cryptos()[0].cipher_suite);
609
610 // Verify the selected crypto is one from the reference audio
611 // media content.
612 const cricket::MediaContentDescription* ref_audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800613 ref_desc->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000614 bool found = false;
615 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
616 if (ref_audio_media_desc->cryptos()[i].Matches(
Yves Gerey665174f2018-06-19 15:03:05 +0200617 audio_media_desc->cryptos()[0])) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000618 found = true;
619 break;
620 }
621 }
622 EXPECT_TRUE(found);
623 }
624
625 // This test that the audio and video media direction is set to
626 // |expected_direction_in_answer| in an answer if the offer direction is set
zhihuang1c378ed2017-08-17 14:10:50 -0700627 // to |direction_in_offer| and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000628 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800629 RtpTransceiverDirection direction_in_offer,
630 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700631 MediaSessionOptions offer_opts;
632 AddAudioVideoSections(direction_in_offer, &offer_opts);
633
Steve Anton6fe1fba2018-12-11 10:15:23 -0800634 std::unique_ptr<SessionDescription> offer =
635 f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000636 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700637 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000638 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700639 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000640 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000641
zhihuang1c378ed2017-08-17 14:10:50 -0700642 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800643 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800644 std::unique_ptr<SessionDescription> answer =
645 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000646 const AudioContentDescription* acd_answer =
647 GetFirstAudioContentDescription(answer.get());
648 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
649 const VideoContentDescription* vcd_answer =
650 GetFirstVideoContentDescription(answer.get());
651 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
652 }
653
654 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800655 RTC_DCHECK(content);
656 RTC_CHECK(content->media_description());
657 const cricket::AudioContentDescription* audio_desc =
658 content->media_description()->as_audio();
659 RTC_CHECK(audio_desc);
660 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
661 if (codec.name == "CN") {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000662 return false;
Steve Antonb1c1de12017-12-21 15:14:30 -0800663 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000664 }
665 return true;
666 }
667
jbauchcb560652016-08-04 05:20:32 -0700668 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
669 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800670 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700671 offer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_offer;
zhihuang1c378ed2017-08-17 14:10:50 -0700672
jbauchcb560652016-08-04 05:20:32 -0700673 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800674 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700675 answer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_answer;
zhihuang1c378ed2017-08-17 14:10:50 -0700676
jbauchcb560652016-08-04 05:20:32 -0700677 f1_.set_secure(SEC_ENABLED);
678 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800679 std::unique_ptr<SessionDescription> offer =
680 f1_.CreateOffer(offer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700681 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800682 std::unique_ptr<SessionDescription> answer =
683 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700684 const ContentInfo* ac = answer->GetContentByName("audio");
685 const ContentInfo* vc = answer->GetContentByName("video");
686 ASSERT_TRUE(ac != NULL);
687 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800688 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
689 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800690 const AudioContentDescription* acd = ac->media_description()->as_audio();
691 const VideoContentDescription* vcd = vc->media_description()->as_video();
jbauchcb560652016-08-04 05:20:32 -0700692 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800693 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -0700694 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700695 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700696 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
697 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700698 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700699 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700700 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700701 }
702 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800703 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +0200704 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
705 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
jbauchcb560652016-08-04 05:20:32 -0700706 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700707 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700708 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700709 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700710 }
Steve Antone38a5a12018-11-21 16:05:15 -0800711 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
jbauchcb560652016-08-04 05:20:32 -0700712 }
713
Johannes Kronce8e8672019-02-22 13:06:44 +0100714 void TestTransportSequenceNumberNegotiation(
715 const cricket::RtpHeaderExtensions& local,
716 const cricket::RtpHeaderExtensions& offered,
717 const cricket::RtpHeaderExtensions& expectedAnswer) {
718 MediaSessionOptions opts;
719 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
720 f1_.set_audio_rtp_header_extensions(offered);
721 f1_.set_video_rtp_header_extensions(offered);
722 f2_.set_audio_rtp_header_extensions(local);
723 f2_.set_video_rtp_header_extensions(local);
724
725 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
726 ASSERT_TRUE(offer.get() != NULL);
727 std::unique_ptr<SessionDescription> answer =
728 f2_.CreateAnswer(offer.get(), opts, NULL);
729
730 EXPECT_EQ(
731 expectedAnswer,
732 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
733 EXPECT_EQ(
734 expectedAnswer,
735 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
736 }
737
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000738 protected:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800739 UniqueRandomIdGenerator ssrc_generator1;
740 UniqueRandomIdGenerator ssrc_generator2;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000741 MediaSessionDescriptionFactory f1_;
742 MediaSessionDescriptionFactory f2_;
743 TransportDescriptionFactory tdf1_;
744 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000745};
746
747// Create a typical audio offer, and ensure it matches what we expect.
748TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
749 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800750 std::unique_ptr<SessionDescription> offer =
751 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000752 ASSERT_TRUE(offer.get() != NULL);
753 const ContentInfo* ac = offer->GetContentByName("audio");
754 const ContentInfo* vc = offer->GetContentByName("video");
755 ASSERT_TRUE(ac != NULL);
756 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800757 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800758 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000759 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700760 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700761 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000762 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
763 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700764 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800765 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000766}
767
768// Create a typical video offer, and ensure it matches what we expect.
769TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
770 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800771 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000772 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800773 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000774 ASSERT_TRUE(offer.get() != NULL);
775 const ContentInfo* ac = offer->GetContentByName("audio");
776 const ContentInfo* vc = offer->GetContentByName("video");
777 ASSERT_TRUE(ac != NULL);
778 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800779 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
780 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800781 const AudioContentDescription* acd = ac->media_description()->as_audio();
782 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000783 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700784 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700785 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000786 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
787 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700788 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800789 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000790 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
791 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700792 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000793 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
794 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700795 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800796 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000797}
798
799// Test creating an offer with bundle where the Codecs have the same dynamic
800// RTP playlod type. The test verifies that the offer don't contain the
801// duplicate RTP payload types.
802TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
803 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700804 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200805 const RtpDataCodec& offered_data_codec = f2_.rtp_data_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000806 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
807 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
808
809 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800810 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
811 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000812 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800813 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000814 const VideoContentDescription* vcd =
815 GetFirstVideoContentDescription(offer.get());
816 const AudioContentDescription* acd =
817 GetFirstAudioContentDescription(offer.get());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200818 const RtpDataContentDescription* dcd =
819 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000820 ASSERT_TRUE(NULL != vcd);
821 ASSERT_TRUE(NULL != acd);
822 ASSERT_TRUE(NULL != dcd);
823 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
824 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
825 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
826 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
827 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
828 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
829}
830
zhihuang1c378ed2017-08-17 14:10:50 -0700831// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000832// after an audio only session has been negotiated.
833TEST_F(MediaSessionDescriptionFactoryTest,
834 TestCreateUpdatedVideoOfferWithBundle) {
835 f1_.set_secure(SEC_ENABLED);
836 f2_.set_secure(SEC_ENABLED);
837 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800838 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
839 RtpTransceiverDirection::kRecvOnly, kActive,
840 &opts);
841 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
842 RtpTransceiverDirection::kInactive, kStopped,
843 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000844 opts.data_channel_type = cricket::DCT_NONE;
845 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800846 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
847 std::unique_ptr<SessionDescription> answer =
848 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000849
850 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800851 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
852 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
853 &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000854 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800855 std::unique_ptr<SessionDescription> updated_offer(
856 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000857
858 const AudioContentDescription* acd =
859 GetFirstAudioContentDescription(updated_offer.get());
860 const VideoContentDescription* vcd =
861 GetFirstVideoContentDescription(updated_offer.get());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200862 const RtpDataContentDescription* dcd =
863 GetFirstRtpDataContentDescription(updated_offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000864 EXPECT_TRUE(NULL != vcd);
865 EXPECT_TRUE(NULL != acd);
866 EXPECT_TRUE(NULL != dcd);
867
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700868 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800869 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700870 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800871 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700872 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800873 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000874}
deadbeef44f08192015-12-15 16:20:09 -0800875
wu@webrtc.org78187522013-10-07 23:32:02 +0000876// Create a RTP data offer, and ensure it matches what we expect.
877TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000878 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800879 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
880 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000881 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800882 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000883 ASSERT_TRUE(offer.get() != NULL);
884 const ContentInfo* ac = offer->GetContentByName("audio");
885 const ContentInfo* dc = offer->GetContentByName("data");
886 ASSERT_TRUE(ac != NULL);
887 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800888 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
889 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800890 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200891 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000892 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700893 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700894 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000895 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
896 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700897 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800898 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000899 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +0200900 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700901 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000902 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +0200903 dcd->bandwidth()); // default bandwidth (auto)
904 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700905 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800906 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000907}
908
wu@webrtc.org78187522013-10-07 23:32:02 +0000909// Create an SCTP data offer with bundle without error.
910TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
911 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000912 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800913 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
wu@webrtc.org78187522013-10-07 23:32:02 +0000914 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800915 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.org78187522013-10-07 23:32:02 +0000916 EXPECT_TRUE(offer.get() != NULL);
917 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
Harald Alvestrandc3f48202019-05-14 17:27:11 +0200918 auto dcd = GetFirstSctpDataContentDescription(offer.get());
919 ASSERT_TRUE(dcd);
920 // Since this transport is insecure, the protocol should be "SCTP".
921 EXPECT_EQ(cricket::kMediaProtocolSctp, dcd->protocol());
922}
923
924// Create an SCTP data offer with bundle without error.
925TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSecureSctpDataOffer) {
926 MediaSessionOptions opts;
927 opts.bundle_enabled = true;
928 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
929 f1_.set_secure(SEC_ENABLED);
930 tdf1_.set_secure(SEC_ENABLED);
931 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
932 EXPECT_TRUE(offer.get() != NULL);
933 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
934 auto dcd = GetFirstSctpDataContentDescription(offer.get());
935 ASSERT_TRUE(dcd);
936 // The protocol should now be "UDP/DTLS/SCTP"
937 EXPECT_EQ(cricket::kMediaProtocolUdpDtlsSctp, dcd->protocol());
wu@webrtc.org78187522013-10-07 23:32:02 +0000938}
939
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000940// Test creating an sctp data channel from an already generated offer.
941TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
942 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000943 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800944 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000945 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800946 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000947 ASSERT_TRUE(offer1.get() != NULL);
948 const ContentInfo* data = offer1->GetContentByName("data");
949 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800950 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000951
952 // Now set data_channel_type to 'none' (default) and make sure that the
953 // datachannel type that gets generated from the previous offer, is of the
954 // same type.
955 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800956 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000957 f1_.CreateOffer(opts, offer1.get()));
958 data = offer2->GetContentByName("data");
959 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800960 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000961}
962
Steve Anton2bed3972019-01-04 17:04:30 -0800963// Test that if BUNDLE is enabled and all media sections are rejected then the
964// BUNDLE group is not present in the re-offer.
965TEST_F(MediaSessionDescriptionFactoryTest, ReOfferNoBundleGroupIfAllRejected) {
966 MediaSessionOptions opts;
967 opts.bundle_enabled = true;
968 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
969 RtpTransceiverDirection::kSendRecv, kActive,
970 &opts);
971 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
972
973 opts.media_description_options[0].stopped = true;
974 std::unique_ptr<SessionDescription> reoffer =
975 f1_.CreateOffer(opts, offer.get());
976
977 EXPECT_FALSE(reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
978}
979
980// Test that if BUNDLE is enabled and the remote re-offer does not include a
981// BUNDLE group since all media sections are rejected, then the re-answer also
982// does not include a BUNDLE group.
983TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerNoBundleGroupIfAllRejected) {
984 MediaSessionOptions opts;
985 opts.bundle_enabled = true;
986 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
987 RtpTransceiverDirection::kSendRecv, kActive,
988 &opts);
989 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
990 std::unique_ptr<SessionDescription> answer =
991 f2_.CreateAnswer(offer.get(), opts, nullptr);
992
993 opts.media_description_options[0].stopped = true;
994 std::unique_ptr<SessionDescription> reoffer =
995 f1_.CreateOffer(opts, offer.get());
996 std::unique_ptr<SessionDescription> reanswer =
997 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
998
999 EXPECT_FALSE(reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
1000}
1001
1002// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1003// was rejected then the new offerer-tagged media section is the non-rejected
1004// media section.
1005TEST_F(MediaSessionDescriptionFactoryTest, ReOfferChangeBundleOffererTagged) {
1006 MediaSessionOptions opts;
1007 opts.bundle_enabled = true;
1008 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1009 RtpTransceiverDirection::kSendRecv, kActive,
1010 &opts);
1011 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1012
1013 // Reject the audio m= section and add a video m= section.
1014 opts.media_description_options[0].stopped = true;
1015 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1016 RtpTransceiverDirection::kSendRecv, kActive,
1017 &opts);
1018 std::unique_ptr<SessionDescription> reoffer =
1019 f1_.CreateOffer(opts, offer.get());
1020
1021 const cricket::ContentGroup* bundle_group =
1022 reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1023 ASSERT_TRUE(bundle_group);
1024 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1025 EXPECT_TRUE(bundle_group->HasContentName("video"));
1026}
1027
1028// Test that if BUNDLE is enabled and the previous offerer-tagged media section
1029// was rejected and a new media section is added, then the re-answer BUNDLE
1030// group will contain only the non-rejected media section.
1031TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerChangedBundleOffererTagged) {
1032 MediaSessionOptions opts;
1033 opts.bundle_enabled = true;
1034 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1035 RtpTransceiverDirection::kSendRecv, kActive,
1036 &opts);
1037 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1038 std::unique_ptr<SessionDescription> answer =
1039 f2_.CreateAnswer(offer.get(), opts, nullptr);
1040
1041 // Reject the audio m= section and add a video m= section.
1042 opts.media_description_options[0].stopped = true;
1043 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1044 RtpTransceiverDirection::kSendRecv, kActive,
1045 &opts);
1046 std::unique_ptr<SessionDescription> reoffer =
1047 f1_.CreateOffer(opts, offer.get());
1048 std::unique_ptr<SessionDescription> reanswer =
1049 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1050
1051 const cricket::ContentGroup* bundle_group =
1052 reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1053 ASSERT_TRUE(bundle_group);
1054 EXPECT_FALSE(bundle_group->HasContentName("audio"));
1055 EXPECT_TRUE(bundle_group->HasContentName("video"));
1056}
1057
1058// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1059// and there is still a non-rejected media section that was in the initial
1060// offer, then the ICE credentials do not change in the reoffer offerer-tagged
1061// media section.
1062TEST_F(MediaSessionDescriptionFactoryTest,
1063 ReOfferChangeBundleOffererTaggedKeepsIceCredentials) {
1064 MediaSessionOptions opts;
1065 opts.bundle_enabled = true;
1066 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1067 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1068 std::unique_ptr<SessionDescription> answer =
1069 f2_.CreateAnswer(offer.get(), opts, nullptr);
1070
1071 // Reject the audio m= section.
1072 opts.media_description_options[0].stopped = true;
1073 std::unique_ptr<SessionDescription> reoffer =
1074 f1_.CreateOffer(opts, offer.get());
1075
1076 const TransportDescription* offer_tagged =
1077 offer->GetTransportDescriptionByName("audio");
1078 ASSERT_TRUE(offer_tagged);
1079 const TransportDescription* reoffer_tagged =
1080 reoffer->GetTransportDescriptionByName("video");
1081 ASSERT_TRUE(reoffer_tagged);
1082 EXPECT_EQ(offer_tagged->ice_ufrag, reoffer_tagged->ice_ufrag);
1083 EXPECT_EQ(offer_tagged->ice_pwd, reoffer_tagged->ice_pwd);
1084}
1085
1086// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1087// and there is still a non-rejected media section that was in the initial
1088// offer, then the ICE credentials do not change in the reanswer answerer-tagged
1089// media section.
1090TEST_F(MediaSessionDescriptionFactoryTest,
1091 ReAnswerChangeBundleOffererTaggedKeepsIceCredentials) {
1092 MediaSessionOptions opts;
1093 opts.bundle_enabled = true;
1094 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1095 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1096 std::unique_ptr<SessionDescription> answer =
1097 f2_.CreateAnswer(offer.get(), opts, nullptr);
1098
1099 // Reject the audio m= section.
1100 opts.media_description_options[0].stopped = true;
1101 std::unique_ptr<SessionDescription> reoffer =
1102 f1_.CreateOffer(opts, offer.get());
1103 std::unique_ptr<SessionDescription> reanswer =
1104 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1105
1106 const TransportDescription* answer_tagged =
1107 answer->GetTransportDescriptionByName("audio");
1108 ASSERT_TRUE(answer_tagged);
1109 const TransportDescription* reanswer_tagged =
1110 reanswer->GetTransportDescriptionByName("video");
1111 ASSERT_TRUE(reanswer_tagged);
1112 EXPECT_EQ(answer_tagged->ice_ufrag, reanswer_tagged->ice_ufrag);
1113 EXPECT_EQ(answer_tagged->ice_pwd, reanswer_tagged->ice_pwd);
1114}
1115
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001116// Create an audio, video offer without legacy StreamParams.
1117TEST_F(MediaSessionDescriptionFactoryTest,
1118 TestCreateOfferWithoutLegacyStreams) {
1119 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001120 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001121 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001122 ASSERT_TRUE(offer.get() != NULL);
1123 const ContentInfo* ac = offer->GetContentByName("audio");
1124 const ContentInfo* vc = offer->GetContentByName("video");
1125 ASSERT_TRUE(ac != NULL);
1126 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001127 const AudioContentDescription* acd = ac->media_description()->as_audio();
1128 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001129
Yves Gerey665174f2018-06-19 15:03:05 +02001130 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1131 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001132}
1133
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001134// Creates an audio+video sendonly offer.
1135TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001136 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001137 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001138 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1139 {kMediaStream1}, 1, &opts);
1140 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1141 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001142
Steve Anton6fe1fba2018-12-11 10:15:23 -08001143 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001144 ASSERT_TRUE(offer.get() != NULL);
1145 EXPECT_EQ(2u, offer->contents().size());
1146 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
1147 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
1148
Steve Anton4e70a722017-11-28 14:57:10 -08001149 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1150 GetMediaDirection(&offer->contents()[0]));
1151 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1152 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001153}
1154
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001155// Verifies that the order of the media contents in the current
1156// SessionDescription is preserved in the new SessionDescription.
1157TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
1158 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001159 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001160
kwiberg31022942016-03-11 14:18:21 -08001161 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001162 ASSERT_TRUE(offer1.get() != NULL);
1163 EXPECT_EQ(1u, offer1->contents().size());
1164 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
1165
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001166 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1167 RtpTransceiverDirection::kRecvOnly, kActive,
1168 &opts);
kwiberg31022942016-03-11 14:18:21 -08001169 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001170 f1_.CreateOffer(opts, offer1.get()));
1171 ASSERT_TRUE(offer2.get() != NULL);
1172 EXPECT_EQ(2u, offer2->contents().size());
1173 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
1174 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
1175
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001176 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1177 RtpTransceiverDirection::kRecvOnly, kActive,
1178 &opts);
kwiberg31022942016-03-11 14:18:21 -08001179 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001180 f1_.CreateOffer(opts, offer2.get()));
1181 ASSERT_TRUE(offer3.get() != NULL);
1182 EXPECT_EQ(3u, offer3->contents().size());
1183 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
1184 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
1185 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001186}
1187
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001188// Create a typical audio answer, and ensure it matches what we expect.
1189TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
1190 f1_.set_secure(SEC_ENABLED);
1191 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001192 std::unique_ptr<SessionDescription> offer =
1193 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001194 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001195 std::unique_ptr<SessionDescription> answer =
1196 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001197 const ContentInfo* ac = answer->GetContentByName("audio");
1198 const ContentInfo* vc = answer->GetContentByName("video");
1199 ASSERT_TRUE(ac != NULL);
1200 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001201 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001202 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001203 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001204 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001205 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001206 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1207 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001208 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001209 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001210}
1211
jbauchcb560652016-08-04 05:20:32 -07001212// Create a typical audio answer with GCM ciphers enabled, and ensure it
1213// matches what we expect.
1214TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
1215 f1_.set_secure(SEC_ENABLED);
1216 f2_.set_secure(SEC_ENABLED);
zhihuang1c378ed2017-08-17 14:10:50 -07001217 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001218 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001219 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001220 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001221 std::unique_ptr<SessionDescription> answer =
1222 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001223 const ContentInfo* ac = answer->GetContentByName("audio");
1224 const ContentInfo* vc = answer->GetContentByName("video");
1225 ASSERT_TRUE(ac != NULL);
1226 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001227 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001228 const AudioContentDescription* acd = ac->media_description()->as_audio();
jbauchcb560652016-08-04 05:20:32 -07001229 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001230 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001231 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001232 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1233 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001234 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001235 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
jbauchcb560652016-08-04 05:20:32 -07001236}
1237
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001238// Create a typical video answer, and ensure it matches what we expect.
1239TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
1240 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001241 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001242 f1_.set_secure(SEC_ENABLED);
1243 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001244 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001245 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001246 std::unique_ptr<SessionDescription> answer =
1247 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001248 const ContentInfo* ac = answer->GetContentByName("audio");
1249 const ContentInfo* vc = answer->GetContentByName("video");
1250 ASSERT_TRUE(ac != NULL);
1251 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001252 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1253 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001254 const AudioContentDescription* acd = ac->media_description()->as_audio();
1255 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001256 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001257 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001258 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001259 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001260 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001261 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001262 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001263 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +02001264 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
1265 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001266 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001267 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001268}
1269
jbauchcb560652016-08-04 05:20:32 -07001270// Create a typical video answer with GCM ciphers enabled, and ensure it
1271// matches what we expect.
1272TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1273 TestVideoGcmCipher(true, true);
1274}
1275
1276// Create a typical video answer with GCM ciphers enabled for the offer only,
1277// and ensure it matches what we expect.
1278TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1279 TestVideoGcmCipher(true, false);
1280}
1281
1282// Create a typical video answer with GCM ciphers enabled for the answer only,
1283// and ensure it matches what we expect.
1284TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1285 TestVideoGcmCipher(false, true);
1286}
1287
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001288TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001289 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001290 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001291 f1_.set_secure(SEC_ENABLED);
1292 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001293 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001294 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001295 std::unique_ptr<SessionDescription> answer =
1296 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001297 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001298 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001299 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001300 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001301 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1302 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001303 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001304 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001305 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001306 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001307 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001308 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001309 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001310 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
zstein4b2e0822017-02-17 19:48:38 -08001311 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001312 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001313 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001314 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001315 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001316 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001317}
1318
jbauchcb560652016-08-04 05:20:32 -07001319TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
zhihuang1c378ed2017-08-17 14:10:50 -07001320 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001321 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001322 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
jbauchcb560652016-08-04 05:20:32 -07001323 f1_.set_secure(SEC_ENABLED);
1324 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001325 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001326 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001327 std::unique_ptr<SessionDescription> answer =
1328 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001329 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001330 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -07001331 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001332 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001333 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1334 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001335 const AudioContentDescription* acd = ac->media_description()->as_audio();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001336 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
jbauchcb560652016-08-04 05:20:32 -07001337 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001338 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -07001339 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001340 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001341 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001342 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
zstein4b2e0822017-02-17 19:48:38 -08001343 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001344 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001345 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001346 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001347 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001348 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
zstein4b2e0822017-02-17 19:48:38 -08001349}
1350
1351// The use_sctpmap flag should be set in a DataContentDescription by default.
1352// The answer's use_sctpmap flag should match the offer's.
1353TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1354 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001355 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001356 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001357 ASSERT_TRUE(offer.get() != NULL);
1358 ContentInfo* dc_offer = offer->GetContentByName("data");
1359 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001360 SctpDataContentDescription* dcd_offer =
1361 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001362 EXPECT_TRUE(dcd_offer->use_sctpmap());
1363
Steve Anton6fe1fba2018-12-11 10:15:23 -08001364 std::unique_ptr<SessionDescription> answer =
1365 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001366 const ContentInfo* dc_answer = answer->GetContentByName("data");
1367 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001368 const SctpDataContentDescription* dcd_answer =
1369 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001370 EXPECT_TRUE(dcd_answer->use_sctpmap());
1371}
1372
1373// The answer's use_sctpmap flag should match the offer's.
1374TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1375 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001376 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001377 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001378 ASSERT_TRUE(offer.get() != NULL);
1379 ContentInfo* dc_offer = offer->GetContentByName("data");
1380 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001381 SctpDataContentDescription* dcd_offer =
1382 dc_offer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001383 dcd_offer->set_use_sctpmap(false);
1384
Steve Anton6fe1fba2018-12-11 10:15:23 -08001385 std::unique_ptr<SessionDescription> answer =
1386 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001387 const ContentInfo* dc_answer = answer->GetContentByName("data");
1388 ASSERT_TRUE(dc_answer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001389 const SctpDataContentDescription* dcd_answer =
1390 dc_answer->media_description()->as_sctp();
zstein4b2e0822017-02-17 19:48:38 -08001391 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001392}
1393
deadbeef8b7e9ad2017-05-25 09:38:55 -07001394// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1395// and "TCP/DTLS/SCTP" offers.
1396TEST_F(MediaSessionDescriptionFactoryTest,
1397 TestCreateDataAnswerToDifferentOfferedProtos) {
1398 // Need to enable DTLS offer/answer generation (disabled by default in this
1399 // test).
1400 f1_.set_secure(SEC_ENABLED);
1401 f2_.set_secure(SEC_ENABLED);
1402 tdf1_.set_secure(SEC_ENABLED);
1403 tdf2_.set_secure(SEC_ENABLED);
1404
1405 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001406 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001407 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001408 ASSERT_TRUE(offer.get() != nullptr);
1409 ContentInfo* dc_offer = offer->GetContentByName("data");
1410 ASSERT_TRUE(dc_offer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001411 SctpDataContentDescription* dcd_offer =
1412 dc_offer->media_description()->as_sctp();
1413 ASSERT_TRUE(dcd_offer);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001414
1415 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1416 "TCP/DTLS/SCTP"};
1417 for (const std::string& proto : protos) {
1418 dcd_offer->set_protocol(proto);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001419 std::unique_ptr<SessionDescription> answer =
1420 f2_.CreateAnswer(offer.get(), opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001421 const ContentInfo* dc_answer = answer->GetContentByName("data");
1422 ASSERT_TRUE(dc_answer != nullptr);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001423 const SctpDataContentDescription* dcd_answer =
1424 dc_answer->media_description()->as_sctp();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001425 EXPECT_FALSE(dc_answer->rejected);
1426 EXPECT_EQ(proto, dcd_answer->protocol());
1427 }
1428}
1429
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001430// Verifies that the order of the media contents in the offer is preserved in
1431// the answer.
1432TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1433 MediaSessionOptions opts;
1434
1435 // Creates a data only offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001436 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001437 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001438 ASSERT_TRUE(offer1.get() != NULL);
1439
1440 // Appends audio to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001441 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1442 RtpTransceiverDirection::kRecvOnly, kActive,
1443 &opts);
kwiberg31022942016-03-11 14:18:21 -08001444 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001445 f1_.CreateOffer(opts, offer1.get()));
1446 ASSERT_TRUE(offer2.get() != NULL);
1447
1448 // Appends video to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001449 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1450 RtpTransceiverDirection::kRecvOnly, kActive,
1451 &opts);
kwiberg31022942016-03-11 14:18:21 -08001452 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001453 f1_.CreateOffer(opts, offer2.get()));
1454 ASSERT_TRUE(offer3.get() != NULL);
1455
Steve Anton6fe1fba2018-12-11 10:15:23 -08001456 std::unique_ptr<SessionDescription> answer =
1457 f2_.CreateAnswer(offer3.get(), opts, NULL);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001458 ASSERT_TRUE(answer.get() != NULL);
1459 EXPECT_EQ(3u, answer->contents().size());
1460 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1461 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1462 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1463}
1464
ossu075af922016-06-14 03:29:38 -07001465// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1466// answerer settings.
1467
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001468// This test that the media direction is set to send/receive in an answer if
1469// the offer is send receive.
1470TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001471 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1472 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001473}
1474
1475// This test that the media direction is set to receive only in an answer if
1476// the offer is send only.
1477TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001478 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1479 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001480}
1481
1482// This test that the media direction is set to send only in an answer if
1483// the offer is recv only.
1484TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001485 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1486 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001487}
1488
1489// This test that the media direction is set to inactive in an answer if
1490// the offer is inactive.
1491TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001492 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1493 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001494}
1495
1496// Test that a data content with an unknown protocol is rejected in an answer.
1497TEST_F(MediaSessionDescriptionFactoryTest,
1498 CreateDataAnswerToOfferWithUnknownProtocol) {
1499 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001500 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001501 f1_.set_secure(SEC_ENABLED);
1502 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001503 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
terelius8c011e52016-04-26 05:28:11 -07001504 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001505 ASSERT_TRUE(dc_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001506 RtpDataContentDescription* dcd_offer =
1507 dc_offer->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001508 ASSERT_TRUE(dcd_offer != NULL);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001509 // Offer must be acceptable as an RTP protocol in order to be set.
1510 std::string protocol = "RTP/a weird unknown protocol";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001511 dcd_offer->set_protocol(protocol);
1512
Steve Anton6fe1fba2018-12-11 10:15:23 -08001513 std::unique_ptr<SessionDescription> answer =
1514 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001515
1516 const ContentInfo* dc_answer = answer->GetContentByName("data");
1517 ASSERT_TRUE(dc_answer != NULL);
1518 EXPECT_TRUE(dc_answer->rejected);
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001519 const RtpDataContentDescription* dcd_answer =
1520 dc_answer->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001521 ASSERT_TRUE(dcd_answer != NULL);
1522 EXPECT_EQ(protocol, dcd_answer->protocol());
1523}
1524
1525// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1526TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001527 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001528 f1_.set_secure(SEC_DISABLED);
1529 f2_.set_secure(SEC_DISABLED);
1530 tdf1_.set_secure(SEC_DISABLED);
1531 tdf2_.set_secure(SEC_DISABLED);
1532
Steve Anton6fe1fba2018-12-11 10:15:23 -08001533 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001534 const AudioContentDescription* offer_acd =
1535 GetFirstAudioContentDescription(offer.get());
1536 ASSERT_TRUE(offer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001537 EXPECT_EQ(cricket::kMediaProtocolAvpf, offer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001538
Steve Anton6fe1fba2018-12-11 10:15:23 -08001539 std::unique_ptr<SessionDescription> answer =
1540 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001541
1542 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1543 ASSERT_TRUE(ac_answer != NULL);
1544 EXPECT_FALSE(ac_answer->rejected);
1545
1546 const AudioContentDescription* answer_acd =
1547 GetFirstAudioContentDescription(answer.get());
1548 ASSERT_TRUE(answer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001549 EXPECT_EQ(cricket::kMediaProtocolAvpf, answer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001550}
1551
1552// Create a video offer and answer and ensure the RTP header extensions
1553// matches what we expect.
1554TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1555 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001556 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001557 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1558 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1559 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1560 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1561
Steve Anton6fe1fba2018-12-11 10:15:23 -08001562 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001563 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001564 std::unique_ptr<SessionDescription> answer =
1565 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001566
Yves Gerey665174f2018-06-19 15:03:05 +02001567 EXPECT_EQ(
1568 MAKE_VECTOR(kAudioRtpExtension1),
1569 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1570 EXPECT_EQ(
1571 MAKE_VECTOR(kVideoRtpExtension1),
1572 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1573 EXPECT_EQ(
1574 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1575 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1576 EXPECT_EQ(
1577 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1578 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001579}
1580
Johannes Kronce8e8672019-02-22 13:06:44 +01001581// Create a audio/video offer and answer and ensure that the
1582// TransportSequenceNumber RTP header extensions are handled correctly. 02 is
1583// supported and should take precedence even though not listed among locally
1584// supported extensions.
1585TEST_F(MediaSessionDescriptionFactoryTest,
1586 TestOfferAnswerWithTransportSequenceNumberInOffer) {
1587 TestTransportSequenceNumberNegotiation(
1588 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1589 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Offer.
1590 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01)); // Expected answer.
1591}
1592TEST_F(MediaSessionDescriptionFactoryTest,
1593 TestOfferAnswerWithTransportSequenceNumber01And02InOffer) {
1594 TestTransportSequenceNumberNegotiation(
1595 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1596 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01And02), // Offer.
1597 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1598}
1599TEST_F(MediaSessionDescriptionFactoryTest,
1600 TestOfferAnswerWithTransportSequenceNumber02InOffer) {
1601 TestTransportSequenceNumberNegotiation(
1602 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber01), // Local.
1603 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02), // Offer.
1604 MAKE_VECTOR(kRtpExtensionTransportSequenceNumber02)); // Expected answer.
1605}
1606
jbauch5869f502017-06-29 12:31:36 -07001607TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001608 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
jbauch5869f502017-06-29 12:31:36 -07001609 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001610 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001611
1612 f1_.set_enable_encrypted_rtp_header_extensions(true);
1613 f2_.set_enable_encrypted_rtp_header_extensions(true);
1614
Yves Gerey665174f2018-06-19 15:03:05 +02001615 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1616 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1617 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1618 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001619
Steve Anton6fe1fba2018-12-11 10:15:23 -08001620 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001621 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001622 std::unique_ptr<SessionDescription> answer =
1623 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001624
Yves Gerey665174f2018-06-19 15:03:05 +02001625 EXPECT_EQ(
1626 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1627 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1628 EXPECT_EQ(
1629 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1630 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1631 EXPECT_EQ(
1632 MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
1633 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1634 EXPECT_EQ(
1635 MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
1636 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001637}
1638
1639TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001640 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
jbauch5869f502017-06-29 12:31:36 -07001641 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001642 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001643
1644 f1_.set_enable_encrypted_rtp_header_extensions(true);
1645
Yves Gerey665174f2018-06-19 15:03:05 +02001646 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1647 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1648 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1649 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001650
Steve Anton6fe1fba2018-12-11 10:15:23 -08001651 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001652 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001653 std::unique_ptr<SessionDescription> answer =
1654 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001655
Yves Gerey665174f2018-06-19 15:03:05 +02001656 EXPECT_EQ(
1657 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1658 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1659 EXPECT_EQ(
1660 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1661 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1662 EXPECT_EQ(
1663 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1664 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1665 EXPECT_EQ(
1666 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1667 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001668}
1669
1670TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001671 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
jbauch5869f502017-06-29 12:31:36 -07001672 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001673 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001674
1675 f2_.set_enable_encrypted_rtp_header_extensions(true);
1676
Yves Gerey665174f2018-06-19 15:03:05 +02001677 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1678 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1679 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1680 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001681
Steve Anton6fe1fba2018-12-11 10:15:23 -08001682 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001683 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001684 std::unique_ptr<SessionDescription> answer =
1685 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001686
Yves Gerey665174f2018-06-19 15:03:05 +02001687 EXPECT_EQ(
1688 MAKE_VECTOR(kAudioRtpExtension1),
1689 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1690 EXPECT_EQ(
1691 MAKE_VECTOR(kVideoRtpExtension1),
1692 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1693 EXPECT_EQ(
1694 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1695 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1696 EXPECT_EQ(
1697 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1698 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001699}
1700
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001701// Create an audio, video, data answer without legacy StreamParams.
1702TEST_F(MediaSessionDescriptionFactoryTest,
1703 TestCreateAnswerWithoutLegacyStreams) {
1704 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001705 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1706 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001707 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001708 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001709 std::unique_ptr<SessionDescription> answer =
1710 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001711 const ContentInfo* ac = answer->GetContentByName("audio");
1712 const ContentInfo* vc = answer->GetContentByName("video");
1713 const ContentInfo* dc = answer->GetContentByName("data");
1714 ASSERT_TRUE(ac != NULL);
1715 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001716 const AudioContentDescription* acd = ac->media_description()->as_audio();
1717 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001718 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001719
1720 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1721 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1722 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1723}
1724
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001725// Create a typical video answer, and ensure it matches what we expect.
1726TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1727 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001728 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
1729 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1730 &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001731
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001732 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001733 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
1734 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1735 &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001736
kwiberg31022942016-03-11 14:18:21 -08001737 std::unique_ptr<SessionDescription> offer;
1738 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001739
1740 offer_opts.rtcp_mux_enabled = true;
1741 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001742 offer = f1_.CreateOffer(offer_opts, NULL);
1743 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001744 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1745 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001746 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001747 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1748 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001749 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001750 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1751 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001752 EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001753 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1754 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001755 EXPECT_TRUE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001756
1757 offer_opts.rtcp_mux_enabled = true;
1758 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001759 offer = f1_.CreateOffer(offer_opts, NULL);
1760 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001761 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1762 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001763 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001764 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1765 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001766 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001767 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1768 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001769 EXPECT_TRUE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001770 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1771 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001772 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001773
1774 offer_opts.rtcp_mux_enabled = false;
1775 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001776 offer = f1_.CreateOffer(offer_opts, NULL);
1777 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001778 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1779 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001780 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001781 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1782 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001783 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001784 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1785 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001786 EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001787 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1788 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001789 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001790
1791 offer_opts.rtcp_mux_enabled = false;
1792 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001793 offer = f1_.CreateOffer(offer_opts, NULL);
1794 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001795 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1796 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001797 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001798 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1799 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001800 ASSERT_TRUE(NULL != GetFirstRtpDataContentDescription(answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001801 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1802 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001803 EXPECT_FALSE(GetFirstRtpDataContentDescription(offer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001804 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1805 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001806 EXPECT_FALSE(GetFirstRtpDataContentDescription(answer.get())->rtcp_mux());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001807}
1808
1809// Create an audio-only answer to a video offer.
1810TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1811 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001812 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1813 RtpTransceiverDirection::kRecvOnly, kActive,
1814 &opts);
1815 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1816 RtpTransceiverDirection::kRecvOnly, kActive,
1817 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001818 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001819 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001820
1821 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001822 std::unique_ptr<SessionDescription> answer =
1823 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001824 const ContentInfo* ac = answer->GetContentByName("audio");
1825 const ContentInfo* vc = answer->GetContentByName("video");
1826 ASSERT_TRUE(ac != NULL);
1827 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001828 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001829 EXPECT_TRUE(vc->rejected);
1830}
1831
1832// Create an audio-only answer to an offer with data.
1833TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001834 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001835 opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001836 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
1837 RtpTransceiverDirection::kRecvOnly, kActive,
1838 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001839 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001840 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001841
1842 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001843 std::unique_ptr<SessionDescription> answer =
1844 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001845 const ContentInfo* ac = answer->GetContentByName("audio");
1846 const ContentInfo* dc = answer->GetContentByName("data");
1847 ASSERT_TRUE(ac != NULL);
1848 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001849 ASSERT_TRUE(dc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001850 EXPECT_TRUE(dc->rejected);
1851}
1852
1853// Create an answer that rejects the contents which are rejected in the offer.
1854TEST_F(MediaSessionDescriptionFactoryTest,
1855 CreateAnswerToOfferWithRejectedMedia) {
1856 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001857 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1858 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001859 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001860 ASSERT_TRUE(offer.get() != NULL);
1861 ContentInfo* ac = offer->GetContentByName("audio");
1862 ContentInfo* vc = offer->GetContentByName("video");
1863 ContentInfo* dc = offer->GetContentByName("data");
1864 ASSERT_TRUE(ac != NULL);
1865 ASSERT_TRUE(vc != NULL);
1866 ASSERT_TRUE(dc != NULL);
1867 ac->rejected = true;
1868 vc->rejected = true;
1869 dc->rejected = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001870 std::unique_ptr<SessionDescription> answer =
1871 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001872 ac = answer->GetContentByName("audio");
1873 vc = answer->GetContentByName("video");
1874 dc = answer->GetContentByName("data");
1875 ASSERT_TRUE(ac != NULL);
1876 ASSERT_TRUE(vc != NULL);
1877 ASSERT_TRUE(dc != NULL);
1878 EXPECT_TRUE(ac->rejected);
1879 EXPECT_TRUE(vc->rejected);
1880 EXPECT_TRUE(dc->rejected);
1881}
1882
Johannes Kron0854eb62018-10-10 22:33:20 +02001883TEST_F(MediaSessionDescriptionFactoryTest,
1884 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensions) {
1885 MediaSessionOptions opts;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001886 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02001887 // Offer without request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001888 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02001889 ASSERT_TRUE(offer.get() != NULL);
1890 std::unique_ptr<SessionDescription> answer_no_support(
1891 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001892 EXPECT_FALSE(answer_no_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001893
1894 // Offer with request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001895 offer->set_extmap_allow_mixed(true);
Johannes Kron0854eb62018-10-10 22:33:20 +02001896 ASSERT_TRUE(offer.get() != NULL);
1897 std::unique_ptr<SessionDescription> answer_support(
1898 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001899 EXPECT_TRUE(answer_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001900}
1901
1902TEST_F(MediaSessionDescriptionFactoryTest,
1903 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensionsOnMediaLevel) {
1904 MediaSessionOptions opts;
1905 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001906 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02001907 MediaContentDescription* video_offer =
1908 offer->GetContentDescriptionByName("video");
1909 ASSERT_TRUE(video_offer);
1910 MediaContentDescription* audio_offer =
1911 offer->GetContentDescriptionByName("audio");
1912 ASSERT_TRUE(audio_offer);
1913
1914 // Explicit disable of mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001915 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
1916 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
Johannes Kron0854eb62018-10-10 22:33:20 +02001917
1918 ASSERT_TRUE(offer.get() != NULL);
1919 std::unique_ptr<SessionDescription> answer_no_support(
1920 f2_.CreateAnswer(offer.get(), opts, NULL));
1921 MediaContentDescription* video_answer =
1922 answer_no_support->GetContentDescriptionByName("video");
1923 MediaContentDescription* audio_answer =
1924 answer_no_support->GetContentDescriptionByName("audio");
1925 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001926 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001927 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001928 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001929
1930 // Enable mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001931 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
1932 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
Johannes Kron0854eb62018-10-10 22:33:20 +02001933 ASSERT_TRUE(offer.get() != NULL);
1934 std::unique_ptr<SessionDescription> answer_support(
1935 f2_.CreateAnswer(offer.get(), opts, NULL));
1936 video_answer = answer_support->GetContentDescriptionByName("video");
1937 audio_answer = answer_support->GetContentDescriptionByName("audio");
1938 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02001939 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001940 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02001941 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001942}
1943
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001944// Create an audio and video offer with:
1945// - one video track
1946// - two audio tracks
1947// - two data tracks
1948// and ensure it matches what we expect. Also updates the initial offer by
1949// adding a new video track and replaces one of the audio tracks.
1950TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
1951 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001952 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001953 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1954 {kMediaStream1}, 1, &opts);
1955 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1956 {kMediaStream1}, 1, &opts);
1957 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
1958 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001959
Steve Anton4e70a722017-11-28 14:57:10 -08001960 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001961 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
1962 {kMediaStream1}, 1, &opts);
1963 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
1964 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001965
1966 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001967 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001968
1969 ASSERT_TRUE(offer.get() != NULL);
1970 const ContentInfo* ac = offer->GetContentByName("audio");
1971 const ContentInfo* vc = offer->GetContentByName("video");
1972 const ContentInfo* dc = offer->GetContentByName("data");
1973 ASSERT_TRUE(ac != NULL);
1974 ASSERT_TRUE(vc != NULL);
1975 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001976 const AudioContentDescription* acd = ac->media_description()->as_audio();
1977 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02001978 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001979 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07001980 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001981
1982 const StreamParamsVec& audio_streams = acd->streams();
1983 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001984 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001985 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1986 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1987 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1988 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1989 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1990 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1991
1992 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1993 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001994 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001995
1996 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1997 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001998 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001999
2000 const StreamParamsVec& video_streams = vcd->streams();
2001 ASSERT_EQ(1U, video_streams.size());
2002 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2003 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2004 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2005 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2006
2007 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002008 EXPECT_EQ(f1_.rtp_data_codecs(), dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002009 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002010
2011 const StreamParamsVec& data_streams = dcd->streams();
2012 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002013 EXPECT_EQ(data_streams[0].cname, data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002014 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2015 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2016 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2017 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2018 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2019 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2020
2021 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002022 dcd->bandwidth()); // default bandwidth (auto)
2023 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002024 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002025
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002026 // Update the offer. Add a new video track that is not synched to the
2027 // other tracks and replace audio track 2 with audio track 3.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002028 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2029 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002030 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002031 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
2032 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002033 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002034 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack3,
2035 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08002036 std::unique_ptr<SessionDescription> updated_offer(
2037 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002038
2039 ASSERT_TRUE(updated_offer.get() != NULL);
2040 ac = updated_offer->GetContentByName("audio");
2041 vc = updated_offer->GetContentByName("video");
2042 dc = updated_offer->GetContentByName("data");
2043 ASSERT_TRUE(ac != NULL);
2044 ASSERT_TRUE(vc != NULL);
2045 ASSERT_TRUE(dc != NULL);
2046 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002047 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002048 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002049 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002050 const RtpDataContentDescription* updated_dcd =
2051 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002052
2053 EXPECT_EQ(acd->type(), updated_acd->type());
2054 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2055 EXPECT_EQ(vcd->type(), updated_vcd->type());
2056 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2057 EXPECT_EQ(dcd->type(), updated_dcd->type());
2058 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002059 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002060 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002061 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002062 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002063 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002064 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2065
2066 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2067 ASSERT_EQ(2U, updated_audio_streams.size());
2068 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
2069 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
2070 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
2071 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
2072 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
2073
2074 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2075 ASSERT_EQ(2U, updated_video_streams.size());
2076 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2077 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002078 // All the media streams in one PeerConnection share one RTCP CNAME.
2079 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002080
2081 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2082 ASSERT_EQ(2U, updated_data_streams.size());
2083 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
2084 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
2085 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
2086 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
2087 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07002088 // The stream correctly got the CNAME from the MediaSessionOptions.
2089 // The Expected RTCP CNAME is the default one as we are using the default
2090 // MediaSessionOptions.
2091 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002092}
2093
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002094// Create an offer with simulcast video stream.
2095TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
2096 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002097 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2098 RtpTransceiverDirection::kRecvOnly, kActive,
2099 &opts);
2100 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2101 RtpTransceiverDirection::kSendRecv, kActive,
2102 &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002103 const int num_sim_layers = 3;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002104 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2105 {kMediaStream1}, num_sim_layers, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002106 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002107
2108 ASSERT_TRUE(offer.get() != NULL);
2109 const ContentInfo* vc = offer->GetContentByName("video");
2110 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002111 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002112
2113 const StreamParamsVec& video_streams = vcd->streams();
2114 ASSERT_EQ(1U, video_streams.size());
2115 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2116 const SsrcGroup* sim_ssrc_group =
2117 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
2118 ASSERT_TRUE(sim_ssrc_group != NULL);
2119 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
2120}
2121
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002122MATCHER(RidDescriptionEquals, "Verifies that two RidDescriptions are equal.") {
2123 const RidDescription& rid1 = ::testing::get<0>(arg);
2124 const RidDescription& rid2 = ::testing::get<1>(arg);
2125 return rid1.rid == rid2.rid && rid1.direction == rid2.direction;
2126}
2127
2128static void CheckSimulcastInSessionDescription(
2129 const SessionDescription* description,
2130 const std::string& content_name,
2131 const std::vector<RidDescription>& send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002132 const SimulcastLayerList& send_layers) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002133 ASSERT_NE(description, nullptr);
2134 const ContentInfo* content = description->GetContentByName(content_name);
2135 ASSERT_NE(content, nullptr);
2136 const MediaContentDescription* cd = content->media_description();
2137 ASSERT_NE(cd, nullptr);
2138 const StreamParamsVec& streams = cd->streams();
2139 ASSERT_THAT(streams, SizeIs(1));
2140 const StreamParams& stream = streams[0];
2141 ASSERT_THAT(stream.ssrcs, IsEmpty());
2142 EXPECT_TRUE(stream.has_rids());
2143 const std::vector<RidDescription> rids = stream.rids();
2144
2145 EXPECT_THAT(rids, Pointwise(RidDescriptionEquals(), send_rids));
2146
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002147 EXPECT_TRUE(cd->HasSimulcast());
2148 const SimulcastDescription& simulcast = cd->simulcast_description();
2149 EXPECT_THAT(simulcast.send_layers(), SizeIs(send_layers.size()));
2150 EXPECT_THAT(simulcast.send_layers(), Pointwise(Eq(), send_layers));
2151
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002152 ASSERT_THAT(simulcast.receive_layers().GetAllLayers(), SizeIs(0));
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002153}
2154
2155// Create an offer with spec-compliant simulcast video stream.
2156TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastOffer) {
2157 MediaSessionOptions opts;
2158 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2159 RtpTransceiverDirection::kSendRecv, kActive,
2160 &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002161 std::vector<RidDescription> send_rids;
2162 send_rids.push_back(RidDescription("f", RidDirection::kSend));
2163 send_rids.push_back(RidDescription("h", RidDirection::kSend));
2164 send_rids.push_back(RidDescription("q", RidDirection::kSend));
2165 SimulcastLayerList simulcast_layers;
2166 simulcast_layers.AddLayer(SimulcastLayer(send_rids[0].rid, false));
2167 simulcast_layers.AddLayer(SimulcastLayer(send_rids[1].rid, true));
2168 simulcast_layers.AddLayer(SimulcastLayer(send_rids[2].rid, false));
2169 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2170 {kMediaStream1}, send_rids,
2171 simulcast_layers, 0, &opts);
2172 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2173
2174 CheckSimulcastInSessionDescription(offer.get(), "video", send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002175 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002176}
2177
2178// Create an offer that signals RIDs (not SSRCs) without Simulcast.
2179// In this scenario, RIDs do not need to be negotiated (there is only one).
2180TEST_F(MediaSessionDescriptionFactoryTest, TestOfferWithRidsNoSimulcast) {
2181 MediaSessionOptions opts;
2182 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2183 RtpTransceiverDirection::kSendRecv, kActive,
2184 &opts);
2185 RidDescription rid("f", RidDirection::kSend);
2186 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2187 {kMediaStream1}, {rid},
2188 SimulcastLayerList(), 0, &opts);
2189 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2190
2191 ASSERT_NE(offer.get(), nullptr);
2192 const ContentInfo* content = offer->GetContentByName("video");
2193 ASSERT_NE(content, nullptr);
2194 const MediaContentDescription* cd = content->media_description();
2195 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002196 const StreamParamsVec& streams = cd->streams();
2197 ASSERT_THAT(streams, SizeIs(1));
2198 const StreamParams& stream = streams[0];
2199 ASSERT_THAT(stream.ssrcs, IsEmpty());
2200 EXPECT_FALSE(stream.has_rids());
2201 EXPECT_FALSE(cd->HasSimulcast());
2202}
2203
2204// Create an answer with spec-compliant simulcast video stream.
2205// In this scenario, the SFU is the caller requesting that we send Simulcast.
2206TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastAnswer) {
2207 MediaSessionOptions offer_opts;
2208 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2209 RtpTransceiverDirection::kSendRecv, kActive,
2210 &offer_opts);
2211 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2212 {kMediaStream1}, 1, &offer_opts);
2213 std::unique_ptr<SessionDescription> offer =
2214 f1_.CreateOffer(offer_opts, nullptr);
2215
2216 MediaSessionOptions answer_opts;
2217 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2218 RtpTransceiverDirection::kSendRecv, kActive,
2219 &answer_opts);
2220
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002221 std::vector<RidDescription> rid_descriptions{
2222 RidDescription("f", RidDirection::kSend),
2223 RidDescription("h", RidDirection::kSend),
2224 RidDescription("q", RidDirection::kSend),
2225 };
2226 SimulcastLayerList simulcast_layers;
2227 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[0].rid, false));
2228 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[1].rid, true));
2229 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[2].rid, false));
2230 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2231 {kMediaStream1}, rid_descriptions,
2232 simulcast_layers, 0, &answer_opts);
2233 std::unique_ptr<SessionDescription> answer =
2234 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2235
2236 CheckSimulcastInSessionDescription(answer.get(), "video", rid_descriptions,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002237 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002238}
2239
2240// Create an answer that signals RIDs (not SSRCs) without Simulcast.
2241// In this scenario, RIDs do not need to be negotiated (there is only one).
2242// Note that RID Direction is not the same as the transceiver direction.
2243TEST_F(MediaSessionDescriptionFactoryTest, TestAnswerWithRidsNoSimulcast) {
2244 MediaSessionOptions offer_opts;
2245 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2246 RtpTransceiverDirection::kSendRecv, kActive,
2247 &offer_opts);
2248 RidDescription rid_offer("f", RidDirection::kSend);
2249 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2250 {kMediaStream1}, {rid_offer},
2251 SimulcastLayerList(), 0, &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
2260 RidDescription rid_answer("f", RidDirection::kReceive);
2261 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2262 {kMediaStream1}, {rid_answer},
2263 SimulcastLayerList(), 0, &answer_opts);
2264 std::unique_ptr<SessionDescription> answer =
2265 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2266
2267 ASSERT_NE(answer.get(), nullptr);
2268 const ContentInfo* content = offer->GetContentByName("video");
2269 ASSERT_NE(content, nullptr);
2270 const MediaContentDescription* cd = content->media_description();
2271 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002272 const StreamParamsVec& streams = cd->streams();
2273 ASSERT_THAT(streams, SizeIs(1));
2274 const StreamParams& stream = streams[0];
2275 ASSERT_THAT(stream.ssrcs, IsEmpty());
2276 EXPECT_FALSE(stream.has_rids());
2277 EXPECT_FALSE(cd->HasSimulcast());
2278}
2279
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002280// Create an audio and video answer to a standard video offer with:
2281// - one video track
2282// - two audio tracks
2283// - two data tracks
2284// and ensure it matches what we expect. Also updates the initial answer by
2285// adding a new video track and removes one of the audio tracks.
2286TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
2287 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002288 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2289 RtpTransceiverDirection::kRecvOnly, kActive,
2290 &offer_opts);
2291 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2292 RtpTransceiverDirection::kRecvOnly, kActive,
2293 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002294 offer_opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002295 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2296 RtpTransceiverDirection::kRecvOnly, kActive,
2297 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002298 f1_.set_secure(SEC_ENABLED);
2299 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002300 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002301
zhihuang1c378ed2017-08-17 14:10:50 -07002302 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002303 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2304 RtpTransceiverDirection::kSendRecv, kActive,
2305 &answer_opts);
2306 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2307 RtpTransceiverDirection::kSendRecv, kActive,
2308 &answer_opts);
2309 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2310 {kMediaStream1}, 1, &answer_opts);
2311 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2312 {kMediaStream1}, 1, &answer_opts);
2313 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2314 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002315
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002316 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2317 RtpTransceiverDirection::kSendRecv, kActive,
2318 &answer_opts);
2319 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2320 {kMediaStream1}, 1, &answer_opts);
2321 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2322 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002323 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002324
Steve Anton6fe1fba2018-12-11 10:15:23 -08002325 std::unique_ptr<SessionDescription> answer =
2326 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002327
2328 ASSERT_TRUE(answer.get() != NULL);
2329 const ContentInfo* ac = answer->GetContentByName("audio");
2330 const ContentInfo* vc = answer->GetContentByName("video");
2331 const ContentInfo* dc = answer->GetContentByName("data");
2332 ASSERT_TRUE(ac != NULL);
2333 ASSERT_TRUE(vc != NULL);
2334 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002335 const AudioContentDescription* acd = ac->media_description()->as_audio();
2336 const VideoContentDescription* vcd = vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002337 const RtpDataContentDescription* dcd = dc->media_description()->as_rtp_data();
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002338 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
2339 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
2340 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002341
2342 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002343 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002344
2345 const StreamParamsVec& audio_streams = acd->streams();
2346 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002347 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002348 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2349 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2350 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2351 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2352 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2353 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2354
2355 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2356 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
2357
2358 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002359 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002360
2361 const StreamParamsVec& video_streams = vcd->streams();
2362 ASSERT_EQ(1U, video_streams.size());
2363 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2364 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2365 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2366 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2367
2368 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002369 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002370
2371 const StreamParamsVec& data_streams = dcd->streams();
2372 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002373 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002374 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2375 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2376 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2377 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2378 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2379 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2380
2381 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002382 dcd->bandwidth()); // default bandwidth (auto)
2383 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002384
2385 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07002386 // other tracks and remove 1 audio track.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002387 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2388 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002389 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
2390 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08002391 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002392 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002393
2394 ASSERT_TRUE(updated_answer.get() != NULL);
2395 ac = updated_answer->GetContentByName("audio");
2396 vc = updated_answer->GetContentByName("video");
2397 dc = updated_answer->GetContentByName("data");
2398 ASSERT_TRUE(ac != NULL);
2399 ASSERT_TRUE(vc != NULL);
2400 ASSERT_TRUE(dc != NULL);
2401 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002402 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002403 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002404 vc->media_description()->as_video();
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02002405 const RtpDataContentDescription* updated_dcd =
2406 dc->media_description()->as_rtp_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002407
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002408 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002409 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002410 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002411 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002412 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002413 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2414
2415 EXPECT_EQ(acd->type(), updated_acd->type());
2416 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2417 EXPECT_EQ(vcd->type(), updated_vcd->type());
2418 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2419 EXPECT_EQ(dcd->type(), updated_dcd->type());
2420 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
2421
2422 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2423 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002424 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002425
2426 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2427 ASSERT_EQ(2U, updated_video_streams.size());
2428 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2429 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002430 // All media streams in one PeerConnection share one CNAME.
2431 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002432
2433 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2434 ASSERT_EQ(1U, updated_data_streams.size());
2435 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
2436}
2437
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002438// Create an updated offer after creating an answer to the original offer and
2439// verify that the codecs that were part of the original answer are not changed
2440// in the updated offer.
2441TEST_F(MediaSessionDescriptionFactoryTest,
2442 RespondentCreatesOfferAfterCreatingAnswer) {
2443 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002444 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002445
Steve Anton6fe1fba2018-12-11 10:15:23 -08002446 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2447 std::unique_ptr<SessionDescription> answer =
2448 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002449
2450 const AudioContentDescription* acd =
2451 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002452 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002453
2454 const VideoContentDescription* vcd =
2455 GetFirstVideoContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002456 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002457
kwiberg31022942016-03-11 14:18:21 -08002458 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002459 f2_.CreateOffer(opts, answer.get()));
2460
2461 // The expected audio codecs are the common audio codecs from the first
2462 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
2463 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002464 // TODO(wu): |updated_offer| should not include the codec
2465 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002466 const AudioCodec kUpdatedAudioCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02002467 kAudioCodecsAnswer[0], kAudioCodecsAnswer[1], kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002468 };
2469
2470 // The expected video codecs are the common video codecs from the first
2471 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
2472 // preference order.
2473 const VideoCodec kUpdatedVideoCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02002474 kVideoCodecsAnswer[0], kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002475 };
2476
2477 const AudioContentDescription* updated_acd =
2478 GetFirstAudioContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002479 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kUpdatedAudioCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002480
2481 const VideoContentDescription* updated_vcd =
2482 GetFirstVideoContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002483 EXPECT_THAT(updated_vcd->codecs(), ElementsAreArray(kUpdatedVideoCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002484}
2485
Steve Anton5c72e712018-12-10 14:25:30 -08002486// Test that a reoffer does not reuse audio codecs from a previous media section
2487// that is being recycled.
2488TEST_F(MediaSessionDescriptionFactoryTest,
2489 ReOfferDoesNotReUseRecycledAudioCodecs) {
2490 f1_.set_video_codecs({});
2491 f2_.set_video_codecs({});
2492
2493 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002494 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2495 RtpTransceiverDirection::kSendRecv, kActive,
2496 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002497 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2498 std::unique_ptr<SessionDescription> answer =
2499 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002500
2501 // Recycle the media section by changing its mid.
2502 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002503 std::unique_ptr<SessionDescription> reoffer =
2504 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002505
2506 // Expect that the results of the first negotiation are ignored. If the m=
2507 // section was not recycled the payload types would match the initial offerer.
2508 const AudioContentDescription* acd =
2509 GetFirstAudioContentDescription(reoffer.get());
2510 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecs2));
2511}
2512
2513// Test that a reoffer does not reuse video codecs from a previous media section
2514// that is being recycled.
2515TEST_F(MediaSessionDescriptionFactoryTest,
2516 ReOfferDoesNotReUseRecycledVideoCodecs) {
2517 f1_.set_audio_codecs({}, {});
2518 f2_.set_audio_codecs({}, {});
2519
2520 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002521 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2522 RtpTransceiverDirection::kSendRecv, kActive,
2523 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002524 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2525 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002526
2527 // Recycle the media section by changing its mid.
2528 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002529 std::unique_ptr<SessionDescription> reoffer =
2530 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002531
2532 // Expect that the results of the first negotiation are ignored. If the m=
2533 // section was not recycled the payload types would match the initial offerer.
2534 const VideoContentDescription* vcd =
2535 GetFirstVideoContentDescription(reoffer.get());
2536 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecs2));
2537}
2538
2539// Test that a reanswer does not reuse audio codecs from a previous media
2540// section that is being recycled.
2541TEST_F(MediaSessionDescriptionFactoryTest,
2542 ReAnswerDoesNotReUseRecycledAudioCodecs) {
2543 f1_.set_video_codecs({});
2544 f2_.set_video_codecs({});
2545
2546 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2547 // second offer/answer is forward (|f1_| as offerer).
2548 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002549 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2550 RtpTransceiverDirection::kSendRecv, kActive,
2551 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002552 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2553 std::unique_ptr<SessionDescription> answer =
2554 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002555
2556 // Recycle the media section by changing its mid.
2557 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002558 std::unique_ptr<SessionDescription> reoffer =
2559 f1_.CreateOffer(opts, answer.get());
2560 std::unique_ptr<SessionDescription> reanswer =
2561 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002562
2563 // Expect that the results of the first negotiation are ignored. If the m=
2564 // section was not recycled the payload types would match the initial offerer.
2565 const AudioContentDescription* acd =
2566 GetFirstAudioContentDescription(reanswer.get());
2567 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
2568}
2569
2570// Test that a reanswer does not reuse video codecs from a previous media
2571// section that is being recycled.
2572TEST_F(MediaSessionDescriptionFactoryTest,
2573 ReAnswerDoesNotReUseRecycledVideoCodecs) {
2574 f1_.set_audio_codecs({}, {});
2575 f2_.set_audio_codecs({}, {});
2576
2577 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2578 // second offer/answer is forward (|f1_| as offerer).
2579 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002580 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2581 RtpTransceiverDirection::kSendRecv, kActive,
2582 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002583 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2584 std::unique_ptr<SessionDescription> answer =
2585 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002586
2587 // Recycle the media section by changing its mid.
2588 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002589 std::unique_ptr<SessionDescription> reoffer =
2590 f1_.CreateOffer(opts, answer.get());
2591 std::unique_ptr<SessionDescription> reanswer =
2592 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002593
2594 // Expect that the results of the first negotiation are ignored. If the m=
2595 // section was not recycled the payload types would match the initial offerer.
2596 const VideoContentDescription* vcd =
2597 GetFirstVideoContentDescription(reanswer.get());
2598 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
2599}
2600
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002601// Create an updated offer after creating an answer to the original offer and
2602// verify that the codecs that were part of the original answer are not changed
2603// in the updated offer. In this test Rtx is enabled.
2604TEST_F(MediaSessionDescriptionFactoryTest,
2605 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2606 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002607 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2608 RtpTransceiverDirection::kRecvOnly, kActive,
2609 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002610 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002611 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002612 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002613 f1_.set_video_codecs(f1_codecs);
2614
2615 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002616 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002617 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002618 f2_.set_video_codecs(f2_codecs);
2619
Steve Anton6fe1fba2018-12-11 10:15:23 -08002620 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002621 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002622 std::unique_ptr<SessionDescription> answer =
2623 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002624
2625 const VideoContentDescription* vcd =
2626 GetFirstVideoContentDescription(answer.get());
2627
2628 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002629 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2630 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002631
2632 EXPECT_EQ(expected_codecs, vcd->codecs());
2633
deadbeef67cf2c12016-04-13 10:07:16 -07002634 // Now, make sure we get same result (except for the order) if |f2_| creates
2635 // an updated offer even though the default payload types between |f1_| and
2636 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08002637 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002638 f2_.CreateOffer(opts, answer.get()));
2639 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002640 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002641 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2642
2643 const VideoContentDescription* updated_vcd =
2644 GetFirstVideoContentDescription(updated_answer.get());
2645
2646 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2647}
2648
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002649// Regression test for:
2650// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2651// Existing codecs should always appear before new codecs in re-offers. But
2652// under a specific set of circumstances, the existing RTX codec was ending up
2653// added to the end of the list.
2654TEST_F(MediaSessionDescriptionFactoryTest,
2655 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2656 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002657 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2658 RtpTransceiverDirection::kRecvOnly, kActive,
2659 &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002660 // We specifically choose different preferred payload types for VP8 to
2661 // trigger the issue.
2662 cricket::VideoCodec vp8_offerer(100, "VP8");
2663 cricket::VideoCodec vp8_offerer_rtx =
2664 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
2665 cricket::VideoCodec vp8_answerer(110, "VP8");
2666 cricket::VideoCodec vp8_answerer_rtx =
2667 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
2668 cricket::VideoCodec vp9(120, "VP9");
2669 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
2670
2671 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
2672 // We also specifically cause the answerer to prefer VP9, such that if it
2673 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
2674 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
2675 vp8_answerer_rtx};
2676
2677 f1_.set_video_codecs(f1_codecs);
2678 f2_.set_video_codecs(f2_codecs);
2679 std::vector<AudioCodec> audio_codecs;
2680 f1_.set_audio_codecs(audio_codecs, audio_codecs);
2681 f2_.set_audio_codecs(audio_codecs, audio_codecs);
2682
2683 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002684 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002685 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002686 std::unique_ptr<SessionDescription> answer =
2687 f2_.CreateAnswer(offer.get(), opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002688
2689 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
2690 // But if the bug is triggered, RTX for VP8 ends up last.
2691 std::unique_ptr<SessionDescription> updated_offer(
2692 f2_.CreateOffer(opts, answer.get()));
2693
2694 const VideoContentDescription* vcd =
2695 GetFirstVideoContentDescription(updated_offer.get());
2696 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
2697 ASSERT_EQ(4u, codecs.size());
2698 EXPECT_EQ(vp8_offerer, codecs[0]);
2699 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
2700 EXPECT_EQ(vp9, codecs[2]);
2701 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002702}
2703
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002704// Create an updated offer that adds video after creating an audio only answer
2705// to the original offer. This test verifies that if a video codec and the RTX
2706// codec have the same default payload type as an audio codec that is already in
2707// use, the added codecs payload types are changed.
2708TEST_F(MediaSessionDescriptionFactoryTest,
2709 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2710 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002711 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002712 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002713 f1_.set_video_codecs(f1_codecs);
2714
2715 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002716 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2717 RtpTransceiverDirection::kRecvOnly, kActive,
2718 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002719
Steve Anton6fe1fba2018-12-11 10:15:23 -08002720 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2721 std::unique_ptr<SessionDescription> answer =
2722 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002723
2724 const AudioContentDescription* acd =
2725 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002726 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002727
2728 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
2729 // reference be the same as an audio codec that was negotiated in the
2730 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002731 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08002732 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002733
2734 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2735 int used_pl_type = acd->codecs()[0].id;
2736 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002737 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002738 f2_.set_video_codecs(f2_codecs);
2739
kwiberg31022942016-03-11 14:18:21 -08002740 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002741 f2_.CreateOffer(opts, answer.get()));
2742 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002743 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002744 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2745
2746 const AudioContentDescription* updated_acd =
2747 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002748 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002749
2750 const VideoContentDescription* updated_vcd =
2751 GetFirstVideoContentDescription(updated_answer.get());
2752
2753 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
Steve Antone38a5a12018-11-21 16:05:15 -08002754 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02002755 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002756 EXPECT_NE(used_pl_type, new_h264_pl_type);
2757 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002758 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002759 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
2760 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
2761}
2762
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002763// Create an updated offer with RTX after creating an answer to an offer
2764// without RTX, and with different default payload types.
2765// Verify that the added RTX codec references the correct payload type.
2766TEST_F(MediaSessionDescriptionFactoryTest,
2767 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
2768 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002769 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002770
2771 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2772 // This creates rtx for H264 with the payload type |f2_| uses.
2773 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
2774 f2_.set_video_codecs(f2_codecs);
2775
Steve Anton6fe1fba2018-12-11 10:15:23 -08002776 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002777 ASSERT_TRUE(offer.get() != nullptr);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002778 std::unique_ptr<SessionDescription> answer =
2779 f2_.CreateAnswer(offer.get(), opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002780
2781 const VideoContentDescription* vcd =
2782 GetFirstVideoContentDescription(answer.get());
2783
2784 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2785 EXPECT_EQ(expected_codecs, vcd->codecs());
2786
2787 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
2788 // updated offer, even though the default payload types are different from
2789 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08002790 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002791 f2_.CreateOffer(opts, answer.get()));
2792 ASSERT_TRUE(updated_offer);
2793
2794 const VideoContentDescription* updated_vcd =
2795 GetFirstVideoContentDescription(updated_offer.get());
2796
2797 // New offer should attempt to add H263, and RTX for H264.
2798 expected_codecs.push_back(kVideoCodecs2[1]);
2799 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
2800 &expected_codecs);
2801 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2802}
2803
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002804// Test that RTX is ignored when there is no associated payload type parameter.
2805TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
2806 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002807 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2808 RtpTransceiverDirection::kRecvOnly, kActive,
2809 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002810 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002811 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07002812 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002813 f1_.set_video_codecs(f1_codecs);
2814
2815 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002816 // This creates RTX for H264 with the payload type |f2_| uses.
2817 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002818 f2_.set_video_codecs(f2_codecs);
2819
Steve Anton6fe1fba2018-12-11 10:15:23 -08002820 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002821 ASSERT_TRUE(offer.get() != NULL);
2822 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
2823 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
2824 // is possible to test that that RTX is dropped when
2825 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08002826 MediaContentDescription* media_desc =
2827 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2828 ASSERT_TRUE(media_desc);
2829 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002830 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07002831 for (VideoCodec& codec : codecs) {
2832 if (codec.name.find(cricket::kRtxCodecName) == 0) {
2833 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002834 }
2835 }
2836 desc->set_codecs(codecs);
2837
Steve Anton6fe1fba2018-12-11 10:15:23 -08002838 std::unique_ptr<SessionDescription> answer =
2839 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002840
Steve Anton64b626b2019-01-28 17:25:26 -08002841 EXPECT_THAT(
2842 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
2843 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002844}
2845
2846// Test that RTX will be filtered out in the answer if its associated payload
2847// type doesn't match the local value.
2848TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
2849 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002850 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2851 RtpTransceiverDirection::kRecvOnly, kActive,
2852 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002853 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2854 // This creates RTX for H264 in sender.
2855 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2856 f1_.set_video_codecs(f1_codecs);
2857
2858 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2859 // This creates RTX for H263 in receiver.
2860 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
2861 f2_.set_video_codecs(f2_codecs);
2862
Steve Anton6fe1fba2018-12-11 10:15:23 -08002863 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002864 ASSERT_TRUE(offer.get() != NULL);
2865 // Associated payload type doesn't match, therefore, RTX codec is removed in
2866 // the answer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002867 std::unique_ptr<SessionDescription> answer =
2868 f2_.CreateAnswer(offer.get(), opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002869
Steve Anton64b626b2019-01-28 17:25:26 -08002870 EXPECT_THAT(
2871 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs()),
2872 Not(Contains(cricket::kRtxCodecName)));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002873}
2874
2875// Test that when multiple RTX codecs are offered, only the matched RTX codec
2876// is added in the answer, and the unsupported RTX codec is filtered out.
2877TEST_F(MediaSessionDescriptionFactoryTest,
2878 FilterOutUnsupportedRtxWhenCreatingAnswer) {
2879 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002880 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2881 RtpTransceiverDirection::kRecvOnly, kActive,
2882 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002883 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2884 // This creates RTX for H264-SVC in sender.
2885 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2886 f1_.set_video_codecs(f1_codecs);
2887
2888 // This creates RTX for H264 in sender.
2889 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2890 f1_.set_video_codecs(f1_codecs);
2891
2892 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2893 // This creates RTX for H264 in receiver.
2894 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
2895 f2_.set_video_codecs(f2_codecs);
2896
2897 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
2898 // for H264-SVC should also be removed.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002899 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002900 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002901 std::unique_ptr<SessionDescription> answer =
2902 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002903 const VideoContentDescription* vcd =
2904 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002905 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2906 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2907 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002908
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002909 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002910}
2911
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002912// Test that after one RTX codec has been negotiated, a new offer can attempt
2913// to add another.
2914TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
2915 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002916 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2917 RtpTransceiverDirection::kRecvOnly, kActive,
2918 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002919 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2920 // This creates RTX for H264 for the offerer.
2921 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2922 f1_.set_video_codecs(f1_codecs);
2923
Steve Anton6fe1fba2018-12-11 10:15:23 -08002924 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002925 ASSERT_TRUE(offer);
2926 const VideoContentDescription* vcd =
2927 GetFirstVideoContentDescription(offer.get());
2928
2929 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
2930 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2931 &expected_codecs);
2932 EXPECT_EQ(expected_codecs, vcd->codecs());
2933
2934 // Now, attempt to add RTX for H264-SVC.
2935 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2936 f1_.set_video_codecs(f1_codecs);
2937
kwiberg31022942016-03-11 14:18:21 -08002938 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002939 f1_.CreateOffer(opts, offer.get()));
2940 ASSERT_TRUE(updated_offer);
2941 vcd = GetFirstVideoContentDescription(updated_offer.get());
2942
2943 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
2944 &expected_codecs);
2945 EXPECT_EQ(expected_codecs, vcd->codecs());
2946}
2947
Noah Richards2e7a0982015-05-18 14:02:54 -07002948// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
2949// generated for each simulcast ssrc and correctly grouped.
2950TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
2951 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002952 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2953 RtpTransceiverDirection::kSendRecv, kActive,
2954 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002955 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002956 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
2957 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002958
2959 // Use a single real codec, and then add RTX for it.
2960 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07002961 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07002962 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
2963 f1_.set_video_codecs(f1_codecs);
2964
2965 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
2966 // is a FID ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002967 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Noah Richards2e7a0982015-05-18 14:02:54 -07002968 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002969 MediaContentDescription* media_desc =
2970 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2971 ASSERT_TRUE(media_desc);
2972 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07002973 const StreamParamsVec& streams = desc->streams();
2974 // Single stream.
2975 ASSERT_EQ(1u, streams.size());
2976 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
2977 EXPECT_EQ(6u, streams[0].ssrcs.size());
2978 // And should have a SIM group for the simulcast.
2979 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2980 // And a FID group for RTX.
2981 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02002982 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002983 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2984 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02002985 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002986 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
2987 EXPECT_EQ(3u, fid_ssrcs.size());
2988}
2989
brandtr03d5fb12016-11-22 03:37:59 -08002990// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
2991// together with a FEC-FR grouping.
2992TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
2993 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002994 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2995 RtpTransceiverDirection::kSendRecv, kActive,
2996 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002997 // Add single stream.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002998 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
2999 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003000
3001 // Use a single real codec, and then add FlexFEC for it.
3002 std::vector<VideoCodec> f1_codecs;
3003 f1_codecs.push_back(VideoCodec(97, "H264"));
3004 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
3005 f1_.set_video_codecs(f1_codecs);
3006
3007 // Ensure that the offer has a single FlexFEC ssrc and that
3008 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003009 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003010 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003011 MediaContentDescription* media_desc =
3012 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3013 ASSERT_TRUE(media_desc);
3014 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003015 const StreamParamsVec& streams = desc->streams();
3016 // Single stream.
3017 ASSERT_EQ(1u, streams.size());
3018 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
3019 EXPECT_EQ(2u, streams[0].ssrcs.size());
3020 // And should have a FEC-FR group for FlexFEC.
3021 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
3022 std::vector<uint32_t> primary_ssrcs;
3023 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3024 ASSERT_EQ(1u, primary_ssrcs.size());
3025 uint32_t flexfec_ssrc;
3026 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
3027 EXPECT_NE(flexfec_ssrc, 0u);
3028}
3029
3030// Test that FlexFEC is disabled for simulcast.
3031// TODO(brandtr): Remove this test when we support simulcast, either through
3032// multiple FlexfecSenders, or through multistream protection.
3033TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
3034 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003035 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3036 RtpTransceiverDirection::kSendRecv, kActive,
3037 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003038 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003039 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
3040 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08003041
3042 // Use a single real codec, and then add FlexFEC for it.
3043 std::vector<VideoCodec> f1_codecs;
3044 f1_codecs.push_back(VideoCodec(97, "H264"));
3045 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
3046 f1_.set_video_codecs(f1_codecs);
3047
3048 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
3049 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003050 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08003051 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003052 MediaContentDescription* media_desc =
3053 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
3054 ASSERT_TRUE(media_desc);
3055 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08003056 const StreamParamsVec& streams = desc->streams();
3057 // Single stream.
3058 ASSERT_EQ(1u, streams.size());
3059 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
3060 EXPECT_EQ(3u, streams[0].ssrcs.size());
3061 // And should have a SIM group for the simulcast.
3062 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
3063 // And not a FEC-FR group for FlexFEC.
3064 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
3065 std::vector<uint32_t> primary_ssrcs;
3066 streams[0].GetPrimarySsrcs(&primary_ssrcs);
3067 EXPECT_EQ(3u, primary_ssrcs.size());
3068 for (uint32_t primary_ssrc : primary_ssrcs) {
3069 uint32_t flexfec_ssrc;
3070 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
3071 }
3072}
3073
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003074// Create an updated offer after creating an answer to the original offer and
3075// verify that the RTP header extensions that were part of the original answer
3076// are not changed in the updated offer.
3077TEST_F(MediaSessionDescriptionFactoryTest,
3078 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
3079 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003080 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003081
3082 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
3083 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
3084 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
3085 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
3086
Steve Anton6fe1fba2018-12-11 10:15:23 -08003087 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
3088 std::unique_ptr<SessionDescription> answer =
3089 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003090
Yves Gerey665174f2018-06-19 15:03:05 +02003091 EXPECT_EQ(
3092 MAKE_VECTOR(kAudioRtpExtensionAnswer),
3093 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
3094 EXPECT_EQ(
3095 MAKE_VECTOR(kVideoRtpExtensionAnswer),
3096 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003097
kwiberg31022942016-03-11 14:18:21 -08003098 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003099 f2_.CreateOffer(opts, answer.get()));
3100
3101 // The expected RTP header extensions in the new offer are the resulting
3102 // extensions from the first offer/answer exchange plus the extensions only
3103 // |f2_| offer.
3104 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003105 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07003106 const RtpExtension kUpdatedAudioRtpExtensions[] = {
3107 kAudioRtpExtensionAnswer[0], RtpExtension(kAudioRtpExtension2[1].uri, 13),
3108 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003109 };
3110
3111 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003112 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07003113 const RtpExtension kUpdatedVideoRtpExtensions[] = {
3114 kVideoRtpExtensionAnswer[0], RtpExtension(kVideoRtpExtension2[1].uri, 12),
3115 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003116 };
3117
3118 const AudioContentDescription* updated_acd =
3119 GetFirstAudioContentDescription(updated_offer.get());
3120 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
3121 updated_acd->rtp_header_extensions());
3122
3123 const VideoContentDescription* updated_vcd =
3124 GetFirstVideoContentDescription(updated_offer.get());
3125 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
3126 updated_vcd->rtp_header_extensions());
3127}
3128
deadbeefa5b273a2015-08-20 17:30:13 -07003129// Verify that if the same RTP extension URI is used for audio and video, the
3130// same ID is used. Also verify that the ID isn't changed when creating an
3131// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07003132TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07003133 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003134 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07003135
3136 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
3137 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
3138
Steve Anton6fe1fba2018-12-11 10:15:23 -08003139 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
deadbeefa5b273a2015-08-20 17:30:13 -07003140
3141 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
3142 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07003143 const RtpExtension kExpectedVideoRtpExtension[] = {
3144 kVideoRtpExtension3[0], kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07003145 };
3146
Yves Gerey665174f2018-06-19 15:03:05 +02003147 EXPECT_EQ(
3148 MAKE_VECTOR(kAudioRtpExtension3),
3149 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3150 EXPECT_EQ(
3151 MAKE_VECTOR(kExpectedVideoRtpExtension),
3152 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003153
3154 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08003155 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07003156 f1_.CreateOffer(opts, offer.get()));
3157
3158 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02003159 GetFirstAudioContentDescription(updated_offer.get())
3160 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003161 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003162 GetFirstVideoContentDescription(updated_offer.get())
3163 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003164}
3165
jbauch5869f502017-06-29 12:31:36 -07003166// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
3167TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
3168 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003169 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07003170
3171 f1_.set_enable_encrypted_rtp_header_extensions(true);
3172 f2_.set_enable_encrypted_rtp_header_extensions(true);
3173
3174 f1_.set_audio_rtp_header_extensions(
3175 MAKE_VECTOR(kAudioRtpExtension3ForEncryption));
3176 f1_.set_video_rtp_header_extensions(
3177 MAKE_VECTOR(kVideoRtpExtension3ForEncryption));
3178
Steve Anton6fe1fba2018-12-11 10:15:23 -08003179 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07003180
3181 // The extensions that are shared between audio and video should use the same
3182 // id.
3183 const RtpExtension kExpectedVideoRtpExtension[] = {
3184 kVideoRtpExtension3ForEncryption[0],
3185 kAudioRtpExtension3ForEncryptionOffer[1],
3186 kAudioRtpExtension3ForEncryptionOffer[2],
3187 };
3188
Yves Gerey665174f2018-06-19 15:03:05 +02003189 EXPECT_EQ(
3190 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
3191 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3192 EXPECT_EQ(
3193 MAKE_VECTOR(kExpectedVideoRtpExtension),
3194 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003195
3196 // Nothing should change when creating a new offer
3197 std::unique_ptr<SessionDescription> updated_offer(
3198 f1_.CreateOffer(opts, offer.get()));
3199
3200 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003201 GetFirstAudioContentDescription(updated_offer.get())
3202 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003203 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003204 GetFirstVideoContentDescription(updated_offer.get())
3205 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003206}
3207
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003208TEST(MediaSessionDescription, CopySessionDescription) {
3209 SessionDescription source;
3210 cricket::ContentGroup group(cricket::CN_AUDIO);
3211 source.AddGroup(group);
3212 AudioContentDescription* acd(new AudioContentDescription());
3213 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
3214 acd->AddLegacyStream(1);
Steve Anton5adfafd2017-12-20 16:34:00 -08003215 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp, acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003216 VideoContentDescription* vcd(new VideoContentDescription());
3217 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
3218 vcd->AddLegacyStream(2);
Steve Anton5adfafd2017-12-20 16:34:00 -08003219 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp, vcd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003220
Harald Alvestrand4d7160e2019-04-12 07:01:29 +02003221 std::unique_ptr<SessionDescription> copy = source.Clone();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003222 ASSERT_TRUE(copy.get() != NULL);
3223 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
3224 const ContentInfo* ac = copy->GetContentByName("audio");
3225 const ContentInfo* vc = copy->GetContentByName("video");
3226 ASSERT_TRUE(ac != NULL);
3227 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08003228 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003229 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003230 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
3231 EXPECT_EQ(1u, acd->first_ssrc());
3232
Steve Anton5adfafd2017-12-20 16:34:00 -08003233 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003234 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003235 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
3236 EXPECT_EQ(2u, vcd->first_ssrc());
3237}
3238
3239// The below TestTransportInfoXXX tests create different offers/answers, and
3240// ensure the TransportInfo in the SessionDescription matches what we expect.
3241TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
3242 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003243 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3244 RtpTransceiverDirection::kRecvOnly, kActive,
3245 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003246 TestTransportInfo(true, options, false);
3247}
3248
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003249TEST_F(MediaSessionDescriptionFactoryTest,
3250 TestTransportInfoOfferIceRenomination) {
3251 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003252 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3253 RtpTransceiverDirection::kRecvOnly, kActive,
3254 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003255 options.media_description_options[0]
3256 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003257 TestTransportInfo(true, options, false);
3258}
3259
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003260TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
3261 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003262 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3263 RtpTransceiverDirection::kRecvOnly, kActive,
3264 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003265 TestTransportInfo(true, options, true);
3266}
3267
3268TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
3269 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003270 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3271 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3272 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003273 TestTransportInfo(true, options, false);
3274}
3275
3276TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003277 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003278 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003279 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3280 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3281 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003282 TestTransportInfo(true, options, true);
3283}
3284
3285TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
3286 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003287 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3288 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3289 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003290 options.bundle_enabled = true;
3291 TestTransportInfo(true, options, false);
3292}
3293
3294TEST_F(MediaSessionDescriptionFactoryTest,
3295 TestTransportInfoOfferBundleCurrent) {
3296 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003297 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3298 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3299 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003300 options.bundle_enabled = true;
3301 TestTransportInfo(true, options, true);
3302}
3303
3304TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
3305 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003306 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3307 RtpTransceiverDirection::kRecvOnly, kActive,
3308 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003309 TestTransportInfo(false, options, false);
3310}
3311
3312TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003313 TestTransportInfoAnswerIceRenomination) {
3314 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003315 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3316 RtpTransceiverDirection::kRecvOnly, kActive,
3317 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003318 options.media_description_options[0]
3319 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003320 TestTransportInfo(false, options, false);
3321}
3322
3323TEST_F(MediaSessionDescriptionFactoryTest,
3324 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003325 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003326 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3327 RtpTransceiverDirection::kRecvOnly, kActive,
3328 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003329 TestTransportInfo(false, options, true);
3330}
3331
3332TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
3333 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003334 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3335 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3336 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003337 TestTransportInfo(false, options, false);
3338}
3339
3340TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003341 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003342 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003343 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3344 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3345 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003346 TestTransportInfo(false, options, true);
3347}
3348
3349TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
3350 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003351 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3352 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3353 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003354 options.bundle_enabled = true;
3355 TestTransportInfo(false, options, false);
3356}
3357
3358TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003359 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003360 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003361 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3362 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3363 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003364 options.bundle_enabled = true;
3365 TestTransportInfo(false, options, true);
3366}
3367
3368// Create an offer with bundle enabled and verify the crypto parameters are
3369// the common set of the available cryptos.
3370TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
3371 TestCryptoWithBundle(true);
3372}
3373
3374// Create an answer with bundle enabled and verify the crypto parameters are
3375// the common set of the available cryptos.
3376TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
3377 TestCryptoWithBundle(false);
3378}
3379
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003380// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
3381// DTLS is not enabled locally.
3382TEST_F(MediaSessionDescriptionFactoryTest,
3383 TestOfferDtlsSavpfWithoutDtlsFailed) {
3384 f1_.set_secure(SEC_ENABLED);
3385 f2_.set_secure(SEC_ENABLED);
3386 tdf1_.set_secure(SEC_DISABLED);
3387 tdf2_.set_secure(SEC_DISABLED);
3388
Steve Anton6fe1fba2018-12-11 10:15:23 -08003389 std::unique_ptr<SessionDescription> offer =
3390 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003391 ASSERT_TRUE(offer.get() != NULL);
3392 ContentInfo* offer_content = offer->GetContentByName("audio");
3393 ASSERT_TRUE(offer_content != NULL);
3394 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003395 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003396 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3397
Steve Anton6fe1fba2018-12-11 10:15:23 -08003398 std::unique_ptr<SessionDescription> answer =
3399 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003400 ASSERT_TRUE(answer != NULL);
3401 ContentInfo* answer_content = answer->GetContentByName("audio");
3402 ASSERT_TRUE(answer_content != NULL);
3403
3404 ASSERT_TRUE(answer_content->rejected);
3405}
3406
3407// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
3408// UDP/TLS/RTP/SAVPF.
3409TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
3410 f1_.set_secure(SEC_ENABLED);
3411 f2_.set_secure(SEC_ENABLED);
3412 tdf1_.set_secure(SEC_ENABLED);
3413 tdf2_.set_secure(SEC_ENABLED);
3414
Steve Anton6fe1fba2018-12-11 10:15:23 -08003415 std::unique_ptr<SessionDescription> offer =
3416 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003417 ASSERT_TRUE(offer.get() != NULL);
3418 ContentInfo* offer_content = offer->GetContentByName("audio");
3419 ASSERT_TRUE(offer_content != NULL);
3420 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003421 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003422 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3423
Steve Anton6fe1fba2018-12-11 10:15:23 -08003424 std::unique_ptr<SessionDescription> answer =
3425 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003426 ASSERT_TRUE(answer != NULL);
3427
3428 const ContentInfo* answer_content = answer->GetContentByName("audio");
3429 ASSERT_TRUE(answer_content != NULL);
3430 ASSERT_FALSE(answer_content->rejected);
3431
3432 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003433 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08003434 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003435}
3436
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003437// Test that we include both SDES and DTLS in the offer, but only include SDES
3438// in the answer if DTLS isn't negotiated.
3439TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
3440 f1_.set_secure(SEC_ENABLED);
3441 f2_.set_secure(SEC_ENABLED);
3442 tdf1_.set_secure(SEC_ENABLED);
3443 tdf2_.set_secure(SEC_DISABLED);
3444 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003445 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08003446 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003447 const cricket::MediaContentDescription* audio_media_desc;
3448 const cricket::MediaContentDescription* video_media_desc;
3449 const cricket::TransportDescription* audio_trans_desc;
3450 const cricket::TransportDescription* video_trans_desc;
3451
3452 // Generate an offer with SDES and DTLS support.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003453 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003454 ASSERT_TRUE(offer.get() != NULL);
3455
Steve Antonb1c1de12017-12-21 15:14:30 -08003456 audio_media_desc = offer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003457 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003458 video_media_desc = offer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003459 ASSERT_TRUE(video_media_desc != NULL);
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07003460 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003461 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3462
3463 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3464 ASSERT_TRUE(audio_trans_desc != NULL);
3465 video_trans_desc = offer->GetTransportDescriptionByName("video");
3466 ASSERT_TRUE(video_trans_desc != NULL);
3467 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3468 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3469
3470 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003471 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003472 ASSERT_TRUE(answer.get() != NULL);
3473
Steve Antonb1c1de12017-12-21 15:14:30 -08003474 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003475 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003476 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003477 ASSERT_TRUE(video_media_desc != NULL);
3478 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3479 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3480
3481 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3482 ASSERT_TRUE(audio_trans_desc != NULL);
3483 video_trans_desc = answer->GetTransportDescriptionByName("video");
3484 ASSERT_TRUE(video_trans_desc != NULL);
3485 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
3486 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
3487
3488 // Enable DTLS; the answer should now only have DTLS support.
3489 tdf2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003490 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003491 ASSERT_TRUE(answer.get() != NULL);
3492
Steve Antonb1c1de12017-12-21 15:14:30 -08003493 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003494 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003495 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003496 ASSERT_TRUE(video_media_desc != NULL);
3497 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3498 EXPECT_TRUE(video_media_desc->cryptos().empty());
Steve Antone38a5a12018-11-21 16:05:15 -08003499 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
3500 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003501
3502 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3503 ASSERT_TRUE(audio_trans_desc != NULL);
3504 video_trans_desc = answer->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);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003508
3509 // Try creating offer again. DTLS enabled now, crypto's should be empty
3510 // in new offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003511 offer = f1_.CreateOffer(options, offer.get());
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003512 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003513 audio_media_desc = offer->GetContentDescriptionByName("audio");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003514 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003515 video_media_desc = offer->GetContentDescriptionByName("video");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003516 ASSERT_TRUE(video_media_desc != NULL);
3517 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3518 EXPECT_TRUE(video_media_desc->cryptos().empty());
3519
3520 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3521 ASSERT_TRUE(audio_trans_desc != NULL);
3522 video_trans_desc = offer->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);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003526}
3527
3528// Test that an answer can't be created if cryptos are required but the offer is
3529// unsecure.
3530TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003531 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003532 f1_.set_secure(SEC_DISABLED);
3533 tdf1_.set_secure(SEC_DISABLED);
3534 f2_.set_secure(SEC_REQUIRED);
3535 tdf1_.set_secure(SEC_ENABLED);
3536
Steve Anton6fe1fba2018-12-11 10:15:23 -08003537 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003538 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003539 std::unique_ptr<SessionDescription> answer =
3540 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003541 EXPECT_TRUE(answer.get() == NULL);
3542}
3543
3544// Test that we accept a DTLS offer without SDES and create an appropriate
3545// answer.
3546TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
3547 f1_.set_secure(SEC_DISABLED);
3548 f2_.set_secure(SEC_ENABLED);
3549 tdf1_.set_secure(SEC_ENABLED);
3550 tdf2_.set_secure(SEC_ENABLED);
3551 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003552 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3553 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3554 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003555
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003556 // Generate an offer with DTLS but without SDES.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003557 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003558 ASSERT_TRUE(offer.get() != NULL);
3559
3560 const AudioContentDescription* audio_offer =
3561 GetFirstAudioContentDescription(offer.get());
3562 ASSERT_TRUE(audio_offer->cryptos().empty());
3563 const VideoContentDescription* video_offer =
3564 GetFirstVideoContentDescription(offer.get());
3565 ASSERT_TRUE(video_offer->cryptos().empty());
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02003566 const RtpDataContentDescription* data_offer =
3567 GetFirstRtpDataContentDescription(offer.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003568 ASSERT_TRUE(data_offer->cryptos().empty());
3569
3570 const cricket::TransportDescription* audio_offer_trans_desc =
3571 offer->GetTransportDescriptionByName("audio");
3572 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
3573 const cricket::TransportDescription* video_offer_trans_desc =
3574 offer->GetTransportDescriptionByName("video");
3575 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
3576 const cricket::TransportDescription* data_offer_trans_desc =
3577 offer->GetTransportDescriptionByName("data");
3578 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
3579
3580 // Generate an answer with DTLS.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003581 std::unique_ptr<SessionDescription> answer =
3582 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003583 ASSERT_TRUE(answer.get() != NULL);
3584
3585 const cricket::TransportDescription* audio_answer_trans_desc =
3586 answer->GetTransportDescriptionByName("audio");
3587 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3588 const cricket::TransportDescription* video_answer_trans_desc =
3589 answer->GetTransportDescriptionByName("video");
3590 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
3591 const cricket::TransportDescription* data_answer_trans_desc =
3592 answer->GetTransportDescriptionByName("data");
3593 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
3594}
3595
3596// Verifies if vad_enabled option is set to false, CN codecs are not present in
3597// offer or answer.
3598TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3599 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003600 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003601 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003602 ASSERT_TRUE(offer.get() != NULL);
3603 const ContentInfo* audio_content = offer->GetContentByName("audio");
3604 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
3605
3606 options.vad_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08003607 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003608 ASSERT_TRUE(offer.get() != NULL);
3609 audio_content = offer->GetContentByName("audio");
3610 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
Steve Anton6fe1fba2018-12-11 10:15:23 -08003611 std::unique_ptr<SessionDescription> answer =
3612 f1_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003613 ASSERT_TRUE(answer.get() != NULL);
3614 audio_content = answer->GetContentByName("audio");
3615 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
3616}
deadbeef44f08192015-12-15 16:20:09 -08003617
zhihuang1c378ed2017-08-17 14:10:50 -07003618// Test that the generated MIDs match the existing offer.
3619TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08003620 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003621 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_modified",
3622 RtpTransceiverDirection::kRecvOnly, kActive,
3623 &opts);
3624 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_modified",
3625 RtpTransceiverDirection::kRecvOnly, kActive,
3626 &opts);
deadbeef44f08192015-12-15 16:20:09 -08003627 opts.data_channel_type = cricket::DCT_SCTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003628 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data_modified",
3629 RtpTransceiverDirection::kSendRecv, kActive,
3630 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003631 // Create offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003632 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
kwiberg31022942016-03-11 14:18:21 -08003633 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08003634 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003635
deadbeef44f08192015-12-15 16:20:09 -08003636 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3637 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3638 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3639 ASSERT_TRUE(audio_content != nullptr);
3640 ASSERT_TRUE(video_content != nullptr);
3641 ASSERT_TRUE(data_content != nullptr);
3642 EXPECT_EQ("audio_modified", audio_content->name);
3643 EXPECT_EQ("video_modified", video_content->name);
3644 EXPECT_EQ("data_modified", data_content->name);
3645}
zhihuangcf5b37c2016-05-05 11:44:35 -07003646
zhihuang1c378ed2017-08-17 14:10:50 -07003647// The following tests verify that the unified plan SDP is supported.
3648// Test that we can create an offer with multiple media sections of same media
3649// type.
3650TEST_F(MediaSessionDescriptionFactoryTest,
3651 CreateOfferWithMultipleAVMediaSections) {
3652 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003653 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3654 RtpTransceiverDirection::kSendRecv, kActive,
3655 &opts);
3656 AttachSenderToMediaDescriptionOptions(
3657 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003658
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003659 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3660 RtpTransceiverDirection::kSendRecv, kActive,
3661 &opts);
3662 AttachSenderToMediaDescriptionOptions(
3663 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003664
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003665 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3666 RtpTransceiverDirection::kSendRecv, kActive,
3667 &opts);
3668 AttachSenderToMediaDescriptionOptions(
3669 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003670
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003671 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3672 RtpTransceiverDirection::kSendRecv, kActive,
3673 &opts);
3674 AttachSenderToMediaDescriptionOptions(
3675 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003676 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003677 ASSERT_TRUE(offer);
3678
3679 ASSERT_EQ(4u, offer->contents().size());
3680 EXPECT_FALSE(offer->contents()[0].rejected);
3681 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003682 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003683 ASSERT_EQ(1u, acd->streams().size());
3684 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003685 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003686
3687 EXPECT_FALSE(offer->contents()[1].rejected);
3688 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003689 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003690 ASSERT_EQ(1u, vcd->streams().size());
3691 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003692 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003693
3694 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003695 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003696 ASSERT_EQ(1u, acd->streams().size());
3697 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003698 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003699
3700 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003701 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003702 ASSERT_EQ(1u, vcd->streams().size());
3703 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003704 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003705}
3706
3707// Test that we can create an answer with multiple media sections of same media
3708// type.
3709TEST_F(MediaSessionDescriptionFactoryTest,
3710 CreateAnswerWithMultipleAVMediaSections) {
3711 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003712 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3713 RtpTransceiverDirection::kSendRecv, kActive,
3714 &opts);
3715 AttachSenderToMediaDescriptionOptions(
3716 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003717
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003718 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3719 RtpTransceiverDirection::kSendRecv, kActive,
3720 &opts);
3721 AttachSenderToMediaDescriptionOptions(
3722 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003723
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003724 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3725 RtpTransceiverDirection::kSendRecv, kActive,
3726 &opts);
3727 AttachSenderToMediaDescriptionOptions(
3728 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003729
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003730 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3731 RtpTransceiverDirection::kSendRecv, kActive,
3732 &opts);
3733 AttachSenderToMediaDescriptionOptions(
3734 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003735
Steve Anton6fe1fba2018-12-11 10:15:23 -08003736 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003737 ASSERT_TRUE(offer);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003738 std::unique_ptr<SessionDescription> answer =
3739 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003740
3741 ASSERT_EQ(4u, answer->contents().size());
3742 EXPECT_FALSE(answer->contents()[0].rejected);
3743 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003744 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003745 ASSERT_EQ(1u, acd->streams().size());
3746 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003747 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003748
3749 EXPECT_FALSE(answer->contents()[1].rejected);
3750 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003751 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003752 ASSERT_EQ(1u, vcd->streams().size());
3753 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003754 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003755
3756 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003757 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003758 ASSERT_EQ(1u, acd->streams().size());
3759 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003760 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003761
3762 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003763 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003764 ASSERT_EQ(1u, vcd->streams().size());
3765 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003766 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003767}
3768
3769// Test that the media section will be rejected in offer if the corresponding
3770// MediaDescriptionOptions is stopped by the offerer.
3771TEST_F(MediaSessionDescriptionFactoryTest,
3772 CreateOfferWithMediaSectionStoppedByOfferer) {
3773 // Create an offer with two audio sections and one of them is stopped.
3774 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003775 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3776 RtpTransceiverDirection::kSendRecv, kActive,
3777 &offer_opts);
3778 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3779 RtpTransceiverDirection::kInactive, kStopped,
3780 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003781 std::unique_ptr<SessionDescription> offer =
3782 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003783 ASSERT_TRUE(offer);
3784 ASSERT_EQ(2u, offer->contents().size());
3785 EXPECT_FALSE(offer->contents()[0].rejected);
3786 EXPECT_TRUE(offer->contents()[1].rejected);
3787}
3788
3789// Test that the media section will be rejected in answer if the corresponding
3790// MediaDescriptionOptions is stopped by the offerer.
3791TEST_F(MediaSessionDescriptionFactoryTest,
3792 CreateAnswerWithMediaSectionStoppedByOfferer) {
3793 // Create an offer with two audio sections and one of them is stopped.
3794 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003795 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3796 RtpTransceiverDirection::kSendRecv, kActive,
3797 &offer_opts);
3798 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3799 RtpTransceiverDirection::kInactive, kStopped,
3800 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003801 std::unique_ptr<SessionDescription> offer =
3802 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003803 ASSERT_TRUE(offer);
3804 ASSERT_EQ(2u, offer->contents().size());
3805 EXPECT_FALSE(offer->contents()[0].rejected);
3806 EXPECT_TRUE(offer->contents()[1].rejected);
3807
3808 // Create an answer based on the offer.
3809 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003810 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3811 RtpTransceiverDirection::kSendRecv, kActive,
3812 &answer_opts);
3813 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3814 RtpTransceiverDirection::kSendRecv, kActive,
3815 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003816 std::unique_ptr<SessionDescription> answer =
3817 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003818 ASSERT_EQ(2u, answer->contents().size());
3819 EXPECT_FALSE(answer->contents()[0].rejected);
3820 EXPECT_TRUE(answer->contents()[1].rejected);
3821}
3822
3823// Test that the media section will be rejected in answer if the corresponding
3824// MediaDescriptionOptions is stopped by the answerer.
3825TEST_F(MediaSessionDescriptionFactoryTest,
3826 CreateAnswerWithMediaSectionRejectedByAnswerer) {
3827 // Create an offer with two audio sections.
3828 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003829 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3830 RtpTransceiverDirection::kSendRecv, kActive,
3831 &offer_opts);
3832 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3833 RtpTransceiverDirection::kSendRecv, kActive,
3834 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003835 std::unique_ptr<SessionDescription> offer =
3836 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003837 ASSERT_TRUE(offer);
3838 ASSERT_EQ(2u, offer->contents().size());
3839 ASSERT_FALSE(offer->contents()[0].rejected);
3840 ASSERT_FALSE(offer->contents()[1].rejected);
3841
3842 // The answerer rejects one of the audio sections.
3843 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003844 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3845 RtpTransceiverDirection::kSendRecv, kActive,
3846 &answer_opts);
3847 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3848 RtpTransceiverDirection::kInactive, kStopped,
3849 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003850 std::unique_ptr<SessionDescription> answer =
3851 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003852 ASSERT_EQ(2u, answer->contents().size());
3853 EXPECT_FALSE(answer->contents()[0].rejected);
3854 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08003855
3856 // The TransportInfo of the rejected m= section is expected to be added in the
3857 // answer.
3858 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07003859}
3860
3861// Test the generated media sections has the same order of the
3862// corresponding MediaDescriptionOptions.
3863TEST_F(MediaSessionDescriptionFactoryTest,
3864 CreateOfferRespectsMediaDescriptionOptionsOrder) {
3865 MediaSessionOptions opts;
3866 // This tests put video section first because normally audio comes first by
3867 // default.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003868 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3869 RtpTransceiverDirection::kSendRecv, kActive,
3870 &opts);
3871 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3872 RtpTransceiverDirection::kSendRecv, kActive,
3873 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003874 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003875
3876 ASSERT_TRUE(offer);
3877 ASSERT_EQ(2u, offer->contents().size());
3878 EXPECT_EQ("video", offer->contents()[0].name);
3879 EXPECT_EQ("audio", offer->contents()[1].name);
3880}
3881
3882// Test that different media sections using the same codec have same payload
3883// type.
3884TEST_F(MediaSessionDescriptionFactoryTest,
3885 PayloadTypesSharedByMediaSectionsOfSameType) {
3886 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003887 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
3888 RtpTransceiverDirection::kSendRecv, kActive,
3889 &opts);
3890 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
3891 RtpTransceiverDirection::kSendRecv, kActive,
3892 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003893 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003894 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003895 ASSERT_TRUE(offer);
3896 ASSERT_EQ(2u, offer->contents().size());
3897 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003898 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003899 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003900 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003901 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3902 ASSERT_EQ(2u, vcd1->codecs().size());
3903 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3904 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3905 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
3906 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
3907
3908 // Create answer and negotiate the codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003909 std::unique_ptr<SessionDescription> answer =
3910 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003911 ASSERT_TRUE(answer);
3912 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08003913 vcd1 = answer->contents()[0].media_description()->as_video();
3914 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003915 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3916 ASSERT_EQ(1u, vcd1->codecs().size());
3917 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3918 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3919}
3920
3921// Test that the codec preference order per media section is respected in
3922// subsequent offer.
3923TEST_F(MediaSessionDescriptionFactoryTest,
3924 CreateOfferRespectsCodecPreferenceOrder) {
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 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 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3941 EXPECT_EQ(video_codecs, vcd1->codecs());
3942 EXPECT_EQ(video_codecs, vcd2->codecs());
3943
3944 // Change the codec preference of the first video section and create a
3945 // follow-up offer.
3946 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3947 vcd1->set_codecs(video_codecs_reverse);
3948 std::unique_ptr<SessionDescription> updated_offer(
3949 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08003950 vcd1 = updated_offer->contents()[0].media_description()->as_video();
3951 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003952 // The video codec preference order should be respected.
3953 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3954 EXPECT_EQ(video_codecs, vcd2->codecs());
3955}
3956
3957// Test that the codec preference order per media section is respected in
3958// the answer.
3959TEST_F(MediaSessionDescriptionFactoryTest,
3960 CreateAnswerRespectsCodecPreferenceOrder) {
3961 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003962 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
3963 RtpTransceiverDirection::kSendRecv, kActive,
3964 &opts);
3965 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
3966 RtpTransceiverDirection::kSendRecv, kActive,
3967 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003968 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003969 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003970 ASSERT_TRUE(offer);
3971 ASSERT_EQ(2u, offer->contents().size());
3972 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003973 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003974 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003975 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003976 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3977 EXPECT_EQ(video_codecs, vcd1->codecs());
3978 EXPECT_EQ(video_codecs, vcd2->codecs());
3979
3980 // Change the codec preference of the first video section and create an
3981 // answer.
3982 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3983 vcd1->set_codecs(video_codecs_reverse);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003984 std::unique_ptr<SessionDescription> answer =
3985 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003986 vcd1 = answer->contents()[0].media_description()->as_video();
3987 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003988 // The video codec preference order should be respected.
3989 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3990 EXPECT_EQ(video_codecs, vcd2->codecs());
3991}
3992
Zhi Huang6f367472017-11-22 13:20:02 -08003993// Test that when creating an answer, the codecs use local parameters instead of
3994// the remote ones.
3995TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
3996 const std::string audio_param_name = "audio_param";
3997 const std::string audio_value1 = "audio_v1";
3998 const std::string audio_value2 = "audio_v2";
3999 const std::string video_param_name = "video_param";
4000 const std::string video_value1 = "video_v1";
4001 const std::string video_value2 = "video_v2";
4002
4003 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
4004 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
4005 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
4006 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
4007
4008 // Set the parameters for codecs.
4009 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
4010 video_codecs1[0].SetParam(video_param_name, video_value1);
4011 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
4012 video_codecs2[0].SetParam(video_param_name, video_value2);
4013
4014 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
4015 f1_.set_video_codecs(video_codecs1);
4016 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
4017 f2_.set_video_codecs(video_codecs2);
4018
4019 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004020 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
4021 RtpTransceiverDirection::kSendRecv, kActive,
4022 &opts);
4023 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4024 RtpTransceiverDirection::kSendRecv, kActive,
4025 &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08004026
Steve Anton6fe1fba2018-12-11 10:15:23 -08004027 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004028 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004029 auto offer_acd = offer->contents()[0].media_description()->as_audio();
4030 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004031 std::string value;
4032 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
4033 EXPECT_EQ(audio_value1, value);
4034 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
4035 EXPECT_EQ(video_value1, value);
4036
Steve Anton6fe1fba2018-12-11 10:15:23 -08004037 std::unique_ptr<SessionDescription> answer =
4038 f2_.CreateAnswer(offer.get(), opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08004039 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08004040 auto answer_acd = answer->contents()[0].media_description()->as_audio();
4041 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08004042 // Use the parameters from the local codecs.
4043 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
4044 EXPECT_EQ(audio_value2, value);
4045 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
4046 EXPECT_EQ(video_value2, value);
4047}
4048
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004049// Test that matching packetization-mode is part of the criteria for matching
4050// H264 codecs (in addition to profile-level-id). Previously, this was not the
4051// case, so the first H264 codec with the same profile-level-id would match and
4052// the payload type in the answer would be incorrect.
4053// This is a regression test for bugs.webrtc.org/8808
4054TEST_F(MediaSessionDescriptionFactoryTest,
4055 H264MatchCriteriaIncludesPacketizationMode) {
4056 // Create two H264 codecs with the same profile level ID and different
4057 // packetization modes.
4058 VideoCodec h264_pm0(96, "H264");
4059 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4060 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
4061 VideoCodec h264_pm1(97, "H264");
4062 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
4063 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
4064
4065 // Offerer will send both codecs, answerer should choose the one with matching
4066 // packetization mode (and not the first one it sees).
4067 f1_.set_video_codecs({h264_pm0, h264_pm1});
4068 f2_.set_video_codecs({h264_pm1});
4069
4070 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004071 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
4072 RtpTransceiverDirection::kSendRecv, kActive,
4073 &opts);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004074
Steve Anton6fe1fba2018-12-11 10:15:23 -08004075 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004076 ASSERT_TRUE(offer);
4077
Steve Anton6fe1fba2018-12-11 10:15:23 -08004078 std::unique_ptr<SessionDescription> answer =
4079 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08004080 ASSERT_TRUE(answer);
4081
4082 // Answer should have one negotiated codec with packetization-mode=1 using the
4083 // offered payload type.
4084 ASSERT_EQ(1u, answer->contents().size());
4085 auto answer_vcd = answer->contents()[0].media_description()->as_video();
4086 ASSERT_EQ(1u, answer_vcd->codecs().size());
4087 auto answer_codec = answer_vcd->codecs()[0];
4088 EXPECT_EQ(h264_pm1.id, answer_codec.id);
4089}
4090
zhihuangcf5b37c2016-05-05 11:44:35 -07004091class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
4092 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004093 MediaProtocolTest()
4094 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -07004095 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
4096 MAKE_VECTOR(kAudioCodecs1));
zhihuangcf5b37c2016-05-05 11:44:35 -07004097 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004098 f1_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07004099 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
4100 MAKE_VECTOR(kAudioCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07004101 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
Harald Alvestrand5fc28b12019-05-13 13:36:16 +02004102 f2_.set_rtp_data_codecs(MAKE_VECTOR(kDataCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07004103 f1_.set_secure(SEC_ENABLED);
4104 f2_.set_secure(SEC_ENABLED);
4105 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004106 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004107 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004108 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004109 tdf1_.set_secure(SEC_ENABLED);
4110 tdf2_.set_secure(SEC_ENABLED);
4111 }
4112
4113 protected:
4114 MediaSessionDescriptionFactory f1_;
4115 MediaSessionDescriptionFactory f2_;
4116 TransportDescriptionFactory tdf1_;
4117 TransportDescriptionFactory tdf2_;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004118 UniqueRandomIdGenerator ssrc_generator1;
4119 UniqueRandomIdGenerator ssrc_generator2;
zhihuangcf5b37c2016-05-05 11:44:35 -07004120};
4121
4122TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
4123 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08004124 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004125 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004126 ASSERT_TRUE(offer.get() != nullptr);
4127 // Set the protocol for all the contents.
4128 for (auto content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004129 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07004130 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004131 std::unique_ptr<SessionDescription> answer =
4132 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004133 const ContentInfo* ac = answer->GetContentByName("audio");
4134 const ContentInfo* vc = answer->GetContentByName("video");
4135 ASSERT_TRUE(ac != nullptr);
4136 ASSERT_TRUE(vc != nullptr);
4137 EXPECT_FALSE(ac->rejected); // the offer is accepted
4138 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004139 const AudioContentDescription* acd = ac->media_description()->as_audio();
4140 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07004141 EXPECT_EQ(GetParam(), acd->protocol());
4142 EXPECT_EQ(GetParam(), vcd->protocol());
4143}
4144
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004145INSTANTIATE_TEST_SUITE_P(MediaProtocolPatternTest,
4146 MediaProtocolTest,
4147 ::testing::ValuesIn(kMediaProtocols));
4148INSTANTIATE_TEST_SUITE_P(MediaProtocolDtlsPatternTest,
4149 MediaProtocolTest,
4150 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07004151
4152TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
4153 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004154 UniqueRandomIdGenerator ssrc_generator;
4155 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004156 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4157 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4158
4159 // The merged list of codecs should contain any send codecs that are also
4160 // nominally in the recieve codecs list. Payload types should be picked from
4161 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
4162 // (set to 1). This equals what happens when the send codecs are used in an
4163 // offer and the receive codecs are used in the following answer.
4164 const std::vector<AudioCodec> sendrecv_codecs =
4165 MAKE_VECTOR(kAudioCodecsAnswer);
4166 const std::vector<AudioCodec> no_codecs;
4167
4168 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
4169 << "Please don't change shared test data!";
4170 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
4171 << "Please don't change shared test data!";
4172 // Alter iLBC send codec to have zero channels, to test that that is handled
4173 // properly.
4174 send_codecs[1].channels = 0;
4175
4176 // Alther iLBC receive codec to be lowercase, to test that case conversions
4177 // are handled properly.
4178 recv_codecs[2].name = "ilbc";
4179
4180 // Test proper merge
4181 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004182 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4183 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4184 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004185
4186 // Test empty send codecs list
4187 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004188 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4189 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4190 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004191
4192 // Test empty recv codecs list
4193 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004194 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4195 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4196 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004197
4198 // Test all empty codec lists
4199 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004200 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4201 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4202 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004203}
4204
Amit Hilbuch77938e62018-12-21 09:23:38 -08004205// Checks that the RID extensions are added to the video RTP header extensions.
4206// Note: This test somewhat shows that |set_video_rtp_header_extensions()| is
4207// not very well defined, as calling set() and immediately get() will yield
4208// an object that is not semantically equivalent to the set object.
4209TEST_F(MediaSessionDescriptionFactoryTest, VideoHasRidExtensionsInUnifiedPlan) {
4210 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004211 UniqueRandomIdGenerator ssrc_generator;
4212 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
Amit Hilbuch77938e62018-12-21 09:23:38 -08004213 sf.set_is_unified_plan(true);
4214 cricket::RtpHeaderExtensions extensions;
4215 sf.set_video_rtp_header_extensions(extensions);
4216 cricket::RtpHeaderExtensions result = sf.video_rtp_header_extensions();
4217 // Check to see that RID extensions were added to the extension list
4218 EXPECT_GE(result.size(), 2u);
Steve Anton64b626b2019-01-28 17:25:26 -08004219 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
Elad Alon157540a2019-02-08 23:37:52 +01004220 RtpExtension::kMidUri)));
4221 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
Steve Anton64b626b2019-01-28 17:25:26 -08004222 RtpExtension::kRidUri)));
4223 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
4224 RtpExtension::kRepairedRidUri)));
Amit Hilbuch77938e62018-12-21 09:23:38 -08004225}
4226
4227// Checks that the RID extensions are added to the audio RTP header extensions.
4228// Note: This test somewhat shows that |set_audio_rtp_header_extensions()| is
4229// not very well defined, as calling set() and immediately get() will yield
4230// an object that is not semantically equivalent to the set object.
4231TEST_F(MediaSessionDescriptionFactoryTest, AudioHasRidExtensionsInUnifiedPlan) {
4232 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004233 UniqueRandomIdGenerator ssrc_generator;
4234 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
Amit Hilbuch77938e62018-12-21 09:23:38 -08004235 sf.set_is_unified_plan(true);
4236 cricket::RtpHeaderExtensions extensions;
4237 sf.set_audio_rtp_header_extensions(extensions);
4238 cricket::RtpHeaderExtensions result = sf.audio_rtp_header_extensions();
4239 // Check to see that RID extensions were added to the extension list
4240 EXPECT_GE(result.size(), 2u);
Steve Anton64b626b2019-01-28 17:25:26 -08004241 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
Elad Alon157540a2019-02-08 23:37:52 +01004242 RtpExtension::kMidUri)));
4243 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
Steve Anton64b626b2019-01-28 17:25:26 -08004244 RtpExtension::kRidUri)));
4245 EXPECT_THAT(result, Contains(Field("uri", &RtpExtension::uri,
4246 RtpExtension::kRepairedRidUri)));
Amit Hilbuch77938e62018-12-21 09:23:38 -08004247}
4248
ossu075af922016-06-14 03:29:38 -07004249namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07004250// Compare the two vectors of codecs ignoring the payload type.
4251template <class Codec>
4252bool CodecsMatch(const std::vector<Codec>& codecs1,
4253 const std::vector<Codec>& codecs2) {
4254 if (codecs1.size() != codecs2.size()) {
4255 return false;
4256 }
4257
4258 for (size_t i = 0; i < codecs1.size(); ++i) {
4259 if (!codecs1[i].Matches(codecs2[i])) {
4260 return false;
4261 }
4262 }
4263 return true;
4264}
4265
Steve Anton4e70a722017-11-28 14:57:10 -08004266void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07004267 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004268 UniqueRandomIdGenerator ssrc_generator;
4269 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004270 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4271 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4272 const std::vector<AudioCodec> sendrecv_codecs =
4273 MAKE_VECTOR(kAudioCodecsAnswer);
4274 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07004275
4276 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004277 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
4278 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004279
Steve Anton4e70a722017-11-28 14:57:10 -08004280 if (direction == RtpTransceiverDirection::kSendRecv ||
4281 direction == RtpTransceiverDirection::kSendOnly) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004282 AttachSenderToMediaDescriptionOptions(
4283 "audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004284 }
ossu075af922016-06-14 03:29:38 -07004285
Steve Anton6fe1fba2018-12-11 10:15:23 -08004286 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
ossu075af922016-06-14 03:29:38 -07004287 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004288 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07004289
4290 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07004291 // that the codecs put in are right. This happens when we neither want to
4292 // send nor receive audio. The checks are still in place if at some point
4293 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004294 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004295 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004296 // sendrecv and inactive should both present lists as if the channel was
4297 // to be used for sending and receiving. Inactive essentially means it
4298 // might eventually be used anything, but we don't know more at this
4299 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08004300 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004301 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08004302 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004303 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004304 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07004305 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004306 }
4307 }
4308}
4309
4310static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07004311 AudioCodec(0, "codec0", 16000, -1, 1),
4312 AudioCodec(1, "codec1", 8000, 13300, 1),
4313 AudioCodec(2, "codec2", 8000, 64000, 1),
4314 AudioCodec(3, "codec3", 8000, 64000, 1),
4315 AudioCodec(4, "codec4", 8000, 0, 2),
4316 AudioCodec(5, "codec5", 32000, 0, 1),
4317 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07004318
zhihuang1c378ed2017-08-17 14:10:50 -07004319/* The codecs groups below are chosen as per the matrix below. The objective
4320 * is to have different sets of codecs in the inputs, to get unique sets of
4321 * codecs after negotiation, depending on offer and answer communication
4322 * directions. One-way directions in the offer should either result in the
4323 * opposite direction in the answer, or an inactive answer. Regardless, the
4324 * choice of codecs should be as if the answer contained the opposite
4325 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07004326 *
4327 * | Offer | Answer | Result
4328 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
4329 * 0 | x - - | - x - | x - - - -
4330 * 1 | x x x | - x - | x - - x -
4331 * 2 | - x - | x - - | - x - - -
4332 * 3 | x x x | x - - | - x x - -
4333 * 4 | - x - | x x x | - x - - -
4334 * 5 | x - - | x x x | x - - - -
4335 * 6 | x x x | x x x | x x x x x
4336 */
4337// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004338static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
4339static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07004340// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
4341// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07004342static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
4343static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07004344// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004345static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
4346static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
4347static const int kResultSendrecv_SendCodecs[] = {3, 6};
4348static const int kResultSendrecv_RecvCodecs[] = {1, 6};
4349static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07004350
4351template <typename T, int IDXS>
4352std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
4353 std::vector<T> out;
4354 out.reserve(IDXS);
4355 for (int idx : indices)
4356 out.push_back(array[idx]);
4357
4358 return out;
4359}
4360
Steve Anton4e70a722017-11-28 14:57:10 -08004361void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
4362 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07004363 bool add_legacy_stream) {
4364 TransportDescriptionFactory offer_tdf;
4365 TransportDescriptionFactory answer_tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004366 UniqueRandomIdGenerator ssrc_generator1, ssrc_generator2;
4367 MediaSessionDescriptionFactory offer_factory(&offer_tdf, &ssrc_generator1);
4368 MediaSessionDescriptionFactory answer_factory(&answer_tdf, &ssrc_generator2);
ossu075af922016-06-14 03:29:38 -07004369 offer_factory.set_audio_codecs(
4370 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
4371 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
4372 answer_factory.set_audio_codecs(
4373 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
4374 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
4375
ossu075af922016-06-14 03:29:38 -07004376 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004377 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", offer_direction,
4378 kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004379
Steve Anton4e70a722017-11-28 14:57:10 -08004380 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004381 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4382 kAudioTrack1, {kMediaStream1}, 1,
4383 &offer_opts);
ossu075af922016-06-14 03:29:38 -07004384 }
4385
Steve Anton6fe1fba2018-12-11 10:15:23 -08004386 std::unique_ptr<SessionDescription> offer =
4387 offer_factory.CreateOffer(offer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004388 ASSERT_TRUE(offer.get() != NULL);
4389
4390 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004391 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", answer_direction,
4392 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004393
Steve Anton4e70a722017-11-28 14:57:10 -08004394 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004395 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4396 kAudioTrack1, {kMediaStream1}, 1,
4397 &answer_opts);
ossu075af922016-06-14 03:29:38 -07004398 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004399 std::unique_ptr<SessionDescription> answer =
4400 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004401 const ContentInfo* ac = answer->GetContentByName("audio");
4402
zhihuang1c378ed2017-08-17 14:10:50 -07004403 // If the factory didn't add any audio content to the answer, we cannot
4404 // check that the codecs put in are right. This happens when we neither want
4405 // to send nor receive audio. The checks are still in place if at some point
4406 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004407 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004408 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
4409 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07004410
ossu075af922016-06-14 03:29:38 -07004411 std::vector<AudioCodec> target_codecs;
4412 // For offers with sendrecv or inactive, we should never reply with more
4413 // codecs than offered, with these codec sets.
4414 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08004415 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07004416 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4417 kResultSendrecv_SendrecvCodecs);
4418 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004419 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004420 target_codecs =
4421 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004422 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004423 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004424 target_codecs =
4425 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07004426 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004427 case RtpTransceiverDirection::kSendRecv:
4428 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004429 target_codecs =
4430 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08004431 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004432 target_codecs =
4433 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004434 } else {
4435 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4436 kResultSendrecv_SendrecvCodecs);
4437 }
4438 break;
4439 }
4440
zhihuang1c378ed2017-08-17 14:10:50 -07004441 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02004442 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07004443 bool first = true;
4444 os << "{";
4445 for (const auto& c : codecs) {
4446 os << (first ? " " : ", ") << c.id;
4447 first = false;
4448 }
4449 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02004450 return os.Release();
ossu075af922016-06-14 03:29:38 -07004451 };
4452
4453 EXPECT_TRUE(acd->codecs() == target_codecs)
4454 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08004455 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
4456 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07004457 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08004458 << webrtc::RtpTransceiverDirectionToString(answer_direction)
4459 << "; got: "
4460 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07004461 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08004462 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07004463 << "Only inactive offers are allowed to not generate any audio "
4464 "content";
ossu075af922016-06-14 03:29:38 -07004465 }
4466}
brandtr03d5fb12016-11-22 03:37:59 -08004467
4468} // namespace
ossu075af922016-06-14 03:29:38 -07004469
4470class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08004471 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07004472
4473TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004474 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07004475}
4476
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004477INSTANTIATE_TEST_SUITE_P(MediaSessionDescriptionFactoryTest,
4478 AudioCodecsOfferTest,
4479 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4480 RtpTransceiverDirection::kRecvOnly,
4481 RtpTransceiverDirection::kSendRecv,
4482 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07004483
4484class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08004485 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
4486 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07004487 bool>> {};
ossu075af922016-06-14 03:29:38 -07004488
4489TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08004490 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
4491 ::testing::get<1>(GetParam()),
4492 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07004493}
4494
Mirko Bonadeic84f6612019-01-31 12:20:57 +01004495INSTANTIATE_TEST_SUITE_P(
zhihuang1c378ed2017-08-17 14:10:50 -07004496 MediaSessionDescriptionFactoryTest,
4497 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004498 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
4499 RtpTransceiverDirection::kRecvOnly,
4500 RtpTransceiverDirection::kSendRecv,
4501 RtpTransceiverDirection::kInactive),
4502 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4503 RtpTransceiverDirection::kRecvOnly,
4504 RtpTransceiverDirection::kSendRecv,
4505 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07004506 ::testing::Bool()));