blob: d1a151f9c28aef856f595573848fd030ab1c27a9 [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 Anton6fe1fba2018-12-11 10:15:23 -080016#include "absl/memory/memory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "media/base/codec.h"
Steve Anton10542f22019-01-11 09:11:00 -080018#include "media/base/test_utils.h"
19#include "p2p/base/p2p_constants.h"
20#include "p2p/base/transport_description.h"
21#include "p2p/base/transport_info.h"
22#include "pc/media_session.h"
23#include "pc/rtp_media_utils.h"
24#include "pc/srtp_filter.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020025#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080026#include "rtc_base/fake_ssl_identity.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020027#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 09:11:00 -080028#include "rtc_base/message_digest.h"
29#include "rtc_base/ssl_adapter.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020030#include "rtc_base/strings/string_builder.h"
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080031#include "rtc_base/unique_id_generator.h"
Steve Antone38a5a12018-11-21 16:05:15 -080032#include "test/gmock.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000033
Yves Gerey665174f2018-06-19 15:03:05 +020034#define ASSERT_CRYPTO(cd, s, cs) \
35 ASSERT_EQ(s, cd->cryptos().size()); \
Steve Antone38a5a12018-11-21 16:05:15 -080036 ASSERT_EQ(cs, cd->cryptos()[0].cipher_suite)
henrike@webrtc.org28e20752013-07-10 00:45:36 +000037
38typedef std::vector<cricket::Candidate> Candidates;
39
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080040using cricket::AudioCodec;
41using cricket::AudioContentDescription;
42using cricket::ContentInfo;
43using cricket::CryptoParamsVec;
44using cricket::DataCodec;
45using cricket::DataContentDescription;
46using cricket::GetFirstAudioContent;
47using cricket::GetFirstAudioContentDescription;
48using cricket::GetFirstDataContent;
49using cricket::GetFirstDataContentDescription;
50using cricket::GetFirstVideoContent;
51using cricket::GetFirstVideoContentDescription;
52using cricket::kAutoBandwidth;
53using cricket::MEDIA_TYPE_AUDIO;
54using cricket::MEDIA_TYPE_DATA;
55using cricket::MEDIA_TYPE_VIDEO;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000056using cricket::MediaContentDescription;
zhihuang1c378ed2017-08-17 14:10:50 -070057using cricket::MediaDescriptionOptions;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080058using cricket::MediaProtocolType;
59using cricket::MediaSessionDescriptionFactory;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000060using cricket::MediaSessionOptions;
61using cricket::MediaType;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080062using cricket::RidDescription;
63using cricket::RidDirection;
64using cricket::SEC_DISABLED;
65using cricket::SEC_ENABLED;
66using cricket::SEC_REQUIRED;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000067using cricket::SessionDescription;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080068using cricket::SimulcastDescription;
69using cricket::SimulcastLayer;
70using cricket::SimulcastLayerList;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000071using cricket::SsrcGroup;
72using cricket::StreamParams;
73using cricket::StreamParamsVec;
74using cricket::TransportDescription;
75using cricket::TransportDescriptionFactory;
76using cricket::TransportInfo;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000077using cricket::VideoCodec;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080078using cricket::VideoContentDescription;
jbauchcb560652016-08-04 05:20:32 -070079using rtc::CS_AEAD_AES_128_GCM;
80using rtc::CS_AEAD_AES_256_GCM;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080081using rtc::CS_AES_CM_128_HMAC_SHA1_32;
82using rtc::CS_AES_CM_128_HMAC_SHA1_80;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -080083using rtc::UniqueRandomIdGenerator;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080084using testing::Each;
Steve Antone38a5a12018-11-21 16:05:15 -080085using testing::ElementsAreArray;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -080086using testing::Eq;
87using testing::Field;
88using testing::IsEmpty;
89using testing::IsFalse;
90using testing::Ne;
91using testing::Pointwise;
92using testing::SizeIs;
isheriff6f8d6862016-05-26 11:24:55 -070093using webrtc::RtpExtension;
Steve Anton4e70a722017-11-28 14:57:10 -080094using webrtc::RtpTransceiverDirection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000095
96static const AudioCodec kAudioCodecs1[] = {
deadbeef67cf2c12016-04-13 10:07:16 -070097 AudioCodec(103, "ISAC", 16000, -1, 1),
98 AudioCodec(102, "iLBC", 8000, 13300, 1),
99 AudioCodec(0, "PCMU", 8000, 64000, 1),
100 AudioCodec(8, "PCMA", 8000, 64000, 1),
101 AudioCodec(117, "red", 8000, 0, 1),
102 AudioCodec(107, "CN", 48000, 0, 1)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000103
104static const AudioCodec kAudioCodecs2[] = {
Henrik Lundinf8ed5612018-05-07 12:05:57 +0200105 AudioCodec(126, "foo", 16000, 22000, 1),
deadbeef67cf2c12016-04-13 10:07:16 -0700106 AudioCodec(0, "PCMU", 8000, 64000, 1),
107 AudioCodec(127, "iLBC", 8000, 13300, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000108};
109
110static const AudioCodec kAudioCodecsAnswer[] = {
deadbeef67cf2c12016-04-13 10:07:16 -0700111 AudioCodec(102, "iLBC", 8000, 13300, 1),
112 AudioCodec(0, "PCMU", 8000, 64000, 1),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000113};
114
perkj26752742016-10-24 01:21:16 -0700115static const VideoCodec kVideoCodecs1[] = {VideoCodec(96, "H264-SVC"),
116 VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000117
zhihuang1c378ed2017-08-17 14:10:50 -0700118static const VideoCodec kVideoCodecs1Reverse[] = {VideoCodec(97, "H264"),
119 VideoCodec(96, "H264-SVC")};
120
perkj26752742016-10-24 01:21:16 -0700121static const VideoCodec kVideoCodecs2[] = {VideoCodec(126, "H264"),
122 VideoCodec(127, "H263")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000123
perkj26752742016-10-24 01:21:16 -0700124static const VideoCodec kVideoCodecsAnswer[] = {VideoCodec(97, "H264")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000125
deadbeef67cf2c12016-04-13 10:07:16 -0700126static const DataCodec kDataCodecs1[] = {DataCodec(98, "binary-data"),
127 DataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000128
deadbeef67cf2c12016-04-13 10:07:16 -0700129static const DataCodec kDataCodecs2[] = {DataCodec(126, "binary-data"),
130 DataCodec(127, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000131
deadbeef67cf2c12016-04-13 10:07:16 -0700132static const DataCodec kDataCodecsAnswer[] = {DataCodec(98, "binary-data"),
133 DataCodec(99, "utf8-text")};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000134
isheriff6f8d6862016-05-26 11:24:55 -0700135static const RtpExtension kAudioRtpExtension1[] = {
136 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
137 RtpExtension("http://google.com/testing/audio_something", 10),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000138};
139
jbauch5869f502017-06-29 12:31:36 -0700140static const RtpExtension kAudioRtpExtensionEncrypted1[] = {
141 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
142 RtpExtension("http://google.com/testing/audio_something", 10),
143 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
144};
145
isheriff6f8d6862016-05-26 11:24:55 -0700146static const RtpExtension kAudioRtpExtension2[] = {
147 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 2),
148 RtpExtension("http://google.com/testing/audio_something_else", 8),
149 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000150};
151
isheriff6f8d6862016-05-26 11:24:55 -0700152static const RtpExtension kAudioRtpExtension3[] = {
153 RtpExtension("http://google.com/testing/audio_something", 2),
154 RtpExtension("http://google.com/testing/both_audio_and_video", 3),
deadbeefa5b273a2015-08-20 17:30:13 -0700155};
156
jbauch5869f502017-06-29 12:31:36 -0700157static const RtpExtension kAudioRtpExtension3ForEncryption[] = {
158 RtpExtension("http://google.com/testing/audio_something", 2),
159 // Use RTP extension that supports encryption.
160 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
161};
162
163static const RtpExtension kAudioRtpExtension3ForEncryptionOffer[] = {
164 RtpExtension("http://google.com/testing/audio_something", 2),
165 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 3),
166 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14, true),
167};
168
isheriff6f8d6862016-05-26 11:24:55 -0700169static const RtpExtension kAudioRtpExtensionAnswer[] = {
170 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000171};
172
jbauch5869f502017-06-29 12:31:36 -0700173static const RtpExtension kAudioRtpExtensionEncryptedAnswer[] = {
174 RtpExtension("urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12, true),
175};
176
isheriff6f8d6862016-05-26 11:24:55 -0700177static const RtpExtension kVideoRtpExtension1[] = {
178 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
179 RtpExtension("http://google.com/testing/video_something", 13),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000180};
181
jbauch5869f502017-06-29 12:31:36 -0700182static const RtpExtension kVideoRtpExtensionEncrypted1[] = {
183 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
184 RtpExtension("http://google.com/testing/video_something", 13),
185 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
186};
187
isheriff6f8d6862016-05-26 11:24:55 -0700188static const RtpExtension kVideoRtpExtension2[] = {
189 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 2),
190 RtpExtension("http://google.com/testing/video_something_else", 14),
191 RtpExtension("http://google.com/testing/both_audio_and_video", 7),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000192};
193
isheriff6f8d6862016-05-26 11:24:55 -0700194static const RtpExtension kVideoRtpExtension3[] = {
195 RtpExtension("http://google.com/testing/video_something", 4),
196 RtpExtension("http://google.com/testing/both_audio_and_video", 5),
deadbeefa5b273a2015-08-20 17:30:13 -0700197};
198
jbauch5869f502017-06-29 12:31:36 -0700199static const RtpExtension kVideoRtpExtension3ForEncryption[] = {
200 RtpExtension("http://google.com/testing/video_something", 4),
201 // Use RTP extension that supports encryption.
202 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 5),
203};
204
isheriff6f8d6862016-05-26 11:24:55 -0700205static const RtpExtension kVideoRtpExtensionAnswer[] = {
206 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 14),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000207};
208
jbauch5869f502017-06-29 12:31:36 -0700209static const RtpExtension kVideoRtpExtensionEncryptedAnswer[] = {
210 RtpExtension("urn:ietf:params:rtp-hdrext:toffset", 11, true),
211};
212
Peter Boström0c4e06b2015-10-07 12:23:21 +0200213static const uint32_t kSimulcastParamsSsrc[] = {10, 11, 20, 21, 30, 31};
214static const uint32_t kSimSsrc[] = {10, 20, 30};
215static const uint32_t kFec1Ssrc[] = {10, 11};
216static const uint32_t kFec2Ssrc[] = {20, 21};
217static const uint32_t kFec3Ssrc[] = {30, 31};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000218
219static const char kMediaStream1[] = "stream_1";
220static const char kMediaStream2[] = "stream_2";
221static const char kVideoTrack1[] = "video_1";
222static const char kVideoTrack2[] = "video_2";
223static const char kAudioTrack1[] = "audio_1";
224static const char kAudioTrack2[] = "audio_2";
225static const char kAudioTrack3[] = "audio_3";
226static const char kDataTrack1[] = "data_1";
227static const char kDataTrack2[] = "data_2";
228static const char kDataTrack3[] = "data_3";
229
zhihuangcf5b37c2016-05-05 11:44:35 -0700230static const char* kMediaProtocols[] = {"RTP/AVP", "RTP/SAVP", "RTP/AVPF",
231 "RTP/SAVPF"};
232static const char* kMediaProtocolsDtls[] = {
233 "TCP/TLS/RTP/SAVPF", "TCP/TLS/RTP/SAVP", "UDP/TLS/RTP/SAVPF",
234 "UDP/TLS/RTP/SAVP"};
235
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700236// SRTP cipher name negotiated by the tests. This must be updated if the
237// default changes.
238static const char* kDefaultSrtpCryptoSuite = CS_AES_CM_128_HMAC_SHA1_80;
239static const char* kDefaultSrtpCryptoSuiteGcm = CS_AEAD_AES_256_GCM;
240
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800241// These constants are used to make the code using "AddMediaDescriptionOptions"
242// more readable.
zhihuang1c378ed2017-08-17 14:10:50 -0700243static constexpr bool kStopped = true;
244static constexpr bool kActive = false;
245
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000246static bool IsMediaContentOfType(const ContentInfo* content,
247 MediaType media_type) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800248 RTC_DCHECK(content);
249 return content->media_description()->type() == media_type;
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +0000250}
251
Steve Anton4e70a722017-11-28 14:57:10 -0800252static RtpTransceiverDirection GetMediaDirection(const ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800253 RTC_DCHECK(content);
254 return content->media_description()->direction();
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000255}
256
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000257static void AddRtxCodec(const VideoCodec& rtx_codec,
258 std::vector<VideoCodec>* codecs) {
magjedb05fa242016-11-11 04:00:16 -0800259 ASSERT_FALSE(cricket::FindCodecById(*codecs, rtx_codec.id));
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +0000260 codecs->push_back(rtx_codec);
261}
262
263template <class T>
264static std::vector<std::string> GetCodecNames(const std::vector<T>& codecs) {
265 std::vector<std::string> codec_names;
266 for (const auto& codec : codecs) {
267 codec_names.push_back(codec.name);
268 }
269 return codec_names;
270}
271
zhihuang1c378ed2017-08-17 14:10:50 -0700272// This is used for test only. MIDs are not the identification of the
273// MediaDescriptionOptions since some end points may not support MID and the SDP
274// may not contain 'mid'.
275std::vector<MediaDescriptionOptions>::iterator FindFirstMediaDescriptionByMid(
276 const std::string& mid,
277 MediaSessionOptions* opts) {
278 return std::find_if(
279 opts->media_description_options.begin(),
280 opts->media_description_options.end(),
Steve Anton36b29d12017-10-30 09:57:42 -0700281 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
282}
283
284std::vector<MediaDescriptionOptions>::const_iterator
285FindFirstMediaDescriptionByMid(const std::string& mid,
286 const MediaSessionOptions& opts) {
287 return std::find_if(
288 opts.media_description_options.begin(),
289 opts.media_description_options.end(),
290 [&mid](const MediaDescriptionOptions& t) { return t.mid == mid; });
zhihuang1c378ed2017-08-17 14:10:50 -0700291}
292
293// Add a media section to the |session_options|.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800294static void AddMediaDescriptionOptions(MediaType type,
295 const std::string& mid,
296 RtpTransceiverDirection direction,
297 bool stopped,
298 MediaSessionOptions* opts) {
Steve Anton4e70a722017-11-28 14:57:10 -0800299 opts->media_description_options.push_back(
300 MediaDescriptionOptions(type, mid, direction, stopped));
zhihuang1c378ed2017-08-17 14:10:50 -0700301}
302
Steve Anton4e70a722017-11-28 14:57:10 -0800303static void AddAudioVideoSections(RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700304 MediaSessionOptions* opts) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800305 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
306 opts);
307 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video", direction, kActive,
308 opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700309}
310
311static void AddDataSection(cricket::DataChannelType dct,
Steve Anton4e70a722017-11-28 14:57:10 -0800312 RtpTransceiverDirection direction,
zhihuang1c378ed2017-08-17 14:10:50 -0700313 MediaSessionOptions* opts) {
314 opts->data_channel_type = dct;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800315 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
zhihuang1c378ed2017-08-17 14:10:50 -0700316}
317
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800318static void AttachSenderToMediaDescriptionOptions(
Steve Anton8ffb9c32017-08-31 15:45:38 -0700319 const std::string& mid,
320 MediaType type,
321 const std::string& track_id,
322 const std::vector<std::string>& stream_ids,
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800323 const std::vector<RidDescription>& rids,
324 const SimulcastLayerList& simulcast_layers,
Steve Anton8ffb9c32017-08-31 15:45:38 -0700325 int num_sim_layer,
326 MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -0700327 auto it = FindFirstMediaDescriptionByMid(mid, session_options);
328 switch (type) {
329 case MEDIA_TYPE_AUDIO:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700330 it->AddAudioSender(track_id, stream_ids);
zhihuang1c378ed2017-08-17 14:10:50 -0700331 break;
332 case MEDIA_TYPE_VIDEO:
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800333 it->AddVideoSender(track_id, stream_ids, rids, simulcast_layers,
334 num_sim_layer);
zhihuang1c378ed2017-08-17 14:10:50 -0700335 break;
336 case MEDIA_TYPE_DATA:
Steve Anton8ffb9c32017-08-31 15:45:38 -0700337 RTC_CHECK(stream_ids.size() == 1U);
338 it->AddRtpDataChannel(track_id, stream_ids[0]);
zhihuang1c378ed2017-08-17 14:10:50 -0700339 break;
340 default:
341 RTC_NOTREACHED();
342 }
343}
344
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800345static void AttachSenderToMediaDescriptionOptions(
346 const std::string& mid,
347 MediaType type,
348 const std::string& track_id,
349 const std::vector<std::string>& stream_ids,
350 int num_sim_layer,
351 MediaSessionOptions* session_options) {
352 AttachSenderToMediaDescriptionOptions(mid, type, track_id, stream_ids, {},
353 SimulcastLayerList(), num_sim_layer,
354 session_options);
355}
356
zhihuang1c378ed2017-08-17 14:10:50 -0700357static void DetachSenderFromMediaSection(const std::string& mid,
358 const std::string& track_id,
359 MediaSessionOptions* session_options) {
Steve Anton3a66edf2018-09-10 12:57:37 -0700360 std::vector<cricket::SenderOptions>& sender_options_list =
361 FindFirstMediaDescriptionByMid(mid, session_options)->sender_options;
362 auto sender_it =
363 std::find_if(sender_options_list.begin(), sender_options_list.end(),
364 [track_id](const cricket::SenderOptions& sender_options) {
365 return sender_options.track_id == track_id;
366 });
367 RTC_DCHECK(sender_it != sender_options_list.end());
368 sender_options_list.erase(sender_it);
zhihuang1c378ed2017-08-17 14:10:50 -0700369}
370
371// Helper function used to create a default MediaSessionOptions for Plan B SDP.
372// (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
373static MediaSessionOptions CreatePlanBMediaSessionOptions() {
374 MediaSessionOptions session_options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800375 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
376 RtpTransceiverDirection::kRecvOnly, kActive,
377 &session_options);
zhihuang1c378ed2017-08-17 14:10:50 -0700378 return session_options;
379}
380
381// TODO(zhihuang): Most of these tests were written while MediaSessionOptions
382// was designed for Plan B SDP, where only one audio "m=" section and one video
383// "m=" section could be generated, and ordering couldn't be controlled. Many of
384// these tests may be obsolete as a result, and should be refactored or removed.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000385class MediaSessionDescriptionFactoryTest : public testing::Test {
386 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800387 MediaSessionDescriptionFactoryTest()
388 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -0700389 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
390 MAKE_VECTOR(kAudioCodecs1));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000391 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
392 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -0700393 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
394 MAKE_VECTOR(kAudioCodecs2));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000395 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
396 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200397 tdf1_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700398 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
Henrik Boström3a14bf32015-08-31 09:27:58 +0200399 tdf2_.set_certificate(rtc::RTCCertificate::Create(
jbauch555604a2016-04-26 03:13:22 -0700400 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000401 }
402
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000403 // Create a video StreamParamsVec object with:
404 // - one video stream with 3 simulcast streams and FEC,
405 StreamParamsVec CreateComplexVideoStreamParamsVec() {
406 SsrcGroup sim_group("SIM", MAKE_VECTOR(kSimSsrc));
407 SsrcGroup fec_group1("FEC", MAKE_VECTOR(kFec1Ssrc));
408 SsrcGroup fec_group2("FEC", MAKE_VECTOR(kFec2Ssrc));
409 SsrcGroup fec_group3("FEC", MAKE_VECTOR(kFec3Ssrc));
410
411 std::vector<SsrcGroup> ssrc_groups;
412 ssrc_groups.push_back(sim_group);
413 ssrc_groups.push_back(fec_group1);
414 ssrc_groups.push_back(fec_group2);
415 ssrc_groups.push_back(fec_group3);
416
417 StreamParams simulcast_params;
418 simulcast_params.id = kVideoTrack1;
419 simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
420 simulcast_params.ssrc_groups = ssrc_groups;
421 simulcast_params.cname = "Video_SIM_FEC";
Seth Hampson845e8782018-03-02 11:34:10 -0800422 simulcast_params.set_stream_ids({kMediaStream1});
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +0000423
424 StreamParamsVec video_streams;
425 video_streams.push_back(simulcast_params);
426
427 return video_streams;
428 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000429
430 bool CompareCryptoParams(const CryptoParamsVec& c1,
431 const CryptoParamsVec& c2) {
432 if (c1.size() != c2.size())
433 return false;
434 for (size_t i = 0; i < c1.size(); ++i)
435 if (c1[i].tag != c2[i].tag || c1[i].cipher_suite != c2[i].cipher_suite ||
436 c1[i].key_params != c2[i].key_params ||
437 c1[i].session_params != c2[i].session_params)
438 return false;
439 return true;
440 }
441
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700442 // Returns true if the transport info contains "renomination" as an
443 // ICE option.
444 bool GetIceRenomination(const TransportInfo* transport_info) {
445 const std::vector<std::string>& ice_options =
446 transport_info->description.transport_options;
deadbeef30952b42017-04-21 02:41:29 -0700447 auto iter =
448 std::find(ice_options.begin(), ice_options.end(), "renomination");
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700449 return iter != ice_options.end();
450 }
451
zhihuang1c378ed2017-08-17 14:10:50 -0700452 void TestTransportInfo(bool offer,
Steve Anton36b29d12017-10-30 09:57:42 -0700453 const MediaSessionOptions& options,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000454 bool has_current_desc) {
455 const std::string current_audio_ufrag = "current_audio_ufrag";
456 const std::string current_audio_pwd = "current_audio_pwd";
457 const std::string current_video_ufrag = "current_video_ufrag";
458 const std::string current_video_pwd = "current_video_pwd";
459 const std::string current_data_ufrag = "current_data_ufrag";
460 const std::string current_data_pwd = "current_data_pwd";
kwiberg31022942016-03-11 14:18:21 -0800461 std::unique_ptr<SessionDescription> current_desc;
462 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000463 if (has_current_desc) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800464 current_desc = absl::make_unique<SessionDescription>();
Steve Anton06817cd2018-12-18 15:55:30 -0800465 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200466 "audio",
Steve Anton06817cd2018-12-18 15:55:30 -0800467 TransportDescription(current_audio_ufrag, current_audio_pwd)));
468 current_desc->AddTransportInfo(TransportInfo(
Yves Gerey665174f2018-06-19 15:03:05 +0200469 "video",
Steve Anton06817cd2018-12-18 15:55:30 -0800470 TransportDescription(current_video_ufrag, current_video_pwd)));
471 current_desc->AddTransportInfo(TransportInfo(
472 "data", TransportDescription(current_data_ufrag, current_data_pwd)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000473 }
474 if (offer) {
Steve Anton6fe1fba2018-12-11 10:15:23 -0800475 desc = f1_.CreateOffer(options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000476 } else {
kwiberg31022942016-03-11 14:18:21 -0800477 std::unique_ptr<SessionDescription> offer;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800478 offer = f1_.CreateOffer(options, NULL);
479 desc = f1_.CreateAnswer(offer.get(), options, current_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000480 }
481 ASSERT_TRUE(desc.get() != NULL);
482 const TransportInfo* ti_audio = desc->GetTransportInfoByName("audio");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000483 if (options.has_audio()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000484 EXPECT_TRUE(ti_audio != NULL);
485 if (has_current_desc) {
486 EXPECT_EQ(current_audio_ufrag, ti_audio->description.ice_ufrag);
487 EXPECT_EQ(current_audio_pwd, ti_audio->description.ice_pwd);
488 } else {
489 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
490 ti_audio->description.ice_ufrag.size());
491 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
492 ti_audio->description.ice_pwd.size());
493 }
zhihuang1c378ed2017-08-17 14:10:50 -0700494 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700495 FindFirstMediaDescriptionByMid("audio", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700496 EXPECT_EQ(
497 media_desc_options_it->transport_options.enable_ice_renomination,
498 GetIceRenomination(ti_audio));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000499
500 } else {
501 EXPECT_TRUE(ti_audio == NULL);
502 }
503 const TransportInfo* ti_video = desc->GetTransportInfoByName("video");
jiayl@webrtc.org742922b2014-10-07 21:32:43 +0000504 if (options.has_video()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000505 EXPECT_TRUE(ti_video != NULL);
506 if (options.bundle_enabled) {
507 EXPECT_EQ(ti_audio->description.ice_ufrag,
508 ti_video->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200509 EXPECT_EQ(ti_audio->description.ice_pwd, ti_video->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000510 } else {
511 if (has_current_desc) {
512 EXPECT_EQ(current_video_ufrag, ti_video->description.ice_ufrag);
513 EXPECT_EQ(current_video_pwd, ti_video->description.ice_pwd);
514 } else {
515 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
516 ti_video->description.ice_ufrag.size());
517 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
518 ti_video->description.ice_pwd.size());
519 }
520 }
zhihuang1c378ed2017-08-17 14:10:50 -0700521 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700522 FindFirstMediaDescriptionByMid("video", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700523 EXPECT_EQ(
524 media_desc_options_it->transport_options.enable_ice_renomination,
525 GetIceRenomination(ti_video));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000526 } else {
527 EXPECT_TRUE(ti_video == NULL);
528 }
529 const TransportInfo* ti_data = desc->GetTransportInfoByName("data");
530 if (options.has_data()) {
531 EXPECT_TRUE(ti_data != NULL);
532 if (options.bundle_enabled) {
533 EXPECT_EQ(ti_audio->description.ice_ufrag,
534 ti_data->description.ice_ufrag);
Yves Gerey665174f2018-06-19 15:03:05 +0200535 EXPECT_EQ(ti_audio->description.ice_pwd, ti_data->description.ice_pwd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000536 } else {
537 if (has_current_desc) {
538 EXPECT_EQ(current_data_ufrag, ti_data->description.ice_ufrag);
539 EXPECT_EQ(current_data_pwd, ti_data->description.ice_pwd);
540 } else {
541 EXPECT_EQ(static_cast<size_t>(cricket::ICE_UFRAG_LENGTH),
542 ti_data->description.ice_ufrag.size());
543 EXPECT_EQ(static_cast<size_t>(cricket::ICE_PWD_LENGTH),
544 ti_data->description.ice_pwd.size());
545 }
546 }
zhihuang1c378ed2017-08-17 14:10:50 -0700547 auto media_desc_options_it =
Steve Anton36b29d12017-10-30 09:57:42 -0700548 FindFirstMediaDescriptionByMid("data", options);
zhihuang1c378ed2017-08-17 14:10:50 -0700549 EXPECT_EQ(
550 media_desc_options_it->transport_options.enable_ice_renomination,
551 GetIceRenomination(ti_data));
Honghai Zhang4cedf2b2016-08-31 08:18:11 -0700552
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000553 } else {
554 EXPECT_TRUE(ti_video == NULL);
555 }
556 }
557
558 void TestCryptoWithBundle(bool offer) {
559 f1_.set_secure(SEC_ENABLED);
560 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -0800561 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
562 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
563 &options);
kwiberg31022942016-03-11 14:18:21 -0800564 std::unique_ptr<SessionDescription> ref_desc;
565 std::unique_ptr<SessionDescription> desc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000566 if (offer) {
567 options.bundle_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800568 ref_desc = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000569 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800570 desc = f1_.CreateOffer(options, ref_desc.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000571 } else {
572 options.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800573 ref_desc = f1_.CreateOffer(options, NULL);
574 desc = f1_.CreateAnswer(ref_desc.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000575 }
Steve Antonb1c1de12017-12-21 15:14:30 -0800576 ASSERT_TRUE(desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000577 const cricket::MediaContentDescription* audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800578 desc->GetContentDescriptionByName("audio");
579 ASSERT_TRUE(audio_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000580 const cricket::MediaContentDescription* video_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800581 desc->GetContentDescriptionByName("video");
582 ASSERT_TRUE(video_media_desc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000583 EXPECT_TRUE(CompareCryptoParams(audio_media_desc->cryptos(),
584 video_media_desc->cryptos()));
585 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
Steve Antone38a5a12018-11-21 16:05:15 -0800586 EXPECT_EQ(kDefaultSrtpCryptoSuite,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000587 audio_media_desc->cryptos()[0].cipher_suite);
588
589 // Verify the selected crypto is one from the reference audio
590 // media content.
591 const cricket::MediaContentDescription* ref_audio_media_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -0800592 ref_desc->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000593 bool found = false;
594 for (size_t i = 0; i < ref_audio_media_desc->cryptos().size(); ++i) {
595 if (ref_audio_media_desc->cryptos()[i].Matches(
Yves Gerey665174f2018-06-19 15:03:05 +0200596 audio_media_desc->cryptos()[0])) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000597 found = true;
598 break;
599 }
600 }
601 EXPECT_TRUE(found);
602 }
603
604 // This test that the audio and video media direction is set to
605 // |expected_direction_in_answer| in an answer if the offer direction is set
zhihuang1c378ed2017-08-17 14:10:50 -0700606 // to |direction_in_offer| and the answer is willing to both send and receive.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000607 void TestMediaDirectionInAnswer(
Steve Anton4e70a722017-11-28 14:57:10 -0800608 RtpTransceiverDirection direction_in_offer,
609 RtpTransceiverDirection expected_direction_in_answer) {
zhihuang1c378ed2017-08-17 14:10:50 -0700610 MediaSessionOptions offer_opts;
611 AddAudioVideoSections(direction_in_offer, &offer_opts);
612
Steve Anton6fe1fba2018-12-11 10:15:23 -0800613 std::unique_ptr<SessionDescription> offer =
614 f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000615 ASSERT_TRUE(offer.get() != NULL);
terelius8c011e52016-04-26 05:28:11 -0700616 ContentInfo* ac_offer = offer->GetContentByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000617 ASSERT_TRUE(ac_offer != NULL);
terelius8c011e52016-04-26 05:28:11 -0700618 ContentInfo* vc_offer = offer->GetContentByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000619 ASSERT_TRUE(vc_offer != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000620
zhihuang1c378ed2017-08-17 14:10:50 -0700621 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800622 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800623 std::unique_ptr<SessionDescription> answer =
624 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000625 const AudioContentDescription* acd_answer =
626 GetFirstAudioContentDescription(answer.get());
627 EXPECT_EQ(expected_direction_in_answer, acd_answer->direction());
628 const VideoContentDescription* vcd_answer =
629 GetFirstVideoContentDescription(answer.get());
630 EXPECT_EQ(expected_direction_in_answer, vcd_answer->direction());
631 }
632
633 bool VerifyNoCNCodecs(const cricket::ContentInfo* content) {
Steve Antonb1c1de12017-12-21 15:14:30 -0800634 RTC_DCHECK(content);
635 RTC_CHECK(content->media_description());
636 const cricket::AudioContentDescription* audio_desc =
637 content->media_description()->as_audio();
638 RTC_CHECK(audio_desc);
639 for (const cricket::AudioCodec& codec : audio_desc->codecs()) {
640 if (codec.name == "CN") {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000641 return false;
Steve Antonb1c1de12017-12-21 15:14:30 -0800642 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000643 }
644 return true;
645 }
646
jbauchcb560652016-08-04 05:20:32 -0700647 void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
648 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800649 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700650 offer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_offer;
zhihuang1c378ed2017-08-17 14:10:50 -0700651
jbauchcb560652016-08-04 05:20:32 -0700652 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800653 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700654 answer_opts.crypto_options.srtp.enable_gcm_crypto_suites = gcm_answer;
zhihuang1c378ed2017-08-17 14:10:50 -0700655
jbauchcb560652016-08-04 05:20:32 -0700656 f1_.set_secure(SEC_ENABLED);
657 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800658 std::unique_ptr<SessionDescription> offer =
659 f1_.CreateOffer(offer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700660 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800661 std::unique_ptr<SessionDescription> answer =
662 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
jbauchcb560652016-08-04 05:20:32 -0700663 const ContentInfo* ac = answer->GetContentByName("audio");
664 const ContentInfo* vc = answer->GetContentByName("video");
665 ASSERT_TRUE(ac != NULL);
666 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800667 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
668 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800669 const AudioContentDescription* acd = ac->media_description()->as_audio();
670 const VideoContentDescription* vcd = vc->media_description()->as_video();
jbauchcb560652016-08-04 05:20:32 -0700671 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800672 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -0700673 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -0700674 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -0700675 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
676 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700677 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700678 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700679 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700680 }
681 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -0800682 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +0200683 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
684 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
jbauchcb560652016-08-04 05:20:32 -0700685 if (gcm_offer && gcm_answer) {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700686 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuiteGcm);
jbauchcb560652016-08-04 05:20:32 -0700687 } else {
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700688 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
jbauchcb560652016-08-04 05:20:32 -0700689 }
Steve Antone38a5a12018-11-21 16:05:15 -0800690 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
jbauchcb560652016-08-04 05:20:32 -0700691 }
692
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000693 protected:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -0800694 UniqueRandomIdGenerator ssrc_generator1;
695 UniqueRandomIdGenerator ssrc_generator2;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000696 MediaSessionDescriptionFactory f1_;
697 MediaSessionDescriptionFactory f2_;
698 TransportDescriptionFactory tdf1_;
699 TransportDescriptionFactory tdf2_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000700};
701
702// Create a typical audio offer, and ensure it matches what we expect.
703TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioOffer) {
704 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800705 std::unique_ptr<SessionDescription> offer =
706 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000707 ASSERT_TRUE(offer.get() != NULL);
708 const ContentInfo* ac = offer->GetContentByName("audio");
709 const ContentInfo* vc = offer->GetContentByName("video");
710 ASSERT_TRUE(ac != NULL);
711 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800712 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800713 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000714 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700715 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700716 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000717 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
718 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700719 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800720 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000721}
722
723// Create a typical video offer, and ensure it matches what we expect.
724TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
725 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800726 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000727 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800728 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000729 ASSERT_TRUE(offer.get() != NULL);
730 const ContentInfo* ac = offer->GetContentByName("audio");
731 const ContentInfo* vc = offer->GetContentByName("video");
732 ASSERT_TRUE(ac != NULL);
733 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800734 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
735 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800736 const AudioContentDescription* acd = ac->media_description()->as_audio();
737 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000738 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700739 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700740 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000741 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
742 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700743 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800744 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000745 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
746 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700747 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000748 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
749 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700750 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800751 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000752}
753
754// Test creating an offer with bundle where the Codecs have the same dynamic
755// RTP playlod type. The test verifies that the offer don't contain the
756// duplicate RTP payload types.
757TEST_F(MediaSessionDescriptionFactoryTest, TestBundleOfferWithSameCodecPlType) {
758 const VideoCodec& offered_video_codec = f2_.video_codecs()[0];
ossudedfd282016-06-14 07:12:39 -0700759 const AudioCodec& offered_audio_codec = f2_.audio_sendrecv_codecs()[0];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000760 const DataCodec& offered_data_codec = f2_.data_codecs()[0];
761 ASSERT_EQ(offered_video_codec.id, offered_audio_codec.id);
762 ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
763
764 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800765 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
766 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000767 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800768 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000769 const VideoContentDescription* vcd =
770 GetFirstVideoContentDescription(offer.get());
771 const AudioContentDescription* acd =
772 GetFirstAudioContentDescription(offer.get());
773 const DataContentDescription* dcd =
774 GetFirstDataContentDescription(offer.get());
775 ASSERT_TRUE(NULL != vcd);
776 ASSERT_TRUE(NULL != acd);
777 ASSERT_TRUE(NULL != dcd);
778 EXPECT_NE(vcd->codecs()[0].id, acd->codecs()[0].id);
779 EXPECT_NE(vcd->codecs()[0].id, dcd->codecs()[0].id);
780 EXPECT_NE(acd->codecs()[0].id, dcd->codecs()[0].id);
781 EXPECT_EQ(vcd->codecs()[0].name, offered_video_codec.name);
782 EXPECT_EQ(acd->codecs()[0].name, offered_audio_codec.name);
783 EXPECT_EQ(dcd->codecs()[0].name, offered_data_codec.name);
784}
785
zhihuang1c378ed2017-08-17 14:10:50 -0700786// Test creating an updated offer with bundle, audio, video and data
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000787// after an audio only session has been negotiated.
788TEST_F(MediaSessionDescriptionFactoryTest,
789 TestCreateUpdatedVideoOfferWithBundle) {
790 f1_.set_secure(SEC_ENABLED);
791 f2_.set_secure(SEC_ENABLED);
792 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -0800793 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
794 RtpTransceiverDirection::kRecvOnly, kActive,
795 &opts);
796 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
797 RtpTransceiverDirection::kInactive, kStopped,
798 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000799 opts.data_channel_type = cricket::DCT_NONE;
800 opts.bundle_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -0800801 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
802 std::unique_ptr<SessionDescription> answer =
803 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000804
805 MediaSessionOptions updated_opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800806 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
807 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
808 &updated_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000809 updated_opts.bundle_enabled = true;
kwiberg31022942016-03-11 14:18:21 -0800810 std::unique_ptr<SessionDescription> updated_offer(
811 f1_.CreateOffer(updated_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000812
813 const AudioContentDescription* acd =
814 GetFirstAudioContentDescription(updated_offer.get());
815 const VideoContentDescription* vcd =
816 GetFirstVideoContentDescription(updated_offer.get());
817 const DataContentDescription* dcd =
818 GetFirstDataContentDescription(updated_offer.get());
819 EXPECT_TRUE(NULL != vcd);
820 EXPECT_TRUE(NULL != acd);
821 EXPECT_TRUE(NULL != dcd);
822
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700823 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800824 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700825 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800826 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700827 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800828 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000829}
deadbeef44f08192015-12-15 16:20:09 -0800830
wu@webrtc.org78187522013-10-07 23:32:02 +0000831// Create a RTP data offer, and ensure it matches what we expect.
832TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000833 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -0800834 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
835 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000836 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800837 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000838 ASSERT_TRUE(offer.get() != NULL);
839 const ContentInfo* ac = offer->GetContentByName("audio");
840 const ContentInfo* dc = offer->GetContentByName("data");
841 ASSERT_TRUE(ac != NULL);
842 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -0800843 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
844 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -0800845 const AudioContentDescription* acd = ac->media_description()->as_audio();
846 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000847 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -0700848 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700849 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attched.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000850 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
851 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700852 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800853 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000854 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
855 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
zhihuang1c378ed2017-08-17 14:10:50 -0700856 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000857 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +0200858 dcd->bandwidth()); // default bandwidth (auto)
859 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -0700860 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -0800861 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000862}
863
wu@webrtc.org78187522013-10-07 23:32:02 +0000864// Create an SCTP data offer with bundle without error.
865TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
866 MediaSessionOptions opts;
wu@webrtc.org78187522013-10-07 23:32:02 +0000867 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800868 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
wu@webrtc.org78187522013-10-07 23:32:02 +0000869 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -0800870 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.org78187522013-10-07 23:32:02 +0000871 EXPECT_TRUE(offer.get() != NULL);
872 EXPECT_TRUE(offer->GetContentByName("data") != NULL);
873}
874
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000875// Test creating an sctp data channel from an already generated offer.
876TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
877 MediaSessionOptions opts;
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000878 opts.bundle_enabled = true;
Steve Anton4e70a722017-11-28 14:57:10 -0800879 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000880 f1_.set_secure(SEC_ENABLED);
kwiberg31022942016-03-11 14:18:21 -0800881 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000882 ASSERT_TRUE(offer1.get() != NULL);
883 const ContentInfo* data = offer1->GetContentByName("data");
884 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800885 ASSERT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000886
887 // Now set data_channel_type to 'none' (default) and make sure that the
888 // datachannel type that gets generated from the previous offer, is of the
889 // same type.
890 opts.data_channel_type = cricket::DCT_NONE;
kwiberg31022942016-03-11 14:18:21 -0800891 std::unique_ptr<SessionDescription> offer2(
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000892 f1_.CreateOffer(opts, offer1.get()));
893 data = offer2->GetContentByName("data");
894 ASSERT_TRUE(data != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -0800895 EXPECT_EQ(cricket::kMediaProtocolSctp, data->media_description()->protocol());
tommi@webrtc.orgf15dee62014-10-27 22:15:04 +0000896}
897
Steve Anton2bed3972019-01-04 17:04:30 -0800898// Test that if BUNDLE is enabled and all media sections are rejected then the
899// BUNDLE group is not present in the re-offer.
900TEST_F(MediaSessionDescriptionFactoryTest, ReOfferNoBundleGroupIfAllRejected) {
901 MediaSessionOptions opts;
902 opts.bundle_enabled = true;
903 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
904 RtpTransceiverDirection::kSendRecv, kActive,
905 &opts);
906 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
907
908 opts.media_description_options[0].stopped = true;
909 std::unique_ptr<SessionDescription> reoffer =
910 f1_.CreateOffer(opts, offer.get());
911
912 EXPECT_FALSE(reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
913}
914
915// Test that if BUNDLE is enabled and the remote re-offer does not include a
916// BUNDLE group since all media sections are rejected, then the re-answer also
917// does not include a BUNDLE group.
918TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerNoBundleGroupIfAllRejected) {
919 MediaSessionOptions opts;
920 opts.bundle_enabled = true;
921 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
922 RtpTransceiverDirection::kSendRecv, kActive,
923 &opts);
924 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
925 std::unique_ptr<SessionDescription> answer =
926 f2_.CreateAnswer(offer.get(), opts, nullptr);
927
928 opts.media_description_options[0].stopped = true;
929 std::unique_ptr<SessionDescription> reoffer =
930 f1_.CreateOffer(opts, offer.get());
931 std::unique_ptr<SessionDescription> reanswer =
932 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
933
934 EXPECT_FALSE(reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE));
935}
936
937// Test that if BUNDLE is enabled and the previous offerer-tagged media section
938// was rejected then the new offerer-tagged media section is the non-rejected
939// media section.
940TEST_F(MediaSessionDescriptionFactoryTest, ReOfferChangeBundleOffererTagged) {
941 MediaSessionOptions opts;
942 opts.bundle_enabled = true;
943 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
944 RtpTransceiverDirection::kSendRecv, kActive,
945 &opts);
946 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
947
948 // Reject the audio m= section and add a video m= section.
949 opts.media_description_options[0].stopped = true;
950 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
951 RtpTransceiverDirection::kSendRecv, kActive,
952 &opts);
953 std::unique_ptr<SessionDescription> reoffer =
954 f1_.CreateOffer(opts, offer.get());
955
956 const cricket::ContentGroup* bundle_group =
957 reoffer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
958 ASSERT_TRUE(bundle_group);
959 EXPECT_FALSE(bundle_group->HasContentName("audio"));
960 EXPECT_TRUE(bundle_group->HasContentName("video"));
961}
962
963// Test that if BUNDLE is enabled and the previous offerer-tagged media section
964// was rejected and a new media section is added, then the re-answer BUNDLE
965// group will contain only the non-rejected media section.
966TEST_F(MediaSessionDescriptionFactoryTest, ReAnswerChangedBundleOffererTagged) {
967 MediaSessionOptions opts;
968 opts.bundle_enabled = true;
969 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
970 RtpTransceiverDirection::kSendRecv, kActive,
971 &opts);
972 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
973 std::unique_ptr<SessionDescription> answer =
974 f2_.CreateAnswer(offer.get(), opts, nullptr);
975
976 // Reject the audio m= section and add a video m= section.
977 opts.media_description_options[0].stopped = true;
978 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
979 RtpTransceiverDirection::kSendRecv, kActive,
980 &opts);
981 std::unique_ptr<SessionDescription> reoffer =
982 f1_.CreateOffer(opts, offer.get());
983 std::unique_ptr<SessionDescription> reanswer =
984 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
985
986 const cricket::ContentGroup* bundle_group =
987 reanswer->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
988 ASSERT_TRUE(bundle_group);
989 EXPECT_FALSE(bundle_group->HasContentName("audio"));
990 EXPECT_TRUE(bundle_group->HasContentName("video"));
991}
992
993// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
994// and there is still a non-rejected media section that was in the initial
995// offer, then the ICE credentials do not change in the reoffer offerer-tagged
996// media section.
997TEST_F(MediaSessionDescriptionFactoryTest,
998 ReOfferChangeBundleOffererTaggedKeepsIceCredentials) {
999 MediaSessionOptions opts;
1000 opts.bundle_enabled = true;
1001 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1002 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1003 std::unique_ptr<SessionDescription> answer =
1004 f2_.CreateAnswer(offer.get(), opts, nullptr);
1005
1006 // Reject the audio m= section.
1007 opts.media_description_options[0].stopped = true;
1008 std::unique_ptr<SessionDescription> reoffer =
1009 f1_.CreateOffer(opts, offer.get());
1010
1011 const TransportDescription* offer_tagged =
1012 offer->GetTransportDescriptionByName("audio");
1013 ASSERT_TRUE(offer_tagged);
1014 const TransportDescription* reoffer_tagged =
1015 reoffer->GetTransportDescriptionByName("video");
1016 ASSERT_TRUE(reoffer_tagged);
1017 EXPECT_EQ(offer_tagged->ice_ufrag, reoffer_tagged->ice_ufrag);
1018 EXPECT_EQ(offer_tagged->ice_pwd, reoffer_tagged->ice_pwd);
1019}
1020
1021// Test that if the BUNDLE offerer-tagged media section is changed in a reoffer
1022// and there is still a non-rejected media section that was in the initial
1023// offer, then the ICE credentials do not change in the reanswer answerer-tagged
1024// media section.
1025TEST_F(MediaSessionDescriptionFactoryTest,
1026 ReAnswerChangeBundleOffererTaggedKeepsIceCredentials) {
1027 MediaSessionOptions opts;
1028 opts.bundle_enabled = true;
1029 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
1030 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
1031 std::unique_ptr<SessionDescription> answer =
1032 f2_.CreateAnswer(offer.get(), opts, nullptr);
1033
1034 // Reject the audio m= section.
1035 opts.media_description_options[0].stopped = true;
1036 std::unique_ptr<SessionDescription> reoffer =
1037 f1_.CreateOffer(opts, offer.get());
1038 std::unique_ptr<SessionDescription> reanswer =
1039 f2_.CreateAnswer(reoffer.get(), opts, answer.get());
1040
1041 const TransportDescription* answer_tagged =
1042 answer->GetTransportDescriptionByName("audio");
1043 ASSERT_TRUE(answer_tagged);
1044 const TransportDescription* reanswer_tagged =
1045 reanswer->GetTransportDescriptionByName("video");
1046 ASSERT_TRUE(reanswer_tagged);
1047 EXPECT_EQ(answer_tagged->ice_ufrag, reanswer_tagged->ice_ufrag);
1048 EXPECT_EQ(answer_tagged->ice_pwd, reanswer_tagged->ice_pwd);
1049}
1050
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001051// Create an audio, video offer without legacy StreamParams.
1052TEST_F(MediaSessionDescriptionFactoryTest,
1053 TestCreateOfferWithoutLegacyStreams) {
1054 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001055 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001056 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001057 ASSERT_TRUE(offer.get() != NULL);
1058 const ContentInfo* ac = offer->GetContentByName("audio");
1059 const ContentInfo* vc = offer->GetContentByName("video");
1060 ASSERT_TRUE(ac != NULL);
1061 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001062 const AudioContentDescription* acd = ac->media_description()->as_audio();
1063 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001064
Yves Gerey665174f2018-06-19 15:03:05 +02001065 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1066 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001067}
1068
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001069// Creates an audio+video sendonly offer.
1070TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001071 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001072 AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001073 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1074 {kMediaStream1}, 1, &opts);
1075 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1076 {kMediaStream1}, 1, &opts);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001077
Steve Anton6fe1fba2018-12-11 10:15:23 -08001078 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001079 ASSERT_TRUE(offer.get() != NULL);
1080 EXPECT_EQ(2u, offer->contents().size());
1081 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
1082 EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
1083
Steve Anton4e70a722017-11-28 14:57:10 -08001084 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1085 GetMediaDirection(&offer->contents()[0]));
1086 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
1087 GetMediaDirection(&offer->contents()[1]));
jiayl@webrtc.org742922b2014-10-07 21:32:43 +00001088}
1089
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001090// Verifies that the order of the media contents in the current
1091// SessionDescription is preserved in the new SessionDescription.
1092TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
1093 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001094 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001095
kwiberg31022942016-03-11 14:18:21 -08001096 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001097 ASSERT_TRUE(offer1.get() != NULL);
1098 EXPECT_EQ(1u, offer1->contents().size());
1099 EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
1100
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001101 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1102 RtpTransceiverDirection::kRecvOnly, kActive,
1103 &opts);
kwiberg31022942016-03-11 14:18:21 -08001104 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001105 f1_.CreateOffer(opts, offer1.get()));
1106 ASSERT_TRUE(offer2.get() != NULL);
1107 EXPECT_EQ(2u, offer2->contents().size());
1108 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
1109 EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
1110
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001111 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1112 RtpTransceiverDirection::kRecvOnly, kActive,
1113 &opts);
kwiberg31022942016-03-11 14:18:21 -08001114 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001115 f1_.CreateOffer(opts, offer2.get()));
1116 ASSERT_TRUE(offer3.get() != NULL);
1117 EXPECT_EQ(3u, offer3->contents().size());
1118 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[0], MEDIA_TYPE_DATA));
1119 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[1], MEDIA_TYPE_VIDEO));
1120 EXPECT_TRUE(IsMediaContentOfType(&offer3->contents()[2], MEDIA_TYPE_AUDIO));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001121}
1122
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001123// Create a typical audio answer, and ensure it matches what we expect.
1124TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswer) {
1125 f1_.set_secure(SEC_ENABLED);
1126 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001127 std::unique_ptr<SessionDescription> offer =
1128 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001129 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001130 std::unique_ptr<SessionDescription> answer =
1131 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001132 const ContentInfo* ac = answer->GetContentByName("audio");
1133 const ContentInfo* vc = answer->GetContentByName("video");
1134 ASSERT_TRUE(ac != NULL);
1135 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001136 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001137 const AudioContentDescription* acd = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001138 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001139 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001140 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001141 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1142 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001143 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001144 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001145}
1146
jbauchcb560652016-08-04 05:20:32 -07001147// Create a typical audio answer with GCM ciphers enabled, and ensure it
1148// matches what we expect.
1149TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerGcm) {
1150 f1_.set_secure(SEC_ENABLED);
1151 f2_.set_secure(SEC_ENABLED);
zhihuang1c378ed2017-08-17 14:10:50 -07001152 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001153 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001154 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001155 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001156 std::unique_ptr<SessionDescription> answer =
1157 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001158 const ContentInfo* ac = answer->GetContentByName("audio");
1159 const ContentInfo* vc = answer->GetContentByName("video");
1160 ASSERT_TRUE(ac != NULL);
1161 ASSERT_TRUE(vc == NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001162 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001163 const AudioContentDescription* acd = ac->media_description()->as_audio();
jbauchcb560652016-08-04 05:20:32 -07001164 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001165 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001166 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001167 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
1168 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001169 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001170 EXPECT_EQ(cricket::kMediaProtocolSavpf, acd->protocol());
jbauchcb560652016-08-04 05:20:32 -07001171}
1172
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001173// Create a typical video answer, and ensure it matches what we expect.
1174TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
1175 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001176 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001177 f1_.set_secure(SEC_ENABLED);
1178 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001179 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001180 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001181 std::unique_ptr<SessionDescription> answer =
1182 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001183 const ContentInfo* ac = answer->GetContentByName("audio");
1184 const ContentInfo* vc = answer->GetContentByName("video");
1185 ASSERT_TRUE(ac != NULL);
1186 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001187 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1188 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001189 const AudioContentDescription* acd = ac->media_description()->as_audio();
1190 const VideoContentDescription* vcd = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001191 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001192 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001193 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001194 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001195 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001196 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001197 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001198 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
Yves Gerey665174f2018-06-19 15:03:05 +02001199 EXPECT_EQ(0U, vcd->first_ssrc()); // no sender is attached
1200 EXPECT_TRUE(vcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001201 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001202 EXPECT_EQ(cricket::kMediaProtocolSavpf, vcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001203}
1204
jbauchcb560652016-08-04 05:20:32 -07001205// Create a typical video answer with GCM ciphers enabled, and ensure it
1206// matches what we expect.
1207TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcm) {
1208 TestVideoGcmCipher(true, true);
1209}
1210
1211// Create a typical video answer with GCM ciphers enabled for the offer only,
1212// and ensure it matches what we expect.
1213TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmOffer) {
1214 TestVideoGcmCipher(true, false);
1215}
1216
1217// Create a typical video answer with GCM ciphers enabled for the answer only,
1218// and ensure it matches what we expect.
1219TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerGcmAnswer) {
1220 TestVideoGcmCipher(false, true);
1221}
1222
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001223TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001224 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001225 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001226 f1_.set_secure(SEC_ENABLED);
1227 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001228 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001229 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001230 std::unique_ptr<SessionDescription> answer =
1231 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001232 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001233 const ContentInfo* dc = answer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001234 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001235 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001236 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1237 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001238 const AudioContentDescription* acd = ac->media_description()->as_audio();
1239 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001240 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001241 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001242 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001243 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001244 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001245 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
zstein4b2e0822017-02-17 19:48:38 -08001246 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001247 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001248 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001249 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001250 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
Steve Antone38a5a12018-11-21 16:05:15 -08001251 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001252}
1253
jbauchcb560652016-08-04 05:20:32 -07001254TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
zhihuang1c378ed2017-08-17 14:10:50 -07001255 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
Steve Anton4e70a722017-11-28 14:57:10 -08001256 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Benjamin Wrighta54daf12018-10-11 15:33:17 -07001257 opts.crypto_options.srtp.enable_gcm_crypto_suites = true;
jbauchcb560652016-08-04 05:20:32 -07001258 f1_.set_secure(SEC_ENABLED);
1259 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001260 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001261 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001262 std::unique_ptr<SessionDescription> answer =
1263 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauchcb560652016-08-04 05:20:32 -07001264 const ContentInfo* ac = answer->GetContentByName("audio");
zstein4b2e0822017-02-17 19:48:38 -08001265 const ContentInfo* dc = answer->GetContentByName("data");
jbauchcb560652016-08-04 05:20:32 -07001266 ASSERT_TRUE(ac != NULL);
zstein4b2e0822017-02-17 19:48:38 -08001267 ASSERT_TRUE(dc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08001268 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
1269 EXPECT_EQ(MediaProtocolType::kRtp, dc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08001270 const AudioContentDescription* acd = ac->media_description()->as_audio();
1271 const DataContentDescription* dcd = dc->media_description()->as_data();
jbauchcb560652016-08-04 05:20:32 -07001272 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001273 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
jbauchcb560652016-08-04 05:20:32 -07001274 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // negotiated auto bw
zhihuang1c378ed2017-08-17 14:10:50 -07001275 EXPECT_EQ(0U, acd->first_ssrc()); // no sender is attached
jbauchcb560652016-08-04 05:20:32 -07001276 EXPECT_TRUE(acd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001277 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuiteGcm);
zstein4b2e0822017-02-17 19:48:38 -08001278 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08001279 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
zhihuang1c378ed2017-08-17 14:10:50 -07001280 EXPECT_EQ(0U, dcd->first_ssrc()); // no sender is attached
zstein4b2e0822017-02-17 19:48:38 -08001281 EXPECT_TRUE(dcd->rtcp_mux()); // negotiated rtcp-mux
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001282 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuiteGcm);
Steve Antone38a5a12018-11-21 16:05:15 -08001283 EXPECT_EQ(cricket::kMediaProtocolSavpf, dcd->protocol());
zstein4b2e0822017-02-17 19:48:38 -08001284}
1285
1286// The use_sctpmap flag should be set in a DataContentDescription by default.
1287// The answer's use_sctpmap flag should match the offer's.
1288TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
1289 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001290 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001291 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001292 ASSERT_TRUE(offer.get() != NULL);
1293 ContentInfo* dc_offer = offer->GetContentByName("data");
1294 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001295 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001296 EXPECT_TRUE(dcd_offer->use_sctpmap());
1297
Steve Anton6fe1fba2018-12-11 10:15:23 -08001298 std::unique_ptr<SessionDescription> answer =
1299 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001300 const ContentInfo* dc_answer = answer->GetContentByName("data");
1301 ASSERT_TRUE(dc_answer != NULL);
1302 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001303 dc_answer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001304 EXPECT_TRUE(dcd_answer->use_sctpmap());
1305}
1306
1307// The answer's use_sctpmap flag should match the offer's.
1308TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
1309 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001310 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001311 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001312 ASSERT_TRUE(offer.get() != NULL);
1313 ContentInfo* dc_offer = offer->GetContentByName("data");
1314 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001315 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001316 dcd_offer->set_use_sctpmap(false);
1317
Steve Anton6fe1fba2018-12-11 10:15:23 -08001318 std::unique_ptr<SessionDescription> answer =
1319 f2_.CreateAnswer(offer.get(), opts, NULL);
zstein4b2e0822017-02-17 19:48:38 -08001320 const ContentInfo* dc_answer = answer->GetContentByName("data");
1321 ASSERT_TRUE(dc_answer != NULL);
1322 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001323 dc_answer->media_description()->as_data();
zstein4b2e0822017-02-17 19:48:38 -08001324 EXPECT_FALSE(dcd_answer->use_sctpmap());
jbauchcb560652016-08-04 05:20:32 -07001325}
1326
deadbeef8b7e9ad2017-05-25 09:38:55 -07001327// Test that a valid answer will be created for "DTLS/SCTP", "UDP/DTLS/SCTP"
1328// and "TCP/DTLS/SCTP" offers.
1329TEST_F(MediaSessionDescriptionFactoryTest,
1330 TestCreateDataAnswerToDifferentOfferedProtos) {
1331 // Need to enable DTLS offer/answer generation (disabled by default in this
1332 // test).
1333 f1_.set_secure(SEC_ENABLED);
1334 f2_.set_secure(SEC_ENABLED);
1335 tdf1_.set_secure(SEC_ENABLED);
1336 tdf2_.set_secure(SEC_ENABLED);
1337
1338 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001339 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001340 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001341 ASSERT_TRUE(offer.get() != nullptr);
1342 ContentInfo* dc_offer = offer->GetContentByName("data");
1343 ASSERT_TRUE(dc_offer != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08001344 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001345
1346 std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
1347 "TCP/DTLS/SCTP"};
1348 for (const std::string& proto : protos) {
1349 dcd_offer->set_protocol(proto);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001350 std::unique_ptr<SessionDescription> answer =
1351 f2_.CreateAnswer(offer.get(), opts, nullptr);
deadbeef8b7e9ad2017-05-25 09:38:55 -07001352 const ContentInfo* dc_answer = answer->GetContentByName("data");
1353 ASSERT_TRUE(dc_answer != nullptr);
1354 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001355 dc_answer->media_description()->as_data();
deadbeef8b7e9ad2017-05-25 09:38:55 -07001356 EXPECT_FALSE(dc_answer->rejected);
1357 EXPECT_EQ(proto, dcd_answer->protocol());
1358 }
1359}
1360
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001361// Verifies that the order of the media contents in the offer is preserved in
1362// the answer.
1363TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
1364 MediaSessionOptions opts;
1365
1366 // Creates a data only offer.
Steve Anton4e70a722017-11-28 14:57:10 -08001367 AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
kwiberg31022942016-03-11 14:18:21 -08001368 std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001369 ASSERT_TRUE(offer1.get() != NULL);
1370
1371 // Appends audio to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001372 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1373 RtpTransceiverDirection::kRecvOnly, kActive,
1374 &opts);
kwiberg31022942016-03-11 14:18:21 -08001375 std::unique_ptr<SessionDescription> offer2(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001376 f1_.CreateOffer(opts, offer1.get()));
1377 ASSERT_TRUE(offer2.get() != NULL);
1378
1379 // Appends video to the offer.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001380 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1381 RtpTransceiverDirection::kRecvOnly, kActive,
1382 &opts);
kwiberg31022942016-03-11 14:18:21 -08001383 std::unique_ptr<SessionDescription> offer3(
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001384 f1_.CreateOffer(opts, offer2.get()));
1385 ASSERT_TRUE(offer3.get() != NULL);
1386
Steve Anton6fe1fba2018-12-11 10:15:23 -08001387 std::unique_ptr<SessionDescription> answer =
1388 f2_.CreateAnswer(offer3.get(), opts, NULL);
jiayl@webrtc.orge7d47a12014-08-05 19:19:05 +00001389 ASSERT_TRUE(answer.get() != NULL);
1390 EXPECT_EQ(3u, answer->contents().size());
1391 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[0], MEDIA_TYPE_DATA));
1392 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[1], MEDIA_TYPE_AUDIO));
1393 EXPECT_TRUE(IsMediaContentOfType(&answer->contents()[2], MEDIA_TYPE_VIDEO));
1394}
1395
ossu075af922016-06-14 03:29:38 -07001396// TODO(deadbeef): Extend these tests to ensure the correct direction with other
1397// answerer settings.
1398
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001399// This test that the media direction is set to send/receive in an answer if
1400// the offer is send receive.
1401TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001402 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
1403 RtpTransceiverDirection::kSendRecv);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001404}
1405
1406// This test that the media direction is set to receive only in an answer if
1407// the offer is send only.
1408TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001409 TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
1410 RtpTransceiverDirection::kRecvOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001411}
1412
1413// This test that the media direction is set to send only in an answer if
1414// the offer is recv only.
1415TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001416 TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
1417 RtpTransceiverDirection::kSendOnly);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001418}
1419
1420// This test that the media direction is set to inactive in an answer if
1421// the offer is inactive.
1422TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
Steve Anton4e70a722017-11-28 14:57:10 -08001423 TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
1424 RtpTransceiverDirection::kInactive);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001425}
1426
1427// Test that a data content with an unknown protocol is rejected in an answer.
1428TEST_F(MediaSessionDescriptionFactoryTest,
1429 CreateDataAnswerToOfferWithUnknownProtocol) {
1430 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001431 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001432 f1_.set_secure(SEC_ENABLED);
1433 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001434 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
terelius8c011e52016-04-26 05:28:11 -07001435 ContentInfo* dc_offer = offer->GetContentByName("data");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001436 ASSERT_TRUE(dc_offer != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001437 DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001438 ASSERT_TRUE(dcd_offer != NULL);
1439 std::string protocol = "a weird unknown protocol";
1440 dcd_offer->set_protocol(protocol);
1441
Steve Anton6fe1fba2018-12-11 10:15:23 -08001442 std::unique_ptr<SessionDescription> answer =
1443 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001444
1445 const ContentInfo* dc_answer = answer->GetContentByName("data");
1446 ASSERT_TRUE(dc_answer != NULL);
1447 EXPECT_TRUE(dc_answer->rejected);
1448 const DataContentDescription* dcd_answer =
Steve Antonb1c1de12017-12-21 15:14:30 -08001449 dc_answer->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001450 ASSERT_TRUE(dcd_answer != NULL);
1451 EXPECT_EQ(protocol, dcd_answer->protocol());
1452}
1453
1454// Test that the media protocol is RTP/AVPF if DTLS and SDES are disabled.
1455TEST_F(MediaSessionDescriptionFactoryTest, AudioOfferAnswerWithCryptoDisabled) {
zhihuang1c378ed2017-08-17 14:10:50 -07001456 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001457 f1_.set_secure(SEC_DISABLED);
1458 f2_.set_secure(SEC_DISABLED);
1459 tdf1_.set_secure(SEC_DISABLED);
1460 tdf2_.set_secure(SEC_DISABLED);
1461
Steve Anton6fe1fba2018-12-11 10:15:23 -08001462 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001463 const AudioContentDescription* offer_acd =
1464 GetFirstAudioContentDescription(offer.get());
1465 ASSERT_TRUE(offer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001466 EXPECT_EQ(cricket::kMediaProtocolAvpf, offer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001467
Steve Anton6fe1fba2018-12-11 10:15:23 -08001468 std::unique_ptr<SessionDescription> answer =
1469 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001470
1471 const ContentInfo* ac_answer = answer->GetContentByName("audio");
1472 ASSERT_TRUE(ac_answer != NULL);
1473 EXPECT_FALSE(ac_answer->rejected);
1474
1475 const AudioContentDescription* answer_acd =
1476 GetFirstAudioContentDescription(answer.get());
1477 ASSERT_TRUE(answer_acd != NULL);
Steve Antone38a5a12018-11-21 16:05:15 -08001478 EXPECT_EQ(cricket::kMediaProtocolAvpf, answer_acd->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001479}
1480
1481// Create a video offer and answer and ensure the RTP header extensions
1482// matches what we expect.
1483TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
1484 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001485 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001486 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1487 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1488 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1489 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
1490
Steve Anton6fe1fba2018-12-11 10:15:23 -08001491 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001492 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001493 std::unique_ptr<SessionDescription> answer =
1494 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001495
Yves Gerey665174f2018-06-19 15:03:05 +02001496 EXPECT_EQ(
1497 MAKE_VECTOR(kAudioRtpExtension1),
1498 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1499 EXPECT_EQ(
1500 MAKE_VECTOR(kVideoRtpExtension1),
1501 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1502 EXPECT_EQ(
1503 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1504 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1505 EXPECT_EQ(
1506 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1507 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001508}
1509
jbauch5869f502017-06-29 12:31:36 -07001510TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001511 TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
jbauch5869f502017-06-29 12:31:36 -07001512 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001513 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001514
1515 f1_.set_enable_encrypted_rtp_header_extensions(true);
1516 f2_.set_enable_encrypted_rtp_header_extensions(true);
1517
Yves Gerey665174f2018-06-19 15:03:05 +02001518 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1519 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1520 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1521 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001522
Steve Anton6fe1fba2018-12-11 10:15:23 -08001523 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001524 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001525 std::unique_ptr<SessionDescription> answer =
1526 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001527
Yves Gerey665174f2018-06-19 15:03:05 +02001528 EXPECT_EQ(
1529 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1530 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1531 EXPECT_EQ(
1532 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1533 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1534 EXPECT_EQ(
1535 MAKE_VECTOR(kAudioRtpExtensionEncryptedAnswer),
1536 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1537 EXPECT_EQ(
1538 MAKE_VECTOR(kVideoRtpExtensionEncryptedAnswer),
1539 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001540}
1541
1542TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001543 TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
jbauch5869f502017-06-29 12:31:36 -07001544 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001545 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001546
1547 f1_.set_enable_encrypted_rtp_header_extensions(true);
1548
Yves Gerey665174f2018-06-19 15:03:05 +02001549 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1550 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1551 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1552 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001553
Steve Anton6fe1fba2018-12-11 10:15:23 -08001554 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001555 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001556 std::unique_ptr<SessionDescription> answer =
1557 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001558
Yves Gerey665174f2018-06-19 15:03:05 +02001559 EXPECT_EQ(
1560 MAKE_VECTOR(kAudioRtpExtensionEncrypted1),
1561 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1562 EXPECT_EQ(
1563 MAKE_VECTOR(kVideoRtpExtensionEncrypted1),
1564 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1565 EXPECT_EQ(
1566 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1567 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1568 EXPECT_EQ(
1569 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1570 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001571}
1572
1573TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02001574 TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
jbauch5869f502017-06-29 12:31:36 -07001575 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001576 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07001577
1578 f2_.set_enable_encrypted_rtp_header_extensions(true);
1579
Yves Gerey665174f2018-06-19 15:03:05 +02001580 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
1581 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
1582 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
1583 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
jbauch5869f502017-06-29 12:31:36 -07001584
Steve Anton6fe1fba2018-12-11 10:15:23 -08001585 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001586 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001587 std::unique_ptr<SessionDescription> answer =
1588 f2_.CreateAnswer(offer.get(), opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07001589
Yves Gerey665174f2018-06-19 15:03:05 +02001590 EXPECT_EQ(
1591 MAKE_VECTOR(kAudioRtpExtension1),
1592 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
1593 EXPECT_EQ(
1594 MAKE_VECTOR(kVideoRtpExtension1),
1595 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
1596 EXPECT_EQ(
1597 MAKE_VECTOR(kAudioRtpExtensionAnswer),
1598 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
1599 EXPECT_EQ(
1600 MAKE_VECTOR(kVideoRtpExtensionAnswer),
1601 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07001602}
1603
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001604// Create an audio, video, data answer without legacy StreamParams.
1605TEST_F(MediaSessionDescriptionFactoryTest,
1606 TestCreateAnswerWithoutLegacyStreams) {
1607 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001608 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1609 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001610 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001611 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001612 std::unique_ptr<SessionDescription> answer =
1613 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001614 const ContentInfo* ac = answer->GetContentByName("audio");
1615 const ContentInfo* vc = answer->GetContentByName("video");
1616 const ContentInfo* dc = answer->GetContentByName("data");
1617 ASSERT_TRUE(ac != NULL);
1618 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001619 const AudioContentDescription* acd = ac->media_description()->as_audio();
1620 const VideoContentDescription* vcd = vc->media_description()->as_video();
1621 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001622
1623 EXPECT_FALSE(acd->has_ssrcs()); // No StreamParams.
1624 EXPECT_FALSE(vcd->has_ssrcs()); // No StreamParams.
1625 EXPECT_FALSE(dcd->has_ssrcs()); // No StreamParams.
1626}
1627
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001628// Create a typical video answer, and ensure it matches what we expect.
1629TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
1630 MediaSessionOptions offer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001631 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
1632 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1633 &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001634
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001635 MediaSessionOptions answer_opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001636 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
1637 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
1638 &answer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001639
kwiberg31022942016-03-11 14:18:21 -08001640 std::unique_ptr<SessionDescription> offer;
1641 std::unique_ptr<SessionDescription> answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001642
1643 offer_opts.rtcp_mux_enabled = true;
1644 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001645 offer = f1_.CreateOffer(offer_opts, NULL);
1646 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001647 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1648 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1649 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1650 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1651 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1652 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1653 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1654 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1655 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1656 EXPECT_TRUE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1657 EXPECT_TRUE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1658 EXPECT_TRUE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1659
1660 offer_opts.rtcp_mux_enabled = true;
1661 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001662 offer = f1_.CreateOffer(offer_opts, NULL);
1663 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001664 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1665 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1666 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1667 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1668 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1669 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1670 EXPECT_TRUE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1671 EXPECT_TRUE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1672 EXPECT_TRUE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1673 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1674 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1675 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1676
1677 offer_opts.rtcp_mux_enabled = false;
1678 answer_opts.rtcp_mux_enabled = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001679 offer = f1_.CreateOffer(offer_opts, NULL);
1680 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001681 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1682 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1683 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1684 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1685 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1686 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1687 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1688 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1689 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1690 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1691 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1692 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1693
1694 offer_opts.rtcp_mux_enabled = false;
1695 answer_opts.rtcp_mux_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001696 offer = f1_.CreateOffer(offer_opts, NULL);
1697 answer = f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001698 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(offer.get()));
1699 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(offer.get()));
1700 ASSERT_TRUE(NULL != GetFirstDataContentDescription(offer.get()));
1701 ASSERT_TRUE(NULL != GetFirstAudioContentDescription(answer.get()));
1702 ASSERT_TRUE(NULL != GetFirstVideoContentDescription(answer.get()));
1703 ASSERT_TRUE(NULL != GetFirstDataContentDescription(answer.get()));
1704 EXPECT_FALSE(GetFirstAudioContentDescription(offer.get())->rtcp_mux());
1705 EXPECT_FALSE(GetFirstVideoContentDescription(offer.get())->rtcp_mux());
1706 EXPECT_FALSE(GetFirstDataContentDescription(offer.get())->rtcp_mux());
1707 EXPECT_FALSE(GetFirstAudioContentDescription(answer.get())->rtcp_mux());
1708 EXPECT_FALSE(GetFirstVideoContentDescription(answer.get())->rtcp_mux());
1709 EXPECT_FALSE(GetFirstDataContentDescription(answer.get())->rtcp_mux());
1710}
1711
1712// Create an audio-only answer to a video offer.
1713TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
1714 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001715 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
1716 RtpTransceiverDirection::kRecvOnly, kActive,
1717 &opts);
1718 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
1719 RtpTransceiverDirection::kRecvOnly, kActive,
1720 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001721 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001722 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001723
1724 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001725 std::unique_ptr<SessionDescription> answer =
1726 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001727 const ContentInfo* ac = answer->GetContentByName("audio");
1728 const ContentInfo* vc = answer->GetContentByName("video");
1729 ASSERT_TRUE(ac != NULL);
1730 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001731 ASSERT_TRUE(vc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001732 EXPECT_TRUE(vc->rejected);
1733}
1734
1735// Create an audio-only answer to an offer with data.
1736TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07001737 MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001738 opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001739 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
1740 RtpTransceiverDirection::kRecvOnly, kActive,
1741 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001742 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001743 ASSERT_TRUE(offer.get() != NULL);
zhihuang1c378ed2017-08-17 14:10:50 -07001744
1745 opts.media_description_options[1].stopped = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001746 std::unique_ptr<SessionDescription> answer =
1747 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001748 const ContentInfo* ac = answer->GetContentByName("audio");
1749 const ContentInfo* dc = answer->GetContentByName("data");
1750 ASSERT_TRUE(ac != NULL);
1751 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001752 ASSERT_TRUE(dc->media_description() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001753 EXPECT_TRUE(dc->rejected);
1754}
1755
1756// Create an answer that rejects the contents which are rejected in the offer.
1757TEST_F(MediaSessionDescriptionFactoryTest,
1758 CreateAnswerToOfferWithRejectedMedia) {
1759 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001760 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
1761 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001762 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001763 ASSERT_TRUE(offer.get() != NULL);
1764 ContentInfo* ac = offer->GetContentByName("audio");
1765 ContentInfo* vc = offer->GetContentByName("video");
1766 ContentInfo* dc = offer->GetContentByName("data");
1767 ASSERT_TRUE(ac != NULL);
1768 ASSERT_TRUE(vc != NULL);
1769 ASSERT_TRUE(dc != NULL);
1770 ac->rejected = true;
1771 vc->rejected = true;
1772 dc->rejected = true;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001773 std::unique_ptr<SessionDescription> answer =
1774 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001775 ac = answer->GetContentByName("audio");
1776 vc = answer->GetContentByName("video");
1777 dc = answer->GetContentByName("data");
1778 ASSERT_TRUE(ac != NULL);
1779 ASSERT_TRUE(vc != NULL);
1780 ASSERT_TRUE(dc != NULL);
1781 EXPECT_TRUE(ac->rejected);
1782 EXPECT_TRUE(vc->rejected);
1783 EXPECT_TRUE(dc->rejected);
1784}
1785
Johannes Kron0854eb62018-10-10 22:33:20 +02001786TEST_F(MediaSessionDescriptionFactoryTest,
1787 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensions) {
1788 MediaSessionOptions opts;
Steve Anton6fe1fba2018-12-11 10:15:23 -08001789 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02001790 // Offer without request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001791 offer->set_extmap_allow_mixed(false);
Johannes Kron0854eb62018-10-10 22:33:20 +02001792 ASSERT_TRUE(offer.get() != NULL);
1793 std::unique_ptr<SessionDescription> answer_no_support(
1794 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001795 EXPECT_FALSE(answer_no_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001796
1797 // Offer with request of mixed one- and two-byte header extensions.
Johannes Kron9581bc42018-10-23 10:17:39 +02001798 offer->set_extmap_allow_mixed(true);
Johannes Kron0854eb62018-10-10 22:33:20 +02001799 ASSERT_TRUE(offer.get() != NULL);
1800 std::unique_ptr<SessionDescription> answer_support(
1801 f2_.CreateAnswer(offer.get(), opts, NULL));
Johannes Kron9581bc42018-10-23 10:17:39 +02001802 EXPECT_TRUE(answer_support->extmap_allow_mixed());
Johannes Kron0854eb62018-10-10 22:33:20 +02001803}
1804
1805TEST_F(MediaSessionDescriptionFactoryTest,
1806 CreateAnswerSupportsMixedOneAndTwoByteHeaderExtensionsOnMediaLevel) {
1807 MediaSessionOptions opts;
1808 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001809 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Johannes Kron0854eb62018-10-10 22:33:20 +02001810 MediaContentDescription* video_offer =
1811 offer->GetContentDescriptionByName("video");
1812 ASSERT_TRUE(video_offer);
1813 MediaContentDescription* audio_offer =
1814 offer->GetContentDescriptionByName("audio");
1815 ASSERT_TRUE(audio_offer);
1816
1817 // Explicit disable of mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001818 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
1819 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kNo);
Johannes Kron0854eb62018-10-10 22:33:20 +02001820
1821 ASSERT_TRUE(offer.get() != NULL);
1822 std::unique_ptr<SessionDescription> answer_no_support(
1823 f2_.CreateAnswer(offer.get(), opts, NULL));
1824 MediaContentDescription* video_answer =
1825 answer_no_support->GetContentDescriptionByName("video");
1826 MediaContentDescription* audio_answer =
1827 answer_no_support->GetContentDescriptionByName("audio");
1828 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001829 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001830 EXPECT_EQ(MediaContentDescription::kNo,
Johannes Kron9581bc42018-10-23 10:17:39 +02001831 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001832
1833 // Enable mixed one-two byte header support in offer.
Johannes Kron9581bc42018-10-23 10:17:39 +02001834 video_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
1835 audio_offer->set_extmap_allow_mixed_enum(MediaContentDescription::kMedia);
Johannes Kron0854eb62018-10-10 22:33:20 +02001836 ASSERT_TRUE(offer.get() != NULL);
1837 std::unique_ptr<SessionDescription> answer_support(
1838 f2_.CreateAnswer(offer.get(), opts, NULL));
1839 video_answer = answer_support->GetContentDescriptionByName("video");
1840 audio_answer = answer_support->GetContentDescriptionByName("audio");
1841 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02001842 video_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001843 EXPECT_EQ(MediaContentDescription::kMedia,
Johannes Kron9581bc42018-10-23 10:17:39 +02001844 audio_answer->extmap_allow_mixed_enum());
Johannes Kron0854eb62018-10-10 22:33:20 +02001845}
1846
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001847// Create an audio and video offer with:
1848// - one video track
1849// - two audio tracks
1850// - two data tracks
1851// and ensure it matches what we expect. Also updates the initial offer by
1852// adding a new video track and replaces one of the audio tracks.
1853TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
1854 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08001855 AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001856 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
1857 {kMediaStream1}, 1, &opts);
1858 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
1859 {kMediaStream1}, 1, &opts);
1860 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
1861 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001862
Steve Anton4e70a722017-11-28 14:57:10 -08001863 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001864 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
1865 {kMediaStream1}, 1, &opts);
1866 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
1867 {kMediaStream1}, 1, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001868
1869 f1_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08001870 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001871
1872 ASSERT_TRUE(offer.get() != NULL);
1873 const ContentInfo* ac = offer->GetContentByName("audio");
1874 const ContentInfo* vc = offer->GetContentByName("video");
1875 const ContentInfo* dc = offer->GetContentByName("data");
1876 ASSERT_TRUE(ac != NULL);
1877 ASSERT_TRUE(vc != NULL);
1878 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08001879 const AudioContentDescription* acd = ac->media_description()->as_audio();
1880 const VideoContentDescription* vcd = vc->media_description()->as_video();
1881 const DataContentDescription* dcd = dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001882 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
ossudedfd282016-06-14 07:12:39 -07001883 EXPECT_EQ(f1_.audio_sendrecv_codecs(), acd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001884
1885 const StreamParamsVec& audio_streams = acd->streams();
1886 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001887 EXPECT_EQ(audio_streams[0].cname, audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001888 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
1889 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
1890 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
1891 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
1892 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
1893 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
1894
1895 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
1896 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001897 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001898
1899 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
1900 EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001901 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001902
1903 const StreamParamsVec& video_streams = vcd->streams();
1904 ASSERT_EQ(1U, video_streams.size());
1905 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
1906 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
1907 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
1908 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
1909
1910 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
1911 EXPECT_EQ(f1_.data_codecs(), dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001912 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001913
1914 const StreamParamsVec& data_streams = dcd->streams();
1915 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02001916 EXPECT_EQ(data_streams[0].cname, data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001917 EXPECT_EQ(kDataTrack1, data_streams[0].id);
1918 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
1919 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
1920 EXPECT_EQ(kDataTrack2, data_streams[1].id);
1921 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
1922 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
1923
1924 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02001925 dcd->bandwidth()); // default bandwidth (auto)
1926 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001927 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001928
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001929 // Update the offer. Add a new video track that is not synched to the
1930 // other tracks and replace audio track 2 with audio track 3.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001931 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
1932 {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001933 DetachSenderFromMediaSection("audio", kAudioTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001934 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack3,
1935 {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07001936 DetachSenderFromMediaSection("data", kDataTrack2, &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08001937 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack3,
1938 {kMediaStream1}, 1, &opts);
kwiberg31022942016-03-11 14:18:21 -08001939 std::unique_ptr<SessionDescription> updated_offer(
1940 f1_.CreateOffer(opts, offer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001941
1942 ASSERT_TRUE(updated_offer.get() != NULL);
1943 ac = updated_offer->GetContentByName("audio");
1944 vc = updated_offer->GetContentByName("video");
1945 dc = updated_offer->GetContentByName("data");
1946 ASSERT_TRUE(ac != NULL);
1947 ASSERT_TRUE(vc != NULL);
1948 ASSERT_TRUE(dc != NULL);
1949 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001950 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001951 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001952 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001953 const DataContentDescription* updated_dcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08001954 dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001955
1956 EXPECT_EQ(acd->type(), updated_acd->type());
1957 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
1958 EXPECT_EQ(vcd->type(), updated_vcd->type());
1959 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
1960 EXPECT_EQ(dcd->type(), updated_dcd->type());
1961 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001962 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001963 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001964 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001965 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07001966 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001967 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
1968
1969 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
1970 ASSERT_EQ(2U, updated_audio_streams.size());
1971 EXPECT_EQ(audio_streams[0], updated_audio_streams[0]);
1972 EXPECT_EQ(kAudioTrack3, updated_audio_streams[1].id); // New audio track.
1973 ASSERT_EQ(1U, updated_audio_streams[1].ssrcs.size());
1974 EXPECT_NE(0U, updated_audio_streams[1].ssrcs[0]);
1975 EXPECT_EQ(updated_audio_streams[0].cname, updated_audio_streams[1].cname);
1976
1977 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
1978 ASSERT_EQ(2U, updated_video_streams.size());
1979 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
1980 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07001981 // All the media streams in one PeerConnection share one RTCP CNAME.
1982 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001983
1984 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
1985 ASSERT_EQ(2U, updated_data_streams.size());
1986 EXPECT_EQ(data_streams[0], updated_data_streams[0]);
1987 EXPECT_EQ(kDataTrack3, updated_data_streams[1].id); // New data track.
1988 ASSERT_EQ(1U, updated_data_streams[1].ssrcs.size());
1989 EXPECT_NE(0U, updated_data_streams[1].ssrcs[0]);
1990 EXPECT_EQ(updated_data_streams[0].cname, updated_data_streams[1].cname);
zhihuang8f65cdf2016-05-06 18:40:30 -07001991 // The stream correctly got the CNAME from the MediaSessionOptions.
1992 // The Expected RTCP CNAME is the default one as we are using the default
1993 // MediaSessionOptions.
1994 EXPECT_EQ(updated_data_streams[0].cname, cricket::kDefaultRtcpCname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001995}
1996
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00001997// Create an offer with simulcast video stream.
1998TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
1999 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002000 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2001 RtpTransceiverDirection::kRecvOnly, kActive,
2002 &opts);
2003 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2004 RtpTransceiverDirection::kSendRecv, kActive,
2005 &opts);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002006 const int num_sim_layers = 3;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002007 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2008 {kMediaStream1}, num_sim_layers, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002009 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002010
2011 ASSERT_TRUE(offer.get() != NULL);
2012 const ContentInfo* vc = offer->GetContentByName("video");
2013 ASSERT_TRUE(vc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002014 const VideoContentDescription* vcd = vc->media_description()->as_video();
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002015
2016 const StreamParamsVec& video_streams = vcd->streams();
2017 ASSERT_EQ(1U, video_streams.size());
2018 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2019 const SsrcGroup* sim_ssrc_group =
2020 video_streams[0].get_ssrc_group(cricket::kSimSsrcGroupSemantics);
2021 ASSERT_TRUE(sim_ssrc_group != NULL);
2022 EXPECT_EQ(static_cast<size_t>(num_sim_layers), sim_ssrc_group->ssrcs.size());
2023}
2024
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002025MATCHER(RidDescriptionEquals, "Verifies that two RidDescriptions are equal.") {
2026 const RidDescription& rid1 = ::testing::get<0>(arg);
2027 const RidDescription& rid2 = ::testing::get<1>(arg);
2028 return rid1.rid == rid2.rid && rid1.direction == rid2.direction;
2029}
2030
2031static void CheckSimulcastInSessionDescription(
2032 const SessionDescription* description,
2033 const std::string& content_name,
2034 const std::vector<RidDescription>& send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002035 const SimulcastLayerList& send_layers) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002036 ASSERT_NE(description, nullptr);
2037 const ContentInfo* content = description->GetContentByName(content_name);
2038 ASSERT_NE(content, nullptr);
2039 const MediaContentDescription* cd = content->media_description();
2040 ASSERT_NE(cd, nullptr);
2041 const StreamParamsVec& streams = cd->streams();
2042 ASSERT_THAT(streams, SizeIs(1));
2043 const StreamParams& stream = streams[0];
2044 ASSERT_THAT(stream.ssrcs, IsEmpty());
2045 EXPECT_TRUE(stream.has_rids());
2046 const std::vector<RidDescription> rids = stream.rids();
2047
2048 EXPECT_THAT(rids, Pointwise(RidDescriptionEquals(), send_rids));
2049
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002050 EXPECT_TRUE(cd->HasSimulcast());
2051 const SimulcastDescription& simulcast = cd->simulcast_description();
2052 EXPECT_THAT(simulcast.send_layers(), SizeIs(send_layers.size()));
2053 EXPECT_THAT(simulcast.send_layers(), Pointwise(Eq(), send_layers));
2054
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002055 ASSERT_THAT(simulcast.receive_layers().GetAllLayers(), SizeIs(0));
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002056}
2057
2058// Create an offer with spec-compliant simulcast video stream.
2059TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastOffer) {
2060 MediaSessionOptions opts;
2061 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2062 RtpTransceiverDirection::kSendRecv, kActive,
2063 &opts);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002064 std::vector<RidDescription> send_rids;
2065 send_rids.push_back(RidDescription("f", RidDirection::kSend));
2066 send_rids.push_back(RidDescription("h", RidDirection::kSend));
2067 send_rids.push_back(RidDescription("q", RidDirection::kSend));
2068 SimulcastLayerList simulcast_layers;
2069 simulcast_layers.AddLayer(SimulcastLayer(send_rids[0].rid, false));
2070 simulcast_layers.AddLayer(SimulcastLayer(send_rids[1].rid, true));
2071 simulcast_layers.AddLayer(SimulcastLayer(send_rids[2].rid, false));
2072 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2073 {kMediaStream1}, send_rids,
2074 simulcast_layers, 0, &opts);
2075 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2076
2077 CheckSimulcastInSessionDescription(offer.get(), "video", send_rids,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002078 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002079}
2080
2081// Create an offer that signals RIDs (not SSRCs) without Simulcast.
2082// In this scenario, RIDs do not need to be negotiated (there is only one).
2083TEST_F(MediaSessionDescriptionFactoryTest, TestOfferWithRidsNoSimulcast) {
2084 MediaSessionOptions opts;
2085 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2086 RtpTransceiverDirection::kSendRecv, kActive,
2087 &opts);
2088 RidDescription rid("f", RidDirection::kSend);
2089 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2090 {kMediaStream1}, {rid},
2091 SimulcastLayerList(), 0, &opts);
2092 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2093
2094 ASSERT_NE(offer.get(), nullptr);
2095 const ContentInfo* content = offer->GetContentByName("video");
2096 ASSERT_NE(content, nullptr);
2097 const MediaContentDescription* cd = content->media_description();
2098 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002099 const StreamParamsVec& streams = cd->streams();
2100 ASSERT_THAT(streams, SizeIs(1));
2101 const StreamParams& stream = streams[0];
2102 ASSERT_THAT(stream.ssrcs, IsEmpty());
2103 EXPECT_FALSE(stream.has_rids());
2104 EXPECT_FALSE(cd->HasSimulcast());
2105}
2106
2107// Create an answer with spec-compliant simulcast video stream.
2108// In this scenario, the SFU is the caller requesting that we send Simulcast.
2109TEST_F(MediaSessionDescriptionFactoryTest, TestCreateCompliantSimulcastAnswer) {
2110 MediaSessionOptions offer_opts;
2111 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2112 RtpTransceiverDirection::kSendRecv, kActive,
2113 &offer_opts);
2114 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2115 {kMediaStream1}, 1, &offer_opts);
2116 std::unique_ptr<SessionDescription> offer =
2117 f1_.CreateOffer(offer_opts, nullptr);
2118
2119 MediaSessionOptions answer_opts;
2120 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2121 RtpTransceiverDirection::kSendRecv, kActive,
2122 &answer_opts);
2123
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002124 std::vector<RidDescription> rid_descriptions{
2125 RidDescription("f", RidDirection::kSend),
2126 RidDescription("h", RidDirection::kSend),
2127 RidDescription("q", RidDirection::kSend),
2128 };
2129 SimulcastLayerList simulcast_layers;
2130 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[0].rid, false));
2131 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[1].rid, true));
2132 simulcast_layers.AddLayer(SimulcastLayer(rid_descriptions[2].rid, false));
2133 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2134 {kMediaStream1}, rid_descriptions,
2135 simulcast_layers, 0, &answer_opts);
2136 std::unique_ptr<SessionDescription> answer =
2137 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2138
2139 CheckSimulcastInSessionDescription(answer.get(), "video", rid_descriptions,
Amit Hilbuchb7446ed2019-01-28 12:25:25 -08002140 simulcast_layers);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002141}
2142
2143// Create an answer that signals RIDs (not SSRCs) without Simulcast.
2144// In this scenario, RIDs do not need to be negotiated (there is only one).
2145// Note that RID Direction is not the same as the transceiver direction.
2146TEST_F(MediaSessionDescriptionFactoryTest, TestAnswerWithRidsNoSimulcast) {
2147 MediaSessionOptions offer_opts;
2148 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2149 RtpTransceiverDirection::kSendRecv, kActive,
2150 &offer_opts);
2151 RidDescription rid_offer("f", RidDirection::kSend);
2152 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2153 {kMediaStream1}, {rid_offer},
2154 SimulcastLayerList(), 0, &offer_opts);
2155 std::unique_ptr<SessionDescription> offer =
2156 f1_.CreateOffer(offer_opts, nullptr);
2157
2158 MediaSessionOptions answer_opts;
2159 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2160 RtpTransceiverDirection::kSendRecv, kActive,
2161 &answer_opts);
2162
2163 RidDescription rid_answer("f", RidDirection::kReceive);
2164 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2165 {kMediaStream1}, {rid_answer},
2166 SimulcastLayerList(), 0, &answer_opts);
2167 std::unique_ptr<SessionDescription> answer =
2168 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
2169
2170 ASSERT_NE(answer.get(), nullptr);
2171 const ContentInfo* content = offer->GetContentByName("video");
2172 ASSERT_NE(content, nullptr);
2173 const MediaContentDescription* cd = content->media_description();
2174 ASSERT_NE(cd, nullptr);
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002175 const StreamParamsVec& streams = cd->streams();
2176 ASSERT_THAT(streams, SizeIs(1));
2177 const StreamParams& stream = streams[0];
2178 ASSERT_THAT(stream.ssrcs, IsEmpty());
2179 EXPECT_FALSE(stream.has_rids());
2180 EXPECT_FALSE(cd->HasSimulcast());
2181}
2182
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002183// Create an audio and video answer to a standard video offer with:
2184// - one video track
2185// - two audio tracks
2186// - two data tracks
2187// and ensure it matches what we expect. Also updates the initial answer by
2188// adding a new video track and removes one of the audio tracks.
2189TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
2190 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002191 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2192 RtpTransceiverDirection::kRecvOnly, kActive,
2193 &offer_opts);
2194 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2195 RtpTransceiverDirection::kRecvOnly, kActive,
2196 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002197 offer_opts.data_channel_type = cricket::DCT_RTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002198 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2199 RtpTransceiverDirection::kRecvOnly, kActive,
2200 &offer_opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002201 f1_.set_secure(SEC_ENABLED);
2202 f2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002203 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(offer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002204
zhihuang1c378ed2017-08-17 14:10:50 -07002205 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002206 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2207 RtpTransceiverDirection::kSendRecv, kActive,
2208 &answer_opts);
2209 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2210 RtpTransceiverDirection::kSendRecv, kActive,
2211 &answer_opts);
2212 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
2213 {kMediaStream1}, 1, &answer_opts);
2214 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
2215 {kMediaStream1}, 1, &answer_opts);
2216 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
2217 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002218
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002219 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data",
2220 RtpTransceiverDirection::kSendRecv, kActive,
2221 &answer_opts);
2222 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack1,
2223 {kMediaStream1}, 1, &answer_opts);
2224 AttachSenderToMediaDescriptionOptions("data", MEDIA_TYPE_DATA, kDataTrack2,
2225 {kMediaStream1}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002226 answer_opts.data_channel_type = cricket::DCT_RTP;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002227
Steve Anton6fe1fba2018-12-11 10:15:23 -08002228 std::unique_ptr<SessionDescription> answer =
2229 f2_.CreateAnswer(offer.get(), answer_opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002230
2231 ASSERT_TRUE(answer.get() != NULL);
2232 const ContentInfo* ac = answer->GetContentByName("audio");
2233 const ContentInfo* vc = answer->GetContentByName("video");
2234 const ContentInfo* dc = answer->GetContentByName("data");
2235 ASSERT_TRUE(ac != NULL);
2236 ASSERT_TRUE(vc != NULL);
2237 ASSERT_TRUE(dc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002238 const AudioContentDescription* acd = ac->media_description()->as_audio();
2239 const VideoContentDescription* vcd = vc->media_description()->as_video();
2240 const DataContentDescription* dcd = dc->media_description()->as_data();
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002241 ASSERT_CRYPTO(acd, 1U, kDefaultSrtpCryptoSuite);
2242 ASSERT_CRYPTO(vcd, 1U, kDefaultSrtpCryptoSuite);
2243 ASSERT_CRYPTO(dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002244
2245 EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002246 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002247
2248 const StreamParamsVec& audio_streams = acd->streams();
2249 ASSERT_EQ(2U, audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002250 EXPECT_TRUE(audio_streams[0].cname == audio_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002251 EXPECT_EQ(kAudioTrack1, audio_streams[0].id);
2252 ASSERT_EQ(1U, audio_streams[0].ssrcs.size());
2253 EXPECT_NE(0U, audio_streams[0].ssrcs[0]);
2254 EXPECT_EQ(kAudioTrack2, audio_streams[1].id);
2255 ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
2256 EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
2257
2258 EXPECT_EQ(kAutoBandwidth, acd->bandwidth()); // default bandwidth (auto)
2259 EXPECT_TRUE(acd->rtcp_mux()); // rtcp-mux defaults on
2260
2261 EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002262 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002263
2264 const StreamParamsVec& video_streams = vcd->streams();
2265 ASSERT_EQ(1U, video_streams.size());
2266 EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
2267 EXPECT_EQ(kVideoTrack1, video_streams[0].id);
2268 EXPECT_EQ(kAutoBandwidth, vcd->bandwidth()); // default bandwidth (auto)
2269 EXPECT_TRUE(vcd->rtcp_mux()); // rtcp-mux defaults on
2270
2271 EXPECT_EQ(MEDIA_TYPE_DATA, dcd->type());
Steve Antone38a5a12018-11-21 16:05:15 -08002272 EXPECT_THAT(dcd->codecs(), ElementsAreArray(kDataCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002273
2274 const StreamParamsVec& data_streams = dcd->streams();
2275 ASSERT_EQ(2U, data_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002276 EXPECT_TRUE(data_streams[0].cname == data_streams[1].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002277 EXPECT_EQ(kDataTrack1, data_streams[0].id);
2278 ASSERT_EQ(1U, data_streams[0].ssrcs.size());
2279 EXPECT_NE(0U, data_streams[0].ssrcs[0]);
2280 EXPECT_EQ(kDataTrack2, data_streams[1].id);
2281 ASSERT_EQ(1U, data_streams[1].ssrcs.size());
2282 EXPECT_NE(0U, data_streams[1].ssrcs[0]);
2283
2284 EXPECT_EQ(cricket::kDataMaxBandwidth,
Yves Gerey665174f2018-06-19 15:03:05 +02002285 dcd->bandwidth()); // default bandwidth (auto)
2286 EXPECT_TRUE(dcd->rtcp_mux()); // rtcp-mux defaults on
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002287
2288 // Update the answer. Add a new video track that is not synched to the
zhihuang8f65cdf2016-05-06 18:40:30 -07002289 // other tracks and remove 1 audio track.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002290 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, kVideoTrack2,
2291 {kMediaStream2}, 1, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07002292 DetachSenderFromMediaSection("audio", kAudioTrack2, &answer_opts);
2293 DetachSenderFromMediaSection("data", kDataTrack2, &answer_opts);
kwiberg31022942016-03-11 14:18:21 -08002294 std::unique_ptr<SessionDescription> updated_answer(
zhihuang1c378ed2017-08-17 14:10:50 -07002295 f2_.CreateAnswer(offer.get(), answer_opts, answer.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002296
2297 ASSERT_TRUE(updated_answer.get() != NULL);
2298 ac = updated_answer->GetContentByName("audio");
2299 vc = updated_answer->GetContentByName("video");
2300 dc = updated_answer->GetContentByName("data");
2301 ASSERT_TRUE(ac != NULL);
2302 ASSERT_TRUE(vc != NULL);
2303 ASSERT_TRUE(dc != NULL);
2304 const AudioContentDescription* updated_acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002305 ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002306 const VideoContentDescription* updated_vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002307 vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002308 const DataContentDescription* updated_dcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08002309 dc->media_description()->as_data();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002310
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002311 ASSERT_CRYPTO(updated_acd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002312 EXPECT_TRUE(CompareCryptoParams(acd->cryptos(), updated_acd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002313 ASSERT_CRYPTO(updated_vcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002314 EXPECT_TRUE(CompareCryptoParams(vcd->cryptos(), updated_vcd->cryptos()));
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07002315 ASSERT_CRYPTO(updated_dcd, 1U, kDefaultSrtpCryptoSuite);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002316 EXPECT_TRUE(CompareCryptoParams(dcd->cryptos(), updated_dcd->cryptos()));
2317
2318 EXPECT_EQ(acd->type(), updated_acd->type());
2319 EXPECT_EQ(acd->codecs(), updated_acd->codecs());
2320 EXPECT_EQ(vcd->type(), updated_vcd->type());
2321 EXPECT_EQ(vcd->codecs(), updated_vcd->codecs());
2322 EXPECT_EQ(dcd->type(), updated_dcd->type());
2323 EXPECT_EQ(dcd->codecs(), updated_dcd->codecs());
2324
2325 const StreamParamsVec& updated_audio_streams = updated_acd->streams();
2326 ASSERT_EQ(1U, updated_audio_streams.size());
Yves Gerey665174f2018-06-19 15:03:05 +02002327 EXPECT_TRUE(audio_streams[0] == updated_audio_streams[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002328
2329 const StreamParamsVec& updated_video_streams = updated_vcd->streams();
2330 ASSERT_EQ(2U, updated_video_streams.size());
2331 EXPECT_EQ(video_streams[0], updated_video_streams[0]);
2332 EXPECT_EQ(kVideoTrack2, updated_video_streams[1].id);
zhihuang8f65cdf2016-05-06 18:40:30 -07002333 // All media streams in one PeerConnection share one CNAME.
2334 EXPECT_EQ(updated_video_streams[1].cname, updated_video_streams[0].cname);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002335
2336 const StreamParamsVec& updated_data_streams = updated_dcd->streams();
2337 ASSERT_EQ(1U, updated_data_streams.size());
2338 EXPECT_TRUE(data_streams[0] == updated_data_streams[0]);
2339}
2340
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002341// Create an updated offer after creating an answer to the original offer and
2342// verify that the codecs that were part of the original answer are not changed
2343// in the updated offer.
2344TEST_F(MediaSessionDescriptionFactoryTest,
2345 RespondentCreatesOfferAfterCreatingAnswer) {
2346 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002347 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002348
Steve Anton6fe1fba2018-12-11 10:15:23 -08002349 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2350 std::unique_ptr<SessionDescription> answer =
2351 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002352
2353 const AudioContentDescription* acd =
2354 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002355 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002356
2357 const VideoContentDescription* vcd =
2358 GetFirstVideoContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002359 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002360
kwiberg31022942016-03-11 14:18:21 -08002361 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002362 f2_.CreateOffer(opts, answer.get()));
2363
2364 // The expected audio codecs are the common audio codecs from the first
2365 // offer/answer exchange plus the audio codecs only |f2_| offer, sorted in
2366 // preference order.
wu@webrtc.orgff1b1bf2014-06-20 20:57:42 +00002367 // TODO(wu): |updated_offer| should not include the codec
2368 // (i.e. |kAudioCodecs2[0]|) the other side doesn't support.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002369 const AudioCodec kUpdatedAudioCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02002370 kAudioCodecsAnswer[0], kAudioCodecsAnswer[1], kAudioCodecs2[0],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002371 };
2372
2373 // The expected video codecs are the common video codecs from the first
2374 // offer/answer exchange plus the video codecs only |f2_| offer, sorted in
2375 // preference order.
2376 const VideoCodec kUpdatedVideoCodecOffer[] = {
Yves Gerey665174f2018-06-19 15:03:05 +02002377 kVideoCodecsAnswer[0], kVideoCodecs2[1],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002378 };
2379
2380 const AudioContentDescription* updated_acd =
2381 GetFirstAudioContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002382 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kUpdatedAudioCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002383
2384 const VideoContentDescription* updated_vcd =
2385 GetFirstVideoContentDescription(updated_offer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002386 EXPECT_THAT(updated_vcd->codecs(), ElementsAreArray(kUpdatedVideoCodecOffer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002387}
2388
Steve Anton5c72e712018-12-10 14:25:30 -08002389// Test that a reoffer does not reuse audio codecs from a previous media section
2390// that is being recycled.
2391TEST_F(MediaSessionDescriptionFactoryTest,
2392 ReOfferDoesNotReUseRecycledAudioCodecs) {
2393 f1_.set_video_codecs({});
2394 f2_.set_video_codecs({});
2395
2396 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002397 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2398 RtpTransceiverDirection::kSendRecv, kActive,
2399 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002400 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2401 std::unique_ptr<SessionDescription> answer =
2402 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002403
2404 // Recycle the media section by changing its mid.
2405 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002406 std::unique_ptr<SessionDescription> reoffer =
2407 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002408
2409 // Expect that the results of the first negotiation are ignored. If the m=
2410 // section was not recycled the payload types would match the initial offerer.
2411 const AudioContentDescription* acd =
2412 GetFirstAudioContentDescription(reoffer.get());
2413 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecs2));
2414}
2415
2416// Test that a reoffer does not reuse video codecs from a previous media section
2417// that is being recycled.
2418TEST_F(MediaSessionDescriptionFactoryTest,
2419 ReOfferDoesNotReUseRecycledVideoCodecs) {
2420 f1_.set_audio_codecs({}, {});
2421 f2_.set_audio_codecs({}, {});
2422
2423 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002424 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2425 RtpTransceiverDirection::kSendRecv, kActive,
2426 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002427 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
2428 auto answer = f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002429
2430 // Recycle the media section by changing its mid.
2431 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002432 std::unique_ptr<SessionDescription> reoffer =
2433 f2_.CreateOffer(opts, answer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002434
2435 // Expect that the results of the first negotiation are ignored. If the m=
2436 // section was not recycled the payload types would match the initial offerer.
2437 const VideoContentDescription* vcd =
2438 GetFirstVideoContentDescription(reoffer.get());
2439 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecs2));
2440}
2441
2442// Test that a reanswer does not reuse audio codecs from a previous media
2443// section that is being recycled.
2444TEST_F(MediaSessionDescriptionFactoryTest,
2445 ReAnswerDoesNotReUseRecycledAudioCodecs) {
2446 f1_.set_video_codecs({});
2447 f2_.set_video_codecs({});
2448
2449 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2450 // second offer/answer is forward (|f1_| as offerer).
2451 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002452 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "a0",
2453 RtpTransceiverDirection::kSendRecv, kActive,
2454 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002455 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2456 std::unique_ptr<SessionDescription> answer =
2457 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002458
2459 // Recycle the media section by changing its mid.
2460 opts.media_description_options[0].mid = "a1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002461 std::unique_ptr<SessionDescription> reoffer =
2462 f1_.CreateOffer(opts, answer.get());
2463 std::unique_ptr<SessionDescription> reanswer =
2464 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002465
2466 // Expect that the results of the first negotiation are ignored. If the m=
2467 // section was not recycled the payload types would match the initial offerer.
2468 const AudioContentDescription* acd =
2469 GetFirstAudioContentDescription(reanswer.get());
2470 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
2471}
2472
2473// Test that a reanswer does not reuse video codecs from a previous media
2474// section that is being recycled.
2475TEST_F(MediaSessionDescriptionFactoryTest,
2476 ReAnswerDoesNotReUseRecycledVideoCodecs) {
2477 f1_.set_audio_codecs({}, {});
2478 f2_.set_audio_codecs({}, {});
2479
2480 // Perform initial offer/answer in reverse (|f2_| as offerer) so that the
2481 // second offer/answer is forward (|f1_| as offerer).
2482 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002483 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "v0",
2484 RtpTransceiverDirection::kSendRecv, kActive,
2485 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002486 std::unique_ptr<SessionDescription> offer = f2_.CreateOffer(opts, nullptr);
2487 std::unique_ptr<SessionDescription> answer =
2488 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton5c72e712018-12-10 14:25:30 -08002489
2490 // Recycle the media section by changing its mid.
2491 opts.media_description_options[0].mid = "v1";
Steve Anton6fe1fba2018-12-11 10:15:23 -08002492 std::unique_ptr<SessionDescription> reoffer =
2493 f1_.CreateOffer(opts, answer.get());
2494 std::unique_ptr<SessionDescription> reanswer =
2495 f2_.CreateAnswer(reoffer.get(), opts, offer.get());
Steve Anton5c72e712018-12-10 14:25:30 -08002496
2497 // Expect that the results of the first negotiation are ignored. If the m=
2498 // section was not recycled the payload types would match the initial offerer.
2499 const VideoContentDescription* vcd =
2500 GetFirstVideoContentDescription(reanswer.get());
2501 EXPECT_THAT(vcd->codecs(), ElementsAreArray(kVideoCodecsAnswer));
2502}
2503
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002504// Create an updated offer after creating an answer to the original offer and
2505// verify that the codecs that were part of the original answer are not changed
2506// in the updated offer. In this test Rtx is enabled.
2507TEST_F(MediaSessionDescriptionFactoryTest,
2508 RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
2509 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002510 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2511 RtpTransceiverDirection::kRecvOnly, kActive,
2512 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002513 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002514 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002515 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002516 f1_.set_video_codecs(f1_codecs);
2517
2518 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002519 // This creates rtx for H264 with the payload type |f2_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002520 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002521 f2_.set_video_codecs(f2_codecs);
2522
Steve Anton6fe1fba2018-12-11 10:15:23 -08002523 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002524 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002525 std::unique_ptr<SessionDescription> answer =
2526 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002527
2528 const VideoContentDescription* vcd =
2529 GetFirstVideoContentDescription(answer.get());
2530
2531 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002532 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2533 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002534
2535 EXPECT_EQ(expected_codecs, vcd->codecs());
2536
deadbeef67cf2c12016-04-13 10:07:16 -07002537 // Now, make sure we get same result (except for the order) if |f2_| creates
2538 // an updated offer even though the default payload types between |f1_| and
2539 // |f2_| are different.
kwiberg31022942016-03-11 14:18:21 -08002540 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002541 f2_.CreateOffer(opts, answer.get()));
2542 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002543 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002544 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2545
2546 const VideoContentDescription* updated_vcd =
2547 GetFirstVideoContentDescription(updated_answer.get());
2548
2549 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2550}
2551
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002552// Regression test for:
2553// https://bugs.chromium.org/p/webrtc/issues/detail?id=8332
2554// Existing codecs should always appear before new codecs in re-offers. But
2555// under a specific set of circumstances, the existing RTX codec was ending up
2556// added to the end of the list.
2557TEST_F(MediaSessionDescriptionFactoryTest,
2558 RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
2559 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002560 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2561 RtpTransceiverDirection::kRecvOnly, kActive,
2562 &opts);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002563 // We specifically choose different preferred payload types for VP8 to
2564 // trigger the issue.
2565 cricket::VideoCodec vp8_offerer(100, "VP8");
2566 cricket::VideoCodec vp8_offerer_rtx =
2567 VideoCodec::CreateRtxCodec(101, vp8_offerer.id);
2568 cricket::VideoCodec vp8_answerer(110, "VP8");
2569 cricket::VideoCodec vp8_answerer_rtx =
2570 VideoCodec::CreateRtxCodec(111, vp8_answerer.id);
2571 cricket::VideoCodec vp9(120, "VP9");
2572 cricket::VideoCodec vp9_rtx = VideoCodec::CreateRtxCodec(121, vp9.id);
2573
2574 std::vector<VideoCodec> f1_codecs = {vp8_offerer, vp8_offerer_rtx};
2575 // We also specifically cause the answerer to prefer VP9, such that if it
2576 // *doesn't* honor the existing preferred codec (VP8) we'll notice.
2577 std::vector<VideoCodec> f2_codecs = {vp9, vp9_rtx, vp8_answerer,
2578 vp8_answerer_rtx};
2579
2580 f1_.set_video_codecs(f1_codecs);
2581 f2_.set_video_codecs(f2_codecs);
2582 std::vector<AudioCodec> audio_codecs;
2583 f1_.set_audio_codecs(audio_codecs, audio_codecs);
2584 f2_.set_audio_codecs(audio_codecs, audio_codecs);
2585
2586 // Offer will be {VP8, RTX for VP8}. Answer will be the same.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002587 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002588 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002589 std::unique_ptr<SessionDescription> answer =
2590 f2_.CreateAnswer(offer.get(), opts, NULL);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002591
2592 // Updated offer *should* be {VP8, RTX for VP8, VP9, RTX for VP9}.
2593 // But if the bug is triggered, RTX for VP8 ends up last.
2594 std::unique_ptr<SessionDescription> updated_offer(
2595 f2_.CreateOffer(opts, answer.get()));
2596
2597 const VideoContentDescription* vcd =
2598 GetFirstVideoContentDescription(updated_offer.get());
2599 std::vector<cricket::VideoCodec> codecs = vcd->codecs();
2600 ASSERT_EQ(4u, codecs.size());
2601 EXPECT_EQ(vp8_offerer, codecs[0]);
2602 EXPECT_EQ(vp8_offerer_rtx, codecs[1]);
2603 EXPECT_EQ(vp9, codecs[2]);
2604 EXPECT_EQ(vp9_rtx, codecs[3]);
Taylor Brandstetter1c349742017-10-03 18:25:36 -07002605}
2606
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002607// Create an updated offer that adds video after creating an audio only answer
2608// to the original offer. This test verifies that if a video codec and the RTX
2609// codec have the same default payload type as an audio codec that is already in
2610// use, the added codecs payload types are changed.
2611TEST_F(MediaSessionDescriptionFactoryTest,
2612 RespondentCreatesOfferWithVideoAndRtxAfterCreatingAudioAnswer) {
2613 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002614 // This creates rtx for H264 with the payload type |f1_| uses.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002615 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002616 f1_.set_video_codecs(f1_codecs);
2617
2618 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002619 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
2620 RtpTransceiverDirection::kRecvOnly, kActive,
2621 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002622
Steve Anton6fe1fba2018-12-11 10:15:23 -08002623 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2624 std::unique_ptr<SessionDescription> answer =
2625 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002626
2627 const AudioContentDescription* acd =
2628 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002629 EXPECT_THAT(acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002630
2631 // Now - let |f2_| add video with RTX and let the payload type the RTX codec
2632 // reference be the same as an audio codec that was negotiated in the
2633 // first offer/answer exchange.
zhihuang1c378ed2017-08-17 14:10:50 -07002634 opts.media_description_options.clear();
Steve Anton4e70a722017-11-28 14:57:10 -08002635 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002636
2637 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2638 int used_pl_type = acd->codecs()[0].id;
2639 f2_codecs[0].id = used_pl_type; // Set the payload type for H264.
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002640 AddRtxCodec(VideoCodec::CreateRtxCodec(125, used_pl_type), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002641 f2_.set_video_codecs(f2_codecs);
2642
kwiberg31022942016-03-11 14:18:21 -08002643 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002644 f2_.CreateOffer(opts, answer.get()));
2645 ASSERT_TRUE(updated_offer);
kwiberg31022942016-03-11 14:18:21 -08002646 std::unique_ptr<SessionDescription> updated_answer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002647 f1_.CreateAnswer(updated_offer.get(), opts, answer.get()));
2648
2649 const AudioContentDescription* updated_acd =
2650 GetFirstAudioContentDescription(answer.get());
Steve Antone38a5a12018-11-21 16:05:15 -08002651 EXPECT_THAT(updated_acd->codecs(), ElementsAreArray(kAudioCodecsAnswer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002652
2653 const VideoContentDescription* updated_vcd =
2654 GetFirstVideoContentDescription(updated_answer.get());
2655
2656 ASSERT_EQ("H264", updated_vcd->codecs()[0].name);
Steve Antone38a5a12018-11-21 16:05:15 -08002657 ASSERT_EQ(cricket::kRtxCodecName, updated_vcd->codecs()[1].name);
Yves Gerey665174f2018-06-19 15:03:05 +02002658 int new_h264_pl_type = updated_vcd->codecs()[0].id;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002659 EXPECT_NE(used_pl_type, new_h264_pl_type);
2660 VideoCodec rtx = updated_vcd->codecs()[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002661 int pt_referenced_by_rtx = rtc::FromString<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002662 rtx.params[cricket::kCodecParamAssociatedPayloadType]);
2663 EXPECT_EQ(new_h264_pl_type, pt_referenced_by_rtx);
2664}
2665
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002666// Create an updated offer with RTX after creating an answer to an offer
2667// without RTX, and with different default payload types.
2668// Verify that the added RTX codec references the correct payload type.
2669TEST_F(MediaSessionDescriptionFactoryTest,
2670 RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
2671 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002672 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002673
2674 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2675 // This creates rtx for H264 with the payload type |f2_| uses.
2676 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
2677 f2_.set_video_codecs(f2_codecs);
2678
Steve Anton6fe1fba2018-12-11 10:15:23 -08002679 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002680 ASSERT_TRUE(offer.get() != nullptr);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002681 std::unique_ptr<SessionDescription> answer =
2682 f2_.CreateAnswer(offer.get(), opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002683
2684 const VideoContentDescription* vcd =
2685 GetFirstVideoContentDescription(answer.get());
2686
2687 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2688 EXPECT_EQ(expected_codecs, vcd->codecs());
2689
2690 // Now, ensure that the RTX codec is created correctly when |f2_| creates an
2691 // updated offer, even though the default payload types are different from
2692 // those of |f1_|.
kwiberg31022942016-03-11 14:18:21 -08002693 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002694 f2_.CreateOffer(opts, answer.get()));
2695 ASSERT_TRUE(updated_offer);
2696
2697 const VideoContentDescription* updated_vcd =
2698 GetFirstVideoContentDescription(updated_offer.get());
2699
2700 // New offer should attempt to add H263, and RTX for H264.
2701 expected_codecs.push_back(kVideoCodecs2[1]);
2702 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[1].id),
2703 &expected_codecs);
2704 EXPECT_EQ(expected_codecs, updated_vcd->codecs());
2705}
2706
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002707// Test that RTX is ignored when there is no associated payload type parameter.
2708TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
2709 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002710 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2711 RtpTransceiverDirection::kRecvOnly, kActive,
2712 &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002713 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002714 // This creates RTX without associated payload type parameter.
perkj26752742016-10-24 01:21:16 -07002715 AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002716 f1_.set_video_codecs(f1_codecs);
2717
2718 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002719 // This creates RTX for H264 with the payload type |f2_| uses.
2720 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[0].id), &f2_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002721 f2_.set_video_codecs(f2_codecs);
2722
Steve Anton6fe1fba2018-12-11 10:15:23 -08002723 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002724 ASSERT_TRUE(offer.get() != NULL);
2725 // kCodecParamAssociatedPayloadType will always be added to the offer when RTX
2726 // is selected. Manually remove kCodecParamAssociatedPayloadType so that it
2727 // is possible to test that that RTX is dropped when
2728 // kCodecParamAssociatedPayloadType is missing in the offer.
Steve Antonb1c1de12017-12-21 15:14:30 -08002729 MediaContentDescription* media_desc =
2730 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2731 ASSERT_TRUE(media_desc);
2732 VideoContentDescription* desc = media_desc->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002733 std::vector<VideoCodec> codecs = desc->codecs();
Steve Anton3a66edf2018-09-10 12:57:37 -07002734 for (VideoCodec& codec : codecs) {
2735 if (codec.name.find(cricket::kRtxCodecName) == 0) {
2736 codec.params.clear();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002737 }
2738 }
2739 desc->set_codecs(codecs);
2740
Steve Anton6fe1fba2018-12-11 10:15:23 -08002741 std::unique_ptr<SessionDescription> answer =
2742 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002743
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002744 std::vector<std::string> codec_names =
2745 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
2746 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
2747 cricket::kRtxCodecName));
2748}
2749
2750// Test that RTX will be filtered out in the answer if its associated payload
2751// type doesn't match the local value.
2752TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
2753 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002754 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2755 RtpTransceiverDirection::kRecvOnly, kActive,
2756 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002757 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2758 // This creates RTX for H264 in sender.
2759 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2760 f1_.set_video_codecs(f1_codecs);
2761
2762 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2763 // This creates RTX for H263 in receiver.
2764 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs2[1].id), &f2_codecs);
2765 f2_.set_video_codecs(f2_codecs);
2766
Steve Anton6fe1fba2018-12-11 10:15:23 -08002767 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002768 ASSERT_TRUE(offer.get() != NULL);
2769 // Associated payload type doesn't match, therefore, RTX codec is removed in
2770 // the answer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002771 std::unique_ptr<SessionDescription> answer =
2772 f2_.CreateAnswer(offer.get(), opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002773
2774 std::vector<std::string> codec_names =
2775 GetCodecNames(GetFirstVideoContentDescription(answer.get())->codecs());
2776 EXPECT_EQ(codec_names.end(), std::find(codec_names.begin(), codec_names.end(),
2777 cricket::kRtxCodecName));
2778}
2779
2780// Test that when multiple RTX codecs are offered, only the matched RTX codec
2781// is added in the answer, and the unsupported RTX codec is filtered out.
2782TEST_F(MediaSessionDescriptionFactoryTest,
2783 FilterOutUnsupportedRtxWhenCreatingAnswer) {
2784 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002785 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2786 RtpTransceiverDirection::kRecvOnly, kActive,
2787 &opts);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002788 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2789 // This creates RTX for H264-SVC in sender.
2790 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2791 f1_.set_video_codecs(f1_codecs);
2792
2793 // This creates RTX for H264 in sender.
2794 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2795 f1_.set_video_codecs(f1_codecs);
2796
2797 std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
2798 // This creates RTX for H264 in receiver.
2799 AddRtxCodec(VideoCodec::CreateRtxCodec(124, kVideoCodecs2[0].id), &f2_codecs);
2800 f2_.set_video_codecs(f2_codecs);
2801
2802 // H264-SVC codec is removed in the answer, therefore, associated RTX codec
2803 // for H264-SVC should also be removed.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002804 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002805 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08002806 std::unique_ptr<SessionDescription> answer =
2807 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002808 const VideoContentDescription* vcd =
2809 GetFirstVideoContentDescription(answer.get());
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002810 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecsAnswer);
2811 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2812 &expected_codecs);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002813
changbin.shao@webrtc.org2d25b442015-03-16 04:14:34 +00002814 EXPECT_EQ(expected_codecs, vcd->codecs());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002815}
2816
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002817// Test that after one RTX codec has been negotiated, a new offer can attempt
2818// to add another.
2819TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
2820 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002821 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2822 RtpTransceiverDirection::kRecvOnly, kActive,
2823 &opts);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002824 std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
2825 // This creates RTX for H264 for the offerer.
2826 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
2827 f1_.set_video_codecs(f1_codecs);
2828
Steve Anton6fe1fba2018-12-11 10:15:23 -08002829 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002830 ASSERT_TRUE(offer);
2831 const VideoContentDescription* vcd =
2832 GetFirstVideoContentDescription(offer.get());
2833
2834 std::vector<VideoCodec> expected_codecs = MAKE_VECTOR(kVideoCodecs1);
2835 AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id),
2836 &expected_codecs);
2837 EXPECT_EQ(expected_codecs, vcd->codecs());
2838
2839 // Now, attempt to add RTX for H264-SVC.
2840 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
2841 f1_.set_video_codecs(f1_codecs);
2842
kwiberg31022942016-03-11 14:18:21 -08002843 std::unique_ptr<SessionDescription> updated_offer(
Taylor Brandstetter6ec641b2016-03-04 16:47:56 -08002844 f1_.CreateOffer(opts, offer.get()));
2845 ASSERT_TRUE(updated_offer);
2846 vcd = GetFirstVideoContentDescription(updated_offer.get());
2847
2848 AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id),
2849 &expected_codecs);
2850 EXPECT_EQ(expected_codecs, vcd->codecs());
2851}
2852
Noah Richards2e7a0982015-05-18 14:02:54 -07002853// Test that when RTX is used in conjunction with simulcast, an RTX ssrc is
2854// generated for each simulcast ssrc and correctly grouped.
2855TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
2856 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002857 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2858 RtpTransceiverDirection::kSendRecv, kActive,
2859 &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002860 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002861 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
2862 {"stream1label"}, 3, &opts);
Noah Richards2e7a0982015-05-18 14:02:54 -07002863
2864 // Use a single real codec, and then add RTX for it.
2865 std::vector<VideoCodec> f1_codecs;
perkj26752742016-10-24 01:21:16 -07002866 f1_codecs.push_back(VideoCodec(97, "H264"));
Noah Richards2e7a0982015-05-18 14:02:54 -07002867 AddRtxCodec(VideoCodec::CreateRtxCodec(125, 97), &f1_codecs);
2868 f1_.set_video_codecs(f1_codecs);
2869
2870 // Ensure that the offer has an RTX ssrc for each regular ssrc, and that there
2871 // is a FID ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002872 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
Noah Richards2e7a0982015-05-18 14:02:54 -07002873 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08002874 MediaContentDescription* media_desc =
2875 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2876 ASSERT_TRUE(media_desc);
2877 VideoContentDescription* desc = media_desc->as_video();
Noah Richards2e7a0982015-05-18 14:02:54 -07002878 const StreamParamsVec& streams = desc->streams();
2879 // Single stream.
2880 ASSERT_EQ(1u, streams.size());
2881 // Stream should have 6 ssrcs: 3 for video, 3 for RTX.
2882 EXPECT_EQ(6u, streams[0].ssrcs.size());
2883 // And should have a SIM group for the simulcast.
2884 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2885 // And a FID group for RTX.
2886 EXPECT_TRUE(streams[0].has_ssrc_group("FID"));
Peter Boström0c4e06b2015-10-07 12:23:21 +02002887 std::vector<uint32_t> primary_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002888 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2889 EXPECT_EQ(3u, primary_ssrcs.size());
Peter Boström0c4e06b2015-10-07 12:23:21 +02002890 std::vector<uint32_t> fid_ssrcs;
Noah Richards2e7a0982015-05-18 14:02:54 -07002891 streams[0].GetFidSsrcs(primary_ssrcs, &fid_ssrcs);
2892 EXPECT_EQ(3u, fid_ssrcs.size());
2893}
2894
brandtr03d5fb12016-11-22 03:37:59 -08002895// Test that, when the FlexFEC codec is added, a FlexFEC ssrc is created
2896// together with a FEC-FR grouping.
2897TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
2898 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002899 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2900 RtpTransceiverDirection::kSendRecv, kActive,
2901 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002902 // Add single stream.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002903 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
2904 {"stream1label"}, 1, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002905
2906 // Use a single real codec, and then add FlexFEC for it.
2907 std::vector<VideoCodec> f1_codecs;
2908 f1_codecs.push_back(VideoCodec(97, "H264"));
2909 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2910 f1_.set_video_codecs(f1_codecs);
2911
2912 // Ensure that the offer has a single FlexFEC ssrc and that
2913 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002914 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08002915 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08002916 MediaContentDescription* media_desc =
2917 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2918 ASSERT_TRUE(media_desc);
2919 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08002920 const StreamParamsVec& streams = desc->streams();
2921 // Single stream.
2922 ASSERT_EQ(1u, streams.size());
2923 // Stream should have 2 ssrcs: 1 for video, 1 for FlexFEC.
2924 EXPECT_EQ(2u, streams[0].ssrcs.size());
2925 // And should have a FEC-FR group for FlexFEC.
2926 EXPECT_TRUE(streams[0].has_ssrc_group("FEC-FR"));
2927 std::vector<uint32_t> primary_ssrcs;
2928 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2929 ASSERT_EQ(1u, primary_ssrcs.size());
2930 uint32_t flexfec_ssrc;
2931 EXPECT_TRUE(streams[0].GetFecFrSsrc(primary_ssrcs[0], &flexfec_ssrc));
2932 EXPECT_NE(flexfec_ssrc, 0u);
2933}
2934
2935// Test that FlexFEC is disabled for simulcast.
2936// TODO(brandtr): Remove this test when we support simulcast, either through
2937// multiple FlexfecSenders, or through multistream protection.
2938TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
2939 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002940 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
2941 RtpTransceiverDirection::kSendRecv, kActive,
2942 &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002943 // Add simulcast streams.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08002944 AttachSenderToMediaDescriptionOptions("video", MEDIA_TYPE_VIDEO, "stream1",
2945 {"stream1label"}, 3, &opts);
brandtr03d5fb12016-11-22 03:37:59 -08002946
2947 // Use a single real codec, and then add FlexFEC for it.
2948 std::vector<VideoCodec> f1_codecs;
2949 f1_codecs.push_back(VideoCodec(97, "H264"));
2950 f1_codecs.push_back(VideoCodec(118, "flexfec-03"));
2951 f1_.set_video_codecs(f1_codecs);
2952
2953 // Ensure that the offer has no FlexFEC ssrcs for each regular ssrc, and that
2954 // there is no FEC-FR ssrc + grouping for each.
Steve Anton6fe1fba2018-12-11 10:15:23 -08002955 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
brandtr03d5fb12016-11-22 03:37:59 -08002956 ASSERT_TRUE(offer.get() != nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08002957 MediaContentDescription* media_desc =
2958 offer->GetContentDescriptionByName(cricket::CN_VIDEO);
2959 ASSERT_TRUE(media_desc);
2960 VideoContentDescription* desc = media_desc->as_video();
brandtr03d5fb12016-11-22 03:37:59 -08002961 const StreamParamsVec& streams = desc->streams();
2962 // Single stream.
2963 ASSERT_EQ(1u, streams.size());
2964 // Stream should have 3 ssrcs: 3 for video, 0 for FlexFEC.
2965 EXPECT_EQ(3u, streams[0].ssrcs.size());
2966 // And should have a SIM group for the simulcast.
2967 EXPECT_TRUE(streams[0].has_ssrc_group("SIM"));
2968 // And not a FEC-FR group for FlexFEC.
2969 EXPECT_FALSE(streams[0].has_ssrc_group("FEC-FR"));
2970 std::vector<uint32_t> primary_ssrcs;
2971 streams[0].GetPrimarySsrcs(&primary_ssrcs);
2972 EXPECT_EQ(3u, primary_ssrcs.size());
2973 for (uint32_t primary_ssrc : primary_ssrcs) {
2974 uint32_t flexfec_ssrc;
2975 EXPECT_FALSE(streams[0].GetFecFrSsrc(primary_ssrc, &flexfec_ssrc));
2976 }
2977}
2978
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002979// Create an updated offer after creating an answer to the original offer and
2980// verify that the RTP header extensions that were part of the original answer
2981// are not changed in the updated offer.
2982TEST_F(MediaSessionDescriptionFactoryTest,
2983 RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
2984 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08002985 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002986
2987 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
2988 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
2989 f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
2990 f2_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension2));
2991
Steve Anton6fe1fba2018-12-11 10:15:23 -08002992 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
2993 std::unique_ptr<SessionDescription> answer =
2994 f2_.CreateAnswer(offer.get(), opts, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002995
Yves Gerey665174f2018-06-19 15:03:05 +02002996 EXPECT_EQ(
2997 MAKE_VECTOR(kAudioRtpExtensionAnswer),
2998 GetFirstAudioContentDescription(answer.get())->rtp_header_extensions());
2999 EXPECT_EQ(
3000 MAKE_VECTOR(kVideoRtpExtensionAnswer),
3001 GetFirstVideoContentDescription(answer.get())->rtp_header_extensions());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003002
kwiberg31022942016-03-11 14:18:21 -08003003 std::unique_ptr<SessionDescription> updated_offer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003004 f2_.CreateOffer(opts, answer.get()));
3005
3006 // The expected RTP header extensions in the new offer are the resulting
3007 // extensions from the first offer/answer exchange plus the extensions only
3008 // |f2_| offer.
3009 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003010 // |f1_| for another extensions, it is changed to 13.
isheriff6f8d6862016-05-26 11:24:55 -07003011 const RtpExtension kUpdatedAudioRtpExtensions[] = {
3012 kAudioRtpExtensionAnswer[0], RtpExtension(kAudioRtpExtension2[1].uri, 13),
3013 kAudioRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003014 };
3015
3016 // Since the default local extension id |f2_| uses has already been used by
henrike@webrtc.org79047f92014-03-06 23:46:59 +00003017 // |f1_| for another extensions, is is changed to 12.
isheriff6f8d6862016-05-26 11:24:55 -07003018 const RtpExtension kUpdatedVideoRtpExtensions[] = {
3019 kVideoRtpExtensionAnswer[0], RtpExtension(kVideoRtpExtension2[1].uri, 12),
3020 kVideoRtpExtension2[2],
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003021 };
3022
3023 const AudioContentDescription* updated_acd =
3024 GetFirstAudioContentDescription(updated_offer.get());
3025 EXPECT_EQ(MAKE_VECTOR(kUpdatedAudioRtpExtensions),
3026 updated_acd->rtp_header_extensions());
3027
3028 const VideoContentDescription* updated_vcd =
3029 GetFirstVideoContentDescription(updated_offer.get());
3030 EXPECT_EQ(MAKE_VECTOR(kUpdatedVideoRtpExtensions),
3031 updated_vcd->rtp_header_extensions());
3032}
3033
deadbeefa5b273a2015-08-20 17:30:13 -07003034// Verify that if the same RTP extension URI is used for audio and video, the
3035// same ID is used. Also verify that the ID isn't changed when creating an
3036// updated offer (this was previously a bug).
isheriff6f8d6862016-05-26 11:24:55 -07003037TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
deadbeefa5b273a2015-08-20 17:30:13 -07003038 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003039 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
deadbeefa5b273a2015-08-20 17:30:13 -07003040
3041 f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
3042 f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
3043
Steve Anton6fe1fba2018-12-11 10:15:23 -08003044 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
deadbeefa5b273a2015-08-20 17:30:13 -07003045
3046 // Since the audio extensions used ID 3 for "both_audio_and_video", so should
3047 // the video extensions.
isheriff6f8d6862016-05-26 11:24:55 -07003048 const RtpExtension kExpectedVideoRtpExtension[] = {
3049 kVideoRtpExtension3[0], kAudioRtpExtension3[1],
deadbeefa5b273a2015-08-20 17:30:13 -07003050 };
3051
Yves Gerey665174f2018-06-19 15:03:05 +02003052 EXPECT_EQ(
3053 MAKE_VECTOR(kAudioRtpExtension3),
3054 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3055 EXPECT_EQ(
3056 MAKE_VECTOR(kExpectedVideoRtpExtension),
3057 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003058
3059 // Nothing should change when creating a new offer
kwiberg31022942016-03-11 14:18:21 -08003060 std::unique_ptr<SessionDescription> updated_offer(
deadbeefa5b273a2015-08-20 17:30:13 -07003061 f1_.CreateOffer(opts, offer.get()));
3062
3063 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3),
Yves Gerey665174f2018-06-19 15:03:05 +02003064 GetFirstAudioContentDescription(updated_offer.get())
3065 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003066 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003067 GetFirstVideoContentDescription(updated_offer.get())
3068 ->rtp_header_extensions());
deadbeefa5b273a2015-08-20 17:30:13 -07003069}
3070
jbauch5869f502017-06-29 12:31:36 -07003071// Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
3072TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
3073 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08003074 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
jbauch5869f502017-06-29 12:31:36 -07003075
3076 f1_.set_enable_encrypted_rtp_header_extensions(true);
3077 f2_.set_enable_encrypted_rtp_header_extensions(true);
3078
3079 f1_.set_audio_rtp_header_extensions(
3080 MAKE_VECTOR(kAudioRtpExtension3ForEncryption));
3081 f1_.set_video_rtp_header_extensions(
3082 MAKE_VECTOR(kVideoRtpExtension3ForEncryption));
3083
Steve Anton6fe1fba2018-12-11 10:15:23 -08003084 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, NULL);
jbauch5869f502017-06-29 12:31:36 -07003085
3086 // The extensions that are shared between audio and video should use the same
3087 // id.
3088 const RtpExtension kExpectedVideoRtpExtension[] = {
3089 kVideoRtpExtension3ForEncryption[0],
3090 kAudioRtpExtension3ForEncryptionOffer[1],
3091 kAudioRtpExtension3ForEncryptionOffer[2],
3092 };
3093
Yves Gerey665174f2018-06-19 15:03:05 +02003094 EXPECT_EQ(
3095 MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
3096 GetFirstAudioContentDescription(offer.get())->rtp_header_extensions());
3097 EXPECT_EQ(
3098 MAKE_VECTOR(kExpectedVideoRtpExtension),
3099 GetFirstVideoContentDescription(offer.get())->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003100
3101 // Nothing should change when creating a new offer
3102 std::unique_ptr<SessionDescription> updated_offer(
3103 f1_.CreateOffer(opts, offer.get()));
3104
3105 EXPECT_EQ(MAKE_VECTOR(kAudioRtpExtension3ForEncryptionOffer),
Yves Gerey665174f2018-06-19 15:03:05 +02003106 GetFirstAudioContentDescription(updated_offer.get())
3107 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003108 EXPECT_EQ(MAKE_VECTOR(kExpectedVideoRtpExtension),
Yves Gerey665174f2018-06-19 15:03:05 +02003109 GetFirstVideoContentDescription(updated_offer.get())
3110 ->rtp_header_extensions());
jbauch5869f502017-06-29 12:31:36 -07003111}
3112
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003113TEST(MediaSessionDescription, CopySessionDescription) {
3114 SessionDescription source;
3115 cricket::ContentGroup group(cricket::CN_AUDIO);
3116 source.AddGroup(group);
3117 AudioContentDescription* acd(new AudioContentDescription());
3118 acd->set_codecs(MAKE_VECTOR(kAudioCodecs1));
3119 acd->AddLegacyStream(1);
Steve Anton5adfafd2017-12-20 16:34:00 -08003120 source.AddContent(cricket::CN_AUDIO, MediaProtocolType::kRtp, acd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003121 VideoContentDescription* vcd(new VideoContentDescription());
3122 vcd->set_codecs(MAKE_VECTOR(kVideoCodecs1));
3123 vcd->AddLegacyStream(2);
Steve Anton5adfafd2017-12-20 16:34:00 -08003124 source.AddContent(cricket::CN_VIDEO, MediaProtocolType::kRtp, vcd);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003125
kwiberg31022942016-03-11 14:18:21 -08003126 std::unique_ptr<SessionDescription> copy(source.Copy());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003127 ASSERT_TRUE(copy.get() != NULL);
3128 EXPECT_TRUE(copy->HasGroup(cricket::CN_AUDIO));
3129 const ContentInfo* ac = copy->GetContentByName("audio");
3130 const ContentInfo* vc = copy->GetContentByName("video");
3131 ASSERT_TRUE(ac != NULL);
3132 ASSERT_TRUE(vc != NULL);
Steve Anton5adfafd2017-12-20 16:34:00 -08003133 EXPECT_EQ(MediaProtocolType::kRtp, ac->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003134 const AudioContentDescription* acd_copy = ac->media_description()->as_audio();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003135 EXPECT_EQ(acd->codecs(), acd_copy->codecs());
3136 EXPECT_EQ(1u, acd->first_ssrc());
3137
Steve Anton5adfafd2017-12-20 16:34:00 -08003138 EXPECT_EQ(MediaProtocolType::kRtp, vc->type);
Steve Antonb1c1de12017-12-21 15:14:30 -08003139 const VideoContentDescription* vcd_copy = vc->media_description()->as_video();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003140 EXPECT_EQ(vcd->codecs(), vcd_copy->codecs());
3141 EXPECT_EQ(2u, vcd->first_ssrc());
3142}
3143
3144// The below TestTransportInfoXXX tests create different offers/answers, and
3145// ensure the TransportInfo in the SessionDescription matches what we expect.
3146TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
3147 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003148 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3149 RtpTransceiverDirection::kRecvOnly, kActive,
3150 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003151 TestTransportInfo(true, options, false);
3152}
3153
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003154TEST_F(MediaSessionDescriptionFactoryTest,
3155 TestTransportInfoOfferIceRenomination) {
3156 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003157 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3158 RtpTransceiverDirection::kRecvOnly, kActive,
3159 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003160 options.media_description_options[0]
3161 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003162 TestTransportInfo(true, options, false);
3163}
3164
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003165TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
3166 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003167 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3168 RtpTransceiverDirection::kRecvOnly, kActive,
3169 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003170 TestTransportInfo(true, options, true);
3171}
3172
3173TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
3174 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003175 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3176 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3177 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003178 TestTransportInfo(true, options, false);
3179}
3180
3181TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003182 TestTransportInfoOfferMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003183 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003184 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3185 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3186 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003187 TestTransportInfo(true, options, true);
3188}
3189
3190TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
3191 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003192 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3193 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3194 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003195 options.bundle_enabled = true;
3196 TestTransportInfo(true, options, false);
3197}
3198
3199TEST_F(MediaSessionDescriptionFactoryTest,
3200 TestTransportInfoOfferBundleCurrent) {
3201 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003202 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3203 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3204 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003205 options.bundle_enabled = true;
3206 TestTransportInfo(true, options, true);
3207}
3208
3209TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
3210 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003211 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3212 RtpTransceiverDirection::kRecvOnly, kActive,
3213 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003214 TestTransportInfo(false, options, false);
3215}
3216
3217TEST_F(MediaSessionDescriptionFactoryTest,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003218 TestTransportInfoAnswerIceRenomination) {
3219 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003220 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3221 RtpTransceiverDirection::kRecvOnly, kActive,
3222 &options);
zhihuang1c378ed2017-08-17 14:10:50 -07003223 options.media_description_options[0]
3224 .transport_options.enable_ice_renomination = true;
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07003225 TestTransportInfo(false, options, false);
3226}
3227
3228TEST_F(MediaSessionDescriptionFactoryTest,
3229 TestTransportInfoAnswerAudioCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003230 MediaSessionOptions options;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003231 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3232 RtpTransceiverDirection::kRecvOnly, kActive,
3233 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003234 TestTransportInfo(false, options, true);
3235}
3236
3237TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
3238 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003239 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3240 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3241 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003242 TestTransportInfo(false, options, false);
3243}
3244
3245TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003246 TestTransportInfoAnswerMultimediaCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003247 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003248 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3249 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3250 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003251 TestTransportInfo(false, options, true);
3252}
3253
3254TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
3255 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003256 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3257 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3258 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003259 options.bundle_enabled = true;
3260 TestTransportInfo(false, options, false);
3261}
3262
3263TEST_F(MediaSessionDescriptionFactoryTest,
Yves Gerey665174f2018-06-19 15:03:05 +02003264 TestTransportInfoAnswerBundleCurrent) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003265 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003266 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3267 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3268 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003269 options.bundle_enabled = true;
3270 TestTransportInfo(false, options, true);
3271}
3272
3273// Create an offer with bundle enabled and verify the crypto parameters are
3274// the common set of the available cryptos.
3275TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithOfferBundle) {
3276 TestCryptoWithBundle(true);
3277}
3278
3279// Create an answer with bundle enabled and verify the crypto parameters are
3280// the common set of the available cryptos.
3281TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoWithAnswerBundle) {
3282 TestCryptoWithBundle(false);
3283}
3284
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003285// Verifies that creating answer fails if the offer has UDP/TLS/RTP/SAVPF but
3286// DTLS is not enabled locally.
3287TEST_F(MediaSessionDescriptionFactoryTest,
3288 TestOfferDtlsSavpfWithoutDtlsFailed) {
3289 f1_.set_secure(SEC_ENABLED);
3290 f2_.set_secure(SEC_ENABLED);
3291 tdf1_.set_secure(SEC_DISABLED);
3292 tdf2_.set_secure(SEC_DISABLED);
3293
Steve Anton6fe1fba2018-12-11 10:15:23 -08003294 std::unique_ptr<SessionDescription> offer =
3295 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003296 ASSERT_TRUE(offer.get() != NULL);
3297 ContentInfo* offer_content = offer->GetContentByName("audio");
3298 ASSERT_TRUE(offer_content != NULL);
3299 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003300 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003301 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3302
Steve Anton6fe1fba2018-12-11 10:15:23 -08003303 std::unique_ptr<SessionDescription> answer =
3304 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003305 ASSERT_TRUE(answer != NULL);
3306 ContentInfo* answer_content = answer->GetContentByName("audio");
3307 ASSERT_TRUE(answer_content != NULL);
3308
3309 ASSERT_TRUE(answer_content->rejected);
3310}
3311
3312// Offers UDP/TLS/RTP/SAVPF and verifies the answer can be created and contains
3313// UDP/TLS/RTP/SAVPF.
3314TEST_F(MediaSessionDescriptionFactoryTest, TestOfferDtlsSavpfCreateAnswer) {
3315 f1_.set_secure(SEC_ENABLED);
3316 f2_.set_secure(SEC_ENABLED);
3317 tdf1_.set_secure(SEC_ENABLED);
3318 tdf2_.set_secure(SEC_ENABLED);
3319
Steve Anton6fe1fba2018-12-11 10:15:23 -08003320 std::unique_ptr<SessionDescription> offer =
3321 f1_.CreateOffer(CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003322 ASSERT_TRUE(offer.get() != NULL);
3323 ContentInfo* offer_content = offer->GetContentByName("audio");
3324 ASSERT_TRUE(offer_content != NULL);
3325 AudioContentDescription* offer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003326 offer_content->media_description()->as_audio();
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003327 offer_audio_desc->set_protocol(cricket::kMediaProtocolDtlsSavpf);
3328
Steve Anton6fe1fba2018-12-11 10:15:23 -08003329 std::unique_ptr<SessionDescription> answer =
3330 f2_.CreateAnswer(offer.get(), CreatePlanBMediaSessionOptions(), NULL);
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003331 ASSERT_TRUE(answer != NULL);
3332
3333 const ContentInfo* answer_content = answer->GetContentByName("audio");
3334 ASSERT_TRUE(answer_content != NULL);
3335 ASSERT_FALSE(answer_content->rejected);
3336
3337 const AudioContentDescription* answer_audio_desc =
Steve Antonb1c1de12017-12-21 15:14:30 -08003338 answer_content->media_description()->as_audio();
Steve Antone38a5a12018-11-21 16:05:15 -08003339 EXPECT_EQ(cricket::kMediaProtocolDtlsSavpf, answer_audio_desc->protocol());
jiayl@webrtc.org8dcd43c2014-05-29 22:07:59 +00003340}
3341
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003342// Test that we include both SDES and DTLS in the offer, but only include SDES
3343// in the answer if DTLS isn't negotiated.
3344TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoDtls) {
3345 f1_.set_secure(SEC_ENABLED);
3346 f2_.set_secure(SEC_ENABLED);
3347 tdf1_.set_secure(SEC_ENABLED);
3348 tdf2_.set_secure(SEC_DISABLED);
3349 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003350 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
kwiberg31022942016-03-11 14:18:21 -08003351 std::unique_ptr<SessionDescription> offer, answer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003352 const cricket::MediaContentDescription* audio_media_desc;
3353 const cricket::MediaContentDescription* video_media_desc;
3354 const cricket::TransportDescription* audio_trans_desc;
3355 const cricket::TransportDescription* video_trans_desc;
3356
3357 // Generate an offer with SDES and DTLS support.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003358 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003359 ASSERT_TRUE(offer.get() != NULL);
3360
Steve Antonb1c1de12017-12-21 15:14:30 -08003361 audio_media_desc = offer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003362 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003363 video_media_desc = offer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003364 ASSERT_TRUE(video_media_desc != NULL);
Taylor Brandstetterfd350d72018-04-03 16:29:26 -07003365 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003366 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3367
3368 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3369 ASSERT_TRUE(audio_trans_desc != NULL);
3370 video_trans_desc = offer->GetTransportDescriptionByName("video");
3371 ASSERT_TRUE(video_trans_desc != NULL);
3372 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3373 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
3374
3375 // Generate an answer with only SDES support, since tdf2 has crypto disabled.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003376 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003377 ASSERT_TRUE(answer.get() != NULL);
3378
Steve Antonb1c1de12017-12-21 15:14:30 -08003379 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003380 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003381 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003382 ASSERT_TRUE(video_media_desc != NULL);
3383 EXPECT_EQ(1u, audio_media_desc->cryptos().size());
3384 EXPECT_EQ(1u, video_media_desc->cryptos().size());
3385
3386 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3387 ASSERT_TRUE(audio_trans_desc != NULL);
3388 video_trans_desc = answer->GetTransportDescriptionByName("video");
3389 ASSERT_TRUE(video_trans_desc != NULL);
3390 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() == NULL);
3391 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() == NULL);
3392
3393 // Enable DTLS; the answer should now only have DTLS support.
3394 tdf2_.set_secure(SEC_ENABLED);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003395 answer = f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003396 ASSERT_TRUE(answer.get() != NULL);
3397
Steve Antonb1c1de12017-12-21 15:14:30 -08003398 audio_media_desc = answer->GetContentDescriptionByName("audio");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003399 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003400 video_media_desc = answer->GetContentDescriptionByName("video");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003401 ASSERT_TRUE(video_media_desc != NULL);
3402 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3403 EXPECT_TRUE(video_media_desc->cryptos().empty());
Steve Antone38a5a12018-11-21 16:05:15 -08003404 EXPECT_EQ(cricket::kMediaProtocolSavpf, audio_media_desc->protocol());
3405 EXPECT_EQ(cricket::kMediaProtocolSavpf, video_media_desc->protocol());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003406
3407 audio_trans_desc = answer->GetTransportDescriptionByName("audio");
3408 ASSERT_TRUE(audio_trans_desc != NULL);
3409 video_trans_desc = answer->GetTransportDescriptionByName("video");
3410 ASSERT_TRUE(video_trans_desc != NULL);
3411 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3412 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003413
3414 // Try creating offer again. DTLS enabled now, crypto's should be empty
3415 // in new offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003416 offer = f1_.CreateOffer(options, offer.get());
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003417 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003418 audio_media_desc = offer->GetContentDescriptionByName("audio");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003419 ASSERT_TRUE(audio_media_desc != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08003420 video_media_desc = offer->GetContentDescriptionByName("video");
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00003421 ASSERT_TRUE(video_media_desc != NULL);
3422 EXPECT_TRUE(audio_media_desc->cryptos().empty());
3423 EXPECT_TRUE(video_media_desc->cryptos().empty());
3424
3425 audio_trans_desc = offer->GetTransportDescriptionByName("audio");
3426 ASSERT_TRUE(audio_trans_desc != NULL);
3427 video_trans_desc = offer->GetTransportDescriptionByName("video");
3428 ASSERT_TRUE(video_trans_desc != NULL);
3429 ASSERT_TRUE(audio_trans_desc->identity_fingerprint.get() != NULL);
3430 ASSERT_TRUE(video_trans_desc->identity_fingerprint.get() != NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003431}
3432
3433// Test that an answer can't be created if cryptos are required but the offer is
3434// unsecure.
3435TEST_F(MediaSessionDescriptionFactoryTest, TestSecureAnswerToUnsecureOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07003436 MediaSessionOptions options = CreatePlanBMediaSessionOptions();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003437 f1_.set_secure(SEC_DISABLED);
3438 tdf1_.set_secure(SEC_DISABLED);
3439 f2_.set_secure(SEC_REQUIRED);
3440 tdf1_.set_secure(SEC_ENABLED);
3441
Steve Anton6fe1fba2018-12-11 10:15:23 -08003442 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003443 ASSERT_TRUE(offer.get() != NULL);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003444 std::unique_ptr<SessionDescription> answer =
3445 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003446 EXPECT_TRUE(answer.get() == NULL);
3447}
3448
3449// Test that we accept a DTLS offer without SDES and create an appropriate
3450// answer.
3451TEST_F(MediaSessionDescriptionFactoryTest, TestCryptoOfferDtlsButNotSdes) {
3452 f1_.set_secure(SEC_DISABLED);
3453 f2_.set_secure(SEC_ENABLED);
3454 tdf1_.set_secure(SEC_ENABLED);
3455 tdf2_.set_secure(SEC_ENABLED);
3456 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003457 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
3458 AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
3459 &options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003460
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003461 // Generate an offer with DTLS but without SDES.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003462 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003463 ASSERT_TRUE(offer.get() != NULL);
3464
3465 const AudioContentDescription* audio_offer =
3466 GetFirstAudioContentDescription(offer.get());
3467 ASSERT_TRUE(audio_offer->cryptos().empty());
3468 const VideoContentDescription* video_offer =
3469 GetFirstVideoContentDescription(offer.get());
3470 ASSERT_TRUE(video_offer->cryptos().empty());
3471 const DataContentDescription* data_offer =
3472 GetFirstDataContentDescription(offer.get());
3473 ASSERT_TRUE(data_offer->cryptos().empty());
3474
3475 const cricket::TransportDescription* audio_offer_trans_desc =
3476 offer->GetTransportDescriptionByName("audio");
3477 ASSERT_TRUE(audio_offer_trans_desc->identity_fingerprint.get() != NULL);
3478 const cricket::TransportDescription* video_offer_trans_desc =
3479 offer->GetTransportDescriptionByName("video");
3480 ASSERT_TRUE(video_offer_trans_desc->identity_fingerprint.get() != NULL);
3481 const cricket::TransportDescription* data_offer_trans_desc =
3482 offer->GetTransportDescriptionByName("data");
3483 ASSERT_TRUE(data_offer_trans_desc->identity_fingerprint.get() != NULL);
3484
3485 // Generate an answer with DTLS.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003486 std::unique_ptr<SessionDescription> answer =
3487 f2_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003488 ASSERT_TRUE(answer.get() != NULL);
3489
3490 const cricket::TransportDescription* audio_answer_trans_desc =
3491 answer->GetTransportDescriptionByName("audio");
3492 EXPECT_TRUE(audio_answer_trans_desc->identity_fingerprint.get() != NULL);
3493 const cricket::TransportDescription* video_answer_trans_desc =
3494 answer->GetTransportDescriptionByName("video");
3495 EXPECT_TRUE(video_answer_trans_desc->identity_fingerprint.get() != NULL);
3496 const cricket::TransportDescription* data_answer_trans_desc =
3497 answer->GetTransportDescriptionByName("data");
3498 EXPECT_TRUE(data_answer_trans_desc->identity_fingerprint.get() != NULL);
3499}
3500
3501// Verifies if vad_enabled option is set to false, CN codecs are not present in
3502// offer or answer.
3503TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
3504 MediaSessionOptions options;
Steve Anton4e70a722017-11-28 14:57:10 -08003505 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003506 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003507 ASSERT_TRUE(offer.get() != NULL);
3508 const ContentInfo* audio_content = offer->GetContentByName("audio");
3509 EXPECT_FALSE(VerifyNoCNCodecs(audio_content));
3510
3511 options.vad_enabled = false;
Steve Anton6fe1fba2018-12-11 10:15:23 -08003512 offer = f1_.CreateOffer(options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003513 ASSERT_TRUE(offer.get() != NULL);
3514 audio_content = offer->GetContentByName("audio");
3515 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
Steve Anton6fe1fba2018-12-11 10:15:23 -08003516 std::unique_ptr<SessionDescription> answer =
3517 f1_.CreateAnswer(offer.get(), options, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003518 ASSERT_TRUE(answer.get() != NULL);
3519 audio_content = answer->GetContentByName("audio");
3520 EXPECT_TRUE(VerifyNoCNCodecs(audio_content));
3521}
deadbeef44f08192015-12-15 16:20:09 -08003522
zhihuang1c378ed2017-08-17 14:10:50 -07003523// Test that the generated MIDs match the existing offer.
3524TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
deadbeef44f08192015-12-15 16:20:09 -08003525 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003526 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_modified",
3527 RtpTransceiverDirection::kRecvOnly, kActive,
3528 &opts);
3529 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_modified",
3530 RtpTransceiverDirection::kRecvOnly, kActive,
3531 &opts);
deadbeef44f08192015-12-15 16:20:09 -08003532 opts.data_channel_type = cricket::DCT_SCTP;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003533 AddMediaDescriptionOptions(MEDIA_TYPE_DATA, "data_modified",
3534 RtpTransceiverDirection::kSendRecv, kActive,
3535 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003536 // Create offer.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003537 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
kwiberg31022942016-03-11 14:18:21 -08003538 std::unique_ptr<SessionDescription> updated_offer(
deadbeef44f08192015-12-15 16:20:09 -08003539 f1_.CreateOffer(opts, offer.get()));
zhihuang1c378ed2017-08-17 14:10:50 -07003540
deadbeef44f08192015-12-15 16:20:09 -08003541 const ContentInfo* audio_content = GetFirstAudioContent(updated_offer.get());
3542 const ContentInfo* video_content = GetFirstVideoContent(updated_offer.get());
3543 const ContentInfo* data_content = GetFirstDataContent(updated_offer.get());
3544 ASSERT_TRUE(audio_content != nullptr);
3545 ASSERT_TRUE(video_content != nullptr);
3546 ASSERT_TRUE(data_content != nullptr);
3547 EXPECT_EQ("audio_modified", audio_content->name);
3548 EXPECT_EQ("video_modified", video_content->name);
3549 EXPECT_EQ("data_modified", data_content->name);
3550}
zhihuangcf5b37c2016-05-05 11:44:35 -07003551
zhihuang1c378ed2017-08-17 14:10:50 -07003552// The following tests verify that the unified plan SDP is supported.
3553// Test that we can create an offer with multiple media sections of same media
3554// type.
3555TEST_F(MediaSessionDescriptionFactoryTest,
3556 CreateOfferWithMultipleAVMediaSections) {
3557 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003558 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3559 RtpTransceiverDirection::kSendRecv, kActive,
3560 &opts);
3561 AttachSenderToMediaDescriptionOptions(
3562 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003563
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003564 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3565 RtpTransceiverDirection::kSendRecv, kActive,
3566 &opts);
3567 AttachSenderToMediaDescriptionOptions(
3568 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003569
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003570 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3571 RtpTransceiverDirection::kSendRecv, kActive,
3572 &opts);
3573 AttachSenderToMediaDescriptionOptions(
3574 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003575
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003576 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3577 RtpTransceiverDirection::kSendRecv, kActive,
3578 &opts);
3579 AttachSenderToMediaDescriptionOptions(
3580 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003581 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003582 ASSERT_TRUE(offer);
3583
3584 ASSERT_EQ(4u, offer->contents().size());
3585 EXPECT_FALSE(offer->contents()[0].rejected);
3586 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003587 offer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003588 ASSERT_EQ(1u, acd->streams().size());
3589 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003590 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003591
3592 EXPECT_FALSE(offer->contents()[1].rejected);
3593 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003594 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003595 ASSERT_EQ(1u, vcd->streams().size());
3596 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003597 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003598
3599 EXPECT_FALSE(offer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003600 acd = offer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003601 ASSERT_EQ(1u, acd->streams().size());
3602 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003603 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003604
3605 EXPECT_FALSE(offer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003606 vcd = offer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003607 ASSERT_EQ(1u, vcd->streams().size());
3608 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003609 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003610}
3611
3612// Test that we can create an answer with multiple media sections of same media
3613// type.
3614TEST_F(MediaSessionDescriptionFactoryTest,
3615 CreateAnswerWithMultipleAVMediaSections) {
3616 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003617 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_1",
3618 RtpTransceiverDirection::kSendRecv, kActive,
3619 &opts);
3620 AttachSenderToMediaDescriptionOptions(
3621 "audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003622
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003623 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_1",
3624 RtpTransceiverDirection::kSendRecv, kActive,
3625 &opts);
3626 AttachSenderToMediaDescriptionOptions(
3627 "video_1", MEDIA_TYPE_VIDEO, kVideoTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003628
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003629 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio_2",
3630 RtpTransceiverDirection::kSendRecv, kActive,
3631 &opts);
3632 AttachSenderToMediaDescriptionOptions(
3633 "audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003634
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003635 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video_2",
3636 RtpTransceiverDirection::kSendRecv, kActive,
3637 &opts);
3638 AttachSenderToMediaDescriptionOptions(
3639 "video_2", MEDIA_TYPE_VIDEO, kVideoTrack2, {kMediaStream2}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003640
Steve Anton6fe1fba2018-12-11 10:15:23 -08003641 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003642 ASSERT_TRUE(offer);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003643 std::unique_ptr<SessionDescription> answer =
3644 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003645
3646 ASSERT_EQ(4u, answer->contents().size());
3647 EXPECT_FALSE(answer->contents()[0].rejected);
3648 const AudioContentDescription* acd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003649 answer->contents()[0].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003650 ASSERT_EQ(1u, acd->streams().size());
3651 EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003652 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003653
3654 EXPECT_FALSE(answer->contents()[1].rejected);
3655 const VideoContentDescription* vcd =
Steve Antonb1c1de12017-12-21 15:14:30 -08003656 answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003657 ASSERT_EQ(1u, vcd->streams().size());
3658 EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003659 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003660
3661 EXPECT_FALSE(answer->contents()[2].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003662 acd = answer->contents()[2].media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07003663 ASSERT_EQ(1u, acd->streams().size());
3664 EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003665 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003666
3667 EXPECT_FALSE(answer->contents()[3].rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08003668 vcd = answer->contents()[3].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003669 ASSERT_EQ(1u, vcd->streams().size());
3670 EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
Steve Anton4e70a722017-11-28 14:57:10 -08003671 EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
zhihuang1c378ed2017-08-17 14:10:50 -07003672}
3673
3674// Test that the media section will be rejected in offer if the corresponding
3675// MediaDescriptionOptions is stopped by the offerer.
3676TEST_F(MediaSessionDescriptionFactoryTest,
3677 CreateOfferWithMediaSectionStoppedByOfferer) {
3678 // Create an offer with two audio sections and one of them is stopped.
3679 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003680 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3681 RtpTransceiverDirection::kSendRecv, kActive,
3682 &offer_opts);
3683 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3684 RtpTransceiverDirection::kInactive, kStopped,
3685 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003686 std::unique_ptr<SessionDescription> offer =
3687 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003688 ASSERT_TRUE(offer);
3689 ASSERT_EQ(2u, offer->contents().size());
3690 EXPECT_FALSE(offer->contents()[0].rejected);
3691 EXPECT_TRUE(offer->contents()[1].rejected);
3692}
3693
3694// Test that the media section will be rejected in answer if the corresponding
3695// MediaDescriptionOptions is stopped by the offerer.
3696TEST_F(MediaSessionDescriptionFactoryTest,
3697 CreateAnswerWithMediaSectionStoppedByOfferer) {
3698 // Create an offer with two audio sections and one of them is stopped.
3699 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003700 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3701 RtpTransceiverDirection::kSendRecv, kActive,
3702 &offer_opts);
3703 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3704 RtpTransceiverDirection::kInactive, kStopped,
3705 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003706 std::unique_ptr<SessionDescription> offer =
3707 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003708 ASSERT_TRUE(offer);
3709 ASSERT_EQ(2u, offer->contents().size());
3710 EXPECT_FALSE(offer->contents()[0].rejected);
3711 EXPECT_TRUE(offer->contents()[1].rejected);
3712
3713 // Create an answer based on the offer.
3714 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003715 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3716 RtpTransceiverDirection::kSendRecv, kActive,
3717 &answer_opts);
3718 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3719 RtpTransceiverDirection::kSendRecv, kActive,
3720 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003721 std::unique_ptr<SessionDescription> answer =
3722 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003723 ASSERT_EQ(2u, answer->contents().size());
3724 EXPECT_FALSE(answer->contents()[0].rejected);
3725 EXPECT_TRUE(answer->contents()[1].rejected);
3726}
3727
3728// Test that the media section will be rejected in answer if the corresponding
3729// MediaDescriptionOptions is stopped by the answerer.
3730TEST_F(MediaSessionDescriptionFactoryTest,
3731 CreateAnswerWithMediaSectionRejectedByAnswerer) {
3732 // Create an offer with two audio sections.
3733 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003734 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3735 RtpTransceiverDirection::kSendRecv, kActive,
3736 &offer_opts);
3737 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3738 RtpTransceiverDirection::kSendRecv, kActive,
3739 &offer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003740 std::unique_ptr<SessionDescription> offer =
3741 f1_.CreateOffer(offer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003742 ASSERT_TRUE(offer);
3743 ASSERT_EQ(2u, offer->contents().size());
3744 ASSERT_FALSE(offer->contents()[0].rejected);
3745 ASSERT_FALSE(offer->contents()[1].rejected);
3746
3747 // The answerer rejects one of the audio sections.
3748 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003749 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio1",
3750 RtpTransceiverDirection::kSendRecv, kActive,
3751 &answer_opts);
3752 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio2",
3753 RtpTransceiverDirection::kInactive, kStopped,
3754 &answer_opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003755 std::unique_ptr<SessionDescription> answer =
3756 f2_.CreateAnswer(offer.get(), answer_opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003757 ASSERT_EQ(2u, answer->contents().size());
3758 EXPECT_FALSE(answer->contents()[0].rejected);
3759 EXPECT_TRUE(answer->contents()[1].rejected);
Zhi Huang3518e7b2018-01-30 13:20:35 -08003760
3761 // The TransportInfo of the rejected m= section is expected to be added in the
3762 // answer.
3763 EXPECT_EQ(offer->transport_infos().size(), answer->transport_infos().size());
zhihuang1c378ed2017-08-17 14:10:50 -07003764}
3765
3766// Test the generated media sections has the same order of the
3767// corresponding MediaDescriptionOptions.
3768TEST_F(MediaSessionDescriptionFactoryTest,
3769 CreateOfferRespectsMediaDescriptionOptionsOrder) {
3770 MediaSessionOptions opts;
3771 // This tests put video section first because normally audio comes first by
3772 // default.
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003773 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3774 RtpTransceiverDirection::kSendRecv, kActive,
3775 &opts);
3776 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3777 RtpTransceiverDirection::kSendRecv, kActive,
3778 &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003779 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003780
3781 ASSERT_TRUE(offer);
3782 ASSERT_EQ(2u, offer->contents().size());
3783 EXPECT_EQ("video", offer->contents()[0].name);
3784 EXPECT_EQ("audio", offer->contents()[1].name);
3785}
3786
3787// Test that different media sections using the same codec have same payload
3788// type.
3789TEST_F(MediaSessionDescriptionFactoryTest,
3790 PayloadTypesSharedByMediaSectionsOfSameType) {
3791 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003792 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
3793 RtpTransceiverDirection::kSendRecv, kActive,
3794 &opts);
3795 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
3796 RtpTransceiverDirection::kSendRecv, kActive,
3797 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003798 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003799 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003800 ASSERT_TRUE(offer);
3801 ASSERT_EQ(2u, offer->contents().size());
3802 const VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003803 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003804 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003805 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003806 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3807 ASSERT_EQ(2u, vcd1->codecs().size());
3808 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3809 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3810 EXPECT_EQ(vcd1->codecs()[1].name, vcd2->codecs()[1].name);
3811 EXPECT_EQ(vcd1->codecs()[1].id, vcd2->codecs()[1].id);
3812
3813 // Create answer and negotiate the codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003814 std::unique_ptr<SessionDescription> answer =
3815 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003816 ASSERT_TRUE(answer);
3817 ASSERT_EQ(2u, answer->contents().size());
Steve Antonb1c1de12017-12-21 15:14:30 -08003818 vcd1 = answer->contents()[0].media_description()->as_video();
3819 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003820 EXPECT_EQ(vcd1->codecs().size(), vcd2->codecs().size());
3821 ASSERT_EQ(1u, vcd1->codecs().size());
3822 EXPECT_EQ(vcd1->codecs()[0].name, vcd2->codecs()[0].name);
3823 EXPECT_EQ(vcd1->codecs()[0].id, vcd2->codecs()[0].id);
3824}
3825
3826// Test that the codec preference order per media section is respected in
3827// subsequent offer.
3828TEST_F(MediaSessionDescriptionFactoryTest,
3829 CreateOfferRespectsCodecPreferenceOrder) {
3830 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003831 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
3832 RtpTransceiverDirection::kSendRecv, kActive,
3833 &opts);
3834 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
3835 RtpTransceiverDirection::kSendRecv, kActive,
3836 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003837 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003838 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003839 ASSERT_TRUE(offer);
3840 ASSERT_EQ(2u, offer->contents().size());
3841 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003842 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003843 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003844 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003845 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3846 EXPECT_EQ(video_codecs, vcd1->codecs());
3847 EXPECT_EQ(video_codecs, vcd2->codecs());
3848
3849 // Change the codec preference of the first video section and create a
3850 // follow-up offer.
3851 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3852 vcd1->set_codecs(video_codecs_reverse);
3853 std::unique_ptr<SessionDescription> updated_offer(
3854 f1_.CreateOffer(opts, offer.get()));
Steve Antonb1c1de12017-12-21 15:14:30 -08003855 vcd1 = updated_offer->contents()[0].media_description()->as_video();
3856 vcd2 = updated_offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003857 // The video codec preference order should be respected.
3858 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3859 EXPECT_EQ(video_codecs, vcd2->codecs());
3860}
3861
3862// Test that the codec preference order per media section is respected in
3863// the answer.
3864TEST_F(MediaSessionDescriptionFactoryTest,
3865 CreateAnswerRespectsCodecPreferenceOrder) {
3866 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003867 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video1",
3868 RtpTransceiverDirection::kSendRecv, kActive,
3869 &opts);
3870 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video2",
3871 RtpTransceiverDirection::kSendRecv, kActive,
3872 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07003873 // Create an offer with two video sections using same codecs.
Steve Anton6fe1fba2018-12-11 10:15:23 -08003874 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuang1c378ed2017-08-17 14:10:50 -07003875 ASSERT_TRUE(offer);
3876 ASSERT_EQ(2u, offer->contents().size());
3877 VideoContentDescription* vcd1 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003878 offer->contents()[0].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003879 const VideoContentDescription* vcd2 =
Steve Antonb1c1de12017-12-21 15:14:30 -08003880 offer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003881 auto video_codecs = MAKE_VECTOR(kVideoCodecs1);
3882 EXPECT_EQ(video_codecs, vcd1->codecs());
3883 EXPECT_EQ(video_codecs, vcd2->codecs());
3884
3885 // Change the codec preference of the first video section and create an
3886 // answer.
3887 auto video_codecs_reverse = MAKE_VECTOR(kVideoCodecs1Reverse);
3888 vcd1->set_codecs(video_codecs_reverse);
Steve Anton6fe1fba2018-12-11 10:15:23 -08003889 std::unique_ptr<SessionDescription> answer =
3890 f1_.CreateAnswer(offer.get(), opts, nullptr);
Steve Antonb1c1de12017-12-21 15:14:30 -08003891 vcd1 = answer->contents()[0].media_description()->as_video();
3892 vcd2 = answer->contents()[1].media_description()->as_video();
zhihuang1c378ed2017-08-17 14:10:50 -07003893 // The video codec preference order should be respected.
3894 EXPECT_EQ(video_codecs_reverse, vcd1->codecs());
3895 EXPECT_EQ(video_codecs, vcd2->codecs());
3896}
3897
Zhi Huang6f367472017-11-22 13:20:02 -08003898// Test that when creating an answer, the codecs use local parameters instead of
3899// the remote ones.
3900TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerWithLocalCodecParams) {
3901 const std::string audio_param_name = "audio_param";
3902 const std::string audio_value1 = "audio_v1";
3903 const std::string audio_value2 = "audio_v2";
3904 const std::string video_param_name = "video_param";
3905 const std::string video_value1 = "video_v1";
3906 const std::string video_value2 = "video_v2";
3907
3908 auto audio_codecs1 = MAKE_VECTOR(kAudioCodecs1);
3909 auto audio_codecs2 = MAKE_VECTOR(kAudioCodecs1);
3910 auto video_codecs1 = MAKE_VECTOR(kVideoCodecs1);
3911 auto video_codecs2 = MAKE_VECTOR(kVideoCodecs1);
3912
3913 // Set the parameters for codecs.
3914 audio_codecs1[0].SetParam(audio_param_name, audio_value1);
3915 video_codecs1[0].SetParam(video_param_name, video_value1);
3916 audio_codecs2[0].SetParam(audio_param_name, audio_value2);
3917 video_codecs2[0].SetParam(video_param_name, video_value2);
3918
3919 f1_.set_audio_codecs(audio_codecs1, audio_codecs1);
3920 f1_.set_video_codecs(video_codecs1);
3921 f2_.set_audio_codecs(audio_codecs2, audio_codecs2);
3922 f2_.set_video_codecs(video_codecs2);
3923
3924 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003925 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio",
3926 RtpTransceiverDirection::kSendRecv, kActive,
3927 &opts);
3928 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3929 RtpTransceiverDirection::kSendRecv, kActive,
3930 &opts);
Zhi Huang6f367472017-11-22 13:20:02 -08003931
Steve Anton6fe1fba2018-12-11 10:15:23 -08003932 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08003933 ASSERT_TRUE(offer);
Steve Antonb1c1de12017-12-21 15:14:30 -08003934 auto offer_acd = offer->contents()[0].media_description()->as_audio();
3935 auto offer_vcd = offer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08003936 std::string value;
3937 EXPECT_TRUE(offer_acd->codecs()[0].GetParam(audio_param_name, &value));
3938 EXPECT_EQ(audio_value1, value);
3939 EXPECT_TRUE(offer_vcd->codecs()[0].GetParam(video_param_name, &value));
3940 EXPECT_EQ(video_value1, value);
3941
Steve Anton6fe1fba2018-12-11 10:15:23 -08003942 std::unique_ptr<SessionDescription> answer =
3943 f2_.CreateAnswer(offer.get(), opts, nullptr);
Zhi Huang6f367472017-11-22 13:20:02 -08003944 ASSERT_TRUE(answer);
Steve Antonb1c1de12017-12-21 15:14:30 -08003945 auto answer_acd = answer->contents()[0].media_description()->as_audio();
3946 auto answer_vcd = answer->contents()[1].media_description()->as_video();
Zhi Huang6f367472017-11-22 13:20:02 -08003947 // Use the parameters from the local codecs.
3948 EXPECT_TRUE(answer_acd->codecs()[0].GetParam(audio_param_name, &value));
3949 EXPECT_EQ(audio_value2, value);
3950 EXPECT_TRUE(answer_vcd->codecs()[0].GetParam(video_param_name, &value));
3951 EXPECT_EQ(video_value2, value);
3952}
3953
Steve Anton9c1fb1e2018-02-26 15:09:41 -08003954// Test that matching packetization-mode is part of the criteria for matching
3955// H264 codecs (in addition to profile-level-id). Previously, this was not the
3956// case, so the first H264 codec with the same profile-level-id would match and
3957// the payload type in the answer would be incorrect.
3958// This is a regression test for bugs.webrtc.org/8808
3959TEST_F(MediaSessionDescriptionFactoryTest,
3960 H264MatchCriteriaIncludesPacketizationMode) {
3961 // Create two H264 codecs with the same profile level ID and different
3962 // packetization modes.
3963 VideoCodec h264_pm0(96, "H264");
3964 h264_pm0.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
3965 h264_pm0.params[cricket::kH264FmtpPacketizationMode] = "0";
3966 VideoCodec h264_pm1(97, "H264");
3967 h264_pm1.params[cricket::kH264FmtpProfileLevelId] = "42c01f";
3968 h264_pm1.params[cricket::kH264FmtpPacketizationMode] = "1";
3969
3970 // Offerer will send both codecs, answerer should choose the one with matching
3971 // packetization mode (and not the first one it sees).
3972 f1_.set_video_codecs({h264_pm0, h264_pm1});
3973 f2_.set_video_codecs({h264_pm1});
3974
3975 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08003976 AddMediaDescriptionOptions(MEDIA_TYPE_VIDEO, "video",
3977 RtpTransceiverDirection::kSendRecv, kActive,
3978 &opts);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08003979
Steve Anton6fe1fba2018-12-11 10:15:23 -08003980 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08003981 ASSERT_TRUE(offer);
3982
Steve Anton6fe1fba2018-12-11 10:15:23 -08003983 std::unique_ptr<SessionDescription> answer =
3984 f2_.CreateAnswer(offer.get(), opts, nullptr);
Steve Anton9c1fb1e2018-02-26 15:09:41 -08003985 ASSERT_TRUE(answer);
3986
3987 // Answer should have one negotiated codec with packetization-mode=1 using the
3988 // offered payload type.
3989 ASSERT_EQ(1u, answer->contents().size());
3990 auto answer_vcd = answer->contents()[0].media_description()->as_video();
3991 ASSERT_EQ(1u, answer_vcd->codecs().size());
3992 auto answer_codec = answer_vcd->codecs()[0];
3993 EXPECT_EQ(h264_pm1.id, answer_codec.id);
3994}
3995
zhihuangcf5b37c2016-05-05 11:44:35 -07003996class MediaProtocolTest : public ::testing::TestWithParam<const char*> {
3997 public:
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08003998 MediaProtocolTest()
3999 : f1_(&tdf1_, &ssrc_generator1), f2_(&tdf2_, &ssrc_generator2) {
ossu075af922016-06-14 03:29:38 -07004000 f1_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs1),
4001 MAKE_VECTOR(kAudioCodecs1));
zhihuangcf5b37c2016-05-05 11:44:35 -07004002 f1_.set_video_codecs(MAKE_VECTOR(kVideoCodecs1));
4003 f1_.set_data_codecs(MAKE_VECTOR(kDataCodecs1));
ossu075af922016-06-14 03:29:38 -07004004 f2_.set_audio_codecs(MAKE_VECTOR(kAudioCodecs2),
4005 MAKE_VECTOR(kAudioCodecs2));
zhihuangcf5b37c2016-05-05 11:44:35 -07004006 f2_.set_video_codecs(MAKE_VECTOR(kVideoCodecs2));
4007 f2_.set_data_codecs(MAKE_VECTOR(kDataCodecs2));
4008 f1_.set_secure(SEC_ENABLED);
4009 f2_.set_secure(SEC_ENABLED);
4010 tdf1_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004011 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id1"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004012 tdf2_.set_certificate(rtc::RTCCertificate::Create(
kwibergfd8be342016-05-14 19:44:11 -07004013 std::unique_ptr<rtc::SSLIdentity>(new rtc::FakeSSLIdentity("id2"))));
zhihuangcf5b37c2016-05-05 11:44:35 -07004014 tdf1_.set_secure(SEC_ENABLED);
4015 tdf2_.set_secure(SEC_ENABLED);
4016 }
4017
4018 protected:
4019 MediaSessionDescriptionFactory f1_;
4020 MediaSessionDescriptionFactory f2_;
4021 TransportDescriptionFactory tdf1_;
4022 TransportDescriptionFactory tdf2_;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004023 UniqueRandomIdGenerator ssrc_generator1;
4024 UniqueRandomIdGenerator ssrc_generator2;
zhihuangcf5b37c2016-05-05 11:44:35 -07004025};
4026
4027TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
4028 MediaSessionOptions opts;
Steve Anton4e70a722017-11-28 14:57:10 -08004029 AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
Steve Anton6fe1fba2018-12-11 10:15:23 -08004030 std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004031 ASSERT_TRUE(offer.get() != nullptr);
4032 // Set the protocol for all the contents.
4033 for (auto content : offer.get()->contents()) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004034 content.media_description()->set_protocol(GetParam());
zhihuangcf5b37c2016-05-05 11:44:35 -07004035 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004036 std::unique_ptr<SessionDescription> answer =
4037 f2_.CreateAnswer(offer.get(), opts, nullptr);
zhihuangcf5b37c2016-05-05 11:44:35 -07004038 const ContentInfo* ac = answer->GetContentByName("audio");
4039 const ContentInfo* vc = answer->GetContentByName("video");
4040 ASSERT_TRUE(ac != nullptr);
4041 ASSERT_TRUE(vc != nullptr);
4042 EXPECT_FALSE(ac->rejected); // the offer is accepted
4043 EXPECT_FALSE(vc->rejected);
Steve Antonb1c1de12017-12-21 15:14:30 -08004044 const AudioContentDescription* acd = ac->media_description()->as_audio();
4045 const VideoContentDescription* vcd = vc->media_description()->as_video();
zhihuangcf5b37c2016-05-05 11:44:35 -07004046 EXPECT_EQ(GetParam(), acd->protocol());
4047 EXPECT_EQ(GetParam(), vcd->protocol());
4048}
4049
4050INSTANTIATE_TEST_CASE_P(MediaProtocolPatternTest,
4051 MediaProtocolTest,
4052 ::testing::ValuesIn(kMediaProtocols));
4053INSTANTIATE_TEST_CASE_P(MediaProtocolDtlsPatternTest,
4054 MediaProtocolTest,
4055 ::testing::ValuesIn(kMediaProtocolsDtls));
ossu075af922016-06-14 03:29:38 -07004056
4057TEST_F(MediaSessionDescriptionFactoryTest, TestSetAudioCodecs) {
4058 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004059 UniqueRandomIdGenerator ssrc_generator;
4060 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004061 std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4062 std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4063
4064 // The merged list of codecs should contain any send codecs that are also
4065 // nominally in the recieve codecs list. Payload types should be picked from
4066 // the send codecs and a number-of-channels of 0 and 1 should be equivalent
4067 // (set to 1). This equals what happens when the send codecs are used in an
4068 // offer and the receive codecs are used in the following answer.
4069 const std::vector<AudioCodec> sendrecv_codecs =
4070 MAKE_VECTOR(kAudioCodecsAnswer);
4071 const std::vector<AudioCodec> no_codecs;
4072
4073 RTC_CHECK_EQ(send_codecs[1].name, "iLBC")
4074 << "Please don't change shared test data!";
4075 RTC_CHECK_EQ(recv_codecs[2].name, "iLBC")
4076 << "Please don't change shared test data!";
4077 // Alter iLBC send codec to have zero channels, to test that that is handled
4078 // properly.
4079 send_codecs[1].channels = 0;
4080
4081 // Alther iLBC receive codec to be lowercase, to test that case conversions
4082 // are handled properly.
4083 recv_codecs[2].name = "ilbc";
4084
4085 // Test proper merge
4086 sf.set_audio_codecs(send_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004087 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4088 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4089 EXPECT_EQ(sendrecv_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004090
4091 // Test empty send codecs list
4092 sf.set_audio_codecs(no_codecs, recv_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004093 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4094 EXPECT_EQ(recv_codecs, sf.audio_recv_codecs());
4095 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004096
4097 // Test empty recv codecs list
4098 sf.set_audio_codecs(send_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004099 EXPECT_EQ(send_codecs, sf.audio_send_codecs());
4100 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4101 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004102
4103 // Test all empty codec lists
4104 sf.set_audio_codecs(no_codecs, no_codecs);
zhihuang1c378ed2017-08-17 14:10:50 -07004105 EXPECT_EQ(no_codecs, sf.audio_send_codecs());
4106 EXPECT_EQ(no_codecs, sf.audio_recv_codecs());
4107 EXPECT_EQ(no_codecs, sf.audio_sendrecv_codecs());
ossu075af922016-06-14 03:29:38 -07004108}
4109
Amit Hilbuch77938e62018-12-21 09:23:38 -08004110// Checks that the RID extensions are added to the video RTP header extensions.
4111// Note: This test somewhat shows that |set_video_rtp_header_extensions()| is
4112// not very well defined, as calling set() and immediately get() will yield
4113// an object that is not semantically equivalent to the set object.
4114TEST_F(MediaSessionDescriptionFactoryTest, VideoHasRidExtensionsInUnifiedPlan) {
4115 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004116 UniqueRandomIdGenerator ssrc_generator;
4117 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
Amit Hilbuch77938e62018-12-21 09:23:38 -08004118 sf.set_is_unified_plan(true);
4119 cricket::RtpHeaderExtensions extensions;
4120 sf.set_video_rtp_header_extensions(extensions);
4121 cricket::RtpHeaderExtensions result = sf.video_rtp_header_extensions();
4122 // Check to see that RID extensions were added to the extension list
4123 EXPECT_GE(result.size(), 2u);
4124 auto rid_extension = std::find_if(
4125 result.begin(), result.end(), [](const RtpExtension& extension) {
4126 return extension.uri == webrtc::RtpExtension::kRidUri;
4127 });
4128 EXPECT_NE(rid_extension, extensions.end());
4129 auto repaired_rid_extension = std::find_if(
4130 result.begin(), result.end(), [](const RtpExtension& extension) {
4131 return extension.uri == webrtc::RtpExtension::kRepairedRidUri;
4132 });
4133 EXPECT_NE(repaired_rid_extension, extensions.end());
4134}
4135
4136// Checks that the RID extensions are added to the audio RTP header extensions.
4137// Note: This test somewhat shows that |set_audio_rtp_header_extensions()| is
4138// not very well defined, as calling set() and immediately get() will yield
4139// an object that is not semantically equivalent to the set object.
4140TEST_F(MediaSessionDescriptionFactoryTest, AudioHasRidExtensionsInUnifiedPlan) {
4141 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004142 UniqueRandomIdGenerator ssrc_generator;
4143 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
Amit Hilbuch77938e62018-12-21 09:23:38 -08004144 sf.set_is_unified_plan(true);
4145 cricket::RtpHeaderExtensions extensions;
4146 sf.set_audio_rtp_header_extensions(extensions);
4147 cricket::RtpHeaderExtensions result = sf.audio_rtp_header_extensions();
4148 // Check to see that RID extensions were added to the extension list
4149 EXPECT_GE(result.size(), 2u);
4150 auto rid_extension = std::find_if(
4151 result.begin(), result.end(), [](const RtpExtension& extension) {
4152 return extension.uri == webrtc::RtpExtension::kRidUri;
4153 });
4154 EXPECT_NE(rid_extension, extensions.end());
4155 auto repaired_rid_extension = std::find_if(
4156 result.begin(), result.end(), [](const RtpExtension& extension) {
4157 return extension.uri == webrtc::RtpExtension::kRepairedRidUri;
4158 });
4159 EXPECT_NE(repaired_rid_extension, extensions.end());
4160}
4161
ossu075af922016-06-14 03:29:38 -07004162namespace {
zhihuang1c378ed2017-08-17 14:10:50 -07004163// Compare the two vectors of codecs ignoring the payload type.
4164template <class Codec>
4165bool CodecsMatch(const std::vector<Codec>& codecs1,
4166 const std::vector<Codec>& codecs2) {
4167 if (codecs1.size() != codecs2.size()) {
4168 return false;
4169 }
4170
4171 for (size_t i = 0; i < codecs1.size(); ++i) {
4172 if (!codecs1[i].Matches(codecs2[i])) {
4173 return false;
4174 }
4175 }
4176 return true;
4177}
4178
Steve Anton4e70a722017-11-28 14:57:10 -08004179void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
ossu075af922016-06-14 03:29:38 -07004180 TransportDescriptionFactory tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004181 UniqueRandomIdGenerator ssrc_generator;
4182 MediaSessionDescriptionFactory sf(&tdf, &ssrc_generator);
ossu075af922016-06-14 03:29:38 -07004183 const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
4184 const std::vector<AudioCodec> recv_codecs = MAKE_VECTOR(kAudioCodecs2);
4185 const std::vector<AudioCodec> sendrecv_codecs =
4186 MAKE_VECTOR(kAudioCodecsAnswer);
4187 sf.set_audio_codecs(send_codecs, recv_codecs);
ossu075af922016-06-14 03:29:38 -07004188
4189 MediaSessionOptions opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004190 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", direction, kActive,
4191 &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004192
Steve Anton4e70a722017-11-28 14:57:10 -08004193 if (direction == RtpTransceiverDirection::kSendRecv ||
4194 direction == RtpTransceiverDirection::kSendOnly) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004195 AttachSenderToMediaDescriptionOptions(
4196 "audio", MEDIA_TYPE_AUDIO, kAudioTrack1, {kMediaStream1}, 1, &opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004197 }
ossu075af922016-06-14 03:29:38 -07004198
Steve Anton6fe1fba2018-12-11 10:15:23 -08004199 std::unique_ptr<SessionDescription> offer = sf.CreateOffer(opts, NULL);
ossu075af922016-06-14 03:29:38 -07004200 ASSERT_TRUE(offer.get() != NULL);
Steve Antonb1c1de12017-12-21 15:14:30 -08004201 ContentInfo* ac = offer->GetContentByName("audio");
ossu075af922016-06-14 03:29:38 -07004202
4203 // If the factory didn't add any audio content to the offer, we cannot check
zhihuang1c378ed2017-08-17 14:10:50 -07004204 // that the codecs put in are right. This happens when we neither want to
4205 // send nor receive audio. The checks are still in place if at some point
4206 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004207 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004208 AudioContentDescription* acd = ac->media_description()->as_audio();
zhihuang1c378ed2017-08-17 14:10:50 -07004209 // sendrecv and inactive should both present lists as if the channel was
4210 // to be used for sending and receiving. Inactive essentially means it
4211 // might eventually be used anything, but we don't know more at this
4212 // moment.
Steve Anton4e70a722017-11-28 14:57:10 -08004213 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004214 EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
Steve Anton4e70a722017-11-28 14:57:10 -08004215 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004216 EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004217 } else {
zhihuang1c378ed2017-08-17 14:10:50 -07004218 EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
ossu075af922016-06-14 03:29:38 -07004219 }
4220 }
4221}
4222
4223static const AudioCodec kOfferAnswerCodecs[] = {
zhihuang1c378ed2017-08-17 14:10:50 -07004224 AudioCodec(0, "codec0", 16000, -1, 1),
4225 AudioCodec(1, "codec1", 8000, 13300, 1),
4226 AudioCodec(2, "codec2", 8000, 64000, 1),
4227 AudioCodec(3, "codec3", 8000, 64000, 1),
4228 AudioCodec(4, "codec4", 8000, 0, 2),
4229 AudioCodec(5, "codec5", 32000, 0, 1),
4230 AudioCodec(6, "codec6", 48000, 0, 1)};
ossu075af922016-06-14 03:29:38 -07004231
zhihuang1c378ed2017-08-17 14:10:50 -07004232/* The codecs groups below are chosen as per the matrix below. The objective
4233 * is to have different sets of codecs in the inputs, to get unique sets of
4234 * codecs after negotiation, depending on offer and answer communication
4235 * directions. One-way directions in the offer should either result in the
4236 * opposite direction in the answer, or an inactive answer. Regardless, the
4237 * choice of codecs should be as if the answer contained the opposite
4238 * direction. Inactive offers should be treated as sendrecv/sendrecv.
ossu075af922016-06-14 03:29:38 -07004239 *
4240 * | Offer | Answer | Result
4241 * codec|send recv sr | send recv sr | s/r r/s sr/s sr/r sr/sr
4242 * 0 | x - - | - x - | x - - - -
4243 * 1 | x x x | - x - | x - - x -
4244 * 2 | - x - | x - - | - x - - -
4245 * 3 | x x x | x - - | - x x - -
4246 * 4 | - x - | x x x | - x - - -
4247 * 5 | x - - | x x x | x - - - -
4248 * 6 | x x x | x x x | x x x x x
4249 */
4250// Codecs used by offerer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004251static const int kOfferSendCodecs[] = {0, 1, 3, 5, 6};
4252static const int kOfferRecvCodecs[] = {1, 2, 3, 4, 6};
ossu075af922016-06-14 03:29:38 -07004253// Codecs used in the answerer in the AudioCodecsAnswerTest. The order is
4254// jumbled to catch the answer not following the order in the offer.
zhihuang1c378ed2017-08-17 14:10:50 -07004255static const int kAnswerSendCodecs[] = {6, 5, 2, 3, 4};
4256static const int kAnswerRecvCodecs[] = {6, 5, 4, 1, 0};
ossu075af922016-06-14 03:29:38 -07004257// The resulting sets of codecs in the answer in the AudioCodecsAnswerTest
zhihuang1c378ed2017-08-17 14:10:50 -07004258static const int kResultSend_RecvCodecs[] = {0, 1, 5, 6};
4259static const int kResultRecv_SendCodecs[] = {2, 3, 4, 6};
4260static const int kResultSendrecv_SendCodecs[] = {3, 6};
4261static const int kResultSendrecv_RecvCodecs[] = {1, 6};
4262static const int kResultSendrecv_SendrecvCodecs[] = {6};
ossu075af922016-06-14 03:29:38 -07004263
4264template <typename T, int IDXS>
4265std::vector<T> VectorFromIndices(const T* array, const int (&indices)[IDXS]) {
4266 std::vector<T> out;
4267 out.reserve(IDXS);
4268 for (int idx : indices)
4269 out.push_back(array[idx]);
4270
4271 return out;
4272}
4273
Steve Anton4e70a722017-11-28 14:57:10 -08004274void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
4275 RtpTransceiverDirection answer_direction,
ossu075af922016-06-14 03:29:38 -07004276 bool add_legacy_stream) {
4277 TransportDescriptionFactory offer_tdf;
4278 TransportDescriptionFactory answer_tdf;
Amit Hilbuchbcd39d42019-01-25 17:13:56 -08004279 UniqueRandomIdGenerator ssrc_generator1, ssrc_generator2;
4280 MediaSessionDescriptionFactory offer_factory(&offer_tdf, &ssrc_generator1);
4281 MediaSessionDescriptionFactory answer_factory(&answer_tdf, &ssrc_generator2);
ossu075af922016-06-14 03:29:38 -07004282 offer_factory.set_audio_codecs(
4283 VectorFromIndices(kOfferAnswerCodecs, kOfferSendCodecs),
4284 VectorFromIndices(kOfferAnswerCodecs, kOfferRecvCodecs));
4285 answer_factory.set_audio_codecs(
4286 VectorFromIndices(kOfferAnswerCodecs, kAnswerSendCodecs),
4287 VectorFromIndices(kOfferAnswerCodecs, kAnswerRecvCodecs));
4288
ossu075af922016-06-14 03:29:38 -07004289 MediaSessionOptions offer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004290 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", offer_direction,
4291 kActive, &offer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004292
Steve Anton4e70a722017-11-28 14:57:10 -08004293 if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004294 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4295 kAudioTrack1, {kMediaStream1}, 1,
4296 &offer_opts);
ossu075af922016-06-14 03:29:38 -07004297 }
4298
Steve Anton6fe1fba2018-12-11 10:15:23 -08004299 std::unique_ptr<SessionDescription> offer =
4300 offer_factory.CreateOffer(offer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004301 ASSERT_TRUE(offer.get() != NULL);
4302
4303 MediaSessionOptions answer_opts;
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004304 AddMediaDescriptionOptions(MEDIA_TYPE_AUDIO, "audio", answer_direction,
4305 kActive, &answer_opts);
zhihuang1c378ed2017-08-17 14:10:50 -07004306
Steve Anton4e70a722017-11-28 14:57:10 -08004307 if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
Amit Hilbuchc63ddb22019-01-02 10:13:58 -08004308 AttachSenderToMediaDescriptionOptions("audio", MEDIA_TYPE_AUDIO,
4309 kAudioTrack1, {kMediaStream1}, 1,
4310 &answer_opts);
ossu075af922016-06-14 03:29:38 -07004311 }
Steve Anton6fe1fba2018-12-11 10:15:23 -08004312 std::unique_ptr<SessionDescription> answer =
4313 answer_factory.CreateAnswer(offer.get(), answer_opts, NULL);
ossu075af922016-06-14 03:29:38 -07004314 const ContentInfo* ac = answer->GetContentByName("audio");
4315
zhihuang1c378ed2017-08-17 14:10:50 -07004316 // If the factory didn't add any audio content to the answer, we cannot
4317 // check that the codecs put in are right. This happens when we neither want
4318 // to send nor receive audio. The checks are still in place if at some point
4319 // we'd instead create an inactive stream.
ossu075af922016-06-14 03:29:38 -07004320 if (ac) {
Steve Antonb1c1de12017-12-21 15:14:30 -08004321 ASSERT_EQ(MEDIA_TYPE_AUDIO, ac->media_description()->type());
4322 const AudioContentDescription* acd = ac->media_description()->as_audio();
ossu075af922016-06-14 03:29:38 -07004323
ossu075af922016-06-14 03:29:38 -07004324 std::vector<AudioCodec> target_codecs;
4325 // For offers with sendrecv or inactive, we should never reply with more
4326 // codecs than offered, with these codec sets.
4327 switch (offer_direction) {
Steve Anton4e70a722017-11-28 14:57:10 -08004328 case RtpTransceiverDirection::kInactive:
ossu075af922016-06-14 03:29:38 -07004329 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4330 kResultSendrecv_SendrecvCodecs);
4331 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004332 case RtpTransceiverDirection::kSendOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004333 target_codecs =
4334 VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004335 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004336 case RtpTransceiverDirection::kRecvOnly:
zhihuang1c378ed2017-08-17 14:10:50 -07004337 target_codecs =
4338 VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
ossu075af922016-06-14 03:29:38 -07004339 break;
Steve Anton4e70a722017-11-28 14:57:10 -08004340 case RtpTransceiverDirection::kSendRecv:
4341 if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004342 target_codecs =
4343 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
Steve Anton4e70a722017-11-28 14:57:10 -08004344 } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
zhihuang1c378ed2017-08-17 14:10:50 -07004345 target_codecs =
4346 VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
ossu075af922016-06-14 03:29:38 -07004347 } else {
4348 target_codecs = VectorFromIndices(kOfferAnswerCodecs,
4349 kResultSendrecv_SendrecvCodecs);
4350 }
4351 break;
4352 }
4353
zhihuang1c378ed2017-08-17 14:10:50 -07004354 auto format_codecs = [](const std::vector<AudioCodec>& codecs) {
Jonas Olsson366a50c2018-09-06 13:41:30 +02004355 rtc::StringBuilder os;
ossu075af922016-06-14 03:29:38 -07004356 bool first = true;
4357 os << "{";
4358 for (const auto& c : codecs) {
4359 os << (first ? " " : ", ") << c.id;
4360 first = false;
4361 }
4362 os << " }";
Jonas Olsson84df1c72018-09-14 16:59:32 +02004363 return os.Release();
ossu075af922016-06-14 03:29:38 -07004364 };
4365
4366 EXPECT_TRUE(acd->codecs() == target_codecs)
4367 << "Expected: " << format_codecs(target_codecs)
Steve Anton4e70a722017-11-28 14:57:10 -08004368 << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
4369 << webrtc::RtpTransceiverDirectionToString(offer_direction)
ossu075af922016-06-14 03:29:38 -07004370 << ", answerer wants: "
Steve Anton4e70a722017-11-28 14:57:10 -08004371 << webrtc::RtpTransceiverDirectionToString(answer_direction)
4372 << "; got: "
4373 << webrtc::RtpTransceiverDirectionToString(acd->direction());
ossu075af922016-06-14 03:29:38 -07004374 } else {
Steve Anton4e70a722017-11-28 14:57:10 -08004375 EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
zhihuang1c378ed2017-08-17 14:10:50 -07004376 << "Only inactive offers are allowed to not generate any audio "
4377 "content";
ossu075af922016-06-14 03:29:38 -07004378 }
4379}
brandtr03d5fb12016-11-22 03:37:59 -08004380
4381} // namespace
ossu075af922016-06-14 03:29:38 -07004382
4383class AudioCodecsOfferTest
Steve Anton4e70a722017-11-28 14:57:10 -08004384 : public ::testing::TestWithParam<RtpTransceiverDirection> {};
ossu075af922016-06-14 03:29:38 -07004385
4386TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
zhihuang1c378ed2017-08-17 14:10:50 -07004387 TestAudioCodecsOffer(GetParam());
ossu075af922016-06-14 03:29:38 -07004388}
4389
4390INSTANTIATE_TEST_CASE_P(MediaSessionDescriptionFactoryTest,
4391 AudioCodecsOfferTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004392 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4393 RtpTransceiverDirection::kRecvOnly,
4394 RtpTransceiverDirection::kSendRecv,
4395 RtpTransceiverDirection::kInactive));
ossu075af922016-06-14 03:29:38 -07004396
4397class AudioCodecsAnswerTest
Steve Anton4e70a722017-11-28 14:57:10 -08004398 : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
4399 RtpTransceiverDirection,
zhihuang1c378ed2017-08-17 14:10:50 -07004400 bool>> {};
ossu075af922016-06-14 03:29:38 -07004401
4402TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
ehmaldonadoabcef5d2017-02-08 04:07:11 -08004403 TestAudioCodecsAnswer(::testing::get<0>(GetParam()),
4404 ::testing::get<1>(GetParam()),
4405 ::testing::get<2>(GetParam()));
ossu075af922016-06-14 03:29:38 -07004406}
4407
zhihuang1c378ed2017-08-17 14:10:50 -07004408INSTANTIATE_TEST_CASE_P(
4409 MediaSessionDescriptionFactoryTest,
4410 AudioCodecsAnswerTest,
Steve Anton4e70a722017-11-28 14:57:10 -08004411 ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
4412 RtpTransceiverDirection::kRecvOnly,
4413 RtpTransceiverDirection::kSendRecv,
4414 RtpTransceiverDirection::kInactive),
4415 ::testing::Values(RtpTransceiverDirection::kSendOnly,
4416 RtpTransceiverDirection::kRecvOnly,
4417 RtpTransceiverDirection::kSendRecv,
4418 RtpTransceiverDirection::kInactive),
zhihuang1c378ed2017-08-17 14:10:50 -07004419 ::testing::Bool()));