summaryrefslogtreecommitdiff
path: root/Source/WebCore/testing/MockLibWebRTCPeerConnection.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/testing/MockLibWebRTCPeerConnection.cpp')
-rw-r--r--Source/WebCore/testing/MockLibWebRTCPeerConnection.cpp401
1 files changed, 401 insertions, 0 deletions
diff --git a/Source/WebCore/testing/MockLibWebRTCPeerConnection.cpp b/Source/WebCore/testing/MockLibWebRTCPeerConnection.cpp
new file mode 100644
index 000000000..963493125
--- /dev/null
+++ b/Source/WebCore/testing/MockLibWebRTCPeerConnection.cpp
@@ -0,0 +1,401 @@
+/*
+ * Copyright (C) 2017 Apple Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "MockLibWebRTCPeerConnection.h"
+
+#if USE(LIBWEBRTC)
+
+#include "LibWebRTCProvider.h"
+#include <sstream>
+#include <webrtc/api/mediastream.h>
+#include <wtf/Function.h>
+#include <wtf/MainThread.h>
+#include <wtf/NeverDestroyed.h>
+
+namespace WebCore {
+
+static inline rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface>& getRealPeerConnectionFactory()
+{
+ static NeverDestroyed<rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface>> realPeerConnectionFactory;
+ return realPeerConnectionFactory;
+}
+
+static inline webrtc::PeerConnectionFactoryInterface* realPeerConnectionFactory()
+{
+ return getRealPeerConnectionFactory().get();
+}
+
+void useMockRTCPeerConnectionFactory(LibWebRTCProvider* provider, const String& testCase)
+{
+ if (provider && !realPeerConnectionFactory()) {
+ auto& factory = getRealPeerConnectionFactory();
+ factory = &provider->factory();
+ }
+
+ LibWebRTCProvider::setPeerConnectionFactory(MockLibWebRTCPeerConnectionFactory::create(String(testCase)));
+}
+
+class MockLibWebRTCPeerConnectionForIceCandidates : public MockLibWebRTCPeerConnection {
+public:
+ explicit MockLibWebRTCPeerConnectionForIceCandidates(webrtc::PeerConnectionObserver& observer) : MockLibWebRTCPeerConnection(observer) { }
+ virtual ~MockLibWebRTCPeerConnectionForIceCandidates() = default;
+private:
+ void gotLocalDescription() final;
+};
+
+void MockLibWebRTCPeerConnectionForIceCandidates::gotLocalDescription()
+{
+ // Let's gather candidates
+ LibWebRTCProvider::callOnWebRTCSignalingThread([this]() {
+ MockLibWebRTCIceCandidate candidate("2013266431 1 udp 2013266432 192.168.0.100 38838 typ host generation 0", "1");
+ m_observer.OnIceCandidate(&candidate);
+ });
+ LibWebRTCProvider::callOnWebRTCSignalingThread([this]() {
+ MockLibWebRTCIceCandidate candidate("1019216383 1 tcp 1019216384 192.168.0.100 9 typ host tcptype passive generation 0", "1");
+ m_observer.OnIceCandidate(&candidate);
+ });
+ LibWebRTCProvider::callOnWebRTCSignalingThread([this]() {
+ MockLibWebRTCIceCandidate candidate("1677722111 1 tcp 1677722112 172.18.0.1 47989 typ srflx raddr 192.168.0.100 rport 47989 generation 0", "1");
+ m_observer.OnIceCandidate(&candidate);
+ });
+ LibWebRTCProvider::callOnWebRTCSignalingThread([this]() {
+ m_observer.OnIceGatheringChange(webrtc::PeerConnectionInterface::kIceGatheringComplete);
+ });
+}
+
+class MockLibWebRTCPeerConnectionForIceConnectionState : public MockLibWebRTCPeerConnection {
+public:
+ explicit MockLibWebRTCPeerConnectionForIceConnectionState(webrtc::PeerConnectionObserver& observer) : MockLibWebRTCPeerConnection(observer) { }
+ virtual ~MockLibWebRTCPeerConnectionForIceConnectionState() = default;
+
+private:
+ void gotLocalDescription() final;
+};
+
+void MockLibWebRTCPeerConnectionForIceConnectionState::gotLocalDescription()
+{
+ m_observer.OnIceConnectionChange(kIceConnectionChecking);
+ m_observer.OnIceConnectionChange(kIceConnectionConnected);
+ m_observer.OnIceConnectionChange(kIceConnectionCompleted);
+ m_observer.OnIceConnectionChange(kIceConnectionFailed);
+ m_observer.OnIceConnectionChange(kIceConnectionDisconnected);
+ m_observer.OnIceConnectionChange(kIceConnectionNew);
+}
+
+template<typename U> static inline void releaseInNetworkThread(MockLibWebRTCPeerConnection& mock, U& observer)
+{
+ mock.AddRef();
+ observer.AddRef();
+ callOnMainThread([&mock, &observer] {
+ LibWebRTCProvider::callOnWebRTCNetworkThread([&mock, &observer]() {
+ observer.Release();
+ mock.Release();
+ });
+ });
+}
+
+class MockLibWebRTCPeerConnectionReleasedInNetworkThreadWhileCreatingOffer : public MockLibWebRTCPeerConnection {
+public:
+ explicit MockLibWebRTCPeerConnectionReleasedInNetworkThreadWhileCreatingOffer(webrtc::PeerConnectionObserver& observer) : MockLibWebRTCPeerConnection(observer) { }
+ virtual ~MockLibWebRTCPeerConnectionReleasedInNetworkThreadWhileCreatingOffer() = default;
+
+private:
+ void CreateOffer(webrtc::CreateSessionDescriptionObserver* observer, const webrtc::MediaConstraintsInterface*) final { releaseInNetworkThread(*this, *observer); }
+};
+
+class MockLibWebRTCPeerConnectionReleasedInNetworkThreadWhileGettingStats : public MockLibWebRTCPeerConnection {
+public:
+ explicit MockLibWebRTCPeerConnectionReleasedInNetworkThreadWhileGettingStats(webrtc::PeerConnectionObserver& observer) : MockLibWebRTCPeerConnection(observer) { }
+ virtual ~MockLibWebRTCPeerConnectionReleasedInNetworkThreadWhileGettingStats() = default;
+
+private:
+ bool GetStats(webrtc::StatsObserver*, webrtc::MediaStreamTrackInterface*, StatsOutputLevel) final;
+};
+
+bool MockLibWebRTCPeerConnectionReleasedInNetworkThreadWhileGettingStats::GetStats(webrtc::StatsObserver* observer, webrtc::MediaStreamTrackInterface*, StatsOutputLevel)
+{
+ releaseInNetworkThread(*this, *observer);
+ return true;
+}
+
+class MockLibWebRTCPeerConnectionReleasedInNetworkThreadWhileSettingDescription : public MockLibWebRTCPeerConnection {
+public:
+ explicit MockLibWebRTCPeerConnectionReleasedInNetworkThreadWhileSettingDescription(webrtc::PeerConnectionObserver& observer) : MockLibWebRTCPeerConnection(observer) { }
+ virtual ~MockLibWebRTCPeerConnectionReleasedInNetworkThreadWhileSettingDescription() = default;
+
+private:
+ void SetLocalDescription(webrtc::SetSessionDescriptionObserver* observer, webrtc::SessionDescriptionInterface*) final { releaseInNetworkThread(*this, *observer); }
+};
+
+MockLibWebRTCPeerConnectionFactory::MockLibWebRTCPeerConnectionFactory(String&& testCase)
+ : m_testCase(WTFMove(testCase))
+{
+ if (m_testCase == "TwoRealPeerConnections") {
+ m_numberOfRealPeerConnections = 2;
+ return;
+ }
+ if (m_testCase == "OneRealPeerConnection")
+ m_numberOfRealPeerConnections = 1;
+}
+
+rtc::scoped_refptr<webrtc::PeerConnectionInterface> MockLibWebRTCPeerConnectionFactory::CreatePeerConnection(const webrtc::PeerConnectionInterface::RTCConfiguration& configuration, std::unique_ptr<cricket::PortAllocator> portAllocator, std::unique_ptr<rtc::RTCCertificateGeneratorInterface> generator, webrtc::PeerConnectionObserver* observer)
+{
+ if (m_numberOfRealPeerConnections) {
+ auto connection = realPeerConnectionFactory()->CreatePeerConnection(configuration, WTFMove(portAllocator), WTFMove(generator), observer);
+ --m_numberOfRealPeerConnections;
+ return connection;
+ }
+
+ if (m_testCase == "ICECandidates")
+ return new rtc::RefCountedObject<MockLibWebRTCPeerConnectionForIceCandidates>(*observer);
+
+ if (m_testCase == "ICEConnectionState")
+ return new rtc::RefCountedObject<MockLibWebRTCPeerConnectionForIceConnectionState>(*observer);
+
+ if (m_testCase == "LibWebRTCReleasingWhileCreatingOffer")
+ return new rtc::RefCountedObject<MockLibWebRTCPeerConnectionReleasedInNetworkThreadWhileCreatingOffer>(*observer);
+
+ if (m_testCase == "LibWebRTCReleasingWhileGettingStats")
+ return new rtc::RefCountedObject<MockLibWebRTCPeerConnectionReleasedInNetworkThreadWhileGettingStats>(*observer);
+
+ if (m_testCase == "LibWebRTCReleasingWhileSettingDescription")
+ return new rtc::RefCountedObject<MockLibWebRTCPeerConnectionReleasedInNetworkThreadWhileSettingDescription>(*observer);
+
+ return new rtc::RefCountedObject<MockLibWebRTCPeerConnection>(*observer);
+}
+
+rtc::scoped_refptr<webrtc::MediaStreamInterface> MockLibWebRTCPeerConnectionFactory::CreateLocalMediaStream(const std::string& label)
+{
+ return new rtc::RefCountedObject<webrtc::MediaStream>(label);
+}
+
+void MockLibWebRTCPeerConnection::SetLocalDescription(webrtc::SetSessionDescriptionObserver* observer, webrtc::SessionDescriptionInterface*)
+{
+ LibWebRTCProvider::callOnWebRTCSignalingThread([this, observer] {
+ observer->OnSuccess();
+ gotLocalDescription();
+ });
+}
+
+void MockLibWebRTCPeerConnection::SetRemoteDescription(webrtc::SetSessionDescriptionObserver* observer, webrtc::SessionDescriptionInterface* sessionDescription)
+{
+ LibWebRTCProvider::callOnWebRTCSignalingThread([observer] {
+ observer->OnSuccess();
+ });
+ ASSERT(sessionDescription);
+ if (sessionDescription->type() == "offer") {
+ std::string sdp;
+ sessionDescription->ToString(&sdp);
+
+ m_isInitiator = false;
+ m_isReceivingAudio = sdp.find("m=audio") != std::string::npos;
+ m_isReceivingVideo = sdp.find("m=video") != std::string::npos;
+ }
+}
+
+rtc::scoped_refptr<webrtc::DataChannelInterface> MockLibWebRTCPeerConnection::CreateDataChannel(const std::string& label, const webrtc::DataChannelInit* init)
+{
+ webrtc::DataChannelInit parameters;
+ if (init)
+ parameters = *init;
+ return new rtc::RefCountedObject<MockLibWebRTCDataChannel>(std::string(label), parameters.ordered, parameters.reliable, parameters.id);
+}
+
+bool MockLibWebRTCPeerConnection::AddStream(webrtc::MediaStreamInterface* stream)
+{
+ m_stream = stream;
+ LibWebRTCProvider::callOnWebRTCSignalingThread([observer = &m_observer] {
+ observer->OnRenegotiationNeeded();
+ });
+ return true;
+}
+
+void MockLibWebRTCPeerConnection::RemoveStream(webrtc::MediaStreamInterface*)
+{
+ LibWebRTCProvider::callOnWebRTCSignalingThread([observer = &m_observer] {
+ observer->OnRenegotiationNeeded();
+ });
+ m_stream = nullptr;
+}
+
+void MockLibWebRTCPeerConnection::CreateOffer(webrtc::CreateSessionDescriptionObserver* observer, const webrtc::MediaConstraintsInterface*)
+{
+ LibWebRTCProvider::callOnWebRTCSignalingThread([this, observer] {
+ std::ostringstream sdp;
+ sdp <<
+ "v=0\r\n"
+ "o=- 5667094644266930845 " << m_counter++ << " IN IP4 127.0.0.1\r\n"
+ "s=-\r\n"
+ "t=0 0\r\n";
+ if (m_stream) {
+ unsigned partCounter = 1;
+ sdp << "a=msid-semantic:WMS " << m_stream->label() << "\r\n";
+ for (auto& audioTrack : m_stream->GetAudioTracks()) {
+ sdp <<
+ "m=audio 9 UDP/TLS/RTP/SAVPF 111 8 0\r\n"
+ "c=IN IP4 0.0.0.0\r\n"
+ "a=rtcp-mux\r\n"
+ "a=sendrecv\r\n"
+ "a=mid:part" << partCounter++ << "\r\n"
+ "a=rtpmap:111 OPUS/48000/2\r\n"
+ "a=rtpmap:8 PCMA/8000\r\n"
+ "a=rtpmap:0 PCMU/8000\r\n"
+ "a=ssrc:3409173717 cname:/chKzCS9K6KOgL0n\r\n"
+ "a=msid:" << m_stream->label() << " " << audioTrack->id() << "\r\n"
+ "a=ice-ufrag:e/B1\r\n"
+ "a=ice-pwd:Yotk3Im3mnyi+1Q38p51MDub\r\n"
+ "a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B\r\n"
+ "a=setup:actpass\r\n";
+ }
+ for (auto& videoTrack : m_stream->GetVideoTracks()) {
+ sdp <<
+ "m=video 9 UDP/TLS/RTP/SAVPF 103 100 120\r\n"
+ "c=IN IP4 0.0.0.0\r\n"
+ "a=rtcp-mux\r\n"
+ "a=sendrecv\r\n"
+ "a=mid:part" << partCounter++ << "\r\n"
+ "a=rtpmap:103 H264/90000\r\n"
+ "a=rtpmap:100 VP8/90000\r\n"
+ "a=rtpmap:120 RTX/90000\r\n"
+ "a=fmtp:103 packetization-mode=1\r\n"
+ "a=fmtp:120 apt=100;rtx-time=200\r\n"
+ "a=rtcp-fb:100 nack\r\n"
+ "a=rtcp-fb:103 nack pli\r\n"
+ "a=rtcp-fb:100 nack pli\r\n"
+ "a=rtcp-fb:103 ccm fir\r\n"
+ "a=rtcp-fb:100 ccm fir\r\n"
+ "a=ssrc:3409173718 cname:/chKzCS9K6KOgL0n\r\n"
+ "a=msid:" << m_stream->label() << " " << videoTrack->id() << "\r\n"
+ "a=ice-ufrag:e/B1\r\n"
+ "a=ice-pwd:Yotk3Im3mnyi+1Q38p51MDub\r\n"
+ "a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B\r\n"
+ "a=setup:actpass\r\n";
+ }
+ }
+ MockLibWebRTCSessionDescription description(sdp.str());
+ observer->OnSuccess(&description);
+ });
+}
+
+void MockLibWebRTCPeerConnection::CreateAnswer(webrtc::CreateSessionDescriptionObserver* observer, const webrtc::MediaConstraintsInterface*)
+{
+ LibWebRTCProvider::callOnWebRTCSignalingThread([this, observer] {
+ std::ostringstream sdp;
+ sdp <<
+ "v=0\r\n"
+ "o=- 5667094644266930846 " << m_counter++ << " IN IP4 127.0.0.1\r\n"
+ "s=-\r\n"
+ "t=0 0\r\n";
+ if (m_stream) {
+ for (auto& audioTrack : m_stream->GetAudioTracks()) {
+ ASSERT_UNUSED(audioTrack, !!audioTrack);
+ sdp <<
+ "m=audio 9 UDP/TLS/RTP/SAVPF 111 8 0\r\n"
+ "c=IN IP4 0.0.0.0\r\n"
+ "a=rtcp-mux\r\n"
+ "a=recvonly\r\n"
+ "a=mid:part1\r\n"
+ "a=rtpmap:111 OPUS/48000/2\r\n"
+ "a=rtpmap:8 PCMA/8000\r\n"
+ "a=rtpmap:0 PCMU/8000\r\n"
+ "a=ssrc:3409173717 cname:/chKzCS9K6KOgL0m\r\n"
+ "a=ice-ufrag:e/B1\r\n"
+ "a=ice-pwd:Yotk3Im3mnyi+1Q38p51MDub\r\n"
+ "a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B\r\n"
+ "a=setup:active\r\n";
+ }
+ for (auto& videoTrack : m_stream->GetVideoTracks()) {
+ ASSERT_UNUSED(videoTrack, !!videoTrack);
+ sdp <<
+ "m=video 9 UDP/TLS/RTP/SAVPF 103 100 120\r\n"
+ "c=IN IP4 0.0.0.0\r\n"
+ "a=rtcp-mux\r\n"
+ "a=recvonly\r\n"
+ "a=mid:part2\r\n"
+ "a=rtpmap:103 H264/90000\r\n"
+ "a=rtpmap:100 VP8/90000\r\n"
+ "a=rtpmap:120 RTX/90000\r\n"
+ "a=fmtp:103 packetization-mode=1\r\n"
+ "a=fmtp:120 apt=100;rtx-time=200\r\n"
+ "a=rtcp-fb:100 nack\r\n"
+ "a=rtcp-fb:103 nack pli\r\n"
+ "a=rtcp-fb:100 nack pli\r\n"
+ "a=rtcp-fb:103 ccm fir\r\n"
+ "a=rtcp-fb:100 ccm fir\r\n"
+ "a=ssrc:3409173718 cname:/chKzCS9K6KOgL0n\r\n"
+ "a=ice-ufrag:e/B1\r\n"
+ "a=ice-pwd:Yotk3Im3mnyi+1Q38p51MDub\r\n"
+ "a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B\r\n"
+ "a=setup:active\r\n";
+ }
+ } else if (!m_isInitiator) {
+ if (m_isReceivingAudio) {
+ sdp <<
+ "m=audio 9 UDP/TLS/RTP/SAVPF 111 8 0\r\n"
+ "c=IN IP4 0.0.0.0\r\n"
+ "a=rtcp-mux\r\n"
+ "a=recvonly\r\n"
+ "a=mid:part1\r\n"
+ "a=rtpmap:111 OPUS/48000/2\r\n"
+ "a=rtpmap:8 PCMA/8000\r\n"
+ "a=rtpmap:0 PCMU/8000\r\n"
+ "a=ssrc:3409173717 cname:/chKzCS9K6KOgL0m\r\n"
+ "a=ice-ufrag:e/B1\r\n"
+ "a=ice-pwd:Yotk3Im3mnyi+1Q38p51MDub\r\n"
+ "a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B\r\n"
+ "a=setup:active\r\n";
+ }
+ if (m_isReceivingVideo) {
+ sdp <<
+ "m=video 9 UDP/TLS/RTP/SAVPF 103 100 120\r\n"
+ "c=IN IP4 0.0.0.0\r\n"
+ "a=rtcp-mux\r\n"
+ "a=recvonly\r\n"
+ "a=mid:part2\r\n"
+ "a=rtpmap:103 H264/90000\r\n"
+ "a=rtpmap:100 VP8/90000\r\n"
+ "a=rtpmap:120 RTX/90000\r\n"
+ "a=fmtp:103 packetization-mode=1\r\n"
+ "a=fmtp:120 apt=100;rtx-time=200\r\n"
+ "a=rtcp-fb:100 nack\r\n"
+ "a=rtcp-fb:103 nack pli\r\n"
+ "a=rtcp-fb:100 nack pli\r\n"
+ "a=rtcp-fb:103 ccm fir\r\n"
+ "a=rtcp-fb:100 ccm fir\r\n"
+ "a=ssrc:3409173718 cname:/chKzCS9K6KOgL0n\r\n"
+ "a=ice-ufrag:e/B1\r\n"
+ "a=ice-pwd:Yotk3Im3mnyi+1Q38p51MDub\r\n"
+ "a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B\r\n"
+ "a=setup:active\r\n";
+ }
+ }
+ MockLibWebRTCSessionDescription description(sdp.str());
+ observer->OnSuccess(&description);
+ });
+}
+
+} // namespace WebCore
+
+#endif // USE(LIBWEBRTC)