blob: 04fb9c9e26b8406a6902b05f7bb2cf705311efa9 [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 Anton10542f22019-01-11 17:11:0069#include "rtc_base/virtual_socket_server.h"
Steve Anton8d3444d2017-10-20 22:30:5170#include "test/gmock.h"
71
72namespace webrtc {
73
74using cricket::FakeMediaEngine;
75using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
76using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
77using ::testing::Bool;
78using ::testing::Combine;
Steve Anton8d3444d2017-10-20 22:30:5179using ::testing::ElementsAre;
Philipp Hancke5aaa9ed2024-01-15 09:07:5880using ::testing::HasSubstr;
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));
Philipp Hancke5aaa9ed2024-01-15 09:07:58289 EXPECT_THAT(error,
290 HasSubstr("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));
Philipp Hancke5aaa9ed2024-01-15 09:07:58300 EXPECT_THAT(error,
301 HasSubstr("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,
Florent Castelli2d9d82e2019-04-23 17:25:511551 SetCodecPreferencesAudioRejectsVideoCodec) {
1552 auto caller = CreatePeerConnectionWithAudio();
1553
1554 auto transceiver = caller->pc()->GetTransceivers().front();
1555 auto video_codecs =
1556 caller->pc_factory()
1557 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)
1558 .codecs;
1559 auto codecs =
1560 caller->pc_factory()
1561 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)
1562 .codecs;
1563 codecs.insert(codecs.end(), video_codecs.begin(), video_codecs.end());
1564 auto result = transceiver->SetCodecPreferences(codecs);
1565 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1566}
1567
1568TEST_F(PeerConnectionMediaTestUnifiedPlan,
1569 SetCodecPreferencesAudioRejectsOnlyRtxRedFec) {
Mirko Bonadei317a1f02019-09-17 15:06:181570 auto fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 17:25:511571 auto audio_codecs = fake_engine->voice().send_codecs();
Florent Castellid0b8e8e2023-06-04 23:22:361572 audio_codecs.push_back(cricket::CreateAudioRtxCodec(
1573 audio_codecs.back().id + 1, audio_codecs.back().id));
Florent Castelli8c4b9ea2023-06-02 16:06:571574 audio_codecs.push_back(cricket::CreateAudioCodec(
1575 audio_codecs.back().id + 1, cricket::kRedCodecName, 0, 1));
1576 audio_codecs.push_back(cricket::CreateAudioCodec(
1577 audio_codecs.back().id + 1, cricket::kUlpfecCodecName, 0, 1));
Florent Castelli2d9d82e2019-04-23 17:25:511578 fake_engine->SetAudioCodecs(audio_codecs);
1579
1580 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
1581
1582 auto transceiver = caller->pc()->GetTransceivers().front();
1583 auto codecs =
1584 caller->pc_factory()
1585 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)
1586 .codecs;
1587 auto codecs_only_rtx_red_fec = codecs;
1588 auto it = std::remove_if(codecs_only_rtx_red_fec.begin(),
1589 codecs_only_rtx_red_fec.end(),
Harald Alvestranda6544372023-11-13 09:33:561590 [](const RtpCodecCapability& codec) {
Florent Castelli2d9d82e2019-04-23 17:25:511591 return !(codec.name == cricket::kRtxCodecName ||
1592 codec.name == cricket::kRedCodecName ||
1593 codec.name == cricket::kUlpfecCodecName);
1594 });
1595 codecs_only_rtx_red_fec.erase(it, codecs_only_rtx_red_fec.end());
1596
1597 auto result = transceiver->SetCodecPreferences(codecs_only_rtx_red_fec);
1598 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1599}
1600
1601TEST_F(PeerConnectionMediaTestUnifiedPlan, SetCodecPreferencesAllAudioCodecs) {
1602 auto caller = CreatePeerConnectionWithAudio();
1603
1604 auto sender_audio_codecs =
1605 caller->pc_factory()
1606 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_AUDIO)
1607 .codecs;
1608
1609 auto audio_transceiver = caller->pc()->GetTransceivers().front();
1610
1611 // Normal case, set all capabilities as preferences
1612 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(sender_audio_codecs).ok());
1613 auto offer = caller->CreateOffer();
1614 auto codecs = offer->description()
1615 ->contents()[0]
1616 .media_description()
Florent Castelli2d9d82e2019-04-23 17:25:511617 ->codecs();
1618 EXPECT_TRUE(CompareCodecs(sender_audio_codecs, codecs));
1619}
1620
1621TEST_F(PeerConnectionMediaTestUnifiedPlan,
1622 SetCodecPreferencesResetAudioCodecs) {
1623 auto caller = CreatePeerConnectionWithAudio();
1624
1625 auto sender_audio_codecs =
1626 caller->pc_factory()
1627 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_AUDIO)
1628 .codecs;
Harald Alvestranda6544372023-11-13 09:33:561629 std::vector<RtpCodecCapability> empty_codecs = {};
Florent Castelli2d9d82e2019-04-23 17:25:511630
1631 auto audio_transceiver = caller->pc()->GetTransceivers().front();
1632
1633 // Normal case, reset codec preferences
1634 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(empty_codecs).ok());
1635 auto offer = caller->CreateOffer();
1636 auto codecs = offer->description()
1637 ->contents()[0]
1638 .media_description()
Florent Castelli2d9d82e2019-04-23 17:25:511639 ->codecs();
1640 EXPECT_TRUE(CompareCodecs(sender_audio_codecs, codecs));
1641}
1642
1643TEST_F(PeerConnectionMediaTestUnifiedPlan,
1644 SetCodecPreferencesVideoRejectsAudioCodec) {
1645 auto caller = CreatePeerConnectionWithVideo();
1646
1647 auto transceiver = caller->pc()->GetTransceivers().front();
1648 auto audio_codecs =
1649 caller->pc_factory()
1650 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_AUDIO)
1651 .codecs;
1652 auto codecs =
1653 caller->pc_factory()
1654 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)
1655 .codecs;
1656 codecs.insert(codecs.end(), audio_codecs.begin(), audio_codecs.end());
1657 auto result = transceiver->SetCodecPreferences(codecs);
1658 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1659}
1660
1661TEST_F(PeerConnectionMediaTestUnifiedPlan,
1662 SetCodecPreferencesVideoRejectsOnlyRtxRedFec) {
Mirko Bonadei317a1f02019-09-17 15:06:181663 auto fake_engine = std::make_unique<FakeMediaEngine>();
Johannes Kron3e983682020-03-29 20:17:001664 auto video_codecs = fake_engine->video().send_codecs();
Florent Castellid0b8e8e2023-06-04 23:22:361665 video_codecs.push_back(cricket::CreateVideoRtxCodec(
1666 video_codecs.back().id + 1, video_codecs.back().id));
Florent Castelli8c4b9ea2023-06-02 16:06:571667 video_codecs.push_back(cricket::CreateVideoCodec(video_codecs.back().id + 1,
1668 cricket::kRedCodecName));
1669 video_codecs.push_back(cricket::CreateVideoCodec(video_codecs.back().id + 1,
1670 cricket::kUlpfecCodecName));
Florent Castelli2d9d82e2019-04-23 17:25:511671 fake_engine->SetVideoCodecs(video_codecs);
1672
1673 auto caller = CreatePeerConnectionWithVideo(std::move(fake_engine));
1674
1675 auto transceiver = caller->pc()->GetTransceivers().front();
1676 auto codecs =
1677 caller->pc_factory()
1678 ->GetRtpSenderCapabilities(cricket::MediaType::MEDIA_TYPE_VIDEO)
1679 .codecs;
1680 auto codecs_only_rtx_red_fec = codecs;
1681 auto it = std::remove_if(codecs_only_rtx_red_fec.begin(),
1682 codecs_only_rtx_red_fec.end(),
Harald Alvestranda6544372023-11-13 09:33:561683 [](const RtpCodecCapability& codec) {
Florent Castelli2d9d82e2019-04-23 17:25:511684 return !(codec.name == cricket::kRtxCodecName ||
1685 codec.name == cricket::kRedCodecName ||
1686 codec.name == cricket::kUlpfecCodecName);
1687 });
1688 codecs_only_rtx_red_fec.erase(it, codecs_only_rtx_red_fec.end());
1689
1690 auto result = transceiver->SetCodecPreferences(codecs_only_rtx_red_fec);
1691 EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type());
1692}
1693
1694TEST_F(PeerConnectionMediaTestUnifiedPlan, SetCodecPreferencesAllVideoCodecs) {
1695 auto caller = CreatePeerConnectionWithVideo();
1696
1697 auto sender_video_codecs =
1698 caller->pc_factory()
1699 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1700 .codecs;
1701
1702 auto video_transceiver = caller->pc()->GetTransceivers().front();
1703
1704 // Normal case, setting preferences to normal capabilities
1705 EXPECT_TRUE(video_transceiver->SetCodecPreferences(sender_video_codecs).ok());
1706 auto offer = caller->CreateOffer();
1707 auto codecs = offer->description()
1708 ->contents()[0]
1709 .media_description()
Florent Castelli2d9d82e2019-04-23 17:25:511710 ->codecs();
1711 EXPECT_TRUE(CompareCodecs(sender_video_codecs, codecs));
1712}
1713
1714TEST_F(PeerConnectionMediaTestUnifiedPlan,
1715 SetCodecPreferencesResetVideoCodecs) {
1716 auto caller = CreatePeerConnectionWithVideo();
1717
1718 auto sender_video_codecs =
1719 caller->pc_factory()
1720 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1721 .codecs;
1722
Harald Alvestranda6544372023-11-13 09:33:561723 std::vector<RtpCodecCapability> empty_codecs = {};
Florent Castelli2d9d82e2019-04-23 17:25:511724
1725 auto video_transceiver = caller->pc()->GetTransceivers().front();
1726
1727 // Normal case, resetting preferences with empty list of codecs
1728 EXPECT_TRUE(video_transceiver->SetCodecPreferences(empty_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 SetCodecPreferencesVideoCodecDuplicatesRemoved) {
1739 auto caller = CreatePeerConnectionWithVideo();
1740
1741 auto sender_video_codecs =
1742 caller->pc_factory()
1743 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1744 .codecs;
1745
1746 auto video_transceiver = caller->pc()->GetTransceivers().front();
1747
1748 // Check duplicates are removed
1749 auto single_codec = sender_video_codecs;
1750 single_codec.resize(1);
1751 auto duplicate_codec = single_codec;
1752 duplicate_codec.push_back(duplicate_codec.front());
1753 duplicate_codec.push_back(duplicate_codec.front());
1754 duplicate_codec.push_back(duplicate_codec.front());
1755
1756 EXPECT_TRUE(video_transceiver->SetCodecPreferences(duplicate_codec).ok());
1757 auto offer = caller->CreateOffer();
1758 auto codecs = offer->description()
1759 ->contents()[0]
1760 .media_description()
Florent Castelli2d9d82e2019-04-23 17:25:511761 ->codecs();
1762 EXPECT_TRUE(CompareCodecs(single_codec, codecs));
1763}
1764
1765TEST_F(PeerConnectionMediaTestUnifiedPlan, SetCodecPreferencesVideoWithRtx) {
Mirko Bonadei317a1f02019-09-17 15:06:181766 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Johannes Kron3e983682020-03-29 20:17:001767 auto caller_video_codecs = caller_fake_engine->video().send_codecs();
Florent Castelli8c4b9ea2023-06-02 16:06:571768 caller_video_codecs.push_back(cricket::CreateVideoCodec(
Florent Castelli2d9d82e2019-04-23 17:25:511769 caller_video_codecs.back().id + 1, cricket::kVp8CodecName));
Florent Castellid0b8e8e2023-06-04 23:22:361770 caller_video_codecs.push_back(cricket::CreateVideoRtxCodec(
1771 caller_video_codecs.back().id + 1, caller_video_codecs.back().id));
Florent Castelli8c4b9ea2023-06-02 16:06:571772 caller_video_codecs.push_back(cricket::CreateVideoCodec(
Florent Castelli2d9d82e2019-04-23 17:25:511773 caller_video_codecs.back().id + 1, cricket::kVp9CodecName));
Florent Castellid0b8e8e2023-06-04 23:22:361774 caller_video_codecs.push_back(cricket::CreateVideoRtxCodec(
1775 caller_video_codecs.back().id + 1, caller_video_codecs.back().id));
Florent Castelli2d9d82e2019-04-23 17:25:511776 caller_fake_engine->SetVideoCodecs(caller_video_codecs);
1777
1778 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
1779
1780 auto sender_video_codecs =
1781 caller->pc_factory()
1782 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1783 .codecs;
1784
1785 auto video_transceiver = caller->pc()->GetTransceivers().front();
1786
1787 // Check that RTX codec is properly added
1788 auto video_codecs_vpx_rtx = sender_video_codecs;
1789 auto it =
1790 std::remove_if(video_codecs_vpx_rtx.begin(), video_codecs_vpx_rtx.end(),
Harald Alvestranda6544372023-11-13 09:33:561791 [](const RtpCodecCapability& codec) {
Florent Castelli2d9d82e2019-04-23 17:25:511792 return codec.name != cricket::kRtxCodecName &&
1793 codec.name != cricket::kVp8CodecName &&
1794 codec.name != cricket::kVp9CodecName;
1795 });
1796 video_codecs_vpx_rtx.erase(it, video_codecs_vpx_rtx.end());
1797 absl::c_reverse(video_codecs_vpx_rtx);
1798 EXPECT_EQ(video_codecs_vpx_rtx.size(), 3u); // VP8, VP9, RTX
1799 EXPECT_TRUE(
1800 video_transceiver->SetCodecPreferences(video_codecs_vpx_rtx).ok());
1801 auto offer = caller->CreateOffer();
1802 auto codecs = offer->description()
1803 ->contents()[0]
1804 .media_description()
Florent Castelli2d9d82e2019-04-23 17:25:511805 ->codecs();
1806
1807 EXPECT_TRUE(CompareCodecs(video_codecs_vpx_rtx, codecs));
1808 EXPECT_EQ(codecs.size(), 4u);
1809}
1810
1811TEST_F(PeerConnectionMediaTestUnifiedPlan,
1812 SetCodecPreferencesVideoCodecsNegotiation) {
Mirko Bonadei317a1f02019-09-17 15:06:181813 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Johannes Kron3e983682020-03-29 20:17:001814 auto caller_video_codecs = caller_fake_engine->video().send_codecs();
Florent Castelli8c4b9ea2023-06-02 16:06:571815 caller_video_codecs.push_back(cricket::CreateVideoCodec(
Florent Castelli2d9d82e2019-04-23 17:25:511816 caller_video_codecs.back().id + 1, cricket::kVp8CodecName));
Florent Castellid0b8e8e2023-06-04 23:22:361817 caller_video_codecs.push_back(cricket::CreateVideoRtxCodec(
1818 caller_video_codecs.back().id + 1, caller_video_codecs.back().id));
Florent Castelli8c4b9ea2023-06-02 16:06:571819 caller_video_codecs.push_back(cricket::CreateVideoCodec(
Florent Castelli2d9d82e2019-04-23 17:25:511820 caller_video_codecs.back().id + 1, cricket::kVp9CodecName));
Florent Castellid0b8e8e2023-06-04 23:22:361821 caller_video_codecs.push_back(cricket::CreateVideoRtxCodec(
1822 caller_video_codecs.back().id + 1, caller_video_codecs.back().id));
Florent Castelli2d9d82e2019-04-23 17:25:511823 caller_fake_engine->SetVideoCodecs(caller_video_codecs);
1824
Mirko Bonadei317a1f02019-09-17 15:06:181825 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 17:25:511826 callee_fake_engine->SetVideoCodecs(caller_video_codecs);
1827
1828 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
1829 auto callee = CreatePeerConnection(std::move(callee_fake_engine));
1830
1831 auto video_codecs = caller->pc_factory()
1832 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1833 .codecs;
1834
1835 auto send_transceiver = caller->pc()->GetTransceivers().front();
1836
1837 auto video_codecs_vpx = video_codecs;
1838 auto it = std::remove_if(video_codecs_vpx.begin(), video_codecs_vpx.end(),
Harald Alvestranda6544372023-11-13 09:33:561839 [](const RtpCodecCapability& codec) {
Florent Castelli2d9d82e2019-04-23 17:25:511840 return codec.name != cricket::kVp8CodecName &&
1841 codec.name != cricket::kVp9CodecName;
1842 });
1843 video_codecs_vpx.erase(it, video_codecs_vpx.end());
1844 EXPECT_EQ(video_codecs_vpx.size(), 2u); // VP8, VP9
1845 EXPECT_TRUE(send_transceiver->SetCodecPreferences(video_codecs_vpx).ok());
1846
1847 auto offer = caller->CreateOfferAndSetAsLocal();
1848 auto codecs = offer->description()
1849 ->contents()[0]
1850 .media_description()
Florent Castelli2d9d82e2019-04-23 17:25:511851 ->codecs();
1852
1853 EXPECT_EQ(codecs.size(), 2u); // VP8, VP9
1854 EXPECT_TRUE(CompareCodecs(video_codecs_vpx, codecs));
1855
1856 callee->SetRemoteDescription(std::move(offer));
1857
1858 auto recv_transceiver = callee->pc()->GetTransceivers().front();
1859 auto video_codecs_vp8_rtx = video_codecs;
1860 it = std::remove_if(video_codecs_vp8_rtx.begin(), video_codecs_vp8_rtx.end(),
Harald Alvestranda6544372023-11-13 09:33:561861 [](const RtpCodecCapability& codec) {
Florent Castelli2d9d82e2019-04-23 17:25:511862 bool r = codec.name != cricket::kVp8CodecName &&
1863 codec.name != cricket::kRtxCodecName;
1864 return r;
1865 });
1866 video_codecs_vp8_rtx.erase(it, video_codecs_vp8_rtx.end());
1867 EXPECT_EQ(video_codecs_vp8_rtx.size(), 2u); // VP8, RTX
1868 recv_transceiver->SetCodecPreferences(video_codecs_vp8_rtx);
1869
1870 auto answer = callee->CreateAnswerAndSetAsLocal();
1871
1872 auto recv_codecs = answer->description()
1873 ->contents()[0]
1874 .media_description()
Florent Castelli2d9d82e2019-04-23 17:25:511875 ->codecs();
1876 EXPECT_EQ(recv_codecs.size(), 1u); // VP8
1877}
1878
1879TEST_F(PeerConnectionMediaTestUnifiedPlan,
1880 SetCodecPreferencesVideoCodecsNegotiationReverseOrder) {
Mirko Bonadei317a1f02019-09-17 15:06:181881 auto caller_fake_engine = std::make_unique<FakeMediaEngine>();
Johannes Kron3e983682020-03-29 20:17:001882 auto caller_video_codecs = caller_fake_engine->video().send_codecs();
Florent Castelli8c4b9ea2023-06-02 16:06:571883 caller_video_codecs.push_back(cricket::CreateVideoCodec(
Florent Castelli2d9d82e2019-04-23 17:25:511884 caller_video_codecs.back().id + 1, cricket::kVp8CodecName));
Florent Castellid0b8e8e2023-06-04 23:22:361885 caller_video_codecs.push_back(cricket::CreateVideoRtxCodec(
1886 caller_video_codecs.back().id + 1, caller_video_codecs.back().id));
Florent Castelli8c4b9ea2023-06-02 16:06:571887 caller_video_codecs.push_back(cricket::CreateVideoCodec(
Florent Castelli2d9d82e2019-04-23 17:25:511888 caller_video_codecs.back().id + 1, cricket::kVp9CodecName));
Florent Castellid0b8e8e2023-06-04 23:22:361889 caller_video_codecs.push_back(cricket::CreateVideoRtxCodec(
1890 caller_video_codecs.back().id + 1, caller_video_codecs.back().id));
Florent Castelli2d9d82e2019-04-23 17:25:511891 caller_fake_engine->SetVideoCodecs(caller_video_codecs);
1892
Mirko Bonadei317a1f02019-09-17 15:06:181893 auto callee_fake_engine = std::make_unique<FakeMediaEngine>();
Florent Castelli2d9d82e2019-04-23 17:25:511894 callee_fake_engine->SetVideoCodecs(caller_video_codecs);
1895
1896 auto caller = CreatePeerConnectionWithVideo(std::move(caller_fake_engine));
1897 auto callee = CreatePeerConnection(std::move(callee_fake_engine));
1898
1899 auto video_codecs = caller->pc_factory()
1900 ->GetRtpSenderCapabilities(cricket::MEDIA_TYPE_VIDEO)
1901 .codecs;
1902
1903 auto send_transceiver = caller->pc()->GetTransceivers().front();
1904
1905 auto video_codecs_vpx = video_codecs;
1906 auto it = std::remove_if(video_codecs_vpx.begin(), video_codecs_vpx.end(),
Harald Alvestranda6544372023-11-13 09:33:561907 [](const RtpCodecCapability& codec) {
Florent Castelli2d9d82e2019-04-23 17:25:511908 return codec.name != cricket::kVp8CodecName &&
1909 codec.name != cricket::kVp9CodecName;
1910 });
1911 video_codecs_vpx.erase(it, video_codecs_vpx.end());
1912 EXPECT_EQ(video_codecs_vpx.size(), 2u); // VP8, VP9
1913 EXPECT_TRUE(send_transceiver->SetCodecPreferences(video_codecs_vpx).ok());
1914
1915 auto video_codecs_vpx_reverse = video_codecs_vpx;
1916 absl::c_reverse(video_codecs_vpx_reverse);
1917
1918 auto offer = caller->CreateOfferAndSetAsLocal();
1919 auto codecs = offer->description()
1920 ->contents()[0]
1921 .media_description()
Florent Castelli2d9d82e2019-04-23 17:25:511922 ->codecs();
1923 EXPECT_EQ(codecs.size(), 2u); // VP9, VP8
1924 EXPECT_TRUE(CompareCodecs(video_codecs_vpx, codecs));
1925
1926 callee->SetRemoteDescription(std::move(offer));
1927
1928 auto recv_transceiver = callee->pc()->GetTransceivers().front();
1929 recv_transceiver->SetCodecPreferences(video_codecs_vpx_reverse);
1930
1931 auto answer = callee->CreateAnswerAndSetAsLocal();
1932
1933 auto recv_codecs = answer->description()
1934 ->contents()[0]
1935 .media_description()
Florent Castelli2d9d82e2019-04-23 17:25:511936 ->codecs();
1937
1938 EXPECT_TRUE(CompareCodecs(video_codecs_vpx_reverse, recv_codecs));
1939}
1940
Philipp Hancke3ac73bd2021-05-11 12:13:061941TEST_F(PeerConnectionMediaTestUnifiedPlan,
1942 SetCodecPreferencesVoiceActivityDetection) {
1943 auto fake_engine = std::make_unique<FakeMediaEngine>();
1944 AddComfortNoiseCodecsToSend(fake_engine.get());
1945 auto caller = CreatePeerConnectionWithAudio(std::move(fake_engine));
1946
1947 RTCOfferAnswerOptions options;
1948 auto offer = caller->CreateOffer(options);
1949 EXPECT_TRUE(HasAnyComfortNoiseCodecs(offer->description()));
1950
1951 auto transceiver = caller->pc()->GetTransceivers().front();
1952 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
1953 cricket::MediaType::MEDIA_TYPE_AUDIO);
1954 EXPECT_TRUE(transceiver->SetCodecPreferences(capabilities.codecs).ok());
1955
1956 options.voice_activity_detection = false;
1957 offer = caller->CreateOffer(options);
1958 EXPECT_FALSE(HasAnyComfortNoiseCodecs(offer->description()));
1959}
1960
Taylor Brandstetterf7fcfb72021-09-09 20:39:381961// If the "default" payload types of audio/video codecs are the same, and
1962// audio/video are bundled (as is the default), payload types should be
1963// remapped to avoid conflict, as normally happens without using
1964// SetCodecPreferences.
1965TEST_F(PeerConnectionMediaTestUnifiedPlan,
1966 SetCodecPreferencesAvoidsPayloadTypeConflictInOffer) {
1967 auto fake_engine = std::make_unique<cricket::FakeMediaEngine>();
1968
1969 std::vector<cricket::AudioCodec> audio_codecs;
Florent Castellid0b8e8e2023-06-04 23:22:361970 audio_codecs.emplace_back(cricket::CreateAudioCodec(100, "foo", 0, 1));
1971 audio_codecs.emplace_back(cricket::CreateAudioRtxCodec(101, 100));
Taylor Brandstetterf7fcfb72021-09-09 20:39:381972 fake_engine->SetAudioCodecs(audio_codecs);
1973
1974 std::vector<cricket::VideoCodec> video_codecs;
Florent Castellid0b8e8e2023-06-04 23:22:361975 video_codecs.emplace_back(cricket::CreateVideoCodec(100, "bar"));
1976 video_codecs.emplace_back(cricket::CreateVideoRtxCodec(101, 100));
Taylor Brandstetterf7fcfb72021-09-09 20:39:381977 fake_engine->SetVideoCodecs(video_codecs);
1978
1979 auto caller = CreatePeerConnectionWithAudioVideo(std::move(fake_engine));
1980 auto transceivers = caller->pc()->GetTransceivers();
1981 ASSERT_EQ(2u, transceivers.size());
1982
1983 auto audio_transceiver = caller->pc()->GetTransceivers()[0];
1984 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
1985 cricket::MediaType::MEDIA_TYPE_AUDIO);
1986 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(capabilities.codecs).ok());
1987
1988 auto video_transceiver = caller->pc()->GetTransceivers()[1];
1989 capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
1990 cricket::MediaType::MEDIA_TYPE_VIDEO);
1991 EXPECT_TRUE(video_transceiver->SetCodecPreferences(capabilities.codecs).ok());
1992
1993 RTCOfferAnswerOptions options;
1994 auto offer = caller->CreateOffer(options);
1995 EXPECT_FALSE(HasPayloadTypeConflict(offer->description()));
1996 // Sanity check that we got the primary codec and RTX.
1997 EXPECT_EQ(2u, cricket::GetFirstAudioContentDescription(offer->description())
1998 ->codecs()
1999 .size());
2000 EXPECT_EQ(2u, cricket::GetFirstVideoContentDescription(offer->description())
2001 ->codecs()
2002 .size());
2003}
2004
2005// Same as above, but preferences set for the answer.
2006TEST_F(PeerConnectionMediaTestUnifiedPlan,
2007 SetCodecPreferencesAvoidsPayloadTypeConflictInAnswer) {
2008 auto fake_engine = std::make_unique<cricket::FakeMediaEngine>();
2009
2010 std::vector<cricket::AudioCodec> audio_codecs;
Florent Castellid0b8e8e2023-06-04 23:22:362011 audio_codecs.emplace_back(cricket::CreateAudioCodec(100, "foo", 0, 1));
2012 audio_codecs.emplace_back(cricket::CreateAudioRtxCodec(101, 100));
Taylor Brandstetterf7fcfb72021-09-09 20:39:382013 fake_engine->SetAudioCodecs(audio_codecs);
2014
2015 std::vector<cricket::VideoCodec> video_codecs;
Florent Castellid0b8e8e2023-06-04 23:22:362016 video_codecs.emplace_back(cricket::CreateVideoCodec(100, "bar"));
2017 video_codecs.emplace_back(cricket::CreateVideoRtxCodec(101, 100));
Taylor Brandstetterf7fcfb72021-09-09 20:39:382018 fake_engine->SetVideoCodecs(video_codecs);
2019
2020 auto caller = CreatePeerConnectionWithAudioVideo(std::move(fake_engine));
2021
2022 RTCOfferAnswerOptions options;
2023 caller->SetRemoteDescription(caller->CreateOffer(options));
2024
2025 auto transceivers = caller->pc()->GetTransceivers();
2026 ASSERT_EQ(2u, transceivers.size());
2027
2028 auto audio_transceiver = caller->pc()->GetTransceivers()[0];
2029 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2030 cricket::MediaType::MEDIA_TYPE_AUDIO);
2031 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(capabilities.codecs).ok());
2032
2033 auto video_transceiver = caller->pc()->GetTransceivers()[1];
2034 capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2035 cricket::MediaType::MEDIA_TYPE_VIDEO);
2036 EXPECT_TRUE(video_transceiver->SetCodecPreferences(capabilities.codecs).ok());
2037
2038 auto answer = caller->CreateAnswer(options);
2039
2040 EXPECT_FALSE(HasPayloadTypeConflict(answer->description()));
2041 // Sanity check that we got the primary codec and RTX.
2042 EXPECT_EQ(2u, cricket::GetFirstAudioContentDescription(answer->description())
2043 ->codecs()
2044 .size());
2045 EXPECT_EQ(2u, cricket::GetFirstVideoContentDescription(answer->description())
2046 ->codecs()
2047 .size());
2048}
2049
2050// Same as above, but preferences set for a subsequent offer.
2051TEST_F(PeerConnectionMediaTestUnifiedPlan,
2052 SetCodecPreferencesAvoidsPayloadTypeConflictInSubsequentOffer) {
2053 auto fake_engine = std::make_unique<cricket::FakeMediaEngine>();
2054
2055 std::vector<cricket::AudioCodec> audio_codecs;
Florent Castellid0b8e8e2023-06-04 23:22:362056 audio_codecs.emplace_back(cricket::CreateAudioCodec(100, "foo", 0, 1));
2057 audio_codecs.emplace_back(cricket::CreateAudioRtxCodec(101, 100));
Taylor Brandstetterf7fcfb72021-09-09 20:39:382058 fake_engine->SetAudioCodecs(audio_codecs);
2059
2060 std::vector<cricket::VideoCodec> video_codecs;
Florent Castellid0b8e8e2023-06-04 23:22:362061 video_codecs.emplace_back(cricket::CreateVideoCodec(100, "bar"));
2062 video_codecs.emplace_back(cricket::CreateVideoRtxCodec(101, 100));
Taylor Brandstetterf7fcfb72021-09-09 20:39:382063 fake_engine->SetVideoCodecs(video_codecs);
2064
2065 auto caller = CreatePeerConnectionWithAudioVideo(std::move(fake_engine));
2066
2067 RTCOfferAnswerOptions options;
2068 caller->SetRemoteDescription(caller->CreateOffer(options));
2069 caller->SetLocalDescription(caller->CreateAnswer(options));
2070
2071 auto transceivers = caller->pc()->GetTransceivers();
2072 ASSERT_EQ(2u, transceivers.size());
2073
2074 auto audio_transceiver = caller->pc()->GetTransceivers()[0];
2075 auto capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2076 cricket::MediaType::MEDIA_TYPE_AUDIO);
2077 EXPECT_TRUE(audio_transceiver->SetCodecPreferences(capabilities.codecs).ok());
2078
2079 auto video_transceiver = caller->pc()->GetTransceivers()[1];
2080 capabilities = caller->pc_factory()->GetRtpSenderCapabilities(
2081 cricket::MediaType::MEDIA_TYPE_VIDEO);
2082 EXPECT_TRUE(video_transceiver->SetCodecPreferences(capabilities.codecs).ok());
2083
2084 auto reoffer = caller->CreateOffer(options);
Harald Alvestrand2f553702023-03-07 10:10:032085 ASSERT_THAT(reoffer, NotNull());
Taylor Brandstetterf7fcfb72021-09-09 20:39:382086
2087 EXPECT_FALSE(HasPayloadTypeConflict(reoffer->description()));
2088 // Sanity check that we got the primary codec and RTX.
2089 EXPECT_EQ(2u, cricket::GetFirstAudioContentDescription(reoffer->description())
2090 ->codecs()
2091 .size());
2092 EXPECT_EQ(2u, cricket::GetFirstVideoContentDescription(reoffer->description())
2093 ->codecs()
2094 .size());
2095}
2096
Mirko Bonadeic84f6612019-01-31 11:20:572097INSTANTIATE_TEST_SUITE_P(PeerConnectionMediaTest,
2098 PeerConnectionMediaTest,
Florent Castelli15a38de2022-04-05 22:38:212099 Values(SdpSemantics::kPlanB_DEPRECATED,
Mirko Bonadeic84f6612019-01-31 11:20:572100 SdpSemantics::kUnifiedPlan));
Steve Antonad7bffc2018-01-22 18:21:562101
Steve Anton8d3444d2017-10-20 22:30:512102} // namespace webrtc