blob: fab926522fc63e8a956596fe2c3594de0ae30876 [file] [log] [blame]
Steve Anton8d3444d2017-10-20 22:30:511/*
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:5915#include <algorithm>
16#include <functional>
17#include <iterator>
18#include <map>
Mirko Bonadei317a1f02019-09-17 15:06:1819#include <memory>
Taylor Brandstetterf7fcfb72021-09-09 20:39:3820#include <set>
Harald Alvestrandc24a2182022-02-23 13:44:5921#include <string>
Steve Anton8d3444d2017-10-20 22:30:5122#include <tuple>
Harald Alvestrandc24a2182022-02-23 13:44:5923#include <type_traits>
24#include <utility>
25#include <vector>
Steve Anton8d3444d2017-10-20 22:30:5126
Steve Anton64b626b2019-01-29 01:25:2627#include "absl/algorithm/container.h"
Mirta Dvornicic479a3c02019-06-04 13:38:5028#include "absl/types/optional.h"
Harald Alvestrandc24a2182022-02-23 13:44:5929#include "api/audio_options.h"
Steve Anton10542f22019-01-11 17:11:0030#include "api/call/call_factory_interface.h"
Harald Alvestrandc24a2182022-02-23 13:44:5931#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 08:19:4235#include "api/rtc_event_log/rtc_event_log_factory.h"
Harald Alvestrandc24a2182022-02-23 13:44:5936#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 08:19:4242#include "api/task_queue/default_task_queue_factory.h"
Harald Alvestrandc24a2182022-02-23 13:44:5943#include "api/task_queue/task_queue_factory.h"
44#include "media/base/codec.h"
Steve Anton10542f22019-01-11 17:11:0045#include "media/base/fake_media_engine.h"
Harald Alvestrandc24a2182022-02-23 13:44:5946#include "media/base/media_constants.h"
47#include "media/base/media_engine.h"
48#include "media/base/stream_params.h"
Steve Anton10542f22019-01-11 17:11:0049#include "p2p/base/fake_port_allocator.h"
Harald Alvestrandc24a2182022-02-23 13:44:5950#include "p2p/base/p2p_constants.h"
51#include "p2p/base/port_allocator.h"
52#include "p2p/base/transport_info.h"
Steve Anton10542f22019-01-11 17:11:0053#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:5956#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 22:30:5162#ifdef WEBRTC_ANDROID
Steve Anton10542f22019-01-11 17:11:0063#include "pc/test/android_test_initializer.h"
Steve Anton8d3444d2017-10-20 22:30:5164#endif
Steve Anton8d3444d2017-10-20 22:30:5165#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 17:11:0066#include "rtc_base/virtual_socket_server.h"
Steve Anton8d3444d2017-10-20 22:30:5167#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 22:30:5176using ::testing::ElementsAre;
Jonas Olssona4d87372019-07-05 17:08:3377using ::testing::Values;
Steve Anton8d3444d2017-10-20 22:30:5178
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 18:21:5692class PeerConnectionMediaBaseTest : public ::testing::Test {
Steve Anton8d3444d2017-10-20 22:30:5193 protected:
94 typedef std::unique_ptr<PeerConnectionWrapperForMediaTest> WrapperPtr;
95
Steve Antonad7bffc2018-01-22 18:21:5696 explicit PeerConnectionMediaBaseTest(SdpSemantics sdp_semantics)
97 : vss_(new rtc::VirtualSocketServer()),
98 main_(vss_.get()),
99 sdp_semantics_(sdp_semantics) {
Steve Anton8d3444d2017-10-20 22:30:51100#ifdef WEBRTC_ANDROID
101 InitializeAndroidObjects();
102#endif
103 }
104
105 WrapperPtr CreatePeerConnection() {
106 return CreatePeerConnection(RTCConfiguration());
107 }
108
Florent Castelli2d9d82e2019-04-23 17:25:51109 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
Mirko Bonadei317a1f02019-09-17 15:06:18110 return CreatePeerConnection(config, std::make_unique<FakeMediaEngine>());
Florent Castelli2d9d82e2019-04-23 17:25:51111 }
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 20:15:42118 // Creates PeerConnectionFactory and PeerConnection for given configuration.
Florent Castelli2d9d82e2019-04-23 17:25:51119 WrapperPtr CreatePeerConnection(
120 const RTCConfiguration& config,
121 std::unique_ptr<FakeMediaEngine> media_engine) {
Steve Anton8d3444d2017-10-20 22:30:51122 auto* media_engine_ptr = media_engine.get();
Anton Sukhanov98a462c2018-10-17 20:15:42123
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 08:19:42129 factory_dependencies.task_queue_factory = CreateDefaultTaskQueueFactory();
Anton Sukhanov98a462c2018-10-17 20:15:42130 factory_dependencies.media_engine = std::move(media_engine);
131 factory_dependencies.call_factory = CreateCallFactory();
Danil Chapovalov9da25bd2019-06-20 08:19:42132 factory_dependencies.event_log_factory =
Mirko Bonadei317a1f02019-09-17 15:06:18133 std::make_unique<RtcEventLogFactory>(
Danil Chapovalov9da25bd2019-06-20 08:19:42134 factory_dependencies.task_queue_factory.get());
Anton Sukhanov98a462c2018-10-17 20:15:42135
136 auto pc_factory =
137 CreateModularPeerConnectionFactory(std::move(factory_dependencies));
Steve Anton8d3444d2017-10-20 22:30:51138
Mirko Bonadei317a1f02019-09-17 15:06:18139 auto fake_port_allocator = std::make_unique<cricket::FakePortAllocator>(
Byoungchan Leed58f5262022-06-27 09:05:22140 rtc::Thread::Current(),
141 std::make_unique<rtc::BasicPacketSocketFactory>(vss_.get()));
Mirko Bonadei317a1f02019-09-17 15:06:18142 auto observer = std::make_unique<MockPeerConnectionObserver>();
Steve Antonad7bffc2018-01-22 18:21:56143 auto modified_config = config;
144 modified_config.sdp_semantics = sdp_semantics_;
Florent Castelli72424402022-04-06 01:45:10145 PeerConnectionDependencies pc_dependencies(observer.get());
146 pc_dependencies.allocator = std::move(fake_port_allocator);
147 auto result = pc_factory->CreatePeerConnectionOrError(
148 modified_config, std::move(pc_dependencies));
149 if (!result.ok()) {
Steve Anton8d3444d2017-10-20 22:30:51150 return nullptr;
151 }
152
Florent Castelli72424402022-04-06 01:45:10153 auto pc = result.MoveValue();
Yves Gerey4e933292018-10-31 14:36:05154 observer->SetPeerConnectionInterface(pc.get());
Mirko Bonadei317a1f02019-09-17 15:06:18155 auto wrapper = std::make_unique<PeerConnectionWrapperForMediaTest>(
Steve Anton8d3444d2017-10-20 22:30:51156 pc_factory, pc, std::move(observer));
157 wrapper->set_media_engine(media_engine_ptr);
158 return wrapper;
159 }
160
161 // Accepts the same arguments as CreatePeerConnection and adds default audio
Piotr (Peter) Slatala10aeb2a2018-11-14 18:57:24162 // track (but no video).
163 template <typename... Args>
164 WrapperPtr CreatePeerConnectionWithAudio(Args&&... args) {
165 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
166 if (!wrapper) {
167 return nullptr;
168 }
169 wrapper->AddAudioTrack("a");
170 return wrapper;
171 }
172
Florent Castelli2d9d82e2019-04-23 17:25:51173 // Accepts the same arguments as CreatePeerConnection and adds default video
174 // track (but no audio).
175 template <typename... Args>
176 WrapperPtr CreatePeerConnectionWithVideo(Args&&... args) {
177 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
178 if (!wrapper) {
179 return nullptr;
180 }
181 wrapper->AddVideoTrack("v");
182 return wrapper;
183 }
184
Piotr (Peter) Slatala10aeb2a2018-11-14 18:57:24185 // Accepts the same arguments as CreatePeerConnection and adds default audio
Steve Anton8d3444d2017-10-20 22:30:51186 // and video tracks.
187 template <typename... Args>
188 WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
189 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
190 if (!wrapper) {
191 return nullptr;
192 }
193 wrapper->AddAudioTrack("a");
194 wrapper->AddVideoTrack("v");
195 return wrapper;
196 }
197
Steve Anton4e70a722017-11-28 22:57:10198 RtpTransceiverDirection GetMediaContentDirection(
Steve Anton8d3444d2017-10-20 22:30:51199 const SessionDescriptionInterface* sdesc,
Steve Antonad7bffc2018-01-22 18:21:56200 cricket::MediaType media_type) {
201 auto* content =
202 cricket::GetFirstMediaContent(sdesc->description(), media_type);
203 RTC_DCHECK(content);
204 return content->media_description()->direction();
205 }
206
207 bool IsUnifiedPlan() const {
208 return sdp_semantics_ == SdpSemantics::kUnifiedPlan;
Steve Anton8d3444d2017-10-20 22:30:51209 }
210
211 std::unique_ptr<rtc::VirtualSocketServer> vss_;
212 rtc::AutoSocketServerThread main_;
Steve Antonad7bffc2018-01-22 18:21:56213 const SdpSemantics sdp_semantics_;
Steve Anton8d3444d2017-10-20 22:30:51214};
215
Steve Antonad7bffc2018-01-22 18:21:56216class PeerConnectionMediaTest
217 : public PeerConnectionMediaBaseTest,
218 public ::testing::WithParamInterface<SdpSemantics> {
219 protected:
220 PeerConnectionMediaTest() : PeerConnectionMediaBaseTest(GetParam()) {}
221};
222
223class PeerConnectionMediaTestUnifiedPlan : public PeerConnectionMediaBaseTest {
224 protected:
225 PeerConnectionMediaTestUnifiedPlan()
226 : PeerConnectionMediaBaseTest(SdpSemantics::kUnifiedPlan) {}
227};
228
229class PeerConnectionMediaTestPlanB : public PeerConnectionMediaBaseTest {
230 protected:
231 PeerConnectionMediaTestPlanB()
Florent Castelli15a38de2022-04-05 22:38:21232 : PeerConnectionMediaBaseTest(SdpSemantics::kPlanB_DEPRECATED) {}
Steve Antonad7bffc2018-01-22 18:21:56233};
234
235TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 22:30:51236 FailToSetRemoteDescriptionIfCreateMediaChannelFails) {
237 auto caller = CreatePeerConnectionWithAudioVideo();
238 auto callee = CreatePeerConnectionWithAudioVideo();
239 callee->media_engine()->set_fail_create_channel(true);
240
241 std::string error;
242 ASSERT_FALSE(callee->SetRemoteDescription(caller->CreateOffer(), &error));
Steve Antonad7bffc2018-01-22 18:21:56243 EXPECT_PRED_FORMAT2(AssertStartsWith, error,
244 "Failed to set remote offer sdp: Failed to create");
Steve Anton8d3444d2017-10-20 22:30:51245}
246
Steve Antonad7bffc2018-01-22 18:21:56247TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 22:30:51248 FailToSetLocalDescriptionIfCreateMediaChannelFails) {
249 auto caller = CreatePeerConnectionWithAudioVideo();
250 caller->media_engine()->set_fail_create_channel(true);
251
252 std::string error;
253 ASSERT_FALSE(caller->SetLocalDescription(caller->CreateOffer(), &error));
Steve Antonad7bffc2018-01-22 18:21:56254 EXPECT_PRED_FORMAT2(AssertStartsWith, error,
255 "Failed to set local offer sdp: Failed to create");
Steve Anton8d3444d2017-10-20 22:30:51256}
257
258std::vector<std::string> GetIds(
259 const std::vector<cricket::StreamParams>& streams) {
260 std::vector<std::string> ids;
Mirko Bonadei649a4c22019-01-29 09:11:53261 ids.reserve(streams.size());
Steve Anton8d3444d2017-10-20 22:30:51262 for (const auto& stream : streams) {
263 ids.push_back(stream.id);
264 }
265 return ids;
266}
267
268// Test that exchanging an offer and answer with each side having an audio and
269// video stream creates the appropriate send/recv streams in the underlying
270// media engine on both sides.
Steve Antonad7bffc2018-01-22 18:21:56271TEST_P(PeerConnectionMediaTest, AudioVideoOfferAnswerCreateSendRecvStreams) {
Steve Anton8d3444d2017-10-20 22:30:51272 const std::string kCallerAudioId = "caller_a";
273 const std::string kCallerVideoId = "caller_v";
274 const std::string kCalleeAudioId = "callee_a";
275 const std::string kCalleeVideoId = "callee_v";
276
277 auto caller = CreatePeerConnection();
278 caller->AddAudioTrack(kCallerAudioId);
279 caller->AddVideoTrack(kCallerVideoId);
280
281 auto callee = CreatePeerConnection();
282 callee->AddAudioTrack(kCalleeAudioId);
283 callee->AddVideoTrack(kCalleeVideoId);
284
285 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
286 ASSERT_TRUE(
287 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
288
289 auto* caller_voice = caller->media_engine()->GetVoiceChannel(0);
290 EXPECT_THAT(GetIds(caller_voice->recv_streams()),
291 ElementsAre(kCalleeAudioId));
292 EXPECT_THAT(GetIds(caller_voice->send_streams()),
293 ElementsAre(kCallerAudioId));
294
295 auto* caller_video = caller->media_engine()->GetVideoChannel(0);
296 EXPECT_THAT(GetIds(caller_video->recv_streams()),
297 ElementsAre(kCalleeVideoId));
298 EXPECT_THAT(GetIds(caller_video->send_streams()),
299 ElementsAre(kCallerVideoId));
300
301 auto* callee_voice = callee->media_engine()->GetVoiceChannel(0);
302 EXPECT_THAT(GetIds(callee_voice->recv_streams()),
303 ElementsAre(kCallerAudioId));
304 EXPECT_THAT(GetIds(callee_voice->send_streams()),
305 ElementsAre(kCalleeAudioId));
306
307 auto* callee_video = callee->media_engine()->GetVideoChannel(0);
308 EXPECT_THAT(GetIds(callee_video->recv_streams()),
309 ElementsAre(kCallerVideoId));
310 EXPECT_THAT(GetIds(callee_video->send_streams()),
311 ElementsAre(kCalleeVideoId));
312}
313
Steve Antonad7bffc2018-01-22 18:21:56314// Test that stopping the caller transceivers causes the media channels on the
315// callee to be destroyed after calling SetRemoteDescription on the generated
316// offer.
317// See next test for equivalent behavior with Plan B semantics.
318TEST_F(PeerConnectionMediaTestUnifiedPlan,
319 StoppedRemoteTransceiversRemovesMediaChannels) {
320 auto caller = CreatePeerConnectionWithAudioVideo();
321 auto callee = CreatePeerConnection();
322
323 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
324
325 // Stop both audio and video transceivers on the caller.
326 auto transceivers = caller->pc()->GetTransceivers();
327 ASSERT_EQ(2u, transceivers.size());
Harald Alvestrand6060df52020-08-11 07:54:02328 transceivers[0]->StopInternal();
329 transceivers[1]->StopInternal();
Steve Antonad7bffc2018-01-22 18:21:56330
331 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
332
333 ASSERT_FALSE(callee->media_engine()->GetVoiceChannel(0));
334 ASSERT_FALSE(callee->media_engine()->GetVideoChannel(0));
335}
336
Steve Anton8d3444d2017-10-20 22:30:51337// Test that removing streams from a subsequent offer causes the receive streams
338// on the callee to be removed.
Steve Antonad7bffc2018-01-22 18:21:56339// See previous test for equivalent behavior with Unified Plan semantics.
340TEST_F(PeerConnectionMediaTestPlanB, EmptyRemoteOfferRemovesRecvStreams) {
Steve Anton8d3444d2017-10-20 22:30:51341 auto caller = CreatePeerConnection();
342 auto caller_audio_track = caller->AddAudioTrack("a");
343 auto caller_video_track = caller->AddVideoTrack("v");
344 auto callee = CreatePeerConnectionWithAudioVideo();
345
Steve Antonad7bffc2018-01-22 18:21:56346 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 22:30:51347
348 // Remove both tracks from caller.
Harald Alvestrand93dd7632022-01-19 12:28:45349 caller->pc()->RemoveTrackOrError(caller_audio_track);
350 caller->pc()->RemoveTrackOrError(caller_video_track);
Steve Anton8d3444d2017-10-20 22:30:51351
Steve Antonad7bffc2018-01-22 18:21:56352 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 22:30:51353
354 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
Steve Antonad7bffc2018-01-22 18:21:56355 auto callee_video = callee->media_engine()->GetVideoChannel(0);
Steve Anton8d3444d2017-10-20 22:30:51356 EXPECT_EQ(1u, callee_voice->send_streams().size());
357 EXPECT_EQ(0u, callee_voice->recv_streams().size());
Steve Anton8d3444d2017-10-20 22:30:51358 EXPECT_EQ(1u, callee_video->send_streams().size());
359 EXPECT_EQ(0u, callee_video->recv_streams().size());
360}
361
Jonas Orelandfc1acd22018-08-24 08:58:37362// Test enabling of simulcast with Plan B semantics.
363// This test creating an offer.
364TEST_F(PeerConnectionMediaTestPlanB, SimulcastOffer) {
365 auto caller = CreatePeerConnection();
366 auto caller_video_track = caller->AddVideoTrack("v");
367 RTCOfferAnswerOptions options;
368 options.num_simulcast_layers = 3;
369 auto offer = caller->CreateOffer(options);
Jonas Olssona4d87372019-07-05 17:08:33370 auto* description = cricket::GetFirstMediaContent(offer->description(),
371 cricket::MEDIA_TYPE_VIDEO)
372 ->media_description();
Jonas Orelandfc1acd22018-08-24 08:58:37373 ASSERT_EQ(1u, description->streams().size());
374 ASSERT_TRUE(description->streams()[0].get_ssrc_group("SIM"));
375 EXPECT_EQ(3u, description->streams()[0].get_ssrc_group("SIM")->ssrcs.size());
376
377 // Check that it actually creates simulcast aswell.
378 caller->SetLocalDescription(std::move(offer));
379 auto senders = caller->pc()->GetSenders();
380 ASSERT_EQ(1u, senders.size());
381 EXPECT_EQ(cricket::MediaType::MEDIA_TYPE_VIDEO, senders[0]->media_type());
382 EXPECT_EQ(3u, senders[0]->GetParameters().encodings.size());
383}
384
385// Test enabling of simulcast with Plan B semantics.
386// This test creating an answer.
387TEST_F(PeerConnectionMediaTestPlanB, SimulcastAnswer) {
388 auto caller = CreatePeerConnection();
389 caller->AddVideoTrack("v0");
390 auto offer = caller->CreateOffer();
391 auto callee = CreatePeerConnection();
392 auto callee_video_track = callee->AddVideoTrack("v1");
393 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
394 RTCOfferAnswerOptions options;
395 options.num_simulcast_layers = 3;
396 auto answer = callee->CreateAnswer(options);
Jonas Olssona4d87372019-07-05 17:08:33397 auto* description = cricket::GetFirstMediaContent(answer->description(),
398 cricket::MEDIA_TYPE_VIDEO)
399 ->media_description();
Jonas Orelandfc1acd22018-08-24 08:58:37400 ASSERT_EQ(1u, description->streams().size());
401 ASSERT_TRUE(description->streams()[0].get_ssrc_group("SIM"));
402 EXPECT_EQ(3u, description->streams()[0].get_ssrc_group("SIM")->ssrcs.size());
403
404 // Check that it actually creates simulcast aswell.
405 callee->SetLocalDescription(std::move(answer));
406 auto senders = callee->pc()->GetSenders();
407 ASSERT_EQ(1u, senders.size());
408 EXPECT_EQ(cricket::MediaType::MEDIA_TYPE_VIDEO, senders[0]->media_type());
409 EXPECT_EQ(3u, senders[0]->GetParameters().encodings.size());
410}
411
Steve Antonad7bffc2018-01-22 18:21:56412// Test that stopping the callee transceivers causes the media channels to be
413// destroyed on the callee after calling SetLocalDescription on the local
414// answer.
415// See next test for equivalent behavior with Plan B semantics.
416TEST_F(PeerConnectionMediaTestUnifiedPlan,
417 StoppedLocalTransceiversRemovesMediaChannels) {
418 auto caller = CreatePeerConnectionWithAudioVideo();
419 auto callee = CreatePeerConnectionWithAudioVideo();
420
421 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
422
423 // Stop both audio and video transceivers on the callee.
424 auto transceivers = callee->pc()->GetTransceivers();
425 ASSERT_EQ(2u, transceivers.size());
Harald Alvestrand6060df52020-08-11 07:54:02426 transceivers[0]->StopInternal();
427 transceivers[1]->StopInternal();
Steve Antonad7bffc2018-01-22 18:21:56428
429 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
430
431 EXPECT_FALSE(callee->media_engine()->GetVoiceChannel(0));
432 EXPECT_FALSE(callee->media_engine()->GetVideoChannel(0));
433}
434
Steve Anton8d3444d2017-10-20 22:30:51435// Test that removing streams from a subsequent answer causes the send streams
436// on the callee to be removed when applied locally.
Steve Antonad7bffc2018-01-22 18:21:56437// See previous test for equivalent behavior with Unified Plan semantics.
438TEST_F(PeerConnectionMediaTestPlanB, EmptyLocalAnswerRemovesSendStreams) {
Steve Anton8d3444d2017-10-20 22:30:51439 auto caller = CreatePeerConnectionWithAudioVideo();
440 auto callee = CreatePeerConnection();
441 auto callee_audio_track = callee->AddAudioTrack("a");
442 auto callee_video_track = callee->AddVideoTrack("v");
443
Steve Antonad7bffc2018-01-22 18:21:56444 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 22:30:51445
446 // Remove both tracks from callee.
Harald Alvestrand93dd7632022-01-19 12:28:45447 callee->pc()->RemoveTrackOrError(callee_audio_track);
448 callee->pc()->RemoveTrackOrError(callee_video_track);
Steve Anton8d3444d2017-10-20 22:30:51449
Steve Antonad7bffc2018-01-22 18:21:56450 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 22:30:51451
452 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
Steve Antonad7bffc2018-01-22 18:21:56453 auto callee_video = callee->media_engine()->GetVideoChannel(0);
Steve Anton8d3444d2017-10-20 22:30:51454 EXPECT_EQ(0u, callee_voice->send_streams().size());
455 EXPECT_EQ(1u, callee_voice->recv_streams().size());
Steve Anton8d3444d2017-10-20 22:30:51456 EXPECT_EQ(0u, callee_video->send_streams().size());
457 EXPECT_EQ(1u, callee_video->recv_streams().size());
458}
459
460// Test that a new stream in a subsequent offer causes a new receive stream to
461// be created on the callee.
Steve Antonad7bffc2018-01-22 18:21:56462TEST_P(PeerConnectionMediaTest, NewStreamInRemoteOfferAddsRecvStreams) {
Steve Anton8d3444d2017-10-20 22:30:51463 auto caller = CreatePeerConnectionWithAudioVideo();
464 auto callee = CreatePeerConnection();
465
Steve Antonad7bffc2018-01-22 18:21:56466 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 22:30:51467
468 // Add second set of tracks to the caller.
469 caller->AddAudioTrack("a2");
470 caller->AddVideoTrack("v2");
471
Steve Antonad7bffc2018-01-22 18:21:56472 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 22:30:51473
Steve Antonad7bffc2018-01-22 18:21:56474 auto a1 = callee->media_engine()->GetVoiceChannel(0);
475 auto a2 = callee->media_engine()->GetVoiceChannel(1);
476 auto v1 = callee->media_engine()->GetVideoChannel(0);
477 auto v2 = callee->media_engine()->GetVideoChannel(1);
478 if (IsUnifiedPlan()) {
479 ASSERT_TRUE(a1);
480 EXPECT_EQ(1u, a1->recv_streams().size());
481 ASSERT_TRUE(a2);
482 EXPECT_EQ(1u, a2->recv_streams().size());
483 ASSERT_TRUE(v1);
484 EXPECT_EQ(1u, v1->recv_streams().size());
485 ASSERT_TRUE(v2);
486 EXPECT_EQ(1u, v2->recv_streams().size());
487 } else {
488 ASSERT_TRUE(a1);
489 EXPECT_EQ(2u, a1->recv_streams().size());
490 ASSERT_FALSE(a2);
491 ASSERT_TRUE(v1);
492 EXPECT_EQ(2u, v1->recv_streams().size());
493 ASSERT_FALSE(v2);
494 }
Steve Anton8d3444d2017-10-20 22:30:51495}
496
497// Test that a new stream in a subsequent answer causes a new send stream to be
498// created on the callee when added locally.
Steve Antonad7bffc2018-01-22 18:21:56499TEST_P(PeerConnectionMediaTest, NewStreamInLocalAnswerAddsSendStreams) {
Steve Anton8d3444d2017-10-20 22:30:51500 auto caller = CreatePeerConnection();
501 auto callee = CreatePeerConnectionWithAudioVideo();
502
Steve Anton22da89f2018-01-25 21:58:07503 RTCOfferAnswerOptions offer_options;
504 offer_options.offer_to_receive_audio =
Steve Anton8d3444d2017-10-20 22:30:51505 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
Steve Anton22da89f2018-01-25 21:58:07506 offer_options.offer_to_receive_video =
Steve Anton8d3444d2017-10-20 22:30:51507 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
Steve Anton22da89f2018-01-25 21:58:07508 RTCOfferAnswerOptions answer_options;
Steve Anton8d3444d2017-10-20 22:30:51509
Steve Anton22da89f2018-01-25 21:58:07510 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get(), offer_options,
511 answer_options));
Steve Anton8d3444d2017-10-20 22:30:51512
513 // Add second set of tracks to the callee.
514 callee->AddAudioTrack("a2");
515 callee->AddVideoTrack("v2");
516
Steve Anton22da89f2018-01-25 21:58:07517 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get(), offer_options,
518 answer_options));
Steve Anton8d3444d2017-10-20 22:30:51519
520 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
Steve Anton22da89f2018-01-25 21:58:07521 ASSERT_TRUE(callee_voice);
Steve Anton8d3444d2017-10-20 22:30:51522 auto callee_video = callee->media_engine()->GetVideoChannel(0);
Steve Anton22da89f2018-01-25 21:58:07523 ASSERT_TRUE(callee_video);
524
525 if (IsUnifiedPlan()) {
526 EXPECT_EQ(1u, callee_voice->send_streams().size());
527 EXPECT_EQ(1u, callee_video->send_streams().size());
528 } else {
529 EXPECT_EQ(2u, callee_voice->send_streams().size());
530 EXPECT_EQ(2u, callee_video->send_streams().size());
531 }
Steve Anton8d3444d2017-10-20 22:30:51532}
533
534// A PeerConnection with no local streams and no explicit answer constraints
535// should not reject any offered media sections.
Steve Antonad7bffc2018-01-22 18:21:56536TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 22:30:51537 CreateAnswerWithNoStreamsAndDefaultOptionsDoesNotReject) {
538 auto caller = CreatePeerConnectionWithAudioVideo();
539 auto callee = CreatePeerConnection();
540 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
541 auto answer = callee->CreateAnswer();
542
543 const auto* audio_content =
544 cricket::GetFirstAudioContent(answer->description());
545 ASSERT_TRUE(audio_content);
546 EXPECT_FALSE(audio_content->rejected);
547
548 const auto* video_content =
549 cricket::GetFirstVideoContent(answer->description());
550 ASSERT_TRUE(video_content);
551 EXPECT_FALSE(video_content->rejected);
552}
553
Mirta Dvornicic479a3c02019-06-04 13:38:50554// Test that raw packetization is not set in the offer by default.
555TEST_P(PeerConnectionMediaTest, RawPacketizationNotSetInOffer) {
556 std::vector<cricket::VideoCodec> fake_codecs;
557 fake_codecs.push_back(cricket::VideoCodec(111, cricket::kVp8CodecName));
558 fake_codecs.push_back(cricket::VideoCodec(112, cricket::kRtxCodecName));
559 fake_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "111";
560 fake_codecs.push_back(cricket::VideoCodec(113, cricket::kVp9CodecName));
561 fake_codecs.push_back(cricket::VideoCodec(114, cricket::kH264CodecName));
562 fake_codecs.push_back(cricket::VideoCodec(115, "HEVC"));
Mirko Bonadei317a1f02019-09-17 15:06:18563 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 13:38:50564 caller_fake_engine->SetVideoCodecs(fake_codecs);
565
566 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
567 auto offer = caller->CreateOfferAndSetAsLocal();
568 auto* offer_description =
569 cricket::GetFirstVideoContentDescription(offer->description());
570 for (const auto& codec : offer_description->codecs()) {
571 EXPECT_EQ(codec.packetization, absl::nullopt);
572 }
573}
574
575// Test that raw packetization is set in the offer and answer for all
576// video payload when raw_packetization_for_video is true.
577TEST_P(PeerConnectionMediaTest, RawPacketizationSetInOfferAndAnswer) {
578 std::vector<cricket::VideoCodec> fake_codecs;
579 fake_codecs.push_back(cricket::VideoCodec(111, cricket::kVp8CodecName));
580 fake_codecs.push_back(cricket::VideoCodec(112, cricket::kRtxCodecName));
581 fake_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "111";
582 fake_codecs.push_back(cricket::VideoCodec(113, cricket::kVp9CodecName));
583 fake_codecs.push_back(cricket::VideoCodec(114, cricket::kH264CodecName));
584 fake_codecs.push_back(cricket::VideoCodec(115, "HEVC"));
Mirko Bonadei317a1f02019-09-17 15:06:18585 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 13:38:50586 caller_fake_engine->SetVideoCodecs(fake_codecs);
Mirko Bonadei317a1f02019-09-17 15:06:18587 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 13:38:50588 callee_fake_engine->SetVideoCodecs(fake_codecs);
589
590 RTCOfferAnswerOptions options;
591 options.raw_packetization_for_video = true;
592
593 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
594 auto offer = caller->CreateOfferAndSetAsLocal(options);
595 auto* offer_description =
596 cricket::GetFirstVideoContentDescription(offer->description());
597 for (const auto& codec : offer_description->codecs()) {
598 if (codec.GetCodecType() == cricket::VideoCodec::CODEC_VIDEO) {
599 EXPECT_EQ(codec.packetization, cricket::kPacketizationParamRaw);
600 }
601 }
602
603 auto callee = CreatePeerConnectionWithVideo(std::move(callee_fake_engine));
604 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
605 auto answer = callee->CreateAnswerAndSetAsLocal(options);
606 auto* answer_description =
607 cricket::GetFirstVideoContentDescription(answer->description());
608 for (const auto& codec : answer_description->codecs()) {
609 if (codec.GetCodecType() == cricket::VideoCodec::CODEC_VIDEO) {
610 EXPECT_EQ(codec.packetization, cricket::kPacketizationParamRaw);
611 }
612 }
613
614 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
615}
616
617// Test that raw packetization is not set in the answer when
618// raw_packetization_for_video is true if it was not set in the offer.
619TEST_P(PeerConnectionMediaTest,
620 RawPacketizationNotSetInAnswerWhenNotSetInOffer) {
621 std::vector<cricket::VideoCodec> fake_codecs;
622 fake_codecs.push_back(cricket::VideoCodec(111, cricket::kVp8CodecName));
623 fake_codecs.push_back(cricket::VideoCodec(112, cricket::kRtxCodecName));
624 fake_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "111";
625 fake_codecs.push_back(cricket::VideoCodec(113, cricket::kVp9CodecName));
626 fake_codecs.push_back(cricket::VideoCodec(114, cricket::kH264CodecName));
627 fake_codecs.push_back(cricket::VideoCodec(115, "HEVC"));
Mirko Bonadei317a1f02019-09-17 15:06:18628 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 13:38:50629 caller_fake_engine->SetVideoCodecs(fake_codecs);
Mirko Bonadei317a1f02019-09-17 15:06:18630 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 13:38:50631 callee_fake_engine->SetVideoCodecs(fake_codecs);
632
633 RTCOfferAnswerOptions caller_options;
634 caller_options.raw_packetization_for_video = false;
635 RTCOfferAnswerOptions callee_options;
636 callee_options.raw_packetization_for_video = true;
637
638 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
639 auto offer = caller->CreateOfferAndSetAsLocal(caller_options);
640
641 auto callee = CreatePeerConnectionWithVideo(std::move(callee_fake_engine));
642 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
643 auto answer = callee->CreateAnswerAndSetAsLocal(callee_options);
644
645 auto* answer_description =
646 cricket::GetFirstVideoContentDescription(answer->description());
647 for (const auto& codec : answer_description->codecs()) {
648 EXPECT_EQ(codec.packetization, absl::nullopt);
649 }
650
651 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
652}
653
Steve Anton8d3444d2017-10-20 22:30:51654class PeerConnectionMediaOfferDirectionTest
Steve Antonad7bffc2018-01-22 18:21:56655 : public PeerConnectionMediaBaseTest,
Steve Anton8d3444d2017-10-20 22:30:51656 public ::testing::WithParamInterface<
Steve Antonad7bffc2018-01-22 18:21:56657 std::tuple<SdpSemantics,
658 std::tuple<bool, int, RtpTransceiverDirection>>> {
Steve Anton8d3444d2017-10-20 22:30:51659 protected:
Steve Antonad7bffc2018-01-22 18:21:56660 PeerConnectionMediaOfferDirectionTest()
661 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
662 auto param = std::get<1>(GetParam());
663 send_media_ = std::get<0>(param);
664 offer_to_receive_ = std::get<1>(param);
665 expected_direction_ = std::get<2>(param);
Steve Anton8d3444d2017-10-20 22:30:51666 }
667
668 bool send_media_;
669 int offer_to_receive_;
Steve Anton4e70a722017-11-28 22:57:10670 RtpTransceiverDirection expected_direction_;
Steve Anton8d3444d2017-10-20 22:30:51671};
672
673// Tests that the correct direction is set on the media description according
674// to the presence of a local media track and the offer_to_receive setting.
675TEST_P(PeerConnectionMediaOfferDirectionTest, VerifyDirection) {
676 auto caller = CreatePeerConnection();
677 if (send_media_) {
678 caller->AddAudioTrack("a");
679 }
680
681 RTCOfferAnswerOptions options;
682 options.offer_to_receive_audio = offer_to_receive_;
683 auto offer = caller->CreateOffer(options);
684
Steve Antonad7bffc2018-01-22 18:21:56685 auto* content = cricket::GetFirstMediaContent(offer->description(),
686 cricket::MEDIA_TYPE_AUDIO);
Steve Anton4e70a722017-11-28 22:57:10687 if (expected_direction_ == RtpTransceiverDirection::kInactive) {
Steve Antonad7bffc2018-01-22 18:21:56688 EXPECT_FALSE(content);
Steve Anton8d3444d2017-10-20 22:30:51689 } else {
Steve Antonad7bffc2018-01-22 18:21:56690 EXPECT_EQ(expected_direction_, content->media_description()->direction());
Steve Anton8d3444d2017-10-20 22:30:51691 }
692}
693
694// Note that in these tests, MD_INACTIVE indicates that no media section is
695// included in the offer, not that the media direction is inactive.
Mirko Bonadeic84f6612019-01-31 11:20:57696INSTANTIATE_TEST_SUITE_P(
Steve Anton4e70a722017-11-28 22:57:10697 PeerConnectionMediaTest,
698 PeerConnectionMediaOfferDirectionTest,
Steve Antonad7bffc2018-01-22 18:21:56699 Combine(
Florent Castelli15a38de2022-04-05 22:38:21700 Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan),
Steve Antonad7bffc2018-01-22 18:21:56701 Values(std::make_tuple(false, -1, RtpTransceiverDirection::kInactive),
702 std::make_tuple(false, 0, RtpTransceiverDirection::kInactive),
703 std::make_tuple(false, 1, RtpTransceiverDirection::kRecvOnly),
704 std::make_tuple(true, -1, RtpTransceiverDirection::kSendRecv),
705 std::make_tuple(true, 0, RtpTransceiverDirection::kSendOnly),
706 std::make_tuple(true, 1, RtpTransceiverDirection::kSendRecv))));
Steve Anton8d3444d2017-10-20 22:30:51707
708class PeerConnectionMediaAnswerDirectionTest
Steve Antonad7bffc2018-01-22 18:21:56709 : public PeerConnectionMediaBaseTest,
Steve Anton8d3444d2017-10-20 22:30:51710 public ::testing::WithParamInterface<
Steve Antonad7bffc2018-01-22 18:21:56711 std::tuple<SdpSemantics, RtpTransceiverDirection, bool, int>> {
Steve Anton8d3444d2017-10-20 22:30:51712 protected:
Steve Antonad7bffc2018-01-22 18:21:56713 PeerConnectionMediaAnswerDirectionTest()
714 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
715 offer_direction_ = std::get<1>(GetParam());
716 send_media_ = std::get<2>(GetParam());
717 offer_to_receive_ = std::get<3>(GetParam());
Steve Anton8d3444d2017-10-20 22:30:51718 }
719
Steve Anton4e70a722017-11-28 22:57:10720 RtpTransceiverDirection offer_direction_;
Steve Anton8d3444d2017-10-20 22:30:51721 bool send_media_;
722 int offer_to_receive_;
723};
724
725// Tests that the direction in an answer is correct according to direction sent
726// in the offer, the presence of a local media track on the receive side and the
727// offer_to_receive setting.
728TEST_P(PeerConnectionMediaAnswerDirectionTest, VerifyDirection) {
Steve Anton22da89f2018-01-25 21:58:07729 if (IsUnifiedPlan() &&
730 offer_to_receive_ != RTCOfferAnswerOptions::kUndefined) {
731 // offer_to_receive_ is not implemented when creating answers with Unified
732 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 18:21:56733 return;
734 }
Steve Anton22da89f2018-01-25 21:58:07735
Steve Anton8d3444d2017-10-20 22:30:51736 auto caller = CreatePeerConnection();
737 caller->AddAudioTrack("a");
738
739 // Create the offer with an audio section and set its direction.
740 auto offer = caller->CreateOffer();
741 cricket::GetFirstAudioContentDescription(offer->description())
742 ->set_direction(offer_direction_);
743
744 auto callee = CreatePeerConnection();
745 if (send_media_) {
746 callee->AddAudioTrack("a");
747 }
748 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
749
750 // Create the answer according to the test parameters.
751 RTCOfferAnswerOptions options;
752 options.offer_to_receive_audio = offer_to_receive_;
753 auto answer = callee->CreateAnswer(options);
754
755 // The expected direction in the answer is the intersection of each side's
756 // capability to send/recv media.
757 // For the offerer, the direction is given in the offer (offer_direction_).
758 // For the answerer, the direction has two components:
759 // 1. Send if the answerer has a local track to send.
760 // 2. Receive if the answerer has explicitly set the offer_to_receive to 1 or
761 // if it has been left as default.
Steve Anton4e70a722017-11-28 22:57:10762 bool offer_send = RtpTransceiverDirectionHasSend(offer_direction_);
763 bool offer_recv = RtpTransceiverDirectionHasRecv(offer_direction_);
Steve Anton8d3444d2017-10-20 22:30:51764
765 // The negotiated components determine the direction set in the answer.
Steve Anton1d03a752017-11-27 22:30:09766 bool negotiate_send = (send_media_ && offer_recv);
767 bool negotiate_recv = ((offer_to_receive_ != 0) && offer_send);
Steve Anton8d3444d2017-10-20 22:30:51768
769 auto expected_direction =
Steve Anton4e70a722017-11-28 22:57:10770 RtpTransceiverDirectionFromSendRecv(negotiate_send, negotiate_recv);
Steve Anton8d3444d2017-10-20 22:30:51771 EXPECT_EQ(expected_direction,
Steve Antonad7bffc2018-01-22 18:21:56772 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton8d3444d2017-10-20 22:30:51773}
774
775// Tests that the media section is rejected if and only if the callee has no
776// local media track and has set offer_to_receive to 0, no matter which
777// direction the caller indicated in the offer.
778TEST_P(PeerConnectionMediaAnswerDirectionTest, VerifyRejected) {
Steve Anton22da89f2018-01-25 21:58:07779 if (IsUnifiedPlan() &&
780 offer_to_receive_ != RTCOfferAnswerOptions::kUndefined) {
781 // offer_to_receive_ is not implemented when creating answers with Unified
782 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 18:21:56783 return;
784 }
Steve Anton22da89f2018-01-25 21:58:07785
Steve Anton8d3444d2017-10-20 22:30:51786 auto caller = CreatePeerConnection();
787 caller->AddAudioTrack("a");
788
789 // Create the offer with an audio section and set its direction.
790 auto offer = caller->CreateOffer();
791 cricket::GetFirstAudioContentDescription(offer->description())
792 ->set_direction(offer_direction_);
793
794 auto callee = CreatePeerConnection();
795 if (send_media_) {
796 callee->AddAudioTrack("a");
797 }
798 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
799
800 // Create the answer according to the test parameters.
801 RTCOfferAnswerOptions options;
802 options.offer_to_receive_audio = offer_to_receive_;
803 auto answer = callee->CreateAnswer(options);
804
805 // The media section is rejected if and only if offer_to_receive is explicitly
806 // set to 0 and there is no media to send.
807 auto* audio_content = cricket::GetFirstAudioContent(answer->description());
808 ASSERT_TRUE(audio_content);
809 EXPECT_EQ((offer_to_receive_ == 0 && !send_media_), audio_content->rejected);
810}
811
Mirko Bonadeic84f6612019-01-31 11:20:57812INSTANTIATE_TEST_SUITE_P(PeerConnectionMediaTest,
813 PeerConnectionMediaAnswerDirectionTest,
Florent Castelli15a38de2022-04-05 22:38:21814 Combine(Values(SdpSemantics::kPlanB_DEPRECATED,
Mirko Bonadeic84f6612019-01-31 11:20:57815 SdpSemantics::kUnifiedPlan),
816 Values(RtpTransceiverDirection::kInactive,
817 RtpTransceiverDirection::kSendOnly,
818 RtpTransceiverDirection::kRecvOnly,
819 RtpTransceiverDirection::kSendRecv),
820 Bool(),
821 Values(-1, 0, 1)));
Steve Anton8d3444d2017-10-20 22:30:51822
Steve Antonad7bffc2018-01-22 18:21:56823TEST_P(PeerConnectionMediaTest, OfferHasDifferentDirectionForAudioVideo) {
Steve Anton8d3444d2017-10-20 22:30:51824 auto caller = CreatePeerConnection();
825 caller->AddVideoTrack("v");
826
827 RTCOfferAnswerOptions options;
828 options.offer_to_receive_audio = 1;
829 options.offer_to_receive_video = 0;
830 auto offer = caller->CreateOffer(options);
831
Steve Anton4e70a722017-11-28 22:57:10832 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
Steve Antonad7bffc2018-01-22 18:21:56833 GetMediaContentDirection(offer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton4e70a722017-11-28 22:57:10834 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
Steve Antonad7bffc2018-01-22 18:21:56835 GetMediaContentDirection(offer.get(), cricket::MEDIA_TYPE_VIDEO));
Steve Anton8d3444d2017-10-20 22:30:51836}
837
Steve Antonad7bffc2018-01-22 18:21:56838TEST_P(PeerConnectionMediaTest, AnswerHasDifferentDirectionsForAudioVideo) {
Steve Antonad7bffc2018-01-22 18:21:56839 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 21:58:07840 // offer_to_receive_ is not implemented when creating answers with Unified
841 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 18:21:56842 return;
843 }
844
Steve Anton8d3444d2017-10-20 22:30:51845 auto caller = CreatePeerConnectionWithAudioVideo();
846 auto callee = CreatePeerConnection();
847 callee->AddVideoTrack("v");
848
849 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
850
851 RTCOfferAnswerOptions options;
852 options.offer_to_receive_audio = 1;
853 options.offer_to_receive_video = 0;
854 auto answer = callee->CreateAnswer(options);
855
Steve Anton4e70a722017-11-28 22:57:10856 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
Steve Antonad7bffc2018-01-22 18:21:56857 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton4e70a722017-11-28 22:57:10858 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
Steve Antonad7bffc2018-01-22 18:21:56859 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_VIDEO));
Steve Anton8d3444d2017-10-20 22:30:51860}
861
862void AddComfortNoiseCodecsToSend(cricket::FakeMediaEngine* media_engine) {
Philipp Hancke8498c252020-06-05 11:28:57863 const cricket::AudioCodec kComfortNoiseCodec8k(102, cricket::kCnCodecName,
864 8000, 0, 1);
865 const cricket::AudioCodec kComfortNoiseCodec16k(103, cricket::kCnCodecName,
866 16000, 0, 1);
Steve Anton8d3444d2017-10-20 22:30:51867
Sebastian Jansson6eb8a162018-11-16 10:29:55868 auto codecs = media_engine->voice().send_codecs();
Steve Anton8d3444d2017-10-20 22:30:51869 codecs.push_back(kComfortNoiseCodec8k);
870 codecs.push_back(kComfortNoiseCodec16k);
871 media_engine->SetAudioCodecs(codecs);
872}
873
874bool HasAnyComfortNoiseCodecs(const cricket::SessionDescription* desc) {
875 const auto* audio_desc = cricket::GetFirstAudioContentDescription(desc);
876 for (const auto& codec : audio_desc->codecs()) {
Philipp Hancke8498c252020-06-05 11:28:57877 if (codec.name == cricket::kCnCodecName) {
Steve Anton8d3444d2017-10-20 22:30:51878 return true;
879 }
880 }
881 return false;
882}
883
Taylor Brandstetterf7fcfb72021-09-09 20:39:38884bool HasPayloadTypeConflict(const cricket::SessionDescription* desc) {
885 std::set<int> payload_types;
886 const auto* audio_desc = cricket::GetFirstAudioContentDescription(desc);
887 if (audio_desc) {
888 for (const auto& codec : audio_desc->codecs()) {
889 if (payload_types.count(codec.id) > 0) {
890 return true;
891 }
892 payload_types.insert(codec.id);
893 }
894 }
895 const auto* video_desc = cricket::GetFirstVideoContentDescription(desc);
896 if (video_desc) {
897 for (const auto& codec : video_desc->codecs()) {
898 if (payload_types.count(codec.id) > 0) {
899 return true;
900 }
901 payload_types.insert(codec.id);
902 }
903 }
904 return false;
905}
906
Steve Antonad7bffc2018-01-22 18:21:56907TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 22:30:51908 CreateOfferWithNoVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
Philipp Hancke718acf62021-05-12 12:18:03909 auto fake_engine = std::make_unique<FakeMediaEngine>();
910 AddComfortNoiseCodecsToSend(fake_engine.get());
911 auto caller = CreatePeerConnectionWithAudioVideo(std::move(fake_engine));
Steve Anton8d3444d2017-10-20 22:30:51912
913 RTCOfferAnswerOptions options;
914 options.voice_activity_detection = false;
915 auto offer = caller->CreateOffer(options);
916
917 EXPECT_FALSE(HasAnyComfortNoiseCodecs(offer->description()));
918}
919
Steve Antonad7bffc2018-01-22 18:21:56920TEST_P(PeerConnectionMediaTest,
Philipp Hancke718acf62021-05-12 12:18:03921 CreateOfferWithVoiceActivityDetectionIncludesComfortNoiseCodecs) {
922 auto fake_engine = std::make_unique<FakeMediaEngine>();
923 AddComfortNoiseCodecsToSend(fake_engine.get());
924 auto caller = CreatePeerConnectionWithAudioVideo(std::move(fake_engine));
925
926 RTCOfferAnswerOptions options;
927 options.voice_activity_detection = true;
928 auto offer = caller->CreateOffer(options);
929
930 EXPECT_TRUE(HasAnyComfortNoiseCodecs(offer->description()));
931}
932
933TEST_P(PeerConnectionMediaTest,
934 CreateAnswerWithVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
Steve Anton8d3444d2017-10-20 22:30:51935 auto caller = CreatePeerConnectionWithAudioVideo();
Philipp Hancke718acf62021-05-12 12:18:03936
937 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
938 AddComfortNoiseCodecsToSend(callee_fake_engine.get());
939 auto callee =
940 CreatePeerConnectionWithAudioVideo(std::move(callee_fake_engine));
941
942 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
943
944 RTCOfferAnswerOptions options;
945 options.voice_activity_detection = true;
946 auto answer = callee->CreateAnswer(options);
947
948 EXPECT_FALSE(HasAnyComfortNoiseCodecs(answer->description()));
949}
950
951TEST_P(PeerConnectionMediaTest,
952 CreateAnswerWithNoVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
953 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
954 AddComfortNoiseCodecsToSend(caller_fake_engine.get());
955 auto caller =
956 CreatePeerConnectionWithAudioVideo(std::move(caller_fake_engine));
957
958 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
959 AddComfortNoiseCodecsToSend(callee_fake_engine.get());
960 auto callee =
961 CreatePeerConnectionWithAudioVideo(std::move(callee_fake_engine));
Steve Anton8d3444d2017-10-20 22:30:51962
963 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
964
965 RTCOfferAnswerOptions options;
966 options.voice_activity_detection = false;
967 auto answer = callee->CreateAnswer(options);
968
969 EXPECT_FALSE(HasAnyComfortNoiseCodecs(answer->description()));
970}
971
972// The following test group verifies that we reject answers with invalid media
973// sections as per RFC 3264.
974
975class PeerConnectionMediaInvalidMediaTest
Steve Antonad7bffc2018-01-22 18:21:56976 : public PeerConnectionMediaBaseTest,
977 public ::testing::WithParamInterface<std::tuple<
978 SdpSemantics,
Steve Anton8d3444d2017-10-20 22:30:51979 std::tuple<std::string,
980 std::function<void(cricket::SessionDescription*)>,
Steve Antonad7bffc2018-01-22 18:21:56981 std::string>>> {
Steve Anton8d3444d2017-10-20 22:30:51982 protected:
Steve Antonad7bffc2018-01-22 18:21:56983 PeerConnectionMediaInvalidMediaTest()
984 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
985 auto param = std::get<1>(GetParam());
986 mutator_ = std::get<1>(param);
987 expected_error_ = std::get<2>(param);
Steve Anton8d3444d2017-10-20 22:30:51988 }
989
990 std::function<void(cricket::SessionDescription*)> mutator_;
991 std::string expected_error_;
992};
993
994TEST_P(PeerConnectionMediaInvalidMediaTest, FailToSetRemoteAnswer) {
995 auto caller = CreatePeerConnectionWithAudioVideo();
996 auto callee = CreatePeerConnectionWithAudioVideo();
997
998 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
999
1000 auto answer = callee->CreateAnswer();
1001 mutator_(answer->description());
1002
1003 std::string error;
1004 ASSERT_FALSE(caller->SetRemoteDescription(std::move(answer), &error));
1005 EXPECT_EQ("Failed to set remote answer sdp: " + expected_error_, error);
1006}
1007
1008TEST_P(PeerConnectionMediaInvalidMediaTest, FailToSetLocalAnswer) {
1009 auto caller = CreatePeerConnectionWithAudioVideo();
1010 auto callee = CreatePeerConnectionWithAudioVideo();
1011
1012 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1013
1014 auto answer = callee->CreateAnswer();
1015 mutator_(answer->description());
1016
1017 std::string error;
1018 ASSERT_FALSE(callee->SetLocalDescription(std::move(answer), &error));
1019 EXPECT_EQ("Failed to set local answer sdp: " + expected_error_, error);
1020}
1021
1022void RemoveVideoContent(cricket::SessionDescription* desc) {
1023 auto content_name = cricket::GetFirstVideoContent(desc)->name;
1024 desc->RemoveContentByName(content_name);
1025 desc->RemoveTransportInfoByName(content_name);
1026}
1027
1028void RenameVideoContent(cricket::SessionDescription* desc) {
1029 auto* video_content = cricket::GetFirstVideoContent(desc);
1030 auto* transport_info = desc->GetTransportInfoByName(video_content->name);
1031 video_content->name = "video_renamed";
1032 transport_info->content_name = video_content->name;
1033}
1034
1035void ReverseMediaContent(cricket::SessionDescription* desc) {
Steve Anton64b626b2019-01-29 01:25:261036 absl::c_reverse(desc->contents());
1037 absl::c_reverse(desc->transport_infos());
Steve Anton8d3444d2017-10-20 22:30:511038}
1039
1040void ChangeMediaTypeAudioToVideo(cricket::SessionDescription* desc) {
Steve Antonad7bffc2018-01-22 18:21:561041 std::string audio_mid = cricket::GetFirstAudioContent(desc)->name;
1042 desc->RemoveContentByName(audio_mid);
1043 auto* video_content = cricket::GetFirstVideoContent(desc);
1044 desc->AddContent(audio_mid, video_content->type,
Harald Alvestrand1716d392019-06-03 18:35:451045 video_content->media_description()->Clone());
Steve Anton8d3444d2017-10-20 22:30:511046}
1047
1048constexpr char kMLinesOutOfOrder[] =
1049 "The order of m-lines in answer doesn't match order in offer. Rejecting "
1050 "answer.";
1051
Mirko Bonadeic84f6612019-01-31 11:20:571052INSTANTIATE_TEST_SUITE_P(
Steve Anton8d3444d2017-10-20 22:30:511053 PeerConnectionMediaTest,
1054 PeerConnectionMediaInvalidMediaTest,
Florent Castelli15a38de2022-04-05 22:38:211055 Combine(Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan),
Steve Antonad7bffc2018-01-22 18:21:561056 Values(std::make_tuple("remove video",
1057 RemoveVideoContent,
1058 kMLinesOutOfOrder),
1059 std::make_tuple("rename video",
1060 RenameVideoContent,
1061 kMLinesOutOfOrder),
1062 std::make_tuple("reverse media sections",
1063 ReverseMediaContent,
1064 kMLinesOutOfOrder),
1065 std::make_tuple("change audio type to video type",
1066 ChangeMediaTypeAudioToVideo,
1067 kMLinesOutOfOrder))));
Steve Anton8d3444d2017-10-20 22:30:511068
1069// Test that the correct media engine send/recv streams are created when doing
1070// a series of offer/answers where audio/video are both sent, then audio is
1071// rejected, then both audio/video sent again.
Steve Antonad7bffc2018-01-22 18:21:561072TEST_P(PeerConnectionMediaTest, TestAVOfferWithAudioOnlyAnswer) {
Steve Antonad7bffc2018-01-22 18:21:561073 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 21:58:071074 // offer_to_receive_ is not implemented when creating answers with Unified
1075 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 18:21:561076 return;
1077 }
1078
Steve Anton8d3444d2017-10-20 22:30:511079 RTCOfferAnswerOptions options_reject_video;
1080 options_reject_video.offer_to_receive_audio =
1081 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
1082 options_reject_video.offer_to_receive_video = 0;
1083
1084 auto caller = CreatePeerConnection();
1085 caller->AddAudioTrack("a");
1086 caller->AddVideoTrack("v");
1087 auto callee = CreatePeerConnection();
1088
1089 // Caller initially offers to send/recv audio and video.
1090 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1091 // Callee accepts the audio as recv only but rejects the video.
1092 ASSERT_TRUE(caller->SetRemoteDescription(
1093 callee->CreateAnswerAndSetAsLocal(options_reject_video)));
1094
1095 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1096 ASSERT_TRUE(caller_voice);
1097 EXPECT_EQ(0u, caller_voice->recv_streams().size());
1098 EXPECT_EQ(1u, caller_voice->send_streams().size());
1099 auto caller_video = caller->media_engine()->GetVideoChannel(0);
1100 EXPECT_FALSE(caller_video);
1101
1102 // Callee adds its own audio/video stream and offers to receive audio/video
1103 // too.
1104 callee->AddAudioTrack("a");
1105 auto callee_video_track = callee->AddVideoTrack("v");
1106 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1107 ASSERT_TRUE(
1108 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1109
1110 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1111 ASSERT_TRUE(callee_voice);
1112 EXPECT_EQ(1u, callee_voice->recv_streams().size());
1113 EXPECT_EQ(1u, callee_voice->send_streams().size());
1114 auto callee_video = callee->media_engine()->GetVideoChannel(0);
1115 ASSERT_TRUE(callee_video);
1116 EXPECT_EQ(1u, callee_video->recv_streams().size());
1117 EXPECT_EQ(1u, callee_video->send_streams().size());
1118
1119 // Callee removes video but keeps audio and rejects the video once again.
Harald Alvestrand93dd7632022-01-19 12:28:451120 callee->pc()->RemoveTrackOrError(callee_video_track);
Steve Anton8d3444d2017-10-20 22:30:511121 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1122 ASSERT_TRUE(
1123 callee->SetLocalDescription(callee->CreateAnswer(options_reject_video)));
1124
1125 callee_voice = callee->media_engine()->GetVoiceChannel(0);
1126 ASSERT_TRUE(callee_voice);
1127 EXPECT_EQ(1u, callee_voice->recv_streams().size());
1128 EXPECT_EQ(1u, callee_voice->send_streams().size());
1129 callee_video = callee->media_engine()->GetVideoChannel(0);
1130 EXPECT_FALSE(callee_video);
1131}
1132
1133// Test that the correct media engine send/recv streams are created when doing
1134// a series of offer/answers where audio/video are both sent, then video is
1135// rejected, then both audio/video sent again.
Steve Antonad7bffc2018-01-22 18:21:561136TEST_P(PeerConnectionMediaTest, TestAVOfferWithVideoOnlyAnswer) {
Steve Antonad7bffc2018-01-22 18:21:561137 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 21:58:071138 // offer_to_receive_ is not implemented when creating answers with Unified
1139 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 18:21:561140 return;
1141 }
1142
Steve Anton8d3444d2017-10-20 22:30:511143 // Disable the bundling here. If the media is bundled on audio
1144 // transport, then we can't reject the audio because switching the bundled
1145 // transport is not currently supported.
1146 // (https://bugs.chromium.org/p/webrtc/issues/detail?id=6704)
1147 RTCOfferAnswerOptions options_no_bundle;
1148 options_no_bundle.use_rtp_mux = false;
1149 RTCOfferAnswerOptions options_reject_audio = options_no_bundle;
1150 options_reject_audio.offer_to_receive_audio = 0;
1151 options_reject_audio.offer_to_receive_video =
1152 RTCOfferAnswerOptions::kMaxOfferToReceiveMedia;
1153
1154 auto caller = CreatePeerConnection();
1155 caller->AddAudioTrack("a");
1156 caller->AddVideoTrack("v");
1157 auto callee = CreatePeerConnection();
1158
1159 // Caller initially offers to send/recv audio and video.
1160 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1161 // Callee accepts the video as recv only but rejects the audio.
1162 ASSERT_TRUE(caller->SetRemoteDescription(
1163 callee->CreateAnswerAndSetAsLocal(options_reject_audio)));
1164
1165 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1166 EXPECT_FALSE(caller_voice);
1167 auto caller_video = caller->media_engine()->GetVideoChannel(0);
1168 ASSERT_TRUE(caller_video);
1169 EXPECT_EQ(0u, caller_video->recv_streams().size());
1170 EXPECT_EQ(1u, caller_video->send_streams().size());
1171
1172 // Callee adds its own audio/video stream and offers to receive audio/video
1173 // too.
1174 auto callee_audio_track = callee->AddAudioTrack("a");
1175 callee->AddVideoTrack("v");
1176 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1177 ASSERT_TRUE(caller->SetRemoteDescription(
1178 callee->CreateAnswerAndSetAsLocal(options_no_bundle)));
1179
1180 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1181 ASSERT_TRUE(callee_voice);
1182 EXPECT_EQ(1u, callee_voice->recv_streams().size());
1183 EXPECT_EQ(1u, callee_voice->send_streams().size());
1184 auto callee_video = callee->media_engine()->GetVideoChannel(0);
1185 ASSERT_TRUE(callee_video);
1186 EXPECT_EQ(1u, callee_video->recv_streams().size());
1187 EXPECT_EQ(1u, callee_video->send_streams().size());
1188
1189 // Callee removes audio but keeps video and rejects the audio once again.
Harald Alvestrand93dd7632022-01-19 12:28:451190 callee->pc()->RemoveTrackOrError(callee_audio_track);
Steve Anton8d3444d2017-10-20 22:30:511191 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1192 ASSERT_TRUE(
1193 callee->SetLocalDescription(callee->CreateAnswer(options_reject_audio)));
1194
1195 callee_voice = callee->media_engine()->GetVoiceChannel(0);
1196 EXPECT_FALSE(callee_voice);
1197 callee_video = callee->media_engine()->GetVideoChannel(0);
1198 ASSERT_TRUE(callee_video);
1199 EXPECT_EQ(1u, callee_video->recv_streams().size());
1200 EXPECT_EQ(1u, callee_video->send_streams().size());
1201}
1202
1203// Tests that if the underlying video encoder fails to be initialized (signaled
1204// by failing to set send codecs), the PeerConnection signals the error to the
1205// client.
Steve Antonad7bffc2018-01-22 18:21:561206TEST_P(PeerConnectionMediaTest, MediaEngineErrorPropagatedToClients) {
Steve Anton8d3444d2017-10-20 22:30:511207 auto caller = CreatePeerConnectionWithAudioVideo();
1208 auto callee = CreatePeerConnectionWithAudioVideo();
1209
1210 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1211
1212 auto video_channel = caller->media_engine()->GetVideoChannel(0);
1213 video_channel->set_fail_set_send_codecs(true);
1214
1215 std::string error;
1216 ASSERT_FALSE(caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(),
1217 &error));
Yura Yaroshevichbc1f9102020-06-03 21:15:221218 EXPECT_EQ(std::string("Failed to set remote answer sdp: Failed to set remote "
1219 "video description "
1220 "send parameters for m-section with mid='") +
1221 (IsUnifiedPlan() ? "1" : "video") + "'.",
1222 error);
Steve Anton8d3444d2017-10-20 22:30:511223}
1224
1225// Tests that if the underlying video encoder fails once then subsequent
1226// attempts at setting the local/remote description will also fail, even if
1227// SetSendCodecs no longer fails.
Steve Antonad7bffc2018-01-22 18:21:561228TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 22:30:511229 FailToApplyDescriptionIfVideoEncoderHasEverFailed) {
1230 auto caller = CreatePeerConnectionWithAudioVideo();
1231 auto callee = CreatePeerConnectionWithAudioVideo();
1232
1233 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1234
1235 auto video_channel = caller->media_engine()->GetVideoChannel(0);
1236 video_channel->set_fail_set_send_codecs(true);
1237
1238 EXPECT_FALSE(
1239 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1240
1241 video_channel->set_fail_set_send_codecs(false);
1242
1243 EXPECT_FALSE(caller->SetRemoteDescription(callee->CreateAnswer()));
1244 EXPECT_FALSE(caller->SetLocalDescription(caller->CreateOffer()));
1245}
1246
1247void RenameContent(cricket::SessionDescription* desc,
Steve Antonad7bffc2018-01-22 18:21:561248 cricket::MediaType media_type,
Steve Anton8d3444d2017-10-20 22:30:511249 const std::string& new_name) {
Steve Antonad7bffc2018-01-22 18:21:561250 auto* content = cricket::GetFirstMediaContent(desc, media_type);
Steve Anton8d3444d2017-10-20 22:30:511251 RTC_DCHECK(content);
Steve Antonad7bffc2018-01-22 18:21:561252 std::string old_name = content->name;
Steve Anton8d3444d2017-10-20 22:30:511253 content->name = new_name;
1254 auto* transport = desc->GetTransportInfoByName(old_name);
1255 RTC_DCHECK(transport);
1256 transport->content_name = new_name;
Zhi Huangd2248f82018-04-10 21:41:031257
1258 // Rename the content name in the BUNDLE group.
1259 cricket::ContentGroup new_bundle_group =
1260 *desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1261 new_bundle_group.RemoveContentName(old_name);
1262 new_bundle_group.AddContentName(new_name);
1263 desc->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1264 desc->AddGroup(new_bundle_group);
Steve Anton8d3444d2017-10-20 22:30:511265}
1266
1267// Tests that an answer responds with the same MIDs as the offer.
Steve Antonad7bffc2018-01-22 18:21:561268TEST_P(PeerConnectionMediaTest, AnswerHasSameMidsAsOffer) {
Zhi Huang365381f2018-04-13 23:44:341269 const std::string kAudioMid = "notdefault1";
1270 const std::string kVideoMid = "notdefault2";
Steve Anton8d3444d2017-10-20 22:30:511271
1272 auto caller = CreatePeerConnectionWithAudioVideo();
1273 auto callee = CreatePeerConnectionWithAudioVideo();
1274
1275 auto offer = caller->CreateOffer();
Steve Antonad7bffc2018-01-22 18:21:561276 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, kAudioMid);
1277 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, kVideoMid);
Steve Anton8d3444d2017-10-20 22:30:511278 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1279
1280 auto answer = callee->CreateAnswer();
1281 EXPECT_EQ(kAudioMid,
1282 cricket::GetFirstAudioContent(answer->description())->name);
1283 EXPECT_EQ(kVideoMid,
1284 cricket::GetFirstVideoContent(answer->description())->name);
1285}
1286
1287// Test that if the callee creates a re-offer, the MIDs are the same as the
1288// original offer.
Steve Antonad7bffc2018-01-22 18:21:561289TEST_P(PeerConnectionMediaTest, ReOfferHasSameMidsAsFirstOffer) {
Zhi Huang365381f2018-04-13 23:44:341290 const std::string kAudioMid = "notdefault1";
1291 const std::string kVideoMid = "notdefault2";
Steve Anton8d3444d2017-10-20 22:30:511292
1293 auto caller = CreatePeerConnectionWithAudioVideo();
1294 auto callee = CreatePeerConnectionWithAudioVideo();
1295
1296 auto offer = caller->CreateOffer();
Steve Antonad7bffc2018-01-22 18:21:561297 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, kAudioMid);
1298 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, kVideoMid);
Steve Anton8d3444d2017-10-20 22:30:511299 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1300 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1301
1302 auto reoffer = callee->CreateOffer();
1303 EXPECT_EQ(kAudioMid,
1304 cricket::GetFirstAudioContent(reoffer->description())->name);
1305 EXPECT_EQ(kVideoMid,
1306 cricket::GetFirstVideoContent(reoffer->description())->name);
1307}
1308
Steve Anton06817cd2018-12-18 23:55:301309// Test that SetRemoteDescription returns an error if there are two m= sections
1310// with the same MID value.
1311TEST_P(PeerConnectionMediaTest, SetRemoteDescriptionFailsWithDuplicateMids) {
1312 auto caller = CreatePeerConnectionWithAudioVideo();
1313 auto callee = CreatePeerConnectionWithAudioVideo();
1314
1315 auto offer = caller->CreateOffer();
1316 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, "same");
1317 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, "same");
1318
1319 std::string error;
1320 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer), &error));
1321 EXPECT_EQ(error,
1322 "Failed to set remote offer sdp: Duplicate a=mid value 'same'.");
1323}
1324
Steve Antonad7bffc2018-01-22 18:21:561325TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 22:30:511326 CombinedAudioVideoBweConfigPropagatedToMediaEngine) {
1327 RTCConfiguration config;
1328 config.combined_audio_video_bwe.emplace(true);
1329 auto caller = CreatePeerConnectionWithAudioVideo(config);
1330
1331 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
1332
1333 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1334 ASSERT_TRUE(caller_voice);
1335 const cricket::AudioOptions& audio_options = caller_voice->options();
1336 EXPECT_EQ(config.combined_audio_video_bwe,
1337 audio_options.combined_audio_video_bwe);
1338}
1339
Philipp Hancke7145a142021-09-28 05:46:061340// Test that if a RED codec refers to another codec in its fmtp line, but that
1341// codec's payload type was reassigned for some reason (either the remote
1342// endpoint selected a different payload type or there was a conflict), the RED
1343// fmtp line is modified to refer to the correct payload type.
1344TEST_P(PeerConnectionMediaTest, RedFmtpPayloadTypeReassigned) {
1345 std::vector<cricket::AudioCodec> caller_fake_codecs;
1346 caller_fake_codecs.push_back(cricket::AudioCodec(100, "foo", 0, 0, 1));
1347 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
1348 caller_fake_engine->SetAudioCodecs(caller_fake_codecs);
1349 auto caller = CreatePeerConnectionWithAudio(std::move(caller_fake_engine));
1350
1351 std::vector<cricket::AudioCodec> callee_fake_codecs;
1352 callee_fake_codecs.push_back(cricket::AudioCodec(120, "foo", 0, 0, 1));
1353 callee_fake_codecs.push_back(
1354 cricket::AudioCodec(121, cricket::kRedCodecName, 0, 0, 1));
1355 callee_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1356 "120/120");
1357 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
1358 callee_fake_engine->SetAudioCodecs(callee_fake_codecs);
1359 auto callee = CreatePeerConnectionWithAudio(std::move(callee_fake_engine));
1360
1361 // Offer from the caller establishes 100 as the "foo" payload type.
1362 auto offer = caller->CreateOfferAndSetAsLocal();
1363 callee->SetRemoteDescription(std::move(offer));
1364 auto answer = callee->CreateAnswerAndSetAsLocal();
1365 auto answer_description =
1366 cricket::GetFirstAudioContentDescription(answer->description());
1367 ASSERT_EQ(1u, answer_description->codecs().size());
1368
1369 // Offer from the callee should respect the established payload type, and
1370 // attempt to add RED, which should refer to the correct payload type.
1371 offer = callee->CreateOfferAndSetAsLocal();
1372 auto* offer_description =
1373 cricket::GetFirstAudioContentDescription(offer->description());
1374 ASSERT_EQ(2u, offer_description->codecs().size());
1375 for (const auto& codec : offer_description->codecs()) {
1376 if (codec.name == "foo") {
1377 ASSERT_EQ(100, codec.id);
1378 } else if (codec.name == cricket::kRedCodecName) {
1379 std::string fmtp;
1380 ASSERT_TRUE(codec.GetParam("", &fmtp));
1381 EXPECT_EQ("100/100", fmtp);
1382 }
1383 }
1384}
1385
1386// Test that RED without fmtp does match RED without fmtp.
1387TEST_P(PeerConnectionMediaTest, RedFmtpPayloadTypeNoFmtpMatchNoFmtp) {
1388 std::vector<cricket::AudioCodec> caller_fake_codecs;
1389 caller_fake_codecs.push_back(cricket::AudioCodec(100, "foo", 0, 0, 1));
1390 caller_fake_codecs.push_back(
1391 cricket::AudioCodec(101, cricket::kRedCodecName, 0, 0, 1));
1392 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
1393 caller_fake_engine->SetAudioCodecs(caller_fake_codecs);
1394 auto caller = CreatePeerConnectionWithAudio(std::move(caller_fake_engine));
1395
1396 std::vector<cricket::AudioCodec> callee_fake_codecs;
1397 callee_fake_codecs.push_back(cricket::AudioCodec(120, "foo", 0, 0, 1));
1398 callee_fake_codecs.push_back(
1399 cricket::AudioCodec(121, cricket::kRedCodecName, 0, 0, 1));
1400 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
1401 callee_fake_engine->SetAudioCodecs(callee_fake_codecs);
1402 auto callee = CreatePeerConnectionWithAudio(std::move(callee_fake_engine));
1403
1404 // Offer from the caller establishes 100 as the "foo" payload type.
1405 // Red (without fmtp) is negotiated.
1406 auto offer = caller->CreateOfferAndSetAsLocal();
1407 callee->SetRemoteDescription(std::move(offer));
1408 auto answer = callee->CreateAnswerAndSetAsLocal();
1409 auto answer_description =
1410 cricket::GetFirstAudioContentDescription(answer->description());
1411 ASSERT_EQ(2u, answer_description->codecs().size());
1412
1413 // Offer from the callee should respect the established payload type, and
1414 // attempt to add RED.
1415 offer = callee->CreateOfferAndSetAsLocal();
1416 auto* offer_description =
1417 cricket::GetFirstAudioContentDescription(offer->description());
1418 ASSERT_EQ(2u, offer_description->codecs().size());
1419 for (const auto& codec : offer_description->codecs()) {
1420 if (codec.name == "foo") {
1421 ASSERT_EQ(100, codec.id);
1422 } else if (codec.name == cricket::kRedCodecName) {
1423 ASSERT_EQ(101, codec.id);
1424 }
1425 }
1426}
1427
1428// Test that RED without fmtp does not match RED with fmtp.
1429TEST_P(PeerConnectionMediaTest, RedFmtpPayloadTypeNoFmtpNoMatchFmtp) {
1430 std::vector<cricket::AudioCodec> caller_fake_codecs;
1431 caller_fake_codecs.push_back(cricket::AudioCodec(100, "foo", 0, 0, 1));
1432 caller_fake_codecs.push_back(
1433 cricket::AudioCodec(101, cricket::kRedCodecName, 0, 0, 1));
1434 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
1435 caller_fake_engine->SetAudioCodecs(caller_fake_codecs);
1436 auto caller = CreatePeerConnectionWithAudio(std::move(caller_fake_engine));
1437
1438 std::vector<cricket::AudioCodec> callee_fake_codecs;
1439 callee_fake_codecs.push_back(cricket::AudioCodec(120, "foo", 0, 0, 1));
1440 callee_fake_codecs.push_back(
1441 cricket::AudioCodec(121, cricket::kRedCodecName, 0, 0, 1));
1442 callee_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1443 "120/120");
1444 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
1445 callee_fake_engine->SetAudioCodecs(callee_fake_codecs);
1446 auto callee = CreatePeerConnectionWithAudio(std::move(callee_fake_engine));
1447
1448 // Offer from the caller establishes 100 as the "foo" payload type.
1449 // It should not negotiate RED.
1450 auto offer = caller->CreateOfferAndSetAsLocal();
1451 callee->SetRemoteDescription(std::move(offer));
1452 auto answer = callee->CreateAnswerAndSetAsLocal();
1453 auto answer_description =
1454 cricket::GetFirstAudioContentDescription(answer->description());
1455 ASSERT_EQ(1u, answer_description->codecs().size());
1456
1457 // Offer from the callee should respect the established payload type, and
1458 // attempt to add RED, which should refer to the correct payload type.
1459 offer = callee->CreateOfferAndSetAsLocal();
1460 auto* offer_description =
1461 cricket::GetFirstAudioContentDescription(offer->description());
1462 ASSERT_EQ(2u, offer_description->codecs().size());
1463 for (const auto& codec : offer_description->codecs()) {
1464 if (codec.name == "foo") {
1465 ASSERT_EQ(100, codec.id);
1466 } else if (codec.name == cricket::kRedCodecName) {
1467 std::string fmtp;
1468 ASSERT_TRUE(
1469 codec.GetParam(cricket::kCodecParamNotInNameValueFormat, &fmtp));
1470 EXPECT_EQ("100/100", fmtp);
1471 }
1472 }
1473}
1474
1475// Test that RED with fmtp must match base codecs.
1476TEST_P(PeerConnectionMediaTest, RedFmtpPayloadTypeMustMatchBaseCodecs) {
1477 std::vector<cricket::AudioCodec> caller_fake_codecs;
1478 caller_fake_codecs.push_back(cricket::AudioCodec(100, "foo", 0, 0, 1));
1479 caller_fake_codecs.push_back(
1480 cricket::AudioCodec(101, cricket::kRedCodecName, 0, 0, 1));
1481 caller_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1482 "100/100");
1483 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
1484 caller_fake_engine->SetAudioCodecs(caller_fake_codecs);
1485 auto caller = CreatePeerConnectionWithAudio(std::move(caller_fake_engine));
1486
1487 std::vector<cricket::AudioCodec> callee_fake_codecs;
1488 callee_fake_codecs.push_back(cricket::AudioCodec(120, "foo", 0, 0, 1));
1489 callee_fake_codecs.push_back(
1490 cricket::AudioCodec(121, cricket::kRedCodecName, 0, 0, 1));
1491 callee_fake_codecs.push_back(cricket::AudioCodec(122, "bar", 0, 0, 1));
1492 callee_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1493 "122/122");
1494 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
1495 callee_fake_engine->SetAudioCodecs(callee_fake_codecs);
1496 auto callee = CreatePeerConnectionWithAudio(std::move(callee_fake_engine));
1497
1498 // Offer from the caller establishes 100 as the "foo" payload type.
1499 // It should not negotiate RED since RED is associated with foo, not bar.
1500 auto offer = caller->CreateOfferAndSetAsLocal();
1501 callee->SetRemoteDescription(std::move(offer));
1502 auto answer = callee->CreateAnswerAndSetAsLocal();
1503 auto answer_description =
1504 cricket::GetFirstAudioContentDescription(answer->description());
1505 ASSERT_EQ(1u, answer_description->codecs().size());
1506}
1507
1508// Test behaviour when the RED fmtp attempts to specify different codecs
1509// which is not supported.
1510TEST_P(PeerConnectionMediaTest, RedFmtpPayloadMixed) {
1511 std::vector<cricket::AudioCodec> caller_fake_codecs;
1512 caller_fake_codecs.push_back(cricket::AudioCodec(100, "foo", 0, 0, 1));
1513 caller_fake_codecs.push_back(cricket::AudioCodec(102, "bar", 0, 0, 1));
1514 caller_fake_codecs.push_back(
1515 cricket::AudioCodec(101, cricket::kRedCodecName, 0, 0, 1));
1516 caller_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1517 "100/102");
1518 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
1519 caller_fake_engine->SetAudioCodecs(caller_fake_codecs);
1520 auto caller = CreatePeerConnectionWithAudio(std::move(caller_fake_engine));
1521
1522 std::vector<cricket::AudioCodec> callee_fake_codecs;
1523 callee_fake_codecs.push_back(cricket::AudioCodec(120, "foo", 0, 0, 1));
1524 callee_fake_codecs.push_back(
1525 cricket::AudioCodec(121, cricket::kRedCodecName, 0, 0, 1));
1526 callee_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1527 "120/120");
1528 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
1529 callee_fake_engine->SetAudioCodecs(callee_fake_codecs);
1530 auto callee = CreatePeerConnectionWithAudio(std::move(callee_fake_engine));
1531
1532 // Offer from the caller establishes 100 as the "foo" payload type.
1533 auto offer = caller->CreateOfferAndSetAsLocal();
1534 callee->SetRemoteDescription(std::move(offer));
1535 auto answer = callee->CreateAnswerAndSetAsLocal();
1536 auto answer_description =
1537 cricket::GetFirstAudioContentDescription(answer->description());
1538 // RED is not negotiated.
1539 ASSERT_EQ(1u, answer_description->codecs().size());
1540}
1541
1542// Test behaviour when the RED fmtp attempts to negotiate different levels of
1543// redundancy.
1544TEST_P(PeerConnectionMediaTest, RedFmtpPayloadDifferentRedundancy) {
1545 std::vector<cricket::AudioCodec> caller_fake_codecs;
1546 caller_fake_codecs.push_back(cricket::AudioCodec(100, "foo", 0, 0, 1));
1547 caller_fake_codecs.push_back(
1548 cricket::AudioCodec(101, cricket::kRedCodecName, 0, 0, 1));
1549 caller_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1550 "100/100");
1551 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
1552 caller_fake_engine->SetAudioCodecs(caller_fake_codecs);
1553 auto caller = CreatePeerConnectionWithAudio(std::move(caller_fake_engine));
1554
1555 std::vector<cricket::AudioCodec> callee_fake_codecs;
1556 callee_fake_codecs.push_back(cricket::AudioCodec(120, "foo", 0, 0, 1));
1557 callee_fake_codecs.push_back(
1558 cricket::AudioCodec(121, cricket::kRedCodecName, 0, 0, 1));
1559 callee_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1560 "120/120/120");
1561 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
1562 callee_fake_engine->SetAudioCodecs(callee_fake_codecs);
1563 auto callee = CreatePeerConnectionWithAudio(std::move(callee_fake_engine));
1564
1565 // Offer from the caller establishes 100 as the "foo" payload type.
1566 auto offer = caller->CreateOfferAndSetAsLocal();
1567 callee->SetRemoteDescription(std::move(offer));
1568 auto answer = callee->CreateAnswerAndSetAsLocal();
1569 auto answer_description =
1570 cricket::GetFirstAudioContentDescription(answer->description());
1571 // RED is negotiated.
1572 ASSERT_EQ(2u, answer_description->codecs().size());
1573
1574 // Offer from the callee should respect the established payload type, and
1575 // attempt to add RED, which should refer to the correct payload type.
1576 offer = callee->CreateOfferAndSetAsLocal();
1577 auto* offer_description =
1578 cricket::GetFirstAudioContentDescription(offer->description());
1579 ASSERT_EQ(2u, offer_description->codecs().size());
1580 for (const auto& codec : offer_description->codecs()) {
1581 if (codec.name == "foo") {
1582 ASSERT_EQ(100, codec.id);
1583 } else if (codec.name == cricket::kRedCodecName) {
1584 std::string fmtp;
1585 ASSERT_TRUE(
1586 codec.GetParam(cricket::kCodecParamNotInNameValueFormat, &fmtp));
1587 EXPECT_EQ("100/100", fmtp);
1588 }
1589 }
1590}
1591
Florent Castelli2d9d82e2019-04-23 17:25:511592template <typename C>
1593bool CompareCodecs(const std::vector<webrtc::RtpCodecCapability>& capabilities,
1594 const std::vector<C>& codecs) {
1595 bool capability_has_rtx =
1596 absl::c_any_of(capabilities, [](const webrtc::RtpCodecCapability& codec) {
1597 return codec.name == cricket::kRtxCodecName;
1598 });
1599 bool codecs_has_rtx = absl::c_any_of(codecs, [](const C& codec) {
1600 return codec.name == cricket::kRtxCodecName;
1601 });
1602
1603 std::vector<C> codecs_no_rtx;
1604 absl::c_copy_if(
1605 codecs, std::back_inserter(codecs_no_rtx),
1606 [](const C& codec) { return codec.name != cricket::kRtxCodecName; });
1607
1608 std::vector<webrtc::RtpCodecCapability> capabilities_no_rtx;
1609 absl::c_copy_if(capabilities, std::back_inserter(capabilities_no_rtx),
1610 [](const webrtc::RtpCodecCapability& codec) {
1611 return codec.name != cricket::kRtxCodecName;
1612 });
1613
1614 return capability_has_rtx == codecs_has_rtx &&
1615 absl::c_equal(
1616 capabilities_no_rtx, codecs_no_rtx,
1617 [](const webrtc::RtpCodecCapability& capability, const C& codec) {
1618 return codec.MatchesCapability(capability);
1619 });
1620}
1621
1622TEST_F(PeerConnectionMediaTestUnifiedPlan,
1623 SetCodecPreferencesAudioMissingRecvCodec) {
Mirko Bonadei317a1f02019-09-17 15:06:181624 auto fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 17:25:511625 auto send_codecs = fake_engine->voice().send_codecs();
1626 send_codecs.push_back(cricket::AudioCodec(send_codecs.back().id + 1,
1627 "send_only_codec", 0, 0, 1));
1628 fake_engine->SetAudioSendCodecs(send_codecs);
1629
1630 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
1631
1632 auto transceiver = caller->pc()->GetTransceivers().front();
1633 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
1634 cricket::MediaType::MEDIA_TYPE_AUDIO);
1635
1636 std::vector<webrtc::RtpCodecCapability> codecs;
1637 absl::c_copy_if(capabilities.codecs, std::back_inserter(codecs),
1638 [](const webrtc::RtpCodecCapability& codec) {
1639 return codec.name.find("_only_") != std::string::npos;
1640 });
1641
1642 auto result = transceiver->SetCodecPreferences(codecs);
1643 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1644}
1645
1646TEST_F(PeerConnectionMediaTestUnifiedPlan,
1647 SetCodecPreferencesAudioMissingSendCodec) {
Mirko Bonadei317a1f02019-09-17 15:06:181648 auto fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 17:25:511649 auto recv_codecs = fake_engine->voice().recv_codecs();
1650 recv_codecs.push_back(cricket::AudioCodec(recv_codecs.back().id + 1,
1651 "recv_only_codec", 0, 0, 1));
1652 fake_engine->SetAudioRecvCodecs(recv_codecs);
1653 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
1654
1655 auto transceiver = caller->pc()->GetTransceivers().front();
1656 auto capabilities = caller->pc_factory()->GetRtpReceiverCapabilities(
1657 cricket::MediaType::MEDIA_TYPE_AUDIO);
1658
1659 std::vector<webrtc::RtpCodecCapability> codecs;
1660 absl::c_copy_if(capabilities.codecs, std::back_inserter(codecs),
1661 [](const webrtc::RtpCodecCapability& codec) {
1662 return codec.name.find("_only_") != std::string::npos;
1663 });
1664
1665 auto result = transceiver->SetCodecPreferences(codecs);
1666 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1667}
1668
1669TEST_F(PeerConnectionMediaTestUnifiedPlan,
1670 SetCodecPreferencesAudioRejectsVideoCodec) {
1671 auto caller = CreatePeerConnectionWithAudio();
1672
1673 auto transceiver = caller->pc()->GetTransceivers().front();
1674 auto video_codecs =
1675 caller->pc_factory()
1676 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)
1677 .codecs;
1678 auto codecs =
1679 caller->pc_factory()
1680 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)
1681 .codecs;
1682 codecs.insert(codecs.end(), video_codecs.begin(), video_codecs.end());
1683 auto result = transceiver->SetCodecPreferences(codecs);
1684 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1685}
1686
1687TEST_F(PeerConnectionMediaTestUnifiedPlan,
1688 SetCodecPreferencesAudioRejectsOnlyRtxRedFec) {
Mirko Bonadei317a1f02019-09-17 15:06:181689 auto fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 17:25:511690 auto audio_codecs = fake_engine->voice().send_codecs();
1691 audio_codecs.push_back(cricket::AudioCodec(audio_codecs.back().id + 1,
1692 cricket::kRtxCodecName, 0, 0, 1));
1693 audio_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1694 std::to_string(audio_codecs.back().id - 1);
1695 audio_codecs.push_back(cricket::AudioCodec(audio_codecs.back().id + 1,
1696 cricket::kRedCodecName, 0, 0, 1));
1697 audio_codecs.push_back(cricket::AudioCodec(
1698 audio_codecs.back().id + 1, cricket::kUlpfecCodecName, 0, 0, 1));
1699 fake_engine->SetAudioCodecs(audio_codecs);
1700
1701 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
1702
1703 auto transceiver = caller->pc()->GetTransceivers().front();
1704 auto codecs =
1705 caller->pc_factory()
1706 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)
1707 .codecs;
1708 auto codecs_only_rtx_red_fec = codecs;
1709 auto it = std::remove_if(codecs_only_rtx_red_fec.begin(),
1710 codecs_only_rtx_red_fec.end(),
1711 [](const webrtc::RtpCodecCapability& codec) {
1712 return !(codec.name == cricket::kRtxCodecName ||
1713 codec.name == cricket::kRedCodecName ||
1714 codec.name == cricket::kUlpfecCodecName);
1715 });
1716 codecs_only_rtx_red_fec.erase(it, codecs_only_rtx_red_fec.end());
1717
1718 auto result = transceiver->SetCodecPreferences(codecs_only_rtx_red_fec);
1719 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1720}
1721
1722TEST_F(PeerConnectionMediaTestUnifiedPlan, SetCodecPreferencesAllAudioCodecs) {
1723 auto caller = CreatePeerConnectionWithAudio();
1724
1725 auto sender_audio_codecs =
1726 caller->pc_factory()
1727 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_AUDIO)
1728 .codecs;
1729
1730 auto audio_transceiver = caller->pc()->GetTransceivers().front();
1731
1732 // Normal case, set all capabilities as preferences
1733 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(sender_audio_codecs).ok());
1734 auto offer = caller->CreateOffer();
1735 auto codecs = offer->description()
1736 ->contents()[0]
1737 .media_description()
1738 ->as_audio()
1739 ->codecs();
1740 EXPECT_TRUE(CompareCodecs(sender_audio_codecs, codecs));
1741}
1742
1743TEST_F(PeerConnectionMediaTestUnifiedPlan,
1744 SetCodecPreferencesResetAudioCodecs) {
1745 auto caller = CreatePeerConnectionWithAudio();
1746
1747 auto sender_audio_codecs =
1748 caller->pc_factory()
1749 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_AUDIO)
1750 .codecs;
1751 std::vector<webrtc::RtpCodecCapability> empty_codecs = {};
1752
1753 auto audio_transceiver = caller->pc()->GetTransceivers().front();
1754
1755 // Normal case, reset codec preferences
1756 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(empty_codecs).ok());
1757 auto offer = caller->CreateOffer();
1758 auto codecs = offer->description()
1759 ->contents()[0]
1760 .media_description()
1761 ->as_audio()
1762 ->codecs();
1763 EXPECT_TRUE(CompareCodecs(sender_audio_codecs, codecs));
1764}
1765
1766TEST_F(PeerConnectionMediaTestUnifiedPlan,
1767 SetCodecPreferencesVideoRejectsAudioCodec) {
1768 auto caller = CreatePeerConnectionWithVideo();
1769
1770 auto transceiver = caller->pc()->GetTransceivers().front();
1771 auto audio_codecs =
1772 caller->pc_factory()
1773 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)
1774 .codecs;
1775 auto codecs =
1776 caller->pc_factory()
1777 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)
1778 .codecs;
1779 codecs.insert(codecs.end(), audio_codecs.begin(), audio_codecs.end());
1780 auto result = transceiver->SetCodecPreferences(codecs);
1781 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1782}
1783
1784TEST_F(PeerConnectionMediaTestUnifiedPlan,
1785 SetCodecPreferencesVideoRejectsOnlyRtxRedFec) {
Mirko Bonadei317a1f02019-09-17 15:06:181786 auto fake_engine = std::make_unique<FakeMediaEngine>();
Johannes Kron3e983682020-03-29 20:17:001787 auto video_codecs = fake_engine->video().send_codecs();
Florent Castelli2d9d82e2019-04-23 17:25:511788 video_codecs.push_back(
1789 cricket::VideoCodec(video_codecs.back().id + 1, cricket::kRtxCodecName));
Johannes Kron3e983682020-03-29 20:17:001790 video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1791 std::to_string(video_codecs.back().id - 1);
Florent Castelli2d9d82e2019-04-23 17:25:511792 video_codecs.push_back(
1793 cricket::VideoCodec(video_codecs.back().id + 1, cricket::kRedCodecName));
1794 video_codecs.push_back(cricket::VideoCodec(video_codecs.back().id + 1,
1795 cricket::kUlpfecCodecName));
1796 fake_engine->SetVideoCodecs(video_codecs);
1797
1798 auto caller = CreatePeerConnectionWithVideo(std::move(fake_engine));
1799
1800 auto transceiver = caller->pc()->GetTransceivers().front();
1801 auto codecs =
1802 caller->pc_factory()
1803 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)
1804 .codecs;
1805 auto codecs_only_rtx_red_fec = codecs;
1806 auto it = std::remove_if(codecs_only_rtx_red_fec.begin(),
1807 codecs_only_rtx_red_fec.end(),
1808 [](const webrtc::RtpCodecCapability& codec) {
1809 return !(codec.name == cricket::kRtxCodecName ||
1810 codec.name == cricket::kRedCodecName ||
1811 codec.name == cricket::kUlpfecCodecName);
1812 });
1813 codecs_only_rtx_red_fec.erase(it, codecs_only_rtx_red_fec.end());
1814
1815 auto result = transceiver->SetCodecPreferences(codecs_only_rtx_red_fec);
1816 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1817}
1818
1819TEST_F(PeerConnectionMediaTestUnifiedPlan, SetCodecPreferencesAllVideoCodecs) {
1820 auto caller = CreatePeerConnectionWithVideo();
1821
1822 auto sender_video_codecs =
1823 caller->pc_factory()
1824 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1825 .codecs;
1826
1827 auto video_transceiver = caller->pc()->GetTransceivers().front();
1828
1829 // Normal case, setting preferences to normal capabilities
1830 EXPECT_TRUE(video_transceiver->SetCodecPreferences(sender_video_codecs).ok());
1831 auto offer = caller->CreateOffer();
1832 auto codecs = offer->description()
1833 ->contents()[0]
1834 .media_description()
1835 ->as_video()
1836 ->codecs();
1837 EXPECT_TRUE(CompareCodecs(sender_video_codecs, codecs));
1838}
1839
1840TEST_F(PeerConnectionMediaTestUnifiedPlan,
1841 SetCodecPreferencesResetVideoCodecs) {
1842 auto caller = CreatePeerConnectionWithVideo();
1843
1844 auto sender_video_codecs =
1845 caller->pc_factory()
1846 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1847 .codecs;
1848
1849 std::vector<webrtc::RtpCodecCapability> empty_codecs = {};
1850
1851 auto video_transceiver = caller->pc()->GetTransceivers().front();
1852
1853 // Normal case, resetting preferences with empty list of codecs
1854 EXPECT_TRUE(video_transceiver->SetCodecPreferences(empty_codecs).ok());
1855 auto offer = caller->CreateOffer();
1856 auto codecs = offer->description()
1857 ->contents()[0]
1858 .media_description()
1859 ->as_video()
1860 ->codecs();
1861 EXPECT_TRUE(CompareCodecs(sender_video_codecs, codecs));
1862}
1863
1864TEST_F(PeerConnectionMediaTestUnifiedPlan,
1865 SetCodecPreferencesVideoCodecDuplicatesRemoved) {
1866 auto caller = CreatePeerConnectionWithVideo();
1867
1868 auto sender_video_codecs =
1869 caller->pc_factory()
1870 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1871 .codecs;
1872
1873 auto video_transceiver = caller->pc()->GetTransceivers().front();
1874
1875 // Check duplicates are removed
1876 auto single_codec = sender_video_codecs;
1877 single_codec.resize(1);
1878 auto duplicate_codec = single_codec;
1879 duplicate_codec.push_back(duplicate_codec.front());
1880 duplicate_codec.push_back(duplicate_codec.front());
1881 duplicate_codec.push_back(duplicate_codec.front());
1882
1883 EXPECT_TRUE(video_transceiver->SetCodecPreferences(duplicate_codec).ok());
1884 auto offer = caller->CreateOffer();
1885 auto codecs = offer->description()
1886 ->contents()[0]
1887 .media_description()
1888 ->as_video()
1889 ->codecs();
1890 EXPECT_TRUE(CompareCodecs(single_codec, codecs));
1891}
1892
1893TEST_F(PeerConnectionMediaTestUnifiedPlan, SetCodecPreferencesVideoWithRtx) {
Mirko Bonadei317a1f02019-09-17 15:06:181894 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Johannes Kron3e983682020-03-29 20:17:001895 auto caller_video_codecs = caller_fake_engine->video().send_codecs();
Florent Castelli2d9d82e2019-04-23 17:25:511896 caller_video_codecs.push_back(cricket::VideoCodec(
1897 caller_video_codecs.back().id + 1, cricket::kVp8CodecName));
1898 caller_video_codecs.push_back(cricket::VideoCodec(
1899 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1900 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1901 std::to_string(caller_video_codecs.back().id - 1);
1902 caller_video_codecs.push_back(cricket::VideoCodec(
1903 caller_video_codecs.back().id + 1, cricket::kVp9CodecName));
1904 caller_video_codecs.push_back(cricket::VideoCodec(
1905 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1906 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1907 std::to_string(caller_video_codecs.back().id - 1);
1908 caller_fake_engine->SetVideoCodecs(caller_video_codecs);
1909
1910 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
1911
1912 auto sender_video_codecs =
1913 caller->pc_factory()
1914 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1915 .codecs;
1916
1917 auto video_transceiver = caller->pc()->GetTransceivers().front();
1918
1919 // Check that RTX codec is properly added
1920 auto video_codecs_vpx_rtx = sender_video_codecs;
1921 auto it =
1922 std::remove_if(video_codecs_vpx_rtx.begin(), video_codecs_vpx_rtx.end(),
1923 [](const webrtc::RtpCodecCapability& codec) {
1924 return codec.name != cricket::kRtxCodecName &&
1925 codec.name != cricket::kVp8CodecName &&
1926 codec.name != cricket::kVp9CodecName;
1927 });
1928 video_codecs_vpx_rtx.erase(it, video_codecs_vpx_rtx.end());
1929 absl::c_reverse(video_codecs_vpx_rtx);
1930 EXPECT_EQ(video_codecs_vpx_rtx.size(), 3u); // VP8, VP9, RTX
1931 EXPECT_TRUE(
1932 video_transceiver->SetCodecPreferences(video_codecs_vpx_rtx).ok());
1933 auto offer = caller->CreateOffer();
1934 auto codecs = offer->description()
1935 ->contents()[0]
1936 .media_description()
1937 ->as_video()
1938 ->codecs();
1939
1940 EXPECT_TRUE(CompareCodecs(video_codecs_vpx_rtx, codecs));
1941 EXPECT_EQ(codecs.size(), 4u);
1942}
1943
1944TEST_F(PeerConnectionMediaTestUnifiedPlan,
1945 SetCodecPreferencesVideoCodecsNegotiation) {
Mirko Bonadei317a1f02019-09-17 15:06:181946 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Johannes Kron3e983682020-03-29 20:17:001947 auto caller_video_codecs = caller_fake_engine->video().send_codecs();
Florent Castelli2d9d82e2019-04-23 17:25:511948 caller_video_codecs.push_back(cricket::VideoCodec(
1949 caller_video_codecs.back().id + 1, cricket::kVp8CodecName));
1950 caller_video_codecs.push_back(cricket::VideoCodec(
1951 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1952 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1953 std::to_string(caller_video_codecs.back().id - 1);
1954 caller_video_codecs.push_back(cricket::VideoCodec(
1955 caller_video_codecs.back().id + 1, cricket::kVp9CodecName));
1956 caller_video_codecs.push_back(cricket::VideoCodec(
1957 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1958 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1959 std::to_string(caller_video_codecs.back().id - 1);
1960 caller_fake_engine->SetVideoCodecs(caller_video_codecs);
1961
Mirko Bonadei317a1f02019-09-17 15:06:181962 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 17:25:511963 callee_fake_engine->SetVideoCodecs(caller_video_codecs);
1964
1965 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
1966 auto callee = CreatePeerConnection(std::move(callee_fake_engine));
1967
1968 auto video_codecs = caller->pc_factory()
1969 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1970 .codecs;
1971
1972 auto send_transceiver = caller->pc()->GetTransceivers().front();
1973
1974 auto video_codecs_vpx = video_codecs;
1975 auto it = std::remove_if(video_codecs_vpx.begin(), video_codecs_vpx.end(),
1976 [](const webrtc::RtpCodecCapability& codec) {
1977 return codec.name != cricket::kVp8CodecName &&
1978 codec.name != cricket::kVp9CodecName;
1979 });
1980 video_codecs_vpx.erase(it, video_codecs_vpx.end());
1981 EXPECT_EQ(video_codecs_vpx.size(), 2u); // VP8, VP9
1982 EXPECT_TRUE(send_transceiver->SetCodecPreferences(video_codecs_vpx).ok());
1983
1984 auto offer = caller->CreateOfferAndSetAsLocal();
1985 auto codecs = offer->description()
1986 ->contents()[0]
1987 .media_description()
1988 ->as_video()
1989 ->codecs();
1990
1991 EXPECT_EQ(codecs.size(), 2u); // VP8, VP9
1992 EXPECT_TRUE(CompareCodecs(video_codecs_vpx, codecs));
1993
1994 callee->SetRemoteDescription(std::move(offer));
1995
1996 auto recv_transceiver = callee->pc()->GetTransceivers().front();
1997 auto video_codecs_vp8_rtx = video_codecs;
1998 it = std::remove_if(video_codecs_vp8_rtx.begin(), video_codecs_vp8_rtx.end(),
1999 [](const webrtc::RtpCodecCapability& codec) {
2000 bool r = codec.name != cricket::kVp8CodecName &&
2001 codec.name != cricket::kRtxCodecName;
2002 return r;
2003 });
2004 video_codecs_vp8_rtx.erase(it, video_codecs_vp8_rtx.end());
2005 EXPECT_EQ(video_codecs_vp8_rtx.size(), 2u); // VP8, RTX
2006 recv_transceiver->SetCodecPreferences(video_codecs_vp8_rtx);
2007
2008 auto answer = callee->CreateAnswerAndSetAsLocal();
2009
2010 auto recv_codecs = answer->description()
2011 ->contents()[0]
2012 .media_description()
2013 ->as_video()
2014 ->codecs();
2015 EXPECT_EQ(recv_codecs.size(), 1u); // VP8
2016}
2017
2018TEST_F(PeerConnectionMediaTestUnifiedPlan,
2019 SetCodecPreferencesVideoCodecsNegotiationReverseOrder) {
Mirko Bonadei317a1f02019-09-17 15:06:182020 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Johannes Kron3e983682020-03-29 20:17:002021 auto caller_video_codecs = caller_fake_engine->video().send_codecs();
Florent Castelli2d9d82e2019-04-23 17:25:512022 caller_video_codecs.push_back(cricket::VideoCodec(
2023 caller_video_codecs.back().id + 1, cricket::kVp8CodecName));
2024 caller_video_codecs.push_back(cricket::VideoCodec(
2025 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
2026 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
2027 std::to_string(caller_video_codecs.back().id - 1);
2028 caller_video_codecs.push_back(cricket::VideoCodec(
2029 caller_video_codecs.back().id + 1, cricket::kVp9CodecName));
2030 caller_video_codecs.push_back(cricket::VideoCodec(
2031 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
2032 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
2033 std::to_string(caller_video_codecs.back().id - 1);
2034 caller_fake_engine->SetVideoCodecs(caller_video_codecs);
2035
Mirko Bonadei317a1f02019-09-17 15:06:182036 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 17:25:512037 callee_fake_engine->SetVideoCodecs(caller_video_codecs);
2038
2039 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
2040 auto callee = CreatePeerConnection(std::move(callee_fake_engine));
2041
2042 auto video_codecs = caller->pc_factory()
2043 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
2044 .codecs;
2045
2046 auto send_transceiver = caller->pc()->GetTransceivers().front();
2047
2048 auto video_codecs_vpx = video_codecs;
2049 auto it = std::remove_if(video_codecs_vpx.begin(), video_codecs_vpx.end(),
2050 [](const webrtc::RtpCodecCapability& codec) {
2051 return codec.name != cricket::kVp8CodecName &&
2052 codec.name != cricket::kVp9CodecName;
2053 });
2054 video_codecs_vpx.erase(it, video_codecs_vpx.end());
2055 EXPECT_EQ(video_codecs_vpx.size(), 2u); // VP8, VP9
2056 EXPECT_TRUE(send_transceiver->SetCodecPreferences(video_codecs_vpx).ok());
2057
2058 auto video_codecs_vpx_reverse = video_codecs_vpx;
2059 absl::c_reverse(video_codecs_vpx_reverse);
2060
2061 auto offer = caller->CreateOfferAndSetAsLocal();
2062 auto codecs = offer->description()
2063 ->contents()[0]
2064 .media_description()
2065 ->as_video()
2066 ->codecs();
2067 EXPECT_EQ(codecs.size(), 2u); // VP9, VP8
2068 EXPECT_TRUE(CompareCodecs(video_codecs_vpx, codecs));
2069
2070 callee->SetRemoteDescription(std::move(offer));
2071
2072 auto recv_transceiver = callee->pc()->GetTransceivers().front();
2073 recv_transceiver->SetCodecPreferences(video_codecs_vpx_reverse);
2074
2075 auto answer = callee->CreateAnswerAndSetAsLocal();
2076
2077 auto recv_codecs = answer->description()
2078 ->contents()[0]
2079 .media_description()
2080 ->as_video()
2081 ->codecs();
2082
2083 EXPECT_TRUE(CompareCodecs(video_codecs_vpx_reverse, recv_codecs));
2084}
2085
Philipp Hancke3ac73bd2021-05-11 12:13:062086TEST_F(PeerConnectionMediaTestUnifiedPlan,
2087 SetCodecPreferencesVoiceActivityDetection) {
2088 auto fake_engine = std::make_unique<FakeMediaEngine>();
2089 AddComfortNoiseCodecsToSend(fake_engine.get());
2090 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
2091
2092 RTCOfferAnswerOptions options;
2093 auto offer = caller->CreateOffer(options);
2094 EXPECT_TRUE(HasAnyComfortNoiseCodecs(offer->description()));
2095
2096 auto transceiver = caller->pc()->GetTransceivers().front();
2097 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2098 cricket::MediaType::MEDIA_TYPE_AUDIO);
2099 EXPECT_TRUE(transceiver->SetCodecPreferences(capabilities.codecs).ok());
2100
2101 options.voice_activity_detection = false;
2102 offer = caller->CreateOffer(options);
2103 EXPECT_FALSE(HasAnyComfortNoiseCodecs(offer->description()));
2104}
2105
Taylor Brandstetterf7fcfb72021-09-09 20:39:382106// If the "default" payload types of audio/video codecs are the same, and
2107// audio/video are bundled (as is the default), payload types should be
2108// remapped to avoid conflict, as normally happens without using
2109// SetCodecPreferences.
2110TEST_F(PeerConnectionMediaTestUnifiedPlan,
2111 SetCodecPreferencesAvoidsPayloadTypeConflictInOffer) {
2112 auto fake_engine = std::make_unique<cricket::FakeMediaEngine>();
2113
2114 std::vector<cricket::AudioCodec> audio_codecs;
2115 audio_codecs.emplace_back(100, "foo", 0, 0, 1);
2116 audio_codecs.emplace_back(101, cricket::kRtxCodecName, 0, 0, 1);
2117 audio_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "100";
2118 fake_engine->SetAudioCodecs(audio_codecs);
2119
2120 std::vector<cricket::VideoCodec> video_codecs;
2121 video_codecs.emplace_back(100, "bar");
2122 video_codecs.emplace_back(101, cricket::kRtxCodecName);
2123 video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "100";
2124 fake_engine->SetVideoCodecs(video_codecs);
2125
2126 auto caller = CreatePeerConnectionWithAudioVideo(std::move(fake_engine));
2127 auto transceivers = caller->pc()->GetTransceivers();
2128 ASSERT_EQ(2u, transceivers.size());
2129
2130 auto audio_transceiver = caller->pc()->GetTransceivers()[0];
2131 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2132 cricket::MediaType::MEDIA_TYPE_AUDIO);
2133 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(capabilities.codecs).ok());
2134
2135 auto video_transceiver = caller->pc()->GetTransceivers()[1];
2136 capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2137 cricket::MediaType::MEDIA_TYPE_VIDEO);
2138 EXPECT_TRUE(video_transceiver->SetCodecPreferences(capabilities.codecs).ok());
2139
2140 RTCOfferAnswerOptions options;
2141 auto offer = caller->CreateOffer(options);
2142 EXPECT_FALSE(HasPayloadTypeConflict(offer->description()));
2143 // Sanity check that we got the primary codec and RTX.
2144 EXPECT_EQ(2u, cricket::GetFirstAudioContentDescription(offer->description())
2145 ->codecs()
2146 .size());
2147 EXPECT_EQ(2u, cricket::GetFirstVideoContentDescription(offer->description())
2148 ->codecs()
2149 .size());
2150}
2151
2152// Same as above, but preferences set for the answer.
2153TEST_F(PeerConnectionMediaTestUnifiedPlan,
2154 SetCodecPreferencesAvoidsPayloadTypeConflictInAnswer) {
2155 auto fake_engine = std::make_unique<cricket::FakeMediaEngine>();
2156
2157 std::vector<cricket::AudioCodec> audio_codecs;
2158 audio_codecs.emplace_back(100, "foo", 0, 0, 1);
2159 audio_codecs.emplace_back(101, cricket::kRtxCodecName, 0, 0, 1);
2160 audio_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "100";
2161 fake_engine->SetAudioCodecs(audio_codecs);
2162
2163 std::vector<cricket::VideoCodec> video_codecs;
2164 video_codecs.emplace_back(100, "bar");
2165 video_codecs.emplace_back(101, cricket::kRtxCodecName);
2166 video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "100";
2167 fake_engine->SetVideoCodecs(video_codecs);
2168
2169 auto caller = CreatePeerConnectionWithAudioVideo(std::move(fake_engine));
2170
2171 RTCOfferAnswerOptions options;
2172 caller->SetRemoteDescription(caller->CreateOffer(options));
2173
2174 auto transceivers = caller->pc()->GetTransceivers();
2175 ASSERT_EQ(2u, transceivers.size());
2176
2177 auto audio_transceiver = caller->pc()->GetTransceivers()[0];
2178 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2179 cricket::MediaType::MEDIA_TYPE_AUDIO);
2180 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(capabilities.codecs).ok());
2181
2182 auto video_transceiver = caller->pc()->GetTransceivers()[1];
2183 capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2184 cricket::MediaType::MEDIA_TYPE_VIDEO);
2185 EXPECT_TRUE(video_transceiver->SetCodecPreferences(capabilities.codecs).ok());
2186
2187 auto answer = caller->CreateAnswer(options);
2188
2189 EXPECT_FALSE(HasPayloadTypeConflict(answer->description()));
2190 // Sanity check that we got the primary codec and RTX.
2191 EXPECT_EQ(2u, cricket::GetFirstAudioContentDescription(answer->description())
2192 ->codecs()
2193 .size());
2194 EXPECT_EQ(2u, cricket::GetFirstVideoContentDescription(answer->description())
2195 ->codecs()
2196 .size());
2197}
2198
2199// Same as above, but preferences set for a subsequent offer.
2200TEST_F(PeerConnectionMediaTestUnifiedPlan,
2201 SetCodecPreferencesAvoidsPayloadTypeConflictInSubsequentOffer) {
2202 auto fake_engine = std::make_unique<cricket::FakeMediaEngine>();
2203
2204 std::vector<cricket::AudioCodec> audio_codecs;
2205 audio_codecs.emplace_back(100, "foo", 0, 0, 1);
2206 audio_codecs.emplace_back(101, cricket::kRtxCodecName, 0, 0, 1);
2207 audio_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "100";
2208 fake_engine->SetAudioCodecs(audio_codecs);
2209
2210 std::vector<cricket::VideoCodec> video_codecs;
2211 video_codecs.emplace_back(100, "bar");
2212 video_codecs.emplace_back(101, cricket::kRtxCodecName);
2213 video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "100";
2214 fake_engine->SetVideoCodecs(video_codecs);
2215
2216 auto caller = CreatePeerConnectionWithAudioVideo(std::move(fake_engine));
2217
2218 RTCOfferAnswerOptions options;
2219 caller->SetRemoteDescription(caller->CreateOffer(options));
2220 caller->SetLocalDescription(caller->CreateAnswer(options));
2221
2222 auto transceivers = caller->pc()->GetTransceivers();
2223 ASSERT_EQ(2u, transceivers.size());
2224
2225 auto audio_transceiver = caller->pc()->GetTransceivers()[0];
2226 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2227 cricket::MediaType::MEDIA_TYPE_AUDIO);
2228 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(capabilities.codecs).ok());
2229
2230 auto video_transceiver = caller->pc()->GetTransceivers()[1];
2231 capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2232 cricket::MediaType::MEDIA_TYPE_VIDEO);
2233 EXPECT_TRUE(video_transceiver->SetCodecPreferences(capabilities.codecs).ok());
2234
2235 auto reoffer = caller->CreateOffer(options);
2236
2237 EXPECT_FALSE(HasPayloadTypeConflict(reoffer->description()));
2238 // Sanity check that we got the primary codec and RTX.
2239 EXPECT_EQ(2u, cricket::GetFirstAudioContentDescription(reoffer->description())
2240 ->codecs()
2241 .size());
2242 EXPECT_EQ(2u, cricket::GetFirstVideoContentDescription(reoffer->description())
2243 ->codecs()
2244 .size());
2245}
2246
Mirko Bonadeic84f6612019-01-31 11:20:572247INSTANTIATE_TEST_SUITE_P(PeerConnectionMediaTest,
2248 PeerConnectionMediaTest,
Florent Castelli15a38de2022-04-05 22:38:212249 Values(SdpSemantics::kPlanB_DEPRECATED,
Mirko Bonadeic84f6612019-01-31 11:20:572250 SdpSemantics::kUnifiedPlan));
Steve Antonad7bffc2018-01-22 18:21:562251
Steve Anton8d3444d2017-10-20 22:30:512252} // namespace webrtc