blob: 277979b330305389c898a692620525853ab4640b [file] [log] [blame]
Markus Handell0357b3e2020-03-16 12:40:511/*
2 * Copyright 2020 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#include <memory>
Harald Alvestrandc24a2182022-02-23 13:44:5912#include <string>
Markus Handell0357b3e2020-03-16 12:40:5113#include <tuple>
Harald Alvestrandc24a2182022-02-23 13:44:5914#include <utility>
15#include <vector>
Markus Handell0357b3e2020-03-16 12:40:5116
Harald Alvestrandc24a2182022-02-23 13:44:5917#include "absl/strings/string_view.h"
18#include "absl/types/optional.h"
Harald Alvestrandc24a2182022-02-23 13:44:5919#include "api/jsep.h"
20#include "api/media_types.h"
21#include "api/peer_connection_interface.h"
22#include "api/rtc_error.h"
Markus Handell0357b3e2020-03-16 12:40:5123#include "api/rtc_event_log/rtc_event_log_factory.h"
Harald Alvestrandc24a2182022-02-23 13:44:5924#include "api/rtc_event_log/rtc_event_log_factory_interface.h"
25#include "api/rtp_parameters.h"
26#include "api/rtp_transceiver_direction.h"
27#include "api/rtp_transceiver_interface.h"
28#include "api/scoped_refptr.h"
Markus Handell0357b3e2020-03-16 12:40:5129#include "api/task_queue/default_task_queue_factory.h"
Harald Alvestrandc24a2182022-02-23 13:44:5930#include "api/task_queue/task_queue_factory.h"
Markus Handell0357b3e2020-03-16 12:40:5131#include "media/base/fake_media_engine.h"
Harald Alvestrandc24a2182022-02-23 13:44:5932#include "media/base/media_engine.h"
Markus Handell0357b3e2020-03-16 12:40:5133#include "p2p/base/fake_port_allocator.h"
Harald Alvestrandc24a2182022-02-23 13:44:5934#include "p2p/base/port_allocator.h"
Markus Handell0357b3e2020-03-16 12:40:5135#include "pc/peer_connection_wrapper.h"
Harald Alvestrandc24a2182022-02-23 13:44:5936#include "pc/session_description.h"
Danil Chapovalovc63120a2023-11-03 10:32:2437#include "pc/test/enable_fake_media.h"
Harald Alvestrandc24a2182022-02-23 13:44:5938#include "pc/test/mock_peer_connection_observers.h"
Byoungchan Leed58f5262022-06-27 09:05:2239#include "rtc_base/internal/default_socket_server.h"
Harald Alvestrandc24a2182022-02-23 13:44:5940#include "rtc_base/rtc_certificate_generator.h"
Markus Handell0357b3e2020-03-16 12:40:5141#include "rtc_base/strings/string_builder.h"
Harald Alvestrandc24a2182022-02-23 13:44:5942#include "rtc_base/thread.h"
Markus Handell0357b3e2020-03-16 12:40:5143#include "test/gmock.h"
Harald Alvestrandc24a2182022-02-23 13:44:5944#include "test/gtest.h"
Sameer Vijaykar0793ee72023-01-23 15:31:2945#include "test/scoped_key_value_config.h"
Markus Handell0357b3e2020-03-16 12:40:5146
47namespace webrtc {
48
49using ::testing::Combine;
50using ::testing::ElementsAre;
51using ::testing::Field;
52using ::testing::Return;
53using ::testing::Values;
54
55class PeerConnectionHeaderExtensionTest
56 : public ::testing::TestWithParam<
57 std::tuple<cricket::MediaType, SdpSemantics>> {
58 protected:
Markus Handell755c65d2020-06-23 23:06:1059 PeerConnectionHeaderExtensionTest()
Byoungchan Leed58f5262022-06-27 09:05:2260 : socket_server_(rtc::CreateDefaultSocketServer()),
61 main_thread_(socket_server_.get()),
62 extensions_(
Markus Handell755c65d2020-06-23 23:06:1063 {RtpHeaderExtensionCapability("uri1",
64 1,
65 RtpTransceiverDirection::kStopped),
66 RtpHeaderExtensionCapability("uri2",
67 2,
68 RtpTransceiverDirection::kSendOnly),
69 RtpHeaderExtensionCapability("uri3",
70 3,
71 RtpTransceiverDirection::kRecvOnly),
72 RtpHeaderExtensionCapability(
73 "uri4",
74 4,
75 RtpTransceiverDirection::kSendRecv)}) {}
76
Markus Handell0357b3e2020-03-16 12:40:5177 std::unique_ptr<PeerConnectionWrapper> CreatePeerConnection(
78 cricket::MediaType media_type,
Markus Handell755c65d2020-06-23 23:06:1079 absl::optional<SdpSemantics> semantics) {
Danil Chapovalovc63120a2023-11-03 10:32:2480 auto media_engine = std::make_unique<cricket::FakeMediaEngine>();
Markus Handell0357b3e2020-03-16 12:40:5181 if (media_type == cricket::MediaType::MEDIA_TYPE_AUDIO)
Danil Chapovalovc63120a2023-11-03 10:32:2482 media_engine->fake_voice_engine()->SetRtpHeaderExtensions(extensions_);
Markus Handell0357b3e2020-03-16 12:40:5183 else
Danil Chapovalovc63120a2023-11-03 10:32:2484 media_engine->fake_video_engine()->SetRtpHeaderExtensions(extensions_);
Markus Handell0357b3e2020-03-16 12:40:5185 PeerConnectionFactoryDependencies factory_dependencies;
86 factory_dependencies.network_thread = rtc::Thread::Current();
87 factory_dependencies.worker_thread = rtc::Thread::Current();
88 factory_dependencies.signaling_thread = rtc::Thread::Current();
89 factory_dependencies.task_queue_factory = CreateDefaultTaskQueueFactory();
Danil Chapovalovc63120a2023-11-03 10:32:2490 EnableFakeMedia(factory_dependencies, std::move(media_engine));
91
Markus Handell0357b3e2020-03-16 12:40:5192 factory_dependencies.event_log_factory =
93 std::make_unique<RtcEventLogFactory>(
94 factory_dependencies.task_queue_factory.get());
95
96 auto pc_factory =
97 CreateModularPeerConnectionFactory(std::move(factory_dependencies));
98
99 auto fake_port_allocator = std::make_unique<cricket::FakePortAllocator>(
Byoungchan Leed58f5262022-06-27 09:05:22100 rtc::Thread::Current(),
Sameer Vijaykar0793ee72023-01-23 15:31:29101 std::make_unique<rtc::BasicPacketSocketFactory>(socket_server_.get()),
102 &field_trials_);
Markus Handell0357b3e2020-03-16 12:40:51103 auto observer = std::make_unique<MockPeerConnectionObserver>();
104 PeerConnectionInterface::RTCConfiguration config;
105 if (semantics)
106 config.sdp_semantics = *semantics;
Florent Castelli72424402022-04-06 01:45:10107 PeerConnectionDependencies pc_dependencies(observer.get());
108 pc_dependencies.allocator = std::move(fake_port_allocator);
109 auto result = pc_factory->CreatePeerConnectionOrError(
110 config, std::move(pc_dependencies));
111 EXPECT_TRUE(result.ok());
Niels Möllerafb246b2022-04-20 12:26:50112 observer->SetPeerConnectionInterface(result.value().get());
Florent Castelli72424402022-04-06 01:45:10113 return std::make_unique<PeerConnectionWrapper>(
114 pc_factory, result.MoveValue(), std::move(observer));
Markus Handell0357b3e2020-03-16 12:40:51115 }
Markus Handell755c65d2020-06-23 23:06:10116
Harald Alvestranda6544372023-11-13 09:33:56117 test::ScopedKeyValueConfig field_trials_;
Byoungchan Leed58f5262022-06-27 09:05:22118 std::unique_ptr<rtc::SocketServer> socket_server_;
119 rtc::AutoSocketServerThread main_thread_;
Markus Handell755c65d2020-06-23 23:06:10120 std::vector<RtpHeaderExtensionCapability> extensions_;
Markus Handell0357b3e2020-03-16 12:40:51121};
122
123TEST_P(PeerConnectionHeaderExtensionTest, TransceiverOffersHeaderExtensions) {
124 cricket::MediaType media_type;
125 SdpSemantics semantics;
126 std::tie(media_type, semantics) = GetParam();
127 if (semantics != SdpSemantics::kUnifiedPlan)
128 return;
Markus Handell0357b3e2020-03-16 12:40:51129 std::unique_ptr<PeerConnectionWrapper> wrapper =
Markus Handell755c65d2020-06-23 23:06:10130 CreatePeerConnection(media_type, semantics);
Markus Handell0357b3e2020-03-16 12:40:51131 auto transceiver = wrapper->AddTransceiver(media_type);
Philipp Hancke9f6ae372023-03-06 17:08:31132 EXPECT_EQ(transceiver->GetHeaderExtensionsToNegotiate(), extensions_);
Markus Handell0357b3e2020-03-16 12:40:51133}
134
135TEST_P(PeerConnectionHeaderExtensionTest,
136 SenderReceiverCapabilitiesReturnNotStoppedExtensions) {
137 cricket::MediaType media_type;
138 SdpSemantics semantics;
139 std::tie(media_type, semantics) = GetParam();
Markus Handell755c65d2020-06-23 23:06:10140 std::unique_ptr<PeerConnectionWrapper> wrapper =
141 CreatePeerConnection(media_type, semantics);
Markus Handell0357b3e2020-03-16 12:40:51142 EXPECT_THAT(wrapper->pc_factory()
143 ->GetRtpSenderCapabilities(media_type)
144 .header_extensions,
Markus Handell755c65d2020-06-23 23:06:10145 ElementsAre(Field(&RtpHeaderExtensionCapability::uri, "uri2"),
146 Field(&RtpHeaderExtensionCapability::uri, "uri3"),
147 Field(&RtpHeaderExtensionCapability::uri, "uri4")));
Markus Handell0357b3e2020-03-16 12:40:51148 EXPECT_EQ(wrapper->pc_factory()
149 ->GetRtpReceiverCapabilities(media_type)
150 .header_extensions,
151 wrapper->pc_factory()
152 ->GetRtpSenderCapabilities(media_type)
153 .header_extensions);
154}
155
Markus Handell755c65d2020-06-23 23:06:10156TEST_P(PeerConnectionHeaderExtensionTest, OffersUnstoppedDefaultExtensions) {
157 cricket::MediaType media_type;
158 SdpSemantics semantics;
159 std::tie(media_type, semantics) = GetParam();
160 if (semantics != SdpSemantics::kUnifiedPlan)
161 return;
162 std::unique_ptr<PeerConnectionWrapper> wrapper =
163 CreatePeerConnection(media_type, semantics);
164 auto transceiver = wrapper->AddTransceiver(media_type);
165 auto session_description = wrapper->CreateOffer();
166 EXPECT_THAT(session_description->description()
167 ->contents()[0]
168 .media_description()
169 ->rtp_header_extensions(),
170 ElementsAre(Field(&RtpExtension::uri, "uri2"),
171 Field(&RtpExtension::uri, "uri3"),
172 Field(&RtpExtension::uri, "uri4")));
173}
174
175TEST_P(PeerConnectionHeaderExtensionTest, OffersUnstoppedModifiedExtensions) {
176 cricket::MediaType media_type;
177 SdpSemantics semantics;
178 std::tie(media_type, semantics) = GetParam();
179 if (semantics != SdpSemantics::kUnifiedPlan)
180 return;
181 std::unique_ptr<PeerConnectionWrapper> wrapper =
182 CreatePeerConnection(media_type, semantics);
183 auto transceiver = wrapper->AddTransceiver(media_type);
Philipp Hancke9f6ae372023-03-06 17:08:31184 auto modified_extensions = transceiver->GetHeaderExtensionsToNegotiate();
Markus Handell755c65d2020-06-23 23:06:10185 modified_extensions[0].direction = RtpTransceiverDirection::kSendRecv;
186 modified_extensions[3].direction = RtpTransceiverDirection::kStopped;
187 EXPECT_TRUE(
Philipp Hancke9f6ae372023-03-06 17:08:31188 transceiver->SetHeaderExtensionsToNegotiate(modified_extensions).ok());
Markus Handell755c65d2020-06-23 23:06:10189 auto session_description = wrapper->CreateOffer();
190 EXPECT_THAT(session_description->description()
191 ->contents()[0]
192 .media_description()
193 ->rtp_header_extensions(),
194 ElementsAre(Field(&RtpExtension::uri, "uri1"),
195 Field(&RtpExtension::uri, "uri2"),
196 Field(&RtpExtension::uri, "uri3")));
197}
198
Philipp Hancked4fe3ce2023-03-31 11:33:42199TEST_P(PeerConnectionHeaderExtensionTest, AnswersUnstoppedModifiedExtensions) {
200 cricket::MediaType media_type;
201 SdpSemantics semantics;
202 std::tie(media_type, semantics) = GetParam();
203 if (semantics != SdpSemantics::kUnifiedPlan)
204 return;
205 std::unique_ptr<PeerConnectionWrapper> pc1 =
206 CreatePeerConnection(media_type, semantics);
207 std::unique_ptr<PeerConnectionWrapper> pc2 =
208 CreatePeerConnection(media_type, semantics);
209 auto transceiver1 = pc1->AddTransceiver(media_type);
210
211 auto offer = pc1->CreateOfferAndSetAsLocal(
212 PeerConnectionInterface::RTCOfferAnswerOptions());
213 pc2->SetRemoteDescription(std::move(offer));
214
215 ASSERT_EQ(pc2->pc()->GetTransceivers().size(), 1u);
216 auto transceiver2 = pc2->pc()->GetTransceivers()[0];
217 auto modified_extensions = transceiver2->GetHeaderExtensionsToNegotiate();
218 // Don't offer uri4.
219 modified_extensions[3].direction = RtpTransceiverDirection::kStopped;
220 transceiver2->SetHeaderExtensionsToNegotiate(modified_extensions);
221
222 auto answer = pc2->CreateAnswerAndSetAsLocal(
223 PeerConnectionInterface::RTCOfferAnswerOptions());
224 EXPECT_THAT(answer->description()
225 ->contents()[0]
226 .media_description()
227 ->rtp_header_extensions(),
228 ElementsAre(Field(&RtpExtension::uri, "uri2"),
229 Field(&RtpExtension::uri, "uri3")));
230}
231
Markus Handell5932fe12020-12-17 21:19:40232TEST_P(PeerConnectionHeaderExtensionTest, NegotiatedExtensionsAreAccessible) {
233 cricket::MediaType media_type;
234 SdpSemantics semantics;
235 std::tie(media_type, semantics) = GetParam();
236 if (semantics != SdpSemantics::kUnifiedPlan)
237 return;
238 std::unique_ptr<PeerConnectionWrapper> pc1 =
239 CreatePeerConnection(media_type, semantics);
240 auto transceiver1 = pc1->AddTransceiver(media_type);
Philipp Hancke9f6ae372023-03-06 17:08:31241 auto modified_extensions = transceiver1->GetHeaderExtensionsToNegotiate();
Markus Handell5932fe12020-12-17 21:19:40242 modified_extensions[3].direction = RtpTransceiverDirection::kStopped;
Philipp Hancke9f6ae372023-03-06 17:08:31243 transceiver1->SetHeaderExtensionsToNegotiate(modified_extensions);
Markus Handell5932fe12020-12-17 21:19:40244 auto offer = pc1->CreateOfferAndSetAsLocal(
245 PeerConnectionInterface::RTCOfferAnswerOptions());
246
247 std::unique_ptr<PeerConnectionWrapper> pc2 =
248 CreatePeerConnection(media_type, semantics);
249 auto transceiver2 = pc2->AddTransceiver(media_type);
250 pc2->SetRemoteDescription(std::move(offer));
251 auto answer = pc2->CreateAnswerAndSetAsLocal(
252 PeerConnectionInterface::RTCOfferAnswerOptions());
253 pc1->SetRemoteDescription(std::move(answer));
254
255 // PC1 has exts 2-4 unstopped and PC2 has exts 1-3 unstopped -> ext 2, 3
256 // survives.
Philipp Hancke9f6ae372023-03-06 17:08:31257 EXPECT_THAT(transceiver1->GetNegotiatedHeaderExtensions(),
Philipp Hancke016bd752023-03-20 14:40:45258 ElementsAre(Field(&RtpHeaderExtensionCapability::direction,
259 RtpTransceiverDirection::kStopped),
260 Field(&RtpHeaderExtensionCapability::direction,
261 RtpTransceiverDirection::kSendRecv),
262 Field(&RtpHeaderExtensionCapability::direction,
263 RtpTransceiverDirection::kSendRecv),
264 Field(&RtpHeaderExtensionCapability::direction,
265 RtpTransceiverDirection::kStopped)));
Markus Handell5932fe12020-12-17 21:19:40266}
267
Philipp Hancked4fe3ce2023-03-31 11:33:42268TEST_P(PeerConnectionHeaderExtensionTest, OfferedExtensionsArePerTransceiver) {
269 cricket::MediaType media_type;
270 SdpSemantics semantics;
271 std::tie(media_type, semantics) = GetParam();
272 if (semantics != SdpSemantics::kUnifiedPlan)
273 return;
274 std::unique_ptr<PeerConnectionWrapper> pc1 =
275 CreatePeerConnection(media_type, semantics);
276 auto transceiver1 = pc1->AddTransceiver(media_type);
277 auto modified_extensions = transceiver1->GetHeaderExtensionsToNegotiate();
278 modified_extensions[3].direction = RtpTransceiverDirection::kStopped;
279 transceiver1->SetHeaderExtensionsToNegotiate(modified_extensions);
280 auto transceiver2 = pc1->AddTransceiver(media_type);
281
282 auto session_description = pc1->CreateOffer();
283 EXPECT_THAT(session_description->description()
284 ->contents()[0]
285 .media_description()
286 ->rtp_header_extensions(),
287 ElementsAre(Field(&RtpExtension::uri, "uri2"),
288 Field(&RtpExtension::uri, "uri3")));
289 EXPECT_THAT(session_description->description()
290 ->contents()[1]
291 .media_description()
292 ->rtp_header_extensions(),
293 ElementsAre(Field(&RtpExtension::uri, "uri2"),
294 Field(&RtpExtension::uri, "uri3"),
295 Field(&RtpExtension::uri, "uri4")));
296}
297
298TEST_P(PeerConnectionHeaderExtensionTest, RemovalAfterRenegotiation) {
299 cricket::MediaType media_type;
300 SdpSemantics semantics;
301 std::tie(media_type, semantics) = GetParam();
302 if (semantics != SdpSemantics::kUnifiedPlan)
303 return;
304 std::unique_ptr<PeerConnectionWrapper> pc1 =
305 CreatePeerConnection(media_type, semantics);
306 std::unique_ptr<PeerConnectionWrapper> pc2 =
307 CreatePeerConnection(media_type, semantics);
308 auto transceiver1 = pc1->AddTransceiver(media_type);
309
310 auto offer = pc1->CreateOfferAndSetAsLocal(
311 PeerConnectionInterface::RTCOfferAnswerOptions());
312 pc2->SetRemoteDescription(std::move(offer));
313 auto answer = pc2->CreateAnswerAndSetAsLocal(
314 PeerConnectionInterface::RTCOfferAnswerOptions());
315 pc1->SetRemoteDescription(std::move(answer));
316
317 auto modified_extensions = transceiver1->GetHeaderExtensionsToNegotiate();
318 modified_extensions[3].direction = RtpTransceiverDirection::kStopped;
319 transceiver1->SetHeaderExtensionsToNegotiate(modified_extensions);
320 auto session_description = pc1->CreateOffer();
321 EXPECT_THAT(session_description->description()
322 ->contents()[0]
323 .media_description()
324 ->rtp_header_extensions(),
325 ElementsAre(Field(&RtpExtension::uri, "uri2"),
326 Field(&RtpExtension::uri, "uri3")));
327}
328
Philipp Hancke016bd752023-03-20 14:40:45329TEST_P(PeerConnectionHeaderExtensionTest,
330 StoppedByDefaultExtensionCanBeActivatedByRemoteSdp) {
331 cricket::MediaType media_type;
332 SdpSemantics semantics;
333 std::tie(media_type, semantics) = GetParam();
334 if (semantics != SdpSemantics::kUnifiedPlan)
335 return;
336 std::unique_ptr<PeerConnectionWrapper> pc1 =
337 CreatePeerConnection(media_type, semantics);
338 std::unique_ptr<PeerConnectionWrapper> pc2 =
339 CreatePeerConnection(media_type, semantics);
340 auto transceiver1 = pc1->AddTransceiver(media_type);
341
342 auto offer = pc1->CreateOfferAndSetAsLocal(
343 PeerConnectionInterface::RTCOfferAnswerOptions());
344 pc2->SetRemoteDescription(std::move(offer));
345 auto answer = pc2->CreateAnswerAndSetAsLocal(
346 PeerConnectionInterface::RTCOfferAnswerOptions());
347 std::string sdp;
348 ASSERT_TRUE(answer->ToString(&sdp));
349 // We support uri1 but it is stopped by default. Let the remote reactivate it.
350 sdp += "a=extmap:15 uri1\r\n";
351 auto modified_answer = CreateSessionDescription(SdpType::kAnswer, sdp);
352 pc1->SetRemoteDescription(std::move(modified_answer));
353 EXPECT_THAT(transceiver1->GetNegotiatedHeaderExtensions(),
354 ElementsAre(Field(&RtpHeaderExtensionCapability::direction,
355 RtpTransceiverDirection::kSendRecv),
356 Field(&RtpHeaderExtensionCapability::direction,
357 RtpTransceiverDirection::kSendRecv),
358 Field(&RtpHeaderExtensionCapability::direction,
359 RtpTransceiverDirection::kSendRecv),
360 Field(&RtpHeaderExtensionCapability::direction,
361 RtpTransceiverDirection::kSendRecv)));
362}
363
364TEST_P(PeerConnectionHeaderExtensionTest,
365 UnknownExtensionInRemoteOfferDoesNotShowUp) {
366 cricket::MediaType media_type;
367 SdpSemantics semantics;
368 std::tie(media_type, semantics) = GetParam();
369 if (semantics != SdpSemantics::kUnifiedPlan)
370 return;
371 std::unique_ptr<PeerConnectionWrapper> pc =
372 CreatePeerConnection(media_type, semantics);
373 std::string sdp =
374 "v=0\r\n"
375 "o=- 0 3 IN IP4 127.0.0.1\r\n"
376 "s=-\r\n"
377 "t=0 0\r\n"
378 "a=fingerprint:sha-256 "
379 "A7:24:72:CA:6E:02:55:39:BA:66:DF:6E:CC:4C:D8:B0:1A:BF:1A:56:65:7D:F4:03:"
380 "AD:7E:77:43:2A:29:EC:93\r\n"
381 "a=ice-ufrag:6HHHdzzeIhkE0CKj\r\n"
Philipp Hanckef21cdb02023-03-23 15:41:52382 "a=ice-pwd:XYDGVpfvklQIEnZ6YnyLsAew\r\n";
383 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
384 sdp +=
385 "m=audio 9 RTP/AVPF 111\r\n"
386 "a=rtpmap:111 fake_audio_codec/8000\r\n";
387 } else {
388 sdp +=
389 "m=video 9 RTP/AVPF 111\r\n"
390 "a=rtpmap:111 fake_video_codec/90000\r\n";
391 }
392 sdp +=
Philipp Hancke016bd752023-03-20 14:40:45393 "c=IN IP4 0.0.0.0\r\n"
394 "a=rtcp-mux\r\n"
395 "a=sendonly\r\n"
396 "a=mid:audio\r\n"
Philipp Hancke016bd752023-03-20 14:40:45397 "a=setup:actpass\r\n"
398 "a=extmap:1 urn:bogus\r\n";
Philipp Hancke016bd752023-03-20 14:40:45399 auto offer = CreateSessionDescription(SdpType::kOffer, sdp);
400 pc->SetRemoteDescription(std::move(offer));
401 pc->CreateAnswerAndSetAsLocal(
402 PeerConnectionInterface::RTCOfferAnswerOptions());
403 ASSERT_GT(pc->pc()->GetTransceivers().size(), 0u);
404 auto transceiver = pc->pc()->GetTransceivers()[0];
405 auto negotiated = transceiver->GetNegotiatedHeaderExtensions();
406 EXPECT_EQ(negotiated.size(),
407 transceiver->GetHeaderExtensionsToNegotiate().size());
408 // All extensions are stopped, the "bogus" one does not show up.
409 for (const auto& extension : negotiated) {
410 EXPECT_EQ(extension.direction, RtpTransceiverDirection::kStopped);
411 EXPECT_NE(extension.uri, "urn:bogus");
412 }
413}
414
Philipp Hancke49e55872023-03-30 11:51:39415// These tests are regression tests for behavior that the API
Philipp Hanckef21cdb02023-03-23 15:41:52416// enables in a proper way. It conflicts with the behavior
417// of the API to only offer non-stopped extensions.
418TEST_P(PeerConnectionHeaderExtensionTest,
Philipp Hancke49e55872023-03-30 11:51:39419 SdpMungingAnswerWithoutApiUsageEnablesExtensions) {
Philipp Hanckef21cdb02023-03-23 15:41:52420 cricket::MediaType media_type;
421 SdpSemantics semantics;
422 std::tie(media_type, semantics) = GetParam();
423 if (semantics != SdpSemantics::kUnifiedPlan)
424 return;
425 std::unique_ptr<PeerConnectionWrapper> pc =
426 CreatePeerConnection(media_type, semantics);
427 std::string sdp =
428 "v=0\r\n"
429 "o=- 0 3 IN IP4 127.0.0.1\r\n"
430 "s=-\r\n"
431 "t=0 0\r\n"
432 "a=fingerprint:sha-256 "
433 "A7:24:72:CA:6E:02:55:39:BA:66:DF:6E:CC:4C:D8:B0:1A:BF:1A:56:65:7D:F4:03:"
434 "AD:7E:77:43:2A:29:EC:93\r\n"
435 "a=ice-ufrag:6HHHdzzeIhkE0CKj\r\n"
436 "a=ice-pwd:XYDGVpfvklQIEnZ6YnyLsAew\r\n";
437 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
438 sdp +=
439 "m=audio 9 RTP/AVPF 111\r\n"
440 "a=rtpmap:111 fake_audio_codec/8000\r\n";
441 } else {
442 sdp +=
443 "m=video 9 RTP/AVPF 111\r\n"
444 "a=rtpmap:111 fake_video_codec/90000\r\n";
445 }
446 sdp +=
447 "c=IN IP4 0.0.0.0\r\n"
448 "a=rtcp-mux\r\n"
449 "a=sendrecv\r\n"
450 "a=mid:audio\r\n"
451 "a=setup:actpass\r\n"
452 "a=extmap:1 uri1\r\n";
453 auto offer = CreateSessionDescription(SdpType::kOffer, sdp);
454 pc->SetRemoteDescription(std::move(offer));
455 auto answer =
456 pc->CreateAnswer(PeerConnectionInterface::RTCOfferAnswerOptions());
457 std::string modified_sdp;
458 ASSERT_TRUE(answer->ToString(&modified_sdp));
459 modified_sdp += "a=extmap:1 uri1\r\n";
460 auto modified_answer =
461 CreateSessionDescription(SdpType::kAnswer, modified_sdp);
462 ASSERT_TRUE(pc->SetLocalDescription(std::move(modified_answer)));
463
464 auto session_description = pc->CreateOffer();
Philipp Hanckef21cdb02023-03-23 15:41:52465 EXPECT_THAT(session_description->description()
466 ->contents()[0]
467 .media_description()
468 ->rtp_header_extensions(),
469 ElementsAre(Field(&RtpExtension::uri, "uri1"),
470 Field(&RtpExtension::uri, "uri2"),
471 Field(&RtpExtension::uri, "uri3"),
472 Field(&RtpExtension::uri, "uri4")));
473}
474
Philipp Hancke49e55872023-03-30 11:51:39475TEST_P(PeerConnectionHeaderExtensionTest,
476 SdpMungingOfferWithoutApiUsageEnablesExtensions) {
477 cricket::MediaType media_type;
478 SdpSemantics semantics;
479 std::tie(media_type, semantics) = GetParam();
480 if (semantics != SdpSemantics::kUnifiedPlan)
481 return;
482 std::unique_ptr<PeerConnectionWrapper> pc =
483 CreatePeerConnection(media_type, semantics);
484 pc->AddTransceiver(media_type);
485
486 auto offer =
487 pc->CreateOffer(PeerConnectionInterface::RTCOfferAnswerOptions());
488 std::string modified_sdp;
489 ASSERT_TRUE(offer->ToString(&modified_sdp));
490 modified_sdp += "a=extmap:1 uri1\r\n";
491 auto modified_offer = CreateSessionDescription(SdpType::kOffer, modified_sdp);
492 ASSERT_TRUE(pc->SetLocalDescription(std::move(modified_offer)));
493
494 auto offer2 =
495 pc->CreateOffer(PeerConnectionInterface::RTCOfferAnswerOptions());
496 EXPECT_THAT(offer2->description()
497 ->contents()[0]
498 .media_description()
499 ->rtp_header_extensions(),
500 ElementsAre(Field(&RtpExtension::uri, "uri2"),
501 Field(&RtpExtension::uri, "uri3"),
502 Field(&RtpExtension::uri, "uri4"),
503 Field(&RtpExtension::uri, "uri1")));
504}
505
Philipp Hanckef21cdb02023-03-23 15:41:52506TEST_P(PeerConnectionHeaderExtensionTest, EnablingExtensionsAfterRemoteOffer) {
507 cricket::MediaType media_type;
508 SdpSemantics semantics;
509 std::tie(media_type, semantics) = GetParam();
510 if (semantics != SdpSemantics::kUnifiedPlan)
511 return;
512 std::unique_ptr<PeerConnectionWrapper> pc =
513 CreatePeerConnection(media_type, semantics);
514 std::string sdp =
515 "v=0\r\n"
516 "o=- 0 3 IN IP4 127.0.0.1\r\n"
517 "s=-\r\n"
518 "t=0 0\r\n"
519 "a=fingerprint:sha-256 "
520 "A7:24:72:CA:6E:02:55:39:BA:66:DF:6E:CC:4C:D8:B0:1A:BF:1A:56:65:7D:F4:03:"
521 "AD:7E:77:43:2A:29:EC:93\r\n"
522 "a=ice-ufrag:6HHHdzzeIhkE0CKj\r\n"
523 "a=ice-pwd:XYDGVpfvklQIEnZ6YnyLsAew\r\n";
524 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
525 sdp +=
526 "m=audio 9 RTP/AVPF 111\r\n"
527 "a=rtpmap:111 fake_audio_codec/8000\r\n";
528 } else {
529 sdp +=
530 "m=video 9 RTP/AVPF 111\r\n"
531 "a=rtpmap:111 fake_video_codec/90000\r\n";
532 }
533 sdp +=
534 "c=IN IP4 0.0.0.0\r\n"
535 "a=rtcp-mux\r\n"
536 "a=sendrecv\r\n"
537 "a=mid:audio\r\n"
538 "a=setup:actpass\r\n"
539 "a=extmap:5 uri1\r\n";
540 auto offer = CreateSessionDescription(SdpType::kOffer, sdp);
541 pc->SetRemoteDescription(std::move(offer));
542
543 ASSERT_GT(pc->pc()->GetTransceivers().size(), 0u);
544 auto transceiver = pc->pc()->GetTransceivers()[0];
545 auto modified_extensions = transceiver->GetHeaderExtensionsToNegotiate();
546 modified_extensions[0].direction = RtpTransceiverDirection::kSendRecv;
547 transceiver->SetHeaderExtensionsToNegotiate(modified_extensions);
548
549 pc->CreateAnswerAndSetAsLocal(
550 PeerConnectionInterface::RTCOfferAnswerOptions());
551
552 auto session_description = pc->CreateOffer();
553 auto extensions = session_description->description()
554 ->contents()[0]
555 .media_description()
556 ->rtp_header_extensions();
557 EXPECT_THAT(extensions, ElementsAre(Field(&RtpExtension::uri, "uri1"),
558 Field(&RtpExtension::uri, "uri2"),
559 Field(&RtpExtension::uri, "uri3"),
560 Field(&RtpExtension::uri, "uri4")));
561 // Check uri1's id still matches the remote id.
562 EXPECT_EQ(extensions[0].id, 5);
563}
564
Markus Handell0357b3e2020-03-16 12:40:51565INSTANTIATE_TEST_SUITE_P(
566 ,
567 PeerConnectionHeaderExtensionTest,
Florent Castelli15a38de2022-04-05 22:38:21568 Combine(Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan),
Björn Terelius99261af2021-05-12 17:06:49569 Values(cricket::MediaType::MEDIA_TYPE_AUDIO,
570 cricket::MediaType::MEDIA_TYPE_VIDEO)),
Markus Handell0357b3e2020-03-16 12:40:51571 [](const testing::TestParamInfo<
572 PeerConnectionHeaderExtensionTest::ParamType>& info) {
573 cricket::MediaType media_type;
574 SdpSemantics semantics;
575 std::tie(media_type, semantics) = info.param;
576 return (rtc::StringBuilder("With")
Florent Castelli15a38de2022-04-05 22:38:21577 << (semantics == SdpSemantics::kPlanB_DEPRECATED ? "PlanB"
578 : "UnifiedPlan")
Markus Handell0357b3e2020-03-16 12:40:51579 << "And"
580 << (media_type == cricket::MediaType::MEDIA_TYPE_AUDIO ? "Voice"
581 : "Video")
582 << "Engine")
583 .str();
584 });
585
586} // namespace webrtc