blob: c5a4a303b39296dac96e344299b3422c7c99b68b [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
Mirko Bonadei317a1f02019-09-17 15:06:1815#include <memory>
Taylor Brandstetterf7fcfb72021-09-09 20:39:3816#include <set>
Steve Anton8d3444d2017-10-20 22:30:5117#include <tuple>
18
Steve Anton64b626b2019-01-29 01:25:2619#include "absl/algorithm/container.h"
Mirta Dvornicic479a3c02019-06-04 13:38:5020#include "absl/types/optional.h"
Steve Anton10542f22019-01-11 17:11:0021#include "api/call/call_factory_interface.h"
Danil Chapovalov9da25bd2019-06-20 08:19:4222#include "api/rtc_event_log/rtc_event_log_factory.h"
23#include "api/task_queue/default_task_queue_factory.h"
Steve Anton10542f22019-01-11 17:11:0024#include "media/base/fake_media_engine.h"
25#include "p2p/base/fake_port_allocator.h"
26#include "pc/media_session.h"
27#include "pc/peer_connection_wrapper.h"
28#include "pc/rtp_media_utils.h"
29#include "pc/sdp_utils.h"
Steve Anton8d3444d2017-10-20 22:30:5130#ifdef WEBRTC_ANDROID
Steve Anton10542f22019-01-11 17:11:0031#include "pc/test/android_test_initializer.h"
Steve Anton8d3444d2017-10-20 22:30:5132#endif
Steve Anton10542f22019-01-11 17:11:0033#include "pc/test/fake_rtc_certificate_generator.h"
Steve Anton8d3444d2017-10-20 22:30:5134#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 17:11:0035#include "rtc_base/virtual_socket_server.h"
Steve Anton8d3444d2017-10-20 22:30:5136#include "test/gmock.h"
37
38namespace webrtc {
39
40using cricket::FakeMediaEngine;
41using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
42using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
43using ::testing::Bool;
44using ::testing::Combine;
Steve Anton8d3444d2017-10-20 22:30:5145using ::testing::ElementsAre;
Jonas Olssona4d87372019-07-05 17:08:3346using ::testing::Values;
Steve Anton8d3444d2017-10-20 22:30:5147
48class PeerConnectionWrapperForMediaTest : public PeerConnectionWrapper {
49 public:
50 using PeerConnectionWrapper::PeerConnectionWrapper;
51
52 FakeMediaEngine* media_engine() { return media_engine_; }
53 void set_media_engine(FakeMediaEngine* media_engine) {
54 media_engine_ = media_engine;
55 }
56
57 private:
58 FakeMediaEngine* media_engine_;
59};
60
Steve Antonad7bffc2018-01-22 18:21:5661class PeerConnectionMediaBaseTest : public ::testing::Test {
Steve Anton8d3444d2017-10-20 22:30:5162 protected:
63 typedef std::unique_ptr<PeerConnectionWrapperForMediaTest> WrapperPtr;
64
Steve Antonad7bffc2018-01-22 18:21:5665 explicit PeerConnectionMediaBaseTest(SdpSemantics sdp_semantics)
66 : vss_(new rtc::VirtualSocketServer()),
67 main_(vss_.get()),
68 sdp_semantics_(sdp_semantics) {
Steve Anton8d3444d2017-10-20 22:30:5169#ifdef WEBRTC_ANDROID
70 InitializeAndroidObjects();
71#endif
72 }
73
74 WrapperPtr CreatePeerConnection() {
75 return CreatePeerConnection(RTCConfiguration());
76 }
77
Florent Castelli2d9d82e2019-04-23 17:25:5178 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
Mirko Bonadei317a1f02019-09-17 15:06:1879 return CreatePeerConnection(config, std::make_unique<FakeMediaEngine>());
Florent Castelli2d9d82e2019-04-23 17:25:5180 }
81
82 WrapperPtr CreatePeerConnection(
83 std::unique_ptr<FakeMediaEngine> media_engine) {
84 return CreatePeerConnection(RTCConfiguration(), std::move(media_engine));
85 }
86
Anton Sukhanov98a462c2018-10-17 20:15:4287 // Creates PeerConnectionFactory and PeerConnection for given configuration.
Florent Castelli2d9d82e2019-04-23 17:25:5188 WrapperPtr CreatePeerConnection(
89 const RTCConfiguration& config,
90 std::unique_ptr<FakeMediaEngine> media_engine) {
Steve Anton8d3444d2017-10-20 22:30:5191 auto* media_engine_ptr = media_engine.get();
Anton Sukhanov98a462c2018-10-17 20:15:4292
93 PeerConnectionFactoryDependencies factory_dependencies;
94
95 factory_dependencies.network_thread = rtc::Thread::Current();
96 factory_dependencies.worker_thread = rtc::Thread::Current();
97 factory_dependencies.signaling_thread = rtc::Thread::Current();
Danil Chapovalov9da25bd2019-06-20 08:19:4298 factory_dependencies.task_queue_factory = CreateDefaultTaskQueueFactory();
Anton Sukhanov98a462c2018-10-17 20:15:4299 factory_dependencies.media_engine = std::move(media_engine);
100 factory_dependencies.call_factory = CreateCallFactory();
Danil Chapovalov9da25bd2019-06-20 08:19:42101 factory_dependencies.event_log_factory =
Mirko Bonadei317a1f02019-09-17 15:06:18102 std::make_unique<RtcEventLogFactory>(
Danil Chapovalov9da25bd2019-06-20 08:19:42103 factory_dependencies.task_queue_factory.get());
Anton Sukhanov98a462c2018-10-17 20:15:42104
105 auto pc_factory =
106 CreateModularPeerConnectionFactory(std::move(factory_dependencies));
Steve Anton8d3444d2017-10-20 22:30:51107
Mirko Bonadei317a1f02019-09-17 15:06:18108 auto fake_port_allocator = std::make_unique<cricket::FakePortAllocator>(
Steve Anton8d3444d2017-10-20 22:30:51109 rtc::Thread::Current(), nullptr);
Mirko Bonadei317a1f02019-09-17 15:06:18110 auto observer = std::make_unique<MockPeerConnectionObserver>();
Steve Antonad7bffc2018-01-22 18:21:56111 auto modified_config = config;
112 modified_config.sdp_semantics = sdp_semantics_;
113 auto pc = pc_factory->CreatePeerConnection(modified_config,
114 std::move(fake_port_allocator),
115 nullptr, observer.get());
Steve Anton8d3444d2017-10-20 22:30:51116 if (!pc) {
117 return nullptr;
118 }
119
Yves Gerey4e933292018-10-31 14:36:05120 observer->SetPeerConnectionInterface(pc.get());
Mirko Bonadei317a1f02019-09-17 15:06:18121 auto wrapper = std::make_unique<PeerConnectionWrapperForMediaTest>(
Steve Anton8d3444d2017-10-20 22:30:51122 pc_factory, pc, std::move(observer));
123 wrapper->set_media_engine(media_engine_ptr);
124 return wrapper;
125 }
126
127 // Accepts the same arguments as CreatePeerConnection and adds default audio
Piotr (Peter) Slatala10aeb2a2018-11-14 18:57:24128 // track (but no video).
129 template <typename... Args>
130 WrapperPtr CreatePeerConnectionWithAudio(Args&&... args) {
131 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
132 if (!wrapper) {
133 return nullptr;
134 }
135 wrapper->AddAudioTrack("a");
136 return wrapper;
137 }
138
Florent Castelli2d9d82e2019-04-23 17:25:51139 // Accepts the same arguments as CreatePeerConnection and adds default video
140 // track (but no audio).
141 template <typename... Args>
142 WrapperPtr CreatePeerConnectionWithVideo(Args&&... args) {
143 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
144 if (!wrapper) {
145 return nullptr;
146 }
147 wrapper->AddVideoTrack("v");
148 return wrapper;
149 }
150
Piotr (Peter) Slatala10aeb2a2018-11-14 18:57:24151 // Accepts the same arguments as CreatePeerConnection and adds default audio
Steve Anton8d3444d2017-10-20 22:30:51152 // and video tracks.
153 template <typename... Args>
154 WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
155 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
156 if (!wrapper) {
157 return nullptr;
158 }
159 wrapper->AddAudioTrack("a");
160 wrapper->AddVideoTrack("v");
161 return wrapper;
162 }
163
Steve Anton4e70a722017-11-28 22:57:10164 RtpTransceiverDirection GetMediaContentDirection(
Steve Anton8d3444d2017-10-20 22:30:51165 const SessionDescriptionInterface* sdesc,
Steve Antonad7bffc2018-01-22 18:21:56166 cricket::MediaType media_type) {
167 auto* content =
168 cricket::GetFirstMediaContent(sdesc->description(), media_type);
169 RTC_DCHECK(content);
170 return content->media_description()->direction();
171 }
172
173 bool IsUnifiedPlan() const {
174 return sdp_semantics_ == SdpSemantics::kUnifiedPlan;
Steve Anton8d3444d2017-10-20 22:30:51175 }
176
177 std::unique_ptr<rtc::VirtualSocketServer> vss_;
178 rtc::AutoSocketServerThread main_;
Steve Antonad7bffc2018-01-22 18:21:56179 const SdpSemantics sdp_semantics_;
Steve Anton8d3444d2017-10-20 22:30:51180};
181
Steve Antonad7bffc2018-01-22 18:21:56182class PeerConnectionMediaTest
183 : public PeerConnectionMediaBaseTest,
184 public ::testing::WithParamInterface<SdpSemantics> {
185 protected:
186 PeerConnectionMediaTest() : PeerConnectionMediaBaseTest(GetParam()) {}
187};
188
189class PeerConnectionMediaTestUnifiedPlan : public PeerConnectionMediaBaseTest {
190 protected:
191 PeerConnectionMediaTestUnifiedPlan()
192 : PeerConnectionMediaBaseTest(SdpSemantics::kUnifiedPlan) {}
193};
194
195class PeerConnectionMediaTestPlanB : public PeerConnectionMediaBaseTest {
196 protected:
197 PeerConnectionMediaTestPlanB()
198 : PeerConnectionMediaBaseTest(SdpSemantics::kPlanB) {}
199};
200
201TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 22:30:51202 FailToSetRemoteDescriptionIfCreateMediaChannelFails) {
203 auto caller = CreatePeerConnectionWithAudioVideo();
204 auto callee = CreatePeerConnectionWithAudioVideo();
205 callee->media_engine()->set_fail_create_channel(true);
206
207 std::string error;
208 ASSERT_FALSE(callee->SetRemoteDescription(caller->CreateOffer(), &error));
Steve Antonad7bffc2018-01-22 18:21:56209 EXPECT_PRED_FORMAT2(AssertStartsWith, error,
210 "Failed to set remote offer sdp: Failed to create");
Steve Anton8d3444d2017-10-20 22:30:51211}
212
Steve Antonad7bffc2018-01-22 18:21:56213TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 22:30:51214 FailToSetLocalDescriptionIfCreateMediaChannelFails) {
215 auto caller = CreatePeerConnectionWithAudioVideo();
216 caller->media_engine()->set_fail_create_channel(true);
217
218 std::string error;
219 ASSERT_FALSE(caller->SetLocalDescription(caller->CreateOffer(), &error));
Steve Antonad7bffc2018-01-22 18:21:56220 EXPECT_PRED_FORMAT2(AssertStartsWith, error,
221 "Failed to set local offer sdp: Failed to create");
Steve Anton8d3444d2017-10-20 22:30:51222}
223
224std::vector<std::string> GetIds(
225 const std::vector<cricket::StreamParams>& streams) {
226 std::vector<std::string> ids;
Mirko Bonadei649a4c22019-01-29 09:11:53227 ids.reserve(streams.size());
Steve Anton8d3444d2017-10-20 22:30:51228 for (const auto& stream : streams) {
229 ids.push_back(stream.id);
230 }
231 return ids;
232}
233
234// Test that exchanging an offer and answer with each side having an audio and
235// video stream creates the appropriate send/recv streams in the underlying
236// media engine on both sides.
Steve Antonad7bffc2018-01-22 18:21:56237TEST_P(PeerConnectionMediaTest, AudioVideoOfferAnswerCreateSendRecvStreams) {
Steve Anton8d3444d2017-10-20 22:30:51238 const std::string kCallerAudioId = "caller_a";
239 const std::string kCallerVideoId = "caller_v";
240 const std::string kCalleeAudioId = "callee_a";
241 const std::string kCalleeVideoId = "callee_v";
242
243 auto caller = CreatePeerConnection();
244 caller->AddAudioTrack(kCallerAudioId);
245 caller->AddVideoTrack(kCallerVideoId);
246
247 auto callee = CreatePeerConnection();
248 callee->AddAudioTrack(kCalleeAudioId);
249 callee->AddVideoTrack(kCalleeVideoId);
250
251 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
252 ASSERT_TRUE(
253 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
254
255 auto* caller_voice = caller->media_engine()->GetVoiceChannel(0);
256 EXPECT_THAT(GetIds(caller_voice->recv_streams()),
257 ElementsAre(kCalleeAudioId));
258 EXPECT_THAT(GetIds(caller_voice->send_streams()),
259 ElementsAre(kCallerAudioId));
260
261 auto* caller_video = caller->media_engine()->GetVideoChannel(0);
262 EXPECT_THAT(GetIds(caller_video->recv_streams()),
263 ElementsAre(kCalleeVideoId));
264 EXPECT_THAT(GetIds(caller_video->send_streams()),
265 ElementsAre(kCallerVideoId));
266
267 auto* callee_voice = callee->media_engine()->GetVoiceChannel(0);
268 EXPECT_THAT(GetIds(callee_voice->recv_streams()),
269 ElementsAre(kCallerAudioId));
270 EXPECT_THAT(GetIds(callee_voice->send_streams()),
271 ElementsAre(kCalleeAudioId));
272
273 auto* callee_video = callee->media_engine()->GetVideoChannel(0);
274 EXPECT_THAT(GetIds(callee_video->recv_streams()),
275 ElementsAre(kCallerVideoId));
276 EXPECT_THAT(GetIds(callee_video->send_streams()),
277 ElementsAre(kCalleeVideoId));
278}
279
Steve Antonad7bffc2018-01-22 18:21:56280// Test that stopping the caller transceivers causes the media channels on the
281// callee to be destroyed after calling SetRemoteDescription on the generated
282// offer.
283// See next test for equivalent behavior with Plan B semantics.
284TEST_F(PeerConnectionMediaTestUnifiedPlan,
285 StoppedRemoteTransceiversRemovesMediaChannels) {
286 auto caller = CreatePeerConnectionWithAudioVideo();
287 auto callee = CreatePeerConnection();
288
289 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
290
291 // Stop both audio and video transceivers on the caller.
292 auto transceivers = caller->pc()->GetTransceivers();
293 ASSERT_EQ(2u, transceivers.size());
Harald Alvestrand6060df52020-08-11 07:54:02294 transceivers[0]->StopInternal();
295 transceivers[1]->StopInternal();
Steve Antonad7bffc2018-01-22 18:21:56296
297 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
298
299 ASSERT_FALSE(callee->media_engine()->GetVoiceChannel(0));
300 ASSERT_FALSE(callee->media_engine()->GetVideoChannel(0));
301}
302
Steve Anton8d3444d2017-10-20 22:30:51303// Test that removing streams from a subsequent offer causes the receive streams
304// on the callee to be removed.
Steve Antonad7bffc2018-01-22 18:21:56305// See previous test for equivalent behavior with Unified Plan semantics.
306TEST_F(PeerConnectionMediaTestPlanB, EmptyRemoteOfferRemovesRecvStreams) {
Steve Anton8d3444d2017-10-20 22:30:51307 auto caller = CreatePeerConnection();
308 auto caller_audio_track = caller->AddAudioTrack("a");
309 auto caller_video_track = caller->AddVideoTrack("v");
310 auto callee = CreatePeerConnectionWithAudioVideo();
311
Steve Antonad7bffc2018-01-22 18:21:56312 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 22:30:51313
314 // Remove both tracks from caller.
315 caller->pc()->RemoveTrack(caller_audio_track);
316 caller->pc()->RemoveTrack(caller_video_track);
317
Steve Antonad7bffc2018-01-22 18:21:56318 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 22:30:51319
320 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
Steve Antonad7bffc2018-01-22 18:21:56321 auto callee_video = callee->media_engine()->GetVideoChannel(0);
Steve Anton8d3444d2017-10-20 22:30:51322 EXPECT_EQ(1u, callee_voice->send_streams().size());
323 EXPECT_EQ(0u, callee_voice->recv_streams().size());
Steve Anton8d3444d2017-10-20 22:30:51324 EXPECT_EQ(1u, callee_video->send_streams().size());
325 EXPECT_EQ(0u, callee_video->recv_streams().size());
326}
327
Jonas Orelandfc1acd22018-08-24 08:58:37328// Test enabling of simulcast with Plan B semantics.
329// This test creating an offer.
330TEST_F(PeerConnectionMediaTestPlanB, SimulcastOffer) {
331 auto caller = CreatePeerConnection();
332 auto caller_video_track = caller->AddVideoTrack("v");
333 RTCOfferAnswerOptions options;
334 options.num_simulcast_layers = 3;
335 auto offer = caller->CreateOffer(options);
Jonas Olssona4d87372019-07-05 17:08:33336 auto* description = cricket::GetFirstMediaContent(offer->description(),
337 cricket::MEDIA_TYPE_VIDEO)
338 ->media_description();
Jonas Orelandfc1acd22018-08-24 08:58:37339 ASSERT_EQ(1u, description->streams().size());
340 ASSERT_TRUE(description->streams()[0].get_ssrc_group("SIM"));
341 EXPECT_EQ(3u, description->streams()[0].get_ssrc_group("SIM")->ssrcs.size());
342
343 // Check that it actually creates simulcast aswell.
344 caller->SetLocalDescription(std::move(offer));
345 auto senders = caller->pc()->GetSenders();
346 ASSERT_EQ(1u, senders.size());
347 EXPECT_EQ(cricket::MediaType::MEDIA_TYPE_VIDEO, senders[0]->media_type());
348 EXPECT_EQ(3u, senders[0]->GetParameters().encodings.size());
349}
350
351// Test enabling of simulcast with Plan B semantics.
352// This test creating an answer.
353TEST_F(PeerConnectionMediaTestPlanB, SimulcastAnswer) {
354 auto caller = CreatePeerConnection();
355 caller->AddVideoTrack("v0");
356 auto offer = caller->CreateOffer();
357 auto callee = CreatePeerConnection();
358 auto callee_video_track = callee->AddVideoTrack("v1");
359 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
360 RTCOfferAnswerOptions options;
361 options.num_simulcast_layers = 3;
362 auto answer = callee->CreateAnswer(options);
Jonas Olssona4d87372019-07-05 17:08:33363 auto* description = cricket::GetFirstMediaContent(answer->description(),
364 cricket::MEDIA_TYPE_VIDEO)
365 ->media_description();
Jonas Orelandfc1acd22018-08-24 08:58:37366 ASSERT_EQ(1u, description->streams().size());
367 ASSERT_TRUE(description->streams()[0].get_ssrc_group("SIM"));
368 EXPECT_EQ(3u, description->streams()[0].get_ssrc_group("SIM")->ssrcs.size());
369
370 // Check that it actually creates simulcast aswell.
371 callee->SetLocalDescription(std::move(answer));
372 auto senders = callee->pc()->GetSenders();
373 ASSERT_EQ(1u, senders.size());
374 EXPECT_EQ(cricket::MediaType::MEDIA_TYPE_VIDEO, senders[0]->media_type());
375 EXPECT_EQ(3u, senders[0]->GetParameters().encodings.size());
376}
377
Steve Antonad7bffc2018-01-22 18:21:56378// Test that stopping the callee transceivers causes the media channels to be
379// destroyed on the callee after calling SetLocalDescription on the local
380// answer.
381// See next test for equivalent behavior with Plan B semantics.
382TEST_F(PeerConnectionMediaTestUnifiedPlan,
383 StoppedLocalTransceiversRemovesMediaChannels) {
384 auto caller = CreatePeerConnectionWithAudioVideo();
385 auto callee = CreatePeerConnectionWithAudioVideo();
386
387 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
388
389 // Stop both audio and video transceivers on the callee.
390 auto transceivers = callee->pc()->GetTransceivers();
391 ASSERT_EQ(2u, transceivers.size());
Harald Alvestrand6060df52020-08-11 07:54:02392 transceivers[0]->StopInternal();
393 transceivers[1]->StopInternal();
Steve Antonad7bffc2018-01-22 18:21:56394
395 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
396
397 EXPECT_FALSE(callee->media_engine()->GetVoiceChannel(0));
398 EXPECT_FALSE(callee->media_engine()->GetVideoChannel(0));
399}
400
Steve Anton8d3444d2017-10-20 22:30:51401// Test that removing streams from a subsequent answer causes the send streams
402// on the callee to be removed when applied locally.
Steve Antonad7bffc2018-01-22 18:21:56403// See previous test for equivalent behavior with Unified Plan semantics.
404TEST_F(PeerConnectionMediaTestPlanB, EmptyLocalAnswerRemovesSendStreams) {
Steve Anton8d3444d2017-10-20 22:30:51405 auto caller = CreatePeerConnectionWithAudioVideo();
406 auto callee = CreatePeerConnection();
407 auto callee_audio_track = callee->AddAudioTrack("a");
408 auto callee_video_track = callee->AddVideoTrack("v");
409
Steve Antonad7bffc2018-01-22 18:21:56410 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 22:30:51411
412 // Remove both tracks from callee.
413 callee->pc()->RemoveTrack(callee_audio_track);
414 callee->pc()->RemoveTrack(callee_video_track);
415
Steve Antonad7bffc2018-01-22 18:21:56416 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 22:30:51417
418 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
Steve Antonad7bffc2018-01-22 18:21:56419 auto callee_video = callee->media_engine()->GetVideoChannel(0);
Steve Anton8d3444d2017-10-20 22:30:51420 EXPECT_EQ(0u, callee_voice->send_streams().size());
421 EXPECT_EQ(1u, callee_voice->recv_streams().size());
Steve Anton8d3444d2017-10-20 22:30:51422 EXPECT_EQ(0u, callee_video->send_streams().size());
423 EXPECT_EQ(1u, callee_video->recv_streams().size());
424}
425
426// Test that a new stream in a subsequent offer causes a new receive stream to
427// be created on the callee.
Steve Antonad7bffc2018-01-22 18:21:56428TEST_P(PeerConnectionMediaTest, NewStreamInRemoteOfferAddsRecvStreams) {
Steve Anton8d3444d2017-10-20 22:30:51429 auto caller = CreatePeerConnectionWithAudioVideo();
430 auto callee = CreatePeerConnection();
431
Steve Antonad7bffc2018-01-22 18:21:56432 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 22:30:51433
434 // Add second set of tracks to the caller.
435 caller->AddAudioTrack("a2");
436 caller->AddVideoTrack("v2");
437
Steve Antonad7bffc2018-01-22 18:21:56438 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 22:30:51439
Steve Antonad7bffc2018-01-22 18:21:56440 auto a1 = callee->media_engine()->GetVoiceChannel(0);
441 auto a2 = callee->media_engine()->GetVoiceChannel(1);
442 auto v1 = callee->media_engine()->GetVideoChannel(0);
443 auto v2 = callee->media_engine()->GetVideoChannel(1);
444 if (IsUnifiedPlan()) {
445 ASSERT_TRUE(a1);
446 EXPECT_EQ(1u, a1->recv_streams().size());
447 ASSERT_TRUE(a2);
448 EXPECT_EQ(1u, a2->recv_streams().size());
449 ASSERT_TRUE(v1);
450 EXPECT_EQ(1u, v1->recv_streams().size());
451 ASSERT_TRUE(v2);
452 EXPECT_EQ(1u, v2->recv_streams().size());
453 } else {
454 ASSERT_TRUE(a1);
455 EXPECT_EQ(2u, a1->recv_streams().size());
456 ASSERT_FALSE(a2);
457 ASSERT_TRUE(v1);
458 EXPECT_EQ(2u, v1->recv_streams().size());
459 ASSERT_FALSE(v2);
460 }
Steve Anton8d3444d2017-10-20 22:30:51461}
462
463// Test that a new stream in a subsequent answer causes a new send stream to be
464// created on the callee when added locally.
Steve Antonad7bffc2018-01-22 18:21:56465TEST_P(PeerConnectionMediaTest, NewStreamInLocalAnswerAddsSendStreams) {
Steve Anton8d3444d2017-10-20 22:30:51466 auto caller = CreatePeerConnection();
467 auto callee = CreatePeerConnectionWithAudioVideo();
468
Steve Anton22da89f2018-01-25 21:58:07469 RTCOfferAnswerOptions offer_options;
470 offer_options.offer_to_receive_audio =
Steve Anton8d3444d2017-10-20 22:30:51471 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
Steve Anton22da89f2018-01-25 21:58:07472 offer_options.offer_to_receive_video =
Steve Anton8d3444d2017-10-20 22:30:51473 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
Steve Anton22da89f2018-01-25 21:58:07474 RTCOfferAnswerOptions answer_options;
Steve Anton8d3444d2017-10-20 22:30:51475
Steve Anton22da89f2018-01-25 21:58:07476 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get(), offer_options,
477 answer_options));
Steve Anton8d3444d2017-10-20 22:30:51478
479 // Add second set of tracks to the callee.
480 callee->AddAudioTrack("a2");
481 callee->AddVideoTrack("v2");
482
Steve Anton22da89f2018-01-25 21:58:07483 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get(), offer_options,
484 answer_options));
Steve Anton8d3444d2017-10-20 22:30:51485
486 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
Steve Anton22da89f2018-01-25 21:58:07487 ASSERT_TRUE(callee_voice);
Steve Anton8d3444d2017-10-20 22:30:51488 auto callee_video = callee->media_engine()->GetVideoChannel(0);
Steve Anton22da89f2018-01-25 21:58:07489 ASSERT_TRUE(callee_video);
490
491 if (IsUnifiedPlan()) {
492 EXPECT_EQ(1u, callee_voice->send_streams().size());
493 EXPECT_EQ(1u, callee_video->send_streams().size());
494 } else {
495 EXPECT_EQ(2u, callee_voice->send_streams().size());
496 EXPECT_EQ(2u, callee_video->send_streams().size());
497 }
Steve Anton8d3444d2017-10-20 22:30:51498}
499
500// A PeerConnection with no local streams and no explicit answer constraints
501// should not reject any offered media sections.
Steve Antonad7bffc2018-01-22 18:21:56502TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 22:30:51503 CreateAnswerWithNoStreamsAndDefaultOptionsDoesNotReject) {
504 auto caller = CreatePeerConnectionWithAudioVideo();
505 auto callee = CreatePeerConnection();
506 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
507 auto answer = callee->CreateAnswer();
508
509 const auto* audio_content =
510 cricket::GetFirstAudioContent(answer->description());
511 ASSERT_TRUE(audio_content);
512 EXPECT_FALSE(audio_content->rejected);
513
514 const auto* video_content =
515 cricket::GetFirstVideoContent(answer->description());
516 ASSERT_TRUE(video_content);
517 EXPECT_FALSE(video_content->rejected);
518}
519
Mirta Dvornicic479a3c02019-06-04 13:38:50520// Test that raw packetization is not set in the offer by default.
521TEST_P(PeerConnectionMediaTest, RawPacketizationNotSetInOffer) {
522 std::vector<cricket::VideoCodec> fake_codecs;
523 fake_codecs.push_back(cricket::VideoCodec(111, cricket::kVp8CodecName));
524 fake_codecs.push_back(cricket::VideoCodec(112, cricket::kRtxCodecName));
525 fake_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "111";
526 fake_codecs.push_back(cricket::VideoCodec(113, cricket::kVp9CodecName));
527 fake_codecs.push_back(cricket::VideoCodec(114, cricket::kH264CodecName));
528 fake_codecs.push_back(cricket::VideoCodec(115, "HEVC"));
Mirko Bonadei317a1f02019-09-17 15:06:18529 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 13:38:50530 caller_fake_engine->SetVideoCodecs(fake_codecs);
531
532 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
533 auto offer = caller->CreateOfferAndSetAsLocal();
534 auto* offer_description =
535 cricket::GetFirstVideoContentDescription(offer->description());
536 for (const auto& codec : offer_description->codecs()) {
537 EXPECT_EQ(codec.packetization, absl::nullopt);
538 }
539}
540
541// Test that raw packetization is set in the offer and answer for all
542// video payload when raw_packetization_for_video is true.
543TEST_P(PeerConnectionMediaTest, RawPacketizationSetInOfferAndAnswer) {
544 std::vector<cricket::VideoCodec> fake_codecs;
545 fake_codecs.push_back(cricket::VideoCodec(111, cricket::kVp8CodecName));
546 fake_codecs.push_back(cricket::VideoCodec(112, cricket::kRtxCodecName));
547 fake_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "111";
548 fake_codecs.push_back(cricket::VideoCodec(113, cricket::kVp9CodecName));
549 fake_codecs.push_back(cricket::VideoCodec(114, cricket::kH264CodecName));
550 fake_codecs.push_back(cricket::VideoCodec(115, "HEVC"));
Mirko Bonadei317a1f02019-09-17 15:06:18551 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 13:38:50552 caller_fake_engine->SetVideoCodecs(fake_codecs);
Mirko Bonadei317a1f02019-09-17 15:06:18553 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 13:38:50554 callee_fake_engine->SetVideoCodecs(fake_codecs);
555
556 RTCOfferAnswerOptions options;
557 options.raw_packetization_for_video = true;
558
559 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
560 auto offer = caller->CreateOfferAndSetAsLocal(options);
561 auto* offer_description =
562 cricket::GetFirstVideoContentDescription(offer->description());
563 for (const auto& codec : offer_description->codecs()) {
564 if (codec.GetCodecType() == cricket::VideoCodec::CODEC_VIDEO) {
565 EXPECT_EQ(codec.packetization, cricket::kPacketizationParamRaw);
566 }
567 }
568
569 auto callee = CreatePeerConnectionWithVideo(std::move(callee_fake_engine));
570 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
571 auto answer = callee->CreateAnswerAndSetAsLocal(options);
572 auto* answer_description =
573 cricket::GetFirstVideoContentDescription(answer->description());
574 for (const auto& codec : answer_description->codecs()) {
575 if (codec.GetCodecType() == cricket::VideoCodec::CODEC_VIDEO) {
576 EXPECT_EQ(codec.packetization, cricket::kPacketizationParamRaw);
577 }
578 }
579
580 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
581}
582
583// Test that raw packetization is not set in the answer when
584// raw_packetization_for_video is true if it was not set in the offer.
585TEST_P(PeerConnectionMediaTest,
586 RawPacketizationNotSetInAnswerWhenNotSetInOffer) {
587 std::vector<cricket::VideoCodec> fake_codecs;
588 fake_codecs.push_back(cricket::VideoCodec(111, cricket::kVp8CodecName));
589 fake_codecs.push_back(cricket::VideoCodec(112, cricket::kRtxCodecName));
590 fake_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "111";
591 fake_codecs.push_back(cricket::VideoCodec(113, cricket::kVp9CodecName));
592 fake_codecs.push_back(cricket::VideoCodec(114, cricket::kH264CodecName));
593 fake_codecs.push_back(cricket::VideoCodec(115, "HEVC"));
Mirko Bonadei317a1f02019-09-17 15:06:18594 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 13:38:50595 caller_fake_engine->SetVideoCodecs(fake_codecs);
Mirko Bonadei317a1f02019-09-17 15:06:18596 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 13:38:50597 callee_fake_engine->SetVideoCodecs(fake_codecs);
598
599 RTCOfferAnswerOptions caller_options;
600 caller_options.raw_packetization_for_video = false;
601 RTCOfferAnswerOptions callee_options;
602 callee_options.raw_packetization_for_video = true;
603
604 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
605 auto offer = caller->CreateOfferAndSetAsLocal(caller_options);
606
607 auto callee = CreatePeerConnectionWithVideo(std::move(callee_fake_engine));
608 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
609 auto answer = callee->CreateAnswerAndSetAsLocal(callee_options);
610
611 auto* answer_description =
612 cricket::GetFirstVideoContentDescription(answer->description());
613 for (const auto& codec : answer_description->codecs()) {
614 EXPECT_EQ(codec.packetization, absl::nullopt);
615 }
616
617 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
618}
619
Steve Anton8d3444d2017-10-20 22:30:51620class PeerConnectionMediaOfferDirectionTest
Steve Antonad7bffc2018-01-22 18:21:56621 : public PeerConnectionMediaBaseTest,
Steve Anton8d3444d2017-10-20 22:30:51622 public ::testing::WithParamInterface<
Steve Antonad7bffc2018-01-22 18:21:56623 std::tuple<SdpSemantics,
624 std::tuple<bool, int, RtpTransceiverDirection>>> {
Steve Anton8d3444d2017-10-20 22:30:51625 protected:
Steve Antonad7bffc2018-01-22 18:21:56626 PeerConnectionMediaOfferDirectionTest()
627 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
628 auto param = std::get<1>(GetParam());
629 send_media_ = std::get<0>(param);
630 offer_to_receive_ = std::get<1>(param);
631 expected_direction_ = std::get<2>(param);
Steve Anton8d3444d2017-10-20 22:30:51632 }
633
634 bool send_media_;
635 int offer_to_receive_;
Steve Anton4e70a722017-11-28 22:57:10636 RtpTransceiverDirection expected_direction_;
Steve Anton8d3444d2017-10-20 22:30:51637};
638
639// Tests that the correct direction is set on the media description according
640// to the presence of a local media track and the offer_to_receive setting.
641TEST_P(PeerConnectionMediaOfferDirectionTest, VerifyDirection) {
642 auto caller = CreatePeerConnection();
643 if (send_media_) {
644 caller->AddAudioTrack("a");
645 }
646
647 RTCOfferAnswerOptions options;
648 options.offer_to_receive_audio = offer_to_receive_;
649 auto offer = caller->CreateOffer(options);
650
Steve Antonad7bffc2018-01-22 18:21:56651 auto* content = cricket::GetFirstMediaContent(offer->description(),
652 cricket::MEDIA_TYPE_AUDIO);
Steve Anton4e70a722017-11-28 22:57:10653 if (expected_direction_ == RtpTransceiverDirection::kInactive) {
Steve Antonad7bffc2018-01-22 18:21:56654 EXPECT_FALSE(content);
Steve Anton8d3444d2017-10-20 22:30:51655 } else {
Steve Antonad7bffc2018-01-22 18:21:56656 EXPECT_EQ(expected_direction_, content->media_description()->direction());
Steve Anton8d3444d2017-10-20 22:30:51657 }
658}
659
660// Note that in these tests, MD_INACTIVE indicates that no media section is
661// included in the offer, not that the media direction is inactive.
Mirko Bonadeic84f6612019-01-31 11:20:57662INSTANTIATE_TEST_SUITE_P(
Steve Anton4e70a722017-11-28 22:57:10663 PeerConnectionMediaTest,
664 PeerConnectionMediaOfferDirectionTest,
Steve Antonad7bffc2018-01-22 18:21:56665 Combine(
666 Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan),
667 Values(std::make_tuple(false, -1, RtpTransceiverDirection::kInactive),
668 std::make_tuple(false, 0, RtpTransceiverDirection::kInactive),
669 std::make_tuple(false, 1, RtpTransceiverDirection::kRecvOnly),
670 std::make_tuple(true, -1, RtpTransceiverDirection::kSendRecv),
671 std::make_tuple(true, 0, RtpTransceiverDirection::kSendOnly),
672 std::make_tuple(true, 1, RtpTransceiverDirection::kSendRecv))));
Steve Anton8d3444d2017-10-20 22:30:51673
674class PeerConnectionMediaAnswerDirectionTest
Steve Antonad7bffc2018-01-22 18:21:56675 : public PeerConnectionMediaBaseTest,
Steve Anton8d3444d2017-10-20 22:30:51676 public ::testing::WithParamInterface<
Steve Antonad7bffc2018-01-22 18:21:56677 std::tuple<SdpSemantics, RtpTransceiverDirection, bool, int>> {
Steve Anton8d3444d2017-10-20 22:30:51678 protected:
Steve Antonad7bffc2018-01-22 18:21:56679 PeerConnectionMediaAnswerDirectionTest()
680 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
681 offer_direction_ = std::get<1>(GetParam());
682 send_media_ = std::get<2>(GetParam());
683 offer_to_receive_ = std::get<3>(GetParam());
Steve Anton8d3444d2017-10-20 22:30:51684 }
685
Steve Anton4e70a722017-11-28 22:57:10686 RtpTransceiverDirection offer_direction_;
Steve Anton8d3444d2017-10-20 22:30:51687 bool send_media_;
688 int offer_to_receive_;
689};
690
691// Tests that the direction in an answer is correct according to direction sent
692// in the offer, the presence of a local media track on the receive side and the
693// offer_to_receive setting.
694TEST_P(PeerConnectionMediaAnswerDirectionTest, VerifyDirection) {
Steve Anton22da89f2018-01-25 21:58:07695 if (IsUnifiedPlan() &&
696 offer_to_receive_ != RTCOfferAnswerOptions::kUndefined) {
697 // offer_to_receive_ is not implemented when creating answers with Unified
698 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 18:21:56699 return;
700 }
Steve Anton22da89f2018-01-25 21:58:07701
Steve Anton8d3444d2017-10-20 22:30:51702 auto caller = CreatePeerConnection();
703 caller->AddAudioTrack("a");
704
705 // Create the offer with an audio section and set its direction.
706 auto offer = caller->CreateOffer();
707 cricket::GetFirstAudioContentDescription(offer->description())
708 ->set_direction(offer_direction_);
709
710 auto callee = CreatePeerConnection();
711 if (send_media_) {
712 callee->AddAudioTrack("a");
713 }
714 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
715
716 // Create the answer according to the test parameters.
717 RTCOfferAnswerOptions options;
718 options.offer_to_receive_audio = offer_to_receive_;
719 auto answer = callee->CreateAnswer(options);
720
721 // The expected direction in the answer is the intersection of each side's
722 // capability to send/recv media.
723 // For the offerer, the direction is given in the offer (offer_direction_).
724 // For the answerer, the direction has two components:
725 // 1. Send if the answerer has a local track to send.
726 // 2. Receive if the answerer has explicitly set the offer_to_receive to 1 or
727 // if it has been left as default.
Steve Anton4e70a722017-11-28 22:57:10728 bool offer_send = RtpTransceiverDirectionHasSend(offer_direction_);
729 bool offer_recv = RtpTransceiverDirectionHasRecv(offer_direction_);
Steve Anton8d3444d2017-10-20 22:30:51730
731 // The negotiated components determine the direction set in the answer.
Steve Anton1d03a752017-11-27 22:30:09732 bool negotiate_send = (send_media_ && offer_recv);
733 bool negotiate_recv = ((offer_to_receive_ != 0) && offer_send);
Steve Anton8d3444d2017-10-20 22:30:51734
735 auto expected_direction =
Steve Anton4e70a722017-11-28 22:57:10736 RtpTransceiverDirectionFromSendRecv(negotiate_send, negotiate_recv);
Steve Anton8d3444d2017-10-20 22:30:51737 EXPECT_EQ(expected_direction,
Steve Antonad7bffc2018-01-22 18:21:56738 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton8d3444d2017-10-20 22:30:51739}
740
741// Tests that the media section is rejected if and only if the callee has no
742// local media track and has set offer_to_receive to 0, no matter which
743// direction the caller indicated in the offer.
744TEST_P(PeerConnectionMediaAnswerDirectionTest, VerifyRejected) {
Steve Anton22da89f2018-01-25 21:58:07745 if (IsUnifiedPlan() &&
746 offer_to_receive_ != RTCOfferAnswerOptions::kUndefined) {
747 // offer_to_receive_ is not implemented when creating answers with Unified
748 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 18:21:56749 return;
750 }
Steve Anton22da89f2018-01-25 21:58:07751
Steve Anton8d3444d2017-10-20 22:30:51752 auto caller = CreatePeerConnection();
753 caller->AddAudioTrack("a");
754
755 // Create the offer with an audio section and set its direction.
756 auto offer = caller->CreateOffer();
757 cricket::GetFirstAudioContentDescription(offer->description())
758 ->set_direction(offer_direction_);
759
760 auto callee = CreatePeerConnection();
761 if (send_media_) {
762 callee->AddAudioTrack("a");
763 }
764 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
765
766 // Create the answer according to the test parameters.
767 RTCOfferAnswerOptions options;
768 options.offer_to_receive_audio = offer_to_receive_;
769 auto answer = callee->CreateAnswer(options);
770
771 // The media section is rejected if and only if offer_to_receive is explicitly
772 // set to 0 and there is no media to send.
773 auto* audio_content = cricket::GetFirstAudioContent(answer->description());
774 ASSERT_TRUE(audio_content);
775 EXPECT_EQ((offer_to_receive_ == 0 && !send_media_), audio_content->rejected);
776}
777
Mirko Bonadeic84f6612019-01-31 11:20:57778INSTANTIATE_TEST_SUITE_P(PeerConnectionMediaTest,
779 PeerConnectionMediaAnswerDirectionTest,
780 Combine(Values(SdpSemantics::kPlanB,
781 SdpSemantics::kUnifiedPlan),
782 Values(RtpTransceiverDirection::kInactive,
783 RtpTransceiverDirection::kSendOnly,
784 RtpTransceiverDirection::kRecvOnly,
785 RtpTransceiverDirection::kSendRecv),
786 Bool(),
787 Values(-1, 0, 1)));
Steve Anton8d3444d2017-10-20 22:30:51788
Steve Antonad7bffc2018-01-22 18:21:56789TEST_P(PeerConnectionMediaTest, OfferHasDifferentDirectionForAudioVideo) {
Steve Anton8d3444d2017-10-20 22:30:51790 auto caller = CreatePeerConnection();
791 caller->AddVideoTrack("v");
792
793 RTCOfferAnswerOptions options;
794 options.offer_to_receive_audio = 1;
795 options.offer_to_receive_video = 0;
796 auto offer = caller->CreateOffer(options);
797
Steve Anton4e70a722017-11-28 22:57:10798 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
Steve Antonad7bffc2018-01-22 18:21:56799 GetMediaContentDirection(offer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton4e70a722017-11-28 22:57:10800 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
Steve Antonad7bffc2018-01-22 18:21:56801 GetMediaContentDirection(offer.get(), cricket::MEDIA_TYPE_VIDEO));
Steve Anton8d3444d2017-10-20 22:30:51802}
803
Steve Antonad7bffc2018-01-22 18:21:56804TEST_P(PeerConnectionMediaTest, AnswerHasDifferentDirectionsForAudioVideo) {
Steve Antonad7bffc2018-01-22 18:21:56805 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 21:58:07806 // offer_to_receive_ is not implemented when creating answers with Unified
807 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 18:21:56808 return;
809 }
810
Steve Anton8d3444d2017-10-20 22:30:51811 auto caller = CreatePeerConnectionWithAudioVideo();
812 auto callee = CreatePeerConnection();
813 callee->AddVideoTrack("v");
814
815 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
816
817 RTCOfferAnswerOptions options;
818 options.offer_to_receive_audio = 1;
819 options.offer_to_receive_video = 0;
820 auto answer = callee->CreateAnswer(options);
821
Steve Anton4e70a722017-11-28 22:57:10822 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
Steve Antonad7bffc2018-01-22 18:21:56823 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton4e70a722017-11-28 22:57:10824 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
Steve Antonad7bffc2018-01-22 18:21:56825 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_VIDEO));
Steve Anton8d3444d2017-10-20 22:30:51826}
827
828void AddComfortNoiseCodecsToSend(cricket::FakeMediaEngine* media_engine) {
Philipp Hancke8498c252020-06-05 11:28:57829 const cricket::AudioCodec kComfortNoiseCodec8k(102, cricket::kCnCodecName,
830 8000, 0, 1);
831 const cricket::AudioCodec kComfortNoiseCodec16k(103, cricket::kCnCodecName,
832 16000, 0, 1);
Steve Anton8d3444d2017-10-20 22:30:51833
Sebastian Jansson6eb8a162018-11-16 10:29:55834 auto codecs = media_engine->voice().send_codecs();
Steve Anton8d3444d2017-10-20 22:30:51835 codecs.push_back(kComfortNoiseCodec8k);
836 codecs.push_back(kComfortNoiseCodec16k);
837 media_engine->SetAudioCodecs(codecs);
838}
839
840bool HasAnyComfortNoiseCodecs(const cricket::SessionDescription* desc) {
841 const auto* audio_desc = cricket::GetFirstAudioContentDescription(desc);
842 for (const auto& codec : audio_desc->codecs()) {
Philipp Hancke8498c252020-06-05 11:28:57843 if (codec.name == cricket::kCnCodecName) {
Steve Anton8d3444d2017-10-20 22:30:51844 return true;
845 }
846 }
847 return false;
848}
849
Taylor Brandstetterf7fcfb72021-09-09 20:39:38850bool HasPayloadTypeConflict(const cricket::SessionDescription* desc) {
851 std::set<int> payload_types;
852 const auto* audio_desc = cricket::GetFirstAudioContentDescription(desc);
853 if (audio_desc) {
854 for (const auto& codec : audio_desc->codecs()) {
855 if (payload_types.count(codec.id) > 0) {
856 return true;
857 }
858 payload_types.insert(codec.id);
859 }
860 }
861 const auto* video_desc = cricket::GetFirstVideoContentDescription(desc);
862 if (video_desc) {
863 for (const auto& codec : video_desc->codecs()) {
864 if (payload_types.count(codec.id) > 0) {
865 return true;
866 }
867 payload_types.insert(codec.id);
868 }
869 }
870 return false;
871}
872
Steve Antonad7bffc2018-01-22 18:21:56873TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 22:30:51874 CreateOfferWithNoVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
Philipp Hancke718acf62021-05-12 12:18:03875 auto fake_engine = std::make_unique<FakeMediaEngine>();
876 AddComfortNoiseCodecsToSend(fake_engine.get());
877 auto caller = CreatePeerConnectionWithAudioVideo(std::move(fake_engine));
Steve Anton8d3444d2017-10-20 22:30:51878
879 RTCOfferAnswerOptions options;
880 options.voice_activity_detection = false;
881 auto offer = caller->CreateOffer(options);
882
883 EXPECT_FALSE(HasAnyComfortNoiseCodecs(offer->description()));
884}
885
Steve Antonad7bffc2018-01-22 18:21:56886TEST_P(PeerConnectionMediaTest,
Philipp Hancke718acf62021-05-12 12:18:03887 CreateOfferWithVoiceActivityDetectionIncludesComfortNoiseCodecs) {
888 auto fake_engine = std::make_unique<FakeMediaEngine>();
889 AddComfortNoiseCodecsToSend(fake_engine.get());
890 auto caller = CreatePeerConnectionWithAudioVideo(std::move(fake_engine));
891
892 RTCOfferAnswerOptions options;
893 options.voice_activity_detection = true;
894 auto offer = caller->CreateOffer(options);
895
896 EXPECT_TRUE(HasAnyComfortNoiseCodecs(offer->description()));
897}
898
899TEST_P(PeerConnectionMediaTest,
900 CreateAnswerWithVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
Steve Anton8d3444d2017-10-20 22:30:51901 auto caller = CreatePeerConnectionWithAudioVideo();
Philipp Hancke718acf62021-05-12 12:18:03902
903 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
904 AddComfortNoiseCodecsToSend(callee_fake_engine.get());
905 auto callee =
906 CreatePeerConnectionWithAudioVideo(std::move(callee_fake_engine));
907
908 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
909
910 RTCOfferAnswerOptions options;
911 options.voice_activity_detection = true;
912 auto answer = callee->CreateAnswer(options);
913
914 EXPECT_FALSE(HasAnyComfortNoiseCodecs(answer->description()));
915}
916
917TEST_P(PeerConnectionMediaTest,
918 CreateAnswerWithNoVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
919 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
920 AddComfortNoiseCodecsToSend(caller_fake_engine.get());
921 auto caller =
922 CreatePeerConnectionWithAudioVideo(std::move(caller_fake_engine));
923
924 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
925 AddComfortNoiseCodecsToSend(callee_fake_engine.get());
926 auto callee =
927 CreatePeerConnectionWithAudioVideo(std::move(callee_fake_engine));
Steve Anton8d3444d2017-10-20 22:30:51928
929 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
930
931 RTCOfferAnswerOptions options;
932 options.voice_activity_detection = false;
933 auto answer = callee->CreateAnswer(options);
934
935 EXPECT_FALSE(HasAnyComfortNoiseCodecs(answer->description()));
936}
937
938// The following test group verifies that we reject answers with invalid media
939// sections as per RFC 3264.
940
941class PeerConnectionMediaInvalidMediaTest
Steve Antonad7bffc2018-01-22 18:21:56942 : public PeerConnectionMediaBaseTest,
943 public ::testing::WithParamInterface<std::tuple<
944 SdpSemantics,
Steve Anton8d3444d2017-10-20 22:30:51945 std::tuple<std::string,
946 std::function<void(cricket::SessionDescription*)>,
Steve Antonad7bffc2018-01-22 18:21:56947 std::string>>> {
Steve Anton8d3444d2017-10-20 22:30:51948 protected:
Steve Antonad7bffc2018-01-22 18:21:56949 PeerConnectionMediaInvalidMediaTest()
950 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
951 auto param = std::get<1>(GetParam());
952 mutator_ = std::get<1>(param);
953 expected_error_ = std::get<2>(param);
Steve Anton8d3444d2017-10-20 22:30:51954 }
955
956 std::function<void(cricket::SessionDescription*)> mutator_;
957 std::string expected_error_;
958};
959
960TEST_P(PeerConnectionMediaInvalidMediaTest, FailToSetRemoteAnswer) {
961 auto caller = CreatePeerConnectionWithAudioVideo();
962 auto callee = CreatePeerConnectionWithAudioVideo();
963
964 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
965
966 auto answer = callee->CreateAnswer();
967 mutator_(answer->description());
968
969 std::string error;
970 ASSERT_FALSE(caller->SetRemoteDescription(std::move(answer), &error));
971 EXPECT_EQ("Failed to set remote answer sdp: " + expected_error_, error);
972}
973
974TEST_P(PeerConnectionMediaInvalidMediaTest, FailToSetLocalAnswer) {
975 auto caller = CreatePeerConnectionWithAudioVideo();
976 auto callee = CreatePeerConnectionWithAudioVideo();
977
978 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
979
980 auto answer = callee->CreateAnswer();
981 mutator_(answer->description());
982
983 std::string error;
984 ASSERT_FALSE(callee->SetLocalDescription(std::move(answer), &error));
985 EXPECT_EQ("Failed to set local answer sdp: " + expected_error_, error);
986}
987
988void RemoveVideoContent(cricket::SessionDescription* desc) {
989 auto content_name = cricket::GetFirstVideoContent(desc)->name;
990 desc->RemoveContentByName(content_name);
991 desc->RemoveTransportInfoByName(content_name);
992}
993
994void RenameVideoContent(cricket::SessionDescription* desc) {
995 auto* video_content = cricket::GetFirstVideoContent(desc);
996 auto* transport_info = desc->GetTransportInfoByName(video_content->name);
997 video_content->name = "video_renamed";
998 transport_info->content_name = video_content->name;
999}
1000
1001void ReverseMediaContent(cricket::SessionDescription* desc) {
Steve Anton64b626b2019-01-29 01:25:261002 absl::c_reverse(desc->contents());
1003 absl::c_reverse(desc->transport_infos());
Steve Anton8d3444d2017-10-20 22:30:511004}
1005
1006void ChangeMediaTypeAudioToVideo(cricket::SessionDescription* desc) {
Steve Antonad7bffc2018-01-22 18:21:561007 std::string audio_mid = cricket::GetFirstAudioContent(desc)->name;
1008 desc->RemoveContentByName(audio_mid);
1009 auto* video_content = cricket::GetFirstVideoContent(desc);
1010 desc->AddContent(audio_mid, video_content->type,
Harald Alvestrand1716d392019-06-03 18:35:451011 video_content->media_description()->Clone());
Steve Anton8d3444d2017-10-20 22:30:511012}
1013
1014constexpr char kMLinesOutOfOrder[] =
1015 "The order of m-lines in answer doesn't match order in offer. Rejecting "
1016 "answer.";
1017
Mirko Bonadeic84f6612019-01-31 11:20:571018INSTANTIATE_TEST_SUITE_P(
Steve Anton8d3444d2017-10-20 22:30:511019 PeerConnectionMediaTest,
1020 PeerConnectionMediaInvalidMediaTest,
Steve Antonad7bffc2018-01-22 18:21:561021 Combine(Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan),
1022 Values(std::make_tuple("remove video",
1023 RemoveVideoContent,
1024 kMLinesOutOfOrder),
1025 std::make_tuple("rename video",
1026 RenameVideoContent,
1027 kMLinesOutOfOrder),
1028 std::make_tuple("reverse media sections",
1029 ReverseMediaContent,
1030 kMLinesOutOfOrder),
1031 std::make_tuple("change audio type to video type",
1032 ChangeMediaTypeAudioToVideo,
1033 kMLinesOutOfOrder))));
Steve Anton8d3444d2017-10-20 22:30:511034
1035// Test that the correct media engine send/recv streams are created when doing
1036// a series of offer/answers where audio/video are both sent, then audio is
1037// rejected, then both audio/video sent again.
Steve Antonad7bffc2018-01-22 18:21:561038TEST_P(PeerConnectionMediaTest, TestAVOfferWithAudioOnlyAnswer) {
Steve Antonad7bffc2018-01-22 18:21:561039 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 21:58:071040 // offer_to_receive_ is not implemented when creating answers with Unified
1041 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 18:21:561042 return;
1043 }
1044
Steve Anton8d3444d2017-10-20 22:30:511045 RTCOfferAnswerOptions options_reject_video;
1046 options_reject_video.offer_to_receive_audio =
1047 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
1048 options_reject_video.offer_to_receive_video = 0;
1049
1050 auto caller = CreatePeerConnection();
1051 caller->AddAudioTrack("a");
1052 caller->AddVideoTrack("v");
1053 auto callee = CreatePeerConnection();
1054
1055 // Caller initially offers to send/recv audio and video.
1056 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1057 // Callee accepts the audio as recv only but rejects the video.
1058 ASSERT_TRUE(caller->SetRemoteDescription(
1059 callee->CreateAnswerAndSetAsLocal(options_reject_video)));
1060
1061 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1062 ASSERT_TRUE(caller_voice);
1063 EXPECT_EQ(0u, caller_voice->recv_streams().size());
1064 EXPECT_EQ(1u, caller_voice->send_streams().size());
1065 auto caller_video = caller->media_engine()->GetVideoChannel(0);
1066 EXPECT_FALSE(caller_video);
1067
1068 // Callee adds its own audio/video stream and offers to receive audio/video
1069 // too.
1070 callee->AddAudioTrack("a");
1071 auto callee_video_track = callee->AddVideoTrack("v");
1072 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1073 ASSERT_TRUE(
1074 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1075
1076 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1077 ASSERT_TRUE(callee_voice);
1078 EXPECT_EQ(1u, callee_voice->recv_streams().size());
1079 EXPECT_EQ(1u, callee_voice->send_streams().size());
1080 auto callee_video = callee->media_engine()->GetVideoChannel(0);
1081 ASSERT_TRUE(callee_video);
1082 EXPECT_EQ(1u, callee_video->recv_streams().size());
1083 EXPECT_EQ(1u, callee_video->send_streams().size());
1084
1085 // Callee removes video but keeps audio and rejects the video once again.
1086 callee->pc()->RemoveTrack(callee_video_track);
1087 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1088 ASSERT_TRUE(
1089 callee->SetLocalDescription(callee->CreateAnswer(options_reject_video)));
1090
1091 callee_voice = callee->media_engine()->GetVoiceChannel(0);
1092 ASSERT_TRUE(callee_voice);
1093 EXPECT_EQ(1u, callee_voice->recv_streams().size());
1094 EXPECT_EQ(1u, callee_voice->send_streams().size());
1095 callee_video = callee->media_engine()->GetVideoChannel(0);
1096 EXPECT_FALSE(callee_video);
1097}
1098
1099// Test that the correct media engine send/recv streams are created when doing
1100// a series of offer/answers where audio/video are both sent, then video is
1101// rejected, then both audio/video sent again.
Steve Antonad7bffc2018-01-22 18:21:561102TEST_P(PeerConnectionMediaTest, TestAVOfferWithVideoOnlyAnswer) {
Steve Antonad7bffc2018-01-22 18:21:561103 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 21:58:071104 // offer_to_receive_ is not implemented when creating answers with Unified
1105 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 18:21:561106 return;
1107 }
1108
Steve Anton8d3444d2017-10-20 22:30:511109 // Disable the bundling here. If the media is bundled on audio
1110 // transport, then we can't reject the audio because switching the bundled
1111 // transport is not currently supported.
1112 // (https://bugs.chromium.org/p/webrtc/issues/detail?id=6704)
1113 RTCOfferAnswerOptions options_no_bundle;
1114 options_no_bundle.use_rtp_mux = false;
1115 RTCOfferAnswerOptions options_reject_audio = options_no_bundle;
1116 options_reject_audio.offer_to_receive_audio = 0;
1117 options_reject_audio.offer_to_receive_video =
1118 RTCOfferAnswerOptions::kMaxOfferToReceiveMedia;
1119
1120 auto caller = CreatePeerConnection();
1121 caller->AddAudioTrack("a");
1122 caller->AddVideoTrack("v");
1123 auto callee = CreatePeerConnection();
1124
1125 // Caller initially offers to send/recv audio and video.
1126 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1127 // Callee accepts the video as recv only but rejects the audio.
1128 ASSERT_TRUE(caller->SetRemoteDescription(
1129 callee->CreateAnswerAndSetAsLocal(options_reject_audio)));
1130
1131 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1132 EXPECT_FALSE(caller_voice);
1133 auto caller_video = caller->media_engine()->GetVideoChannel(0);
1134 ASSERT_TRUE(caller_video);
1135 EXPECT_EQ(0u, caller_video->recv_streams().size());
1136 EXPECT_EQ(1u, caller_video->send_streams().size());
1137
1138 // Callee adds its own audio/video stream and offers to receive audio/video
1139 // too.
1140 auto callee_audio_track = callee->AddAudioTrack("a");
1141 callee->AddVideoTrack("v");
1142 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1143 ASSERT_TRUE(caller->SetRemoteDescription(
1144 callee->CreateAnswerAndSetAsLocal(options_no_bundle)));
1145
1146 auto callee_voice = callee->media_engine()->GetVoiceChannel(0);
1147 ASSERT_TRUE(callee_voice);
1148 EXPECT_EQ(1u, callee_voice->recv_streams().size());
1149 EXPECT_EQ(1u, callee_voice->send_streams().size());
1150 auto callee_video = callee->media_engine()->GetVideoChannel(0);
1151 ASSERT_TRUE(callee_video);
1152 EXPECT_EQ(1u, callee_video->recv_streams().size());
1153 EXPECT_EQ(1u, callee_video->send_streams().size());
1154
1155 // Callee removes audio but keeps video and rejects the audio once again.
1156 callee->pc()->RemoveTrack(callee_audio_track);
1157 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1158 ASSERT_TRUE(
1159 callee->SetLocalDescription(callee->CreateAnswer(options_reject_audio)));
1160
1161 callee_voice = callee->media_engine()->GetVoiceChannel(0);
1162 EXPECT_FALSE(callee_voice);
1163 callee_video = callee->media_engine()->GetVideoChannel(0);
1164 ASSERT_TRUE(callee_video);
1165 EXPECT_EQ(1u, callee_video->recv_streams().size());
1166 EXPECT_EQ(1u, callee_video->send_streams().size());
1167}
1168
1169// Tests that if the underlying video encoder fails to be initialized (signaled
1170// by failing to set send codecs), the PeerConnection signals the error to the
1171// client.
Steve Antonad7bffc2018-01-22 18:21:561172TEST_P(PeerConnectionMediaTest, MediaEngineErrorPropagatedToClients) {
Steve Anton8d3444d2017-10-20 22:30:511173 auto caller = CreatePeerConnectionWithAudioVideo();
1174 auto callee = CreatePeerConnectionWithAudioVideo();
1175
1176 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1177
1178 auto video_channel = caller->media_engine()->GetVideoChannel(0);
1179 video_channel->set_fail_set_send_codecs(true);
1180
1181 std::string error;
1182 ASSERT_FALSE(caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(),
1183 &error));
Yura Yaroshevichbc1f9102020-06-03 21:15:221184 EXPECT_EQ(std::string("Failed to set remote answer sdp: Failed to set remote "
1185 "video description "
1186 "send parameters for m-section with mid='") +
1187 (IsUnifiedPlan() ? "1" : "video") + "'.",
1188 error);
Steve Anton8d3444d2017-10-20 22:30:511189}
1190
1191// Tests that if the underlying video encoder fails once then subsequent
1192// attempts at setting the local/remote description will also fail, even if
1193// SetSendCodecs no longer fails.
Steve Antonad7bffc2018-01-22 18:21:561194TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 22:30:511195 FailToApplyDescriptionIfVideoEncoderHasEverFailed) {
1196 auto caller = CreatePeerConnectionWithAudioVideo();
1197 auto callee = CreatePeerConnectionWithAudioVideo();
1198
1199 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1200
1201 auto video_channel = caller->media_engine()->GetVideoChannel(0);
1202 video_channel->set_fail_set_send_codecs(true);
1203
1204 EXPECT_FALSE(
1205 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1206
1207 video_channel->set_fail_set_send_codecs(false);
1208
1209 EXPECT_FALSE(caller->SetRemoteDescription(callee->CreateAnswer()));
1210 EXPECT_FALSE(caller->SetLocalDescription(caller->CreateOffer()));
1211}
1212
1213void RenameContent(cricket::SessionDescription* desc,
Steve Antonad7bffc2018-01-22 18:21:561214 cricket::MediaType media_type,
Steve Anton8d3444d2017-10-20 22:30:511215 const std::string& new_name) {
Steve Antonad7bffc2018-01-22 18:21:561216 auto* content = cricket::GetFirstMediaContent(desc, media_type);
Steve Anton8d3444d2017-10-20 22:30:511217 RTC_DCHECK(content);
Steve Antonad7bffc2018-01-22 18:21:561218 std::string old_name = content->name;
Steve Anton8d3444d2017-10-20 22:30:511219 content->name = new_name;
1220 auto* transport = desc->GetTransportInfoByName(old_name);
1221 RTC_DCHECK(transport);
1222 transport->content_name = new_name;
Zhi Huangd2248f82018-04-10 21:41:031223
1224 // Rename the content name in the BUNDLE group.
1225 cricket::ContentGroup new_bundle_group =
1226 *desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1227 new_bundle_group.RemoveContentName(old_name);
1228 new_bundle_group.AddContentName(new_name);
1229 desc->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1230 desc->AddGroup(new_bundle_group);
Steve Anton8d3444d2017-10-20 22:30:511231}
1232
1233// Tests that an answer responds with the same MIDs as the offer.
Steve Antonad7bffc2018-01-22 18:21:561234TEST_P(PeerConnectionMediaTest, AnswerHasSameMidsAsOffer) {
Zhi Huang365381f2018-04-13 23:44:341235 const std::string kAudioMid = "notdefault1";
1236 const std::string kVideoMid = "notdefault2";
Steve Anton8d3444d2017-10-20 22:30:511237
1238 auto caller = CreatePeerConnectionWithAudioVideo();
1239 auto callee = CreatePeerConnectionWithAudioVideo();
1240
1241 auto offer = caller->CreateOffer();
Steve Antonad7bffc2018-01-22 18:21:561242 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, kAudioMid);
1243 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, kVideoMid);
Steve Anton8d3444d2017-10-20 22:30:511244 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1245
1246 auto answer = callee->CreateAnswer();
1247 EXPECT_EQ(kAudioMid,
1248 cricket::GetFirstAudioContent(answer->description())->name);
1249 EXPECT_EQ(kVideoMid,
1250 cricket::GetFirstVideoContent(answer->description())->name);
1251}
1252
1253// Test that if the callee creates a re-offer, the MIDs are the same as the
1254// original offer.
Steve Antonad7bffc2018-01-22 18:21:561255TEST_P(PeerConnectionMediaTest, ReOfferHasSameMidsAsFirstOffer) {
Zhi Huang365381f2018-04-13 23:44:341256 const std::string kAudioMid = "notdefault1";
1257 const std::string kVideoMid = "notdefault2";
Steve Anton8d3444d2017-10-20 22:30:511258
1259 auto caller = CreatePeerConnectionWithAudioVideo();
1260 auto callee = CreatePeerConnectionWithAudioVideo();
1261
1262 auto offer = caller->CreateOffer();
Steve Antonad7bffc2018-01-22 18:21:561263 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, kAudioMid);
1264 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, kVideoMid);
Steve Anton8d3444d2017-10-20 22:30:511265 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1266 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1267
1268 auto reoffer = callee->CreateOffer();
1269 EXPECT_EQ(kAudioMid,
1270 cricket::GetFirstAudioContent(reoffer->description())->name);
1271 EXPECT_EQ(kVideoMid,
1272 cricket::GetFirstVideoContent(reoffer->description())->name);
1273}
1274
Steve Anton06817cd2018-12-18 23:55:301275// Test that SetRemoteDescription returns an error if there are two m= sections
1276// with the same MID value.
1277TEST_P(PeerConnectionMediaTest, SetRemoteDescriptionFailsWithDuplicateMids) {
1278 auto caller = CreatePeerConnectionWithAudioVideo();
1279 auto callee = CreatePeerConnectionWithAudioVideo();
1280
1281 auto offer = caller->CreateOffer();
1282 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, "same");
1283 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, "same");
1284
1285 std::string error;
1286 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer), &error));
1287 EXPECT_EQ(error,
1288 "Failed to set remote offer sdp: Duplicate a=mid value 'same'.");
1289}
1290
Steve Antonad7bffc2018-01-22 18:21:561291TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 22:30:511292 CombinedAudioVideoBweConfigPropagatedToMediaEngine) {
1293 RTCConfiguration config;
1294 config.combined_audio_video_bwe.emplace(true);
1295 auto caller = CreatePeerConnectionWithAudioVideo(config);
1296
1297 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
1298
1299 auto caller_voice = caller->media_engine()->GetVoiceChannel(0);
1300 ASSERT_TRUE(caller_voice);
1301 const cricket::AudioOptions& audio_options = caller_voice->options();
1302 EXPECT_EQ(config.combined_audio_video_bwe,
1303 audio_options.combined_audio_video_bwe);
1304}
1305
Philipp Hancke7145a142021-09-28 05:46:061306// Test that if a RED codec refers to another codec in its fmtp line, but that
1307// codec's payload type was reassigned for some reason (either the remote
1308// endpoint selected a different payload type or there was a conflict), the RED
1309// fmtp line is modified to refer to the correct payload type.
1310TEST_P(PeerConnectionMediaTest, RedFmtpPayloadTypeReassigned) {
1311 std::vector<cricket::AudioCodec> caller_fake_codecs;
1312 caller_fake_codecs.push_back(cricket::AudioCodec(100, "foo", 0, 0, 1));
1313 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
1314 caller_fake_engine->SetAudioCodecs(caller_fake_codecs);
1315 auto caller = CreatePeerConnectionWithAudio(std::move(caller_fake_engine));
1316
1317 std::vector<cricket::AudioCodec> callee_fake_codecs;
1318 callee_fake_codecs.push_back(cricket::AudioCodec(120, "foo", 0, 0, 1));
1319 callee_fake_codecs.push_back(
1320 cricket::AudioCodec(121, cricket::kRedCodecName, 0, 0, 1));
1321 callee_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1322 "120/120");
1323 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
1324 callee_fake_engine->SetAudioCodecs(callee_fake_codecs);
1325 auto callee = CreatePeerConnectionWithAudio(std::move(callee_fake_engine));
1326
1327 // Offer from the caller establishes 100 as the "foo" payload type.
1328 auto offer = caller->CreateOfferAndSetAsLocal();
1329 callee->SetRemoteDescription(std::move(offer));
1330 auto answer = callee->CreateAnswerAndSetAsLocal();
1331 auto answer_description =
1332 cricket::GetFirstAudioContentDescription(answer->description());
1333 ASSERT_EQ(1u, answer_description->codecs().size());
1334
1335 // Offer from the callee should respect the established payload type, and
1336 // attempt to add RED, which should refer to the correct payload type.
1337 offer = callee->CreateOfferAndSetAsLocal();
1338 auto* offer_description =
1339 cricket::GetFirstAudioContentDescription(offer->description());
1340 ASSERT_EQ(2u, offer_description->codecs().size());
1341 for (const auto& codec : offer_description->codecs()) {
1342 if (codec.name == "foo") {
1343 ASSERT_EQ(100, codec.id);
1344 } else if (codec.name == cricket::kRedCodecName) {
1345 std::string fmtp;
1346 ASSERT_TRUE(codec.GetParam("", &fmtp));
1347 EXPECT_EQ("100/100", fmtp);
1348 }
1349 }
1350}
1351
1352// Test that RED without fmtp does match RED without fmtp.
1353TEST_P(PeerConnectionMediaTest, RedFmtpPayloadTypeNoFmtpMatchNoFmtp) {
1354 std::vector<cricket::AudioCodec> caller_fake_codecs;
1355 caller_fake_codecs.push_back(cricket::AudioCodec(100, "foo", 0, 0, 1));
1356 caller_fake_codecs.push_back(
1357 cricket::AudioCodec(101, cricket::kRedCodecName, 0, 0, 1));
1358 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
1359 caller_fake_engine->SetAudioCodecs(caller_fake_codecs);
1360 auto caller = CreatePeerConnectionWithAudio(std::move(caller_fake_engine));
1361
1362 std::vector<cricket::AudioCodec> callee_fake_codecs;
1363 callee_fake_codecs.push_back(cricket::AudioCodec(120, "foo", 0, 0, 1));
1364 callee_fake_codecs.push_back(
1365 cricket::AudioCodec(121, cricket::kRedCodecName, 0, 0, 1));
1366 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
1367 callee_fake_engine->SetAudioCodecs(callee_fake_codecs);
1368 auto callee = CreatePeerConnectionWithAudio(std::move(callee_fake_engine));
1369
1370 // Offer from the caller establishes 100 as the "foo" payload type.
1371 // Red (without fmtp) is negotiated.
1372 auto offer = caller->CreateOfferAndSetAsLocal();
1373 callee->SetRemoteDescription(std::move(offer));
1374 auto answer = callee->CreateAnswerAndSetAsLocal();
1375 auto answer_description =
1376 cricket::GetFirstAudioContentDescription(answer->description());
1377 ASSERT_EQ(2u, answer_description->codecs().size());
1378
1379 // Offer from the callee should respect the established payload type, and
1380 // attempt to add RED.
1381 offer = callee->CreateOfferAndSetAsLocal();
1382 auto* offer_description =
1383 cricket::GetFirstAudioContentDescription(offer->description());
1384 ASSERT_EQ(2u, offer_description->codecs().size());
1385 for (const auto& codec : offer_description->codecs()) {
1386 if (codec.name == "foo") {
1387 ASSERT_EQ(100, codec.id);
1388 } else if (codec.name == cricket::kRedCodecName) {
1389 ASSERT_EQ(101, codec.id);
1390 }
1391 }
1392}
1393
1394// Test that RED without fmtp does not match RED with fmtp.
1395TEST_P(PeerConnectionMediaTest, RedFmtpPayloadTypeNoFmtpNoMatchFmtp) {
1396 std::vector<cricket::AudioCodec> caller_fake_codecs;
1397 caller_fake_codecs.push_back(cricket::AudioCodec(100, "foo", 0, 0, 1));
1398 caller_fake_codecs.push_back(
1399 cricket::AudioCodec(101, cricket::kRedCodecName, 0, 0, 1));
1400 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
1401 caller_fake_engine->SetAudioCodecs(caller_fake_codecs);
1402 auto caller = CreatePeerConnectionWithAudio(std::move(caller_fake_engine));
1403
1404 std::vector<cricket::AudioCodec> callee_fake_codecs;
1405 callee_fake_codecs.push_back(cricket::AudioCodec(120, "foo", 0, 0, 1));
1406 callee_fake_codecs.push_back(
1407 cricket::AudioCodec(121, cricket::kRedCodecName, 0, 0, 1));
1408 callee_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1409 "120/120");
1410 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
1411 callee_fake_engine->SetAudioCodecs(callee_fake_codecs);
1412 auto callee = CreatePeerConnectionWithAudio(std::move(callee_fake_engine));
1413
1414 // Offer from the caller establishes 100 as the "foo" payload type.
1415 // It should not negotiate RED.
1416 auto offer = caller->CreateOfferAndSetAsLocal();
1417 callee->SetRemoteDescription(std::move(offer));
1418 auto answer = callee->CreateAnswerAndSetAsLocal();
1419 auto answer_description =
1420 cricket::GetFirstAudioContentDescription(answer->description());
1421 ASSERT_EQ(1u, answer_description->codecs().size());
1422
1423 // Offer from the callee should respect the established payload type, and
1424 // attempt to add RED, which should refer to the correct payload type.
1425 offer = callee->CreateOfferAndSetAsLocal();
1426 auto* offer_description =
1427 cricket::GetFirstAudioContentDescription(offer->description());
1428 ASSERT_EQ(2u, offer_description->codecs().size());
1429 for (const auto& codec : offer_description->codecs()) {
1430 if (codec.name == "foo") {
1431 ASSERT_EQ(100, codec.id);
1432 } else if (codec.name == cricket::kRedCodecName) {
1433 std::string fmtp;
1434 ASSERT_TRUE(
1435 codec.GetParam(cricket::kCodecParamNotInNameValueFormat, &fmtp));
1436 EXPECT_EQ("100/100", fmtp);
1437 }
1438 }
1439}
1440
1441// Test that RED with fmtp must match base codecs.
1442TEST_P(PeerConnectionMediaTest, RedFmtpPayloadTypeMustMatchBaseCodecs) {
1443 std::vector<cricket::AudioCodec> caller_fake_codecs;
1444 caller_fake_codecs.push_back(cricket::AudioCodec(100, "foo", 0, 0, 1));
1445 caller_fake_codecs.push_back(
1446 cricket::AudioCodec(101, cricket::kRedCodecName, 0, 0, 1));
1447 caller_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1448 "100/100");
1449 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
1450 caller_fake_engine->SetAudioCodecs(caller_fake_codecs);
1451 auto caller = CreatePeerConnectionWithAudio(std::move(caller_fake_engine));
1452
1453 std::vector<cricket::AudioCodec> callee_fake_codecs;
1454 callee_fake_codecs.push_back(cricket::AudioCodec(120, "foo", 0, 0, 1));
1455 callee_fake_codecs.push_back(
1456 cricket::AudioCodec(121, cricket::kRedCodecName, 0, 0, 1));
1457 callee_fake_codecs.push_back(cricket::AudioCodec(122, "bar", 0, 0, 1));
1458 callee_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1459 "122/122");
1460 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
1461 callee_fake_engine->SetAudioCodecs(callee_fake_codecs);
1462 auto callee = CreatePeerConnectionWithAudio(std::move(callee_fake_engine));
1463
1464 // Offer from the caller establishes 100 as the "foo" payload type.
1465 // It should not negotiate RED since RED is associated with foo, not bar.
1466 auto offer = caller->CreateOfferAndSetAsLocal();
1467 callee->SetRemoteDescription(std::move(offer));
1468 auto answer = callee->CreateAnswerAndSetAsLocal();
1469 auto answer_description =
1470 cricket::GetFirstAudioContentDescription(answer->description());
1471 ASSERT_EQ(1u, answer_description->codecs().size());
1472}
1473
1474// Test behaviour when the RED fmtp attempts to specify different codecs
1475// which is not supported.
1476TEST_P(PeerConnectionMediaTest, RedFmtpPayloadMixed) {
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(cricket::AudioCodec(102, "bar", 0, 0, 1));
1480 caller_fake_codecs.push_back(
1481 cricket::AudioCodec(101, cricket::kRedCodecName, 0, 0, 1));
1482 caller_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1483 "100/102");
1484 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
1485 caller_fake_engine->SetAudioCodecs(caller_fake_codecs);
1486 auto caller = CreatePeerConnectionWithAudio(std::move(caller_fake_engine));
1487
1488 std::vector<cricket::AudioCodec> callee_fake_codecs;
1489 callee_fake_codecs.push_back(cricket::AudioCodec(120, "foo", 0, 0, 1));
1490 callee_fake_codecs.push_back(
1491 cricket::AudioCodec(121, cricket::kRedCodecName, 0, 0, 1));
1492 callee_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1493 "120/120");
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 auto offer = caller->CreateOfferAndSetAsLocal();
1500 callee->SetRemoteDescription(std::move(offer));
1501 auto answer = callee->CreateAnswerAndSetAsLocal();
1502 auto answer_description =
1503 cricket::GetFirstAudioContentDescription(answer->description());
1504 // RED is not negotiated.
1505 ASSERT_EQ(1u, answer_description->codecs().size());
1506}
1507
1508// Test behaviour when the RED fmtp attempts to negotiate different levels of
1509// redundancy.
1510TEST_P(PeerConnectionMediaTest, RedFmtpPayloadDifferentRedundancy) {
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(
1514 cricket::AudioCodec(101, cricket::kRedCodecName, 0, 0, 1));
1515 caller_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1516 "100/100");
1517 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
1518 caller_fake_engine->SetAudioCodecs(caller_fake_codecs);
1519 auto caller = CreatePeerConnectionWithAudio(std::move(caller_fake_engine));
1520
1521 std::vector<cricket::AudioCodec> callee_fake_codecs;
1522 callee_fake_codecs.push_back(cricket::AudioCodec(120, "foo", 0, 0, 1));
1523 callee_fake_codecs.push_back(
1524 cricket::AudioCodec(121, cricket::kRedCodecName, 0, 0, 1));
1525 callee_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1526 "120/120/120");
1527 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
1528 callee_fake_engine->SetAudioCodecs(callee_fake_codecs);
1529 auto callee = CreatePeerConnectionWithAudio(std::move(callee_fake_engine));
1530
1531 // Offer from the caller establishes 100 as the "foo" payload type.
1532 auto offer = caller->CreateOfferAndSetAsLocal();
1533 callee->SetRemoteDescription(std::move(offer));
1534 auto answer = callee->CreateAnswerAndSetAsLocal();
1535 auto answer_description =
1536 cricket::GetFirstAudioContentDescription(answer->description());
1537 // RED is negotiated.
1538 ASSERT_EQ(2u, answer_description->codecs().size());
1539
1540 // Offer from the callee should respect the established payload type, and
1541 // attempt to add RED, which should refer to the correct payload type.
1542 offer = callee->CreateOfferAndSetAsLocal();
1543 auto* offer_description =
1544 cricket::GetFirstAudioContentDescription(offer->description());
1545 ASSERT_EQ(2u, offer_description->codecs().size());
1546 for (const auto& codec : offer_description->codecs()) {
1547 if (codec.name == "foo") {
1548 ASSERT_EQ(100, codec.id);
1549 } else if (codec.name == cricket::kRedCodecName) {
1550 std::string fmtp;
1551 ASSERT_TRUE(
1552 codec.GetParam(cricket::kCodecParamNotInNameValueFormat, &fmtp));
1553 EXPECT_EQ("100/100", fmtp);
1554 }
1555 }
1556}
1557
Florent Castelli2d9d82e2019-04-23 17:25:511558template <typename C>
1559bool CompareCodecs(const std::vector<webrtc::RtpCodecCapability>& capabilities,
1560 const std::vector<C>& codecs) {
1561 bool capability_has_rtx =
1562 absl::c_any_of(capabilities, [](const webrtc::RtpCodecCapability& codec) {
1563 return codec.name == cricket::kRtxCodecName;
1564 });
1565 bool codecs_has_rtx = absl::c_any_of(codecs, [](const C& codec) {
1566 return codec.name == cricket::kRtxCodecName;
1567 });
1568
1569 std::vector<C> codecs_no_rtx;
1570 absl::c_copy_if(
1571 codecs, std::back_inserter(codecs_no_rtx),
1572 [](const C& codec) { return codec.name != cricket::kRtxCodecName; });
1573
1574 std::vector<webrtc::RtpCodecCapability> capabilities_no_rtx;
1575 absl::c_copy_if(capabilities, std::back_inserter(capabilities_no_rtx),
1576 [](const webrtc::RtpCodecCapability& codec) {
1577 return codec.name != cricket::kRtxCodecName;
1578 });
1579
1580 return capability_has_rtx == codecs_has_rtx &&
1581 absl::c_equal(
1582 capabilities_no_rtx, codecs_no_rtx,
1583 [](const webrtc::RtpCodecCapability& capability, const C& codec) {
1584 return codec.MatchesCapability(capability);
1585 });
1586}
1587
1588TEST_F(PeerConnectionMediaTestUnifiedPlan,
1589 SetCodecPreferencesAudioMissingRecvCodec) {
Mirko Bonadei317a1f02019-09-17 15:06:181590 auto fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 17:25:511591 auto send_codecs = fake_engine->voice().send_codecs();
1592 send_codecs.push_back(cricket::AudioCodec(send_codecs.back().id + 1,
1593 "send_only_codec", 0, 0, 1));
1594 fake_engine->SetAudioSendCodecs(send_codecs);
1595
1596 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
1597
1598 auto transceiver = caller->pc()->GetTransceivers().front();
1599 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
1600 cricket::MediaType::MEDIA_TYPE_AUDIO);
1601
1602 std::vector<webrtc::RtpCodecCapability> codecs;
1603 absl::c_copy_if(capabilities.codecs, std::back_inserter(codecs),
1604 [](const webrtc::RtpCodecCapability& codec) {
1605 return codec.name.find("_only_") != std::string::npos;
1606 });
1607
1608 auto result = transceiver->SetCodecPreferences(codecs);
1609 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1610}
1611
1612TEST_F(PeerConnectionMediaTestUnifiedPlan,
1613 SetCodecPreferencesAudioMissingSendCodec) {
Mirko Bonadei317a1f02019-09-17 15:06:181614 auto fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 17:25:511615 auto recv_codecs = fake_engine->voice().recv_codecs();
1616 recv_codecs.push_back(cricket::AudioCodec(recv_codecs.back().id + 1,
1617 "recv_only_codec", 0, 0, 1));
1618 fake_engine->SetAudioRecvCodecs(recv_codecs);
1619 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
1620
1621 auto transceiver = caller->pc()->GetTransceivers().front();
1622 auto capabilities = caller->pc_factory()->GetRtpReceiverCapabilities(
1623 cricket::MediaType::MEDIA_TYPE_AUDIO);
1624
1625 std::vector<webrtc::RtpCodecCapability> codecs;
1626 absl::c_copy_if(capabilities.codecs, std::back_inserter(codecs),
1627 [](const webrtc::RtpCodecCapability& codec) {
1628 return codec.name.find("_only_") != std::string::npos;
1629 });
1630
1631 auto result = transceiver->SetCodecPreferences(codecs);
1632 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1633}
1634
1635TEST_F(PeerConnectionMediaTestUnifiedPlan,
1636 SetCodecPreferencesAudioRejectsVideoCodec) {
1637 auto caller = CreatePeerConnectionWithAudio();
1638
1639 auto transceiver = caller->pc()->GetTransceivers().front();
1640 auto video_codecs =
1641 caller->pc_factory()
1642 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)
1643 .codecs;
1644 auto codecs =
1645 caller->pc_factory()
1646 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)
1647 .codecs;
1648 codecs.insert(codecs.end(), video_codecs.begin(), video_codecs.end());
1649 auto result = transceiver->SetCodecPreferences(codecs);
1650 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1651}
1652
1653TEST_F(PeerConnectionMediaTestUnifiedPlan,
1654 SetCodecPreferencesAudioRejectsOnlyRtxRedFec) {
Mirko Bonadei317a1f02019-09-17 15:06:181655 auto fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 17:25:511656 auto audio_codecs = fake_engine->voice().send_codecs();
1657 audio_codecs.push_back(cricket::AudioCodec(audio_codecs.back().id + 1,
1658 cricket::kRtxCodecName, 0, 0, 1));
1659 audio_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1660 std::to_string(audio_codecs.back().id - 1);
1661 audio_codecs.push_back(cricket::AudioCodec(audio_codecs.back().id + 1,
1662 cricket::kRedCodecName, 0, 0, 1));
1663 audio_codecs.push_back(cricket::AudioCodec(
1664 audio_codecs.back().id + 1, cricket::kUlpfecCodecName, 0, 0, 1));
1665 fake_engine->SetAudioCodecs(audio_codecs);
1666
1667 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
1668
1669 auto transceiver = caller->pc()->GetTransceivers().front();
1670 auto codecs =
1671 caller->pc_factory()
1672 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)
1673 .codecs;
1674 auto codecs_only_rtx_red_fec = codecs;
1675 auto it = std::remove_if(codecs_only_rtx_red_fec.begin(),
1676 codecs_only_rtx_red_fec.end(),
1677 [](const webrtc::RtpCodecCapability& codec) {
1678 return !(codec.name == cricket::kRtxCodecName ||
1679 codec.name == cricket::kRedCodecName ||
1680 codec.name == cricket::kUlpfecCodecName);
1681 });
1682 codecs_only_rtx_red_fec.erase(it, codecs_only_rtx_red_fec.end());
1683
1684 auto result = transceiver->SetCodecPreferences(codecs_only_rtx_red_fec);
1685 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1686}
1687
1688TEST_F(PeerConnectionMediaTestUnifiedPlan, SetCodecPreferencesAllAudioCodecs) {
1689 auto caller = CreatePeerConnectionWithAudio();
1690
1691 auto sender_audio_codecs =
1692 caller->pc_factory()
1693 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_AUDIO)
1694 .codecs;
1695
1696 auto audio_transceiver = caller->pc()->GetTransceivers().front();
1697
1698 // Normal case, set all capabilities as preferences
1699 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(sender_audio_codecs).ok());
1700 auto offer = caller->CreateOffer();
1701 auto codecs = offer->description()
1702 ->contents()[0]
1703 .media_description()
1704 ->as_audio()
1705 ->codecs();
1706 EXPECT_TRUE(CompareCodecs(sender_audio_codecs, codecs));
1707}
1708
1709TEST_F(PeerConnectionMediaTestUnifiedPlan,
1710 SetCodecPreferencesResetAudioCodecs) {
1711 auto caller = CreatePeerConnectionWithAudio();
1712
1713 auto sender_audio_codecs =
1714 caller->pc_factory()
1715 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_AUDIO)
1716 .codecs;
1717 std::vector<webrtc::RtpCodecCapability> empty_codecs = {};
1718
1719 auto audio_transceiver = caller->pc()->GetTransceivers().front();
1720
1721 // Normal case, reset codec preferences
1722 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(empty_codecs).ok());
1723 auto offer = caller->CreateOffer();
1724 auto codecs = offer->description()
1725 ->contents()[0]
1726 .media_description()
1727 ->as_audio()
1728 ->codecs();
1729 EXPECT_TRUE(CompareCodecs(sender_audio_codecs, codecs));
1730}
1731
1732TEST_F(PeerConnectionMediaTestUnifiedPlan,
1733 SetCodecPreferencesVideoRejectsAudioCodec) {
1734 auto caller = CreatePeerConnectionWithVideo();
1735
1736 auto transceiver = caller->pc()->GetTransceivers().front();
1737 auto audio_codecs =
1738 caller->pc_factory()
1739 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)
1740 .codecs;
1741 auto codecs =
1742 caller->pc_factory()
1743 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)
1744 .codecs;
1745 codecs.insert(codecs.end(), audio_codecs.begin(), audio_codecs.end());
1746 auto result = transceiver->SetCodecPreferences(codecs);
1747 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1748}
1749
1750TEST_F(PeerConnectionMediaTestUnifiedPlan,
1751 SetCodecPreferencesVideoRejectsOnlyRtxRedFec) {
Mirko Bonadei317a1f02019-09-17 15:06:181752 auto fake_engine = std::make_unique<FakeMediaEngine>();
Johannes Kron3e983682020-03-29 20:17:001753 auto video_codecs = fake_engine->video().send_codecs();
Florent Castelli2d9d82e2019-04-23 17:25:511754 video_codecs.push_back(
1755 cricket::VideoCodec(video_codecs.back().id + 1, cricket::kRtxCodecName));
Johannes Kron3e983682020-03-29 20:17:001756 video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1757 std::to_string(video_codecs.back().id - 1);
Florent Castelli2d9d82e2019-04-23 17:25:511758 video_codecs.push_back(
1759 cricket::VideoCodec(video_codecs.back().id + 1, cricket::kRedCodecName));
1760 video_codecs.push_back(cricket::VideoCodec(video_codecs.back().id + 1,
1761 cricket::kUlpfecCodecName));
1762 fake_engine->SetVideoCodecs(video_codecs);
1763
1764 auto caller = CreatePeerConnectionWithVideo(std::move(fake_engine));
1765
1766 auto transceiver = caller->pc()->GetTransceivers().front();
1767 auto codecs =
1768 caller->pc_factory()
1769 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)
1770 .codecs;
1771 auto codecs_only_rtx_red_fec = codecs;
1772 auto it = std::remove_if(codecs_only_rtx_red_fec.begin(),
1773 codecs_only_rtx_red_fec.end(),
1774 [](const webrtc::RtpCodecCapability& codec) {
1775 return !(codec.name == cricket::kRtxCodecName ||
1776 codec.name == cricket::kRedCodecName ||
1777 codec.name == cricket::kUlpfecCodecName);
1778 });
1779 codecs_only_rtx_red_fec.erase(it, codecs_only_rtx_red_fec.end());
1780
1781 auto result = transceiver->SetCodecPreferences(codecs_only_rtx_red_fec);
1782 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1783}
1784
1785TEST_F(PeerConnectionMediaTestUnifiedPlan, SetCodecPreferencesAllVideoCodecs) {
1786 auto caller = CreatePeerConnectionWithVideo();
1787
1788 auto sender_video_codecs =
1789 caller->pc_factory()
1790 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1791 .codecs;
1792
1793 auto video_transceiver = caller->pc()->GetTransceivers().front();
1794
1795 // Normal case, setting preferences to normal capabilities
1796 EXPECT_TRUE(video_transceiver->SetCodecPreferences(sender_video_codecs).ok());
1797 auto offer = caller->CreateOffer();
1798 auto codecs = offer->description()
1799 ->contents()[0]
1800 .media_description()
1801 ->as_video()
1802 ->codecs();
1803 EXPECT_TRUE(CompareCodecs(sender_video_codecs, codecs));
1804}
1805
1806TEST_F(PeerConnectionMediaTestUnifiedPlan,
1807 SetCodecPreferencesResetVideoCodecs) {
1808 auto caller = CreatePeerConnectionWithVideo();
1809
1810 auto sender_video_codecs =
1811 caller->pc_factory()
1812 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1813 .codecs;
1814
1815 std::vector<webrtc::RtpCodecCapability> empty_codecs = {};
1816
1817 auto video_transceiver = caller->pc()->GetTransceivers().front();
1818
1819 // Normal case, resetting preferences with empty list of codecs
1820 EXPECT_TRUE(video_transceiver->SetCodecPreferences(empty_codecs).ok());
1821 auto offer = caller->CreateOffer();
1822 auto codecs = offer->description()
1823 ->contents()[0]
1824 .media_description()
1825 ->as_video()
1826 ->codecs();
1827 EXPECT_TRUE(CompareCodecs(sender_video_codecs, codecs));
1828}
1829
1830TEST_F(PeerConnectionMediaTestUnifiedPlan,
1831 SetCodecPreferencesVideoCodecDuplicatesRemoved) {
1832 auto caller = CreatePeerConnectionWithVideo();
1833
1834 auto sender_video_codecs =
1835 caller->pc_factory()
1836 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1837 .codecs;
1838
1839 auto video_transceiver = caller->pc()->GetTransceivers().front();
1840
1841 // Check duplicates are removed
1842 auto single_codec = sender_video_codecs;
1843 single_codec.resize(1);
1844 auto duplicate_codec = single_codec;
1845 duplicate_codec.push_back(duplicate_codec.front());
1846 duplicate_codec.push_back(duplicate_codec.front());
1847 duplicate_codec.push_back(duplicate_codec.front());
1848
1849 EXPECT_TRUE(video_transceiver->SetCodecPreferences(duplicate_codec).ok());
1850 auto offer = caller->CreateOffer();
1851 auto codecs = offer->description()
1852 ->contents()[0]
1853 .media_description()
1854 ->as_video()
1855 ->codecs();
1856 EXPECT_TRUE(CompareCodecs(single_codec, codecs));
1857}
1858
1859TEST_F(PeerConnectionMediaTestUnifiedPlan, SetCodecPreferencesVideoWithRtx) {
Mirko Bonadei317a1f02019-09-17 15:06:181860 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Johannes Kron3e983682020-03-29 20:17:001861 auto caller_video_codecs = caller_fake_engine->video().send_codecs();
Florent Castelli2d9d82e2019-04-23 17:25:511862 caller_video_codecs.push_back(cricket::VideoCodec(
1863 caller_video_codecs.back().id + 1, cricket::kVp8CodecName));
1864 caller_video_codecs.push_back(cricket::VideoCodec(
1865 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1866 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1867 std::to_string(caller_video_codecs.back().id - 1);
1868 caller_video_codecs.push_back(cricket::VideoCodec(
1869 caller_video_codecs.back().id + 1, cricket::kVp9CodecName));
1870 caller_video_codecs.push_back(cricket::VideoCodec(
1871 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1872 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1873 std::to_string(caller_video_codecs.back().id - 1);
1874 caller_fake_engine->SetVideoCodecs(caller_video_codecs);
1875
1876 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
1877
1878 auto sender_video_codecs =
1879 caller->pc_factory()
1880 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1881 .codecs;
1882
1883 auto video_transceiver = caller->pc()->GetTransceivers().front();
1884
1885 // Check that RTX codec is properly added
1886 auto video_codecs_vpx_rtx = sender_video_codecs;
1887 auto it =
1888 std::remove_if(video_codecs_vpx_rtx.begin(), video_codecs_vpx_rtx.end(),
1889 [](const webrtc::RtpCodecCapability& codec) {
1890 return codec.name != cricket::kRtxCodecName &&
1891 codec.name != cricket::kVp8CodecName &&
1892 codec.name != cricket::kVp9CodecName;
1893 });
1894 video_codecs_vpx_rtx.erase(it, video_codecs_vpx_rtx.end());
1895 absl::c_reverse(video_codecs_vpx_rtx);
1896 EXPECT_EQ(video_codecs_vpx_rtx.size(), 3u); // VP8, VP9, RTX
1897 EXPECT_TRUE(
1898 video_transceiver->SetCodecPreferences(video_codecs_vpx_rtx).ok());
1899 auto offer = caller->CreateOffer();
1900 auto codecs = offer->description()
1901 ->contents()[0]
1902 .media_description()
1903 ->as_video()
1904 ->codecs();
1905
1906 EXPECT_TRUE(CompareCodecs(video_codecs_vpx_rtx, codecs));
1907 EXPECT_EQ(codecs.size(), 4u);
1908}
1909
1910TEST_F(PeerConnectionMediaTestUnifiedPlan,
1911 SetCodecPreferencesVideoCodecsNegotiation) {
Mirko Bonadei317a1f02019-09-17 15:06:181912 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Johannes Kron3e983682020-03-29 20:17:001913 auto caller_video_codecs = caller_fake_engine->video().send_codecs();
Florent Castelli2d9d82e2019-04-23 17:25:511914 caller_video_codecs.push_back(cricket::VideoCodec(
1915 caller_video_codecs.back().id + 1, cricket::kVp8CodecName));
1916 caller_video_codecs.push_back(cricket::VideoCodec(
1917 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1918 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1919 std::to_string(caller_video_codecs.back().id - 1);
1920 caller_video_codecs.push_back(cricket::VideoCodec(
1921 caller_video_codecs.back().id + 1, cricket::kVp9CodecName));
1922 caller_video_codecs.push_back(cricket::VideoCodec(
1923 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1924 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1925 std::to_string(caller_video_codecs.back().id - 1);
1926 caller_fake_engine->SetVideoCodecs(caller_video_codecs);
1927
Mirko Bonadei317a1f02019-09-17 15:06:181928 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 17:25:511929 callee_fake_engine->SetVideoCodecs(caller_video_codecs);
1930
1931 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
1932 auto callee = CreatePeerConnection(std::move(callee_fake_engine));
1933
1934 auto video_codecs = caller->pc_factory()
1935 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1936 .codecs;
1937
1938 auto send_transceiver = caller->pc()->GetTransceivers().front();
1939
1940 auto video_codecs_vpx = video_codecs;
1941 auto it = std::remove_if(video_codecs_vpx.begin(), video_codecs_vpx.end(),
1942 [](const webrtc::RtpCodecCapability& codec) {
1943 return codec.name != cricket::kVp8CodecName &&
1944 codec.name != cricket::kVp9CodecName;
1945 });
1946 video_codecs_vpx.erase(it, video_codecs_vpx.end());
1947 EXPECT_EQ(video_codecs_vpx.size(), 2u); // VP8, VP9
1948 EXPECT_TRUE(send_transceiver->SetCodecPreferences(video_codecs_vpx).ok());
1949
1950 auto offer = caller->CreateOfferAndSetAsLocal();
1951 auto codecs = offer->description()
1952 ->contents()[0]
1953 .media_description()
1954 ->as_video()
1955 ->codecs();
1956
1957 EXPECT_EQ(codecs.size(), 2u); // VP8, VP9
1958 EXPECT_TRUE(CompareCodecs(video_codecs_vpx, codecs));
1959
1960 callee->SetRemoteDescription(std::move(offer));
1961
1962 auto recv_transceiver = callee->pc()->GetTransceivers().front();
1963 auto video_codecs_vp8_rtx = video_codecs;
1964 it = std::remove_if(video_codecs_vp8_rtx.begin(), video_codecs_vp8_rtx.end(),
1965 [](const webrtc::RtpCodecCapability& codec) {
1966 bool r = codec.name != cricket::kVp8CodecName &&
1967 codec.name != cricket::kRtxCodecName;
1968 return r;
1969 });
1970 video_codecs_vp8_rtx.erase(it, video_codecs_vp8_rtx.end());
1971 EXPECT_EQ(video_codecs_vp8_rtx.size(), 2u); // VP8, RTX
1972 recv_transceiver->SetCodecPreferences(video_codecs_vp8_rtx);
1973
1974 auto answer = callee->CreateAnswerAndSetAsLocal();
1975
1976 auto recv_codecs = answer->description()
1977 ->contents()[0]
1978 .media_description()
1979 ->as_video()
1980 ->codecs();
1981 EXPECT_EQ(recv_codecs.size(), 1u); // VP8
1982}
1983
1984TEST_F(PeerConnectionMediaTestUnifiedPlan,
1985 SetCodecPreferencesVideoCodecsNegotiationReverseOrder) {
Mirko Bonadei317a1f02019-09-17 15:06:181986 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Johannes Kron3e983682020-03-29 20:17:001987 auto caller_video_codecs = caller_fake_engine->video().send_codecs();
Florent Castelli2d9d82e2019-04-23 17:25:511988 caller_video_codecs.push_back(cricket::VideoCodec(
1989 caller_video_codecs.back().id + 1, cricket::kVp8CodecName));
1990 caller_video_codecs.push_back(cricket::VideoCodec(
1991 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1992 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1993 std::to_string(caller_video_codecs.back().id - 1);
1994 caller_video_codecs.push_back(cricket::VideoCodec(
1995 caller_video_codecs.back().id + 1, cricket::kVp9CodecName));
1996 caller_video_codecs.push_back(cricket::VideoCodec(
1997 caller_video_codecs.back().id + 1, cricket::kRtxCodecName));
1998 caller_video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] =
1999 std::to_string(caller_video_codecs.back().id - 1);
2000 caller_fake_engine->SetVideoCodecs(caller_video_codecs);
2001
Mirko Bonadei317a1f02019-09-17 15:06:182002 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 17:25:512003 callee_fake_engine->SetVideoCodecs(caller_video_codecs);
2004
2005 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
2006 auto callee = CreatePeerConnection(std::move(callee_fake_engine));
2007
2008 auto video_codecs = caller->pc_factory()
2009 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
2010 .codecs;
2011
2012 auto send_transceiver = caller->pc()->GetTransceivers().front();
2013
2014 auto video_codecs_vpx = video_codecs;
2015 auto it = std::remove_if(video_codecs_vpx.begin(), video_codecs_vpx.end(),
2016 [](const webrtc::RtpCodecCapability& codec) {
2017 return codec.name != cricket::kVp8CodecName &&
2018 codec.name != cricket::kVp9CodecName;
2019 });
2020 video_codecs_vpx.erase(it, video_codecs_vpx.end());
2021 EXPECT_EQ(video_codecs_vpx.size(), 2u); // VP8, VP9
2022 EXPECT_TRUE(send_transceiver->SetCodecPreferences(video_codecs_vpx).ok());
2023
2024 auto video_codecs_vpx_reverse = video_codecs_vpx;
2025 absl::c_reverse(video_codecs_vpx_reverse);
2026
2027 auto offer = caller->CreateOfferAndSetAsLocal();
2028 auto codecs = offer->description()
2029 ->contents()[0]
2030 .media_description()
2031 ->as_video()
2032 ->codecs();
2033 EXPECT_EQ(codecs.size(), 2u); // VP9, VP8
2034 EXPECT_TRUE(CompareCodecs(video_codecs_vpx, codecs));
2035
2036 callee->SetRemoteDescription(std::move(offer));
2037
2038 auto recv_transceiver = callee->pc()->GetTransceivers().front();
2039 recv_transceiver->SetCodecPreferences(video_codecs_vpx_reverse);
2040
2041 auto answer = callee->CreateAnswerAndSetAsLocal();
2042
2043 auto recv_codecs = answer->description()
2044 ->contents()[0]
2045 .media_description()
2046 ->as_video()
2047 ->codecs();
2048
2049 EXPECT_TRUE(CompareCodecs(video_codecs_vpx_reverse, recv_codecs));
2050}
2051
Philipp Hancke3ac73bd2021-05-11 12:13:062052TEST_F(PeerConnectionMediaTestUnifiedPlan,
2053 SetCodecPreferencesVoiceActivityDetection) {
2054 auto fake_engine = std::make_unique<FakeMediaEngine>();
2055 AddComfortNoiseCodecsToSend(fake_engine.get());
2056 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
2057
2058 RTCOfferAnswerOptions options;
2059 auto offer = caller->CreateOffer(options);
2060 EXPECT_TRUE(HasAnyComfortNoiseCodecs(offer->description()));
2061
2062 auto transceiver = caller->pc()->GetTransceivers().front();
2063 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2064 cricket::MediaType::MEDIA_TYPE_AUDIO);
2065 EXPECT_TRUE(transceiver->SetCodecPreferences(capabilities.codecs).ok());
2066
2067 options.voice_activity_detection = false;
2068 offer = caller->CreateOffer(options);
2069 EXPECT_FALSE(HasAnyComfortNoiseCodecs(offer->description()));
2070}
2071
Taylor Brandstetterf7fcfb72021-09-09 20:39:382072// If the "default" payload types of audio/video codecs are the same, and
2073// audio/video are bundled (as is the default), payload types should be
2074// remapped to avoid conflict, as normally happens without using
2075// SetCodecPreferences.
2076TEST_F(PeerConnectionMediaTestUnifiedPlan,
2077 SetCodecPreferencesAvoidsPayloadTypeConflictInOffer) {
2078 auto fake_engine = std::make_unique<cricket::FakeMediaEngine>();
2079
2080 std::vector<cricket::AudioCodec> audio_codecs;
2081 audio_codecs.emplace_back(100, "foo", 0, 0, 1);
2082 audio_codecs.emplace_back(101, cricket::kRtxCodecName, 0, 0, 1);
2083 audio_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "100";
2084 fake_engine->SetAudioCodecs(audio_codecs);
2085
2086 std::vector<cricket::VideoCodec> video_codecs;
2087 video_codecs.emplace_back(100, "bar");
2088 video_codecs.emplace_back(101, cricket::kRtxCodecName);
2089 video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "100";
2090 fake_engine->SetVideoCodecs(video_codecs);
2091
2092 auto caller = CreatePeerConnectionWithAudioVideo(std::move(fake_engine));
2093 auto transceivers = caller->pc()->GetTransceivers();
2094 ASSERT_EQ(2u, transceivers.size());
2095
2096 auto audio_transceiver = caller->pc()->GetTransceivers()[0];
2097 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2098 cricket::MediaType::MEDIA_TYPE_AUDIO);
2099 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(capabilities.codecs).ok());
2100
2101 auto video_transceiver = caller->pc()->GetTransceivers()[1];
2102 capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2103 cricket::MediaType::MEDIA_TYPE_VIDEO);
2104 EXPECT_TRUE(video_transceiver->SetCodecPreferences(capabilities.codecs).ok());
2105
2106 RTCOfferAnswerOptions options;
2107 auto offer = caller->CreateOffer(options);
2108 EXPECT_FALSE(HasPayloadTypeConflict(offer->description()));
2109 // Sanity check that we got the primary codec and RTX.
2110 EXPECT_EQ(2u, cricket::GetFirstAudioContentDescription(offer->description())
2111 ->codecs()
2112 .size());
2113 EXPECT_EQ(2u, cricket::GetFirstVideoContentDescription(offer->description())
2114 ->codecs()
2115 .size());
2116}
2117
2118// Same as above, but preferences set for the answer.
2119TEST_F(PeerConnectionMediaTestUnifiedPlan,
2120 SetCodecPreferencesAvoidsPayloadTypeConflictInAnswer) {
2121 auto fake_engine = std::make_unique<cricket::FakeMediaEngine>();
2122
2123 std::vector<cricket::AudioCodec> audio_codecs;
2124 audio_codecs.emplace_back(100, "foo", 0, 0, 1);
2125 audio_codecs.emplace_back(101, cricket::kRtxCodecName, 0, 0, 1);
2126 audio_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "100";
2127 fake_engine->SetAudioCodecs(audio_codecs);
2128
2129 std::vector<cricket::VideoCodec> video_codecs;
2130 video_codecs.emplace_back(100, "bar");
2131 video_codecs.emplace_back(101, cricket::kRtxCodecName);
2132 video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "100";
2133 fake_engine->SetVideoCodecs(video_codecs);
2134
2135 auto caller = CreatePeerConnectionWithAudioVideo(std::move(fake_engine));
2136
2137 RTCOfferAnswerOptions options;
2138 caller->SetRemoteDescription(caller->CreateOffer(options));
2139
2140 auto transceivers = caller->pc()->GetTransceivers();
2141 ASSERT_EQ(2u, transceivers.size());
2142
2143 auto audio_transceiver = caller->pc()->GetTransceivers()[0];
2144 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2145 cricket::MediaType::MEDIA_TYPE_AUDIO);
2146 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(capabilities.codecs).ok());
2147
2148 auto video_transceiver = caller->pc()->GetTransceivers()[1];
2149 capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2150 cricket::MediaType::MEDIA_TYPE_VIDEO);
2151 EXPECT_TRUE(video_transceiver->SetCodecPreferences(capabilities.codecs).ok());
2152
2153 auto answer = caller->CreateAnswer(options);
2154
2155 EXPECT_FALSE(HasPayloadTypeConflict(answer->description()));
2156 // Sanity check that we got the primary codec and RTX.
2157 EXPECT_EQ(2u, cricket::GetFirstAudioContentDescription(answer->description())
2158 ->codecs()
2159 .size());
2160 EXPECT_EQ(2u, cricket::GetFirstVideoContentDescription(answer->description())
2161 ->codecs()
2162 .size());
2163}
2164
2165// Same as above, but preferences set for a subsequent offer.
2166TEST_F(PeerConnectionMediaTestUnifiedPlan,
2167 SetCodecPreferencesAvoidsPayloadTypeConflictInSubsequentOffer) {
2168 auto fake_engine = std::make_unique<cricket::FakeMediaEngine>();
2169
2170 std::vector<cricket::AudioCodec> audio_codecs;
2171 audio_codecs.emplace_back(100, "foo", 0, 0, 1);
2172 audio_codecs.emplace_back(101, cricket::kRtxCodecName, 0, 0, 1);
2173 audio_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "100";
2174 fake_engine->SetAudioCodecs(audio_codecs);
2175
2176 std::vector<cricket::VideoCodec> video_codecs;
2177 video_codecs.emplace_back(100, "bar");
2178 video_codecs.emplace_back(101, cricket::kRtxCodecName);
2179 video_codecs.back().params[cricket::kCodecParamAssociatedPayloadType] = "100";
2180 fake_engine->SetVideoCodecs(video_codecs);
2181
2182 auto caller = CreatePeerConnectionWithAudioVideo(std::move(fake_engine));
2183
2184 RTCOfferAnswerOptions options;
2185 caller->SetRemoteDescription(caller->CreateOffer(options));
2186 caller->SetLocalDescription(caller->CreateAnswer(options));
2187
2188 auto transceivers = caller->pc()->GetTransceivers();
2189 ASSERT_EQ(2u, transceivers.size());
2190
2191 auto audio_transceiver = caller->pc()->GetTransceivers()[0];
2192 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2193 cricket::MediaType::MEDIA_TYPE_AUDIO);
2194 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(capabilities.codecs).ok());
2195
2196 auto video_transceiver = caller->pc()->GetTransceivers()[1];
2197 capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2198 cricket::MediaType::MEDIA_TYPE_VIDEO);
2199 EXPECT_TRUE(video_transceiver->SetCodecPreferences(capabilities.codecs).ok());
2200
2201 auto reoffer = caller->CreateOffer(options);
2202
2203 EXPECT_FALSE(HasPayloadTypeConflict(reoffer->description()));
2204 // Sanity check that we got the primary codec and RTX.
2205 EXPECT_EQ(2u, cricket::GetFirstAudioContentDescription(reoffer->description())
2206 ->codecs()
2207 .size());
2208 EXPECT_EQ(2u, cricket::GetFirstVideoContentDescription(reoffer->description())
2209 ->codecs()
2210 .size());
2211}
2212
Mirko Bonadeic84f6612019-01-31 11:20:572213INSTANTIATE_TEST_SUITE_P(PeerConnectionMediaTest,
2214 PeerConnectionMediaTest,
2215 Values(SdpSemantics::kPlanB,
2216 SdpSemantics::kUnifiedPlan));
Steve Antonad7bffc2018-01-22 18:21:562217
Steve Anton8d3444d2017-10-20 22:30:512218} // namespace webrtc