summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/pc/sdp_offer_answer_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/pc/sdp_offer_answer_unittest.cc')
-rw-r--r--third_party/libwebrtc/pc/sdp_offer_answer_unittest.cc454
1 files changed, 454 insertions, 0 deletions
diff --git a/third_party/libwebrtc/pc/sdp_offer_answer_unittest.cc b/third_party/libwebrtc/pc/sdp_offer_answer_unittest.cc
new file mode 100644
index 0000000000..e16cd6aafc
--- /dev/null
+++ b/third_party/libwebrtc/pc/sdp_offer_answer_unittest.cc
@@ -0,0 +1,454 @@
+/*
+ * Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "api/audio/audio_mixer.h"
+#include "api/audio_codecs/builtin_audio_decoder_factory.h"
+#include "api/audio_codecs/builtin_audio_encoder_factory.h"
+#include "api/create_peerconnection_factory.h"
+#include "api/media_types.h"
+#include "api/peer_connection_interface.h"
+#include "api/rtp_transceiver_interface.h"
+#include "api/scoped_refptr.h"
+#include "api/video_codecs/builtin_video_decoder_factory.h"
+#include "api/video_codecs/builtin_video_encoder_factory.h"
+#include "modules/audio_device/include/audio_device.h"
+#include "modules/audio_processing/include/audio_processing.h"
+#include "p2p/base/port_allocator.h"
+#include "pc/peer_connection_wrapper.h"
+#include "pc/test/fake_audio_capture_module.h"
+#include "pc/test/mock_peer_connection_observers.h"
+#include "rtc_base/rtc_certificate_generator.h"
+#include "rtc_base/thread.h"
+#include "system_wrappers/include/metrics.h"
+#include "test/gtest.h"
+
+// This file contains unit tests that relate to the behavior of the
+// SdpOfferAnswer module.
+// Tests are writen as integration tests with PeerConnection, since the
+// behaviors are still linked so closely that it is hard to test them in
+// isolation.
+
+namespace webrtc {
+
+using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
+
+namespace {
+
+std::unique_ptr<rtc::Thread> CreateAndStartThread() {
+ auto thread = rtc::Thread::Create();
+ thread->Start();
+ return thread;
+}
+
+} // namespace
+
+class SdpOfferAnswerTest : public ::testing::Test {
+ public:
+ SdpOfferAnswerTest()
+ // Note: We use a PeerConnectionFactory with a distinct
+ // signaling thread, so that thread handling can be tested.
+ : signaling_thread_(CreateAndStartThread()),
+ pc_factory_(
+ CreatePeerConnectionFactory(nullptr,
+ nullptr,
+ signaling_thread_.get(),
+ FakeAudioCaptureModule::Create(),
+ CreateBuiltinAudioEncoderFactory(),
+ CreateBuiltinAudioDecoderFactory(),
+ CreateBuiltinVideoEncoderFactory(),
+ CreateBuiltinVideoDecoderFactory(),
+ nullptr /* audio_mixer */,
+ nullptr /* audio_processing */)) {
+ webrtc::metrics::Reset();
+ }
+
+ std::unique_ptr<PeerConnectionWrapper> CreatePeerConnection() {
+ RTCConfiguration config;
+ config.sdp_semantics = SdpSemantics::kUnifiedPlan;
+ return CreatePeerConnection(config);
+ }
+
+ std::unique_ptr<PeerConnectionWrapper> CreatePeerConnection(
+ const RTCConfiguration& config) {
+ auto observer = std::make_unique<MockPeerConnectionObserver>();
+ auto result = pc_factory_->CreatePeerConnectionOrError(
+ config, PeerConnectionDependencies(observer.get()));
+ EXPECT_TRUE(result.ok());
+ observer->SetPeerConnectionInterface(result.value().get());
+ return std::make_unique<PeerConnectionWrapper>(
+ pc_factory_, result.MoveValue(), std::move(observer));
+ }
+
+ protected:
+ std::unique_ptr<rtc::Thread> signaling_thread_;
+ rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_;
+
+ private:
+ rtc::AutoThread main_thread_;
+};
+
+TEST_F(SdpOfferAnswerTest, OnTrackReturnsProxiedObject) {
+ auto caller = CreatePeerConnection();
+ auto callee = CreatePeerConnection();
+
+ auto audio_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
+
+ ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
+ // Verify that caller->observer->OnTrack() has been called with a
+ // proxied transceiver object.
+ ASSERT_EQ(callee->observer()->on_track_transceivers_.size(), 1u);
+ auto transceiver = callee->observer()->on_track_transceivers_[0];
+ // Since the signaling thread is not the current thread,
+ // this will DCHECK if the transceiver is not proxied.
+ transceiver->stopped();
+}
+
+TEST_F(SdpOfferAnswerTest, BundleRejectsCodecCollisionsAudioVideo) {
+ auto pc = CreatePeerConnection();
+ std::string sdp =
+ "v=0\r\n"
+ "o=- 0 3 IN IP4 127.0.0.1\r\n"
+ "s=-\r\n"
+ "t=0 0\r\n"
+ "a=group:BUNDLE 0 1\r\n"
+ "a=fingerprint:sha-1 "
+ "4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB\r\n"
+ "a=setup:actpass\r\n"
+ "a=ice-ufrag:ETEn\r\n"
+ "a=ice-pwd:OtSK0WpNtpUjkY4+86js7Z/l\r\n"
+ "m=audio 9 UDP/TLS/RTP/SAVPF 111\r\n"
+ "c=IN IP4 0.0.0.0\r\n"
+ "a=rtcp-mux\r\n"
+ "a=sendonly\r\n"
+ "a=mid:0\r\n"
+ "a=rtpmap:111 opus/48000/2\r\n"
+ "m=video 9 UDP/TLS/RTP/SAVPF 111\r\n"
+ "c=IN IP4 0.0.0.0\r\n"
+ "a=rtcp-mux\r\n"
+ "a=sendonly\r\n"
+ "a=mid:1\r\n"
+ "a=rtpmap:111 H264/90000\r\n"
+ "a=fmtp:111 "
+ "level-asymmetry-allowed=1;packetization-mode=0;profile-level-id="
+ "42e01f\r\n";
+
+ auto desc = CreateSessionDescription(SdpType::kOffer, sdp);
+ ASSERT_NE(desc, nullptr);
+ RTCError error;
+ pc->SetRemoteDescription(std::move(desc), &error);
+ EXPECT_TRUE(error.ok());
+ EXPECT_METRIC_EQ(
+ 1, webrtc::metrics::NumEvents(
+ "WebRTC.PeerConnection.ValidBundledPayloadTypes", false));
+}
+
+TEST_F(SdpOfferAnswerTest, BundleRejectsCodecCollisionsVideoFmtp) {
+ auto pc = CreatePeerConnection();
+ std::string sdp =
+ "v=0\r\n"
+ "o=- 0 3 IN IP4 127.0.0.1\r\n"
+ "s=-\r\n"
+ "t=0 0\r\n"
+ "a=group:BUNDLE 0 1\r\n"
+ "a=fingerprint:sha-1 "
+ "4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB\r\n"
+ "a=setup:actpass\r\n"
+ "a=ice-ufrag:ETEn\r\n"
+ "a=ice-pwd:OtSK0WpNtpUjkY4+86js7Z/l\r\n"
+ "m=video 9 UDP/TLS/RTP/SAVPF 111\r\n"
+ "c=IN IP4 0.0.0.0\r\n"
+ "a=rtcp-mux\r\n"
+ "a=sendonly\r\n"
+ "a=mid:0\r\n"
+ "a=rtpmap:111 H264/90000\r\n"
+ "a=fmtp:111 "
+ "level-asymmetry-allowed=1;packetization-mode=0;profile-level-id="
+ "42e01f\r\n"
+ "m=video 9 UDP/TLS/RTP/SAVPF 111\r\n"
+ "c=IN IP4 0.0.0.0\r\n"
+ "a=rtcp-mux\r\n"
+ "a=sendonly\r\n"
+ "a=mid:1\r\n"
+ "a=rtpmap:111 H264/90000\r\n"
+ "a=fmtp:111 "
+ "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id="
+ "42e01f\r\n";
+
+ auto desc = CreateSessionDescription(SdpType::kOffer, sdp);
+ ASSERT_NE(desc, nullptr);
+ RTCError error;
+ pc->SetRemoteDescription(std::move(desc), &error);
+ EXPECT_TRUE(error.ok());
+ EXPECT_METRIC_EQ(
+ 1, webrtc::metrics::NumEvents(
+ "WebRTC.PeerConnection.ValidBundledPayloadTypes", false));
+}
+
+TEST_F(SdpOfferAnswerTest, BundleCodecCollisionInDifferentBundlesAllowed) {
+ auto pc = CreatePeerConnection();
+ std::string sdp =
+ "v=0\r\n"
+ "o=- 0 3 IN IP4 127.0.0.1\r\n"
+ "s=-\r\n"
+ "t=0 0\r\n"
+ "a=group:BUNDLE 0\r\n"
+ "a=group:BUNDLE 1\r\n"
+ "a=fingerprint:sha-1 "
+ "4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB\r\n"
+ "a=setup:actpass\r\n"
+ "a=ice-ufrag:ETEn\r\n"
+ "a=ice-pwd:OtSK0WpNtpUjkY4+86js7Z/l\r\n"
+ "m=video 9 UDP/TLS/RTP/SAVPF 111\r\n"
+ "c=IN IP4 0.0.0.0\r\n"
+ "a=rtcp-mux\r\n"
+ "a=sendonly\r\n"
+ "a=mid:0\r\n"
+ "a=rtpmap:111 H264/90000\r\n"
+ "a=fmtp:111 "
+ "level-asymmetry-allowed=1;packetization-mode=0;profile-level-id="
+ "42e01f\r\n"
+ "m=video 9 UDP/TLS/RTP/SAVPF 111\r\n"
+ "c=IN IP4 0.0.0.0\r\n"
+ "a=rtcp-mux\r\n"
+ "a=sendonly\r\n"
+ "a=mid:1\r\n"
+ "a=rtpmap:111 H264/90000\r\n"
+ "a=fmtp:111 "
+ "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id="
+ "42e01f\r\n";
+
+ auto desc = CreateSessionDescription(SdpType::kOffer, sdp);
+ ASSERT_NE(desc, nullptr);
+ RTCError error;
+ pc->SetRemoteDescription(std::move(desc), &error);
+ EXPECT_TRUE(error.ok());
+ EXPECT_METRIC_EQ(
+ 0, webrtc::metrics::NumEvents(
+ "WebRTC.PeerConnection.ValidBundledPayloadTypes", false));
+}
+
+TEST_F(SdpOfferAnswerTest, BundleMeasuresHeaderExtensionIdCollision) {
+ auto pc = CreatePeerConnection();
+ std::string sdp =
+ "v=0\r\n"
+ "o=- 0 3 IN IP4 127.0.0.1\r\n"
+ "s=-\r\n"
+ "t=0 0\r\n"
+ "a=group:BUNDLE 0 1\r\n"
+ "a=fingerprint:sha-1 "
+ "4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB\r\n"
+ "a=setup:actpass\r\n"
+ "a=ice-ufrag:ETEn\r\n"
+ "a=ice-pwd:OtSK0WpNtpUjkY4+86js7Z/l\r\n"
+ "m=audio 9 UDP/TLS/RTP/SAVPF 111\r\n"
+ "c=IN IP4 0.0.0.0\r\n"
+ "a=rtcp-mux\r\n"
+ "a=sendonly\r\n"
+ "a=mid:0\r\n"
+ "a=rtpmap:111 opus/48000/2\r\n"
+ "a=extmap:3 "
+ "http://www.ietf.org/id/"
+ "draft-holmer-rmcat-transport-wide-cc-extensions-01\r\n"
+ "m=video 9 UDP/TLS/RTP/SAVPF 112\r\n"
+ "c=IN IP4 0.0.0.0\r\n"
+ "a=rtcp-mux\r\n"
+ "a=sendonly\r\n"
+ "a=mid:1\r\n"
+ "a=rtpmap:112 VP8/90000\r\n"
+ "a=extmap:3 "
+ "http://www.ietf.org/id/"
+ "draft-holmer-rmcat-transport-wide-cc-extensions-01\r\n";
+ auto desc = CreateSessionDescription(SdpType::kOffer, sdp);
+ ASSERT_NE(desc, nullptr);
+ RTCError error;
+ pc->SetRemoteDescription(std::move(desc), &error);
+ EXPECT_TRUE(error.ok());
+ EXPECT_METRIC_EQ(1,
+ webrtc::metrics::NumEvents(
+ "WebRTC.PeerConnection.ValidBundledExtensionIds", true));
+}
+
+// extmap:3 is used with two different URIs which is not allowed.
+TEST_F(SdpOfferAnswerTest, BundleRejectsHeaderExtensionIdCollision) {
+ auto pc = CreatePeerConnection();
+ std::string sdp =
+ "v=0\r\n"
+ "o=- 0 3 IN IP4 127.0.0.1\r\n"
+ "s=-\r\n"
+ "t=0 0\r\n"
+ "a=group:BUNDLE 0 1\r\n"
+ "a=fingerprint:sha-1 "
+ "4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB\r\n"
+ "a=setup:actpass\r\n"
+ "a=ice-ufrag:ETEn\r\n"
+ "a=ice-pwd:OtSK0WpNtpUjkY4+86js7Z/l\r\n"
+ "m=audio 9 UDP/TLS/RTP/SAVPF 111\r\n"
+ "c=IN IP4 0.0.0.0\r\n"
+ "a=rtcp-mux\r\n"
+ "a=sendonly\r\n"
+ "a=mid:0\r\n"
+ "a=rtpmap:111 opus/48000/2\r\n"
+ "a=extmap:3 "
+ "http://www.ietf.org/id/"
+ "draft-holmer-rmcat-transport-wide-cc-extensions-01\r\n"
+ "m=video 9 UDP/TLS/RTP/SAVPF 112\r\n"
+ "c=IN IP4 0.0.0.0\r\n"
+ "a=rtcp-mux\r\n"
+ "a=sendonly\r\n"
+ "a=mid:1\r\n"
+ "a=rtpmap:112 VP8/90000\r\n"
+ "a=extmap:3 urn:3gpp:video-orientation\r\n";
+ auto desc = CreateSessionDescription(SdpType::kOffer, sdp);
+ ASSERT_NE(desc, nullptr);
+ RTCError error;
+ pc->SetRemoteDescription(std::move(desc), &error);
+ EXPECT_TRUE(error.ok());
+ EXPECT_METRIC_EQ(
+ 1, webrtc::metrics::NumEvents(
+ "WebRTC.PeerConnection.ValidBundledExtensionIds", false));
+}
+
+// transport-wide cc is negotiated with two different ids 3 and 4.
+// This is not a good idea but tolerable.
+TEST_F(SdpOfferAnswerTest, BundleAcceptsDifferentIdsForSameExtension) {
+ auto pc = CreatePeerConnection();
+ std::string sdp =
+ "v=0\r\n"
+ "o=- 0 3 IN IP4 127.0.0.1\r\n"
+ "s=-\r\n"
+ "t=0 0\r\n"
+ "a=group:BUNDLE 0 1\r\n"
+ "a=fingerprint:sha-1 "
+ "4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB\r\n"
+ "a=setup:actpass\r\n"
+ "a=ice-ufrag:ETEn\r\n"
+ "a=ice-pwd:OtSK0WpNtpUjkY4+86js7Z/l\r\n"
+ "m=audio 9 UDP/TLS/RTP/SAVPF 111\r\n"
+ "c=IN IP4 0.0.0.0\r\n"
+ "a=rtcp-mux\r\n"
+ "a=sendonly\r\n"
+ "a=mid:0\r\n"
+ "a=rtpmap:111 opus/48000/2\r\n"
+ "a=extmap:3 "
+ "http://www.ietf.org/id/"
+ "draft-holmer-rmcat-transport-wide-cc-extensions-01\r\n"
+ "m=video 9 UDP/TLS/RTP/SAVPF 112\r\n"
+ "c=IN IP4 0.0.0.0\r\n"
+ "a=rtcp-mux\r\n"
+ "a=sendonly\r\n"
+ "a=mid:1\r\n"
+ "a=rtpmap:112 VP8/90000\r\n"
+ "a=extmap:4 "
+ "http://www.ietf.org/id/"
+ "draft-holmer-rmcat-transport-wide-cc-extensions-01\r\n";
+ auto desc = CreateSessionDescription(SdpType::kOffer, sdp);
+ ASSERT_NE(desc, nullptr);
+ RTCError error;
+ pc->SetRemoteDescription(std::move(desc), &error);
+ EXPECT_TRUE(error.ok());
+ EXPECT_METRIC_EQ(1,
+ webrtc::metrics::NumEvents(
+ "WebRTC.PeerConnection.ValidBundledExtensionIds", true));
+}
+
+TEST_F(SdpOfferAnswerTest, LargeMidsAreRejected) {
+ auto pc = CreatePeerConnection();
+ std::string sdp =
+ "v=0\r\n"
+ "o=- 0 3 IN IP4 127.0.0.1\r\n"
+ "s=-\r\n"
+ "t=0 0\r\n"
+ "a=fingerprint:sha-1 "
+ "4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB\r\n"
+ "a=setup:actpass\r\n"
+ "a=ice-ufrag:ETEn\r\n"
+ "a=ice-pwd:OtSK0WpNtpUjkY4+86js7Z/l\r\n"
+ "m=video 9 UDP/TLS/RTP/SAVPF 111\r\n"
+ "c=IN IP4 0.0.0.0\r\n"
+ "a=rtcp-mux\r\n"
+ "a=sendonly\r\n"
+ "a=rtpmap:111 VP8/90000\r\n"
+ "a=mid:01234567890123456\r\n";
+ auto desc = CreateSessionDescription(SdpType::kOffer, sdp);
+ ASSERT_NE(desc, nullptr);
+ RTCError error;
+ pc->SetRemoteDescription(std::move(desc), &error);
+ EXPECT_FALSE(error.ok());
+ EXPECT_EQ(error.type(), RTCErrorType::INVALID_PARAMETER);
+}
+
+TEST_F(SdpOfferAnswerTest, RollbackPreservesAddTrackMid) {
+ std::string sdp =
+ "v=0\r\n"
+ "o=- 4131505339648218884 3 IN IP4 **-----**\r\n"
+ "s=-\r\n"
+ "t=0 0\r\n"
+ "a=ice-lite\r\n"
+ "a=msid-semantic: WMS 100030878598094:4Qs1PjbLM32RK5u3\r\n"
+ "a=ice-ufrag:zGWFZ+fVXDeN6UoI/136\r\n"
+ "a=ice-pwd:9AUNgUqRNI5LSIrC1qFD2iTR\r\n"
+ "a=fingerprint:sha-256 "
+ "AD:52:52:E0:B1:37:34:21:0E:15:8E:B7:56:56:7B:B4:39:0E:6D:1C:F5:84:A7:EE:"
+ "B5:27:3E:30:B1:7D:69:42\r\n"
+ "a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\n"
+ "a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid\r\n"
+ "a=group:BUNDLE 0 1\r\n"
+ "m=audio 40005 UDP/TLS/RTP/SAVPF 111\r\n"
+ "a=rtpmap:111 opus/48000/2\r\n"
+ "a=fmtp:111 "
+ "maxaveragebitrate=20000;maxplaybackrate=16000;minptime=10;usedtx=1;"
+ "useinbandfec=1;stereo=0\r\n"
+ "a=rtcp-fb:111 nack\r\n"
+ "a=setup:passive\r\n"
+ "a=mid:0\r\n"
+ "a=msid:- 75156ebd-e705-4da1-920e-2dac39794dfd\r\n"
+ "a=ptime:60\r\n"
+ "a=recvonly\r\n"
+ "a=rtcp-mux\r\n"
+ "m=audio 40005 UDP/TLS/RTP/SAVPF 111\r\n"
+ "a=rtpmap:111 opus/48000/2\r\n"
+ "a=fmtp:111 "
+ "maxaveragebitrate=20000;maxplaybackrate=16000;minptime=10;usedtx=1;"
+ "useinbandfec=1;stereo=0\r\n"
+ "a=rtcp-fb:111 nack\r\n"
+ "a=setup:passive\r\n"
+ "a=mid:1\r\n"
+ "a=msid:100030878598094:4Qs1PjbLM32RK5u3 9695447562408476674\r\n"
+ "a=ptime:60\r\n"
+ "a=sendonly\r\n"
+ "a=ssrc:2565730539 cname:100030878598094:4Qs1PjbLM32RK5u3\r\n"
+ "a=rtcp-mux\r\n";
+ auto pc = CreatePeerConnection();
+ auto audio_track = pc->AddAudioTrack("audio_track", {});
+ auto first_transceiver = pc->pc()->GetTransceivers()[0];
+ EXPECT_FALSE(first_transceiver->mid().has_value());
+ auto desc = CreateSessionDescription(SdpType::kOffer, sdp);
+ ASSERT_NE(desc, nullptr);
+ RTCError error;
+ ASSERT_TRUE(pc->SetRemoteDescription(std::move(desc)));
+ pc->CreateAnswerAndSetAsLocal();
+ auto saved_mid = first_transceiver->mid();
+ EXPECT_TRUE(saved_mid.has_value());
+ auto offer_before_rollback = pc->CreateOfferAndSetAsLocal();
+ EXPECT_EQ(saved_mid, first_transceiver->mid());
+ auto rollback = pc->CreateRollback();
+ ASSERT_NE(rollback, nullptr);
+ ASSERT_TRUE(pc->SetLocalDescription(std::move(rollback)));
+ EXPECT_EQ(saved_mid, first_transceiver->mid());
+ auto offer2 = pc->CreateOfferAndSetAsLocal();
+ ASSERT_NE(offer2, nullptr);
+ EXPECT_EQ(saved_mid, first_transceiver->mid());
+}
+
+} // namespace webrtc