blob: 2a3a0aff99701f57764f6924eb38436b0c48723e [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_;
144 auto pc = pc_factory->CreatePeerConnection(modified_config,
145 std::move(fake_port_allocator),
146 nullptr, observer.get());
Steve Anton8d3444d2017-10-20 15:30:51 -0700147 if (!pc) {
148 return nullptr;
149 }
150
Yves Gerey4e933292018-10-31 15:36:05 +0100151 observer->SetPeerConnectionInterface(pc.get());
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200152 auto wrapper = std::make_unique<PeerConnectionWrapperForMediaTest>(
Steve Anton8d3444d2017-10-20 15:30:51 -0700153 pc_factory, pc, std::move(observer));
154 wrapper->set_media_engine(media_engine_ptr);
155 return wrapper;
156 }
157
158 // Accepts the same arguments as CreatePeerConnection and adds default audio
Piotr (Peter) Slatala10aeb2a2018-11-14 10:57:24 -0800159 // track (but no video).
160 template <typename... Args>
161 WrapperPtr CreatePeerConnectionWithAudio(Args&&... args) {
162 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
163 if (!wrapper) {
164 return nullptr;
165 }
166 wrapper->AddAudioTrack("a");
167 return wrapper;
168 }
169
Florent Castelli2d9d82e2019-04-23 19:25:51 +0200170 // Accepts the same arguments as CreatePeerConnection and adds default video
171 // track (but no audio).
172 template <typename... Args>
173 WrapperPtr CreatePeerConnectionWithVideo(Args&&... args) {
174 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
175 if (!wrapper) {
176 return nullptr;
177 }
178 wrapper->AddVideoTrack("v");
179 return wrapper;
180 }
181
Piotr (Peter) Slatala10aeb2a2018-11-14 10:57:24 -0800182 // Accepts the same arguments as CreatePeerConnection and adds default audio
Steve Anton8d3444d2017-10-20 15:30:51 -0700183 // and video tracks.
184 template <typename... Args>
185 WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
186 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
187 if (!wrapper) {
188 return nullptr;
189 }
190 wrapper->AddAudioTrack("a");
191 wrapper->AddVideoTrack("v");
192 return wrapper;
193 }
194
Steve Anton4e70a722017-11-28 14:57:10 -0800195 RtpTransceiverDirection GetMediaContentDirection(
Steve Anton8d3444d2017-10-20 15:30:51 -0700196 const SessionDescriptionInterface* sdesc,
Steve Antonad7bffc2018-01-22 10:21:56 -0800197 cricket::MediaType media_type) {
198 auto* content =
199 cricket::GetFirstMediaContent(sdesc->description(), media_type);
200 RTC_DCHECK(content);
201 return content->media_description()->direction();
202 }
203
204 bool IsUnifiedPlan() const {
205 return sdp_semantics_ == SdpSemantics::kUnifiedPlan;
Steve Anton8d3444d2017-10-20 15:30:51 -0700206 }
207
208 std::unique_ptr<rtc::VirtualSocketServer> vss_;
209 rtc::AutoSocketServerThread main_;
Steve Antonad7bffc2018-01-22 10:21:56 -0800210 const SdpSemantics sdp_semantics_;
Steve Anton8d3444d2017-10-20 15:30:51 -0700211};
212
Steve Antonad7bffc2018-01-22 10:21:56 -0800213class PeerConnectionMediaTest
214 : public PeerConnectionMediaBaseTest,
215 public ::testing::WithParamInterface<SdpSemantics> {
216 protected:
217 PeerConnectionMediaTest() : PeerConnectionMediaBaseTest(GetParam()) {}
218};
219
220class PeerConnectionMediaTestUnifiedPlan : public PeerConnectionMediaBaseTest {
221 protected:
222 PeerConnectionMediaTestUnifiedPlan()
223 : PeerConnectionMediaBaseTest(SdpSemantics::kUnifiedPlan) {}
224};
225
226class PeerConnectionMediaTestPlanB : public PeerConnectionMediaBaseTest {
227 protected:
228 PeerConnectionMediaTestPlanB()
229 : PeerConnectionMediaBaseTest(SdpSemantics::kPlanB) {}
230};
231
232TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700233 FailToSetRemoteDescriptionIfCreateMediaChannelFails) {
234 auto caller = CreatePeerConnectionWithAudioVideo();
235 auto callee = CreatePeerConnectionWithAudioVideo();
236 callee->media_engine()->set_fail_create_channel(true);
237
238 std::string error;
239 ASSERT_FALSE(callee->SetRemoteDescription(caller->CreateOffer(), &error));
Steve Antonad7bffc2018-01-22 10:21:56 -0800240 EXPECT_PRED_FORMAT2(AssertStartsWith, error,
241 "Failed to set remote offer sdp: Failed to create");
Steve Anton8d3444d2017-10-20 15:30:51 -0700242}
243
Steve Antonad7bffc2018-01-22 10:21:56 -0800244TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700245 FailToSetLocalDescriptionIfCreateMediaChannelFails) {
246 auto caller = CreatePeerConnectionWithAudioVideo();
247 caller->media_engine()->set_fail_create_channel(true);
248
249 std::string error;
250 ASSERT_FALSE(caller->SetLocalDescription(caller->CreateOffer(), &error));
Steve Antonad7bffc2018-01-22 10:21:56 -0800251 EXPECT_PRED_FORMAT2(AssertStartsWith, error,
252 "Failed to set local offer sdp: Failed to create");
Steve Anton8d3444d2017-10-20 15:30:51 -0700253}
254
255std::vector<std::string> GetIds(
256 const std::vector<cricket::StreamParams>& streams) {
257 std::vector<std::string> ids;
Mirko Bonadei649a4c22019-01-29 10:11:53 +0100258 ids.reserve(streams.size());
Steve Anton8d3444d2017-10-20 15:30:51 -0700259 for (const auto& stream : streams) {
260 ids.push_back(stream.id);
261 }
262 return ids;
263}
264
265// Test that exchanging an offer and answer with each side having an audio and
266// video stream creates the appropriate send/recv streams in the underlying
267// media engine on both sides.
Steve Antonad7bffc2018-01-22 10:21:56 -0800268TEST_P(PeerConnectionMediaTest, AudioVideoOfferAnswerCreateSendRecvStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700269 const std::string kCallerAudioId = "caller_a";
270 const std::string kCallerVideoId = "caller_v";
271 const std::string kCalleeAudioId = "callee_a";
272 const std::string kCalleeVideoId = "callee_v";
273
274 auto caller = CreatePeerConnection();
275 caller->AddAudioTrack(kCallerAudioId);
276 caller->AddVideoTrack(kCallerVideoId);
277
278 auto callee = CreatePeerConnection();
279 callee->AddAudioTrack(kCalleeAudioId);
280 callee->AddVideoTrack(kCalleeVideoId);
281
282 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
283 ASSERT_TRUE(
284 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
285
286 auto* caller_voice = caller->media_engine()->GetVoiceChannel(0);
287 EXPECT_THAT(GetIds(caller_voice->recv_streams()),
288 ElementsAre(kCalleeAudioId));
289 EXPECT_THAT(GetIds(caller_voice->send_streams()),
290 ElementsAre(kCallerAudioId));
291
292 auto* caller_video = caller->media_engine()->GetVideoChannel(0);
293 EXPECT_THAT(GetIds(caller_video->recv_streams()),
294 ElementsAre(kCalleeVideoId));
295 EXPECT_THAT(GetIds(caller_video->send_streams()),
296 ElementsAre(kCallerVideoId));
297
298 auto* callee_voice = callee->media_engine()->GetVoiceChannel(0);
299 EXPECT_THAT(GetIds(callee_voice->recv_streams()),
300 ElementsAre(kCallerAudioId));
301 EXPECT_THAT(GetIds(callee_voice->send_streams()),
302 ElementsAre(kCalleeAudioId));
303
304 auto* callee_video = callee->media_engine()->GetVideoChannel(0);
305 EXPECT_THAT(GetIds(callee_video->recv_streams()),
306 ElementsAre(kCallerVideoId));
307 EXPECT_THAT(GetIds(callee_video->send_streams()),
308 ElementsAre(kCalleeVideoId));
309}
310
Steve Antonad7bffc2018-01-22 10:21:56 -0800311// Test that stopping the caller transceivers causes the media channels on the
312// callee to be destroyed after calling SetRemoteDescription on the generated
313// offer.
314// See next test for equivalent behavior with Plan B semantics.
315TEST_F(PeerConnectionMediaTestUnifiedPlan,
316 StoppedRemoteTransceiversRemovesMediaChannels) {
317 auto caller = CreatePeerConnectionWithAudioVideo();
318 auto callee = CreatePeerConnection();
319
320 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
321
322 // Stop both audio and video transceivers on the caller.
323 auto transceivers = caller->pc()->GetTransceivers();
324 ASSERT_EQ(2u, transceivers.size());
Harald Alvestrand6060df52020-08-11 09:54:02 +0200325 transceivers[0]->StopInternal();
326 transceivers[1]->StopInternal();
Steve Antonad7bffc2018-01-22 10:21:56 -0800327
328 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
329
330 ASSERT_FALSE(callee->media_engine()->GetVoiceChannel(0));
331 ASSERT_FALSE(callee->media_engine()->GetVideoChannel(0));
332}
333
Steve Anton8d3444d2017-10-20 15:30:51 -0700334// Test that removing streams from a subsequent offer causes the receive streams
335// on the callee to be removed.
Steve Antonad7bffc2018-01-22 10:21:56 -0800336// See previous test for equivalent behavior with Unified Plan semantics.
337TEST_F(PeerConnectionMediaTestPlanB, EmptyRemoteOfferRemovesRecvStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700338 auto caller = CreatePeerConnection();
339 auto caller_audio_track = caller->AddAudioTrack("a");
340 auto caller_video_track = caller->AddVideoTrack("v");
341 auto callee = CreatePeerConnectionWithAudioVideo();
342
Steve Antonad7bffc2018-01-22 10:21:56 -0800343 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700344
345 // Remove both tracks from caller.
Harald Alvestrand93dd7632022-01-19 12:28:45 +0000346 caller->pc()->RemoveTrackOrError(caller_audio_track);
347 caller->pc()->RemoveTrackOrError(caller_video_track);
Steve Anton8d3444d2017-10-20 15:30:51 -0700348
Steve Antonad7bffc2018-01-22 10:21:56 -0800349 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700350
351 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
Steve Antonad7bffc2018-01-22 10:21:56 -0800352 auto callee_video = callee->media_engine()->GetVideoChannel(0);
Steve Anton8d3444d2017-10-20 15:30:51 -0700353 EXPECT_EQ(1u, callee_voice->send_streams().size());
354 EXPECT_EQ(0u, callee_voice->recv_streams().size());
Steve Anton8d3444d2017-10-20 15:30:51 -0700355 EXPECT_EQ(1u, callee_video->send_streams().size());
356 EXPECT_EQ(0u, callee_video->recv_streams().size());
357}
358
Jonas Orelandfc1acd22018-08-24 10:58:37 +0200359// Test enabling of simulcast with Plan B semantics.
360// This test creating an offer.
361TEST_F(PeerConnectionMediaTestPlanB, SimulcastOffer) {
362 auto caller = CreatePeerConnection();
363 auto caller_video_track = caller->AddVideoTrack("v");
364 RTCOfferAnswerOptions options;
365 options.num_simulcast_layers = 3;
366 auto offer = caller->CreateOffer(options);
Jonas Olssona4d87372019-07-05 19:08:33 +0200367 auto* description = cricket::GetFirstMediaContent(offer->description(),
368 cricket::MEDIA_TYPE_VIDEO)
369 ->media_description();
Jonas Orelandfc1acd22018-08-24 10:58:37 +0200370 ASSERT_EQ(1u, description->streams().size());
371 ASSERT_TRUE(description->streams()[0].get_ssrc_group("SIM"));
372 EXPECT_EQ(3u, description->streams()[0].get_ssrc_group("SIM")->ssrcs.size());
373
374 // Check that it actually creates simulcast aswell.
375 caller->SetLocalDescription(std::move(offer));
376 auto senders = caller->pc()->GetSenders();
377 ASSERT_EQ(1u, senders.size());
378 EXPECT_EQ(cricket::MediaType::MEDIA_TYPE_VIDEO, senders[0]->media_type());
379 EXPECT_EQ(3u, senders[0]->GetParameters().encodings.size());
380}
381
382// Test enabling of simulcast with Plan B semantics.
383// This test creating an answer.
384TEST_F(PeerConnectionMediaTestPlanB, SimulcastAnswer) {
385 auto caller = CreatePeerConnection();
386 caller->AddVideoTrack("v0");
387 auto offer = caller->CreateOffer();
388 auto callee = CreatePeerConnection();
389 auto callee_video_track = callee->AddVideoTrack("v1");
390 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
391 RTCOfferAnswerOptions options;
392 options.num_simulcast_layers = 3;
393 auto answer = callee->CreateAnswer(options);
Jonas Olssona4d87372019-07-05 19:08:33 +0200394 auto* description = cricket::GetFirstMediaContent(answer->description(),
395 cricket::MEDIA_TYPE_VIDEO)
396 ->media_description();
Jonas Orelandfc1acd22018-08-24 10:58:37 +0200397 ASSERT_EQ(1u, description->streams().size());
398 ASSERT_TRUE(description->streams()[0].get_ssrc_group("SIM"));
399 EXPECT_EQ(3u, description->streams()[0].get_ssrc_group("SIM")->ssrcs.size());
400
401 // Check that it actually creates simulcast aswell.
402 callee->SetLocalDescription(std::move(answer));
403 auto senders = callee->pc()->GetSenders();
404 ASSERT_EQ(1u, senders.size());
405 EXPECT_EQ(cricket::MediaType::MEDIA_TYPE_VIDEO, senders[0]->media_type());
406 EXPECT_EQ(3u, senders[0]->GetParameters().encodings.size());
407}
408
Steve Antonad7bffc2018-01-22 10:21:56 -0800409// Test that stopping the callee transceivers causes the media channels to be
410// destroyed on the callee after calling SetLocalDescription on the local
411// answer.
412// See next test for equivalent behavior with Plan B semantics.
413TEST_F(PeerConnectionMediaTestUnifiedPlan,
414 StoppedLocalTransceiversRemovesMediaChannels) {
415 auto caller = CreatePeerConnectionWithAudioVideo();
416 auto callee = CreatePeerConnectionWithAudioVideo();
417
418 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
419
420 // Stop both audio and video transceivers on the callee.
421 auto transceivers = callee->pc()->GetTransceivers();
422 ASSERT_EQ(2u, transceivers.size());
Harald Alvestrand6060df52020-08-11 09:54:02 +0200423 transceivers[0]->StopInternal();
424 transceivers[1]->StopInternal();
Steve Antonad7bffc2018-01-22 10:21:56 -0800425
426 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
427
428 EXPECT_FALSE(callee->media_engine()->GetVoiceChannel(0));
429 EXPECT_FALSE(callee->media_engine()->GetVideoChannel(0));
430}
431
Steve Anton8d3444d2017-10-20 15:30:51 -0700432// Test that removing streams from a subsequent answer causes the send streams
433// on the callee to be removed when applied locally.
Steve Antonad7bffc2018-01-22 10:21:56 -0800434// See previous test for equivalent behavior with Unified Plan semantics.
435TEST_F(PeerConnectionMediaTestPlanB, EmptyLocalAnswerRemovesSendStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700436 auto caller = CreatePeerConnectionWithAudioVideo();
437 auto callee = CreatePeerConnection();
438 auto callee_audio_track = callee->AddAudioTrack("a");
439 auto callee_video_track = callee->AddVideoTrack("v");
440
Steve Antonad7bffc2018-01-22 10:21:56 -0800441 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700442
443 // Remove both tracks from callee.
Harald Alvestrand93dd7632022-01-19 12:28:45 +0000444 callee->pc()->RemoveTrackOrError(callee_audio_track);
445 callee->pc()->RemoveTrackOrError(callee_video_track);
Steve Anton8d3444d2017-10-20 15:30:51 -0700446
Steve Antonad7bffc2018-01-22 10:21:56 -0800447 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700448
449 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
Steve Antonad7bffc2018-01-22 10:21:56 -0800450 auto callee_video = callee->media_engine()->GetVideoChannel(0);
Steve Anton8d3444d2017-10-20 15:30:51 -0700451 EXPECT_EQ(0u, callee_voice->send_streams().size());
452 EXPECT_EQ(1u, callee_voice->recv_streams().size());
Steve Anton8d3444d2017-10-20 15:30:51 -0700453 EXPECT_EQ(0u, callee_video->send_streams().size());
454 EXPECT_EQ(1u, callee_video->recv_streams().size());
455}
456
457// Test that a new stream in a subsequent offer causes a new receive stream to
458// be created on the callee.
Steve Antonad7bffc2018-01-22 10:21:56 -0800459TEST_P(PeerConnectionMediaTest, NewStreamInRemoteOfferAddsRecvStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700460 auto caller = CreatePeerConnectionWithAudioVideo();
461 auto callee = CreatePeerConnection();
462
Steve Antonad7bffc2018-01-22 10:21:56 -0800463 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700464
465 // Add second set of tracks to the caller.
466 caller->AddAudioTrack("a2");
467 caller->AddVideoTrack("v2");
468
Steve Antonad7bffc2018-01-22 10:21:56 -0800469 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 15:30:51 -0700470
Steve Antonad7bffc2018-01-22 10:21:56 -0800471 auto a1 = callee->media_engine()->GetVoiceChannel(0);
472 auto a2 = callee->media_engine()->GetVoiceChannel(1);
473 auto v1 = callee->media_engine()->GetVideoChannel(0);
474 auto v2 = callee->media_engine()->GetVideoChannel(1);
475 if (IsUnifiedPlan()) {
476 ASSERT_TRUE(a1);
477 EXPECT_EQ(1u, a1->recv_streams().size());
478 ASSERT_TRUE(a2);
479 EXPECT_EQ(1u, a2->recv_streams().size());
480 ASSERT_TRUE(v1);
481 EXPECT_EQ(1u, v1->recv_streams().size());
482 ASSERT_TRUE(v2);
483 EXPECT_EQ(1u, v2->recv_streams().size());
484 } else {
485 ASSERT_TRUE(a1);
486 EXPECT_EQ(2u, a1->recv_streams().size());
487 ASSERT_FALSE(a2);
488 ASSERT_TRUE(v1);
489 EXPECT_EQ(2u, v1->recv_streams().size());
490 ASSERT_FALSE(v2);
491 }
Steve Anton8d3444d2017-10-20 15:30:51 -0700492}
493
494// Test that a new stream in a subsequent answer causes a new send stream to be
495// created on the callee when added locally.
Steve Antonad7bffc2018-01-22 10:21:56 -0800496TEST_P(PeerConnectionMediaTest, NewStreamInLocalAnswerAddsSendStreams) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700497 auto caller = CreatePeerConnection();
498 auto callee = CreatePeerConnectionWithAudioVideo();
499
Steve Anton22da89f2018-01-25 13:58:07 -0800500 RTCOfferAnswerOptions offer_options;
501 offer_options.offer_to_receive_audio =
Steve Anton8d3444d2017-10-20 15:30:51 -0700502 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
Steve Anton22da89f2018-01-25 13:58:07 -0800503 offer_options.offer_to_receive_video =
Steve Anton8d3444d2017-10-20 15:30:51 -0700504 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
Steve Anton22da89f2018-01-25 13:58:07 -0800505 RTCOfferAnswerOptions answer_options;
Steve Anton8d3444d2017-10-20 15:30:51 -0700506
Steve Anton22da89f2018-01-25 13:58:07 -0800507 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get(), offer_options,
508 answer_options));
Steve Anton8d3444d2017-10-20 15:30:51 -0700509
510 // Add second set of tracks to the callee.
511 callee->AddAudioTrack("a2");
512 callee->AddVideoTrack("v2");
513
Steve Anton22da89f2018-01-25 13:58:07 -0800514 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get(), offer_options,
515 answer_options));
Steve Anton8d3444d2017-10-20 15:30:51 -0700516
517 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
Steve Anton22da89f2018-01-25 13:58:07 -0800518 ASSERT_TRUE(callee_voice);
Steve Anton8d3444d2017-10-20 15:30:51 -0700519 auto callee_video = callee->media_engine()->GetVideoChannel(0);
Steve Anton22da89f2018-01-25 13:58:07 -0800520 ASSERT_TRUE(callee_video);
521
522 if (IsUnifiedPlan()) {
523 EXPECT_EQ(1u, callee_voice->send_streams().size());
524 EXPECT_EQ(1u, callee_video->send_streams().size());
525 } else {
526 EXPECT_EQ(2u, callee_voice->send_streams().size());
527 EXPECT_EQ(2u, callee_video->send_streams().size());
528 }
Steve Anton8d3444d2017-10-20 15:30:51 -0700529}
530
531// A PeerConnection with no local streams and no explicit answer constraints
532// should not reject any offered media sections.
Steve Antonad7bffc2018-01-22 10:21:56 -0800533TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700534 CreateAnswerWithNoStreamsAndDefaultOptionsDoesNotReject) {
535 auto caller = CreatePeerConnectionWithAudioVideo();
536 auto callee = CreatePeerConnection();
537 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
538 auto answer = callee->CreateAnswer();
539
540 const auto* audio_content =
541 cricket::GetFirstAudioContent(answer->description());
542 ASSERT_TRUE(audio_content);
543 EXPECT_FALSE(audio_content->rejected);
544
545 const auto* video_content =
546 cricket::GetFirstVideoContent(answer->description());
547 ASSERT_TRUE(video_content);
548 EXPECT_FALSE(video_content->rejected);
549}
550
Mirta Dvornicic479a3c02019-06-04 15:38:50 +0200551// Test that raw packetization is not set in the offer by default.
552TEST_P(PeerConnectionMediaTest, RawPacketizationNotSetInOffer) {
553 std::vector<cricket::VideoCodec> fake_codecs;
554 fake_codecs.push_back(cricket::VideoCodec(111, cricket::kVp8CodecName));
555 fake_codecs.push_back(cricket::VideoCodec(112, cricket::kRtxCodecName));
556 fake_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "111";
557 fake_codecs.push_back(cricket::VideoCodec(113, cricket::kVp9CodecName));
558 fake_codecs.push_back(cricket::VideoCodec(114, cricket::kH264CodecName));
559 fake_codecs.push_back(cricket::VideoCodec(115, "HEVC"));
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200560 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 15:38:50 +0200561 caller_fake_engine->SetVideoCodecs(fake_codecs);
562
563 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
564 auto offer = caller->CreateOfferAndSetAsLocal();
565 auto* offer_description =
566 cricket::GetFirstVideoContentDescription(offer->description());
567 for (const auto& codec : offer_description->codecs()) {
568 EXPECT_EQ(codec.packetization, absl::nullopt);
569 }
570}
571
572// Test that raw packetization is set in the offer and answer for all
573// video payload when raw_packetization_for_video is true.
574TEST_P(PeerConnectionMediaTest, RawPacketizationSetInOfferAndAnswer) {
575 std::vector<cricket::VideoCodec> fake_codecs;
576 fake_codecs.push_back(cricket::VideoCodec(111, cricket::kVp8CodecName));
577 fake_codecs.push_back(cricket::VideoCodec(112, cricket::kRtxCodecName));
578 fake_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "111";
579 fake_codecs.push_back(cricket::VideoCodec(113, cricket::kVp9CodecName));
580 fake_codecs.push_back(cricket::VideoCodec(114, cricket::kH264CodecName));
581 fake_codecs.push_back(cricket::VideoCodec(115, "HEVC"));
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200582 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 15:38:50 +0200583 caller_fake_engine->SetVideoCodecs(fake_codecs);
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200584 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 15:38:50 +0200585 callee_fake_engine->SetVideoCodecs(fake_codecs);
586
587 RTCOfferAnswerOptions options;
588 options.raw_packetization_for_video = true;
589
590 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
591 auto offer = caller->CreateOfferAndSetAsLocal(options);
592 auto* offer_description =
593 cricket::GetFirstVideoContentDescription(offer->description());
594 for (const auto& codec : offer_description->codecs()) {
595 if (codec.GetCodecType() == cricket::VideoCodec::CODEC_VIDEO) {
596 EXPECT_EQ(codec.packetization, cricket::kPacketizationParamRaw);
597 }
598 }
599
600 auto callee = CreatePeerConnectionWithVideo(std::move(callee_fake_engine));
601 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
602 auto answer = callee->CreateAnswerAndSetAsLocal(options);
603 auto* answer_description =
604 cricket::GetFirstVideoContentDescription(answer->description());
605 for (const auto& codec : answer_description->codecs()) {
606 if (codec.GetCodecType() == cricket::VideoCodec::CODEC_VIDEO) {
607 EXPECT_EQ(codec.packetization, cricket::kPacketizationParamRaw);
608 }
609 }
610
611 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
612}
613
614// Test that raw packetization is not set in the answer when
615// raw_packetization_for_video is true if it was not set in the offer.
616TEST_P(PeerConnectionMediaTest,
617 RawPacketizationNotSetInAnswerWhenNotSetInOffer) {
618 std::vector<cricket::VideoCodec> fake_codecs;
619 fake_codecs.push_back(cricket::VideoCodec(111, cricket::kVp8CodecName));
620 fake_codecs.push_back(cricket::VideoCodec(112, cricket::kRtxCodecName));
621 fake_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "111";
622 fake_codecs.push_back(cricket::VideoCodec(113, cricket::kVp9CodecName));
623 fake_codecs.push_back(cricket::VideoCodec(114, cricket::kH264CodecName));
624 fake_codecs.push_back(cricket::VideoCodec(115, "HEVC"));
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200625 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 15:38:50 +0200626 caller_fake_engine->SetVideoCodecs(fake_codecs);
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200627 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 15:38:50 +0200628 callee_fake_engine->SetVideoCodecs(fake_codecs);
629
630 RTCOfferAnswerOptions caller_options;
631 caller_options.raw_packetization_for_video = false;
632 RTCOfferAnswerOptions callee_options;
633 callee_options.raw_packetization_for_video = true;
634
635 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
636 auto offer = caller->CreateOfferAndSetAsLocal(caller_options);
637
638 auto callee = CreatePeerConnectionWithVideo(std::move(callee_fake_engine));
639 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
640 auto answer = callee->CreateAnswerAndSetAsLocal(callee_options);
641
642 auto* answer_description =
643 cricket::GetFirstVideoContentDescription(answer->description());
644 for (const auto& codec : answer_description->codecs()) {
645 EXPECT_EQ(codec.packetization, absl::nullopt);
646 }
647
648 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
649}
650
Steve Anton8d3444d2017-10-20 15:30:51 -0700651class PeerConnectionMediaOfferDirectionTest
Steve Antonad7bffc2018-01-22 10:21:56 -0800652 : public PeerConnectionMediaBaseTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700653 public ::testing::WithParamInterface<
Steve Antonad7bffc2018-01-22 10:21:56 -0800654 std::tuple<SdpSemantics,
655 std::tuple<bool, int, RtpTransceiverDirection>>> {
Steve Anton8d3444d2017-10-20 15:30:51 -0700656 protected:
Steve Antonad7bffc2018-01-22 10:21:56 -0800657 PeerConnectionMediaOfferDirectionTest()
658 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
659 auto param = std::get<1>(GetParam());
660 send_media_ = std::get<0>(param);
661 offer_to_receive_ = std::get<1>(param);
662 expected_direction_ = std::get<2>(param);
Steve Anton8d3444d2017-10-20 15:30:51 -0700663 }
664
665 bool send_media_;
666 int offer_to_receive_;
Steve Anton4e70a722017-11-28 14:57:10 -0800667 RtpTransceiverDirection expected_direction_;
Steve Anton8d3444d2017-10-20 15:30:51 -0700668};
669
670// Tests that the correct direction is set on the media description according
671// to the presence of a local media track and the offer_to_receive setting.
672TEST_P(PeerConnectionMediaOfferDirectionTest, VerifyDirection) {
673 auto caller = CreatePeerConnection();
674 if (send_media_) {
675 caller->AddAudioTrack("a");
676 }
677
678 RTCOfferAnswerOptions options;
679 options.offer_to_receive_audio = offer_to_receive_;
680 auto offer = caller->CreateOffer(options);
681
Steve Antonad7bffc2018-01-22 10:21:56 -0800682 auto* content = cricket::GetFirstMediaContent(offer->description(),
683 cricket::MEDIA_TYPE_AUDIO);
Steve Anton4e70a722017-11-28 14:57:10 -0800684 if (expected_direction_ == RtpTransceiverDirection::kInactive) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800685 EXPECT_FALSE(content);
Steve Anton8d3444d2017-10-20 15:30:51 -0700686 } else {
Steve Antonad7bffc2018-01-22 10:21:56 -0800687 EXPECT_EQ(expected_direction_, content->media_description()->direction());
Steve Anton8d3444d2017-10-20 15:30:51 -0700688 }
689}
690
691// Note that in these tests, MD_INACTIVE indicates that no media section is
692// included in the offer, not that the media direction is inactive.
Mirko Bonadeic84f6612019-01-31 12:20:57 +0100693INSTANTIATE_TEST_SUITE_P(
Steve Anton4e70a722017-11-28 14:57:10 -0800694 PeerConnectionMediaTest,
695 PeerConnectionMediaOfferDirectionTest,
Steve Antonad7bffc2018-01-22 10:21:56 -0800696 Combine(
697 Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan),
698 Values(std::make_tuple(false, -1, RtpTransceiverDirection::kInactive),
699 std::make_tuple(false, 0, RtpTransceiverDirection::kInactive),
700 std::make_tuple(false, 1, RtpTransceiverDirection::kRecvOnly),
701 std::make_tuple(true, -1, RtpTransceiverDirection::kSendRecv),
702 std::make_tuple(true, 0, RtpTransceiverDirection::kSendOnly),
703 std::make_tuple(true, 1, RtpTransceiverDirection::kSendRecv))));
Steve Anton8d3444d2017-10-20 15:30:51 -0700704
705class PeerConnectionMediaAnswerDirectionTest
Steve Antonad7bffc2018-01-22 10:21:56 -0800706 : public PeerConnectionMediaBaseTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700707 public ::testing::WithParamInterface<
Steve Antonad7bffc2018-01-22 10:21:56 -0800708 std::tuple<SdpSemantics, RtpTransceiverDirection, bool, int>> {
Steve Anton8d3444d2017-10-20 15:30:51 -0700709 protected:
Steve Antonad7bffc2018-01-22 10:21:56 -0800710 PeerConnectionMediaAnswerDirectionTest()
711 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
712 offer_direction_ = std::get<1>(GetParam());
713 send_media_ = std::get<2>(GetParam());
714 offer_to_receive_ = std::get<3>(GetParam());
Steve Anton8d3444d2017-10-20 15:30:51 -0700715 }
716
Steve Anton4e70a722017-11-28 14:57:10 -0800717 RtpTransceiverDirection offer_direction_;
Steve Anton8d3444d2017-10-20 15:30:51 -0700718 bool send_media_;
719 int offer_to_receive_;
720};
721
722// Tests that the direction in an answer is correct according to direction sent
723// in the offer, the presence of a local media track on the receive side and the
724// offer_to_receive setting.
725TEST_P(PeerConnectionMediaAnswerDirectionTest, VerifyDirection) {
Steve Anton22da89f2018-01-25 13:58:07 -0800726 if (IsUnifiedPlan() &&
727 offer_to_receive_ != RTCOfferAnswerOptions::kUndefined) {
728 // offer_to_receive_ is not implemented when creating answers with Unified
729 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800730 return;
731 }
Steve Anton22da89f2018-01-25 13:58:07 -0800732
Steve Anton8d3444d2017-10-20 15:30:51 -0700733 auto caller = CreatePeerConnection();
734 caller->AddAudioTrack("a");
735
736 // Create the offer with an audio section and set its direction.
737 auto offer = caller->CreateOffer();
738 cricket::GetFirstAudioContentDescription(offer->description())
739 ->set_direction(offer_direction_);
740
741 auto callee = CreatePeerConnection();
742 if (send_media_) {
743 callee->AddAudioTrack("a");
744 }
745 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
746
747 // Create the answer according to the test parameters.
748 RTCOfferAnswerOptions options;
749 options.offer_to_receive_audio = offer_to_receive_;
750 auto answer = callee->CreateAnswer(options);
751
752 // The expected direction in the answer is the intersection of each side's
753 // capability to send/recv media.
754 // For the offerer, the direction is given in the offer (offer_direction_).
755 // For the answerer, the direction has two components:
756 // 1. Send if the answerer has a local track to send.
757 // 2. Receive if the answerer has explicitly set the offer_to_receive to 1 or
758 // if it has been left as default.
Steve Anton4e70a722017-11-28 14:57:10 -0800759 bool offer_send = RtpTransceiverDirectionHasSend(offer_direction_);
760 bool offer_recv = RtpTransceiverDirectionHasRecv(offer_direction_);
Steve Anton8d3444d2017-10-20 15:30:51 -0700761
762 // The negotiated components determine the direction set in the answer.
Steve Anton1d03a752017-11-27 14:30:09 -0800763 bool negotiate_send = (send_media_ && offer_recv);
764 bool negotiate_recv = ((offer_to_receive_ != 0) && offer_send);
Steve Anton8d3444d2017-10-20 15:30:51 -0700765
766 auto expected_direction =
Steve Anton4e70a722017-11-28 14:57:10 -0800767 RtpTransceiverDirectionFromSendRecv(negotiate_send, negotiate_recv);
Steve Anton8d3444d2017-10-20 15:30:51 -0700768 EXPECT_EQ(expected_direction,
Steve Antonad7bffc2018-01-22 10:21:56 -0800769 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton8d3444d2017-10-20 15:30:51 -0700770}
771
772// Tests that the media section is rejected if and only if the callee has no
773// local media track and has set offer_to_receive to 0, no matter which
774// direction the caller indicated in the offer.
775TEST_P(PeerConnectionMediaAnswerDirectionTest, VerifyRejected) {
Steve Anton22da89f2018-01-25 13:58:07 -0800776 if (IsUnifiedPlan() &&
777 offer_to_receive_ != RTCOfferAnswerOptions::kUndefined) {
778 // offer_to_receive_ is not implemented when creating answers with Unified
779 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800780 return;
781 }
Steve Anton22da89f2018-01-25 13:58:07 -0800782
Steve Anton8d3444d2017-10-20 15:30:51 -0700783 auto caller = CreatePeerConnection();
784 caller->AddAudioTrack("a");
785
786 // Create the offer with an audio section and set its direction.
787 auto offer = caller->CreateOffer();
788 cricket::GetFirstAudioContentDescription(offer->description())
789 ->set_direction(offer_direction_);
790
791 auto callee = CreatePeerConnection();
792 if (send_media_) {
793 callee->AddAudioTrack("a");
794 }
795 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
796
797 // Create the answer according to the test parameters.
798 RTCOfferAnswerOptions options;
799 options.offer_to_receive_audio = offer_to_receive_;
800 auto answer = callee->CreateAnswer(options);
801
802 // The media section is rejected if and only if offer_to_receive is explicitly
803 // set to 0 and there is no media to send.
804 auto* audio_content = cricket::GetFirstAudioContent(answer->description());
805 ASSERT_TRUE(audio_content);
806 EXPECT_EQ((offer_to_receive_ == 0 && !send_media_), audio_content->rejected);
807}
808
Mirko Bonadeic84f6612019-01-31 12:20:57 +0100809INSTANTIATE_TEST_SUITE_P(PeerConnectionMediaTest,
810 PeerConnectionMediaAnswerDirectionTest,
811 Combine(Values(SdpSemantics::kPlanB,
812 SdpSemantics::kUnifiedPlan),
813 Values(RtpTransceiverDirection::kInactive,
814 RtpTransceiverDirection::kSendOnly,
815 RtpTransceiverDirection::kRecvOnly,
816 RtpTransceiverDirection::kSendRecv),
817 Bool(),
818 Values(-1, 0, 1)));
Steve Anton8d3444d2017-10-20 15:30:51 -0700819
Steve Antonad7bffc2018-01-22 10:21:56 -0800820TEST_P(PeerConnectionMediaTest, OfferHasDifferentDirectionForAudioVideo) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700821 auto caller = CreatePeerConnection();
822 caller->AddVideoTrack("v");
823
824 RTCOfferAnswerOptions options;
825 options.offer_to_receive_audio = 1;
826 options.offer_to_receive_video = 0;
827 auto offer = caller->CreateOffer(options);
828
Steve Anton4e70a722017-11-28 14:57:10 -0800829 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800830 GetMediaContentDirection(offer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton4e70a722017-11-28 14:57:10 -0800831 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800832 GetMediaContentDirection(offer.get(), cricket::MEDIA_TYPE_VIDEO));
Steve Anton8d3444d2017-10-20 15:30:51 -0700833}
834
Steve Antonad7bffc2018-01-22 10:21:56 -0800835TEST_P(PeerConnectionMediaTest, AnswerHasDifferentDirectionsForAudioVideo) {
Steve Antonad7bffc2018-01-22 10:21:56 -0800836 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 13:58:07 -0800837 // offer_to_receive_ is not implemented when creating answers with Unified
838 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -0800839 return;
840 }
841
Steve Anton8d3444d2017-10-20 15:30:51 -0700842 auto caller = CreatePeerConnectionWithAudioVideo();
843 auto callee = CreatePeerConnection();
844 callee->AddVideoTrack("v");
845
846 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
847
848 RTCOfferAnswerOptions options;
849 options.offer_to_receive_audio = 1;
850 options.offer_to_receive_video = 0;
851 auto answer = callee->CreateAnswer(options);
852
Steve Anton4e70a722017-11-28 14:57:10 -0800853 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800854 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton4e70a722017-11-28 14:57:10 -0800855 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
Steve Antonad7bffc2018-01-22 10:21:56 -0800856 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_VIDEO));
Steve Anton8d3444d2017-10-20 15:30:51 -0700857}
858
859void AddComfortNoiseCodecsToSend(cricket::FakeMediaEngine* media_engine) {
Philipp Hancke8498c252020-06-05 13:28:57 +0200860 const cricket::AudioCodec kComfortNoiseCodec8k(102, cricket::kCnCodecName,
861 8000, 0, 1);
862 const cricket::AudioCodec kComfortNoiseCodec16k(103, cricket::kCnCodecName,
863 16000, 0, 1);
Steve Anton8d3444d2017-10-20 15:30:51 -0700864
Sebastian Jansson6eb8a162018-11-16 11:29:55 +0100865 auto codecs = media_engine->voice().send_codecs();
Steve Anton8d3444d2017-10-20 15:30:51 -0700866 codecs.push_back(kComfortNoiseCodec8k);
867 codecs.push_back(kComfortNoiseCodec16k);
868 media_engine->SetAudioCodecs(codecs);
869}
870
871bool HasAnyComfortNoiseCodecs(const cricket::SessionDescription* desc) {
872 const auto* audio_desc = cricket::GetFirstAudioContentDescription(desc);
873 for (const auto& codec : audio_desc->codecs()) {
Philipp Hancke8498c252020-06-05 13:28:57 +0200874 if (codec.name == cricket::kCnCodecName) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700875 return true;
876 }
877 }
878 return false;
879}
880
Taylor Brandstetterf7fcfb72021-09-09 13:39:38 -0700881bool HasPayloadTypeConflict(const cricket::SessionDescription* desc) {
882 std::set<int> payload_types;
883 const auto* audio_desc = cricket::GetFirstAudioContentDescription(desc);
884 if (audio_desc) {
885 for (const auto& codec : audio_desc->codecs()) {
886 if (payload_types.count(codec.id) > 0) {
887 return true;
888 }
889 payload_types.insert(codec.id);
890 }
891 }
892 const auto* video_desc = cricket::GetFirstVideoContentDescription(desc);
893 if (video_desc) {
894 for (const auto& codec : video_desc->codecs()) {
895 if (payload_types.count(codec.id) > 0) {
896 return true;
897 }
898 payload_types.insert(codec.id);
899 }
900 }
901 return false;
902}
903
Steve Antonad7bffc2018-01-22 10:21:56 -0800904TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -0700905 CreateOfferWithNoVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
Philipp Hancke718acf62021-05-12 14:18:03 +0200906 auto fake_engine = std::make_unique<FakeMediaEngine>();
907 AddComfortNoiseCodecsToSend(fake_engine.get());
908 auto caller = CreatePeerConnectionWithAudioVideo(std::move(fake_engine));
Steve Anton8d3444d2017-10-20 15:30:51 -0700909
910 RTCOfferAnswerOptions options;
911 options.voice_activity_detection = false;
912 auto offer = caller->CreateOffer(options);
913
914 EXPECT_FALSE(HasAnyComfortNoiseCodecs(offer->description()));
915}
916
Steve Antonad7bffc2018-01-22 10:21:56 -0800917TEST_P(PeerConnectionMediaTest,
Philipp Hancke718acf62021-05-12 14:18:03 +0200918 CreateOfferWithVoiceActivityDetectionIncludesComfortNoiseCodecs) {
919 auto fake_engine = std::make_unique<FakeMediaEngine>();
920 AddComfortNoiseCodecsToSend(fake_engine.get());
921 auto caller = CreatePeerConnectionWithAudioVideo(std::move(fake_engine));
922
923 RTCOfferAnswerOptions options;
924 options.voice_activity_detection = true;
925 auto offer = caller->CreateOffer(options);
926
927 EXPECT_TRUE(HasAnyComfortNoiseCodecs(offer->description()));
928}
929
930TEST_P(PeerConnectionMediaTest,
931 CreateAnswerWithVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
Steve Anton8d3444d2017-10-20 15:30:51 -0700932 auto caller = CreatePeerConnectionWithAudioVideo();
Philipp Hancke718acf62021-05-12 14:18:03 +0200933
934 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
935 AddComfortNoiseCodecsToSend(callee_fake_engine.get());
936 auto callee =
937 CreatePeerConnectionWithAudioVideo(std::move(callee_fake_engine));
938
939 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
940
941 RTCOfferAnswerOptions options;
942 options.voice_activity_detection = true;
943 auto answer = callee->CreateAnswer(options);
944
945 EXPECT_FALSE(HasAnyComfortNoiseCodecs(answer->description()));
946}
947
948TEST_P(PeerConnectionMediaTest,
949 CreateAnswerWithNoVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
950 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
951 AddComfortNoiseCodecsToSend(caller_fake_engine.get());
952 auto caller =
953 CreatePeerConnectionWithAudioVideo(std::move(caller_fake_engine));
954
955 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
956 AddComfortNoiseCodecsToSend(callee_fake_engine.get());
957 auto callee =
958 CreatePeerConnectionWithAudioVideo(std::move(callee_fake_engine));
Steve Anton8d3444d2017-10-20 15:30:51 -0700959
960 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
961
962 RTCOfferAnswerOptions options;
963 options.voice_activity_detection = false;
964 auto answer = callee->CreateAnswer(options);
965
966 EXPECT_FALSE(HasAnyComfortNoiseCodecs(answer->description()));
967}
968
969// The following test group verifies that we reject answers with invalid media
970// sections as per RFC 3264.
971
972class PeerConnectionMediaInvalidMediaTest
Steve Antonad7bffc2018-01-22 10:21:56 -0800973 : public PeerConnectionMediaBaseTest,
974 public ::testing::WithParamInterface<std::tuple<
975 SdpSemantics,
Steve Anton8d3444d2017-10-20 15:30:51 -0700976 std::tuple<std::string,
977 std::function<void(cricket::SessionDescription*)>,
Steve Antonad7bffc2018-01-22 10:21:56 -0800978 std::string>>> {
Steve Anton8d3444d2017-10-20 15:30:51 -0700979 protected:
Steve Antonad7bffc2018-01-22 10:21:56 -0800980 PeerConnectionMediaInvalidMediaTest()
981 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
982 auto param = std::get<1>(GetParam());
983 mutator_ = std::get<1>(param);
984 expected_error_ = std::get<2>(param);
Steve Anton8d3444d2017-10-20 15:30:51 -0700985 }
986
987 std::function<void(cricket::SessionDescription*)> mutator_;
988 std::string expected_error_;
989};
990
991TEST_P(PeerConnectionMediaInvalidMediaTest, FailToSetRemoteAnswer) {
992 auto caller = CreatePeerConnectionWithAudioVideo();
993 auto callee = CreatePeerConnectionWithAudioVideo();
994
995 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
996
997 auto answer = callee->CreateAnswer();
998 mutator_(answer->description());
999
1000 std::string error;
1001 ASSERT_FALSE(caller->SetRemoteDescription(std::move(answer), &error));
1002 EXPECT_EQ("Failed to set remote answer sdp: " + expected_error_, error);
1003}
1004
1005TEST_P(PeerConnectionMediaInvalidMediaTest, FailToSetLocalAnswer) {
1006 auto caller = CreatePeerConnectionWithAudioVideo();
1007 auto callee = CreatePeerConnectionWithAudioVideo();
1008
1009 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1010
1011 auto answer = callee->CreateAnswer();
1012 mutator_(answer->description());
1013
1014 std::string error;
1015 ASSERT_FALSE(callee->SetLocalDescription(std::move(answer), &error));
1016 EXPECT_EQ("Failed to set local answer sdp: " + expected_error_, error);
1017}
1018
1019void RemoveVideoContent(cricket::SessionDescription* desc) {
1020 auto content_name = cricket::GetFirstVideoContent(desc)->name;
1021 desc->RemoveContentByName(content_name);
1022 desc->RemoveTransportInfoByName(content_name);
1023}
1024
1025void RenameVideoContent(cricket::SessionDescription* desc) {
1026 auto* video_content = cricket::GetFirstVideoContent(desc);
1027 auto* transport_info = desc->GetTransportInfoByName(video_content->name);
1028 video_content->name = "video_renamed";
1029 transport_info->content_name = video_content->name;
1030}
1031
1032void ReverseMediaContent(cricket::SessionDescription* desc) {
Steve Anton64b626b2019-01-28 17:25:26 -08001033 absl::c_reverse(desc->contents());
1034 absl::c_reverse(desc->transport_infos());
Steve Anton8d3444d2017-10-20 15:30:51 -07001035}
1036
1037void ChangeMediaTypeAudioToVideo(cricket::SessionDescription* desc) {
Steve Antonad7bffc2018-01-22 10:21:56 -08001038 std::string audio_mid = cricket::GetFirstAudioContent(desc)->name;
1039 desc->RemoveContentByName(audio_mid);
1040 auto* video_content = cricket::GetFirstVideoContent(desc);
1041 desc->AddContent(audio_mid, video_content->type,
Harald Alvestrand1716d392019-06-03 20:35:45 +02001042 video_content->media_description()->Clone());
Steve Anton8d3444d2017-10-20 15:30:51 -07001043}
1044
1045constexpr char kMLinesOutOfOrder[] =
1046 "The order of m-lines in answer doesn't match order in offer. Rejecting "
1047 "answer.";
1048
Mirko Bonadeic84f6612019-01-31 12:20:57 +01001049INSTANTIATE_TEST_SUITE_P(
Steve Anton8d3444d2017-10-20 15:30:51 -07001050 PeerConnectionMediaTest,
1051 PeerConnectionMediaInvalidMediaTest,
Steve Antonad7bffc2018-01-22 10:21:56 -08001052 Combine(Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan),
1053 Values(std::make_tuple("remove video",
1054 RemoveVideoContent,
1055 kMLinesOutOfOrder),
1056 std::make_tuple("rename video",
1057 RenameVideoContent,
1058 kMLinesOutOfOrder),
1059 std::make_tuple("reverse media sections",
1060 ReverseMediaContent,
1061 kMLinesOutOfOrder),
1062 std::make_tuple("change audio type to video type",
1063 ChangeMediaTypeAudioToVideo,
1064 kMLinesOutOfOrder))));
Steve Anton8d3444d2017-10-20 15:30:51 -07001065
1066// Test that the correct media engine send/recv streams are created when doing
1067// a series of offer/answers where audio/video are both sent, then audio is
1068// rejected, then both audio/video sent again.
Steve Antonad7bffc2018-01-22 10:21:56 -08001069TEST_P(PeerConnectionMediaTest, TestAVOfferWithAudioOnlyAnswer) {
Steve Antonad7bffc2018-01-22 10:21:56 -08001070 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 13:58:07 -08001071 // offer_to_receive_ is not implemented when creating answers with Unified
1072 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -08001073 return;
1074 }
1075
Steve Anton8d3444d2017-10-20 15:30:51 -07001076 RTCOfferAnswerOptions options_reject_video;
1077 options_reject_video.offer_to_receive_audio =
1078 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
1079 options_reject_video.offer_to_receive_video = 0;
1080
1081 auto caller = CreatePeerConnection();
1082 caller->AddAudioTrack("a");
1083 caller->AddVideoTrack("v");
1084 auto callee = CreatePeerConnection();
1085
1086 // Caller initially offers to send/recv audio and video.
1087 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1088 // Callee accepts the audio as recv only but rejects the video.
1089 ASSERT_TRUE(caller->SetRemoteDescription(
1090 callee->CreateAnswerAndSetAsLocal(options_reject_video)));
1091
1092 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1093 ASSERT_TRUE(caller_voice);
1094 EXPECT_EQ(0u, caller_voice->recv_streams().size());
1095 EXPECT_EQ(1u, caller_voice->send_streams().size());
1096 auto caller_video = caller->media_engine()->GetVideoChannel(0);
1097 EXPECT_FALSE(caller_video);
1098
1099 // Callee adds its own audio/video stream and offers to receive audio/video
1100 // too.
1101 callee->AddAudioTrack("a");
1102 auto callee_video_track = callee->AddVideoTrack("v");
1103 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1104 ASSERT_TRUE(
1105 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1106
1107 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1108 ASSERT_TRUE(callee_voice);
1109 EXPECT_EQ(1u, callee_voice->recv_streams().size());
1110 EXPECT_EQ(1u, callee_voice->send_streams().size());
1111 auto callee_video = callee->media_engine()->GetVideoChannel(0);
1112 ASSERT_TRUE(callee_video);
1113 EXPECT_EQ(1u, callee_video->recv_streams().size());
1114 EXPECT_EQ(1u, callee_video->send_streams().size());
1115
1116 // Callee removes video but keeps audio and rejects the video once again.
Harald Alvestrand93dd7632022-01-19 12:28:45 +00001117 callee->pc()->RemoveTrackOrError(callee_video_track);
Steve Anton8d3444d2017-10-20 15:30:51 -07001118 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1119 ASSERT_TRUE(
1120 callee->SetLocalDescription(callee->CreateAnswer(options_reject_video)));
1121
1122 callee_voice = callee->media_engine()->GetVoiceChannel(0);
1123 ASSERT_TRUE(callee_voice);
1124 EXPECT_EQ(1u, callee_voice->recv_streams().size());
1125 EXPECT_EQ(1u, callee_voice->send_streams().size());
1126 callee_video = callee->media_engine()->GetVideoChannel(0);
1127 EXPECT_FALSE(callee_video);
1128}
1129
1130// Test that the correct media engine send/recv streams are created when doing
1131// a series of offer/answers where audio/video are both sent, then video is
1132// rejected, then both audio/video sent again.
Steve Antonad7bffc2018-01-22 10:21:56 -08001133TEST_P(PeerConnectionMediaTest, TestAVOfferWithVideoOnlyAnswer) {
Steve Antonad7bffc2018-01-22 10:21:56 -08001134 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 13:58:07 -08001135 // offer_to_receive_ is not implemented when creating answers with Unified
1136 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 10:21:56 -08001137 return;
1138 }
1139
Steve Anton8d3444d2017-10-20 15:30:51 -07001140 // Disable the bundling here. If the media is bundled on audio
1141 // transport, then we can't reject the audio because switching the bundled
1142 // transport is not currently supported.
1143 // (https://bugs.chromium.org/p/webrtc/issues/detail?id=6704)
1144 RTCOfferAnswerOptions options_no_bundle;
1145 options_no_bundle.use_rtp_mux = false;
1146 RTCOfferAnswerOptions options_reject_audio = options_no_bundle;
1147 options_reject_audio.offer_to_receive_audio = 0;
1148 options_reject_audio.offer_to_receive_video =
1149 RTCOfferAnswerOptions::kMaxOfferToReceiveMedia;
1150
1151 auto caller = CreatePeerConnection();
1152 caller->AddAudioTrack("a");
1153 caller->AddVideoTrack("v");
1154 auto callee = CreatePeerConnection();
1155
1156 // Caller initially offers to send/recv audio and video.
1157 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1158 // Callee accepts the video as recv only but rejects the audio.
1159 ASSERT_TRUE(caller->SetRemoteDescription(
1160 callee->CreateAnswerAndSetAsLocal(options_reject_audio)));
1161
1162 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1163 EXPECT_FALSE(caller_voice);
1164 auto caller_video = caller->media_engine()->GetVideoChannel(0);
1165 ASSERT_TRUE(caller_video);
1166 EXPECT_EQ(0u, caller_video->recv_streams().size());
1167 EXPECT_EQ(1u, caller_video->send_streams().size());
1168
1169 // Callee adds its own audio/video stream and offers to receive audio/video
1170 // too.
1171 auto callee_audio_track = callee->AddAudioTrack("a");
1172 callee->AddVideoTrack("v");
1173 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1174 ASSERT_TRUE(caller->SetRemoteDescription(
1175 callee->CreateAnswerAndSetAsLocal(options_no_bundle)));
1176
1177 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1178 ASSERT_TRUE(callee_voice);
1179 EXPECT_EQ(1u, callee_voice->recv_streams().size());
1180 EXPECT_EQ(1u, callee_voice->send_streams().size());
1181 auto callee_video = callee->media_engine()->GetVideoChannel(0);
1182 ASSERT_TRUE(callee_video);
1183 EXPECT_EQ(1u, callee_video->recv_streams().size());
1184 EXPECT_EQ(1u, callee_video->send_streams().size());
1185
1186 // Callee removes audio but keeps video and rejects the audio once again.
Harald Alvestrand93dd7632022-01-19 12:28:45 +00001187 callee->pc()->RemoveTrackOrError(callee_audio_track);
Steve Anton8d3444d2017-10-20 15:30:51 -07001188 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1189 ASSERT_TRUE(
1190 callee->SetLocalDescription(callee->CreateAnswer(options_reject_audio)));
1191
1192 callee_voice = callee->media_engine()->GetVoiceChannel(0);
1193 EXPECT_FALSE(callee_voice);
1194 callee_video = callee->media_engine()->GetVideoChannel(0);
1195 ASSERT_TRUE(callee_video);
1196 EXPECT_EQ(1u, callee_video->recv_streams().size());
1197 EXPECT_EQ(1u, callee_video->send_streams().size());
1198}
1199
1200// Tests that if the underlying video encoder fails to be initialized (signaled
1201// by failing to set send codecs), the PeerConnection signals the error to the
1202// client.
Steve Antonad7bffc2018-01-22 10:21:56 -08001203TEST_P(PeerConnectionMediaTest, MediaEngineErrorPropagatedToClients) {
Steve Anton8d3444d2017-10-20 15:30:51 -07001204 auto caller = CreatePeerConnectionWithAudioVideo();
1205 auto callee = CreatePeerConnectionWithAudioVideo();
1206
1207 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1208
1209 auto video_channel = caller->media_engine()->GetVideoChannel(0);
1210 video_channel->set_fail_set_send_codecs(true);
1211
1212 std::string error;
1213 ASSERT_FALSE(caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(),
1214 &error));
Yura Yaroshevichbc1f9102020-06-03 21:15:22 +00001215 EXPECT_EQ(std::string("Failed to set remote answer sdp: Failed to set remote "
1216 "video description "
1217 "send parameters for m-section with mid='") +
1218 (IsUnifiedPlan() ? "1" : "video") + "'.",
1219 error);
Steve Anton8d3444d2017-10-20 15:30:51 -07001220}
1221
1222// Tests that if the underlying video encoder fails once then subsequent
1223// attempts at setting the local/remote description will also fail, even if
1224// SetSendCodecs no longer fails.
Steve Antonad7bffc2018-01-22 10:21:56 -08001225TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -07001226 FailToApplyDescriptionIfVideoEncoderHasEverFailed) {
1227 auto caller = CreatePeerConnectionWithAudioVideo();
1228 auto callee = CreatePeerConnectionWithAudioVideo();
1229
1230 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1231
1232 auto video_channel = caller->media_engine()->GetVideoChannel(0);
1233 video_channel->set_fail_set_send_codecs(true);
1234
1235 EXPECT_FALSE(
1236 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1237
1238 video_channel->set_fail_set_send_codecs(false);
1239
1240 EXPECT_FALSE(caller->SetRemoteDescription(callee->CreateAnswer()));
1241 EXPECT_FALSE(caller->SetLocalDescription(caller->CreateOffer()));
1242}
1243
1244void RenameContent(cricket::SessionDescription* desc,
Steve Antonad7bffc2018-01-22 10:21:56 -08001245 cricket::MediaType media_type,
Steve Anton8d3444d2017-10-20 15:30:51 -07001246 const std::string& new_name) {
Steve Antonad7bffc2018-01-22 10:21:56 -08001247 auto* content = cricket::GetFirstMediaContent(desc, media_type);
Steve Anton8d3444d2017-10-20 15:30:51 -07001248 RTC_DCHECK(content);
Steve Antonad7bffc2018-01-22 10:21:56 -08001249 std::string old_name = content->name;
Steve Anton8d3444d2017-10-20 15:30:51 -07001250 content->name = new_name;
1251 auto* transport = desc->GetTransportInfoByName(old_name);
1252 RTC_DCHECK(transport);
1253 transport->content_name = new_name;
Zhi Huangd2248f82018-04-10 14:41:03 -07001254
1255 // Rename the content name in the BUNDLE group.
1256 cricket::ContentGroup new_bundle_group =
1257 *desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1258 new_bundle_group.RemoveContentName(old_name);
1259 new_bundle_group.AddContentName(new_name);
1260 desc->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1261 desc->AddGroup(new_bundle_group);
Steve Anton8d3444d2017-10-20 15:30:51 -07001262}
1263
1264// Tests that an answer responds with the same MIDs as the offer.
Steve Antonad7bffc2018-01-22 10:21:56 -08001265TEST_P(PeerConnectionMediaTest, AnswerHasSameMidsAsOffer) {
Zhi Huang365381f2018-04-13 16:44:34 -07001266 const std::string kAudioMid = "notdefault1";
1267 const std::string kVideoMid = "notdefault2";
Steve Anton8d3444d2017-10-20 15:30:51 -07001268
1269 auto caller = CreatePeerConnectionWithAudioVideo();
1270 auto callee = CreatePeerConnectionWithAudioVideo();
1271
1272 auto offer = caller->CreateOffer();
Steve Antonad7bffc2018-01-22 10:21:56 -08001273 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, kAudioMid);
1274 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, kVideoMid);
Steve Anton8d3444d2017-10-20 15:30:51 -07001275 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1276
1277 auto answer = callee->CreateAnswer();
1278 EXPECT_EQ(kAudioMid,
1279 cricket::GetFirstAudioContent(answer->description())->name);
1280 EXPECT_EQ(kVideoMid,
1281 cricket::GetFirstVideoContent(answer->description())->name);
1282}
1283
1284// Test that if the callee creates a re-offer, the MIDs are the same as the
1285// original offer.
Steve Antonad7bffc2018-01-22 10:21:56 -08001286TEST_P(PeerConnectionMediaTest, ReOfferHasSameMidsAsFirstOffer) {
Zhi Huang365381f2018-04-13 16:44:34 -07001287 const std::string kAudioMid = "notdefault1";
1288 const std::string kVideoMid = "notdefault2";
Steve Anton8d3444d2017-10-20 15:30:51 -07001289
1290 auto caller = CreatePeerConnectionWithAudioVideo();
1291 auto callee = CreatePeerConnectionWithAudioVideo();
1292
1293 auto offer = caller->CreateOffer();
Steve Antonad7bffc2018-01-22 10:21:56 -08001294 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, kAudioMid);
1295 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, kVideoMid);
Steve Anton8d3444d2017-10-20 15:30:51 -07001296 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1297 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1298
1299 auto reoffer = callee->CreateOffer();
1300 EXPECT_EQ(kAudioMid,
1301 cricket::GetFirstAudioContent(reoffer->description())->name);
1302 EXPECT_EQ(kVideoMid,
1303 cricket::GetFirstVideoContent(reoffer->description())->name);
1304}
1305
Steve Anton06817cd2018-12-18 15:55:30 -08001306// Test that SetRemoteDescription returns an error if there are two m= sections
1307// with the same MID value.
1308TEST_P(PeerConnectionMediaTest, SetRemoteDescriptionFailsWithDuplicateMids) {
1309 auto caller = CreatePeerConnectionWithAudioVideo();
1310 auto callee = CreatePeerConnectionWithAudioVideo();
1311
1312 auto offer = caller->CreateOffer();
1313 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, "same");
1314 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, "same");
1315
1316 std::string error;
1317 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer), &error));
1318 EXPECT_EQ(error,
1319 "Failed to set remote offer sdp: Duplicate a=mid value 'same'.");
1320}
1321
Steve Antonad7bffc2018-01-22 10:21:56 -08001322TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 15:30:51 -07001323 CombinedAudioVideoBweConfigPropagatedToMediaEngine) {
1324 RTCConfiguration config;
1325 config.combined_audio_video_bwe.emplace(true);
1326 auto caller = CreatePeerConnectionWithAudioVideo(config);
1327
1328 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
1329
1330 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1331 ASSERT_TRUE(caller_voice);
1332 const cricket::AudioOptions& audio_options = caller_voice->options();
1333 EXPECT_EQ(config.combined_audio_video_bwe,
1334 audio_options.combined_audio_video_bwe);
1335}
1336
Philipp Hancke7145a142021-09-28 07:46:06 +02001337// Test that if a RED codec refers to another codec in its fmtp line, but that
1338// codec's payload type was reassigned for some reason (either the remote
1339// endpoint selected a different payload type or there was a conflict), the RED
1340// fmtp line is modified to refer to the correct payload type.
1341TEST_P(PeerConnectionMediaTest, RedFmtpPayloadTypeReassigned) {
1342 std::vector<cricket::AudioCodec> caller_fake_codecs;
1343 caller_fake_codecs.push_back(cricket::AudioCodec(100, "foo", 0, 0, 1));
1344 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
1345 caller_fake_engine->SetAudioCodecs(caller_fake_codecs);
1346 auto caller = CreatePeerConnectionWithAudio(std::move(caller_fake_engine));
1347
1348 std::vector<cricket::AudioCodec> callee_fake_codecs;
1349 callee_fake_codecs.push_back(cricket::AudioCodec(120, "foo", 0, 0, 1));
1350 callee_fake_codecs.push_back(
1351 cricket::AudioCodec(121, cricket::kRedCodecName, 0, 0, 1));
1352 callee_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1353 "120/120");
1354 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
1355 callee_fake_engine->SetAudioCodecs(callee_fake_codecs);
1356 auto callee = CreatePeerConnectionWithAudio(std::move(callee_fake_engine));
1357
1358 // Offer from the caller establishes 100 as the "foo" payload type.
1359 auto offer = caller->CreateOfferAndSetAsLocal();
1360 callee->SetRemoteDescription(std::move(offer));
1361 auto answer = callee->CreateAnswerAndSetAsLocal();
1362 auto answer_description =
1363 cricket::GetFirstAudioContentDescription(answer->description());
1364 ASSERT_EQ(1u, answer_description->codecs().size());
1365
1366 // Offer from the callee should respect the established payload type, and
1367 // attempt to add RED, which should refer to the correct payload type.
1368 offer = callee->CreateOfferAndSetAsLocal();
1369 auto* offer_description =
1370 cricket::GetFirstAudioContentDescription(offer->description());
1371 ASSERT_EQ(2u, offer_description->codecs().size());
1372 for (const auto& codec : offer_description->codecs()) {
1373 if (codec.name == "foo") {
1374 ASSERT_EQ(100, codec.id);
1375 } else if (codec.name == cricket::kRedCodecName) {
1376 std::string fmtp;
1377 ASSERT_TRUE(codec.GetParam("", &fmtp));
1378 EXPECT_EQ("100/100", fmtp);
1379 }
1380 }
1381}
1382
1383// Test that RED without fmtp does match RED without fmtp.
1384TEST_P(PeerConnectionMediaTest, RedFmtpPayloadTypeNoFmtpMatchNoFmtp) {
1385 std::vector<cricket::AudioCodec> caller_fake_codecs;
1386 caller_fake_codecs.push_back(cricket::AudioCodec(100, "foo", 0, 0, 1));
1387 caller_fake_codecs.push_back(
1388 cricket::AudioCodec(101, cricket::kRedCodecName, 0, 0, 1));
1389 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
1390 caller_fake_engine->SetAudioCodecs(caller_fake_codecs);
1391 auto caller = CreatePeerConnectionWithAudio(std::move(caller_fake_engine));
1392
1393 std::vector<cricket::AudioCodec> callee_fake_codecs;
1394 callee_fake_codecs.push_back(cricket::AudioCodec(120, "foo", 0, 0, 1));
1395 callee_fake_codecs.push_back(
1396 cricket::AudioCodec(121, cricket::kRedCodecName, 0, 0, 1));
1397 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
1398 callee_fake_engine->SetAudioCodecs(callee_fake_codecs);
1399 auto callee = CreatePeerConnectionWithAudio(std::move(callee_fake_engine));
1400
1401 // Offer from the caller establishes 100 as the "foo" payload type.
1402 // Red (without fmtp) is negotiated.
1403 auto offer = caller->CreateOfferAndSetAsLocal();
1404 callee->SetRemoteDescription(std::move(offer));
1405 auto answer = callee->CreateAnswerAndSetAsLocal();
1406 auto answer_description =
1407 cricket::GetFirstAudioContentDescription(answer->description());
1408 ASSERT_EQ(2u, answer_description->codecs().size());
1409
1410 // Offer from the callee should respect the established payload type, and
1411 // attempt to add RED.
1412 offer = callee->CreateOfferAndSetAsLocal();
1413 auto* offer_description =
1414 cricket::GetFirstAudioContentDescription(offer->description());
1415 ASSERT_EQ(2u, offer_description->codecs().size());
1416 for (const auto& codec : offer_description->codecs()) {
1417 if (codec.name == "foo") {
1418 ASSERT_EQ(100, codec.id);
1419 } else if (codec.name == cricket::kRedCodecName) {
1420 ASSERT_EQ(101, codec.id);
1421 }
1422 }
1423}
1424
1425// Test that RED without fmtp does not match RED with fmtp.
1426TEST_P(PeerConnectionMediaTest, RedFmtpPayloadTypeNoFmtpNoMatchFmtp) {
1427 std::vector<cricket::AudioCodec> caller_fake_codecs;
1428 caller_fake_codecs.push_back(cricket::AudioCodec(100, "foo", 0, 0, 1));
1429 caller_fake_codecs.push_back(
1430 cricket::AudioCodec(101, cricket::kRedCodecName, 0, 0, 1));
1431 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
1432 caller_fake_engine->SetAudioCodecs(caller_fake_codecs);
1433 auto caller = CreatePeerConnectionWithAudio(std::move(caller_fake_engine));
1434
1435 std::vector<cricket::AudioCodec> callee_fake_codecs;
1436 callee_fake_codecs.push_back(cricket::AudioCodec(120, "foo", 0, 0, 1));
1437 callee_fake_codecs.push_back(
1438 cricket::AudioCodec(121, cricket::kRedCodecName, 0, 0, 1));
1439 callee_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1440 "120/120");
1441 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
1442 callee_fake_engine->SetAudioCodecs(callee_fake_codecs);
1443 auto callee = CreatePeerConnectionWithAudio(std::move(callee_fake_engine));
1444
1445 // Offer from the caller establishes 100 as the "foo" payload type.
1446 // It should not negotiate RED.
1447 auto offer = caller->CreateOfferAndSetAsLocal();
1448 callee->SetRemoteDescription(std::move(offer));
1449 auto answer = callee->CreateAnswerAndSetAsLocal();
1450 auto answer_description =
1451 cricket::GetFirstAudioContentDescription(answer->description());
1452 ASSERT_EQ(1u, answer_description->codecs().size());
1453
1454 // Offer from the callee should respect the established payload type, and
1455 // attempt to add RED, which should refer to the correct payload type.
1456 offer = callee->CreateOfferAndSetAsLocal();
1457 auto* offer_description =
1458 cricket::GetFirstAudioContentDescription(offer->description());
1459 ASSERT_EQ(2u, offer_description->codecs().size());
1460 for (const auto& codec : offer_description->codecs()) {
1461 if (codec.name == "foo") {
1462 ASSERT_EQ(100, codec.id);
1463 } else if (codec.name == cricket::kRedCodecName) {
1464 std::string fmtp;
1465 ASSERT_TRUE(
1466 codec.GetParam(cricket::kCodecParamNotInNameValueFormat, &fmtp));
1467 EXPECT_EQ("100/100", fmtp);
1468 }
1469 }
1470}
1471
1472// Test that RED with fmtp must match base codecs.
1473TEST_P(PeerConnectionMediaTest, RedFmtpPayloadTypeMustMatchBaseCodecs) {
1474 std::vector<cricket::AudioCodec> caller_fake_codecs;
1475 caller_fake_codecs.push_back(cricket::AudioCodec(100, "foo", 0, 0, 1));
1476 caller_fake_codecs.push_back(
1477 cricket::AudioCodec(101, cricket::kRedCodecName, 0, 0, 1));
1478 caller_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1479 "100/100");
1480 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
1481 caller_fake_engine->SetAudioCodecs(caller_fake_codecs);
1482 auto caller = CreatePeerConnectionWithAudio(std::move(caller_fake_engine));
1483
1484 std::vector<cricket::AudioCodec> callee_fake_codecs;
1485 callee_fake_codecs.push_back(cricket::AudioCodec(120, "foo", 0, 0, 1));
1486 callee_fake_codecs.push_back(
1487 cricket::AudioCodec(121, cricket::kRedCodecName, 0, 0, 1));
1488 callee_fake_codecs.push_back(cricket::AudioCodec(122, "bar", 0, 0, 1));
1489 callee_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1490 "122/122");
1491 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
1492 callee_fake_engine->SetAudioCodecs(callee_fake_codecs);
1493 auto callee = CreatePeerConnectionWithAudio(std::move(callee_fake_engine));
1494
1495 // Offer from the caller establishes 100 as the "foo" payload type.
1496 // It should not negotiate RED since RED is associated with foo, not bar.
1497 auto offer = caller->CreateOfferAndSetAsLocal();
1498 callee->SetRemoteDescription(std::move(offer));
1499 auto answer = callee->CreateAnswerAndSetAsLocal();
1500 auto answer_description =
1501 cricket::GetFirstAudioContentDescription(answer->description());
1502 ASSERT_EQ(1u, answer_description->codecs().size());
1503}
1504
1505// Test behaviour when the RED fmtp attempts to specify different codecs
1506// which is not supported.
1507TEST_P(PeerConnectionMediaTest, RedFmtpPayloadMixed) {
1508 std::vector<cricket::AudioCodec> caller_fake_codecs;
1509 caller_fake_codecs.push_back(cricket::AudioCodec(100, "foo", 0, 0, 1));
1510 caller_fake_codecs.push_back(cricket::AudioCodec(102, "bar", 0, 0, 1));
1511 caller_fake_codecs.push_back(
1512 cricket::AudioCodec(101, cricket::kRedCodecName, 0, 0, 1));
1513 caller_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1514 "100/102");
1515 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
1516 caller_fake_engine->SetAudioCodecs(caller_fake_codecs);
1517 auto caller = CreatePeerConnectionWithAudio(std::move(caller_fake_engine));
1518
1519 std::vector<cricket::AudioCodec> callee_fake_codecs;
1520 callee_fake_codecs.push_back(cricket::AudioCodec(120, "foo", 0, 0, 1));
1521 callee_fake_codecs.push_back(
1522 cricket::AudioCodec(121, cricket::kRedCodecName, 0, 0, 1));
1523 callee_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1524 "120/120");
1525 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
1526 callee_fake_engine->SetAudioCodecs(callee_fake_codecs);
1527 auto callee = CreatePeerConnectionWithAudio(std::move(callee_fake_engine));
1528
1529 // Offer from the caller establishes 100 as the "foo" payload type.
1530 auto offer = caller->CreateOfferAndSetAsLocal();
1531 callee->SetRemoteDescription(std::move(offer));
1532 auto answer = callee->CreateAnswerAndSetAsLocal();
1533 auto answer_description =
1534 cricket::GetFirstAudioContentDescription(answer->description());
1535 // RED is not negotiated.
1536 ASSERT_EQ(1u, answer_description->codecs().size());
1537}
1538
1539// Test behaviour when the RED fmtp attempts to negotiate different levels of
1540// redundancy.
1541TEST_P(PeerConnectionMediaTest, RedFmtpPayloadDifferentRedundancy) {
1542 std::vector<cricket::AudioCodec> caller_fake_codecs;
1543 caller_fake_codecs.push_back(cricket::AudioCodec(100, "foo", 0, 0, 1));
1544 caller_fake_codecs.push_back(
1545 cricket::AudioCodec(101, cricket::kRedCodecName, 0, 0, 1));
1546 caller_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1547 "100/100");
1548 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
1549 caller_fake_engine->SetAudioCodecs(caller_fake_codecs);
1550 auto caller = CreatePeerConnectionWithAudio(std::move(caller_fake_engine));
1551
1552 std::vector<cricket::AudioCodec> callee_fake_codecs;
1553 callee_fake_codecs.push_back(cricket::AudioCodec(120, "foo", 0, 0, 1));
1554 callee_fake_codecs.push_back(
1555 cricket::AudioCodec(121, cricket::kRedCodecName, 0, 0, 1));
1556 callee_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1557 "120/120/120");
1558 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
1559 callee_fake_engine->SetAudioCodecs(callee_fake_codecs);
1560 auto callee = CreatePeerConnectionWithAudio(std::move(callee_fake_engine));
1561
1562 // Offer from the caller establishes 100 as the "foo" payload type.
1563 auto offer = caller->CreateOfferAndSetAsLocal();
1564 callee->SetRemoteDescription(std::move(offer));
1565 auto answer = callee->CreateAnswerAndSetAsLocal();
1566 auto answer_description =
1567 cricket::GetFirstAudioContentDescription(answer->description());
1568 // RED is negotiated.
1569 ASSERT_EQ(2u, answer_description->codecs().size());
1570
1571 // Offer from the callee should respect the established payload type, and
1572 // attempt to add RED, which should refer to the correct payload type.
1573 offer = callee->CreateOfferAndSetAsLocal();
1574 auto* offer_description =
1575 cricket::GetFirstAudioContentDescription(offer->description());
1576 ASSERT_EQ(2u, offer_description->codecs().size());
1577 for (const auto& codec : offer_description->codecs()) {
1578 if (codec.name == "foo") {
1579 ASSERT_EQ(100, codec.id);
1580 } else if (codec.name == cricket::kRedCodecName) {
1581 std::string fmtp;
1582 ASSERT_TRUE(
1583 codec.GetParam(cricket::kCodecParamNotInNameValueFormat, &fmtp));
1584 EXPECT_EQ("100/100", fmtp);
1585 }
1586 }
1587}
1588
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001589template <typename C>
1590bool CompareCodecs(const std::vector<webrtc::RtpCodecCapability>& capabilities,
1591 const std::vector<C>& codecs) {
1592 bool capability_has_rtx =
1593 absl::c_any_of(capabilities, [](const webrtc::RtpCodecCapability& codec) {
1594 return codec.name == cricket::kRtxCodecName;
1595 });
1596 bool codecs_has_rtx = absl::c_any_of(codecs, [](const C& codec) {
1597 return codec.name == cricket::kRtxCodecName;
1598 });
1599
1600 std::vector<C> codecs_no_rtx;
1601 absl::c_copy_if(
1602 codecs, std::back_inserter(codecs_no_rtx),
1603 [](const C& codec) { return codec.name != cricket::kRtxCodecName; });
1604
1605 std::vector<webrtc::RtpCodecCapability> capabilities_no_rtx;
1606 absl::c_copy_if(capabilities, std::back_inserter(capabilities_no_rtx),
1607 [](const webrtc::RtpCodecCapability& codec) {
1608 return codec.name != cricket::kRtxCodecName;
1609 });
1610
1611 return capability_has_rtx == codecs_has_rtx &&
1612 absl::c_equal(
1613 capabilities_no_rtx, codecs_no_rtx,
1614 [](const webrtc::RtpCodecCapability& capability, const C& codec) {
1615 return codec.MatchesCapability(capability);
1616 });
1617}
1618
1619TEST_F(PeerConnectionMediaTestUnifiedPlan,
1620 SetCodecPreferencesAudioMissingRecvCodec) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001621 auto fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001622 auto send_codecs = fake_engine->voice().send_codecs();
1623 send_codecs.push_back(cricket::AudioCodec(send_codecs.back().id + 1,
1624 "send_only_codec", 0, 0, 1));
1625 fake_engine->SetAudioSendCodecs(send_codecs);
1626
1627 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
1628
1629 auto transceiver = caller->pc()->GetTransceivers().front();
1630 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
1631 cricket::MediaType::MEDIA_TYPE_AUDIO);
1632
1633 std::vector<webrtc::RtpCodecCapability> codecs;
1634 absl::c_copy_if(capabilities.codecs, std::back_inserter(codecs),
1635 [](const webrtc::RtpCodecCapability& codec) {
1636 return codec.name.find("_only_") != std::string::npos;
1637 });
1638
1639 auto result = transceiver->SetCodecPreferences(codecs);
1640 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1641}
1642
1643TEST_F(PeerConnectionMediaTestUnifiedPlan,
1644 SetCodecPreferencesAudioMissingSendCodec) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001645 auto fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001646 auto recv_codecs = fake_engine->voice().recv_codecs();
1647 recv_codecs.push_back(cricket::AudioCodec(recv_codecs.back().id + 1,
1648 "recv_only_codec", 0, 0, 1));
1649 fake_engine->SetAudioRecvCodecs(recv_codecs);
1650 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
1651
1652 auto transceiver = caller->pc()->GetTransceivers().front();
1653 auto capabilities = caller->pc_factory()->GetRtpReceiverCapabilities(
1654 cricket::MediaType::MEDIA_TYPE_AUDIO);
1655
1656 std::vector<webrtc::RtpCodecCapability> codecs;
1657 absl::c_copy_if(capabilities.codecs, std::back_inserter(codecs),
1658 [](const webrtc::RtpCodecCapability& codec) {
1659 return codec.name.find("_only_") != std::string::npos;
1660 });
1661
1662 auto result = transceiver->SetCodecPreferences(codecs);
1663 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1664}
1665
1666TEST_F(PeerConnectionMediaTestUnifiedPlan,
1667 SetCodecPreferencesAudioRejectsVideoCodec) {
1668 auto caller = CreatePeerConnectionWithAudio();
1669
1670 auto transceiver = caller->pc()->GetTransceivers().front();
1671 auto video_codecs =
1672 caller->pc_factory()
1673 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)
1674 .codecs;
1675 auto codecs =
1676 caller->pc_factory()
1677 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)
1678 .codecs;
1679 codecs.insert(codecs.end(), video_codecs.begin(), video_codecs.end());
1680 auto result = transceiver->SetCodecPreferences(codecs);
1681 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1682}
1683
1684TEST_F(PeerConnectionMediaTestUnifiedPlan,
1685 SetCodecPreferencesAudioRejectsOnlyRtxRedFec) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001686 auto fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001687 auto audio_codecs = fake_engine->voice().send_codecs();
1688 audio_codecs.push_back(cricket::AudioCodec(audio_codecs.back().id + 1,
1689 cricket::kRtxCodecName, 0, 0, 1));
1690 audio_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1691 std::to_string(audio_codecs.back().id - 1);
1692 audio_codecs.push_back(cricket::AudioCodec(audio_codecs.back().id + 1,
1693 cricket::kRedCodecName, 0, 0, 1));
1694 audio_codecs.push_back(cricket::AudioCodec(
1695 audio_codecs.back().id + 1, cricket::kUlpfecCodecName, 0, 0, 1));
1696 fake_engine->SetAudioCodecs(audio_codecs);
1697
1698 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
1699
1700 auto transceiver = caller->pc()->GetTransceivers().front();
1701 auto codecs =
1702 caller->pc_factory()
1703 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)
1704 .codecs;
1705 auto codecs_only_rtx_red_fec = codecs;
1706 auto it = std::remove_if(codecs_only_rtx_red_fec.begin(),
1707 codecs_only_rtx_red_fec.end(),
1708 [](const webrtc::RtpCodecCapability& codec) {
1709 return !(codec.name == cricket::kRtxCodecName ||
1710 codec.name == cricket::kRedCodecName ||
1711 codec.name == cricket::kUlpfecCodecName);
1712 });
1713 codecs_only_rtx_red_fec.erase(it, codecs_only_rtx_red_fec.end());
1714
1715 auto result = transceiver->SetCodecPreferences(codecs_only_rtx_red_fec);
1716 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1717}
1718
1719TEST_F(PeerConnectionMediaTestUnifiedPlan, SetCodecPreferencesAllAudioCodecs) {
1720 auto caller = CreatePeerConnectionWithAudio();
1721
1722 auto sender_audio_codecs =
1723 caller->pc_factory()
1724 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_AUDIO)
1725 .codecs;
1726
1727 auto audio_transceiver = caller->pc()->GetTransceivers().front();
1728
1729 // Normal case, set all capabilities as preferences
1730 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(sender_audio_codecs).ok());
1731 auto offer = caller->CreateOffer();
1732 auto codecs = offer->description()
1733 ->contents()[0]
1734 .media_description()
1735 ->as_audio()
1736 ->codecs();
1737 EXPECT_TRUE(CompareCodecs(sender_audio_codecs, codecs));
1738}
1739
1740TEST_F(PeerConnectionMediaTestUnifiedPlan,
1741 SetCodecPreferencesResetAudioCodecs) {
1742 auto caller = CreatePeerConnectionWithAudio();
1743
1744 auto sender_audio_codecs =
1745 caller->pc_factory()
1746 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_AUDIO)
1747 .codecs;
1748 std::vector<webrtc::RtpCodecCapability> empty_codecs = {};
1749
1750 auto audio_transceiver = caller->pc()->GetTransceivers().front();
1751
1752 // Normal case, reset codec preferences
1753 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(empty_codecs).ok());
1754 auto offer = caller->CreateOffer();
1755 auto codecs = offer->description()
1756 ->contents()[0]
1757 .media_description()
1758 ->as_audio()
1759 ->codecs();
1760 EXPECT_TRUE(CompareCodecs(sender_audio_codecs, codecs));
1761}
1762
1763TEST_F(PeerConnectionMediaTestUnifiedPlan,
1764 SetCodecPreferencesVideoRejectsAudioCodec) {
1765 auto caller = CreatePeerConnectionWithVideo();
1766
1767 auto transceiver = caller->pc()->GetTransceivers().front();
1768 auto audio_codecs =
1769 caller->pc_factory()
1770 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)
1771 .codecs;
1772 auto codecs =
1773 caller->pc_factory()
1774 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)
1775 .codecs;
1776 codecs.insert(codecs.end(), audio_codecs.begin(), audio_codecs.end());
1777 auto result = transceiver->SetCodecPreferences(codecs);
1778 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1779}
1780
1781TEST_F(PeerConnectionMediaTestUnifiedPlan,
1782 SetCodecPreferencesVideoRejectsOnlyRtxRedFec) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001783 auto fake_engine = std::make_unique<FakeMediaEngine>();
Johannes Kron3e983682020-03-29 22:17:00 +02001784 auto video_codecs = fake_engine->video().send_codecs();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001785 video_codecs.push_back(
1786 cricket::VideoCodec(video_codecs.back().id + 1, cricket::kRtxCodecName));
Johannes Kron3e983682020-03-29 22:17:00 +02001787 video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1788 std::to_string(video_codecs.back().id - 1);
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001789 video_codecs.push_back(
1790 cricket::VideoCodec(video_codecs.back().id + 1, cricket::kRedCodecName));
1791 video_codecs.push_back(cricket::VideoCodec(video_codecs.back().id + 1,
1792 cricket::kUlpfecCodecName));
1793 fake_engine->SetVideoCodecs(video_codecs);
1794
1795 auto caller = CreatePeerConnectionWithVideo(std::move(fake_engine));
1796
1797 auto transceiver = caller->pc()->GetTransceivers().front();
1798 auto codecs =
1799 caller->pc_factory()
1800 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)
1801 .codecs;
1802 auto codecs_only_rtx_red_fec = codecs;
1803 auto it = std::remove_if(codecs_only_rtx_red_fec.begin(),
1804 codecs_only_rtx_red_fec.end(),
1805 [](const webrtc::RtpCodecCapability& codec) {
1806 return !(codec.name == cricket::kRtxCodecName ||
1807 codec.name == cricket::kRedCodecName ||
1808 codec.name == cricket::kUlpfecCodecName);
1809 });
1810 codecs_only_rtx_red_fec.erase(it, codecs_only_rtx_red_fec.end());
1811
1812 auto result = transceiver->SetCodecPreferences(codecs_only_rtx_red_fec);
1813 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1814}
1815
1816TEST_F(PeerConnectionMediaTestUnifiedPlan, SetCodecPreferencesAllVideoCodecs) {
1817 auto caller = CreatePeerConnectionWithVideo();
1818
1819 auto sender_video_codecs =
1820 caller->pc_factory()
1821 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1822 .codecs;
1823
1824 auto video_transceiver = caller->pc()->GetTransceivers().front();
1825
1826 // Normal case, setting preferences to normal capabilities
1827 EXPECT_TRUE(video_transceiver->SetCodecPreferences(sender_video_codecs).ok());
1828 auto offer = caller->CreateOffer();
1829 auto codecs = offer->description()
1830 ->contents()[0]
1831 .media_description()
1832 ->as_video()
1833 ->codecs();
1834 EXPECT_TRUE(CompareCodecs(sender_video_codecs, codecs));
1835}
1836
1837TEST_F(PeerConnectionMediaTestUnifiedPlan,
1838 SetCodecPreferencesResetVideoCodecs) {
1839 auto caller = CreatePeerConnectionWithVideo();
1840
1841 auto sender_video_codecs =
1842 caller->pc_factory()
1843 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1844 .codecs;
1845
1846 std::vector<webrtc::RtpCodecCapability> empty_codecs = {};
1847
1848 auto video_transceiver = caller->pc()->GetTransceivers().front();
1849
1850 // Normal case, resetting preferences with empty list of codecs
1851 EXPECT_TRUE(video_transceiver->SetCodecPreferences(empty_codecs).ok());
1852 auto offer = caller->CreateOffer();
1853 auto codecs = offer->description()
1854 ->contents()[0]
1855 .media_description()
1856 ->as_video()
1857 ->codecs();
1858 EXPECT_TRUE(CompareCodecs(sender_video_codecs, codecs));
1859}
1860
1861TEST_F(PeerConnectionMediaTestUnifiedPlan,
1862 SetCodecPreferencesVideoCodecDuplicatesRemoved) {
1863 auto caller = CreatePeerConnectionWithVideo();
1864
1865 auto sender_video_codecs =
1866 caller->pc_factory()
1867 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1868 .codecs;
1869
1870 auto video_transceiver = caller->pc()->GetTransceivers().front();
1871
1872 // Check duplicates are removed
1873 auto single_codec = sender_video_codecs;
1874 single_codec.resize(1);
1875 auto duplicate_codec = single_codec;
1876 duplicate_codec.push_back(duplicate_codec.front());
1877 duplicate_codec.push_back(duplicate_codec.front());
1878 duplicate_codec.push_back(duplicate_codec.front());
1879
1880 EXPECT_TRUE(video_transceiver->SetCodecPreferences(duplicate_codec).ok());
1881 auto offer = caller->CreateOffer();
1882 auto codecs = offer->description()
1883 ->contents()[0]
1884 .media_description()
1885 ->as_video()
1886 ->codecs();
1887 EXPECT_TRUE(CompareCodecs(single_codec, codecs));
1888}
1889
1890TEST_F(PeerConnectionMediaTestUnifiedPlan, SetCodecPreferencesVideoWithRtx) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001891 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Johannes Kron3e983682020-03-29 22:17:00 +02001892 auto caller_video_codecs = caller_fake_engine->video().send_codecs();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001893 caller_video_codecs.push_back(cricket::VideoCodec(
1894 caller_video_codecs.back().id + 1, cricket::kVp8CodecName));
1895 caller_video_codecs.push_back(cricket::VideoCodec(
1896 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1897 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1898 std::to_string(caller_video_codecs.back().id - 1);
1899 caller_video_codecs.push_back(cricket::VideoCodec(
1900 caller_video_codecs.back().id + 1, cricket::kVp9CodecName));
1901 caller_video_codecs.push_back(cricket::VideoCodec(
1902 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1903 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1904 std::to_string(caller_video_codecs.back().id - 1);
1905 caller_fake_engine->SetVideoCodecs(caller_video_codecs);
1906
1907 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
1908
1909 auto sender_video_codecs =
1910 caller->pc_factory()
1911 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1912 .codecs;
1913
1914 auto video_transceiver = caller->pc()->GetTransceivers().front();
1915
1916 // Check that RTX codec is properly added
1917 auto video_codecs_vpx_rtx = sender_video_codecs;
1918 auto it =
1919 std::remove_if(video_codecs_vpx_rtx.begin(), video_codecs_vpx_rtx.end(),
1920 [](const webrtc::RtpCodecCapability& codec) {
1921 return codec.name != cricket::kRtxCodecName &&
1922 codec.name != cricket::kVp8CodecName &&
1923 codec.name != cricket::kVp9CodecName;
1924 });
1925 video_codecs_vpx_rtx.erase(it, video_codecs_vpx_rtx.end());
1926 absl::c_reverse(video_codecs_vpx_rtx);
1927 EXPECT_EQ(video_codecs_vpx_rtx.size(), 3u); // VP8, VP9, RTX
1928 EXPECT_TRUE(
1929 video_transceiver->SetCodecPreferences(video_codecs_vpx_rtx).ok());
1930 auto offer = caller->CreateOffer();
1931 auto codecs = offer->description()
1932 ->contents()[0]
1933 .media_description()
1934 ->as_video()
1935 ->codecs();
1936
1937 EXPECT_TRUE(CompareCodecs(video_codecs_vpx_rtx, codecs));
1938 EXPECT_EQ(codecs.size(), 4u);
1939}
1940
1941TEST_F(PeerConnectionMediaTestUnifiedPlan,
1942 SetCodecPreferencesVideoCodecsNegotiation) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001943 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Johannes Kron3e983682020-03-29 22:17:00 +02001944 auto caller_video_codecs = caller_fake_engine->video().send_codecs();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001945 caller_video_codecs.push_back(cricket::VideoCodec(
1946 caller_video_codecs.back().id + 1, cricket::kVp8CodecName));
1947 caller_video_codecs.push_back(cricket::VideoCodec(
1948 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1949 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1950 std::to_string(caller_video_codecs.back().id - 1);
1951 caller_video_codecs.push_back(cricket::VideoCodec(
1952 caller_video_codecs.back().id + 1, cricket::kVp9CodecName));
1953 caller_video_codecs.push_back(cricket::VideoCodec(
1954 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1955 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1956 std::to_string(caller_video_codecs.back().id - 1);
1957 caller_fake_engine->SetVideoCodecs(caller_video_codecs);
1958
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001959 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02001960 callee_fake_engine->SetVideoCodecs(caller_video_codecs);
1961
1962 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
1963 auto callee = CreatePeerConnection(std::move(callee_fake_engine));
1964
1965 auto video_codecs = caller->pc_factory()
1966 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1967 .codecs;
1968
1969 auto send_transceiver = caller->pc()->GetTransceivers().front();
1970
1971 auto video_codecs_vpx = video_codecs;
1972 auto it = std::remove_if(video_codecs_vpx.begin(), video_codecs_vpx.end(),
1973 [](const webrtc::RtpCodecCapability& codec) {
1974 return codec.name != cricket::kVp8CodecName &&
1975 codec.name != cricket::kVp9CodecName;
1976 });
1977 video_codecs_vpx.erase(it, video_codecs_vpx.end());
1978 EXPECT_EQ(video_codecs_vpx.size(), 2u); // VP8, VP9
1979 EXPECT_TRUE(send_transceiver->SetCodecPreferences(video_codecs_vpx).ok());
1980
1981 auto offer = caller->CreateOfferAndSetAsLocal();
1982 auto codecs = offer->description()
1983 ->contents()[0]
1984 .media_description()
1985 ->as_video()
1986 ->codecs();
1987
1988 EXPECT_EQ(codecs.size(), 2u); // VP8, VP9
1989 EXPECT_TRUE(CompareCodecs(video_codecs_vpx, codecs));
1990
1991 callee->SetRemoteDescription(std::move(offer));
1992
1993 auto recv_transceiver = callee->pc()->GetTransceivers().front();
1994 auto video_codecs_vp8_rtx = video_codecs;
1995 it = std::remove_if(video_codecs_vp8_rtx.begin(), video_codecs_vp8_rtx.end(),
1996 [](const webrtc::RtpCodecCapability& codec) {
1997 bool r = codec.name != cricket::kVp8CodecName &&
1998 codec.name != cricket::kRtxCodecName;
1999 return r;
2000 });
2001 video_codecs_vp8_rtx.erase(it, video_codecs_vp8_rtx.end());
2002 EXPECT_EQ(video_codecs_vp8_rtx.size(), 2u); // VP8, RTX
2003 recv_transceiver->SetCodecPreferences(video_codecs_vp8_rtx);
2004
2005 auto answer = callee->CreateAnswerAndSetAsLocal();
2006
2007 auto recv_codecs = answer->description()
2008 ->contents()[0]
2009 .media_description()
2010 ->as_video()
2011 ->codecs();
2012 EXPECT_EQ(recv_codecs.size(), 1u); // VP8
2013}
2014
2015TEST_F(PeerConnectionMediaTestUnifiedPlan,
2016 SetCodecPreferencesVideoCodecsNegotiationReverseOrder) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +02002017 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Johannes Kron3e983682020-03-29 22:17:00 +02002018 auto caller_video_codecs = caller_fake_engine->video().send_codecs();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002019 caller_video_codecs.push_back(cricket::VideoCodec(
2020 caller_video_codecs.back().id + 1, cricket::kVp8CodecName));
2021 caller_video_codecs.push_back(cricket::VideoCodec(
2022 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
2023 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
2024 std::to_string(caller_video_codecs.back().id - 1);
2025 caller_video_codecs.push_back(cricket::VideoCodec(
2026 caller_video_codecs.back().id + 1, cricket::kVp9CodecName));
2027 caller_video_codecs.push_back(cricket::VideoCodec(
2028 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
2029 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
2030 std::to_string(caller_video_codecs.back().id - 1);
2031 caller_fake_engine->SetVideoCodecs(caller_video_codecs);
2032
Mirko Bonadei317a1f02019-09-17 17:06:18 +02002033 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 19:25:51 +02002034 callee_fake_engine->SetVideoCodecs(caller_video_codecs);
2035
2036 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
2037 auto callee = CreatePeerConnection(std::move(callee_fake_engine));
2038
2039 auto video_codecs = caller->pc_factory()
2040 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
2041 .codecs;
2042
2043 auto send_transceiver = caller->pc()->GetTransceivers().front();
2044
2045 auto video_codecs_vpx = video_codecs;
2046 auto it = std::remove_if(video_codecs_vpx.begin(), video_codecs_vpx.end(),
2047 [](const webrtc::RtpCodecCapability& codec) {
2048 return codec.name != cricket::kVp8CodecName &&
2049 codec.name != cricket::kVp9CodecName;
2050 });
2051 video_codecs_vpx.erase(it, video_codecs_vpx.end());
2052 EXPECT_EQ(video_codecs_vpx.size(), 2u); // VP8, VP9
2053 EXPECT_TRUE(send_transceiver->SetCodecPreferences(video_codecs_vpx).ok());
2054
2055 auto video_codecs_vpx_reverse = video_codecs_vpx;
2056 absl::c_reverse(video_codecs_vpx_reverse);
2057
2058 auto offer = caller->CreateOfferAndSetAsLocal();
2059 auto codecs = offer->description()
2060 ->contents()[0]
2061 .media_description()
2062 ->as_video()
2063 ->codecs();
2064 EXPECT_EQ(codecs.size(), 2u); // VP9, VP8
2065 EXPECT_TRUE(CompareCodecs(video_codecs_vpx, codecs));
2066
2067 callee->SetRemoteDescription(std::move(offer));
2068
2069 auto recv_transceiver = callee->pc()->GetTransceivers().front();
2070 recv_transceiver->SetCodecPreferences(video_codecs_vpx_reverse);
2071
2072 auto answer = callee->CreateAnswerAndSetAsLocal();
2073
2074 auto recv_codecs = answer->description()
2075 ->contents()[0]
2076 .media_description()
2077 ->as_video()
2078 ->codecs();
2079
2080 EXPECT_TRUE(CompareCodecs(video_codecs_vpx_reverse, recv_codecs));
2081}
2082
Philipp Hancke3ac73bd2021-05-11 14:13:06 +02002083TEST_F(PeerConnectionMediaTestUnifiedPlan,
2084 SetCodecPreferencesVoiceActivityDetection) {
2085 auto fake_engine = std::make_unique<FakeMediaEngine>();
2086 AddComfortNoiseCodecsToSend(fake_engine.get());
2087 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
2088
2089 RTCOfferAnswerOptions options;
2090 auto offer = caller->CreateOffer(options);
2091 EXPECT_TRUE(HasAnyComfortNoiseCodecs(offer->description()));
2092
2093 auto transceiver = caller->pc()->GetTransceivers().front();
2094 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2095 cricket::MediaType::MEDIA_TYPE_AUDIO);
2096 EXPECT_TRUE(transceiver->SetCodecPreferences(capabilities.codecs).ok());
2097
2098 options.voice_activity_detection = false;
2099 offer = caller->CreateOffer(options);
2100 EXPECT_FALSE(HasAnyComfortNoiseCodecs(offer->description()));
2101}
2102
Taylor Brandstetterf7fcfb72021-09-09 13:39:38 -07002103// If the "default" payload types of audio/video codecs are the same, and
2104// audio/video are bundled (as is the default), payload types should be
2105// remapped to avoid conflict, as normally happens without using
2106// SetCodecPreferences.
2107TEST_F(PeerConnectionMediaTestUnifiedPlan,
2108 SetCodecPreferencesAvoidsPayloadTypeConflictInOffer) {
2109 auto fake_engine = std::make_unique<cricket::FakeMediaEngine>();
2110
2111 std::vector<cricket::AudioCodec> audio_codecs;
2112 audio_codecs.emplace_back(100, "foo", 0, 0, 1);
2113 audio_codecs.emplace_back(101, cricket::kRtxCodecName, 0, 0, 1);
2114 audio_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "100";
2115 fake_engine->SetAudioCodecs(audio_codecs);
2116
2117 std::vector<cricket::VideoCodec> video_codecs;
2118 video_codecs.emplace_back(100, "bar");
2119 video_codecs.emplace_back(101, cricket::kRtxCodecName);
2120 video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "100";
2121 fake_engine->SetVideoCodecs(video_codecs);
2122
2123 auto caller = CreatePeerConnectionWithAudioVideo(std::move(fake_engine));
2124 auto transceivers = caller->pc()->GetTransceivers();
2125 ASSERT_EQ(2u, transceivers.size());
2126
2127 auto audio_transceiver = caller->pc()->GetTransceivers()[0];
2128 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2129 cricket::MediaType::MEDIA_TYPE_AUDIO);
2130 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(capabilities.codecs).ok());
2131
2132 auto video_transceiver = caller->pc()->GetTransceivers()[1];
2133 capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2134 cricket::MediaType::MEDIA_TYPE_VIDEO);
2135 EXPECT_TRUE(video_transceiver->SetCodecPreferences(capabilities.codecs).ok());
2136
2137 RTCOfferAnswerOptions options;
2138 auto offer = caller->CreateOffer(options);
2139 EXPECT_FALSE(HasPayloadTypeConflict(offer->description()));
2140 // Sanity check that we got the primary codec and RTX.
2141 EXPECT_EQ(2u, cricket::GetFirstAudioContentDescription(offer->description())
2142 ->codecs()
2143 .size());
2144 EXPECT_EQ(2u, cricket::GetFirstVideoContentDescription(offer->description())
2145 ->codecs()
2146 .size());
2147}
2148
2149// Same as above, but preferences set for the answer.
2150TEST_F(PeerConnectionMediaTestUnifiedPlan,
2151 SetCodecPreferencesAvoidsPayloadTypeConflictInAnswer) {
2152 auto fake_engine = std::make_unique<cricket::FakeMediaEngine>();
2153
2154 std::vector<cricket::AudioCodec> audio_codecs;
2155 audio_codecs.emplace_back(100, "foo", 0, 0, 1);
2156 audio_codecs.emplace_back(101, cricket::kRtxCodecName, 0, 0, 1);
2157 audio_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "100";
2158 fake_engine->SetAudioCodecs(audio_codecs);
2159
2160 std::vector<cricket::VideoCodec> video_codecs;
2161 video_codecs.emplace_back(100, "bar");
2162 video_codecs.emplace_back(101, cricket::kRtxCodecName);
2163 video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "100";
2164 fake_engine->SetVideoCodecs(video_codecs);
2165
2166 auto caller = CreatePeerConnectionWithAudioVideo(std::move(fake_engine));
2167
2168 RTCOfferAnswerOptions options;
2169 caller->SetRemoteDescription(caller->CreateOffer(options));
2170
2171 auto transceivers = caller->pc()->GetTransceivers();
2172 ASSERT_EQ(2u, transceivers.size());
2173
2174 auto audio_transceiver = caller->pc()->GetTransceivers()[0];
2175 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2176 cricket::MediaType::MEDIA_TYPE_AUDIO);
2177 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(capabilities.codecs).ok());
2178
2179 auto video_transceiver = caller->pc()->GetTransceivers()[1];
2180 capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2181 cricket::MediaType::MEDIA_TYPE_VIDEO);
2182 EXPECT_TRUE(video_transceiver->SetCodecPreferences(capabilities.codecs).ok());
2183
2184 auto answer = caller->CreateAnswer(options);
2185
2186 EXPECT_FALSE(HasPayloadTypeConflict(answer->description()));
2187 // Sanity check that we got the primary codec and RTX.
2188 EXPECT_EQ(2u, cricket::GetFirstAudioContentDescription(answer->description())
2189 ->codecs()
2190 .size());
2191 EXPECT_EQ(2u, cricket::GetFirstVideoContentDescription(answer->description())
2192 ->codecs()
2193 .size());
2194}
2195
2196// Same as above, but preferences set for a subsequent offer.
2197TEST_F(PeerConnectionMediaTestUnifiedPlan,
2198 SetCodecPreferencesAvoidsPayloadTypeConflictInSubsequentOffer) {
2199 auto fake_engine = std::make_unique<cricket::FakeMediaEngine>();
2200
2201 std::vector<cricket::AudioCodec> audio_codecs;
2202 audio_codecs.emplace_back(100, "foo", 0, 0, 1);
2203 audio_codecs.emplace_back(101, cricket::kRtxCodecName, 0, 0, 1);
2204 audio_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "100";
2205 fake_engine->SetAudioCodecs(audio_codecs);
2206
2207 std::vector<cricket::VideoCodec> video_codecs;
2208 video_codecs.emplace_back(100, "bar");
2209 video_codecs.emplace_back(101, cricket::kRtxCodecName);
2210 video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "100";
2211 fake_engine->SetVideoCodecs(video_codecs);
2212
2213 auto caller = CreatePeerConnectionWithAudioVideo(std::move(fake_engine));
2214
2215 RTCOfferAnswerOptions options;
2216 caller->SetRemoteDescription(caller->CreateOffer(options));
2217 caller->SetLocalDescription(caller->CreateAnswer(options));
2218
2219 auto transceivers = caller->pc()->GetTransceivers();
2220 ASSERT_EQ(2u, transceivers.size());
2221
2222 auto audio_transceiver = caller->pc()->GetTransceivers()[0];
2223 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2224 cricket::MediaType::MEDIA_TYPE_AUDIO);
2225 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(capabilities.codecs).ok());
2226
2227 auto video_transceiver = caller->pc()->GetTransceivers()[1];
2228 capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2229 cricket::MediaType::MEDIA_TYPE_VIDEO);
2230 EXPECT_TRUE(video_transceiver->SetCodecPreferences(capabilities.codecs).ok());
2231
2232 auto reoffer = caller->CreateOffer(options);
2233
2234 EXPECT_FALSE(HasPayloadTypeConflict(reoffer->description()));
2235 // Sanity check that we got the primary codec and RTX.
2236 EXPECT_EQ(2u, cricket::GetFirstAudioContentDescription(reoffer->description())
2237 ->codecs()
2238 .size());
2239 EXPECT_EQ(2u, cricket::GetFirstVideoContentDescription(reoffer->description())
2240 ->codecs()
2241 .size());
2242}
2243
Mirko Bonadeic84f6612019-01-31 12:20:57 +01002244INSTANTIATE_TEST_SUITE_P(PeerConnectionMediaTest,
2245 PeerConnectionMediaTest,
2246 Values(SdpSemantics::kPlanB,
2247 SdpSemantics::kUnifiedPlan));
Steve Antonad7bffc2018-01-22 10:21:56 -08002248
Steve Anton8d3444d2017-10-20 15:30:51 -07002249} // namespace webrtc