blob: 061c59a3b06e213723d557baab57bc44ed56515a [file] [log] [blame]
Steve Anton8d3444d2017-10-20 22:30:511/*
2 * Copyright 2017 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11// This file contains tests that check the interaction between the
12// PeerConnection and the underlying media engine, as well as tests that check
13// the media-related aspects of SDP.
14
Harald Alvestrandc24a2182022-02-23 13:44:5915#include <algorithm>
16#include <functional>
17#include <iterator>
18#include <map>
Mirko Bonadei317a1f02019-09-17 15:06:1819#include <memory>
Taylor Brandstetterf7fcfb72021-09-09 20:39:3820#include <set>
Harald Alvestrandc24a2182022-02-23 13:44:5921#include <string>
Steve Anton8d3444d2017-10-20 22:30:5122#include <tuple>
Harald Alvestrandc24a2182022-02-23 13:44:5923#include <type_traits>
24#include <utility>
25#include <vector>
Steve Anton8d3444d2017-10-20 22:30:5126
Steve Anton64b626b2019-01-29 01:25:2627#include "absl/algorithm/container.h"
Mirta Dvornicic479a3c02019-06-04 13:38:5028#include "absl/types/optional.h"
Harald Alvestrandc24a2182022-02-23 13:44:5929#include "api/audio_options.h"
Harald Alvestrandc24a2182022-02-23 13:44:5930#include "api/jsep.h"
31#include "api/media_types.h"
32#include "api/peer_connection_interface.h"
33#include "api/rtc_error.h"
Danil Chapovalov9da25bd2019-06-20 08:19:4234#include "api/rtc_event_log/rtc_event_log_factory.h"
Harald Alvestrandc24a2182022-02-23 13:44:5935#include "api/rtc_event_log/rtc_event_log_factory_interface.h"
36#include "api/rtp_parameters.h"
37#include "api/rtp_sender_interface.h"
38#include "api/rtp_transceiver_direction.h"
39#include "api/rtp_transceiver_interface.h"
40#include "api/scoped_refptr.h"
Danil Chapovalov9da25bd2019-06-20 08:19:4241#include "api/task_queue/default_task_queue_factory.h"
Harald Alvestrandc24a2182022-02-23 13:44:5942#include "api/task_queue/task_queue_factory.h"
43#include "media/base/codec.h"
Steve Anton10542f22019-01-11 17:11:0044#include "media/base/fake_media_engine.h"
Florent Castelli1f31c202023-06-26 00:26:0745#include "media/base/media_channel.h"
Harald Alvestrandc24a2182022-02-23 13:44:5946#include "media/base/media_constants.h"
47#include "media/base/media_engine.h"
48#include "media/base/stream_params.h"
Steve Anton10542f22019-01-11 17:11:0049#include "p2p/base/fake_port_allocator.h"
Harald Alvestrandc24a2182022-02-23 13:44:5950#include "p2p/base/p2p_constants.h"
51#include "p2p/base/port_allocator.h"
52#include "p2p/base/transport_info.h"
Florent Castelli1f31c202023-06-26 00:26:0753#include "pc/channel_interface.h"
Steve Anton10542f22019-01-11 17:11:0054#include "pc/media_session.h"
55#include "pc/peer_connection_wrapper.h"
56#include "pc/rtp_media_utils.h"
Florent Castelli1f31c202023-06-26 00:26:0757#include "pc/rtp_transceiver.h"
Harald Alvestrandc24a2182022-02-23 13:44:5958#include "pc/session_description.h"
Danil Chapovalovc63120a2023-11-03 10:32:2459#include "pc/test/enable_fake_media.h"
Harald Alvestrandc24a2182022-02-23 13:44:5960#include "pc/test/mock_peer_connection_observers.h"
61#include "rtc_base/checks.h"
62#include "rtc_base/rtc_certificate_generator.h"
63#include "rtc_base/thread.h"
64#include "test/gtest.h"
Sameer Vijaykar0793ee72023-01-23 15:31:2965#include "test/scoped_key_value_config.h"
Steve Anton8d3444d2017-10-20 22:30:5166#ifdef WEBRTC_ANDROID
Steve Anton10542f22019-01-11 17:11:0067#include "pc/test/android_test_initializer.h"
Steve Anton8d3444d2017-10-20 22:30:5168#endif
Steve Anton8d3444d2017-10-20 22:30:5169#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 17:11:0070#include "rtc_base/virtual_socket_server.h"
Steve Anton8d3444d2017-10-20 22:30:5171#include "test/gmock.h"
72
73namespace webrtc {
74
75using cricket::FakeMediaEngine;
76using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
77using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
78using ::testing::Bool;
79using ::testing::Combine;
Steve Anton8d3444d2017-10-20 22:30:5180using ::testing::ElementsAre;
Harald Alvestrand2f553702023-03-07 10:10:0381using ::testing::NotNull;
Jonas Olssona4d87372019-07-05 17:08:3382using ::testing::Values;
Steve Anton8d3444d2017-10-20 22:30:5183
Florent Castelli1f31c202023-06-26 00:26:0784cricket::MediaSendChannelInterface* SendChannelInternal(
Harald Alvestranda6544372023-11-13 09:33:5685 rtc::scoped_refptr<RtpTransceiverInterface> transceiver) {
86 auto transceiver_with_internal = static_cast<
87 rtc::RefCountedObject<RtpTransceiverProxyWithInternal<RtpTransceiver>>*>(
Florent Castelli1f31c202023-06-26 00:26:0788 transceiver.get());
89 auto transceiver_internal =
90 static_cast<RtpTransceiver*>(transceiver_with_internal->internal());
91 return transceiver_internal->channel()->media_send_channel();
92}
93
94cricket::MediaReceiveChannelInterface* ReceiveChannelInternal(
Harald Alvestranda6544372023-11-13 09:33:5695 rtc::scoped_refptr<RtpTransceiverInterface> transceiver) {
96 auto transceiver_with_internal = static_cast<
97 rtc::RefCountedObject<RtpTransceiverProxyWithInternal<RtpTransceiver>>*>(
Florent Castelli1f31c202023-06-26 00:26:0798 transceiver.get());
99 auto transceiver_internal =
100 static_cast<RtpTransceiver*>(transceiver_with_internal->internal());
101 return transceiver_internal->channel()->media_receive_channel();
102}
103
104cricket::FakeVideoMediaSendChannel* VideoMediaSendChannel(
Harald Alvestranda6544372023-11-13 09:33:56105 rtc::scoped_refptr<RtpTransceiverInterface> transceiver) {
Florent Castelli1f31c202023-06-26 00:26:07106 return static_cast<cricket::FakeVideoMediaSendChannel*>(
107 SendChannelInternal(transceiver));
108}
109cricket::FakeVideoMediaReceiveChannel* VideoMediaReceiveChannel(
Harald Alvestranda6544372023-11-13 09:33:56110 rtc::scoped_refptr<RtpTransceiverInterface> transceiver) {
Florent Castelli1f31c202023-06-26 00:26:07111 return static_cast<cricket::FakeVideoMediaReceiveChannel*>(
112 ReceiveChannelInternal(transceiver));
113}
114cricket::FakeVoiceMediaSendChannel* VoiceMediaSendChannel(
Harald Alvestranda6544372023-11-13 09:33:56115 rtc::scoped_refptr<RtpTransceiverInterface> transceiver) {
Florent Castelli1f31c202023-06-26 00:26:07116 return static_cast<cricket::FakeVoiceMediaSendChannel*>(
117 SendChannelInternal(transceiver));
118}
119cricket::FakeVoiceMediaReceiveChannel* VoiceMediaReceiveChannel(
Harald Alvestranda6544372023-11-13 09:33:56120 rtc::scoped_refptr<RtpTransceiverInterface> transceiver) {
Florent Castelli1f31c202023-06-26 00:26:07121 return static_cast<cricket::FakeVoiceMediaReceiveChannel*>(
122 ReceiveChannelInternal(transceiver));
123}
124
Steve Anton8d3444d2017-10-20 22:30:51125class PeerConnectionWrapperForMediaTest : public PeerConnectionWrapper {
126 public:
127 using PeerConnectionWrapper::PeerConnectionWrapper;
128
129 FakeMediaEngine* media_engine() { return media_engine_; }
130 void set_media_engine(FakeMediaEngine* media_engine) {
131 media_engine_ = media_engine;
132 }
133
134 private:
135 FakeMediaEngine* media_engine_;
136};
137
Steve Antonad7bffc2018-01-22 18:21:56138class PeerConnectionMediaBaseTest : public ::testing::Test {
Steve Anton8d3444d2017-10-20 22:30:51139 protected:
140 typedef std::unique_ptr<PeerConnectionWrapperForMediaTest> WrapperPtr;
141
Steve Antonad7bffc2018-01-22 18:21:56142 explicit PeerConnectionMediaBaseTest(SdpSemantics sdp_semantics)
143 : vss_(new rtc::VirtualSocketServer()),
144 main_(vss_.get()),
145 sdp_semantics_(sdp_semantics) {
Steve Anton8d3444d2017-10-20 22:30:51146#ifdef WEBRTC_ANDROID
147 InitializeAndroidObjects();
148#endif
149 }
150
151 WrapperPtr CreatePeerConnection() {
152 return CreatePeerConnection(RTCConfiguration());
153 }
154
Florent Castelli2d9d82e2019-04-23 17:25:51155 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
Mirko Bonadei317a1f02019-09-17 15:06:18156 return CreatePeerConnection(config, std::make_unique<FakeMediaEngine>());
Florent Castelli2d9d82e2019-04-23 17:25:51157 }
158
159 WrapperPtr CreatePeerConnection(
160 std::unique_ptr<FakeMediaEngine> media_engine) {
161 return CreatePeerConnection(RTCConfiguration(), std::move(media_engine));
162 }
163
Anton Sukhanov98a462c2018-10-17 20:15:42164 // Creates PeerConnectionFactory and PeerConnection for given configuration.
Florent Castelli2d9d82e2019-04-23 17:25:51165 WrapperPtr CreatePeerConnection(
166 const RTCConfiguration& config,
167 std::unique_ptr<FakeMediaEngine> media_engine) {
Steve Anton8d3444d2017-10-20 22:30:51168 auto* media_engine_ptr = media_engine.get();
Anton Sukhanov98a462c2018-10-17 20:15:42169
170 PeerConnectionFactoryDependencies factory_dependencies;
171
172 factory_dependencies.network_thread = rtc::Thread::Current();
173 factory_dependencies.worker_thread = rtc::Thread::Current();
174 factory_dependencies.signaling_thread = rtc::Thread::Current();
Danil Chapovalov9da25bd2019-06-20 08:19:42175 factory_dependencies.task_queue_factory = CreateDefaultTaskQueueFactory();
Danil Chapovalovc63120a2023-11-03 10:32:24176 EnableFakeMedia(factory_dependencies, std::move(media_engine));
Danil Chapovalov9da25bd2019-06-20 08:19:42177 factory_dependencies.event_log_factory =
Danil Chapovalov151003d2023-12-07 19:01:06178 std::make_unique<RtcEventLogFactory>();
Anton Sukhanov98a462c2018-10-17 20:15:42179
180 auto pc_factory =
181 CreateModularPeerConnectionFactory(std::move(factory_dependencies));
Steve Anton8d3444d2017-10-20 22:30:51182
Mirko Bonadei317a1f02019-09-17 15:06:18183 auto fake_port_allocator = std::make_unique<cricket::FakePortAllocator>(
Byoungchan Leed58f5262022-06-27 09:05:22184 rtc::Thread::Current(),
Sameer Vijaykar0793ee72023-01-23 15:31:29185 std::make_unique<rtc::BasicPacketSocketFactory>(vss_.get()),
186 &field_trials_);
Mirko Bonadei317a1f02019-09-17 15:06:18187 auto observer = std::make_unique<MockPeerConnectionObserver>();
Steve Antonad7bffc2018-01-22 18:21:56188 auto modified_config = config;
189 modified_config.sdp_semantics = sdp_semantics_;
Florent Castelli72424402022-04-06 01:45:10190 PeerConnectionDependencies pc_dependencies(observer.get());
191 pc_dependencies.allocator = std::move(fake_port_allocator);
192 auto result = pc_factory->CreatePeerConnectionOrError(
193 modified_config, std::move(pc_dependencies));
194 if (!result.ok()) {
Steve Anton8d3444d2017-10-20 22:30:51195 return nullptr;
196 }
197
Florent Castelli72424402022-04-06 01:45:10198 auto pc = result.MoveValue();
Yves Gerey4e933292018-10-31 14:36:05199 observer->SetPeerConnectionInterface(pc.get());
Mirko Bonadei317a1f02019-09-17 15:06:18200 auto wrapper = std::make_unique<PeerConnectionWrapperForMediaTest>(
Steve Anton8d3444d2017-10-20 22:30:51201 pc_factory, pc, std::move(observer));
202 wrapper->set_media_engine(media_engine_ptr);
203 return wrapper;
204 }
205
206 // Accepts the same arguments as CreatePeerConnection and adds default audio
Piotr (Peter) Slatala10aeb2a2018-11-14 18:57:24207 // track (but no video).
208 template <typename... Args>
209 WrapperPtr CreatePeerConnectionWithAudio(Args&&... args) {
210 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
211 if (!wrapper) {
212 return nullptr;
213 }
214 wrapper->AddAudioTrack("a");
215 return wrapper;
216 }
217
Florent Castelli2d9d82e2019-04-23 17:25:51218 // Accepts the same arguments as CreatePeerConnection and adds default video
219 // track (but no audio).
220 template <typename... Args>
221 WrapperPtr CreatePeerConnectionWithVideo(Args&&... args) {
222 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
223 if (!wrapper) {
224 return nullptr;
225 }
226 wrapper->AddVideoTrack("v");
227 return wrapper;
228 }
229
Piotr (Peter) Slatala10aeb2a2018-11-14 18:57:24230 // Accepts the same arguments as CreatePeerConnection and adds default audio
Steve Anton8d3444d2017-10-20 22:30:51231 // and video tracks.
232 template <typename... Args>
233 WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
234 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
235 if (!wrapper) {
236 return nullptr;
237 }
238 wrapper->AddAudioTrack("a");
239 wrapper->AddVideoTrack("v");
240 return wrapper;
241 }
242
Steve Anton4e70a722017-11-28 22:57:10243 RtpTransceiverDirection GetMediaContentDirection(
Steve Anton8d3444d2017-10-20 22:30:51244 const SessionDescriptionInterface* sdesc,
Steve Antonad7bffc2018-01-22 18:21:56245 cricket::MediaType media_type) {
246 auto* content =
247 cricket::GetFirstMediaContent(sdesc->description(), media_type);
248 RTC_DCHECK(content);
249 return content->media_description()->direction();
250 }
251
252 bool IsUnifiedPlan() const {
253 return sdp_semantics_ == SdpSemantics::kUnifiedPlan;
Steve Anton8d3444d2017-10-20 22:30:51254 }
255
Harald Alvestranda6544372023-11-13 09:33:56256 test::ScopedKeyValueConfig field_trials_;
Steve Anton8d3444d2017-10-20 22:30:51257 std::unique_ptr<rtc::VirtualSocketServer> vss_;
258 rtc::AutoSocketServerThread main_;
Steve Antonad7bffc2018-01-22 18:21:56259 const SdpSemantics sdp_semantics_;
Steve Anton8d3444d2017-10-20 22:30:51260};
261
Steve Antonad7bffc2018-01-22 18:21:56262class PeerConnectionMediaTest
263 : public PeerConnectionMediaBaseTest,
264 public ::testing::WithParamInterface<SdpSemantics> {
265 protected:
266 PeerConnectionMediaTest() : PeerConnectionMediaBaseTest(GetParam()) {}
267};
268
269class PeerConnectionMediaTestUnifiedPlan : public PeerConnectionMediaBaseTest {
270 protected:
271 PeerConnectionMediaTestUnifiedPlan()
272 : PeerConnectionMediaBaseTest(SdpSemantics::kUnifiedPlan) {}
273};
274
275class PeerConnectionMediaTestPlanB : public PeerConnectionMediaBaseTest {
276 protected:
277 PeerConnectionMediaTestPlanB()
Florent Castelli15a38de2022-04-05 22:38:21278 : PeerConnectionMediaBaseTest(SdpSemantics::kPlanB_DEPRECATED) {}
Steve Antonad7bffc2018-01-22 18:21:56279};
280
281TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 22:30:51282 FailToSetRemoteDescriptionIfCreateMediaChannelFails) {
283 auto caller = CreatePeerConnectionWithAudioVideo();
284 auto callee = CreatePeerConnectionWithAudioVideo();
285 callee->media_engine()->set_fail_create_channel(true);
286
287 std::string error;
288 ASSERT_FALSE(callee->SetRemoteDescription(caller->CreateOffer(), &error));
Steve Antonad7bffc2018-01-22 18:21:56289 EXPECT_PRED_FORMAT2(AssertStartsWith, error,
290 "Failed to set remote offer sdp: Failed to create");
Steve Anton8d3444d2017-10-20 22:30:51291}
292
Steve Antonad7bffc2018-01-22 18:21:56293TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 22:30:51294 FailToSetLocalDescriptionIfCreateMediaChannelFails) {
295 auto caller = CreatePeerConnectionWithAudioVideo();
296 caller->media_engine()->set_fail_create_channel(true);
297
298 std::string error;
299 ASSERT_FALSE(caller->SetLocalDescription(caller->CreateOffer(), &error));
Steve Antonad7bffc2018-01-22 18:21:56300 EXPECT_PRED_FORMAT2(AssertStartsWith, error,
301 "Failed to set local offer sdp: Failed to create");
Steve Anton8d3444d2017-10-20 22:30:51302}
303
304std::vector<std::string> GetIds(
305 const std::vector<cricket::StreamParams>& streams) {
306 std::vector<std::string> ids;
Mirko Bonadei649a4c22019-01-29 09:11:53307 ids.reserve(streams.size());
Steve Anton8d3444d2017-10-20 22:30:51308 for (const auto& stream : streams) {
309 ids.push_back(stream.id);
310 }
311 return ids;
312}
313
314// Test that exchanging an offer and answer with each side having an audio and
315// video stream creates the appropriate send/recv streams in the underlying
316// media engine on both sides.
Florent Castelli1f31c202023-06-26 00:26:07317TEST_F(PeerConnectionMediaTestUnifiedPlan,
318 AudioVideoOfferAnswerCreateSendRecvStreams) {
Steve Anton8d3444d2017-10-20 22:30:51319 const std::string kCallerAudioId = "caller_a";
320 const std::string kCallerVideoId = "caller_v";
321 const std::string kCalleeAudioId = "callee_a";
322 const std::string kCalleeVideoId = "callee_v";
323
324 auto caller = CreatePeerConnection();
325 caller->AddAudioTrack(kCallerAudioId);
326 caller->AddVideoTrack(kCallerVideoId);
327
328 auto callee = CreatePeerConnection();
329 callee->AddAudioTrack(kCalleeAudioId);
330 callee->AddVideoTrack(kCalleeVideoId);
331
332 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
333 ASSERT_TRUE(
334 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
335
Florent Castelli1f31c202023-06-26 00:26:07336 auto* caller_voice_send =
337 VoiceMediaSendChannel(caller->pc()->GetTransceivers()[0]);
Harald Alvestrand2f553702023-03-07 10:10:03338 auto* caller_voice_receive =
Florent Castelli1f31c202023-06-26 00:26:07339 VoiceMediaReceiveChannel(caller->pc()->GetTransceivers()[0]);
Harald Alvestrand2f553702023-03-07 10:10:03340 EXPECT_THAT(GetIds(caller_voice_receive->recv_streams()),
Steve Anton8d3444d2017-10-20 22:30:51341 ElementsAre(kCalleeAudioId));
Harald Alvestrand2f553702023-03-07 10:10:03342 EXPECT_THAT(GetIds(caller_voice_send->send_streams()),
Steve Anton8d3444d2017-10-20 22:30:51343 ElementsAre(kCallerAudioId));
344
Florent Castelli1f31c202023-06-26 00:26:07345 auto* caller_video_send =
346 VideoMediaSendChannel(caller->pc()->GetTransceivers()[1]);
Harald Alvestrand2f553702023-03-07 10:10:03347 auto* caller_video_receive =
Florent Castelli1f31c202023-06-26 00:26:07348 VideoMediaReceiveChannel(caller->pc()->GetTransceivers()[1]);
Harald Alvestrand2f553702023-03-07 10:10:03349 EXPECT_THAT(GetIds(caller_video_receive->recv_streams()),
Steve Anton8d3444d2017-10-20 22:30:51350 ElementsAre(kCalleeVideoId));
Harald Alvestrand2f553702023-03-07 10:10:03351 EXPECT_THAT(GetIds(caller_video_send->send_streams()),
Steve Anton8d3444d2017-10-20 22:30:51352 ElementsAre(kCallerVideoId));
353
Florent Castelli1f31c202023-06-26 00:26:07354 auto* callee_voice_send =
355 VoiceMediaSendChannel(callee->pc()->GetTransceivers()[0]);
Harald Alvestrand2f553702023-03-07 10:10:03356 auto* callee_voice_receive =
Florent Castelli1f31c202023-06-26 00:26:07357 VoiceMediaReceiveChannel(callee->pc()->GetTransceivers()[0]);
Harald Alvestrand2f553702023-03-07 10:10:03358 EXPECT_THAT(GetIds(callee_voice_receive->recv_streams()),
Steve Anton8d3444d2017-10-20 22:30:51359 ElementsAre(kCallerAudioId));
Harald Alvestrand2f553702023-03-07 10:10:03360 EXPECT_THAT(GetIds(callee_voice_send->send_streams()),
Steve Anton8d3444d2017-10-20 22:30:51361 ElementsAre(kCalleeAudioId));
362
Florent Castelli1f31c202023-06-26 00:26:07363 auto* callee_video_send =
364 VideoMediaSendChannel(callee->pc()->GetTransceivers()[1]);
Harald Alvestrand2f553702023-03-07 10:10:03365 auto* callee_video_receive =
Florent Castelli1f31c202023-06-26 00:26:07366 VideoMediaReceiveChannel(callee->pc()->GetTransceivers()[1]);
Harald Alvestrand2f553702023-03-07 10:10:03367 EXPECT_THAT(GetIds(callee_video_receive->recv_streams()),
Steve Anton8d3444d2017-10-20 22:30:51368 ElementsAre(kCallerVideoId));
Harald Alvestrand2f553702023-03-07 10:10:03369 EXPECT_THAT(GetIds(callee_video_send->send_streams()),
Steve Anton8d3444d2017-10-20 22:30:51370 ElementsAre(kCalleeVideoId));
371}
372
Steve Antonad7bffc2018-01-22 18:21:56373// Test that stopping the caller transceivers causes the media channels on the
374// callee to be destroyed after calling SetRemoteDescription on the generated
375// offer.
376// See next test for equivalent behavior with Plan B semantics.
377TEST_F(PeerConnectionMediaTestUnifiedPlan,
378 StoppedRemoteTransceiversRemovesMediaChannels) {
379 auto caller = CreatePeerConnectionWithAudioVideo();
380 auto callee = CreatePeerConnection();
381
382 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
383
384 // Stop both audio and video transceivers on the caller.
385 auto transceivers = caller->pc()->GetTransceivers();
386 ASSERT_EQ(2u, transceivers.size());
Harald Alvestrand6060df52020-08-11 07:54:02387 transceivers[0]->StopInternal();
388 transceivers[1]->StopInternal();
Steve Antonad7bffc2018-01-22 18:21:56389
390 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
391
Florent Castelli1f31c202023-06-26 00:26:07392 ASSERT_TRUE(callee->pc()->GetTransceivers().empty());
Steve Antonad7bffc2018-01-22 18:21:56393}
394
Steve Anton8d3444d2017-10-20 22:30:51395// Test that removing streams from a subsequent offer causes the receive streams
396// on the callee to be removed.
Steve Antonad7bffc2018-01-22 18:21:56397// See previous test for equivalent behavior with Unified Plan semantics.
398TEST_F(PeerConnectionMediaTestPlanB, EmptyRemoteOfferRemovesRecvStreams) {
Steve Anton8d3444d2017-10-20 22:30:51399 auto caller = CreatePeerConnection();
400 auto caller_audio_track = caller->AddAudioTrack("a");
401 auto caller_video_track = caller->AddVideoTrack("v");
402 auto callee = CreatePeerConnectionWithAudioVideo();
403
Steve Antonad7bffc2018-01-22 18:21:56404 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 22:30:51405
406 // Remove both tracks from caller.
Harald Alvestrand93dd7632022-01-19 12:28:45407 caller->pc()->RemoveTrackOrError(caller_audio_track);
408 caller->pc()->RemoveTrackOrError(caller_video_track);
Steve Anton8d3444d2017-10-20 22:30:51409
Steve Antonad7bffc2018-01-22 18:21:56410 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 22:30:51411
Florent Castelli1f31c202023-06-26 00:26:07412 EXPECT_TRUE(callee->pc()->GetReceivers().empty());
413 EXPECT_EQ(2u, callee->pc()->GetSenders().size());
Steve Anton8d3444d2017-10-20 22:30:51414}
415
Jonas Orelandfc1acd22018-08-24 08:58:37416// Test enabling of simulcast with Plan B semantics.
417// This test creating an offer.
418TEST_F(PeerConnectionMediaTestPlanB, SimulcastOffer) {
419 auto caller = CreatePeerConnection();
420 auto caller_video_track = caller->AddVideoTrack("v");
421 RTCOfferAnswerOptions options;
422 options.num_simulcast_layers = 3;
423 auto offer = caller->CreateOffer(options);
Jonas Olssona4d87372019-07-05 17:08:33424 auto* description = cricket::GetFirstMediaContent(offer->description(),
425 cricket::MEDIA_TYPE_VIDEO)
426 ->media_description();
Jonas Orelandfc1acd22018-08-24 08:58:37427 ASSERT_EQ(1u, description->streams().size());
428 ASSERT_TRUE(description->streams()[0].get_ssrc_group("SIM"));
429 EXPECT_EQ(3u, description->streams()[0].get_ssrc_group("SIM")->ssrcs.size());
430
431 // Check that it actually creates simulcast aswell.
432 caller->SetLocalDescription(std::move(offer));
433 auto senders = caller->pc()->GetSenders();
434 ASSERT_EQ(1u, senders.size());
435 EXPECT_EQ(cricket::MediaType::MEDIA_TYPE_VIDEO, senders[0]->media_type());
436 EXPECT_EQ(3u, senders[0]->GetParameters().encodings.size());
437}
438
439// Test enabling of simulcast with Plan B semantics.
440// This test creating an answer.
441TEST_F(PeerConnectionMediaTestPlanB, SimulcastAnswer) {
442 auto caller = CreatePeerConnection();
443 caller->AddVideoTrack("v0");
444 auto offer = caller->CreateOffer();
445 auto callee = CreatePeerConnection();
446 auto callee_video_track = callee->AddVideoTrack("v1");
447 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
448 RTCOfferAnswerOptions options;
449 options.num_simulcast_layers = 3;
450 auto answer = callee->CreateAnswer(options);
Jonas Olssona4d87372019-07-05 17:08:33451 auto* description = cricket::GetFirstMediaContent(answer->description(),
452 cricket::MEDIA_TYPE_VIDEO)
453 ->media_description();
Jonas Orelandfc1acd22018-08-24 08:58:37454 ASSERT_EQ(1u, description->streams().size());
455 ASSERT_TRUE(description->streams()[0].get_ssrc_group("SIM"));
456 EXPECT_EQ(3u, description->streams()[0].get_ssrc_group("SIM")->ssrcs.size());
457
458 // Check that it actually creates simulcast aswell.
459 callee->SetLocalDescription(std::move(answer));
460 auto senders = callee->pc()->GetSenders();
461 ASSERT_EQ(1u, senders.size());
462 EXPECT_EQ(cricket::MediaType::MEDIA_TYPE_VIDEO, senders[0]->media_type());
463 EXPECT_EQ(3u, senders[0]->GetParameters().encodings.size());
464}
465
Steve Antonad7bffc2018-01-22 18:21:56466// Test that stopping the callee transceivers causes the media channels to be
467// destroyed on the callee after calling SetLocalDescription on the local
468// answer.
469// See next test for equivalent behavior with Plan B semantics.
470TEST_F(PeerConnectionMediaTestUnifiedPlan,
471 StoppedLocalTransceiversRemovesMediaChannels) {
472 auto caller = CreatePeerConnectionWithAudioVideo();
473 auto callee = CreatePeerConnectionWithAudioVideo();
474
475 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
476
477 // Stop both audio and video transceivers on the callee.
478 auto transceivers = callee->pc()->GetTransceivers();
479 ASSERT_EQ(2u, transceivers.size());
Harald Alvestrand6060df52020-08-11 07:54:02480 transceivers[0]->StopInternal();
481 transceivers[1]->StopInternal();
Steve Antonad7bffc2018-01-22 18:21:56482
483 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
484
Florent Castelli1f31c202023-06-26 00:26:07485 EXPECT_TRUE(callee->pc()->GetTransceivers().empty());
Steve Antonad7bffc2018-01-22 18:21:56486}
487
Steve Anton8d3444d2017-10-20 22:30:51488// Test that removing streams from a subsequent answer causes the send streams
489// on the callee to be removed when applied locally.
Steve Antonad7bffc2018-01-22 18:21:56490// See previous test for equivalent behavior with Unified Plan semantics.
491TEST_F(PeerConnectionMediaTestPlanB, EmptyLocalAnswerRemovesSendStreams) {
Steve Anton8d3444d2017-10-20 22:30:51492 auto caller = CreatePeerConnectionWithAudioVideo();
493 auto callee = CreatePeerConnection();
494 auto callee_audio_track = callee->AddAudioTrack("a");
495 auto callee_video_track = callee->AddVideoTrack("v");
496
Steve Antonad7bffc2018-01-22 18:21:56497 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 22:30:51498
499 // Remove both tracks from callee.
Harald Alvestrand93dd7632022-01-19 12:28:45500 callee->pc()->RemoveTrackOrError(callee_audio_track);
501 callee->pc()->RemoveTrackOrError(callee_video_track);
Steve Anton8d3444d2017-10-20 22:30:51502
Steve Antonad7bffc2018-01-22 18:21:56503 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 22:30:51504
Florent Castelli1f31c202023-06-26 00:26:07505 EXPECT_TRUE(callee->pc()->GetSenders().empty());
506 EXPECT_EQ(2u, callee->pc()->GetReceivers().size());
Steve Anton8d3444d2017-10-20 22:30:51507}
508
509// Test that a new stream in a subsequent offer causes a new receive stream to
510// be created on the callee.
Steve Antonad7bffc2018-01-22 18:21:56511TEST_P(PeerConnectionMediaTest, NewStreamInRemoteOfferAddsRecvStreams) {
Steve Anton8d3444d2017-10-20 22:30:51512 auto caller = CreatePeerConnectionWithAudioVideo();
513 auto callee = CreatePeerConnection();
514
Steve Antonad7bffc2018-01-22 18:21:56515 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 22:30:51516
517 // Add second set of tracks to the caller.
518 caller->AddAudioTrack("a2");
519 caller->AddVideoTrack("v2");
520
Steve Antonad7bffc2018-01-22 18:21:56521 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Steve Anton8d3444d2017-10-20 22:30:51522
Steve Antonad7bffc2018-01-22 18:21:56523 if (IsUnifiedPlan()) {
Florent Castelli1f31c202023-06-26 00:26:07524 auto a1 = VoiceMediaReceiveChannel(callee->pc()->GetTransceivers()[0]);
525 auto a2 = VoiceMediaReceiveChannel(callee->pc()->GetTransceivers()[2]);
526 auto v1 = VideoMediaReceiveChannel(callee->pc()->GetTransceivers()[1]);
527 auto v2 = VideoMediaReceiveChannel(callee->pc()->GetTransceivers()[3]);
528
Steve Antonad7bffc2018-01-22 18:21:56529 ASSERT_TRUE(a1);
530 EXPECT_EQ(1u, a1->recv_streams().size());
531 ASSERT_TRUE(a2);
532 EXPECT_EQ(1u, a2->recv_streams().size());
533 ASSERT_TRUE(v1);
534 EXPECT_EQ(1u, v1->recv_streams().size());
535 ASSERT_TRUE(v2);
536 EXPECT_EQ(1u, v2->recv_streams().size());
537 } else {
Florent Castelli1f31c202023-06-26 00:26:07538 EXPECT_EQ(4u, callee->pc()->GetReceivers().size());
Steve Antonad7bffc2018-01-22 18:21:56539 }
Steve Anton8d3444d2017-10-20 22:30:51540}
541
542// Test that a new stream in a subsequent answer causes a new send stream to be
543// created on the callee when added locally.
Steve Antonad7bffc2018-01-22 18:21:56544TEST_P(PeerConnectionMediaTest, NewStreamInLocalAnswerAddsSendStreams) {
Steve Anton8d3444d2017-10-20 22:30:51545 auto caller = CreatePeerConnection();
546 auto callee = CreatePeerConnectionWithAudioVideo();
547
Steve Anton22da89f2018-01-25 21:58:07548 RTCOfferAnswerOptions offer_options;
549 offer_options.offer_to_receive_audio =
Steve Anton8d3444d2017-10-20 22:30:51550 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
Steve Anton22da89f2018-01-25 21:58:07551 offer_options.offer_to_receive_video =
Steve Anton8d3444d2017-10-20 22:30:51552 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
Steve Anton22da89f2018-01-25 21:58:07553 RTCOfferAnswerOptions answer_options;
Steve Anton8d3444d2017-10-20 22:30:51554
Steve Anton22da89f2018-01-25 21:58:07555 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get(), offer_options,
556 answer_options));
Steve Anton8d3444d2017-10-20 22:30:51557
558 // Add second set of tracks to the callee.
559 callee->AddAudioTrack("a2");
560 callee->AddVideoTrack("v2");
561
Steve Anton22da89f2018-01-25 21:58:07562 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get(), offer_options,
563 answer_options));
Steve Anton8d3444d2017-10-20 22:30:51564
Steve Anton22da89f2018-01-25 21:58:07565 if (IsUnifiedPlan()) {
Florent Castelli1f31c202023-06-26 00:26:07566 auto callee_voice =
567 VoiceMediaSendChannel(callee->pc()->GetTransceivers()[0]);
568 ASSERT_TRUE(callee_voice);
569 auto callee_video =
570 VideoMediaSendChannel(callee->pc()->GetTransceivers()[1]);
571 ASSERT_TRUE(callee_video);
572
Steve Anton22da89f2018-01-25 21:58:07573 EXPECT_EQ(1u, callee_voice->send_streams().size());
574 EXPECT_EQ(1u, callee_video->send_streams().size());
575 } else {
Florent Castelli1f31c202023-06-26 00:26:07576 EXPECT_EQ(4u, callee->pc()->GetSenders().size());
Steve Anton22da89f2018-01-25 21:58:07577 }
Steve Anton8d3444d2017-10-20 22:30:51578}
579
580// A PeerConnection with no local streams and no explicit answer constraints
581// should not reject any offered media sections.
Steve Antonad7bffc2018-01-22 18:21:56582TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 22:30:51583 CreateAnswerWithNoStreamsAndDefaultOptionsDoesNotReject) {
584 auto caller = CreatePeerConnectionWithAudioVideo();
585 auto callee = CreatePeerConnection();
586 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
587 auto answer = callee->CreateAnswer();
588
589 const auto* audio_content =
590 cricket::GetFirstAudioContent(answer->description());
591 ASSERT_TRUE(audio_content);
592 EXPECT_FALSE(audio_content->rejected);
593
594 const auto* video_content =
595 cricket::GetFirstVideoContent(answer->description());
596 ASSERT_TRUE(video_content);
597 EXPECT_FALSE(video_content->rejected);
598}
599
Mirta Dvornicic479a3c02019-06-04 13:38:50600// Test that raw packetization is not set in the offer by default.
601TEST_P(PeerConnectionMediaTest, RawPacketizationNotSetInOffer) {
602 std::vector<cricket::VideoCodec> fake_codecs;
Florent Castelli8c4b9ea2023-06-02 16:06:57603 fake_codecs.push_back(cricket::CreateVideoCodec(111, cricket::kVp8CodecName));
Florent Castellid0b8e8e2023-06-04 23:22:36604 fake_codecs.push_back(cricket::CreateVideoRtxCodec(112, 111));
Florent Castelli8c4b9ea2023-06-02 16:06:57605 fake_codecs.push_back(cricket::CreateVideoCodec(113, cricket::kVp9CodecName));
606 fake_codecs.push_back(
607 cricket::CreateVideoCodec(114, cricket::kH264CodecName));
608 fake_codecs.push_back(cricket::CreateVideoCodec(115, "HEVC"));
Mirko Bonadei317a1f02019-09-17 15:06:18609 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 13:38:50610 caller_fake_engine->SetVideoCodecs(fake_codecs);
611
612 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
613 auto offer = caller->CreateOfferAndSetAsLocal();
614 auto* offer_description =
615 cricket::GetFirstVideoContentDescription(offer->description());
616 for (const auto& codec : offer_description->codecs()) {
617 EXPECT_EQ(codec.packetization, absl::nullopt);
618 }
619}
620
621// Test that raw packetization is set in the offer and answer for all
622// video payload when raw_packetization_for_video is true.
623TEST_P(PeerConnectionMediaTest, RawPacketizationSetInOfferAndAnswer) {
624 std::vector<cricket::VideoCodec> fake_codecs;
Florent Castelli8c4b9ea2023-06-02 16:06:57625 fake_codecs.push_back(cricket::CreateVideoCodec(111, cricket::kVp8CodecName));
Florent Castellid0b8e8e2023-06-04 23:22:36626 fake_codecs.push_back(cricket::CreateVideoRtxCodec(112, 111));
Florent Castelli8c4b9ea2023-06-02 16:06:57627 fake_codecs.push_back(cricket::CreateVideoCodec(113, cricket::kVp9CodecName));
628 fake_codecs.push_back(
629 cricket::CreateVideoCodec(114, cricket::kH264CodecName));
630 fake_codecs.push_back(cricket::CreateVideoCodec(115, "HEVC"));
Mirko Bonadei317a1f02019-09-17 15:06:18631 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 13:38:50632 caller_fake_engine->SetVideoCodecs(fake_codecs);
Mirko Bonadei317a1f02019-09-17 15:06:18633 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 13:38:50634 callee_fake_engine->SetVideoCodecs(fake_codecs);
635
636 RTCOfferAnswerOptions options;
637 options.raw_packetization_for_video = true;
638
639 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
640 auto offer = caller->CreateOfferAndSetAsLocal(options);
641 auto* offer_description =
642 cricket::GetFirstVideoContentDescription(offer->description());
643 for (const auto& codec : offer_description->codecs()) {
Florent Castelli811e24a2023-05-31 12:35:47644 if (codec.IsMediaCodec()) {
Mirta Dvornicic479a3c02019-06-04 13:38:50645 EXPECT_EQ(codec.packetization, cricket::kPacketizationParamRaw);
646 }
647 }
648
649 auto callee = CreatePeerConnectionWithVideo(std::move(callee_fake_engine));
650 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
651 auto answer = callee->CreateAnswerAndSetAsLocal(options);
652 auto* answer_description =
653 cricket::GetFirstVideoContentDescription(answer->description());
654 for (const auto& codec : answer_description->codecs()) {
Florent Castelli811e24a2023-05-31 12:35:47655 if (codec.IsMediaCodec()) {
Mirta Dvornicic479a3c02019-06-04 13:38:50656 EXPECT_EQ(codec.packetization, cricket::kPacketizationParamRaw);
657 }
658 }
659
660 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
661}
662
663// Test that raw packetization is not set in the answer when
664// raw_packetization_for_video is true if it was not set in the offer.
665TEST_P(PeerConnectionMediaTest,
666 RawPacketizationNotSetInAnswerWhenNotSetInOffer) {
667 std::vector<cricket::VideoCodec> fake_codecs;
Florent Castelli8c4b9ea2023-06-02 16:06:57668 fake_codecs.push_back(cricket::CreateVideoCodec(111, cricket::kVp8CodecName));
Florent Castellid0b8e8e2023-06-04 23:22:36669 fake_codecs.push_back(cricket::CreateVideoRtxCodec(112, 111));
Florent Castelli8c4b9ea2023-06-02 16:06:57670 fake_codecs.push_back(cricket::CreateVideoCodec(113, cricket::kVp9CodecName));
671 fake_codecs.push_back(
672 cricket::CreateVideoCodec(114, cricket::kH264CodecName));
673 fake_codecs.push_back(cricket::CreateVideoCodec(115, "HEVC"));
Mirko Bonadei317a1f02019-09-17 15:06:18674 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 13:38:50675 caller_fake_engine->SetVideoCodecs(fake_codecs);
Mirko Bonadei317a1f02019-09-17 15:06:18676 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
Mirta Dvornicic479a3c02019-06-04 13:38:50677 callee_fake_engine->SetVideoCodecs(fake_codecs);
678
679 RTCOfferAnswerOptions caller_options;
680 caller_options.raw_packetization_for_video = false;
681 RTCOfferAnswerOptions callee_options;
682 callee_options.raw_packetization_for_video = true;
683
684 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
685 auto offer = caller->CreateOfferAndSetAsLocal(caller_options);
686
687 auto callee = CreatePeerConnectionWithVideo(std::move(callee_fake_engine));
688 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
689 auto answer = callee->CreateAnswerAndSetAsLocal(callee_options);
690
691 auto* answer_description =
692 cricket::GetFirstVideoContentDescription(answer->description());
693 for (const auto& codec : answer_description->codecs()) {
694 EXPECT_EQ(codec.packetization, absl::nullopt);
695 }
696
697 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
698}
699
Steve Anton8d3444d2017-10-20 22:30:51700class PeerConnectionMediaOfferDirectionTest
Steve Antonad7bffc2018-01-22 18:21:56701 : public PeerConnectionMediaBaseTest,
Steve Anton8d3444d2017-10-20 22:30:51702 public ::testing::WithParamInterface<
Steve Antonad7bffc2018-01-22 18:21:56703 std::tuple<SdpSemantics,
704 std::tuple<bool, int, RtpTransceiverDirection>>> {
Steve Anton8d3444d2017-10-20 22:30:51705 protected:
Steve Antonad7bffc2018-01-22 18:21:56706 PeerConnectionMediaOfferDirectionTest()
707 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
708 auto param = std::get<1>(GetParam());
709 send_media_ = std::get<0>(param);
710 offer_to_receive_ = std::get<1>(param);
711 expected_direction_ = std::get<2>(param);
Steve Anton8d3444d2017-10-20 22:30:51712 }
713
714 bool send_media_;
715 int offer_to_receive_;
Steve Anton4e70a722017-11-28 22:57:10716 RtpTransceiverDirection expected_direction_;
Steve Anton8d3444d2017-10-20 22:30:51717};
718
719// Tests that the correct direction is set on the media description according
720// to the presence of a local media track and the offer_to_receive setting.
721TEST_P(PeerConnectionMediaOfferDirectionTest, VerifyDirection) {
722 auto caller = CreatePeerConnection();
723 if (send_media_) {
724 caller->AddAudioTrack("a");
725 }
726
727 RTCOfferAnswerOptions options;
728 options.offer_to_receive_audio = offer_to_receive_;
729 auto offer = caller->CreateOffer(options);
730
Steve Antonad7bffc2018-01-22 18:21:56731 auto* content = cricket::GetFirstMediaContent(offer->description(),
732 cricket::MEDIA_TYPE_AUDIO);
Steve Anton4e70a722017-11-28 22:57:10733 if (expected_direction_ == RtpTransceiverDirection::kInactive) {
Steve Antonad7bffc2018-01-22 18:21:56734 EXPECT_FALSE(content);
Steve Anton8d3444d2017-10-20 22:30:51735 } else {
Steve Antonad7bffc2018-01-22 18:21:56736 EXPECT_EQ(expected_direction_, content->media_description()->direction());
Steve Anton8d3444d2017-10-20 22:30:51737 }
738}
739
740// Note that in these tests, MD_INACTIVE indicates that no media section is
741// included in the offer, not that the media direction is inactive.
Mirko Bonadeic84f6612019-01-31 11:20:57742INSTANTIATE_TEST_SUITE_P(
Steve Anton4e70a722017-11-28 22:57:10743 PeerConnectionMediaTest,
744 PeerConnectionMediaOfferDirectionTest,
Steve Antonad7bffc2018-01-22 18:21:56745 Combine(
Florent Castelli15a38de2022-04-05 22:38:21746 Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan),
Steve Antonad7bffc2018-01-22 18:21:56747 Values(std::make_tuple(false, -1, RtpTransceiverDirection::kInactive),
748 std::make_tuple(false, 0, RtpTransceiverDirection::kInactive),
749 std::make_tuple(false, 1, RtpTransceiverDirection::kRecvOnly),
750 std::make_tuple(true, -1, RtpTransceiverDirection::kSendRecv),
751 std::make_tuple(true, 0, RtpTransceiverDirection::kSendOnly),
752 std::make_tuple(true, 1, RtpTransceiverDirection::kSendRecv))));
Steve Anton8d3444d2017-10-20 22:30:51753
754class PeerConnectionMediaAnswerDirectionTest
Steve Antonad7bffc2018-01-22 18:21:56755 : public PeerConnectionMediaBaseTest,
Steve Anton8d3444d2017-10-20 22:30:51756 public ::testing::WithParamInterface<
Steve Antonad7bffc2018-01-22 18:21:56757 std::tuple<SdpSemantics, RtpTransceiverDirection, bool, int>> {
Steve Anton8d3444d2017-10-20 22:30:51758 protected:
Steve Antonad7bffc2018-01-22 18:21:56759 PeerConnectionMediaAnswerDirectionTest()
760 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
761 offer_direction_ = std::get<1>(GetParam());
762 send_media_ = std::get<2>(GetParam());
763 offer_to_receive_ = std::get<3>(GetParam());
Steve Anton8d3444d2017-10-20 22:30:51764 }
765
Steve Anton4e70a722017-11-28 22:57:10766 RtpTransceiverDirection offer_direction_;
Steve Anton8d3444d2017-10-20 22:30:51767 bool send_media_;
768 int offer_to_receive_;
769};
770
771// Tests that the direction in an answer is correct according to direction sent
772// in the offer, the presence of a local media track on the receive side and the
773// offer_to_receive setting.
774TEST_P(PeerConnectionMediaAnswerDirectionTest, VerifyDirection) {
Steve Anton22da89f2018-01-25 21:58:07775 if (IsUnifiedPlan() &&
776 offer_to_receive_ != RTCOfferAnswerOptions::kUndefined) {
777 // offer_to_receive_ is not implemented when creating answers with Unified
778 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 18:21:56779 return;
780 }
Steve Anton22da89f2018-01-25 21:58:07781
Steve Anton8d3444d2017-10-20 22:30:51782 auto caller = CreatePeerConnection();
783 caller->AddAudioTrack("a");
784
785 // Create the offer with an audio section and set its direction.
786 auto offer = caller->CreateOffer();
787 cricket::GetFirstAudioContentDescription(offer->description())
788 ->set_direction(offer_direction_);
789
790 auto callee = CreatePeerConnection();
791 if (send_media_) {
792 callee->AddAudioTrack("a");
793 }
794 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
795
796 // Create the answer according to the test parameters.
797 RTCOfferAnswerOptions options;
798 options.offer_to_receive_audio = offer_to_receive_;
799 auto answer = callee->CreateAnswer(options);
800
801 // The expected direction in the answer is the intersection of each side's
802 // capability to send/recv media.
803 // For the offerer, the direction is given in the offer (offer_direction_).
804 // For the answerer, the direction has two components:
805 // 1. Send if the answerer has a local track to send.
806 // 2. Receive if the answerer has explicitly set the offer_to_receive to 1 or
807 // if it has been left as default.
Steve Anton4e70a722017-11-28 22:57:10808 bool offer_send = RtpTransceiverDirectionHasSend(offer_direction_);
809 bool offer_recv = RtpTransceiverDirectionHasRecv(offer_direction_);
Steve Anton8d3444d2017-10-20 22:30:51810
811 // The negotiated components determine the direction set in the answer.
Steve Anton1d03a752017-11-27 22:30:09812 bool negotiate_send = (send_media_ && offer_recv);
813 bool negotiate_recv = ((offer_to_receive_ != 0) && offer_send);
Steve Anton8d3444d2017-10-20 22:30:51814
815 auto expected_direction =
Steve Anton4e70a722017-11-28 22:57:10816 RtpTransceiverDirectionFromSendRecv(negotiate_send, negotiate_recv);
Steve Anton8d3444d2017-10-20 22:30:51817 EXPECT_EQ(expected_direction,
Steve Antonad7bffc2018-01-22 18:21:56818 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton8d3444d2017-10-20 22:30:51819}
820
821// Tests that the media section is rejected if and only if the callee has no
822// local media track and has set offer_to_receive to 0, no matter which
823// direction the caller indicated in the offer.
824TEST_P(PeerConnectionMediaAnswerDirectionTest, VerifyRejected) {
Steve Anton22da89f2018-01-25 21:58:07825 if (IsUnifiedPlan() &&
826 offer_to_receive_ != RTCOfferAnswerOptions::kUndefined) {
827 // offer_to_receive_ is not implemented when creating answers with Unified
828 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 18:21:56829 return;
830 }
Steve Anton22da89f2018-01-25 21:58:07831
Steve Anton8d3444d2017-10-20 22:30:51832 auto caller = CreatePeerConnection();
833 caller->AddAudioTrack("a");
834
835 // Create the offer with an audio section and set its direction.
836 auto offer = caller->CreateOffer();
837 cricket::GetFirstAudioContentDescription(offer->description())
838 ->set_direction(offer_direction_);
839
840 auto callee = CreatePeerConnection();
841 if (send_media_) {
842 callee->AddAudioTrack("a");
843 }
844 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
845
846 // Create the answer according to the test parameters.
847 RTCOfferAnswerOptions options;
848 options.offer_to_receive_audio = offer_to_receive_;
849 auto answer = callee->CreateAnswer(options);
850
851 // The media section is rejected if and only if offer_to_receive is explicitly
852 // set to 0 and there is no media to send.
853 auto* audio_content = cricket::GetFirstAudioContent(answer->description());
854 ASSERT_TRUE(audio_content);
855 EXPECT_EQ((offer_to_receive_ == 0 && !send_media_), audio_content->rejected);
856}
857
Mirko Bonadeic84f6612019-01-31 11:20:57858INSTANTIATE_TEST_SUITE_P(PeerConnectionMediaTest,
859 PeerConnectionMediaAnswerDirectionTest,
Florent Castelli15a38de2022-04-05 22:38:21860 Combine(Values(SdpSemantics::kPlanB_DEPRECATED,
Mirko Bonadeic84f6612019-01-31 11:20:57861 SdpSemantics::kUnifiedPlan),
862 Values(RtpTransceiverDirection::kInactive,
863 RtpTransceiverDirection::kSendOnly,
864 RtpTransceiverDirection::kRecvOnly,
865 RtpTransceiverDirection::kSendRecv),
866 Bool(),
867 Values(-1, 0, 1)));
Steve Anton8d3444d2017-10-20 22:30:51868
Steve Antonad7bffc2018-01-22 18:21:56869TEST_P(PeerConnectionMediaTest, OfferHasDifferentDirectionForAudioVideo) {
Steve Anton8d3444d2017-10-20 22:30:51870 auto caller = CreatePeerConnection();
871 caller->AddVideoTrack("v");
872
873 RTCOfferAnswerOptions options;
874 options.offer_to_receive_audio = 1;
875 options.offer_to_receive_video = 0;
876 auto offer = caller->CreateOffer(options);
877
Steve Anton4e70a722017-11-28 22:57:10878 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
Steve Antonad7bffc2018-01-22 18:21:56879 GetMediaContentDirection(offer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton4e70a722017-11-28 22:57:10880 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
Steve Antonad7bffc2018-01-22 18:21:56881 GetMediaContentDirection(offer.get(), cricket::MEDIA_TYPE_VIDEO));
Steve Anton8d3444d2017-10-20 22:30:51882}
883
Steve Antonad7bffc2018-01-22 18:21:56884TEST_P(PeerConnectionMediaTest, AnswerHasDifferentDirectionsForAudioVideo) {
Steve Antonad7bffc2018-01-22 18:21:56885 if (IsUnifiedPlan()) {
Steve Anton22da89f2018-01-25 21:58:07886 // offer_to_receive_ is not implemented when creating answers with Unified
887 // Plan semantics specified.
Steve Antonad7bffc2018-01-22 18:21:56888 return;
889 }
890
Steve Anton8d3444d2017-10-20 22:30:51891 auto caller = CreatePeerConnectionWithAudioVideo();
892 auto callee = CreatePeerConnection();
893 callee->AddVideoTrack("v");
894
895 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
896
897 RTCOfferAnswerOptions options;
898 options.offer_to_receive_audio = 1;
899 options.offer_to_receive_video = 0;
900 auto answer = callee->CreateAnswer(options);
901
Steve Anton4e70a722017-11-28 22:57:10902 EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
Steve Antonad7bffc2018-01-22 18:21:56903 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_AUDIO));
Steve Anton4e70a722017-11-28 22:57:10904 EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
Steve Antonad7bffc2018-01-22 18:21:56905 GetMediaContentDirection(answer.get(), cricket::MEDIA_TYPE_VIDEO));
Steve Anton8d3444d2017-10-20 22:30:51906}
907
908void AddComfortNoiseCodecsToSend(cricket::FakeMediaEngine* media_engine) {
Florent Castelli8c4b9ea2023-06-02 16:06:57909 const cricket::AudioCodec kComfortNoiseCodec8k =
910 cricket::CreateAudioCodec(102, cricket::kCnCodecName, 8000, 1);
911 const cricket::AudioCodec kComfortNoiseCodec16k =
912 cricket::CreateAudioCodec(103, cricket::kCnCodecName, 16000, 1);
Steve Anton8d3444d2017-10-20 22:30:51913
Sebastian Jansson6eb8a162018-11-16 10:29:55914 auto codecs = media_engine->voice().send_codecs();
Steve Anton8d3444d2017-10-20 22:30:51915 codecs.push_back(kComfortNoiseCodec8k);
916 codecs.push_back(kComfortNoiseCodec16k);
917 media_engine->SetAudioCodecs(codecs);
918}
919
920bool HasAnyComfortNoiseCodecs(const cricket::SessionDescription* desc) {
921 const auto* audio_desc = cricket::GetFirstAudioContentDescription(desc);
922 for (const auto& codec : audio_desc->codecs()) {
Philipp Hancke8498c252020-06-05 11:28:57923 if (codec.name == cricket::kCnCodecName) {
Steve Anton8d3444d2017-10-20 22:30:51924 return true;
925 }
926 }
927 return false;
928}
929
Taylor Brandstetterf7fcfb72021-09-09 20:39:38930bool HasPayloadTypeConflict(const cricket::SessionDescription* desc) {
931 std::set<int> payload_types;
932 const auto* audio_desc = cricket::GetFirstAudioContentDescription(desc);
933 if (audio_desc) {
934 for (const auto& codec : audio_desc->codecs()) {
935 if (payload_types.count(codec.id) > 0) {
936 return true;
937 }
938 payload_types.insert(codec.id);
939 }
940 }
941 const auto* video_desc = cricket::GetFirstVideoContentDescription(desc);
942 if (video_desc) {
943 for (const auto& codec : video_desc->codecs()) {
944 if (payload_types.count(codec.id) > 0) {
945 return true;
946 }
947 payload_types.insert(codec.id);
948 }
949 }
950 return false;
951}
952
Steve Antonad7bffc2018-01-22 18:21:56953TEST_P(PeerConnectionMediaTest,
Steve Anton8d3444d2017-10-20 22:30:51954 CreateOfferWithNoVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
Philipp Hancke718acf62021-05-12 12:18:03955 auto fake_engine = std::make_unique<FakeMediaEngine>();
956 AddComfortNoiseCodecsToSend(fake_engine.get());
957 auto caller = CreatePeerConnectionWithAudioVideo(std::move(fake_engine));
Steve Anton8d3444d2017-10-20 22:30:51958
959 RTCOfferAnswerOptions options;
960 options.voice_activity_detection = false;
961 auto offer = caller->CreateOffer(options);
962
963 EXPECT_FALSE(HasAnyComfortNoiseCodecs(offer->description()));
964}
965
Steve Antonad7bffc2018-01-22 18:21:56966TEST_P(PeerConnectionMediaTest,
Philipp Hancke718acf62021-05-12 12:18:03967 CreateOfferWithVoiceActivityDetectionIncludesComfortNoiseCodecs) {
968 auto fake_engine = std::make_unique<FakeMediaEngine>();
969 AddComfortNoiseCodecsToSend(fake_engine.get());
970 auto caller = CreatePeerConnectionWithAudioVideo(std::move(fake_engine));
971
972 RTCOfferAnswerOptions options;
973 options.voice_activity_detection = true;
974 auto offer = caller->CreateOffer(options);
975
976 EXPECT_TRUE(HasAnyComfortNoiseCodecs(offer->description()));
977}
978
979TEST_P(PeerConnectionMediaTest,
980 CreateAnswerWithVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
Steve Anton8d3444d2017-10-20 22:30:51981 auto caller = CreatePeerConnectionWithAudioVideo();
Philipp Hancke718acf62021-05-12 12:18:03982
983 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
984 AddComfortNoiseCodecsToSend(callee_fake_engine.get());
985 auto callee =
986 CreatePeerConnectionWithAudioVideo(std::move(callee_fake_engine));
987
988 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
989
990 RTCOfferAnswerOptions options;
991 options.voice_activity_detection = true;
992 auto answer = callee->CreateAnswer(options);
993
994 EXPECT_FALSE(HasAnyComfortNoiseCodecs(answer->description()));
995}
996
997TEST_P(PeerConnectionMediaTest,
998 CreateAnswerWithNoVoiceActivityDetectionIncludesNoComfortNoiseCodecs) {
999 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
1000 AddComfortNoiseCodecsToSend(caller_fake_engine.get());
1001 auto caller =
1002 CreatePeerConnectionWithAudioVideo(std::move(caller_fake_engine));
1003
1004 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
1005 AddComfortNoiseCodecsToSend(callee_fake_engine.get());
1006 auto callee =
1007 CreatePeerConnectionWithAudioVideo(std::move(callee_fake_engine));
Steve Anton8d3444d2017-10-20 22:30:511008
1009 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1010
1011 RTCOfferAnswerOptions options;
1012 options.voice_activity_detection = false;
1013 auto answer = callee->CreateAnswer(options);
1014
1015 EXPECT_FALSE(HasAnyComfortNoiseCodecs(answer->description()));
1016}
1017
1018// The following test group verifies that we reject answers with invalid media
1019// sections as per RFC 3264.
1020
1021class PeerConnectionMediaInvalidMediaTest
Steve Antonad7bffc2018-01-22 18:21:561022 : public PeerConnectionMediaBaseTest,
1023 public ::testing::WithParamInterface<std::tuple<
1024 SdpSemantics,
Steve Anton8d3444d2017-10-20 22:30:511025 std::tuple<std::string,
1026 std::function<void(cricket::SessionDescription*)>,
Steve Antonad7bffc2018-01-22 18:21:561027 std::string>>> {
Steve Anton8d3444d2017-10-20 22:30:511028 protected:
Steve Antonad7bffc2018-01-22 18:21:561029 PeerConnectionMediaInvalidMediaTest()
1030 : PeerConnectionMediaBaseTest(std::get<0>(GetParam())) {
1031 auto param = std::get<1>(GetParam());
1032 mutator_ = std::get<1>(param);
1033 expected_error_ = std::get<2>(param);
Steve Anton8d3444d2017-10-20 22:30:511034 }
1035
1036 std::function<void(cricket::SessionDescription*)> mutator_;
1037 std::string expected_error_;
1038};
1039
1040TEST_P(PeerConnectionMediaInvalidMediaTest, FailToSetRemoteAnswer) {
1041 auto caller = CreatePeerConnectionWithAudioVideo();
1042 auto callee = CreatePeerConnectionWithAudioVideo();
1043
1044 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1045
1046 auto answer = callee->CreateAnswer();
1047 mutator_(answer->description());
1048
1049 std::string error;
1050 ASSERT_FALSE(caller->SetRemoteDescription(std::move(answer), &error));
1051 EXPECT_EQ("Failed to set remote answer sdp: " + expected_error_, error);
1052}
1053
1054TEST_P(PeerConnectionMediaInvalidMediaTest, FailToSetLocalAnswer) {
1055 auto caller = CreatePeerConnectionWithAudioVideo();
1056 auto callee = CreatePeerConnectionWithAudioVideo();
1057
1058 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1059
1060 auto answer = callee->CreateAnswer();
1061 mutator_(answer->description());
1062
1063 std::string error;
1064 ASSERT_FALSE(callee->SetLocalDescription(std::move(answer), &error));
1065 EXPECT_EQ("Failed to set local answer sdp: " + expected_error_, error);
1066}
1067
Philipp Hancke4bf52382023-05-25 14:11:361068void RemoveVideoContentAndUnbundle(cricket::SessionDescription* desc) {
1069 // Removing BUNDLE is easier than removing the content in there.
1070 desc->RemoveGroupByName("BUNDLE");
Steve Anton8d3444d2017-10-20 22:30:511071 auto content_name = cricket::GetFirstVideoContent(desc)->name;
1072 desc->RemoveContentByName(content_name);
1073 desc->RemoveTransportInfoByName(content_name);
1074}
1075
Philipp Hancke4bf52382023-05-25 14:11:361076void RenameVideoContentAndUnbundle(cricket::SessionDescription* desc) {
1077 // Removing BUNDLE is easier than renaming the content in there.
1078 desc->RemoveGroupByName("BUNDLE");
Steve Anton8d3444d2017-10-20 22:30:511079 auto* video_content = cricket::GetFirstVideoContent(desc);
1080 auto* transport_info = desc->GetTransportInfoByName(video_content->name);
1081 video_content->name = "video_renamed";
1082 transport_info->content_name = video_content->name;
1083}
1084
1085void ReverseMediaContent(cricket::SessionDescription* desc) {
Steve Anton64b626b2019-01-29 01:25:261086 absl::c_reverse(desc->contents());
1087 absl::c_reverse(desc->transport_infos());
Steve Anton8d3444d2017-10-20 22:30:511088}
1089
1090void ChangeMediaTypeAudioToVideo(cricket::SessionDescription* desc) {
Steve Antonad7bffc2018-01-22 18:21:561091 std::string audio_mid = cricket::GetFirstAudioContent(desc)->name;
1092 desc->RemoveContentByName(audio_mid);
1093 auto* video_content = cricket::GetFirstVideoContent(desc);
1094 desc->AddContent(audio_mid, video_content->type,
Harald Alvestrand1716d392019-06-03 18:35:451095 video_content->media_description()->Clone());
Steve Anton8d3444d2017-10-20 22:30:511096}
1097
1098constexpr char kMLinesOutOfOrder[] =
1099 "The order of m-lines in answer doesn't match order in offer. Rejecting "
1100 "answer.";
1101
Mirko Bonadeic84f6612019-01-31 11:20:571102INSTANTIATE_TEST_SUITE_P(
Steve Anton8d3444d2017-10-20 22:30:511103 PeerConnectionMediaTest,
1104 PeerConnectionMediaInvalidMediaTest,
Florent Castelli15a38de2022-04-05 22:38:211105 Combine(Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan),
Steve Antonad7bffc2018-01-22 18:21:561106 Values(std::make_tuple("remove video",
Philipp Hancke4bf52382023-05-25 14:11:361107 RemoveVideoContentAndUnbundle,
Steve Antonad7bffc2018-01-22 18:21:561108 kMLinesOutOfOrder),
1109 std::make_tuple("rename video",
Philipp Hancke4bf52382023-05-25 14:11:361110 RenameVideoContentAndUnbundle,
Steve Antonad7bffc2018-01-22 18:21:561111 kMLinesOutOfOrder),
1112 std::make_tuple("reverse media sections",
1113 ReverseMediaContent,
1114 kMLinesOutOfOrder),
1115 std::make_tuple("change audio type to video type",
1116 ChangeMediaTypeAudioToVideo,
1117 kMLinesOutOfOrder))));
Steve Anton8d3444d2017-10-20 22:30:511118
Steve Anton8d3444d2017-10-20 22:30:511119// Tests that if the underlying video encoder fails to be initialized (signaled
1120// by failing to set send codecs), the PeerConnection signals the error to the
1121// client.
Florent Castelli1f31c202023-06-26 00:26:071122TEST_F(PeerConnectionMediaTestUnifiedPlan,
1123 MediaEngineErrorPropagatedToClients) {
Steve Anton8d3444d2017-10-20 22:30:511124 auto caller = CreatePeerConnectionWithAudioVideo();
1125 auto callee = CreatePeerConnectionWithAudioVideo();
1126
1127 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1128
Florent Castelli1f31c202023-06-26 00:26:071129 auto video_channel =
1130 VideoMediaSendChannel(caller->pc()->GetTransceivers()[1]);
Steve Anton8d3444d2017-10-20 22:30:511131 video_channel->set_fail_set_send_codecs(true);
1132
1133 std::string error;
1134 ASSERT_FALSE(caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal(),
1135 &error));
Yura Yaroshevichbc1f9102020-06-03 21:15:221136 EXPECT_EQ(std::string("Failed to set remote answer sdp: Failed to set remote "
1137 "video description "
1138 "send parameters for m-section with mid='") +
1139 (IsUnifiedPlan() ? "1" : "video") + "'.",
1140 error);
Steve Anton8d3444d2017-10-20 22:30:511141}
1142
1143// Tests that if the underlying video encoder fails once then subsequent
1144// attempts at setting the local/remote description will also fail, even if
1145// SetSendCodecs no longer fails.
Florent Castelli1f31c202023-06-26 00:26:071146TEST_F(PeerConnectionMediaTestUnifiedPlan,
Steve Anton8d3444d2017-10-20 22:30:511147 FailToApplyDescriptionIfVideoEncoderHasEverFailed) {
1148 auto caller = CreatePeerConnectionWithAudioVideo();
1149 auto callee = CreatePeerConnectionWithAudioVideo();
1150
1151 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1152
Florent Castelli1f31c202023-06-26 00:26:071153 auto video_channel =
1154 VideoMediaSendChannel(caller->pc()->GetTransceivers()[1]);
Steve Anton8d3444d2017-10-20 22:30:511155 video_channel->set_fail_set_send_codecs(true);
1156
1157 EXPECT_FALSE(
1158 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1159
1160 video_channel->set_fail_set_send_codecs(false);
1161
1162 EXPECT_FALSE(caller->SetRemoteDescription(callee->CreateAnswer()));
1163 EXPECT_FALSE(caller->SetLocalDescription(caller->CreateOffer()));
1164}
1165
1166void RenameContent(cricket::SessionDescription* desc,
Steve Antonad7bffc2018-01-22 18:21:561167 cricket::MediaType media_type,
Steve Anton8d3444d2017-10-20 22:30:511168 const std::string& new_name) {
Steve Antonad7bffc2018-01-22 18:21:561169 auto* content = cricket::GetFirstMediaContent(desc, media_type);
Steve Anton8d3444d2017-10-20 22:30:511170 RTC_DCHECK(content);
Steve Antonad7bffc2018-01-22 18:21:561171 std::string old_name = content->name;
Steve Anton8d3444d2017-10-20 22:30:511172 content->name = new_name;
1173 auto* transport = desc->GetTransportInfoByName(old_name);
1174 RTC_DCHECK(transport);
1175 transport->content_name = new_name;
Zhi Huangd2248f82018-04-10 21:41:031176
1177 // Rename the content name in the BUNDLE group.
1178 cricket::ContentGroup new_bundle_group =
1179 *desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
1180 new_bundle_group.RemoveContentName(old_name);
1181 new_bundle_group.AddContentName(new_name);
1182 desc->RemoveGroupByName(cricket::GROUP_TYPE_BUNDLE);
1183 desc->AddGroup(new_bundle_group);
Steve Anton8d3444d2017-10-20 22:30:511184}
1185
1186// Tests that an answer responds with the same MIDs as the offer.
Steve Antonad7bffc2018-01-22 18:21:561187TEST_P(PeerConnectionMediaTest, AnswerHasSameMidsAsOffer) {
Zhi Huang365381f2018-04-13 23:44:341188 const std::string kAudioMid = "notdefault1";
1189 const std::string kVideoMid = "notdefault2";
Steve Anton8d3444d2017-10-20 22:30:511190
1191 auto caller = CreatePeerConnectionWithAudioVideo();
1192 auto callee = CreatePeerConnectionWithAudioVideo();
1193
1194 auto offer = caller->CreateOffer();
Steve Antonad7bffc2018-01-22 18:21:561195 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, kAudioMid);
1196 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, kVideoMid);
Steve Anton8d3444d2017-10-20 22:30:511197 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1198
1199 auto answer = callee->CreateAnswer();
1200 EXPECT_EQ(kAudioMid,
1201 cricket::GetFirstAudioContent(answer->description())->name);
1202 EXPECT_EQ(kVideoMid,
1203 cricket::GetFirstVideoContent(answer->description())->name);
1204}
1205
1206// Test that if the callee creates a re-offer, the MIDs are the same as the
1207// original offer.
Steve Antonad7bffc2018-01-22 18:21:561208TEST_P(PeerConnectionMediaTest, ReOfferHasSameMidsAsFirstOffer) {
Zhi Huang365381f2018-04-13 23:44:341209 const std::string kAudioMid = "notdefault1";
1210 const std::string kVideoMid = "notdefault2";
Steve Anton8d3444d2017-10-20 22:30:511211
1212 auto caller = CreatePeerConnectionWithAudioVideo();
1213 auto callee = CreatePeerConnectionWithAudioVideo();
1214
1215 auto offer = caller->CreateOffer();
Steve Antonad7bffc2018-01-22 18:21:561216 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, kAudioMid);
1217 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, kVideoMid);
Steve Anton8d3444d2017-10-20 22:30:511218 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1219 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
1220
1221 auto reoffer = callee->CreateOffer();
1222 EXPECT_EQ(kAudioMid,
1223 cricket::GetFirstAudioContent(reoffer->description())->name);
1224 EXPECT_EQ(kVideoMid,
1225 cricket::GetFirstVideoContent(reoffer->description())->name);
1226}
1227
Steve Anton06817cd2018-12-18 23:55:301228// Test that SetRemoteDescription returns an error if there are two m= sections
1229// with the same MID value.
1230TEST_P(PeerConnectionMediaTest, SetRemoteDescriptionFailsWithDuplicateMids) {
1231 auto caller = CreatePeerConnectionWithAudioVideo();
1232 auto callee = CreatePeerConnectionWithAudioVideo();
1233
1234 auto offer = caller->CreateOffer();
1235 RenameContent(offer->description(), cricket::MEDIA_TYPE_AUDIO, "same");
1236 RenameContent(offer->description(), cricket::MEDIA_TYPE_VIDEO, "same");
1237
1238 std::string error;
1239 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer), &error));
1240 EXPECT_EQ(error,
1241 "Failed to set remote offer sdp: Duplicate a=mid value 'same'.");
1242}
1243
Philipp Hancke7145a142021-09-28 05:46:061244// Test that if a RED codec refers to another codec in its fmtp line, but that
1245// codec's payload type was reassigned for some reason (either the remote
1246// endpoint selected a different payload type or there was a conflict), the RED
1247// fmtp line is modified to refer to the correct payload type.
1248TEST_P(PeerConnectionMediaTest, RedFmtpPayloadTypeReassigned) {
1249 std::vector<cricket::AudioCodec> caller_fake_codecs;
Florent Castelli8c4b9ea2023-06-02 16:06:571250 caller_fake_codecs.push_back(cricket::CreateAudioCodec(100, "foo", 0, 1));
Philipp Hancke7145a142021-09-28 05:46:061251 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
1252 caller_fake_engine->SetAudioCodecs(caller_fake_codecs);
1253 auto caller = CreatePeerConnectionWithAudio(std::move(caller_fake_engine));
1254
1255 std::vector<cricket::AudioCodec> callee_fake_codecs;
Florent Castelli8c4b9ea2023-06-02 16:06:571256 callee_fake_codecs.push_back(cricket::CreateAudioCodec(120, "foo", 0, 1));
Philipp Hancke7145a142021-09-28 05:46:061257 callee_fake_codecs.push_back(
Florent Castelli8c4b9ea2023-06-02 16:06:571258 cricket::CreateAudioCodec(121, cricket::kRedCodecName, 0, 1));
Philipp Hancke7145a142021-09-28 05:46:061259 callee_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1260 "120/120");
1261 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
1262 callee_fake_engine->SetAudioCodecs(callee_fake_codecs);
1263 auto callee = CreatePeerConnectionWithAudio(std::move(callee_fake_engine));
1264
1265 // Offer from the caller establishes 100 as the "foo" payload type.
1266 auto offer = caller->CreateOfferAndSetAsLocal();
1267 callee->SetRemoteDescription(std::move(offer));
1268 auto answer = callee->CreateAnswerAndSetAsLocal();
1269 auto answer_description =
1270 cricket::GetFirstAudioContentDescription(answer->description());
1271 ASSERT_EQ(1u, answer_description->codecs().size());
1272
1273 // Offer from the callee should respect the established payload type, and
1274 // attempt to add RED, which should refer to the correct payload type.
1275 offer = callee->CreateOfferAndSetAsLocal();
1276 auto* offer_description =
1277 cricket::GetFirstAudioContentDescription(offer->description());
1278 ASSERT_EQ(2u, offer_description->codecs().size());
1279 for (const auto& codec : offer_description->codecs()) {
1280 if (codec.name == "foo") {
1281 ASSERT_EQ(100, codec.id);
1282 } else if (codec.name == cricket::kRedCodecName) {
1283 std::string fmtp;
1284 ASSERT_TRUE(codec.GetParam("", &fmtp));
1285 EXPECT_EQ("100/100", fmtp);
1286 }
1287 }
1288}
1289
1290// Test that RED without fmtp does match RED without fmtp.
1291TEST_P(PeerConnectionMediaTest, RedFmtpPayloadTypeNoFmtpMatchNoFmtp) {
1292 std::vector<cricket::AudioCodec> caller_fake_codecs;
Florent Castelli8c4b9ea2023-06-02 16:06:571293 caller_fake_codecs.push_back(cricket::CreateAudioCodec(100, "foo", 0, 1));
Philipp Hancke7145a142021-09-28 05:46:061294 caller_fake_codecs.push_back(
Florent Castelli8c4b9ea2023-06-02 16:06:571295 cricket::CreateAudioCodec(101, cricket::kRedCodecName, 0, 1));
Philipp Hancke7145a142021-09-28 05:46:061296 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
1297 caller_fake_engine->SetAudioCodecs(caller_fake_codecs);
1298 auto caller = CreatePeerConnectionWithAudio(std::move(caller_fake_engine));
1299
1300 std::vector<cricket::AudioCodec> callee_fake_codecs;
Florent Castelli8c4b9ea2023-06-02 16:06:571301 callee_fake_codecs.push_back(cricket::CreateAudioCodec(120, "foo", 0, 1));
Philipp Hancke7145a142021-09-28 05:46:061302 callee_fake_codecs.push_back(
Florent Castelli8c4b9ea2023-06-02 16:06:571303 cricket::CreateAudioCodec(121, cricket::kRedCodecName, 0, 1));
Philipp Hancke7145a142021-09-28 05:46:061304 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
1305 callee_fake_engine->SetAudioCodecs(callee_fake_codecs);
1306 auto callee = CreatePeerConnectionWithAudio(std::move(callee_fake_engine));
1307
1308 // Offer from the caller establishes 100 as the "foo" payload type.
1309 // Red (without fmtp) is negotiated.
1310 auto offer = caller->CreateOfferAndSetAsLocal();
1311 callee->SetRemoteDescription(std::move(offer));
1312 auto answer = callee->CreateAnswerAndSetAsLocal();
1313 auto answer_description =
1314 cricket::GetFirstAudioContentDescription(answer->description());
1315 ASSERT_EQ(2u, answer_description->codecs().size());
1316
1317 // Offer from the callee should respect the established payload type, and
1318 // attempt to add RED.
1319 offer = callee->CreateOfferAndSetAsLocal();
1320 auto* offer_description =
1321 cricket::GetFirstAudioContentDescription(offer->description());
1322 ASSERT_EQ(2u, offer_description->codecs().size());
1323 for (const auto& codec : offer_description->codecs()) {
1324 if (codec.name == "foo") {
1325 ASSERT_EQ(100, codec.id);
1326 } else if (codec.name == cricket::kRedCodecName) {
1327 ASSERT_EQ(101, codec.id);
1328 }
1329 }
1330}
1331
1332// Test that RED without fmtp does not match RED with fmtp.
1333TEST_P(PeerConnectionMediaTest, RedFmtpPayloadTypeNoFmtpNoMatchFmtp) {
1334 std::vector<cricket::AudioCodec> caller_fake_codecs;
Florent Castelli8c4b9ea2023-06-02 16:06:571335 caller_fake_codecs.push_back(cricket::CreateAudioCodec(100, "foo", 0, 1));
Philipp Hancke7145a142021-09-28 05:46:061336 caller_fake_codecs.push_back(
Florent Castelli8c4b9ea2023-06-02 16:06:571337 cricket::CreateAudioCodec(101, cricket::kRedCodecName, 0, 1));
Philipp Hancke7145a142021-09-28 05:46:061338 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
1339 caller_fake_engine->SetAudioCodecs(caller_fake_codecs);
1340 auto caller = CreatePeerConnectionWithAudio(std::move(caller_fake_engine));
1341
1342 std::vector<cricket::AudioCodec> callee_fake_codecs;
Florent Castelli8c4b9ea2023-06-02 16:06:571343 callee_fake_codecs.push_back(cricket::CreateAudioCodec(120, "foo", 0, 1));
Philipp Hancke7145a142021-09-28 05:46:061344 callee_fake_codecs.push_back(
Florent Castelli8c4b9ea2023-06-02 16:06:571345 cricket::CreateAudioCodec(121, cricket::kRedCodecName, 0, 1));
Philipp Hancke7145a142021-09-28 05:46:061346 callee_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1347 "120/120");
1348 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
1349 callee_fake_engine->SetAudioCodecs(callee_fake_codecs);
1350 auto callee = CreatePeerConnectionWithAudio(std::move(callee_fake_engine));
1351
1352 // Offer from the caller establishes 100 as the "foo" payload type.
1353 // It should not negotiate RED.
1354 auto offer = caller->CreateOfferAndSetAsLocal();
1355 callee->SetRemoteDescription(std::move(offer));
1356 auto answer = callee->CreateAnswerAndSetAsLocal();
1357 auto answer_description =
1358 cricket::GetFirstAudioContentDescription(answer->description());
1359 ASSERT_EQ(1u, answer_description->codecs().size());
1360
1361 // Offer from the callee should respect the established payload type, and
1362 // attempt to add RED, which should refer to the correct payload type.
1363 offer = callee->CreateOfferAndSetAsLocal();
1364 auto* offer_description =
1365 cricket::GetFirstAudioContentDescription(offer->description());
1366 ASSERT_EQ(2u, offer_description->codecs().size());
1367 for (const auto& codec : offer_description->codecs()) {
1368 if (codec.name == "foo") {
1369 ASSERT_EQ(100, codec.id);
1370 } else if (codec.name == cricket::kRedCodecName) {
1371 std::string fmtp;
1372 ASSERT_TRUE(
1373 codec.GetParam(cricket::kCodecParamNotInNameValueFormat, &fmtp));
1374 EXPECT_EQ("100/100", fmtp);
1375 }
1376 }
1377}
1378
1379// Test that RED with fmtp must match base codecs.
1380TEST_P(PeerConnectionMediaTest, RedFmtpPayloadTypeMustMatchBaseCodecs) {
1381 std::vector<cricket::AudioCodec> caller_fake_codecs;
Florent Castelli8c4b9ea2023-06-02 16:06:571382 caller_fake_codecs.push_back(cricket::CreateAudioCodec(100, "foo", 0, 1));
Philipp Hancke7145a142021-09-28 05:46:061383 caller_fake_codecs.push_back(
Florent Castelli8c4b9ea2023-06-02 16:06:571384 cricket::CreateAudioCodec(101, cricket::kRedCodecName, 0, 1));
Philipp Hancke7145a142021-09-28 05:46:061385 caller_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1386 "100/100");
1387 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
1388 caller_fake_engine->SetAudioCodecs(caller_fake_codecs);
1389 auto caller = CreatePeerConnectionWithAudio(std::move(caller_fake_engine));
1390
1391 std::vector<cricket::AudioCodec> callee_fake_codecs;
Florent Castelli8c4b9ea2023-06-02 16:06:571392 callee_fake_codecs.push_back(cricket::CreateAudioCodec(120, "foo", 0, 1));
Philipp Hancke7145a142021-09-28 05:46:061393 callee_fake_codecs.push_back(
Florent Castelli8c4b9ea2023-06-02 16:06:571394 cricket::CreateAudioCodec(121, cricket::kRedCodecName, 0, 1));
1395 callee_fake_codecs.push_back(cricket::CreateAudioCodec(122, "bar", 0, 1));
Philipp Hancke7145a142021-09-28 05:46:061396 callee_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1397 "122/122");
1398 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
1399 callee_fake_engine->SetAudioCodecs(callee_fake_codecs);
1400 auto callee = CreatePeerConnectionWithAudio(std::move(callee_fake_engine));
1401
1402 // Offer from the caller establishes 100 as the "foo" payload type.
1403 // It should not negotiate RED since RED is associated with foo, not bar.
1404 auto offer = caller->CreateOfferAndSetAsLocal();
1405 callee->SetRemoteDescription(std::move(offer));
1406 auto answer = callee->CreateAnswerAndSetAsLocal();
1407 auto answer_description =
1408 cricket::GetFirstAudioContentDescription(answer->description());
1409 ASSERT_EQ(1u, answer_description->codecs().size());
1410}
1411
1412// Test behaviour when the RED fmtp attempts to specify different codecs
1413// which is not supported.
1414TEST_P(PeerConnectionMediaTest, RedFmtpPayloadMixed) {
1415 std::vector<cricket::AudioCodec> caller_fake_codecs;
Florent Castelli8c4b9ea2023-06-02 16:06:571416 caller_fake_codecs.push_back(cricket::CreateAudioCodec(100, "foo", 0, 1));
1417 caller_fake_codecs.push_back(cricket::CreateAudioCodec(102, "bar", 0, 1));
Philipp Hancke7145a142021-09-28 05:46:061418 caller_fake_codecs.push_back(
Florent Castelli8c4b9ea2023-06-02 16:06:571419 cricket::CreateAudioCodec(101, cricket::kRedCodecName, 0, 1));
Philipp Hancke7145a142021-09-28 05:46:061420 caller_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1421 "100/102");
1422 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
1423 caller_fake_engine->SetAudioCodecs(caller_fake_codecs);
1424 auto caller = CreatePeerConnectionWithAudio(std::move(caller_fake_engine));
1425
1426 std::vector<cricket::AudioCodec> callee_fake_codecs;
Florent Castelli8c4b9ea2023-06-02 16:06:571427 callee_fake_codecs.push_back(cricket::CreateAudioCodec(120, "foo", 0, 1));
Philipp Hancke7145a142021-09-28 05:46:061428 callee_fake_codecs.push_back(
Florent Castelli8c4b9ea2023-06-02 16:06:571429 cricket::CreateAudioCodec(121, cricket::kRedCodecName, 0, 1));
Philipp Hancke7145a142021-09-28 05:46:061430 callee_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1431 "120/120");
1432 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
1433 callee_fake_engine->SetAudioCodecs(callee_fake_codecs);
1434 auto callee = CreatePeerConnectionWithAudio(std::move(callee_fake_engine));
1435
1436 // Offer from the caller establishes 100 as the "foo" payload type.
1437 auto offer = caller->CreateOfferAndSetAsLocal();
1438 callee->SetRemoteDescription(std::move(offer));
1439 auto answer = callee->CreateAnswerAndSetAsLocal();
1440 auto answer_description =
1441 cricket::GetFirstAudioContentDescription(answer->description());
1442 // RED is not negotiated.
1443 ASSERT_EQ(1u, answer_description->codecs().size());
1444}
1445
1446// Test behaviour when the RED fmtp attempts to negotiate different levels of
1447// redundancy.
1448TEST_P(PeerConnectionMediaTest, RedFmtpPayloadDifferentRedundancy) {
1449 std::vector<cricket::AudioCodec> caller_fake_codecs;
Florent Castelli8c4b9ea2023-06-02 16:06:571450 caller_fake_codecs.push_back(cricket::CreateAudioCodec(100, "foo", 0, 1));
Philipp Hancke7145a142021-09-28 05:46:061451 caller_fake_codecs.push_back(
Florent Castelli8c4b9ea2023-06-02 16:06:571452 cricket::CreateAudioCodec(101, cricket::kRedCodecName, 0, 1));
Philipp Hancke7145a142021-09-28 05:46:061453 caller_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1454 "100/100");
1455 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
1456 caller_fake_engine->SetAudioCodecs(caller_fake_codecs);
1457 auto caller = CreatePeerConnectionWithAudio(std::move(caller_fake_engine));
1458
1459 std::vector<cricket::AudioCodec> callee_fake_codecs;
Florent Castelli8c4b9ea2023-06-02 16:06:571460 callee_fake_codecs.push_back(cricket::CreateAudioCodec(120, "foo", 0, 1));
Philipp Hancke7145a142021-09-28 05:46:061461 callee_fake_codecs.push_back(
Florent Castelli8c4b9ea2023-06-02 16:06:571462 cricket::CreateAudioCodec(121, cricket::kRedCodecName, 0, 1));
Philipp Hancke7145a142021-09-28 05:46:061463 callee_fake_codecs.back().SetParam(cricket::kCodecParamNotInNameValueFormat,
1464 "120/120/120");
1465 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
1466 callee_fake_engine->SetAudioCodecs(callee_fake_codecs);
1467 auto callee = CreatePeerConnectionWithAudio(std::move(callee_fake_engine));
1468
1469 // Offer from the caller establishes 100 as the "foo" payload type.
1470 auto offer = caller->CreateOfferAndSetAsLocal();
1471 callee->SetRemoteDescription(std::move(offer));
1472 auto answer = callee->CreateAnswerAndSetAsLocal();
1473 auto answer_description =
1474 cricket::GetFirstAudioContentDescription(answer->description());
1475 // RED is negotiated.
1476 ASSERT_EQ(2u, answer_description->codecs().size());
1477
1478 // Offer from the callee should respect the established payload type, and
1479 // attempt to add RED, which should refer to the correct payload type.
1480 offer = callee->CreateOfferAndSetAsLocal();
1481 auto* offer_description =
1482 cricket::GetFirstAudioContentDescription(offer->description());
1483 ASSERT_EQ(2u, offer_description->codecs().size());
1484 for (const auto& codec : offer_description->codecs()) {
1485 if (codec.name == "foo") {
1486 ASSERT_EQ(100, codec.id);
1487 } else if (codec.name == cricket::kRedCodecName) {
1488 std::string fmtp;
1489 ASSERT_TRUE(
1490 codec.GetParam(cricket::kCodecParamNotInNameValueFormat, &fmtp));
1491 EXPECT_EQ("100/100", fmtp);
1492 }
1493 }
1494}
1495
Florent Castelli2d9d82e2019-04-23 17:25:511496template <typename C>
Harald Alvestranda6544372023-11-13 09:33:561497bool CompareCodecs(const std::vector<RtpCodecCapability>& capabilities,
Florent Castelli2d9d82e2019-04-23 17:25:511498 const std::vector<C>& codecs) {
1499 bool capability_has_rtx =
Harald Alvestranda6544372023-11-13 09:33:561500 absl::c_any_of(capabilities, [](const RtpCodecCapability& codec) {
Florent Castelli2d9d82e2019-04-23 17:25:511501 return codec.name == cricket::kRtxCodecName;
1502 });
1503 bool codecs_has_rtx = absl::c_any_of(codecs, [](const C& codec) {
1504 return codec.name == cricket::kRtxCodecName;
1505 });
1506
1507 std::vector<C> codecs_no_rtx;
1508 absl::c_copy_if(
1509 codecs, std::back_inserter(codecs_no_rtx),
1510 [](const C& codec) { return codec.name != cricket::kRtxCodecName; });
1511
Harald Alvestranda6544372023-11-13 09:33:561512 std::vector<RtpCodecCapability> capabilities_no_rtx;
Florent Castelli2d9d82e2019-04-23 17:25:511513 absl::c_copy_if(capabilities, std::back_inserter(capabilities_no_rtx),
Harald Alvestranda6544372023-11-13 09:33:561514 [](const RtpCodecCapability& codec) {
Florent Castelli2d9d82e2019-04-23 17:25:511515 return codec.name != cricket::kRtxCodecName;
1516 });
1517
1518 return capability_has_rtx == codecs_has_rtx &&
1519 absl::c_equal(
1520 capabilities_no_rtx, codecs_no_rtx,
Harald Alvestranda6544372023-11-13 09:33:561521 [](const RtpCodecCapability& capability, const C& codec) {
Florent Castelli43a5dd82023-04-12 10:45:071522 return codec.MatchesRtpCodec(capability);
Florent Castelli2d9d82e2019-04-23 17:25:511523 });
1524}
1525
1526TEST_F(PeerConnectionMediaTestUnifiedPlan,
1527 SetCodecPreferencesAudioMissingRecvCodec) {
Mirko Bonadei317a1f02019-09-17 15:06:181528 auto fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 17:25:511529 auto send_codecs = fake_engine->voice().send_codecs();
Florent Castelli8c4b9ea2023-06-02 16:06:571530 send_codecs.push_back(cricket::CreateAudioCodec(send_codecs.back().id + 1,
1531 "send_only_codec", 0, 1));
Florent Castelli2d9d82e2019-04-23 17:25:511532 fake_engine->SetAudioSendCodecs(send_codecs);
1533
1534 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
1535
1536 auto transceiver = caller->pc()->GetTransceivers().front();
1537 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
1538 cricket::MediaType::MEDIA_TYPE_AUDIO);
1539
Harald Alvestranda6544372023-11-13 09:33:561540 std::vector<RtpCodecCapability> codecs;
Florent Castelli2d9d82e2019-04-23 17:25:511541 absl::c_copy_if(capabilities.codecs, std::back_inserter(codecs),
Harald Alvestranda6544372023-11-13 09:33:561542 [](const RtpCodecCapability& codec) {
Florent Castelli2d9d82e2019-04-23 17:25:511543 return codec.name.find("_only_") != std::string::npos;
1544 });
1545
1546 auto result = transceiver->SetCodecPreferences(codecs);
1547 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1548}
1549
1550TEST_F(PeerConnectionMediaTestUnifiedPlan,
1551 SetCodecPreferencesAudioMissingSendCodec) {
Mirko Bonadei317a1f02019-09-17 15:06:181552 auto fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 17:25:511553 auto recv_codecs = fake_engine->voice().recv_codecs();
Florent Castelli8c4b9ea2023-06-02 16:06:571554 recv_codecs.push_back(cricket::CreateAudioCodec(recv_codecs.back().id + 1,
1555 "recv_only_codec", 0, 1));
Florent Castelli2d9d82e2019-04-23 17:25:511556 fake_engine->SetAudioRecvCodecs(recv_codecs);
1557 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
1558
1559 auto transceiver = caller->pc()->GetTransceivers().front();
1560 auto capabilities = caller->pc_factory()->GetRtpReceiverCapabilities(
1561 cricket::MediaType::MEDIA_TYPE_AUDIO);
1562
Harald Alvestranda6544372023-11-13 09:33:561563 std::vector<RtpCodecCapability> codecs;
Florent Castelli2d9d82e2019-04-23 17:25:511564 absl::c_copy_if(capabilities.codecs, std::back_inserter(codecs),
Harald Alvestranda6544372023-11-13 09:33:561565 [](const RtpCodecCapability& codec) {
Florent Castelli2d9d82e2019-04-23 17:25:511566 return codec.name.find("_only_") != std::string::npos;
1567 });
1568
1569 auto result = transceiver->SetCodecPreferences(codecs);
1570 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1571}
1572
1573TEST_F(PeerConnectionMediaTestUnifiedPlan,
1574 SetCodecPreferencesAudioRejectsVideoCodec) {
1575 auto caller = CreatePeerConnectionWithAudio();
1576
1577 auto transceiver = caller->pc()->GetTransceivers().front();
1578 auto video_codecs =
1579 caller->pc_factory()
1580 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)
1581 .codecs;
1582 auto codecs =
1583 caller->pc_factory()
1584 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)
1585 .codecs;
1586 codecs.insert(codecs.end(), video_codecs.begin(), video_codecs.end());
1587 auto result = transceiver->SetCodecPreferences(codecs);
1588 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1589}
1590
1591TEST_F(PeerConnectionMediaTestUnifiedPlan,
1592 SetCodecPreferencesAudioRejectsOnlyRtxRedFec) {
Mirko Bonadei317a1f02019-09-17 15:06:181593 auto fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 17:25:511594 auto audio_codecs = fake_engine->voice().send_codecs();
Florent Castellid0b8e8e2023-06-04 23:22:361595 audio_codecs.push_back(cricket::CreateAudioRtxCodec(
1596 audio_codecs.back().id + 1, audio_codecs.back().id));
Florent Castelli8c4b9ea2023-06-02 16:06:571597 audio_codecs.push_back(cricket::CreateAudioCodec(
1598 audio_codecs.back().id + 1, cricket::kRedCodecName, 0, 1));
1599 audio_codecs.push_back(cricket::CreateAudioCodec(
1600 audio_codecs.back().id + 1, cricket::kUlpfecCodecName, 0, 1));
Florent Castelli2d9d82e2019-04-23 17:25:511601 fake_engine->SetAudioCodecs(audio_codecs);
1602
1603 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
1604
1605 auto transceiver = caller->pc()->GetTransceivers().front();
1606 auto codecs =
1607 caller->pc_factory()
1608 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)
1609 .codecs;
1610 auto codecs_only_rtx_red_fec = codecs;
1611 auto it = std::remove_if(codecs_only_rtx_red_fec.begin(),
1612 codecs_only_rtx_red_fec.end(),
Harald Alvestranda6544372023-11-13 09:33:561613 [](const RtpCodecCapability& codec) {
Florent Castelli2d9d82e2019-04-23 17:25:511614 return !(codec.name == cricket::kRtxCodecName ||
1615 codec.name == cricket::kRedCodecName ||
1616 codec.name == cricket::kUlpfecCodecName);
1617 });
1618 codecs_only_rtx_red_fec.erase(it, codecs_only_rtx_red_fec.end());
1619
1620 auto result = transceiver->SetCodecPreferences(codecs_only_rtx_red_fec);
1621 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1622}
1623
1624TEST_F(PeerConnectionMediaTestUnifiedPlan, SetCodecPreferencesAllAudioCodecs) {
1625 auto caller = CreatePeerConnectionWithAudio();
1626
1627 auto sender_audio_codecs =
1628 caller->pc_factory()
1629 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_AUDIO)
1630 .codecs;
1631
1632 auto audio_transceiver = caller->pc()->GetTransceivers().front();
1633
1634 // Normal case, set all capabilities as preferences
1635 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(sender_audio_codecs).ok());
1636 auto offer = caller->CreateOffer();
1637 auto codecs = offer->description()
1638 ->contents()[0]
1639 .media_description()
Florent Castelli2d9d82e2019-04-23 17:25:511640 ->codecs();
1641 EXPECT_TRUE(CompareCodecs(sender_audio_codecs, codecs));
1642}
1643
1644TEST_F(PeerConnectionMediaTestUnifiedPlan,
1645 SetCodecPreferencesResetAudioCodecs) {
1646 auto caller = CreatePeerConnectionWithAudio();
1647
1648 auto sender_audio_codecs =
1649 caller->pc_factory()
1650 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_AUDIO)
1651 .codecs;
Harald Alvestranda6544372023-11-13 09:33:561652 std::vector<RtpCodecCapability> empty_codecs = {};
Florent Castelli2d9d82e2019-04-23 17:25:511653
1654 auto audio_transceiver = caller->pc()->GetTransceivers().front();
1655
1656 // Normal case, reset codec preferences
1657 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(empty_codecs).ok());
1658 auto offer = caller->CreateOffer();
1659 auto codecs = offer->description()
1660 ->contents()[0]
1661 .media_description()
Florent Castelli2d9d82e2019-04-23 17:25:511662 ->codecs();
1663 EXPECT_TRUE(CompareCodecs(sender_audio_codecs, codecs));
1664}
1665
1666TEST_F(PeerConnectionMediaTestUnifiedPlan,
1667 SetCodecPreferencesVideoRejectsAudioCodec) {
1668 auto caller = CreatePeerConnectionWithVideo();
1669
1670 auto transceiver = caller->pc()->GetTransceivers().front();
1671 auto audio_codecs =
1672 caller->pc_factory()
1673 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)
1674 .codecs;
1675 auto codecs =
1676 caller->pc_factory()
1677 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)
1678 .codecs;
1679 codecs.insert(codecs.end(), audio_codecs.begin(), audio_codecs.end());
1680 auto result = transceiver->SetCodecPreferences(codecs);
1681 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1682}
1683
1684TEST_F(PeerConnectionMediaTestUnifiedPlan,
1685 SetCodecPreferencesVideoRejectsOnlyRtxRedFec) {
Mirko Bonadei317a1f02019-09-17 15:06:181686 auto fake_engine = std::make_unique<FakeMediaEngine>();
Johannes Kron3e983682020-03-29 20:17:001687 auto video_codecs = fake_engine->video().send_codecs();
Florent Castellid0b8e8e2023-06-04 23:22:361688 video_codecs.push_back(cricket::CreateVideoRtxCodec(
1689 video_codecs.back().id + 1, video_codecs.back().id));
Florent Castelli8c4b9ea2023-06-02 16:06:571690 video_codecs.push_back(cricket::CreateVideoCodec(video_codecs.back().id + 1,
1691 cricket::kRedCodecName));
1692 video_codecs.push_back(cricket::CreateVideoCodec(video_codecs.back().id + 1,
1693 cricket::kUlpfecCodecName));
Florent Castelli2d9d82e2019-04-23 17:25:511694 fake_engine->SetVideoCodecs(video_codecs);
1695
1696 auto caller = CreatePeerConnectionWithVideo(std::move(fake_engine));
1697
1698 auto transceiver = caller->pc()->GetTransceivers().front();
1699 auto codecs =
1700 caller->pc_factory()
1701 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)
1702 .codecs;
1703 auto codecs_only_rtx_red_fec = codecs;
1704 auto it = std::remove_if(codecs_only_rtx_red_fec.begin(),
1705 codecs_only_rtx_red_fec.end(),
Harald Alvestranda6544372023-11-13 09:33:561706 [](const RtpCodecCapability& codec) {
Florent Castelli2d9d82e2019-04-23 17:25:511707 return !(codec.name == cricket::kRtxCodecName ||
1708 codec.name == cricket::kRedCodecName ||
1709 codec.name == cricket::kUlpfecCodecName);
1710 });
1711 codecs_only_rtx_red_fec.erase(it, codecs_only_rtx_red_fec.end());
1712
1713 auto result = transceiver->SetCodecPreferences(codecs_only_rtx_red_fec);
1714 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1715}
1716
1717TEST_F(PeerConnectionMediaTestUnifiedPlan, SetCodecPreferencesAllVideoCodecs) {
1718 auto caller = CreatePeerConnectionWithVideo();
1719
1720 auto sender_video_codecs =
1721 caller->pc_factory()
1722 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1723 .codecs;
1724
1725 auto video_transceiver = caller->pc()->GetTransceivers().front();
1726
1727 // Normal case, setting preferences to normal capabilities
1728 EXPECT_TRUE(video_transceiver->SetCodecPreferences(sender_video_codecs).ok());
1729 auto offer = caller->CreateOffer();
1730 auto codecs = offer->description()
1731 ->contents()[0]
1732 .media_description()
Florent Castelli2d9d82e2019-04-23 17:25:511733 ->codecs();
1734 EXPECT_TRUE(CompareCodecs(sender_video_codecs, codecs));
1735}
1736
1737TEST_F(PeerConnectionMediaTestUnifiedPlan,
1738 SetCodecPreferencesResetVideoCodecs) {
1739 auto caller = CreatePeerConnectionWithVideo();
1740
1741 auto sender_video_codecs =
1742 caller->pc_factory()
1743 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1744 .codecs;
1745
Harald Alvestranda6544372023-11-13 09:33:561746 std::vector<RtpCodecCapability> empty_codecs = {};
Florent Castelli2d9d82e2019-04-23 17:25:511747
1748 auto video_transceiver = caller->pc()->GetTransceivers().front();
1749
1750 // Normal case, resetting preferences with empty list of codecs
1751 EXPECT_TRUE(video_transceiver->SetCodecPreferences(empty_codecs).ok());
1752 auto offer = caller->CreateOffer();
1753 auto codecs = offer->description()
1754 ->contents()[0]
1755 .media_description()
Florent Castelli2d9d82e2019-04-23 17:25:511756 ->codecs();
1757 EXPECT_TRUE(CompareCodecs(sender_video_codecs, codecs));
1758}
1759
1760TEST_F(PeerConnectionMediaTestUnifiedPlan,
1761 SetCodecPreferencesVideoCodecDuplicatesRemoved) {
1762 auto caller = CreatePeerConnectionWithVideo();
1763
1764 auto sender_video_codecs =
1765 caller->pc_factory()
1766 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1767 .codecs;
1768
1769 auto video_transceiver = caller->pc()->GetTransceivers().front();
1770
1771 // Check duplicates are removed
1772 auto single_codec = sender_video_codecs;
1773 single_codec.resize(1);
1774 auto duplicate_codec = single_codec;
1775 duplicate_codec.push_back(duplicate_codec.front());
1776 duplicate_codec.push_back(duplicate_codec.front());
1777 duplicate_codec.push_back(duplicate_codec.front());
1778
1779 EXPECT_TRUE(video_transceiver->SetCodecPreferences(duplicate_codec).ok());
1780 auto offer = caller->CreateOffer();
1781 auto codecs = offer->description()
1782 ->contents()[0]
1783 .media_description()
Florent Castelli2d9d82e2019-04-23 17:25:511784 ->codecs();
1785 EXPECT_TRUE(CompareCodecs(single_codec, codecs));
1786}
1787
1788TEST_F(PeerConnectionMediaTestUnifiedPlan, SetCodecPreferencesVideoWithRtx) {
Mirko Bonadei317a1f02019-09-17 15:06:181789 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Johannes Kron3e983682020-03-29 20:17:001790 auto caller_video_codecs = caller_fake_engine->video().send_codecs();
Florent Castelli8c4b9ea2023-06-02 16:06:571791 caller_video_codecs.push_back(cricket::CreateVideoCodec(
Florent Castelli2d9d82e2019-04-23 17:25:511792 caller_video_codecs.back().id + 1, cricket::kVp8CodecName));
Florent Castellid0b8e8e2023-06-04 23:22:361793 caller_video_codecs.push_back(cricket::CreateVideoRtxCodec(
1794 caller_video_codecs.back().id + 1, caller_video_codecs.back().id));
Florent Castelli8c4b9ea2023-06-02 16:06:571795 caller_video_codecs.push_back(cricket::CreateVideoCodec(
Florent Castelli2d9d82e2019-04-23 17:25:511796 caller_video_codecs.back().id + 1, cricket::kVp9CodecName));
Florent Castellid0b8e8e2023-06-04 23:22:361797 caller_video_codecs.push_back(cricket::CreateVideoRtxCodec(
1798 caller_video_codecs.back().id + 1, caller_video_codecs.back().id));
Florent Castelli2d9d82e2019-04-23 17:25:511799 caller_fake_engine->SetVideoCodecs(caller_video_codecs);
1800
1801 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
1802
1803 auto sender_video_codecs =
1804 caller->pc_factory()
1805 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1806 .codecs;
1807
1808 auto video_transceiver = caller->pc()->GetTransceivers().front();
1809
1810 // Check that RTX codec is properly added
1811 auto video_codecs_vpx_rtx = sender_video_codecs;
1812 auto it =
1813 std::remove_if(video_codecs_vpx_rtx.begin(), video_codecs_vpx_rtx.end(),
Harald Alvestranda6544372023-11-13 09:33:561814 [](const RtpCodecCapability& codec) {
Florent Castelli2d9d82e2019-04-23 17:25:511815 return codec.name != cricket::kRtxCodecName &&
1816 codec.name != cricket::kVp8CodecName &&
1817 codec.name != cricket::kVp9CodecName;
1818 });
1819 video_codecs_vpx_rtx.erase(it, video_codecs_vpx_rtx.end());
1820 absl::c_reverse(video_codecs_vpx_rtx);
1821 EXPECT_EQ(video_codecs_vpx_rtx.size(), 3u); // VP8, VP9, RTX
1822 EXPECT_TRUE(
1823 video_transceiver->SetCodecPreferences(video_codecs_vpx_rtx).ok());
1824 auto offer = caller->CreateOffer();
1825 auto codecs = offer->description()
1826 ->contents()[0]
1827 .media_description()
Florent Castelli2d9d82e2019-04-23 17:25:511828 ->codecs();
1829
1830 EXPECT_TRUE(CompareCodecs(video_codecs_vpx_rtx, codecs));
1831 EXPECT_EQ(codecs.size(), 4u);
1832}
1833
1834TEST_F(PeerConnectionMediaTestUnifiedPlan,
1835 SetCodecPreferencesVideoCodecsNegotiation) {
Mirko Bonadei317a1f02019-09-17 15:06:181836 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Johannes Kron3e983682020-03-29 20:17:001837 auto caller_video_codecs = caller_fake_engine->video().send_codecs();
Florent Castelli8c4b9ea2023-06-02 16:06:571838 caller_video_codecs.push_back(cricket::CreateVideoCodec(
Florent Castelli2d9d82e2019-04-23 17:25:511839 caller_video_codecs.back().id + 1, cricket::kVp8CodecName));
Florent Castellid0b8e8e2023-06-04 23:22:361840 caller_video_codecs.push_back(cricket::CreateVideoRtxCodec(
1841 caller_video_codecs.back().id + 1, caller_video_codecs.back().id));
Florent Castelli8c4b9ea2023-06-02 16:06:571842 caller_video_codecs.push_back(cricket::CreateVideoCodec(
Florent Castelli2d9d82e2019-04-23 17:25:511843 caller_video_codecs.back().id + 1, cricket::kVp9CodecName));
Florent Castellid0b8e8e2023-06-04 23:22:361844 caller_video_codecs.push_back(cricket::CreateVideoRtxCodec(
1845 caller_video_codecs.back().id + 1, caller_video_codecs.back().id));
Florent Castelli2d9d82e2019-04-23 17:25:511846 caller_fake_engine->SetVideoCodecs(caller_video_codecs);
1847
Mirko Bonadei317a1f02019-09-17 15:06:181848 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 17:25:511849 callee_fake_engine->SetVideoCodecs(caller_video_codecs);
1850
1851 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
1852 auto callee = CreatePeerConnection(std::move(callee_fake_engine));
1853
1854 auto video_codecs = caller->pc_factory()
1855 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1856 .codecs;
1857
1858 auto send_transceiver = caller->pc()->GetTransceivers().front();
1859
1860 auto video_codecs_vpx = video_codecs;
1861 auto it = std::remove_if(video_codecs_vpx.begin(), video_codecs_vpx.end(),
Harald Alvestranda6544372023-11-13 09:33:561862 [](const RtpCodecCapability& codec) {
Florent Castelli2d9d82e2019-04-23 17:25:511863 return codec.name != cricket::kVp8CodecName &&
1864 codec.name != cricket::kVp9CodecName;
1865 });
1866 video_codecs_vpx.erase(it, video_codecs_vpx.end());
1867 EXPECT_EQ(video_codecs_vpx.size(), 2u); // VP8, VP9
1868 EXPECT_TRUE(send_transceiver->SetCodecPreferences(video_codecs_vpx).ok());
1869
1870 auto offer = caller->CreateOfferAndSetAsLocal();
1871 auto codecs = offer->description()
1872 ->contents()[0]
1873 .media_description()
Florent Castelli2d9d82e2019-04-23 17:25:511874 ->codecs();
1875
1876 EXPECT_EQ(codecs.size(), 2u); // VP8, VP9
1877 EXPECT_TRUE(CompareCodecs(video_codecs_vpx, codecs));
1878
1879 callee->SetRemoteDescription(std::move(offer));
1880
1881 auto recv_transceiver = callee->pc()->GetTransceivers().front();
1882 auto video_codecs_vp8_rtx = video_codecs;
1883 it = std::remove_if(video_codecs_vp8_rtx.begin(), video_codecs_vp8_rtx.end(),
Harald Alvestranda6544372023-11-13 09:33:561884 [](const RtpCodecCapability& codec) {
Florent Castelli2d9d82e2019-04-23 17:25:511885 bool r = codec.name != cricket::kVp8CodecName &&
1886 codec.name != cricket::kRtxCodecName;
1887 return r;
1888 });
1889 video_codecs_vp8_rtx.erase(it, video_codecs_vp8_rtx.end());
1890 EXPECT_EQ(video_codecs_vp8_rtx.size(), 2u); // VP8, RTX
1891 recv_transceiver->SetCodecPreferences(video_codecs_vp8_rtx);
1892
1893 auto answer = callee->CreateAnswerAndSetAsLocal();
1894
1895 auto recv_codecs = answer->description()
1896 ->contents()[0]
1897 .media_description()
Florent Castelli2d9d82e2019-04-23 17:25:511898 ->codecs();
1899 EXPECT_EQ(recv_codecs.size(), 1u); // VP8
1900}
1901
1902TEST_F(PeerConnectionMediaTestUnifiedPlan,
1903 SetCodecPreferencesVideoCodecsNegotiationReverseOrder) {
Mirko Bonadei317a1f02019-09-17 15:06:181904 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Johannes Kron3e983682020-03-29 20:17:001905 auto caller_video_codecs = caller_fake_engine->video().send_codecs();
Florent Castelli8c4b9ea2023-06-02 16:06:571906 caller_video_codecs.push_back(cricket::CreateVideoCodec(
Florent Castelli2d9d82e2019-04-23 17:25:511907 caller_video_codecs.back().id + 1, cricket::kVp8CodecName));
Florent Castellid0b8e8e2023-06-04 23:22:361908 caller_video_codecs.push_back(cricket::CreateVideoRtxCodec(
1909 caller_video_codecs.back().id + 1, caller_video_codecs.back().id));
Florent Castelli8c4b9ea2023-06-02 16:06:571910 caller_video_codecs.push_back(cricket::CreateVideoCodec(
Florent Castelli2d9d82e2019-04-23 17:25:511911 caller_video_codecs.back().id + 1, cricket::kVp9CodecName));
Florent Castellid0b8e8e2023-06-04 23:22:361912 caller_video_codecs.push_back(cricket::CreateVideoRtxCodec(
1913 caller_video_codecs.back().id + 1, caller_video_codecs.back().id));
Florent Castelli2d9d82e2019-04-23 17:25:511914 caller_fake_engine->SetVideoCodecs(caller_video_codecs);
1915
Mirko Bonadei317a1f02019-09-17 15:06:181916 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 17:25:511917 callee_fake_engine->SetVideoCodecs(caller_video_codecs);
1918
1919 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
1920 auto callee = CreatePeerConnection(std::move(callee_fake_engine));
1921
1922 auto video_codecs = caller->pc_factory()
1923 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1924 .codecs;
1925
1926 auto send_transceiver = caller->pc()->GetTransceivers().front();
1927
1928 auto video_codecs_vpx = video_codecs;
1929 auto it = std::remove_if(video_codecs_vpx.begin(), video_codecs_vpx.end(),
Harald Alvestranda6544372023-11-13 09:33:561930 [](const RtpCodecCapability& codec) {
Florent Castelli2d9d82e2019-04-23 17:25:511931 return codec.name != cricket::kVp8CodecName &&
1932 codec.name != cricket::kVp9CodecName;
1933 });
1934 video_codecs_vpx.erase(it, video_codecs_vpx.end());
1935 EXPECT_EQ(video_codecs_vpx.size(), 2u); // VP8, VP9
1936 EXPECT_TRUE(send_transceiver->SetCodecPreferences(video_codecs_vpx).ok());
1937
1938 auto video_codecs_vpx_reverse = video_codecs_vpx;
1939 absl::c_reverse(video_codecs_vpx_reverse);
1940
1941 auto offer = caller->CreateOfferAndSetAsLocal();
1942 auto codecs = offer->description()
1943 ->contents()[0]
1944 .media_description()
Florent Castelli2d9d82e2019-04-23 17:25:511945 ->codecs();
1946 EXPECT_EQ(codecs.size(), 2u); // VP9, VP8
1947 EXPECT_TRUE(CompareCodecs(video_codecs_vpx, codecs));
1948
1949 callee->SetRemoteDescription(std::move(offer));
1950
1951 auto recv_transceiver = callee->pc()->GetTransceivers().front();
1952 recv_transceiver->SetCodecPreferences(video_codecs_vpx_reverse);
1953
1954 auto answer = callee->CreateAnswerAndSetAsLocal();
1955
1956 auto recv_codecs = answer->description()
1957 ->contents()[0]
1958 .media_description()
Florent Castelli2d9d82e2019-04-23 17:25:511959 ->codecs();
1960
1961 EXPECT_TRUE(CompareCodecs(video_codecs_vpx_reverse, recv_codecs));
1962}
1963
Philipp Hancke3ac73bd2021-05-11 12:13:061964TEST_F(PeerConnectionMediaTestUnifiedPlan,
1965 SetCodecPreferencesVoiceActivityDetection) {
1966 auto fake_engine = std::make_unique<FakeMediaEngine>();
1967 AddComfortNoiseCodecsToSend(fake_engine.get());
1968 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
1969
1970 RTCOfferAnswerOptions options;
1971 auto offer = caller->CreateOffer(options);
1972 EXPECT_TRUE(HasAnyComfortNoiseCodecs(offer->description()));
1973
1974 auto transceiver = caller->pc()->GetTransceivers().front();
1975 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
1976 cricket::MediaType::MEDIA_TYPE_AUDIO);
1977 EXPECT_TRUE(transceiver->SetCodecPreferences(capabilities.codecs).ok());
1978
1979 options.voice_activity_detection = false;
1980 offer = caller->CreateOffer(options);
1981 EXPECT_FALSE(HasAnyComfortNoiseCodecs(offer->description()));
1982}
1983
Taylor Brandstetterf7fcfb72021-09-09 20:39:381984// If the "default" payload types of audio/video codecs are the same, and
1985// audio/video are bundled (as is the default), payload types should be
1986// remapped to avoid conflict, as normally happens without using
1987// SetCodecPreferences.
1988TEST_F(PeerConnectionMediaTestUnifiedPlan,
1989 SetCodecPreferencesAvoidsPayloadTypeConflictInOffer) {
1990 auto fake_engine = std::make_unique<cricket::FakeMediaEngine>();
1991
1992 std::vector<cricket::AudioCodec> audio_codecs;
Florent Castellid0b8e8e2023-06-04 23:22:361993 audio_codecs.emplace_back(cricket::CreateAudioCodec(100, "foo", 0, 1));
1994 audio_codecs.emplace_back(cricket::CreateAudioRtxCodec(101, 100));
Taylor Brandstetterf7fcfb72021-09-09 20:39:381995 fake_engine->SetAudioCodecs(audio_codecs);
1996
1997 std::vector<cricket::VideoCodec> video_codecs;
Florent Castellid0b8e8e2023-06-04 23:22:361998 video_codecs.emplace_back(cricket::CreateVideoCodec(100, "bar"));
1999 video_codecs.emplace_back(cricket::CreateVideoRtxCodec(101, 100));
Taylor Brandstetterf7fcfb72021-09-09 20:39:382000 fake_engine->SetVideoCodecs(video_codecs);
2001
2002 auto caller = CreatePeerConnectionWithAudioVideo(std::move(fake_engine));
2003 auto transceivers = caller->pc()->GetTransceivers();
2004 ASSERT_EQ(2u, transceivers.size());
2005
2006 auto audio_transceiver = caller->pc()->GetTransceivers()[0];
2007 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2008 cricket::MediaType::MEDIA_TYPE_AUDIO);
2009 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(capabilities.codecs).ok());
2010
2011 auto video_transceiver = caller->pc()->GetTransceivers()[1];
2012 capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2013 cricket::MediaType::MEDIA_TYPE_VIDEO);
2014 EXPECT_TRUE(video_transceiver->SetCodecPreferences(capabilities.codecs).ok());
2015
2016 RTCOfferAnswerOptions options;
2017 auto offer = caller->CreateOffer(options);
2018 EXPECT_FALSE(HasPayloadTypeConflict(offer->description()));
2019 // Sanity check that we got the primary codec and RTX.
2020 EXPECT_EQ(2u, cricket::GetFirstAudioContentDescription(offer->description())
2021 ->codecs()
2022 .size());
2023 EXPECT_EQ(2u, cricket::GetFirstVideoContentDescription(offer->description())
2024 ->codecs()
2025 .size());
2026}
2027
2028// Same as above, but preferences set for the answer.
2029TEST_F(PeerConnectionMediaTestUnifiedPlan,
2030 SetCodecPreferencesAvoidsPayloadTypeConflictInAnswer) {
2031 auto fake_engine = std::make_unique<cricket::FakeMediaEngine>();
2032
2033 std::vector<cricket::AudioCodec> audio_codecs;
Florent Castellid0b8e8e2023-06-04 23:22:362034 audio_codecs.emplace_back(cricket::CreateAudioCodec(100, "foo", 0, 1));
2035 audio_codecs.emplace_back(cricket::CreateAudioRtxCodec(101, 100));
Taylor Brandstetterf7fcfb72021-09-09 20:39:382036 fake_engine->SetAudioCodecs(audio_codecs);
2037
2038 std::vector<cricket::VideoCodec> video_codecs;
Florent Castellid0b8e8e2023-06-04 23:22:362039 video_codecs.emplace_back(cricket::CreateVideoCodec(100, "bar"));
2040 video_codecs.emplace_back(cricket::CreateVideoRtxCodec(101, 100));
Taylor Brandstetterf7fcfb72021-09-09 20:39:382041 fake_engine->SetVideoCodecs(video_codecs);
2042
2043 auto caller = CreatePeerConnectionWithAudioVideo(std::move(fake_engine));
2044
2045 RTCOfferAnswerOptions options;
2046 caller->SetRemoteDescription(caller->CreateOffer(options));
2047
2048 auto transceivers = caller->pc()->GetTransceivers();
2049 ASSERT_EQ(2u, transceivers.size());
2050
2051 auto audio_transceiver = caller->pc()->GetTransceivers()[0];
2052 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2053 cricket::MediaType::MEDIA_TYPE_AUDIO);
2054 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(capabilities.codecs).ok());
2055
2056 auto video_transceiver = caller->pc()->GetTransceivers()[1];
2057 capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2058 cricket::MediaType::MEDIA_TYPE_VIDEO);
2059 EXPECT_TRUE(video_transceiver->SetCodecPreferences(capabilities.codecs).ok());
2060
2061 auto answer = caller->CreateAnswer(options);
2062
2063 EXPECT_FALSE(HasPayloadTypeConflict(answer->description()));
2064 // Sanity check that we got the primary codec and RTX.
2065 EXPECT_EQ(2u, cricket::GetFirstAudioContentDescription(answer->description())
2066 ->codecs()
2067 .size());
2068 EXPECT_EQ(2u, cricket::GetFirstVideoContentDescription(answer->description())
2069 ->codecs()
2070 .size());
2071}
2072
2073// Same as above, but preferences set for a subsequent offer.
2074TEST_F(PeerConnectionMediaTestUnifiedPlan,
2075 SetCodecPreferencesAvoidsPayloadTypeConflictInSubsequentOffer) {
2076 auto fake_engine = std::make_unique<cricket::FakeMediaEngine>();
2077
2078 std::vector<cricket::AudioCodec> audio_codecs;
Florent Castellid0b8e8e2023-06-04 23:22:362079 audio_codecs.emplace_back(cricket::CreateAudioCodec(100, "foo", 0, 1));
2080 audio_codecs.emplace_back(cricket::CreateAudioRtxCodec(101, 100));
Taylor Brandstetterf7fcfb72021-09-09 20:39:382081 fake_engine->SetAudioCodecs(audio_codecs);
2082
2083 std::vector<cricket::VideoCodec> video_codecs;
Florent Castellid0b8e8e2023-06-04 23:22:362084 video_codecs.emplace_back(cricket::CreateVideoCodec(100, "bar"));
2085 video_codecs.emplace_back(cricket::CreateVideoRtxCodec(101, 100));
Taylor Brandstetterf7fcfb72021-09-09 20:39:382086 fake_engine->SetVideoCodecs(video_codecs);
2087
2088 auto caller = CreatePeerConnectionWithAudioVideo(std::move(fake_engine));
2089
2090 RTCOfferAnswerOptions options;
2091 caller->SetRemoteDescription(caller->CreateOffer(options));
2092 caller->SetLocalDescription(caller->CreateAnswer(options));
2093
2094 auto transceivers = caller->pc()->GetTransceivers();
2095 ASSERT_EQ(2u, transceivers.size());
2096
2097 auto audio_transceiver = caller->pc()->GetTransceivers()[0];
2098 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2099 cricket::MediaType::MEDIA_TYPE_AUDIO);
2100 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(capabilities.codecs).ok());
2101
2102 auto video_transceiver = caller->pc()->GetTransceivers()[1];
2103 capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2104 cricket::MediaType::MEDIA_TYPE_VIDEO);
2105 EXPECT_TRUE(video_transceiver->SetCodecPreferences(capabilities.codecs).ok());
2106
2107 auto reoffer = caller->CreateOffer(options);
Harald Alvestrand2f553702023-03-07 10:10:032108 ASSERT_THAT(reoffer, NotNull());
Taylor Brandstetterf7fcfb72021-09-09 20:39:382109
2110 EXPECT_FALSE(HasPayloadTypeConflict(reoffer->description()));
2111 // Sanity check that we got the primary codec and RTX.
2112 EXPECT_EQ(2u, cricket::GetFirstAudioContentDescription(reoffer->description())
2113 ->codecs()
2114 .size());
2115 EXPECT_EQ(2u, cricket::GetFirstVideoContentDescription(reoffer->description())
2116 ->codecs()
2117 .size());
2118}
2119
Mirko Bonadeic84f6612019-01-31 11:20:572120INSTANTIATE_TEST_SUITE_P(PeerConnectionMediaTest,
2121 PeerConnectionMediaTest,
Florent Castelli15a38de2022-04-05 22:38:212122 Values(SdpSemantics::kPlanB_DEPRECATED,
Mirko Bonadeic84f6612019-01-31 11:20:572123 SdpSemantics::kUnifiedPlan));
Steve Antonad7bffc2018-01-22 18:21:562124
Steve Anton8d3444d2017-10-20 22:30:512125} // namespace webrtc