blob: 4973aed7b381d0244a58045f2ba9dd435bdb5f33 [file] [log] [blame]
Steve Anton8d3444d2017-10-20 15:30:51 -07001/*
2 * Copyright 2017 The WebRTC project authors. All Rights Reserved.
3 *
4 * 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.
9 */
10
11// This file contains tests that check the interaction between the
12// PeerConnection and the underlying media engine, as well as tests that check
13// the media-related aspects of SDP.
14
Harald Alvestrandc24a2182022-02-23 13:44:59 +000015#include <algorithm>
16#include <functional>
17#include <iterator>
18#include <map>
Mirko Bonadei317a1f02019-09-17 17:06:18 +020019#include <memory>
Taylor Brandstetterf7fcfb72021-09-09 13:39:38 -070020#include <set>
Harald Alvestrandc24a2182022-02-23 13:44:59 +000021#include <string>
Steve Anton8d3444d2017-10-20 15:30:51 -070022#include <tuple>
Harald Alvestrandc24a2182022-02-23 13:44:59 +000023#include <type_traits>
24#include <utility>
25#include <vector>
Steve Anton8d3444d2017-10-20 15:30:51 -070026
Steve Anton64b626b2019-01-28 17:25:26 -080027#include "absl/algorithm/container.h"
Mirta Dvornicic479a3c02019-06-04 15:38:50 +020028#include "absl/types/optional.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000029#include "api/audio_options.h"
Steve Anton10542f22019-01-11 09:11:00 -080030#include "api/call/call_factory_interface.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000031#include "api/jsep.h"
32#include "api/media_types.h"
33#include "api/peer_connection_interface.h"
34#include "api/rtc_error.h"
Danil Chapovalov9da25bd2019-06-20 10:19:42 +020035#include "api/rtc_event_log/rtc_event_log_factory.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000036#include "api/rtc_event_log/rtc_event_log_factory_interface.h"
37#include "api/rtp_parameters.h"
38#include "api/rtp_sender_interface.h"
39#include "api/rtp_transceiver_direction.h"
40#include "api/rtp_transceiver_interface.h"
41#include "api/scoped_refptr.h"
Danil Chapovalov9da25bd2019-06-20 10:19:42 +020042#include "api/task_queue/default_task_queue_factory.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000043#include "api/task_queue/task_queue_factory.h"
44#include "media/base/codec.h"
Steve Anton10542f22019-01-11 09:11:00 -080045#include "media/base/fake_media_engine.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000046#include "media/base/media_constants.h"
47#include "media/base/media_engine.h"
48#include "media/base/stream_params.h"
Steve Anton10542f22019-01-11 09:11:00 -080049#include "p2p/base/fake_port_allocator.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000050#include "p2p/base/p2p_constants.h"
51#include "p2p/base/port_allocator.h"
52#include "p2p/base/transport_info.h"
Steve Anton10542f22019-01-11 09:11:00 -080053#include "pc/media_session.h"
54#include "pc/peer_connection_wrapper.h"
55#include "pc/rtp_media_utils.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000056#include "pc/session_description.h"
57#include "pc/test/mock_peer_connection_observers.h"
58#include "rtc_base/checks.h"
59#include "rtc_base/rtc_certificate_generator.h"
60#include "rtc_base/thread.h"
61#include "test/gtest.h"
Steve Anton8d3444d2017-10-20 15:30:51 -070062#ifdef WEBRTC_ANDROID
Steve Anton10542f22019-01-11 09:11:00 -080063#include "pc/test/android_test_initializer.h"
Steve Anton8d3444d2017-10-20 15:30:51 -070064#endif
Steve Anton8d3444d2017-10-20 15:30:51 -070065#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 09:11:00 -080066#include "rtc_base/virtual_socket_server.h"
Steve Anton8d3444d2017-10-20 15:30:51 -070067#include "test/gmock.h"
68
69namespace webrtc {
70
71using cricket::FakeMediaEngine;
72using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
73using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
74using ::testing::Bool;
75using ::testing::Combine;
Steve Anton8d3444d2017-10-20 15:30:51 -070076using ::testing::ElementsAre;
Jonas Olssona4d87372019-07-05 19:08:33 +020077using ::testing::Values;
Steve Anton8d3444d2017-10-20 15:30:51 -070078
79class PeerConnectionWrapperForMediaTest : public PeerConnectionWrapper {
80 public:
81 using PeerConnectionWrapper::PeerConnectionWrapper;
82
83 FakeMediaEngine* media_engine() { return media_engine_; }
84 void set_media_engine(FakeMediaEngine* media_engine) {
85 media_engine_ = media_engine;
86 }
87
88 private:
89 FakeMediaEngine* media_engine_;
90};
91
Steve Antonad7bffc2018-01-22 10:21:56 -080092class PeerConnectionMediaBaseTest : public ::testing::Test {
Steve Anton8d3444d2017-10-20 15:30:51 -070093 protected:
94 typedef std::unique_ptr<PeerConnectionWrapperForMediaTest> WrapperPtr;
95
Steve Antonad7bffc2018-01-22 10:21:56 -080096 explicit PeerConnectionMediaBaseTest(SdpSemantics sdp_semantics)
97 : vss_(new rtc::VirtualSocketServer()),
98 main_(vss_.get()),
99 sdp_semantics_(sdp_semantics) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700100#ifdef WEBRTC_ANDROID
101 InitializeAndroidObjects();
102#endif
103 }
104
105 WrapperPtr CreatePeerConnection() {
106 return CreatePeerConnection(RTCConfiguration());
107 }
108
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200109 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200110 return CreatePeerConnection(config, std::make_unique<FakeMediaEngine>());
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200111 }
112
113 WrapperPtr CreatePeerConnection(
114 std::unique_ptr<FakeMediaEngine> media_engine) {
115 return CreatePeerConnection(RTCConfiguration(), std::move(media_engine));
116 }
117
Anton Sukhanov98a462c2018-10-17 13:15:42 -0700118 // Creates PeerConnectionFactory and PeerConnection for given configuration.
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200119 WrapperPtr CreatePeerConnection(
120 const RTCConfiguration& config,
121 std::unique_ptr<FakeMediaEngine> media_engine) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700122 auto* media_engine_ptr = media_engine.get();
Anton Sukhanov98a462c2018-10-17 13:15:42 -0700123
124 PeerConnectionFactoryDependencies factory_dependencies;
125
126 factory_dependencies.network_thread = rtc::Thread::Current();
127 factory_dependencies.worker_thread = rtc::Thread::Current();
128 factory_dependencies.signaling_thread = rtc::Thread::Current();
Danil Chapovalov9da25bd2019-06-20 10:19:42 +0200129 factory_dependencies.task_queue_factory = CreateDefaultTaskQueueFactory();
Anton Sukhanov98a462c2018-10-17 13:15:42 -0700130 factory_dependencies.media_engine = std::move(media_engine);
131 factory_dependencies.call_factory = CreateCallFactory();
Danil Chapovalov9da25bd2019-06-20 10:19:42 +0200132 factory_dependencies.event_log_factory =
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200133 std::make_unique<RtcEventLogFactory>(
Danil Chapovalov9da25bd2019-06-20 10:19:42 +0200134 factory_dependencies.task_queue_factory.get());
Anton Sukhanov98a462c2018-10-17 13:15:42 -0700135
136 auto pc_factory =
137 CreateModularPeerConnectionFactory(std::move(factory_dependencies));
Steve Anton8d3444d2017-10-20 15:30:51 -0700138
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200139 auto fake_port_allocator = std::make_unique<cricket::FakePortAllocator>(
Steve Anton8d3444d2017-10-20 15:30:51 -0700140 rtc::Thread::Current(), nullptr);
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200141 auto observer = std::make_unique<MockPeerConnectionObserver>();
Steve Antonad7bffc2018-01-22 10:21:56 -0800142 auto modified_config = config;
143 modified_config.sdp_semantics = sdp_semantics_;
Florent Castelli72424402022-04-06 03:45:10 +0200144 PeerConnectionDependencies pc_dependencies(observer.get());
145 pc_dependencies.allocator = std::move(fake_port_allocator);
146 auto result = pc_factory->CreatePeerConnectionOrError(
147 modified_config, std::move(pc_dependencies));
148 if (!result.ok()) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700149 return nullptr;
150 }
151
Florent Castelli72424402022-04-06 03:45:10 +0200152 auto pc = result.MoveValue();
Yves Gerey4e933292018-10-31 15:36:05 +0100153 observer->SetPeerConnectionInterface(pc.get());
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200154 auto wrapper = std::make_unique<PeerConnectionWrapperForMediaTest>(
Steve Anton8d3444d2017-10-20 15:30:51 -0700155 pc_factory, pc, std::move(observer));
156 wrapper->set_media_engine(media_engine_ptr);
157 return wrapper;
158 }
159
160 // Accepts the same arguments as CreatePeerConnection and adds default audio
Piotr (Peter) Slatala10aeb2a2018-11-14 10:57:24 -0800161 // track (but no video).
162 template <typename... Args>
163 WrapperPtr CreatePeerConnectionWithAudio(Args&&... args) {
164 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
165 if (!wrapper) {
166 return nullptr;
167 }
168 wrapper->AddAudioTrack("a");
169 return wrapper;
170 }
171
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200172 // Accepts the same arguments as CreatePeerConnection and adds default video
173 // track (but no audio).
174 template <typename... Args>
175 WrapperPtr CreatePeerConnectionWithVideo(Args&&... args) {
176 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
177 if (!wrapper) {
178 return nullptr;
179 }
180 wrapper->AddVideoTrack("v");
181 return wrapper;
182 }
183
Piotr (Peter) Slatala10aeb2a2018-11-14 10:57:24 -0800184 // Accepts the same arguments as CreatePeerConnection and adds default audio
Steve Anton8d3444d2017-10-20 15:30:51 -0700185 // and video tracks.
186 template <typename... Args>
187 WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
188 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
189 if (!wrapper) {
190 return nullptr;
191 }
192 wrapper->AddAudioTrack("a");
193 wrapper->AddVideoTrack("v");
194 return wrapper;
195 }
196
Steve Anton4e70a722017-11-28 14:57:10 -0800197 RtpTransceiverDirection GetMediaContentDirection(
Steve Anton8d3444d2017-10-20 15:30:51 -0700198 const SessionDescriptionInterface* sdesc,
Steve Antonad7bffc2018-01-22 10:21:56 -0800199 cricket::MediaType media_type) {
200 auto* content =
201 cricket::GetFirstMediaContent(sdesc->description(), media_type);
202 RTC_DCHECK(content);
203 return content->media_description()->direction();
204 }
205
206 bool IsUnifiedPlan() const {
207 return sdp_semantics_ == SdpSemantics::kUnifiedPlan;
Steve Anton8d3444d2017-10-20 15:30:51 -0700208 }
209
210 std::unique_ptr<rtc::VirtualSocketServer> vss_;
211 rtc::AutoSocketServerThread main_;
Steve Antonad7bffc2018-01-22 10:21:56 -0800212 const SdpSemantics sdp_semantics_;
Steve Anton8d3444d2017-10-20 15:30:51 -0700213};
214
Steve Antonad7bffc2018-01-22 10:21:56 -0800215class PeerConnectionMediaTest
216 : public PeerConnectionMediaBaseTest,
217 public ::testing::WithParamInterface<SdpSemantics> {
218 protected:
219 PeerConnectionMediaTest() : PeerConnectionMediaBaseTest(GetParam()) {}
220};
221
222class PeerConnectionMediaTestUnifiedPlan : public PeerConnectionMediaBaseTest {
223 protected:
224 PeerConnectionMediaTestUnifiedPlan()
225 : PeerConnectionMediaBaseTest(SdpSemantics::kUnifiedPlan) {}
226};
227
228class PeerConnectionMediaTestPlanB : public PeerConnectionMediaBaseTest {
229 protected:
230 PeerConnectionMediaTestPlanB()
Florent Castelli15a38de2022-04-06 00:38:21 +0200231 : PeerConnectionMediaBaseTest(SdpSemantics::kPlanB_DEPRECATED) {}
Steve Antonad7bffc2018-01-22 10:21:56 -0800232};
233
234TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700235 FailToSetRemoteDescriptionIfCreateMediaChannelFails) {
236 auto caller = CreatePeerConnectionWithAudioVideo();
237 auto callee = CreatePeerConnectionWithAudioVideo();
238 callee->media_engine()->set_fail_create_channel(true);
239
240 std::string error;
241 ASSERT_FALSE(callee->SetRemoteDescription(caller->CreateOffer(), &error));
Steve Antonad7bffc2018-01-22 10:21:56 -0800242 EXPECT_PRED_FORMAT2(AssertStartsWith, error,
243 "Failed to set remote offer sdp: Failed to create");
Steve Anton8d3444d2017-10-20 15:30:51 -0700244}
245
Steve Antonad7bffc2018-01-22 10:21:56 -0800246TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700247 FailToSetLocalDescriptionIfCreateMediaChannelFails) {
248 auto caller = CreatePeerConnectionWithAudioVideo();
249 caller->media_engine()->set_fail_create_channel(true);
250
251 std::string error;
252 ASSERT_FALSE(caller->SetLocalDescription(caller->CreateOffer(), &error));
Steve Antonad7bffc2018-01-22 10:21:56 -0800253 EXPECT_PRED_FORMAT2(AssertStartsWith, error,
254 "Failed to set local offer sdp: Failed to create");
Steve Anton8d3444d2017-10-20 15:30:51 -0700255}
256
257std::vector<std::string> GetIds(
258 const std::vector<cricket::StreamParams>& streams) {
259 std::vector<std::string> ids;
Mirko Bonadei649a4c22019-01-29 10:11:53 +0100260 ids.reserve(streams.size());
Steve Anton8d3444d2017-10-20 15:30:51 -0700261 for (const auto& stream : streams) {
262 ids.push_back(stream.id);
263 }
264 return ids;
265}
266
267// Test that exchanging an offer and answer with each side having an audio and
268// video stream creates the appropriate send/recv streams in the underlying
269// media engine on both sides.
Steve Antonad7bffc2018-01-22 10:21:56 -0800270TEST_P(PeerConnectionMediaTest, AudioVideoOfferAnswerCreateSendRecvStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700271 const std::string kCallerAudioId = "caller_a";
272 const std::string kCallerVideoId = "caller_v";
273 const std::string kCalleeAudioId = "callee_a";
274 const std::string kCalleeVideoId = "callee_v";
275
276 auto caller = CreatePeerConnection();
277 caller->AddAudioTrack(kCallerAudioId);
278 caller->AddVideoTrack(kCallerVideoId);
279
280 auto callee = CreatePeerConnection();
281 callee->AddAudioTrack(kCalleeAudioId);
282 callee->AddVideoTrack(kCalleeVideoId);
283
284 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
285 ASSERT_TRUE(
286 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
287
288 auto* caller_voice = caller->media_engine()->GetVoiceChannel(0);
289 EXPECT_THAT(GetIds(caller_voice->recv_streams()),
290 ElementsAre(kCalleeAudioId));
291 EXPECT_THAT(GetIds(caller_voice->send_streams()),
292 ElementsAre(kCallerAudioId));
293
294 auto* caller_video = caller->media_engine()->GetVideoChannel(0);
295 EXPECT_THAT(GetIds(caller_video->recv_streams()),
296 ElementsAre(kCalleeVideoId));
297 EXPECT_THAT(GetIds(caller_video->send_streams()),
298 ElementsAre(kCallerVideoId));
299
300 auto* callee_voice = callee->media_engine()->GetVoiceChannel(0);
301 EXPECT_THAT(GetIds(callee_voice->recv_streams()),
302 ElementsAre(kCallerAudioId));
303 EXPECT_THAT(GetIds(callee_voice->send_streams()),
304 ElementsAre(kCalleeAudioId));
305
306 auto* callee_video = callee->media_engine()->GetVideoChannel(0);
307 EXPECT_THAT(GetIds(callee_video->recv_streams()),
308 ElementsAre(kCallerVideoId));
309 EXPECT_THAT(GetIds(callee_video->send_streams()),
310 ElementsAre(kCalleeVideoId));
311}
312
Steve Antonad7bffc2018-01-22 10:21:56 -0800313// Test that stopping the caller transceivers causes the media channels on the
314// callee to be destroyed after calling SetRemoteDescription on the generated
315// offer.
316// See next test for equivalent behavior with Plan B semantics.
317TEST_F(PeerConnectionMediaTestUnifiedPlan,
318 StoppedRemoteTransceiversRemovesMediaChannels) {
319 auto caller = CreatePeerConnectionWithAudioVideo();
320 auto callee = CreatePeerConnection();
321
322 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
323
324 // Stop both audio and video transceivers on the caller.
325 auto transceivers = caller->pc()->GetTransceivers();
326 ASSERT_EQ(2u, transceivers.size());
Harald Alvestrand6060df52020-08-11 09:54:02 +0200327 transceivers[0]->StopInternal();
328 transceivers[1]->StopInternal();
Steve Antonad7bffc2018-01-22 10:21:56 -0800329
330 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
331
332 ASSERT_FALSE(callee->media_engine()->GetVoiceChannel(0));
333 ASSERT_FALSE(callee->media_engine()->GetVideoChannel(0));
334}
335
Steve Anton8d3444d2017-10-20 15:30:51 -0700336// Test that removing streams from a subsequent offer causes the receive streams
337// on the callee to be removed.
Steve Antonad7bffc2018-01-22 10:21:56 -0800338// See previous test for equivalent behavior with Unified Plan semantics.
339TEST_F(PeerConnectionMediaTestPlanB, EmptyRemoteOfferRemovesRecvStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700340 auto caller = CreatePeerConnection();
341 auto caller_audio_track = caller->AddAudioTrack("a");
342 auto caller_video_track = caller->AddVideoTrack("v");
343 auto callee = CreatePeerConnectionWithAudioVideo();
344
Steve Antonad7bffc2018-01-22 10:21:56 -0800345 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700346
347 // Remove both tracks from caller.
Harald Alvestrand93dd7632022-01-19 12:28:45 +0000348 caller->pc()->RemoveTrackOrError(caller_audio_track);
349 caller->pc()->RemoveTrackOrError(caller_video_track);
Steve Anton8d3444d2017-10-20 15:30:51 -0700350
Steve Antonad7bffc2018-01-22 10:21:56 -0800351 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700352
353 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
Steve Antonad7bffc2018-01-22 10:21:56 -0800354 auto callee_video = callee->media_engine()->GetVideoChannel(0);
Steve Anton8d3444d2017-10-20 15:30:51 -0700355 EXPECT_EQ(1u, callee_voice->send_streams().size());
356 EXPECT_EQ(0u, callee_voice->recv_streams().size());
Steve Anton8d3444d2017-10-20 15:30:51 -0700357 EXPECT_EQ(1u, callee_video->send_streams().size());
358 EXPECT_EQ(0u, callee_video->recv_streams().size());
359}
360
Jonas Orelandfc1acd22018-08-24 10:58:37 +0200361// Test enabling of simulcast with Plan B semantics.
362// This test creating an offer.
363TEST_F(PeerConnectionMediaTestPlanB, SimulcastOffer) {
364 auto caller = CreatePeerConnection();
365 auto caller_video_track = caller->AddVideoTrack("v");
366 RTCOfferAnswerOptions options;
367 options.num_simulcast_layers = 3;
368 auto offer = caller->CreateOffer(options);
Jonas Olssona4d87372019-07-05 19:08:33 +0200369 auto* description = cricket::GetFirstMediaContent(offer->description(),
370 cricket::MEDIA_TYPE_VIDEO)
371 ->media_description();
Jonas Orelandfc1acd22018-08-24 10:58:37 +0200372 ASSERT_EQ(1u, description->streams().size());
373 ASSERT_TRUE(description->streams()[0].get_ssrc_group("SIM"));
374 EXPECT_EQ(3u, description->streams()[0].get_ssrc_group("SIM")->ssrcs.size());
375
376 // Check that it actually creates simulcast aswell.
377 caller->SetLocalDescription(std::move(offer));
378 auto senders = caller->pc()->GetSenders();
379 ASSERT_EQ(1u, senders.size());
380 EXPECT_EQ(cricket::MediaType::MEDIA_TYPE_VIDEO, senders[0]->media_type());
381 EXPECT_EQ(3u, senders[0]->GetParameters().encodings.size());
382}
383
384// Test enabling of simulcast with Plan B semantics.
385// This test creating an answer.
386TEST_F(PeerConnectionMediaTestPlanB, SimulcastAnswer) {
387 auto caller = CreatePeerConnection();
388 caller->AddVideoTrack("v0");
389 auto offer = caller->CreateOffer();
390 auto callee = CreatePeerConnection();
391 auto callee_video_track = callee->AddVideoTrack("v1");
392 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
393 RTCOfferAnswerOptions options;
394 options.num_simulcast_layers = 3;
395 auto answer = callee->CreateAnswer(options);
Jonas Olssona4d87372019-07-05 19:08:33 +0200396 auto* description = cricket::GetFirstMediaContent(answer->description(),
397 cricket::MEDIA_TYPE_VIDEO)
398 ->media_description();
Jonas Orelandfc1acd22018-08-24 10:58:37 +0200399 ASSERT_EQ(1u, description->streams().size());
400 ASSERT_TRUE(description->streams()[0].get_ssrc_group("SIM"));
401 EXPECT_EQ(3u, description->streams()[0].get_ssrc_group("SIM")->ssrcs.size());
402
403 // Check that it actually creates simulcast aswell.
404 callee->SetLocalDescription(std::move(answer));
405 auto senders = callee->pc()->GetSenders();
406 ASSERT_EQ(1u, senders.size());
407 EXPECT_EQ(cricket::MediaType::MEDIA_TYPE_VIDEO, senders[0]->media_type());
408 EXPECT_EQ(3u, senders[0]->GetParameters().encodings.size());
409}
410
Steve Antonad7bffc2018-01-22 10:21:56 -0800411// Test that stopping the callee transceivers causes the media channels to be
412// destroyed on the callee after calling SetLocalDescription on the local
413// answer.
414// See next test for equivalent behavior with Plan B semantics.
415TEST_F(PeerConnectionMediaTestUnifiedPlan,
416 StoppedLocalTransceiversRemovesMediaChannels) {
417 auto caller = CreatePeerConnectionWithAudioVideo();
418 auto callee = CreatePeerConnectionWithAudioVideo();
419
420 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
421
422 // Stop both audio and video transceivers on the callee.
423 auto transceivers = callee->pc()->GetTransceivers();
424 ASSERT_EQ(2u, transceivers.size());
Harald Alvestrand6060df52020-08-11 09:54:02 +0200425 transceivers[0]->StopInternal();
426 transceivers[1]->StopInternal();
Steve Antonad7bffc2018-01-22 10:21:56 -0800427
428 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
429
430 EXPECT_FALSE(callee->media_engine()->GetVoiceChannel(0));
431 EXPECT_FALSE(callee->media_engine()->GetVideoChannel(0));
432}
433
Steve Anton8d3444d2017-10-20 15:30:51 -0700434// Test that removing streams from a subsequent answer causes the send streams
435// on the callee to be removed when applied locally.
Steve Antonad7bffc2018-01-22 10:21:56 -0800436// See previous test for equivalent behavior with Unified Plan semantics.
437TEST_F(PeerConnectionMediaTestPlanB, EmptyLocalAnswerRemovesSendStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700438 auto caller = CreatePeerConnectionWithAudioVideo();
439 auto callee = CreatePeerConnection();
440 auto callee_audio_track = callee->AddAudioTrack("a");
441 auto callee_video_track = callee->AddVideoTrack("v");
442
Steve Antonad7bffc2018-01-22 10:21:56 -0800443 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700444
445 // Remove both tracks from callee.
Harald Alvestrand93dd7632022-01-19 12:28:45 +0000446 callee->pc()->RemoveTrackOrError(callee_audio_track);
447 callee->pc()->RemoveTrackOrError(callee_video_track);
Steve Anton8d3444d2017-10-20 15:30:51 -0700448
Steve Antonad7bffc2018-01-22 10:21:56 -0800449 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700450
451 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
Steve Antonad7bffc2018-01-22 10:21:56 -0800452 auto callee_video = callee->media_engine()->GetVideoChannel(0);
Steve Anton8d3444d2017-10-20 15:30:51 -0700453 EXPECT_EQ(0u, callee_voice->send_streams().size());
454 EXPECT_EQ(1u, callee_voice->recv_streams().size());
Steve Anton8d3444d2017-10-20 15:30:51 -0700455 EXPECT_EQ(0u, callee_video->send_streams().size());
456 EXPECT_EQ(1u, callee_video->recv_streams().size());
457}
458
459// Test that a new stream in a subsequent offer causes a new receive stream to
460// be created on the callee.
Steve Antonad7bffc2018-01-22 10:21:56 -0800461TEST_P(PeerConnectionMediaTest, NewStreamInRemoteOfferAddsRecvStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700462 auto caller = CreatePeerConnectionWithAudioVideo();
463 auto callee = CreatePeerConnection();
464
Steve Antonad7bffc2018-01-22 10:21:56 -0800465 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700466
467 // Add second set of tracks to the caller.
468 caller->AddAudioTrack("a2");
469 caller->AddVideoTrack("v2");
470
Steve Antonad7bffc2018-01-22 10:21:56 -0800471 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700472
Steve Antonad7bffc2018-01-22 10:21:56 -0800473 auto a1 = callee->media_engine()->GetVoiceChannel(0);
474 auto a2 = callee->media_engine()->GetVoiceChannel(1);
475 auto v1 = callee->media_engine()->GetVideoChannel(0);
476 auto v2 = callee->media_engine()->GetVideoChannel(1);
477 if (IsUnifiedPlan()) {
478 ASSERT_TRUE(a1);
479 EXPECT_EQ(1u, a1->recv_streams().size());
480 ASSERT_TRUE(a2);
481 EXPECT_EQ(1u, a2->recv_streams().size());
482 ASSERT_TRUE(v1);
483 EXPECT_EQ(1u, v1->recv_streams().size());
484 ASSERT_TRUE(v2);
485 EXPECT_EQ(1u, v2->recv_streams().size());
486 } else {
487 ASSERT_TRUE(a1);
488 EXPECT_EQ(2u, a1->recv_streams().size());
489 ASSERT_FALSE(a2);
490 ASSERT_TRUE(v1);
491 EXPECT_EQ(2u, v1->recv_streams().size());
492 ASSERT_FALSE(v2);
493 }
Steve Anton8d3444d2017-10-20 15:30:51 -0700494}
495
496// Test that a new stream in a subsequent answer causes a new send stream to be
497// created on the callee when added locally.
Steve Antonad7bffc2018-01-22 10:21:56 -0800498TEST_P(PeerConnectionMediaTest, NewStreamInLocalAnswerAddsSendStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700499 auto caller = CreatePeerConnection();
500 auto callee = CreatePeerConnectionWithAudioVideo();
501
Steve Anton22da89f2018-01-25 13:58:07 -0800502 RTCOfferAnswerOptions offer_options;
503 offer_options.offer_to_receive_audio =
Steve Anton8d3444d2017-10-20 15:30:51 -0700504 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
Steve Anton22da89f2018-01-25 13:58:07 -0800505 offer_options.offer_to_receive_video =
Steve Anton8d3444d2017-10-20 15:30:51 -0700506 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
Steve Anton22da89f2018-01-25 13:58:07 -0800507 RTCOfferAnswerOptions answer_options;
Steve Anton8d3444d2017-10-20 15:30:51 -0700508
Steve Anton22da89f2018-01-25 13:58:07 -0800509 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get(), offer_options,
510 answer_options));
Steve Anton8d3444d2017-10-20 15:30:51 -0700511
512 // Add second set of tracks to the callee.
513 callee->AddAudioTrack("a2");
514 callee->AddVideoTrack("v2");
515
Steve Anton22da89f2018-01-25 13:58:07 -0800516 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get(), offer_options,
517 answer_options));
Steve Anton8d3444d2017-10-20 15:30:51 -0700518
519 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
Steve Anton22da89f2018-01-25 13:58:07 -0800520 ASSERT_TRUE(callee_voice);
Steve Anton8d3444d2017-10-20 15:30:51 -0700521 auto callee_video = callee->media_engine()->GetVideoChannel(0);
Steve Anton22da89f2018-01-25 13:58:07 -0800522 ASSERT_TRUE(callee_video);
523
524 if (IsUnifiedPlan()) {
525 EXPECT_EQ(1u, callee_voice->send_streams().size());
526 EXPECT_EQ(1u, callee_video->send_streams().size());
527 } else {
528 EXPECT_EQ(2u, callee_voice->send_streams().size());
529 EXPECT_EQ(2u, callee_video->send_streams().size());
530 }
Steve Anton8d3444d2017-10-20 15:30:51 -0700531}
532
533// A PeerConnection with no local streams and no explicit answer constraints
534// should not reject any offered media sections.
Steve Antonad7bffc2018-01-22 10:21:56 -0800535TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700536 CreateAnswerWithNoStreamsAndDefaultOptionsDoesNotReject) {
537 auto caller = CreatePeerConnectionWithAudioVideo();
538 auto callee = CreatePeerConnection();
539 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
540 auto answer = callee->CreateAnswer();
541
542 const auto* audio_content =
543 cricket::GetFirstAudioContent(answer->description());
544 ASSERT_TRUE(audio_content);
545 EXPECT_FALSE(audio_content->rejected);
546
547 const auto* video_content =
548 cricket::GetFirstVideoContent(answer->description());
549 ASSERT_TRUE(video_content);
550 EXPECT_FALSE(video_content->rejected);
551}
552
Mirta Dvornicic479a3c02019-06-04 15:38:50 +0200553// Test that raw packetization is not set in the offer by default.
554TEST_P(PeerConnectionMediaTest, RawPacketizationNotSetInOffer) {
555 std::vector<cricket::VideoCodec> fake_codecs;
556 fake_codecs.push_back(cricket::VideoCodec(111, cricket::kVp8CodecName));
557 fake_codecs.push_back(cricket::VideoCodec(112, cricket::kRtxCodecName));
558 fake_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "111";
559 fake_codecs.push_back(cricket::VideoCodec(113, cricket::kVp9CodecName));
560 fake_codecs.push_back(cricket::VideoCodec(114, cricket::kH264CodecName));
561 fake_codecs.push_back(cricket::VideoCodec(115, "HEVC"));
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200562 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 15:38:50 +0200563 caller_fake_engine->SetVideoCodecs(fake_codecs);
564
565 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
566 auto offer = caller->CreateOfferAndSetAsLocal();
567 auto* offer_description =
568 cricket::GetFirstVideoContentDescription(offer->description());
569 for (const auto& codec : offer_description->codecs()) {
570 EXPECT_EQ(codec.packetization, absl::nullopt);
571 }
572}
573
574// Test that raw packetization is set in the offer and answer for all
575// video payload when raw_packetization_for_video is true.
576TEST_P(PeerConnectionMediaTest, RawPacketizationSetInOfferAndAnswer) {
577 std::vector<cricket::VideoCodec> fake_codecs;
578 fake_codecs.push_back(cricket::VideoCodec(111, cricket::kVp8CodecName));
579 fake_codecs.push_back(cricket::VideoCodec(112, cricket::kRtxCodecName));
580 fake_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "111";
581 fake_codecs.push_back(cricket::VideoCodec(113, cricket::kVp9CodecName));
582 fake_codecs.push_back(cricket::VideoCodec(114, cricket::kH264CodecName));
583 fake_codecs.push_back(cricket::VideoCodec(115, "HEVC"));
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200584 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 15:38:50 +0200585 caller_fake_engine->SetVideoCodecs(fake_codecs);
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200586 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 15:38:50 +0200587 callee_fake_engine->SetVideoCodecs(fake_codecs);
588
589 RTCOfferAnswerOptions options;
590 options.raw_packetization_for_video = true;
591
592 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
593 auto offer = caller->CreateOfferAndSetAsLocal(options);
594 auto* offer_description =
595 cricket::GetFirstVideoContentDescription(offer->description());
596 for (const auto& codec : offer_description->codecs()) {
597 if (codec.GetCodecType() == cricket::VideoCodec::CODEC_VIDEO) {
598 EXPECT_EQ(codec.packetization, cricket::kPacketizationParamRaw);
599 }
600 }
601
602 auto callee = CreatePeerConnectionWithVideo(std::move(callee_fake_engine));
603 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
604 auto answer = callee->CreateAnswerAndSetAsLocal(options);
605 auto* answer_description =
606 cricket::GetFirstVideoContentDescription(answer->description());
607 for (const auto& codec : answer_description->codecs()) {
608 if (codec.GetCodecType() == cricket::VideoCodec::CODEC_VIDEO) {
609 EXPECT_EQ(codec.packetization, cricket::kPacketizationParamRaw);
610 }
611 }
612
613 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
614}
615
616// Test that raw packetization is not set in the answer when
617// raw_packetization_for_video is true if it was not set in the offer.
618TEST_P(PeerConnectionMediaTest,
619 RawPacketizationNotSetInAnswerWhenNotSetInOffer) {
620 std::vector<cricket::VideoCodec> fake_codecs;
621 fake_codecs.push_back(cricket::VideoCodec(111, cricket::kVp8CodecName));
622 fake_codecs.push_back(cricket::VideoCodec(112, cricket::kRtxCodecName));
623 fake_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "111";
624 fake_codecs.push_back(cricket::VideoCodec(113, cricket::kVp9CodecName));
625 fake_codecs.push_back(cricket::VideoCodec(114, cricket::kH264CodecName));
626 fake_codecs.push_back(cricket::VideoCodec(115, "HEVC"));
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200627 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 15:38:50 +0200628 caller_fake_engine->SetVideoCodecs(fake_codecs);
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200629 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 15:38:50 +0200630 callee_fake_engine->SetVideoCodecs(fake_codecs);
631
632 RTCOfferAnswerOptions caller_options;
633 caller_options.raw_packetization_for_video = false;
634 RTCOfferAnswerOptions callee_options;
635 callee_options.raw_packetization_for_video = true;
636
637 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
638 auto offer = caller->CreateOfferAndSetAsLocal(caller_options);
639
640 auto callee = CreatePeerConnectionWithVideo(std::move(callee_fake_engine));
641 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
642 auto answer = callee->CreateAnswerAndSetAsLocal(callee_options);
643
644 auto* answer_description =
645 cricket::GetFirstVideoContentDescription(answer->description());
646 for (const auto& codec : answer_description->codecs()) {
647 EXPECT_EQ(codec.packetization, absl::nullopt);
648 }
649
650 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
651}
652
Steve Anton8d3444d2017-10-20 15:30:51 -0700653class PeerConnectionMediaOfferDirectionTest
Steve Antonad7bffc2018-01-22 10:21:56 -0800654 : public PeerConnectionMediaBaseTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700655 public ::testing::WithParamInterface<
Steve Antonad7bffc2018-01-22 10:21:56 -0800656 std::tuple<SdpSemantics,
657 std::tuple<bool, int, RtpTransceiverDirection>>> {
Steve Anton8d3444d2017-10-20 15:30:51 -0700658 protected:
Steve Antonad7bffc2018-01-22 10:21:56 -0800659 PeerConnectionMediaOfferDirectionTest()
660 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
661 auto param = std::get<1>(GetParam());
662 send_media_ = std::get<0>(param);
663 offer_to_receive_ = std::get<1>(param);
664 expected_direction_ = std::get<2>(param);
Steve Anton8d3444d2017-10-20 15:30:51 -0700665 }
666
667 bool send_media_;
668 int offer_to_receive_;
Steve Anton4e70a722017-11-28 14:57:10 -0800669 RtpTransceiverDirection expected_direction_;
Steve Anton8d3444d2017-10-20 15:30:51 -0700670};
671
672// Tests that the correct direction is set on the media description according
673// to the presence of a local media track and the offer_to_receive setting.
674TEST_P(PeerConnectionMediaOfferDirectionTest, VerifyDirection) {
675 auto caller = CreatePeerConnection();
676 if (send_media_) {
677 caller->AddAudioTrack("a");
678 }
679
680 RTCOfferAnswerOptions options;
681 options.offer_to_receive_audio = offer_to_receive_;
682 auto offer = caller->CreateOffer(options);
683
Steve Antonad7bffc2018-01-22 10:21:56 -0800684 auto* content = cricket::GetFirstMediaContent(offer->description(),
685 cricket::MEDIA_TYPE_AUDIO);
Steve Anton4e70a722017-11-28 14:57:10 -0800686 if (expected_direction_ == RtpTransceiverDirection::kInactive) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800687 EXPECT_FALSE(content);
Steve Anton8d3444d2017-10-20 15:30:51 -0700688 } else {
Steve Antonad7bffc2018-01-22 10:21:56 -0800689 EXPECT_EQ(expected_direction_, content->media_description()->direction());
Steve Anton8d3444d2017-10-20 15:30:51 -0700690 }
691}
692
693// Note that in these tests, MD_INACTIVE indicates that no media section is
694// included in the offer, not that the media direction is inactive.
Mirko Bonadeic84f6612019-01-31 12:20:57 +0100695INSTANTIATE_TEST_SUITE_P(
Steve Anton4e70a722017-11-28 14:57:10 -0800696 PeerConnectionMediaTest,
697 PeerConnectionMediaOfferDirectionTest,
Steve Antonad7bffc2018-01-22 10:21:56 -0800698 Combine(
Florent Castelli15a38de2022-04-06 00:38:21 +0200699 Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan),
Steve Antonad7bffc2018-01-22 10:21:56 -0800700 Values(std::make_tuple(false, -1, RtpTransceiverDirection::kInactive),
701 std::make_tuple(false, 0, RtpTransceiverDirection::kInactive),
702 std::make_tuple(false, 1, RtpTransceiverDirection::kRecvOnly),
703 std::make_tuple(true, -1, RtpTransceiverDirection::kSendRecv),
704 std::make_tuple(true, 0, RtpTransceiverDirection::kSendOnly),
705 std::make_tuple(true, 1, RtpTransceiverDirection::kSendRecv))));
Steve Anton8d3444d2017-10-20 15:30:51 -0700706
707class PeerConnectionMediaAnswerDirectionTest
Steve Antonad7bffc2018-01-22 10:21:56 -0800708 : public PeerConnectionMediaBaseTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700709 public ::testing::WithParamInterface<
Steve Antonad7bffc2018-01-22 10:21:56 -0800710 std::tuple<SdpSemantics, RtpTransceiverDirection, bool, int>> {
Steve Anton8d3444d2017-10-20 15:30:51 -0700711 protected:
Steve Antonad7bffc2018-01-22 10:21:56 -0800712 PeerConnectionMediaAnswerDirectionTest()
713 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
714 offer_direction_ = std::get<1>(GetParam());
715 send_media_ = std::get<2>(GetParam());
716 offer_to_receive_ = std::get<3>(GetParam());
Steve Anton8d3444d2017-10-20 15:30:51 -0700717 }
718
Steve Anton4e70a722017-11-28 14:57:10 -0800719 RtpTransceiverDirection offer_direction_;
Steve Anton8d3444d2017-10-20 15:30:51 -0700720 bool send_media_;
721 int offer_to_receive_;
722};
723
724// Tests that the direction in an answer is correct according to direction sent
725// in the offer, the presence of a local media track on the receive side and the
726// offer_to_receive setting.
727TEST_P(PeerConnectionMediaAnswerDirectionTest, VerifyDirection) {
Steve Anton22da89f2018-01-25 13:58:07 -0800728 if (IsUnifiedPlan() &&
729 offer_to_receive_ != RTCOfferAnswerOptions::kUndefined) {
730 // offer_to_receive_ is not implemented when creating answers with Unified
731 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800732 return;
733 }
Steve Anton22da89f2018-01-25 13:58:07 -0800734
Steve Anton8d3444d2017-10-20 15:30:51 -0700735 auto caller = CreatePeerConnection();
736 caller->AddAudioTrack("a");
737
738 // Create the offer with an audio section and set its direction.
739 auto offer = caller->CreateOffer();
740 cricket::GetFirstAudioContentDescription(offer->description())
741 ->set_direction(offer_direction_);
742
743 auto callee = CreatePeerConnection();
744 if (send_media_) {
745 callee->AddAudioTrack("a");
746 }
747 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
748
749 // Create the answer according to the test parameters.
750 RTCOfferAnswerOptions options;
751 options.offer_to_receive_audio = offer_to_receive_;
752 auto answer = callee->CreateAnswer(options);
753
754 // The expected direction in the answer is the intersection of each side's
755 // capability to send/recv media.
756 // For the offerer, the direction is given in the offer (offer_direction_).
757 // For the answerer, the direction has two components:
758 // 1. Send if the answerer has a local track to send.
759 // 2. Receive if the answerer has explicitly set the offer_to_receive to 1 or
760 // if it has been left as default.
Steve Anton4e70a722017-11-28 14:57:10 -0800761 bool offer_send = RtpTransceiverDirectionHasSend(offer_direction_);
762 bool offer_recv = RtpTransceiverDirectionHasRecv(offer_direction_);
Steve Anton8d3444d2017-10-20 15:30:51 -0700763
764 // The negotiated components determine the direction set in the answer.
Steve Anton1d03a752017-11-27 14:30:09 -0800765 bool negotiate_send = (send_media_ && offer_recv);
766 bool negotiate_recv = ((offer_to_receive_ != 0) && offer_send);
Steve Anton8d3444d2017-10-20 15:30:51 -0700767
768 auto expected_direction =
Steve Anton4e70a722017-11-28 14:57:10 -0800769 RtpTransceiverDirectionFromSendRecv(negotiate_send, negotiate_recv);
Steve Anton8d3444d2017-10-20 15:30:51 -0700770 EXPECT_EQ(expected_direction,
Steve Antonad7bffc2018-01-22 10:21:56 -0800771 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton8d3444d2017-10-20 15:30:51 -0700772}
773
774// Tests that the media section is rejected if and only if the callee has no
775// local media track and has set offer_to_receive to 0, no matter which
776// direction the caller indicated in the offer.
777TEST_P(PeerConnectionMediaAnswerDirectionTest, VerifyRejected) {
Steve Anton22da89f2018-01-25 13:58:07 -0800778 if (IsUnifiedPlan() &&
779 offer_to_receive_ != RTCOfferAnswerOptions::kUndefined) {
780 // offer_to_receive_ is not implemented when creating answers with Unified
781 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800782 return;
783 }
Steve Anton22da89f2018-01-25 13:58:07 -0800784
Steve Anton8d3444d2017-10-20 15:30:51 -0700785 auto caller = CreatePeerConnection();
786 caller->AddAudioTrack("a");
787
788 // Create the offer with an audio section and set its direction.
789 auto offer = caller->CreateOffer();
790 cricket::GetFirstAudioContentDescription(offer->description())
791 ->set_direction(offer_direction_);
792
793 auto callee = CreatePeerConnection();
794 if (send_media_) {
795 callee->AddAudioTrack("a");
796 }
797 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
798
799 // Create the answer according to the test parameters.
800 RTCOfferAnswerOptions options;
801 options.offer_to_receive_audio = offer_to_receive_;
802 auto answer = callee->CreateAnswer(options);
803
804 // The media section is rejected if and only if offer_to_receive is explicitly
805 // set to 0 and there is no media to send.
806 auto* audio_content = cricket::GetFirstAudioContent(answer->description());
807 ASSERT_TRUE(audio_content);
808 EXPECT_EQ((offer_to_receive_ == 0 && !send_media_), audio_content->rejected);
809}
810
Mirko Bonadeic84f6612019-01-31 12:20:57 +0100811INSTANTIATE_TEST_SUITE_P(PeerConnectionMediaTest,
812 PeerConnectionMediaAnswerDirectionTest,
Florent Castelli15a38de2022-04-06 00:38:21 +0200813 Combine(Values(SdpSemantics::kPlanB_DEPRECATED,
Mirko Bonadeic84f6612019-01-31 12:20:57 +0100814 SdpSemantics::kUnifiedPlan),
815 Values(RtpTransceiverDirection::kInactive,
816 RtpTransceiverDirection::kSendOnly,
817 RtpTransceiverDirection::kRecvOnly,
818 RtpTransceiverDirection::kSendRecv),
819 Bool(),
820 Values(-1, 0, 1)));
Steve Anton8d3444d2017-10-20 15:30:51 -0700821
Steve Antonad7bffc2018-01-22 10:21:56 -0800822TEST_P(PeerConnectionMediaTest, OfferHasDifferentDirectionForAudioVideo) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700823 auto caller = CreatePeerConnection();
824 caller->AddVideoTrack("v");
825
826 RTCOfferAnswerOptions options;
827 options.offer_to_receive_audio = 1;
828 options.offer_to_receive_video = 0;
829 auto offer = caller->CreateOffer(options);
830
Steve Anton4e70a722017-11-28 14:57:10 -0800831 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800832 GetMediaContentDirection(offer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton4e70a722017-11-28 14:57:10 -0800833 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800834 GetMediaContentDirection(offer.get(), cricket::MEDIA_TYPE_VIDEO));
Steve Anton8d3444d2017-10-20 15:30:51 -0700835}
836
Steve Antonad7bffc2018-01-22 10:21:56 -0800837TEST_P(PeerConnectionMediaTest, AnswerHasDifferentDirectionsForAudioVideo) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800838 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 13:58:07 -0800839 // offer_to_receive_ is not implemented when creating answers with Unified
840 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800841 return;
842 }
843
Steve Anton8d3444d2017-10-20 15:30:51 -0700844 auto caller = CreatePeerConnectionWithAudioVideo();
845 auto callee = CreatePeerConnection();
846 callee->AddVideoTrack("v");
847
848 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
849
850 RTCOfferAnswerOptions options;
851 options.offer_to_receive_audio = 1;
852 options.offer_to_receive_video = 0;
853 auto answer = callee->CreateAnswer(options);
854
Steve Anton4e70a722017-11-28 14:57:10 -0800855 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800856 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton4e70a722017-11-28 14:57:10 -0800857 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800858 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_VIDEO));
Steve Anton8d3444d2017-10-20 15:30:51 -0700859}
860
861void AddComfortNoiseCodecsToSend(cricket::FakeMediaEngine* media_engine) {
Philipp Hancke8498c252020-06-05 13:28:57 +0200862 const cricket::AudioCodec kComfortNoiseCodec8k(102, cricket::kCnCodecName,
863 8000, 0, 1);
864 const cricket::AudioCodec kComfortNoiseCodec16k(103, cricket::kCnCodecName,
865 16000, 0, 1);
Steve Anton8d3444d2017-10-20 15:30:51 -0700866
Sebastian Jansson6eb8a162018-11-16 11:29:55 +0100867 auto codecs = media_engine->voice().send_codecs();
Steve Anton8d3444d2017-10-20 15:30:51 -0700868 codecs.push_back(kComfortNoiseCodec8k);
869 codecs.push_back(kComfortNoiseCodec16k);
870 media_engine->SetAudioCodecs(codecs);
871}
872
873bool HasAnyComfortNoiseCodecs(const cricket::SessionDescription* desc) {
874 const auto* audio_desc = cricket::GetFirstAudioContentDescription(desc);
875 for (const auto& codec : audio_desc->codecs()) {
Philipp Hancke8498c252020-06-05 13:28:57 +0200876 if (codec.name == cricket::kCnCodecName) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700877 return true;
878 }
879 }
880 return false;
881}
882
Taylor Brandstetterf7fcfb72021-09-09 13:39:38 -0700883bool HasPayloadTypeConflict(const cricket::SessionDescription* desc) {
884 std::set<int> payload_types;
885 const auto* audio_desc = cricket::GetFirstAudioContentDescription(desc);
886 if (audio_desc) {
887 for (const auto& codec : audio_desc->codecs()) {
888 if (payload_types.count(codec.id) > 0) {
889 return true;
890 }
891 payload_types.insert(codec.id);
892 }
893 }
894 const auto* video_desc = cricket::GetFirstVideoContentDescription(desc);
895 if (video_desc) {
896 for (const auto& codec : video_desc->codecs()) {
897 if (payload_types.count(codec.id) > 0) {
898 return true;
899 }
900 payload_types.insert(codec.id);
901 }
902 }
903 return false;
904}
905
Steve Antonad7bffc2018-01-22 10:21:56 -0800906TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700907 CreateOfferWithNoVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
Philipp Hancke718acf62021-05-12 14:18:03 +0200908 auto fake_engine = std::make_unique<FakeMediaEngine>();
909 AddComfortNoiseCodecsToSend(fake_engine.get());
910 auto caller = CreatePeerConnectionWithAudioVideo(std::move(fake_engine));
Steve Anton8d3444d2017-10-20 15:30:51 -0700911
912 RTCOfferAnswerOptions options;
913 options.voice_activity_detection = false;
914 auto offer = caller->CreateOffer(options);
915
916 EXPECT_FALSE(HasAnyComfortNoiseCodecs(offer->description()));
917}
918
Steve Antonad7bffc2018-01-22 10:21:56 -0800919TEST_P(PeerConnectionMediaTest,
Philipp Hancke718acf62021-05-12 14:18:03 +0200920 CreateOfferWithVoiceActivityDetectionIncludesComfortNoiseCodecs) {
921 auto fake_engine = std::make_unique<FakeMediaEngine>();
922 AddComfortNoiseCodecsToSend(fake_engine.get());
923 auto caller = CreatePeerConnectionWithAudioVideo(std::move(fake_engine));
924
925 RTCOfferAnswerOptions options;
926 options.voice_activity_detection = true;
927 auto offer = caller->CreateOffer(options);
928
929 EXPECT_TRUE(HasAnyComfortNoiseCodecs(offer->description()));
930}
931
932TEST_P(PeerConnectionMediaTest,
933 CreateAnswerWithVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700934 auto caller = CreatePeerConnectionWithAudioVideo();
Philipp Hancke718acf62021-05-12 14:18:03 +0200935
936 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
937 AddComfortNoiseCodecsToSend(callee_fake_engine.get());
938 auto callee =
939 CreatePeerConnectionWithAudioVideo(std::move(callee_fake_engine));
940
941 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
942
943 RTCOfferAnswerOptions options;
944 options.voice_activity_detection = true;
945 auto answer = callee->CreateAnswer(options);
946
947 EXPECT_FALSE(HasAnyComfortNoiseCodecs(answer->description()));
948}
949
950TEST_P(PeerConnectionMediaTest,
951 CreateAnswerWithNoVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
952 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
953 AddComfortNoiseCodecsToSend(caller_fake_engine.get());
954 auto caller =
955 CreatePeerConnectionWithAudioVideo(std::move(caller_fake_engine));
956
957 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
958 AddComfortNoiseCodecsToSend(callee_fake_engine.get());
959 auto callee =
960 CreatePeerConnectionWithAudioVideo(std::move(callee_fake_engine));
Steve Anton8d3444d2017-10-20 15:30:51 -0700961
962 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
963
964 RTCOfferAnswerOptions options;
965 options.voice_activity_detection = false;
966 auto answer = callee->CreateAnswer(options);
967
968 EXPECT_FALSE(HasAnyComfortNoiseCodecs(answer->description()));
969}
970
971// The following test group verifies that we reject answers with invalid media
972// sections as per RFC 3264.
973
974class PeerConnectionMediaInvalidMediaTest
Steve Antonad7bffc2018-01-22 10:21:56 -0800975 : public PeerConnectionMediaBaseTest,
976 public ::testing::WithParamInterface<std::tuple<
977 SdpSemantics,
Steve Anton8d3444d2017-10-20 15:30:51 -0700978 std::tuple<std::string,
979 std::function<void(cricket::SessionDescription*)>,
Steve Antonad7bffc2018-01-22 10:21:56 -0800980 std::string>>> {
Steve Anton8d3444d2017-10-20 15:30:51 -0700981 protected:
Steve Antonad7bffc2018-01-22 10:21:56 -0800982 PeerConnectionMediaInvalidMediaTest()
983 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
984 auto param = std::get<1>(GetParam());
985 mutator_ = std::get<1>(param);
986 expected_error_ = std::get<2>(param);
Steve Anton8d3444d2017-10-20 15:30:51 -0700987 }
988
989 std::function<void(cricket::SessionDescription*)> mutator_;
990 std::string expected_error_;
991};
992
993TEST_P(PeerConnectionMediaInvalidMediaTest, FailToSetRemoteAnswer) {
994 auto caller = CreatePeerConnectionWithAudioVideo();
995 auto callee = CreatePeerConnectionWithAudioVideo();
996
997 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
998
999 auto answer = callee->CreateAnswer();
1000 mutator_(answer->description());
1001
1002 std::string error;
1003 ASSERT_FALSE(caller->SetRemoteDescription(std::move(answer), &error));
1004 EXPECT_EQ("Failed to set remote answer sdp: " + expected_error_, error);
1005}
1006
1007TEST_P(PeerConnectionMediaInvalidMediaTest, FailToSetLocalAnswer) {
1008 auto caller = CreatePeerConnectionWithAudioVideo();
1009 auto callee = CreatePeerConnectionWithAudioVideo();
1010
1011 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1012
1013 auto answer = callee->CreateAnswer();
1014 mutator_(answer->description());
1015
1016 std::string error;
1017 ASSERT_FALSE(callee->SetLocalDescription(std::move(answer), &error));
1018 EXPECT_EQ("Failed to set local answer sdp: " + expected_error_, error);
1019}
1020
1021void RemoveVideoContent(cricket::SessionDescription* desc) {
1022 auto content_name = cricket::GetFirstVideoContent(desc)->name;
1023 desc->RemoveContentByName(content_name);
1024 desc->RemoveTransportInfoByName(content_name);
1025}
1026
1027void RenameVideoContent(cricket::SessionDescription* desc) {
1028 auto* video_content = cricket::GetFirstVideoContent(desc);
1029 auto* transport_info = desc->GetTransportInfoByName(video_content->name);
1030 video_content->name = "video_renamed";
1031 transport_info->content_name = video_content->name;
1032}
1033
1034void ReverseMediaContent(cricket::SessionDescription* desc) {
Steve Anton64b626b2019-01-28 17:25:26 -08001035 absl::c_reverse(desc->contents());
1036 absl::c_reverse(desc->transport_infos());
Steve Anton8d3444d2017-10-20 15:30:51 -07001037}
1038
1039void ChangeMediaTypeAudioToVideo(cricket::SessionDescription* desc) {
Steve Antonad7bffc2018-01-22 10:21:56 -08001040 std::string audio_mid = cricket::GetFirstAudioContent(desc)->name;
1041 desc->RemoveContentByName(audio_mid);
1042 auto* video_content = cricket::GetFirstVideoContent(desc);
1043 desc->AddContent(audio_mid, video_content->type,
Harald Alvestrand1716d392019-06-03 20:35:45 +02001044 video_content->media_description()->Clone());
Steve Anton8d3444d2017-10-20 15:30:51 -07001045}
1046
1047constexpr char kMLinesOutOfOrder[] =
1048 "The order of m-lines in answer doesn't match order in offer. Rejecting "
1049 "answer.";
1050
Mirko Bonadeic84f6612019-01-31 12:20:57 +01001051INSTANTIATE_TEST_SUITE_P(
Steve Anton8d3444d2017-10-20 15:30:51 -07001052 PeerConnectionMediaTest,
1053 PeerConnectionMediaInvalidMediaTest,
Florent Castelli15a38de2022-04-06 00:38:21 +02001054 Combine(Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan),
Steve Antonad7bffc2018-01-22 10:21:56 -08001055 Values(std::make_tuple("remove video",
1056 RemoveVideoContent,
1057 kMLinesOutOfOrder),
1058 std::make_tuple("rename video",
1059 RenameVideoContent,
1060 kMLinesOutOfOrder),
1061 std::make_tuple("reverse media sections",
1062 ReverseMediaContent,
1063 kMLinesOutOfOrder),
1064 std::make_tuple("change audio type to video type",
1065 ChangeMediaTypeAudioToVideo,
1066 kMLinesOutOfOrder))));
Steve Anton8d3444d2017-10-20 15:30:51 -07001067
1068// Test that the correct media engine send/recv streams are created when doing
1069// a series of offer/answers where audio/video are both sent, then audio is
1070// rejected, then both audio/video sent again.
Steve Antonad7bffc2018-01-22 10:21:56 -08001071TEST_P(PeerConnectionMediaTest, TestAVOfferWithAudioOnlyAnswer) {
Steve Antonad7bffc2018-01-22 10:21:56 -08001072 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 13:58:07 -08001073 // offer_to_receive_ is not implemented when creating answers with Unified
1074 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -08001075 return;
1076 }
1077
Steve Anton8d3444d2017-10-20 15:30:51 -07001078 RTCOfferAnswerOptions options_reject_video;
1079 options_reject_video.offer_to_receive_audio =
1080 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
1081 options_reject_video.offer_to_receive_video = 0;
1082
1083 auto caller = CreatePeerConnection();
1084 caller->AddAudioTrack("a");
1085 caller->AddVideoTrack("v");
1086 auto callee = CreatePeerConnection();
1087
1088 // Caller initially offers to send/recv audio and video.
1089 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1090 // Callee accepts the audio as recv only but rejects the video.
1091 ASSERT_TRUE(caller->SetRemoteDescription(
1092 callee->CreateAnswerAndSetAsLocal(options_reject_video)));
1093
1094 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1095 ASSERT_TRUE(caller_voice);
1096 EXPECT_EQ(0u, caller_voice->recv_streams().size());
1097 EXPECT_EQ(1u, caller_voice->send_streams().size());
1098 auto caller_video = caller->media_engine()->GetVideoChannel(0);
1099 EXPECT_FALSE(caller_video);
1100
1101 // Callee adds its own audio/video stream and offers to receive audio/video
1102 // too.
1103 callee->AddAudioTrack("a");
1104 auto callee_video_track = callee->AddVideoTrack("v");
1105 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1106 ASSERT_TRUE(
1107 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1108
1109 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1110 ASSERT_TRUE(callee_voice);
1111 EXPECT_EQ(1u, callee_voice->recv_streams().size());
1112 EXPECT_EQ(1u, callee_voice->send_streams().size());
1113 auto callee_video = callee->media_engine()->GetVideoChannel(0);
1114 ASSERT_TRUE(callee_video);
1115 EXPECT_EQ(1u, callee_video->recv_streams().size());
1116 EXPECT_EQ(1u, callee_video->send_streams().size());
1117
1118 // Callee removes video but keeps audio and rejects the video once again.
Harald Alvestrand93dd7632022-01-19 12:28:45 +00001119 callee->pc()->RemoveTrackOrError(callee_video_track);
Steve Anton8d3444d2017-10-20 15:30:51 -07001120 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1121 ASSERT_TRUE(
1122 callee->SetLocalDescription(callee->CreateAnswer(options_reject_video)));
1123
1124 callee_voice = callee->media_engine()->GetVoiceChannel(0);
1125 ASSERT_TRUE(callee_voice);
1126 EXPECT_EQ(1u, callee_voice->recv_streams().size());
1127 EXPECT_EQ(1u, callee_voice->send_streams().size());
1128 callee_video = callee->media_engine()->GetVideoChannel(0);
1129 EXPECT_FALSE(callee_video);
1130}
1131
1132// Test that the correct media engine send/recv streams are created when doing
1133// a series of offer/answers where audio/video are both sent, then video is
1134// rejected, then both audio/video sent again.
Steve Antonad7bffc2018-01-22 10:21:56 -08001135TEST_P(PeerConnectionMediaTest, TestAVOfferWithVideoOnlyAnswer) {
Steve Antonad7bffc2018-01-22 10:21:56 -08001136 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 13:58:07 -08001137 // offer_to_receive_ is not implemented when creating answers with Unified
1138 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -08001139 return;
1140 }
1141
Steve Anton8d3444d2017-10-20 15:30:51 -07001142 // Disable the bundling here. If the media is bundled on audio
1143 // transport, then we can't reject the audio because switching the bundled
1144 // transport is not currently supported.
1145 // (https://bugs.chromium.org/p/webrtc/issues/detail?id=6704)
1146 RTCOfferAnswerOptions options_no_bundle;
1147 options_no_bundle.use_rtp_mux = false;
1148 RTCOfferAnswerOptions options_reject_audio = options_no_bundle;
1149 options_reject_audio.offer_to_receive_audio = 0;
1150 options_reject_audio.offer_to_receive_video =
1151 RTCOfferAnswerOptions::kMaxOfferToReceiveMedia;
1152
1153 auto caller = CreatePeerConnection();
1154 caller->AddAudioTrack("a");
1155 caller->AddVideoTrack("v");
1156 auto callee = CreatePeerConnection();
1157
1158 // Caller initially offers to send/recv audio and video.
1159 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1160 // Callee accepts the video as recv only but rejects the audio.
1161 ASSERT_TRUE(caller->SetRemoteDescription(
1162 callee->CreateAnswerAndSetAsLocal(options_reject_audio)));
1163
1164 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1165 EXPECT_FALSE(caller_voice);
1166 auto caller_video = caller->media_engine()->GetVideoChannel(0);
1167 ASSERT_TRUE(caller_video);
1168 EXPECT_EQ(0u, caller_video->recv_streams().size());
1169 EXPECT_EQ(1u, caller_video->send_streams().size());
1170
1171 // Callee adds its own audio/video stream and offers to receive audio/video
1172 // too.
1173 auto callee_audio_track = callee->AddAudioTrack("a");
1174 callee->AddVideoTrack("v");
1175 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1176 ASSERT_TRUE(caller->SetRemoteDescription(
1177 callee->CreateAnswerAndSetAsLocal(options_no_bundle)));
1178
1179 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1180 ASSERT_TRUE(callee_voice);
1181 EXPECT_EQ(1u, callee_voice->recv_streams().size());
1182 EXPECT_EQ(1u, callee_voice->send_streams().size());
1183 auto callee_video = callee->media_engine()->GetVideoChannel(0);
1184 ASSERT_TRUE(callee_video);
1185 EXPECT_EQ(1u, callee_video->recv_streams().size());
1186 EXPECT_EQ(1u, callee_video->send_streams().size());
1187
1188 // Callee removes audio but keeps video and rejects the audio once again.
Harald Alvestrand93dd7632022-01-19 12:28:45 +00001189 callee->pc()->RemoveTrackOrError(callee_audio_track);
Steve Anton8d3444d2017-10-20 15:30:51 -07001190 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1191 ASSERT_TRUE(
1192 callee->SetLocalDescription(callee->CreateAnswer(options_reject_audio)));
1193
1194 callee_voice = callee->media_engine()->GetVoiceChannel(0);
1195 EXPECT_FALSE(callee_voice);
1196 callee_video = callee->media_engine()->GetVideoChannel(0);
1197 ASSERT_TRUE(callee_video);
1198 EXPECT_EQ(1u, callee_video->recv_streams().size());
1199 EXPECT_EQ(1u, callee_video->send_streams().size());
1200}
1201
1202// Tests that if the underlying video encoder fails to be initialized (signaled
1203// by failing to set send codecs), the PeerConnection signals the error to the
1204// client.
Steve Antonad7bffc2018-01-22 10:21:56 -08001205TEST_P(PeerConnectionMediaTest, MediaEngineErrorPropagatedToClients) {
Steve Anton8d3444d2017-10-20 15:30:51 -07001206 auto caller = CreatePeerConnectionWithAudioVideo();
1207 auto callee = CreatePeerConnectionWithAudioVideo();
1208
1209 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1210
1211 auto video_channel = caller->media_engine()->GetVideoChannel(0);
1212 video_channel->set_fail_set_send_codecs(true);
1213
1214 std::string error;
1215 ASSERT_FALSE(caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(),
1216 &error));
Yura Yaroshevichbc1f9102020-06-03 21:15:22 +00001217 EXPECT_EQ(std::string("Failed to set remote answer sdp: Failed to set remote "
1218 "video description "
1219 "send parameters for m-section with mid='") +
1220 (IsUnifiedPlan() ? "1" : "video") + "'.",
1221 error);
Steve Anton8d3444d2017-10-20 15:30:51 -07001222}
1223
1224// Tests that if the underlying video encoder fails once then subsequent
1225// attempts at setting the local/remote description will also fail, even if
1226// SetSendCodecs no longer fails.
Steve Antonad7bffc2018-01-22 10:21:56 -08001227TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -07001228 FailToApplyDescriptionIfVideoEncoderHasEverFailed) {
1229 auto caller = CreatePeerConnectionWithAudioVideo();
1230 auto callee = CreatePeerConnectionWithAudioVideo();
1231
1232 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1233
1234 auto video_channel = caller->media_engine()->GetVideoChannel(0);
1235 video_channel->set_fail_set_send_codecs(true);
1236
1237 EXPECT_FALSE(
1238 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1239
1240 video_channel->set_fail_set_send_codecs(false);
1241
1242 EXPECT_FALSE(caller->SetRemoteDescription(callee->CreateAnswer()));
1243 EXPECT_FALSE(caller->SetLocalDescription(caller->CreateOffer()));
1244}
1245
1246void RenameContent(cricket::SessionDescription* desc,
Steve Antonad7bffc2018-01-22 10:21:56 -08001247 cricket::MediaType media_type,
Steve Anton8d3444d2017-10-20 15:30:51 -07001248 const std::string& new_name) {
Steve Antonad7bffc2018-01-22 10:21:56 -08001249 auto* content = cricket::GetFirstMediaContent(desc, media_type);
Steve Anton8d3444d2017-10-20 15:30:51 -07001250 RTC_DCHECK(content);
Steve Antonad7bffc2018-01-22 10:21:56 -08001251 std::string old_name = content->name;
Steve Anton8d3444d2017-10-20 15:30:51 -07001252 content->name = new_name;
1253 auto* transport = desc->GetTransportInfoByName(old_name);
1254 RTC_DCHECK(transport);
1255 transport->content_name = new_name;
Zhi Huangd2248f82018-04-10 14:41:03 -07001256
1257 // Rename the content name in the BUNDLE group.
1258 cricket::ContentGroup new_bundle_group =
1259 *desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1260 new_bundle_group.RemoveContentName(old_name);
1261 new_bundle_group.AddContentName(new_name);
1262 desc->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1263 desc->AddGroup(new_bundle_group);
Steve Anton8d3444d2017-10-20 15:30:51 -07001264}
1265
1266// Tests that an answer responds with the same MIDs as the offer.
Steve Antonad7bffc2018-01-22 10:21:56 -08001267TEST_P(PeerConnectionMediaTest, AnswerHasSameMidsAsOffer) {
Zhi Huang365381f2018-04-13 16:44:34 -07001268 const std::string kAudioMid = "notdefault1";
1269 const std::string kVideoMid = "notdefault2";
Steve Anton8d3444d2017-10-20 15:30:51 -07001270
1271 auto caller = CreatePeerConnectionWithAudioVideo();
1272 auto callee = CreatePeerConnectionWithAudioVideo();
1273
1274 auto offer = caller->CreateOffer();
Steve Antonad7bffc2018-01-22 10:21:56 -08001275 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, kAudioMid);
1276 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, kVideoMid);
Steve Anton8d3444d2017-10-20 15:30:51 -07001277 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1278
1279 auto answer = callee->CreateAnswer();
1280 EXPECT_EQ(kAudioMid,
1281 cricket::GetFirstAudioContent(answer->description())->name);
1282 EXPECT_EQ(kVideoMid,
1283 cricket::GetFirstVideoContent(answer->description())->name);
1284}
1285
1286// Test that if the callee creates a re-offer, the MIDs are the same as the
1287// original offer.
Steve Antonad7bffc2018-01-22 10:21:56 -08001288TEST_P(PeerConnectionMediaTest, ReOfferHasSameMidsAsFirstOffer) {
Zhi Huang365381f2018-04-13 16:44:34 -07001289 const std::string kAudioMid = "notdefault1";
1290 const std::string kVideoMid = "notdefault2";
Steve Anton8d3444d2017-10-20 15:30:51 -07001291
1292 auto caller = CreatePeerConnectionWithAudioVideo();
1293 auto callee = CreatePeerConnectionWithAudioVideo();
1294
1295 auto offer = caller->CreateOffer();
Steve Antonad7bffc2018-01-22 10:21:56 -08001296 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, kAudioMid);
1297 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, kVideoMid);
Steve Anton8d3444d2017-10-20 15:30:51 -07001298 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1299 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1300
1301 auto reoffer = callee->CreateOffer();
1302 EXPECT_EQ(kAudioMid,
1303 cricket::GetFirstAudioContent(reoffer->description())->name);
1304 EXPECT_EQ(kVideoMid,
1305 cricket::GetFirstVideoContent(reoffer->description())->name);
1306}
1307
Steve Anton06817cd2018-12-18 15:55:30 -08001308// Test that SetRemoteDescription returns an error if there are two m= sections
1309// with the same MID value.
1310TEST_P(PeerConnectionMediaTest, SetRemoteDescriptionFailsWithDuplicateMids) {
1311 auto caller = CreatePeerConnectionWithAudioVideo();
1312 auto callee = CreatePeerConnectionWithAudioVideo();
1313
1314 auto offer = caller->CreateOffer();
1315 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, "same");
1316 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, "same");
1317
1318 std::string error;
1319 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer), &error));
1320 EXPECT_EQ(error,
1321 "Failed to set remote offer sdp: Duplicate a=mid value 'same'.");
1322}
1323
Steve Antonad7bffc2018-01-22 10:21:56 -08001324TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -07001325 CombinedAudioVideoBweConfigPropagatedToMediaEngine) {
1326 RTCConfiguration config;
1327 config.combined_audio_video_bwe.emplace(true);
1328 auto caller = CreatePeerConnectionWithAudioVideo(config);
1329
1330 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
1331
1332 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1333 ASSERT_TRUE(caller_voice);
1334 const cricket::AudioOptions& audio_options = caller_voice->options();
1335 EXPECT_EQ(config.combined_audio_video_bwe,
1336 audio_options.combined_audio_video_bwe);
1337}
1338
Philipp Hancke7145a142021-09-28 07:46:06 +02001339// Test that if a RED codec refers to another codec in its fmtp line, but that
1340// codec's payload type was reassigned for some reason (either the remote
1341// endpoint selected a different payload type or there was a conflict), the RED
1342// fmtp line is modified to refer to the correct payload type.
1343TEST_P(PeerConnectionMediaTest, RedFmtpPayloadTypeReassigned) {
1344 std::vector<cricket::AudioCodec> caller_fake_codecs;
1345 caller_fake_codecs.push_back(cricket::AudioCodec(100, "foo", 0, 0, 1));
1346 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
1347 caller_fake_engine->SetAudioCodecs(caller_fake_codecs);
1348 auto caller = CreatePeerConnectionWithAudio(std::move(caller_fake_engine));
1349
1350 std::vector<cricket::AudioCodec> callee_fake_codecs;
1351 callee_fake_codecs.push_back(cricket::AudioCodec(120, "foo", 0, 0, 1));
1352 callee_fake_codecs.push_back(
1353 cricket::AudioCodec(121, cricket::kRedCodecName, 0, 0, 1));
1354 callee_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1355 "120/120");
1356 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
1357 callee_fake_engine->SetAudioCodecs(callee_fake_codecs);
1358 auto callee = CreatePeerConnectionWithAudio(std::move(callee_fake_engine));
1359
1360 // Offer from the caller establishes 100 as the "foo" payload type.
1361 auto offer = caller->CreateOfferAndSetAsLocal();
1362 callee->SetRemoteDescription(std::move(offer));
1363 auto answer = callee->CreateAnswerAndSetAsLocal();
1364 auto answer_description =
1365 cricket::GetFirstAudioContentDescription(answer->description());
1366 ASSERT_EQ(1u, answer_description->codecs().size());
1367
1368 // Offer from the callee should respect the established payload type, and
1369 // attempt to add RED, which should refer to the correct payload type.
1370 offer = callee->CreateOfferAndSetAsLocal();
1371 auto* offer_description =
1372 cricket::GetFirstAudioContentDescription(offer->description());
1373 ASSERT_EQ(2u, offer_description->codecs().size());
1374 for (const auto& codec : offer_description->codecs()) {
1375 if (codec.name == "foo") {
1376 ASSERT_EQ(100, codec.id);
1377 } else if (codec.name == cricket::kRedCodecName) {
1378 std::string fmtp;
1379 ASSERT_TRUE(codec.GetParam("", &fmtp));
1380 EXPECT_EQ("100/100", fmtp);
1381 }
1382 }
1383}
1384
1385// Test that RED without fmtp does match RED without fmtp.
1386TEST_P(PeerConnectionMediaTest, RedFmtpPayloadTypeNoFmtpMatchNoFmtp) {
1387 std::vector<cricket::AudioCodec> caller_fake_codecs;
1388 caller_fake_codecs.push_back(cricket::AudioCodec(100, "foo", 0, 0, 1));
1389 caller_fake_codecs.push_back(
1390 cricket::AudioCodec(101, cricket::kRedCodecName, 0, 0, 1));
1391 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
1392 caller_fake_engine->SetAudioCodecs(caller_fake_codecs);
1393 auto caller = CreatePeerConnectionWithAudio(std::move(caller_fake_engine));
1394
1395 std::vector<cricket::AudioCodec> callee_fake_codecs;
1396 callee_fake_codecs.push_back(cricket::AudioCodec(120, "foo", 0, 0, 1));
1397 callee_fake_codecs.push_back(
1398 cricket::AudioCodec(121, cricket::kRedCodecName, 0, 0, 1));
1399 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
1400 callee_fake_engine->SetAudioCodecs(callee_fake_codecs);
1401 auto callee = CreatePeerConnectionWithAudio(std::move(callee_fake_engine));
1402
1403 // Offer from the caller establishes 100 as the "foo" payload type.
1404 // Red (without fmtp) is negotiated.
1405 auto offer = caller->CreateOfferAndSetAsLocal();
1406 callee->SetRemoteDescription(std::move(offer));
1407 auto answer = callee->CreateAnswerAndSetAsLocal();
1408 auto answer_description =
1409 cricket::GetFirstAudioContentDescription(answer->description());
1410 ASSERT_EQ(2u, answer_description->codecs().size());
1411
1412 // Offer from the callee should respect the established payload type, and
1413 // attempt to add RED.
1414 offer = callee->CreateOfferAndSetAsLocal();
1415 auto* offer_description =
1416 cricket::GetFirstAudioContentDescription(offer->description());
1417 ASSERT_EQ(2u, offer_description->codecs().size());
1418 for (const auto& codec : offer_description->codecs()) {
1419 if (codec.name == "foo") {
1420 ASSERT_EQ(100, codec.id);
1421 } else if (codec.name == cricket::kRedCodecName) {
1422 ASSERT_EQ(101, codec.id);
1423 }
1424 }
1425}
1426
1427// Test that RED without fmtp does not match RED with fmtp.
1428TEST_P(PeerConnectionMediaTest, RedFmtpPayloadTypeNoFmtpNoMatchFmtp) {
1429 std::vector<cricket::AudioCodec> caller_fake_codecs;
1430 caller_fake_codecs.push_back(cricket::AudioCodec(100, "foo", 0, 0, 1));
1431 caller_fake_codecs.push_back(
1432 cricket::AudioCodec(101, cricket::kRedCodecName, 0, 0, 1));
1433 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
1434 caller_fake_engine->SetAudioCodecs(caller_fake_codecs);
1435 auto caller = CreatePeerConnectionWithAudio(std::move(caller_fake_engine));
1436
1437 std::vector<cricket::AudioCodec> callee_fake_codecs;
1438 callee_fake_codecs.push_back(cricket::AudioCodec(120, "foo", 0, 0, 1));
1439 callee_fake_codecs.push_back(
1440 cricket::AudioCodec(121, cricket::kRedCodecName, 0, 0, 1));
1441 callee_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1442 "120/120");
1443 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
1444 callee_fake_engine->SetAudioCodecs(callee_fake_codecs);
1445 auto callee = CreatePeerConnectionWithAudio(std::move(callee_fake_engine));
1446
1447 // Offer from the caller establishes 100 as the "foo" payload type.
1448 // It should not negotiate RED.
1449 auto offer = caller->CreateOfferAndSetAsLocal();
1450 callee->SetRemoteDescription(std::move(offer));
1451 auto answer = callee->CreateAnswerAndSetAsLocal();
1452 auto answer_description =
1453 cricket::GetFirstAudioContentDescription(answer->description());
1454 ASSERT_EQ(1u, answer_description->codecs().size());
1455
1456 // Offer from the callee should respect the established payload type, and
1457 // attempt to add RED, which should refer to the correct payload type.
1458 offer = callee->CreateOfferAndSetAsLocal();
1459 auto* offer_description =
1460 cricket::GetFirstAudioContentDescription(offer->description());
1461 ASSERT_EQ(2u, offer_description->codecs().size());
1462 for (const auto& codec : offer_description->codecs()) {
1463 if (codec.name == "foo") {
1464 ASSERT_EQ(100, codec.id);
1465 } else if (codec.name == cricket::kRedCodecName) {
1466 std::string fmtp;
1467 ASSERT_TRUE(
1468 codec.GetParam(cricket::kCodecParamNotInNameValueFormat, &fmtp));
1469 EXPECT_EQ("100/100", fmtp);
1470 }
1471 }
1472}
1473
1474// Test that RED with fmtp must match base codecs.
1475TEST_P(PeerConnectionMediaTest, RedFmtpPayloadTypeMustMatchBaseCodecs) {
1476 std::vector<cricket::AudioCodec> caller_fake_codecs;
1477 caller_fake_codecs.push_back(cricket::AudioCodec(100, "foo", 0, 0, 1));
1478 caller_fake_codecs.push_back(
1479 cricket::AudioCodec(101, cricket::kRedCodecName, 0, 0, 1));
1480 caller_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1481 "100/100");
1482 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
1483 caller_fake_engine->SetAudioCodecs(caller_fake_codecs);
1484 auto caller = CreatePeerConnectionWithAudio(std::move(caller_fake_engine));
1485
1486 std::vector<cricket::AudioCodec> callee_fake_codecs;
1487 callee_fake_codecs.push_back(cricket::AudioCodec(120, "foo", 0, 0, 1));
1488 callee_fake_codecs.push_back(
1489 cricket::AudioCodec(121, cricket::kRedCodecName, 0, 0, 1));
1490 callee_fake_codecs.push_back(cricket::AudioCodec(122, "bar", 0, 0, 1));
1491 callee_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1492 "122/122");
1493 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
1494 callee_fake_engine->SetAudioCodecs(callee_fake_codecs);
1495 auto callee = CreatePeerConnectionWithAudio(std::move(callee_fake_engine));
1496
1497 // Offer from the caller establishes 100 as the "foo" payload type.
1498 // It should not negotiate RED since RED is associated with foo, not bar.
1499 auto offer = caller->CreateOfferAndSetAsLocal();
1500 callee->SetRemoteDescription(std::move(offer));
1501 auto answer = callee->CreateAnswerAndSetAsLocal();
1502 auto answer_description =
1503 cricket::GetFirstAudioContentDescription(answer->description());
1504 ASSERT_EQ(1u, answer_description->codecs().size());
1505}
1506
1507// Test behaviour when the RED fmtp attempts to specify different codecs
1508// which is not supported.
1509TEST_P(PeerConnectionMediaTest, RedFmtpPayloadMixed) {
1510 std::vector<cricket::AudioCodec> caller_fake_codecs;
1511 caller_fake_codecs.push_back(cricket::AudioCodec(100, "foo", 0, 0, 1));
1512 caller_fake_codecs.push_back(cricket::AudioCodec(102, "bar", 0, 0, 1));
1513 caller_fake_codecs.push_back(
1514 cricket::AudioCodec(101, cricket::kRedCodecName, 0, 0, 1));
1515 caller_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1516 "100/102");
1517 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
1518 caller_fake_engine->SetAudioCodecs(caller_fake_codecs);
1519 auto caller = CreatePeerConnectionWithAudio(std::move(caller_fake_engine));
1520
1521 std::vector<cricket::AudioCodec> callee_fake_codecs;
1522 callee_fake_codecs.push_back(cricket::AudioCodec(120, "foo", 0, 0, 1));
1523 callee_fake_codecs.push_back(
1524 cricket::AudioCodec(121, cricket::kRedCodecName, 0, 0, 1));
1525 callee_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1526 "120/120");
1527 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
1528 callee_fake_engine->SetAudioCodecs(callee_fake_codecs);
1529 auto callee = CreatePeerConnectionWithAudio(std::move(callee_fake_engine));
1530
1531 // Offer from the caller establishes 100 as the "foo" payload type.
1532 auto offer = caller->CreateOfferAndSetAsLocal();
1533 callee->SetRemoteDescription(std::move(offer));
1534 auto answer = callee->CreateAnswerAndSetAsLocal();
1535 auto answer_description =
1536 cricket::GetFirstAudioContentDescription(answer->description());
1537 // RED is not negotiated.
1538 ASSERT_EQ(1u, answer_description->codecs().size());
1539}
1540
1541// Test behaviour when the RED fmtp attempts to negotiate different levels of
1542// redundancy.
1543TEST_P(PeerConnectionMediaTest, RedFmtpPayloadDifferentRedundancy) {
1544 std::vector<cricket::AudioCodec> caller_fake_codecs;
1545 caller_fake_codecs.push_back(cricket::AudioCodec(100, "foo", 0, 0, 1));
1546 caller_fake_codecs.push_back(
1547 cricket::AudioCodec(101, cricket::kRedCodecName, 0, 0, 1));
1548 caller_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1549 "100/100");
1550 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
1551 caller_fake_engine->SetAudioCodecs(caller_fake_codecs);
1552 auto caller = CreatePeerConnectionWithAudio(std::move(caller_fake_engine));
1553
1554 std::vector<cricket::AudioCodec> callee_fake_codecs;
1555 callee_fake_codecs.push_back(cricket::AudioCodec(120, "foo", 0, 0, 1));
1556 callee_fake_codecs.push_back(
1557 cricket::AudioCodec(121, cricket::kRedCodecName, 0, 0, 1));
1558 callee_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1559 "120/120/120");
1560 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
1561 callee_fake_engine->SetAudioCodecs(callee_fake_codecs);
1562 auto callee = CreatePeerConnectionWithAudio(std::move(callee_fake_engine));
1563
1564 // Offer from the caller establishes 100 as the "foo" payload type.
1565 auto offer = caller->CreateOfferAndSetAsLocal();
1566 callee->SetRemoteDescription(std::move(offer));
1567 auto answer = callee->CreateAnswerAndSetAsLocal();
1568 auto answer_description =
1569 cricket::GetFirstAudioContentDescription(answer->description());
1570 // RED is negotiated.
1571 ASSERT_EQ(2u, answer_description->codecs().size());
1572
1573 // Offer from the callee should respect the established payload type, and
1574 // attempt to add RED, which should refer to the correct payload type.
1575 offer = callee->CreateOfferAndSetAsLocal();
1576 auto* offer_description =
1577 cricket::GetFirstAudioContentDescription(offer->description());
1578 ASSERT_EQ(2u, offer_description->codecs().size());
1579 for (const auto& codec : offer_description->codecs()) {
1580 if (codec.name == "foo") {
1581 ASSERT_EQ(100, codec.id);
1582 } else if (codec.name == cricket::kRedCodecName) {
1583 std::string fmtp;
1584 ASSERT_TRUE(
1585 codec.GetParam(cricket::kCodecParamNotInNameValueFormat, &fmtp));
1586 EXPECT_EQ("100/100", fmtp);
1587 }
1588 }
1589}
1590
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001591template <typename C>
1592bool CompareCodecs(const std::vector<webrtc::RtpCodecCapability>& capabilities,
1593 const std::vector<C>& codecs) {
1594 bool capability_has_rtx =
1595 absl::c_any_of(capabilities, [](const webrtc::RtpCodecCapability& codec) {
1596 return codec.name == cricket::kRtxCodecName;
1597 });
1598 bool codecs_has_rtx = absl::c_any_of(codecs, [](const C& codec) {
1599 return codec.name == cricket::kRtxCodecName;
1600 });
1601
1602 std::vector<C> codecs_no_rtx;
1603 absl::c_copy_if(
1604 codecs, std::back_inserter(codecs_no_rtx),
1605 [](const C& codec) { return codec.name != cricket::kRtxCodecName; });
1606
1607 std::vector<webrtc::RtpCodecCapability> capabilities_no_rtx;
1608 absl::c_copy_if(capabilities, std::back_inserter(capabilities_no_rtx),
1609 [](const webrtc::RtpCodecCapability& codec) {
1610 return codec.name != cricket::kRtxCodecName;
1611 });
1612
1613 return capability_has_rtx == codecs_has_rtx &&
1614 absl::c_equal(
1615 capabilities_no_rtx, codecs_no_rtx,
1616 [](const webrtc::RtpCodecCapability& capability, const C& codec) {
1617 return codec.MatchesCapability(capability);
1618 });
1619}
1620
1621TEST_F(PeerConnectionMediaTestUnifiedPlan,
1622 SetCodecPreferencesAudioMissingRecvCodec) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001623 auto fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001624 auto send_codecs = fake_engine->voice().send_codecs();
1625 send_codecs.push_back(cricket::AudioCodec(send_codecs.back().id + 1,
1626 "send_only_codec", 0, 0, 1));
1627 fake_engine->SetAudioSendCodecs(send_codecs);
1628
1629 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
1630
1631 auto transceiver = caller->pc()->GetTransceivers().front();
1632 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
1633 cricket::MediaType::MEDIA_TYPE_AUDIO);
1634
1635 std::vector<webrtc::RtpCodecCapability> codecs;
1636 absl::c_copy_if(capabilities.codecs, std::back_inserter(codecs),
1637 [](const webrtc::RtpCodecCapability& codec) {
1638 return codec.name.find("_only_") != std::string::npos;
1639 });
1640
1641 auto result = transceiver->SetCodecPreferences(codecs);
1642 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1643}
1644
1645TEST_F(PeerConnectionMediaTestUnifiedPlan,
1646 SetCodecPreferencesAudioMissingSendCodec) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001647 auto fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001648 auto recv_codecs = fake_engine->voice().recv_codecs();
1649 recv_codecs.push_back(cricket::AudioCodec(recv_codecs.back().id + 1,
1650 "recv_only_codec", 0, 0, 1));
1651 fake_engine->SetAudioRecvCodecs(recv_codecs);
1652 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
1653
1654 auto transceiver = caller->pc()->GetTransceivers().front();
1655 auto capabilities = caller->pc_factory()->GetRtpReceiverCapabilities(
1656 cricket::MediaType::MEDIA_TYPE_AUDIO);
1657
1658 std::vector<webrtc::RtpCodecCapability> codecs;
1659 absl::c_copy_if(capabilities.codecs, std::back_inserter(codecs),
1660 [](const webrtc::RtpCodecCapability& codec) {
1661 return codec.name.find("_only_") != std::string::npos;
1662 });
1663
1664 auto result = transceiver->SetCodecPreferences(codecs);
1665 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1666}
1667
1668TEST_F(PeerConnectionMediaTestUnifiedPlan,
1669 SetCodecPreferencesAudioRejectsVideoCodec) {
1670 auto caller = CreatePeerConnectionWithAudio();
1671
1672 auto transceiver = caller->pc()->GetTransceivers().front();
1673 auto video_codecs =
1674 caller->pc_factory()
1675 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)
1676 .codecs;
1677 auto codecs =
1678 caller->pc_factory()
1679 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)
1680 .codecs;
1681 codecs.insert(codecs.end(), video_codecs.begin(), video_codecs.end());
1682 auto result = transceiver->SetCodecPreferences(codecs);
1683 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1684}
1685
1686TEST_F(PeerConnectionMediaTestUnifiedPlan,
1687 SetCodecPreferencesAudioRejectsOnlyRtxRedFec) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001688 auto fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001689 auto audio_codecs = fake_engine->voice().send_codecs();
1690 audio_codecs.push_back(cricket::AudioCodec(audio_codecs.back().id + 1,
1691 cricket::kRtxCodecName, 0, 0, 1));
1692 audio_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1693 std::to_string(audio_codecs.back().id - 1);
1694 audio_codecs.push_back(cricket::AudioCodec(audio_codecs.back().id + 1,
1695 cricket::kRedCodecName, 0, 0, 1));
1696 audio_codecs.push_back(cricket::AudioCodec(
1697 audio_codecs.back().id + 1, cricket::kUlpfecCodecName, 0, 0, 1));
1698 fake_engine->SetAudioCodecs(audio_codecs);
1699
1700 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
1701
1702 auto transceiver = caller->pc()->GetTransceivers().front();
1703 auto codecs =
1704 caller->pc_factory()
1705 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)
1706 .codecs;
1707 auto codecs_only_rtx_red_fec = codecs;
1708 auto it = std::remove_if(codecs_only_rtx_red_fec.begin(),
1709 codecs_only_rtx_red_fec.end(),
1710 [](const webrtc::RtpCodecCapability& codec) {
1711 return !(codec.name == cricket::kRtxCodecName ||
1712 codec.name == cricket::kRedCodecName ||
1713 codec.name == cricket::kUlpfecCodecName);
1714 });
1715 codecs_only_rtx_red_fec.erase(it, codecs_only_rtx_red_fec.end());
1716
1717 auto result = transceiver->SetCodecPreferences(codecs_only_rtx_red_fec);
1718 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1719}
1720
1721TEST_F(PeerConnectionMediaTestUnifiedPlan, SetCodecPreferencesAllAudioCodecs) {
1722 auto caller = CreatePeerConnectionWithAudio();
1723
1724 auto sender_audio_codecs =
1725 caller->pc_factory()
1726 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_AUDIO)
1727 .codecs;
1728
1729 auto audio_transceiver = caller->pc()->GetTransceivers().front();
1730
1731 // Normal case, set all capabilities as preferences
1732 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(sender_audio_codecs).ok());
1733 auto offer = caller->CreateOffer();
1734 auto codecs = offer->description()
1735 ->contents()[0]
1736 .media_description()
1737 ->as_audio()
1738 ->codecs();
1739 EXPECT_TRUE(CompareCodecs(sender_audio_codecs, codecs));
1740}
1741
1742TEST_F(PeerConnectionMediaTestUnifiedPlan,
1743 SetCodecPreferencesResetAudioCodecs) {
1744 auto caller = CreatePeerConnectionWithAudio();
1745
1746 auto sender_audio_codecs =
1747 caller->pc_factory()
1748 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_AUDIO)
1749 .codecs;
1750 std::vector<webrtc::RtpCodecCapability> empty_codecs = {};
1751
1752 auto audio_transceiver = caller->pc()->GetTransceivers().front();
1753
1754 // Normal case, reset codec preferences
1755 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(empty_codecs).ok());
1756 auto offer = caller->CreateOffer();
1757 auto codecs = offer->description()
1758 ->contents()[0]
1759 .media_description()
1760 ->as_audio()
1761 ->codecs();
1762 EXPECT_TRUE(CompareCodecs(sender_audio_codecs, codecs));
1763}
1764
1765TEST_F(PeerConnectionMediaTestUnifiedPlan,
1766 SetCodecPreferencesVideoRejectsAudioCodec) {
1767 auto caller = CreatePeerConnectionWithVideo();
1768
1769 auto transceiver = caller->pc()->GetTransceivers().front();
1770 auto audio_codecs =
1771 caller->pc_factory()
1772 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)
1773 .codecs;
1774 auto codecs =
1775 caller->pc_factory()
1776 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)
1777 .codecs;
1778 codecs.insert(codecs.end(), audio_codecs.begin(), audio_codecs.end());
1779 auto result = transceiver->SetCodecPreferences(codecs);
1780 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1781}
1782
1783TEST_F(PeerConnectionMediaTestUnifiedPlan,
1784 SetCodecPreferencesVideoRejectsOnlyRtxRedFec) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001785 auto fake_engine = std::make_unique<FakeMediaEngine>();
Johannes Kron3e983682020-03-29 22:17:00 +02001786 auto video_codecs = fake_engine->video().send_codecs();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001787 video_codecs.push_back(
1788 cricket::VideoCodec(video_codecs.back().id + 1, cricket::kRtxCodecName));
Johannes Kron3e983682020-03-29 22:17:00 +02001789 video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1790 std::to_string(video_codecs.back().id - 1);
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001791 video_codecs.push_back(
1792 cricket::VideoCodec(video_codecs.back().id + 1, cricket::kRedCodecName));
1793 video_codecs.push_back(cricket::VideoCodec(video_codecs.back().id + 1,
1794 cricket::kUlpfecCodecName));
1795 fake_engine->SetVideoCodecs(video_codecs);
1796
1797 auto caller = CreatePeerConnectionWithVideo(std::move(fake_engine));
1798
1799 auto transceiver = caller->pc()->GetTransceivers().front();
1800 auto codecs =
1801 caller->pc_factory()
1802 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)
1803 .codecs;
1804 auto codecs_only_rtx_red_fec = codecs;
1805 auto it = std::remove_if(codecs_only_rtx_red_fec.begin(),
1806 codecs_only_rtx_red_fec.end(),
1807 [](const webrtc::RtpCodecCapability& codec) {
1808 return !(codec.name == cricket::kRtxCodecName ||
1809 codec.name == cricket::kRedCodecName ||
1810 codec.name == cricket::kUlpfecCodecName);
1811 });
1812 codecs_only_rtx_red_fec.erase(it, codecs_only_rtx_red_fec.end());
1813
1814 auto result = transceiver->SetCodecPreferences(codecs_only_rtx_red_fec);
1815 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1816}
1817
1818TEST_F(PeerConnectionMediaTestUnifiedPlan, SetCodecPreferencesAllVideoCodecs) {
1819 auto caller = CreatePeerConnectionWithVideo();
1820
1821 auto sender_video_codecs =
1822 caller->pc_factory()
1823 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1824 .codecs;
1825
1826 auto video_transceiver = caller->pc()->GetTransceivers().front();
1827
1828 // Normal case, setting preferences to normal capabilities
1829 EXPECT_TRUE(video_transceiver->SetCodecPreferences(sender_video_codecs).ok());
1830 auto offer = caller->CreateOffer();
1831 auto codecs = offer->description()
1832 ->contents()[0]
1833 .media_description()
1834 ->as_video()
1835 ->codecs();
1836 EXPECT_TRUE(CompareCodecs(sender_video_codecs, codecs));
1837}
1838
1839TEST_F(PeerConnectionMediaTestUnifiedPlan,
1840 SetCodecPreferencesResetVideoCodecs) {
1841 auto caller = CreatePeerConnectionWithVideo();
1842
1843 auto sender_video_codecs =
1844 caller->pc_factory()
1845 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1846 .codecs;
1847
1848 std::vector<webrtc::RtpCodecCapability> empty_codecs = {};
1849
1850 auto video_transceiver = caller->pc()->GetTransceivers().front();
1851
1852 // Normal case, resetting preferences with empty list of codecs
1853 EXPECT_TRUE(video_transceiver->SetCodecPreferences(empty_codecs).ok());
1854 auto offer = caller->CreateOffer();
1855 auto codecs = offer->description()
1856 ->contents()[0]
1857 .media_description()
1858 ->as_video()
1859 ->codecs();
1860 EXPECT_TRUE(CompareCodecs(sender_video_codecs, codecs));
1861}
1862
1863TEST_F(PeerConnectionMediaTestUnifiedPlan,
1864 SetCodecPreferencesVideoCodecDuplicatesRemoved) {
1865 auto caller = CreatePeerConnectionWithVideo();
1866
1867 auto sender_video_codecs =
1868 caller->pc_factory()
1869 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1870 .codecs;
1871
1872 auto video_transceiver = caller->pc()->GetTransceivers().front();
1873
1874 // Check duplicates are removed
1875 auto single_codec = sender_video_codecs;
1876 single_codec.resize(1);
1877 auto duplicate_codec = single_codec;
1878 duplicate_codec.push_back(duplicate_codec.front());
1879 duplicate_codec.push_back(duplicate_codec.front());
1880 duplicate_codec.push_back(duplicate_codec.front());
1881
1882 EXPECT_TRUE(video_transceiver->SetCodecPreferences(duplicate_codec).ok());
1883 auto offer = caller->CreateOffer();
1884 auto codecs = offer->description()
1885 ->contents()[0]
1886 .media_description()
1887 ->as_video()
1888 ->codecs();
1889 EXPECT_TRUE(CompareCodecs(single_codec, codecs));
1890}
1891
1892TEST_F(PeerConnectionMediaTestUnifiedPlan, SetCodecPreferencesVideoWithRtx) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001893 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Johannes Kron3e983682020-03-29 22:17:00 +02001894 auto caller_video_codecs = caller_fake_engine->video().send_codecs();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001895 caller_video_codecs.push_back(cricket::VideoCodec(
1896 caller_video_codecs.back().id + 1, cricket::kVp8CodecName));
1897 caller_video_codecs.push_back(cricket::VideoCodec(
1898 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1899 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1900 std::to_string(caller_video_codecs.back().id - 1);
1901 caller_video_codecs.push_back(cricket::VideoCodec(
1902 caller_video_codecs.back().id + 1, cricket::kVp9CodecName));
1903 caller_video_codecs.push_back(cricket::VideoCodec(
1904 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1905 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1906 std::to_string(caller_video_codecs.back().id - 1);
1907 caller_fake_engine->SetVideoCodecs(caller_video_codecs);
1908
1909 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
1910
1911 auto sender_video_codecs =
1912 caller->pc_factory()
1913 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1914 .codecs;
1915
1916 auto video_transceiver = caller->pc()->GetTransceivers().front();
1917
1918 // Check that RTX codec is properly added
1919 auto video_codecs_vpx_rtx = sender_video_codecs;
1920 auto it =
1921 std::remove_if(video_codecs_vpx_rtx.begin(), video_codecs_vpx_rtx.end(),
1922 [](const webrtc::RtpCodecCapability& codec) {
1923 return codec.name != cricket::kRtxCodecName &&
1924 codec.name != cricket::kVp8CodecName &&
1925 codec.name != cricket::kVp9CodecName;
1926 });
1927 video_codecs_vpx_rtx.erase(it, video_codecs_vpx_rtx.end());
1928 absl::c_reverse(video_codecs_vpx_rtx);
1929 EXPECT_EQ(video_codecs_vpx_rtx.size(), 3u); // VP8, VP9, RTX
1930 EXPECT_TRUE(
1931 video_transceiver->SetCodecPreferences(video_codecs_vpx_rtx).ok());
1932 auto offer = caller->CreateOffer();
1933 auto codecs = offer->description()
1934 ->contents()[0]
1935 .media_description()
1936 ->as_video()
1937 ->codecs();
1938
1939 EXPECT_TRUE(CompareCodecs(video_codecs_vpx_rtx, codecs));
1940 EXPECT_EQ(codecs.size(), 4u);
1941}
1942
1943TEST_F(PeerConnectionMediaTestUnifiedPlan,
1944 SetCodecPreferencesVideoCodecsNegotiation) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001945 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Johannes Kron3e983682020-03-29 22:17:00 +02001946 auto caller_video_codecs = caller_fake_engine->video().send_codecs();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001947 caller_video_codecs.push_back(cricket::VideoCodec(
1948 caller_video_codecs.back().id + 1, cricket::kVp8CodecName));
1949 caller_video_codecs.push_back(cricket::VideoCodec(
1950 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1951 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1952 std::to_string(caller_video_codecs.back().id - 1);
1953 caller_video_codecs.push_back(cricket::VideoCodec(
1954 caller_video_codecs.back().id + 1, cricket::kVp9CodecName));
1955 caller_video_codecs.push_back(cricket::VideoCodec(
1956 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1957 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1958 std::to_string(caller_video_codecs.back().id - 1);
1959 caller_fake_engine->SetVideoCodecs(caller_video_codecs);
1960
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001961 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001962 callee_fake_engine->SetVideoCodecs(caller_video_codecs);
1963
1964 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
1965 auto callee = CreatePeerConnection(std::move(callee_fake_engine));
1966
1967 auto video_codecs = caller->pc_factory()
1968 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1969 .codecs;
1970
1971 auto send_transceiver = caller->pc()->GetTransceivers().front();
1972
1973 auto video_codecs_vpx = video_codecs;
1974 auto it = std::remove_if(video_codecs_vpx.begin(), video_codecs_vpx.end(),
1975 [](const webrtc::RtpCodecCapability& codec) {
1976 return codec.name != cricket::kVp8CodecName &&
1977 codec.name != cricket::kVp9CodecName;
1978 });
1979 video_codecs_vpx.erase(it, video_codecs_vpx.end());
1980 EXPECT_EQ(video_codecs_vpx.size(), 2u); // VP8, VP9
1981 EXPECT_TRUE(send_transceiver->SetCodecPreferences(video_codecs_vpx).ok());
1982
1983 auto offer = caller->CreateOfferAndSetAsLocal();
1984 auto codecs = offer->description()
1985 ->contents()[0]
1986 .media_description()
1987 ->as_video()
1988 ->codecs();
1989
1990 EXPECT_EQ(codecs.size(), 2u); // VP8, VP9
1991 EXPECT_TRUE(CompareCodecs(video_codecs_vpx, codecs));
1992
1993 callee->SetRemoteDescription(std::move(offer));
1994
1995 auto recv_transceiver = callee->pc()->GetTransceivers().front();
1996 auto video_codecs_vp8_rtx = video_codecs;
1997 it = std::remove_if(video_codecs_vp8_rtx.begin(), video_codecs_vp8_rtx.end(),
1998 [](const webrtc::RtpCodecCapability& codec) {
1999 bool r = codec.name != cricket::kVp8CodecName &&
2000 codec.name != cricket::kRtxCodecName;
2001 return r;
2002 });
2003 video_codecs_vp8_rtx.erase(it, video_codecs_vp8_rtx.end());
2004 EXPECT_EQ(video_codecs_vp8_rtx.size(), 2u); // VP8, RTX
2005 recv_transceiver->SetCodecPreferences(video_codecs_vp8_rtx);
2006
2007 auto answer = callee->CreateAnswerAndSetAsLocal();
2008
2009 auto recv_codecs = answer->description()
2010 ->contents()[0]
2011 .media_description()
2012 ->as_video()
2013 ->codecs();
2014 EXPECT_EQ(recv_codecs.size(), 1u); // VP8
2015}
2016
2017TEST_F(PeerConnectionMediaTestUnifiedPlan,
2018 SetCodecPreferencesVideoCodecsNegotiationReverseOrder) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +02002019 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Johannes Kron3e983682020-03-29 22:17:00 +02002020 auto caller_video_codecs = caller_fake_engine->video().send_codecs();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002021 caller_video_codecs.push_back(cricket::VideoCodec(
2022 caller_video_codecs.back().id + 1, cricket::kVp8CodecName));
2023 caller_video_codecs.push_back(cricket::VideoCodec(
2024 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
2025 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
2026 std::to_string(caller_video_codecs.back().id - 1);
2027 caller_video_codecs.push_back(cricket::VideoCodec(
2028 caller_video_codecs.back().id + 1, cricket::kVp9CodecName));
2029 caller_video_codecs.push_back(cricket::VideoCodec(
2030 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
2031 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
2032 std::to_string(caller_video_codecs.back().id - 1);
2033 caller_fake_engine->SetVideoCodecs(caller_video_codecs);
2034
Mirko Bonadei317a1f02019-09-17 17:06:18 +02002035 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002036 callee_fake_engine->SetVideoCodecs(caller_video_codecs);
2037
2038 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
2039 auto callee = CreatePeerConnection(std::move(callee_fake_engine));
2040
2041 auto video_codecs = caller->pc_factory()
2042 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
2043 .codecs;
2044
2045 auto send_transceiver = caller->pc()->GetTransceivers().front();
2046
2047 auto video_codecs_vpx = video_codecs;
2048 auto it = std::remove_if(video_codecs_vpx.begin(), video_codecs_vpx.end(),
2049 [](const webrtc::RtpCodecCapability& codec) {
2050 return codec.name != cricket::kVp8CodecName &&
2051 codec.name != cricket::kVp9CodecName;
2052 });
2053 video_codecs_vpx.erase(it, video_codecs_vpx.end());
2054 EXPECT_EQ(video_codecs_vpx.size(), 2u); // VP8, VP9
2055 EXPECT_TRUE(send_transceiver->SetCodecPreferences(video_codecs_vpx).ok());
2056
2057 auto video_codecs_vpx_reverse = video_codecs_vpx;
2058 absl::c_reverse(video_codecs_vpx_reverse);
2059
2060 auto offer = caller->CreateOfferAndSetAsLocal();
2061 auto codecs = offer->description()
2062 ->contents()[0]
2063 .media_description()
2064 ->as_video()
2065 ->codecs();
2066 EXPECT_EQ(codecs.size(), 2u); // VP9, VP8
2067 EXPECT_TRUE(CompareCodecs(video_codecs_vpx, codecs));
2068
2069 callee->SetRemoteDescription(std::move(offer));
2070
2071 auto recv_transceiver = callee->pc()->GetTransceivers().front();
2072 recv_transceiver->SetCodecPreferences(video_codecs_vpx_reverse);
2073
2074 auto answer = callee->CreateAnswerAndSetAsLocal();
2075
2076 auto recv_codecs = answer->description()
2077 ->contents()[0]
2078 .media_description()
2079 ->as_video()
2080 ->codecs();
2081
2082 EXPECT_TRUE(CompareCodecs(video_codecs_vpx_reverse, recv_codecs));
2083}
2084
Philipp Hancke3ac73bd2021-05-11 14:13:06 +02002085TEST_F(PeerConnectionMediaTestUnifiedPlan,
2086 SetCodecPreferencesVoiceActivityDetection) {
2087 auto fake_engine = std::make_unique<FakeMediaEngine>();
2088 AddComfortNoiseCodecsToSend(fake_engine.get());
2089 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
2090
2091 RTCOfferAnswerOptions options;
2092 auto offer = caller->CreateOffer(options);
2093 EXPECT_TRUE(HasAnyComfortNoiseCodecs(offer->description()));
2094
2095 auto transceiver = caller->pc()->GetTransceivers().front();
2096 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2097 cricket::MediaType::MEDIA_TYPE_AUDIO);
2098 EXPECT_TRUE(transceiver->SetCodecPreferences(capabilities.codecs).ok());
2099
2100 options.voice_activity_detection = false;
2101 offer = caller->CreateOffer(options);
2102 EXPECT_FALSE(HasAnyComfortNoiseCodecs(offer->description()));
2103}
2104
Taylor Brandstetterf7fcfb72021-09-09 13:39:38 -07002105// If the "default" payload types of audio/video codecs are the same, and
2106// audio/video are bundled (as is the default), payload types should be
2107// remapped to avoid conflict, as normally happens without using
2108// SetCodecPreferences.
2109TEST_F(PeerConnectionMediaTestUnifiedPlan,
2110 SetCodecPreferencesAvoidsPayloadTypeConflictInOffer) {
2111 auto fake_engine = std::make_unique<cricket::FakeMediaEngine>();
2112
2113 std::vector<cricket::AudioCodec> audio_codecs;
2114 audio_codecs.emplace_back(100, "foo", 0, 0, 1);
2115 audio_codecs.emplace_back(101, cricket::kRtxCodecName, 0, 0, 1);
2116 audio_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "100";
2117 fake_engine->SetAudioCodecs(audio_codecs);
2118
2119 std::vector<cricket::VideoCodec> video_codecs;
2120 video_codecs.emplace_back(100, "bar");
2121 video_codecs.emplace_back(101, cricket::kRtxCodecName);
2122 video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "100";
2123 fake_engine->SetVideoCodecs(video_codecs);
2124
2125 auto caller = CreatePeerConnectionWithAudioVideo(std::move(fake_engine));
2126 auto transceivers = caller->pc()->GetTransceivers();
2127 ASSERT_EQ(2u, transceivers.size());
2128
2129 auto audio_transceiver = caller->pc()->GetTransceivers()[0];
2130 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2131 cricket::MediaType::MEDIA_TYPE_AUDIO);
2132 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(capabilities.codecs).ok());
2133
2134 auto video_transceiver = caller->pc()->GetTransceivers()[1];
2135 capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2136 cricket::MediaType::MEDIA_TYPE_VIDEO);
2137 EXPECT_TRUE(video_transceiver->SetCodecPreferences(capabilities.codecs).ok());
2138
2139 RTCOfferAnswerOptions options;
2140 auto offer = caller->CreateOffer(options);
2141 EXPECT_FALSE(HasPayloadTypeConflict(offer->description()));
2142 // Sanity check that we got the primary codec and RTX.
2143 EXPECT_EQ(2u, cricket::GetFirstAudioContentDescription(offer->description())
2144 ->codecs()
2145 .size());
2146 EXPECT_EQ(2u, cricket::GetFirstVideoContentDescription(offer->description())
2147 ->codecs()
2148 .size());
2149}
2150
2151// Same as above, but preferences set for the answer.
2152TEST_F(PeerConnectionMediaTestUnifiedPlan,
2153 SetCodecPreferencesAvoidsPayloadTypeConflictInAnswer) {
2154 auto fake_engine = std::make_unique<cricket::FakeMediaEngine>();
2155
2156 std::vector<cricket::AudioCodec> audio_codecs;
2157 audio_codecs.emplace_back(100, "foo", 0, 0, 1);
2158 audio_codecs.emplace_back(101, cricket::kRtxCodecName, 0, 0, 1);
2159 audio_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "100";
2160 fake_engine->SetAudioCodecs(audio_codecs);
2161
2162 std::vector<cricket::VideoCodec> video_codecs;
2163 video_codecs.emplace_back(100, "bar");
2164 video_codecs.emplace_back(101, cricket::kRtxCodecName);
2165 video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "100";
2166 fake_engine->SetVideoCodecs(video_codecs);
2167
2168 auto caller = CreatePeerConnectionWithAudioVideo(std::move(fake_engine));
2169
2170 RTCOfferAnswerOptions options;
2171 caller->SetRemoteDescription(caller->CreateOffer(options));
2172
2173 auto transceivers = caller->pc()->GetTransceivers();
2174 ASSERT_EQ(2u, transceivers.size());
2175
2176 auto audio_transceiver = caller->pc()->GetTransceivers()[0];
2177 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2178 cricket::MediaType::MEDIA_TYPE_AUDIO);
2179 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(capabilities.codecs).ok());
2180
2181 auto video_transceiver = caller->pc()->GetTransceivers()[1];
2182 capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2183 cricket::MediaType::MEDIA_TYPE_VIDEO);
2184 EXPECT_TRUE(video_transceiver->SetCodecPreferences(capabilities.codecs).ok());
2185
2186 auto answer = caller->CreateAnswer(options);
2187
2188 EXPECT_FALSE(HasPayloadTypeConflict(answer->description()));
2189 // Sanity check that we got the primary codec and RTX.
2190 EXPECT_EQ(2u, cricket::GetFirstAudioContentDescription(answer->description())
2191 ->codecs()
2192 .size());
2193 EXPECT_EQ(2u, cricket::GetFirstVideoContentDescription(answer->description())
2194 ->codecs()
2195 .size());
2196}
2197
2198// Same as above, but preferences set for a subsequent offer.
2199TEST_F(PeerConnectionMediaTestUnifiedPlan,
2200 SetCodecPreferencesAvoidsPayloadTypeConflictInSubsequentOffer) {
2201 auto fake_engine = std::make_unique<cricket::FakeMediaEngine>();
2202
2203 std::vector<cricket::AudioCodec> audio_codecs;
2204 audio_codecs.emplace_back(100, "foo", 0, 0, 1);
2205 audio_codecs.emplace_back(101, cricket::kRtxCodecName, 0, 0, 1);
2206 audio_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "100";
2207 fake_engine->SetAudioCodecs(audio_codecs);
2208
2209 std::vector<cricket::VideoCodec> video_codecs;
2210 video_codecs.emplace_back(100, "bar");
2211 video_codecs.emplace_back(101, cricket::kRtxCodecName);
2212 video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "100";
2213 fake_engine->SetVideoCodecs(video_codecs);
2214
2215 auto caller = CreatePeerConnectionWithAudioVideo(std::move(fake_engine));
2216
2217 RTCOfferAnswerOptions options;
2218 caller->SetRemoteDescription(caller->CreateOffer(options));
2219 caller->SetLocalDescription(caller->CreateAnswer(options));
2220
2221 auto transceivers = caller->pc()->GetTransceivers();
2222 ASSERT_EQ(2u, transceivers.size());
2223
2224 auto audio_transceiver = caller->pc()->GetTransceivers()[0];
2225 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2226 cricket::MediaType::MEDIA_TYPE_AUDIO);
2227 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(capabilities.codecs).ok());
2228
2229 auto video_transceiver = caller->pc()->GetTransceivers()[1];
2230 capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2231 cricket::MediaType::MEDIA_TYPE_VIDEO);
2232 EXPECT_TRUE(video_transceiver->SetCodecPreferences(capabilities.codecs).ok());
2233
2234 auto reoffer = caller->CreateOffer(options);
2235
2236 EXPECT_FALSE(HasPayloadTypeConflict(reoffer->description()));
2237 // Sanity check that we got the primary codec and RTX.
2238 EXPECT_EQ(2u, cricket::GetFirstAudioContentDescription(reoffer->description())
2239 ->codecs()
2240 .size());
2241 EXPECT_EQ(2u, cricket::GetFirstVideoContentDescription(reoffer->description())
2242 ->codecs()
2243 .size());
2244}
2245
Mirko Bonadeic84f6612019-01-31 12:20:57 +01002246INSTANTIATE_TEST_SUITE_P(PeerConnectionMediaTest,
2247 PeerConnectionMediaTest,
Florent Castelli15a38de2022-04-06 00:38:21 +02002248 Values(SdpSemantics::kPlanB_DEPRECATED,
Mirko Bonadeic84f6612019-01-31 12:20:57 +01002249 SdpSemantics::kUnifiedPlan));
Steve Antonad7bffc2018-01-22 10:21:56 -08002250
Steve Anton8d3444d2017-10-20 15:30:51 -07002251} // namespace webrtc