From 4604113749d7e2855082a1c93a9be7e7345cf236 Mon Sep 17 00:00:00 2001 From: "Byron Campen [:bwc]" Date: Thu, 21 Feb 2019 16:42:12 +0000 Subject: [PATCH] Bug 1521879 - Part 1: IPC-based MediaTransport implementation r=mjf Differential Revision: https://phabricator.services.mozilla.com/D17273 --HG-- extra : moz-landing-system : lando --- dom/media/moz.build | 3 +- dom/media/webrtc/PMediaTransport.ipdl | 93 ++++ dom/media/webrtc/WebrtcGlobal.h | 33 ++ dom/media/webrtc/WebrtcIPCTraits.h | 167 ++++++++ dom/media/webrtc/moz.build | 4 + media/mtransport/dtlsidentity.cpp | 1 + media/mtransport/dtlsidentity.h | 1 + media/mtransport/mediapacket.cpp | 70 +++ media/mtransport/mediapacket.h | 30 ++ media/mtransport/nr_socket_prsock.cpp | 2 +- media/mtransport/nr_socket_prsock.h | 6 + .../nICEr/src/net/transport_addr.h | 2 + .../gtest/mediapipeline_unittest.cpp | 33 +- media/webrtc/signaling/src/common/moz.build | 4 + .../src/mediapipeline/MediaPipeline.cpp | 4 +- .../src/mediapipeline/MediaPipeline.h | 2 +- .../peerconnection/MediaTransportHandler.cpp | 389 ++++++++++++++--- .../peerconnection/MediaTransportHandler.h | 45 +- .../MediaTransportHandlerIPC.cpp | 400 ++++++++++++++++++ .../peerconnection/MediaTransportHandlerIPC.h | 91 ++++ .../MediaTransportHandlerParent.cpp | 260 ++++++++++++ .../MediaTransportHandlerParent.h | 78 ++++ .../src/peerconnection/PeerConnectionCtx.h | 4 +- .../src/peerconnection/PeerConnectionImpl.cpp | 10 +- .../signaling/src/peerconnection/moz.build | 2 + netwerk/ipc/NeckoChild.cpp | 2 + netwerk/ipc/PSocketProcessBridge.ipdl | 5 + netwerk/ipc/SocketProcessBridgeChild.cpp | 67 ++- netwerk/ipc/SocketProcessBridgeChild.h | 10 +- netwerk/ipc/SocketProcessBridgeParent.cpp | 19 + netwerk/ipc/SocketProcessBridgeParent.h | 4 + netwerk/ipc/moz.build | 2 + 32 files changed, 1714 insertions(+), 129 deletions(-) create mode 100644 dom/media/webrtc/PMediaTransport.ipdl create mode 100644 dom/media/webrtc/WebrtcIPCTraits.h create mode 100644 media/webrtc/signaling/src/peerconnection/MediaTransportHandlerIPC.cpp create mode 100644 media/webrtc/signaling/src/peerconnection/MediaTransportHandlerIPC.h create mode 100644 media/webrtc/signaling/src/peerconnection/MediaTransportHandlerParent.cpp create mode 100644 media/webrtc/signaling/src/peerconnection/MediaTransportHandlerParent.h diff --git a/dom/media/moz.build b/dom/media/moz.build index 3812bb727d88..0699c5a72fc0 100644 --- a/dom/media/moz.build +++ b/dom/media/moz.build @@ -175,6 +175,7 @@ EXPORTS.mozilla += [ EXPORTS.mozilla.media.webrtc += [ 'webrtc/WebrtcGlobal.h', + 'webrtc/WebrtcIPCTraits.h', ] if not CONFIG['MOZ_WEBRTC']: @@ -183,7 +184,7 @@ if not CONFIG['MOZ_WEBRTC']: ] IPDL_SOURCES += [ - 'webrtc/PWebrtcGlobal.ipdl' + 'webrtc/PWebrtcGlobal.ipdl', ] EXPORTS.mozilla.dom += [ diff --git a/dom/media/webrtc/PMediaTransport.ipdl b/dom/media/webrtc/PMediaTransport.ipdl new file mode 100644 index 000000000000..cc3ae509aa15 --- /dev/null +++ b/dom/media/webrtc/PMediaTransport.ipdl @@ -0,0 +1,93 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +include protocol PSocketProcessBridge; +include PBrowserOrId; + +// ParamTraits stuff for generated code and other classes we don't want to change +include "mozilla/media/webrtc/WebrtcIPCTraits.h"; +using StringVector from "mozilla/media/webrtc/WebrtcIPCTraits.h"; +using CandidateInfo from "mozilla/media/webrtc/WebrtcIPCTraits.h"; +using DtlsDigestList from "mozilla/media/webrtc/WebrtcIPCTraits.h"; +using std::string from "ipc/IPCMessageUtils.h"; +using struct mozilla::dom::RTCStatsReportInternal from "mozilla/dom/RTCStatsReportBinding.h"; +using struct mozilla::dom::MovableRTCStatsReportInternal from "mozilla/media/webrtc/WebrtcGlobal.h"; +using WebrtcGlobalLog from "mozilla/media/webrtc/WebrtcGlobal.h"; +using mozilla::dom::RTCIceServer from "mozilla/dom/RTCConfigurationBinding.h"; +using mozilla::dom::RTCIceTransportPolicy from "mozilla/dom/RTCConfigurationBinding.h"; + +// ParamTraits stuff for our own classes +using MediaPacket from "mtransport/mediapacket.h"; +using net::NrIceStunAddrArray from "mozilla/net/PStunAddrsParams.h"; + +namespace mozilla { +namespace dom { + +async protocol PMediaTransport { + manager PSocketProcessBridge; + +parent: + async __delete__(); + async GetIceLog(nsCString pattern) returns (WebrtcGlobalLog loglines); + async ClearIceLog(); + async EnterPrivateMode(); + async ExitPrivateMode(); + + async CreateIceCtx(string name, + RTCIceServer[] iceServers, + RTCIceTransportPolicy icePolicy); + + async SetProxyServer(PBrowserOrId browserOrId, + nsCString alpn); + + async EnsureProvisionalTransport(string transportId, + string localUfrag, + string localPwd, + int componentCount); + + async StartIceGathering(bool defaultRouteOnly, + NrIceStunAddrArray stunAddrs); + + async ActivateTransport(string transportId, + string localUfrag, + string localPwd, + int componentCount, + string remoteUfrag, + string remotePwd, + uint8_t[] keyDer, + uint8_t[] certDer, + int authType, + bool dtlsClient, + DtlsDigestList digests, + bool privacyRequested); + + async RemoveTransportsExcept(StringVector transportIds); + + async StartIceChecks(bool isControlling, + bool isOfferer, + StringVector iceOptions); + + async SendPacket(string transportId, MediaPacket packet); + + async AddIceCandidate(string transportId, + string candidate); + + async UpdateNetworkState(bool online); + + async GetIceStats(string transportId, + double now, + RTCStatsReportInternal reportIn) returns (MovableRTCStatsReportInternal reportOut); + +child: + async OnCandidate(string transportId, CandidateInfo candidateInfo); + async OnAlpnNegotiated(string alpn); + async OnGatheringStateChange(int state); + async OnConnectionStateChange(int state); + async OnPacketReceived(string transportId, MediaPacket packet); + async OnEncryptedSending(string transportId, MediaPacket packet); + async OnStateChange(string transportId, int state); + async OnRtcpStateChange(string transportId, int state); +}; +} // namespace dom +} // namespace mozilla diff --git a/dom/media/webrtc/WebrtcGlobal.h b/dom/media/webrtc/WebrtcGlobal.h index 2033c2f86ae4..f0bed8c2230c 100644 --- a/dom/media/webrtc/WebrtcGlobal.h +++ b/dom/media/webrtc/WebrtcGlobal.h @@ -14,6 +14,24 @@ typedef mozilla::dom::RTCStatsReportInternal StatsReport; typedef nsTArray> RTCReports; typedef mozilla::dom::Sequence WebrtcGlobalLog; +namespace mozilla { +namespace dom { +// webidl dictionaries don't have move semantics, which is something that ipdl +// needs for async returns. So, we create a "moveable" subclass that just +// copies. _Really_ lame, but it gets the job done. +struct MovableRTCStatsReportInternal : public RTCStatsReportInternal { + MovableRTCStatsReportInternal() = default; + explicit MovableRTCStatsReportInternal(RTCStatsReportInternal&& aReport) { + RTCStatsReportInternal::operator=(aReport); + } + explicit MovableRTCStatsReportInternal( + const RTCStatsReportInternal& aReport) { + RTCStatsReportInternal::operator=(aReport); + } +}; +} // namespace dom +} // namespace mozilla + namespace IPC { template @@ -50,6 +68,21 @@ struct ParamTraits mozilla::dom::RTCIceCandidateType::Host, mozilla::dom::RTCIceCandidateType::EndGuard_> {}; +template <> +struct ParamTraits { + typedef mozilla::dom::MovableRTCStatsReportInternal paramType; + static void Write(Message* aMsg, const paramType& aParam) { + WriteParam( + aMsg, static_cast(aParam)); + } + static bool Read(const Message* aMsg, PickleIterator* aIter, + paramType* aResult) { + return ReadParam( + aMsg, aIter, + static_cast(aResult)); + } +}; + template <> struct ParamTraits { typedef mozilla::dom::RTCStatsReportInternal paramType; diff --git a/dom/media/webrtc/WebrtcIPCTraits.h b/dom/media/webrtc/WebrtcIPCTraits.h new file mode 100644 index 000000000000..5038aa89e5ef --- /dev/null +++ b/dom/media/webrtc/WebrtcIPCTraits.h @@ -0,0 +1,167 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _WEBRTC_IPC_TRAITS_H_ +#define _WEBRTC_IPC_TRAITS_H_ + +#include "ipc/IPCMessageUtils.h" +#include "mozilla/dom/BindingDeclarations.h" +#include "mozilla/dom/RTCConfigurationBinding.h" +#include "mozilla/media/webrtc/WebrtcGlobal.h" +#include "mozilla/dom/CandidateInfo.h" +#include "mozilla/MacroForEach.h" +#include "mtransport/transportlayerdtls.h" +#include + +namespace mozilla { +typedef std::vector StringVector; +} + +namespace IPC { + +template +struct ParamTraits> { + typedef std::vector paramType; + + static void Write(Message* aMsg, const paramType& aParam) { + aMsg->WriteSize(aParam.size()); + for (const T& elem : aParam) { + WriteParam(aMsg, elem); + } + } + + static bool Read(const Message* aMsg, PickleIterator* aIter, + paramType* aResult) { + size_t size; + if (!aMsg->ReadSize(aIter, &size)) { + return false; + } + while (size--) { + // Only works when T is movable. Meh. + T elem; + if (!ReadParam(aMsg, aIter, &elem)) { + return false; + } + aResult->emplace_back(std::move(elem)); + } + + return true; + } +}; + +template <> +struct ParamTraits { + typedef mozilla::dom::OwningStringOrStringSequence paramType; + + // Ugh. OwningStringOrStringSequence already has this enum, but it is + // private generated code. So we have to re-create it. + enum Type { kUninitialized, kString, kStringSequence }; + + static void Write(Message* aMsg, const paramType& aParam) { + if (aParam.IsString()) { + aMsg->WriteInt16(kString); + WriteParam(aMsg, aParam.GetAsString()); + } else if (aParam.IsStringSequence()) { + aMsg->WriteInt16(kStringSequence); + WriteParam(aMsg, aParam.GetAsStringSequence()); + } else { + aMsg->WriteInt16(kUninitialized); + } + } + + static bool Read(const Message* aMsg, PickleIterator* aIter, + paramType* aResult) { + int16_t type; + if (!aMsg->ReadInt16(aIter, &type)) { + return false; + } + + switch (type) { + case kUninitialized: + aResult->Uninit(); + return true; + case kString: + return ReadParam(aMsg, aIter, &aResult->SetAsString()); + case kStringSequence: + return ReadParam(aMsg, aIter, &aResult->SetAsStringSequence()); + } + + return false; + } +}; + +template +struct WebidlEnumSerializer + : public ContiguousEnumSerializer {}; + +template <> +struct ParamTraits + : public WebidlEnumSerializer {}; + +template <> +struct ParamTraits + : public WebidlEnumSerializer {}; + +// A couple of recursive helper functions, allows syntax like: +// WriteParams(aMsg, aParam.foo, aParam.bar, aParam.baz) +// ReadParams(aMsg, aIter, aParam.foo, aParam.bar, aParam.baz) + +// Base case +static void WriteParams(Message* aMsg) {} + +template +static void WriteParams(Message* aMsg, const T0& aArg, + const Tn&... aRemainingArgs) { + WriteParam(aMsg, aArg); // Write first arg + WriteParams(aMsg, aRemainingArgs...); // Recurse for the rest +} + +// Base case +static bool ReadParams(const Message* aMsg, PickleIterator* aIter) { + return true; +} + +template +static bool ReadParams(const Message* aMsg, PickleIterator* aIter, T0& aArg, + Tn&... aRemainingArgs) { + return ReadParam(aMsg, aIter, &aArg) && // Read first arg + ReadParams(aMsg, aIter, aRemainingArgs...); // Recurse for the rest +} + +// Macros that allow syntax like: +// DEFINE_IPC_SERIALIZER_WITH_FIELDS(SomeType, member1, member2, member3) +// Makes sure that serialize/deserialize code do the same members in the same +// order. +#define ACCESS_PARAM_FIELD(Field) aParam.Field + +#define DEFINE_IPC_SERIALIZER_WITH_FIELDS(Type, ...) \ + template <> \ + struct ParamTraits { \ + typedef Type paramType; \ + static void Write(Message* aMsg, const paramType& aParam) { \ + WriteParams(aMsg, MOZ_FOR_EACH_SEPARATED(ACCESS_PARAM_FIELD, (, ), (), \ + (__VA_ARGS__))); \ + } \ + \ + static bool Read(const Message* aMsg, PickleIterator* aIter, \ + paramType* aResult) { \ + paramType& aParam = *aResult; \ + return ReadParams(aMsg, aIter, \ + MOZ_FOR_EACH_SEPARATED(ACCESS_PARAM_FIELD, (, ), (), \ + (__VA_ARGS__))); \ + } \ + }; + +DEFINE_IPC_SERIALIZER_WITH_FIELDS(mozilla::dom::RTCIceServer, mCredential, + mCredentialType, mUrl, mUrls, mUsername) + +DEFINE_IPC_SERIALIZER_WITH_FIELDS(mozilla::CandidateInfo, mCandidate, + mDefaultHostRtp, mDefaultPortRtp, + mDefaultHostRtcp, mDefaultPortRtcp) + +DEFINE_IPC_SERIALIZER_WITH_FIELDS(mozilla::DtlsDigest, algorithm_, value_) + +} // namespace IPC + +#endif // _WEBRTC_IPC_TRAITS_H_ diff --git a/dom/media/webrtc/moz.build b/dom/media/webrtc/moz.build index d8918515a77e..0b3f4704191d 100644 --- a/dom/media/webrtc/moz.build +++ b/dom/media/webrtc/moz.build @@ -53,6 +53,10 @@ if CONFIG['MOZ_WEBRTC']: '/media/webrtc/trunk/webrtc' ] + IPDL_SOURCES += [ + 'PMediaTransport.ipdl', + ] + XPIDL_SOURCES += [ 'nsITabSource.idl' ] diff --git a/media/mtransport/dtlsidentity.cpp b/media/mtransport/dtlsidentity.cpp index 3351dae65508..bb315922807a 100644 --- a/media/mtransport/dtlsidentity.cpp +++ b/media/mtransport/dtlsidentity.cpp @@ -19,6 +19,7 @@ #include "mozilla/Sprintf.h" #include "mozilla/dom/CryptoBuffer.h" #include "mozilla/dom/CryptoKey.h" +#include "ipc/IPCMessageUtils.h" namespace mozilla { diff --git a/media/mtransport/dtlsidentity.h b/media/mtransport/dtlsidentity.h index 63a88a2bd6f5..c1b3e5c5a730 100644 --- a/media/mtransport/dtlsidentity.h +++ b/media/mtransport/dtlsidentity.h @@ -25,6 +25,7 @@ namespace mozilla { class DtlsDigest { public: const static size_t kMaxDtlsDigestLength = HASH_LENGTH_MAX; + DtlsDigest() = default; explicit DtlsDigest(const std::string& algorithm) : algorithm_(algorithm) {} DtlsDigest(const std::string& algorithm, const std::vector& value) : algorithm_(algorithm), value_(value) { diff --git a/media/mtransport/mediapacket.cpp b/media/mtransport/mediapacket.cpp index 8d3f29441dfa..1e8ab106d74d 100644 --- a/media/mtransport/mediapacket.cpp +++ b/media/mtransport/mediapacket.cpp @@ -7,9 +7,15 @@ #include "mediapacket.h" #include +#include "ipc/IPCMessageUtils.h" namespace mozilla { +MediaPacket::MediaPacket(const MediaPacket& orig) + : sdp_level_(orig.sdp_level_), type_(orig.type_) { + Copy(orig.data(), orig.len(), orig.capacity_); +} + void MediaPacket::Copy(const uint8_t* data, size_t len, size_t capacity) { if (capacity < len) { capacity = len; @@ -20,6 +26,70 @@ void MediaPacket::Copy(const uint8_t* data, size_t len, size_t capacity) { memcpy(data_.get(), data, len); } +void MediaPacket::Serialize(IPC::Message* aMsg) const { + aMsg->WriteSize(len_); + aMsg->WriteSize(capacity_); + if (len_) { + aMsg->WriteBytes(data_.get(), len_); + } + aMsg->WriteSize(encrypted_len_); + if (encrypted_len_) { + aMsg->WriteBytes(encrypted_data_.get(), encrypted_len_); + } + aMsg->WriteInt32(sdp_level_.isSome() ? *sdp_level_ : -1); + aMsg->WriteInt32(type_); +} + +bool MediaPacket::Deserialize(const IPC::Message* aMsg, PickleIterator* aIter) { + Reset(); + size_t len; + if (!aMsg->ReadSize(aIter, &len)) { + return false; + } + size_t capacity; + if (!aMsg->ReadSize(aIter, &capacity)) { + return false; + } + if (len) { + MOZ_RELEASE_ASSERT(capacity >= len); + UniquePtr data(new uint8_t[capacity]); + if (!aMsg->ReadBytesInto(aIter, data.get(), len)) { + return false; + } + data_ = std::move(data); + len_ = len; + capacity_ = capacity; + } + + if (!aMsg->ReadSize(aIter, &len)) { + return false; + } + if (len) { + UniquePtr data(new uint8_t[len]); + if (!aMsg->ReadBytesInto(aIter, data.get(), len)) { + return false; + } + encrypted_data_ = std::move(data); + encrypted_len_ = len; + } + + int32_t sdp_level; + if (!aMsg->ReadInt32(aIter, &sdp_level)) { + return false; + } + + if (sdp_level >= 0) { + sdp_level_ = Some(sdp_level); + } + + int32_t type; + if (!aMsg->ReadInt32(aIter, &type)) { + return false; + } + type_ = static_cast(type); + return true; +} + static bool IsRtp(const uint8_t* data, size_t len) { if (len < 2) return false; diff --git a/media/mtransport/mediapacket.h b/media/mtransport/mediapacket.h index 4cfd1fdb42df..a8c3132e8b2d 100644 --- a/media/mtransport/mediapacket.h +++ b/media/mtransport/mediapacket.h @@ -12,6 +12,12 @@ #include "mozilla/UniquePtr.h" #include "mozilla/Maybe.h" +class PickleIterator; + +namespace IPC { +class Message; +} + namespace mozilla { // TODO: It might be worthwhile to teach this class how to "borrow" a buffer. @@ -20,6 +26,7 @@ class MediaPacket { public: MediaPacket() = default; MediaPacket(MediaPacket&& orig) = default; + MediaPacket(const MediaPacket& orig); // Takes ownership of the passed-in data void Take(UniquePtr&& data, size_t len, size_t capacity = 0) { @@ -35,6 +42,9 @@ class MediaPacket { data_.reset(); len_ = 0; capacity_ = 0; + encrypted_data_.reset(); + encrypted_len_ = 0; + sdp_level_.reset(); } // Copies the passed-in data @@ -68,6 +78,9 @@ class MediaPacket { Type type() const { return type_; } + void Serialize(IPC::Message* aMsg) const; + bool Deserialize(const IPC::Message* aMsg, PickleIterator* aIter); + private: UniquePtr data_; size_t len_ = 0; @@ -80,4 +93,21 @@ class MediaPacket { Type type_ = UNCLASSIFIED; }; } // namespace mozilla + +namespace IPC { +template +struct ParamTraits; + +template <> +struct ParamTraits { + static void Write(Message* aMsg, const mozilla::MediaPacket& aParam) { + aParam.Serialize(aMsg); + } + + static bool Read(const Message* aMsg, PickleIterator* aIter, + mozilla::MediaPacket* aResult) { + return aResult->Deserialize(aMsg, aIter); + } +}; +} // namespace IPC #endif // mediapacket_h__ diff --git a/media/mtransport/nr_socket_prsock.cpp b/media/mtransport/nr_socket_prsock.cpp index 1bc3694810e6..943b75832f2b 100644 --- a/media/mtransport/nr_socket_prsock.cpp +++ b/media/mtransport/nr_socket_prsock.cpp @@ -2098,7 +2098,7 @@ int NrSocketBase::CreateSocket( } // create IPC bridge for content process - if (XRE_IsParentProcess()) { + if (XRE_IsParentProcess() || XRE_IsSocketProcess()) { *sock = new NrSocket(); } else { switch (addr->protocol) { diff --git a/media/mtransport/nr_socket_prsock.h b/media/mtransport/nr_socket_prsock.h index 4b73b3d39434..82e6f612e3f9 100644 --- a/media/mtransport/nr_socket_prsock.h +++ b/media/mtransport/nr_socket_prsock.h @@ -69,6 +69,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "mozilla/TimeStamp.h" #include "mozilla/ClearOnShutdown.h" +// nICEr includes +extern "C" { +#include "transport_addr.h" +#include "async_wait.h" +} + // Stub declaration for nICEr type typedef struct nr_socket_vtbl_ nr_socket_vtbl; typedef struct nr_socket_ nr_socket; diff --git a/media/mtransport/third_party/nICEr/src/net/transport_addr.h b/media/mtransport/third_party/nICEr/src/net/transport_addr.h index 5071c252c8b7..f029a886b8c3 100644 --- a/media/mtransport/third_party/nICEr/src/net/transport_addr.h +++ b/media/mtransport/third_party/nICEr/src/net/transport_addr.h @@ -44,6 +44,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #endif +#include "r_types.h" + /* Length of a string hex representation of a MD5 hash */ #define MAXIFNAME 33 diff --git a/media/webrtc/signaling/gtest/mediapipeline_unittest.cpp b/media/webrtc/signaling/gtest/mediapipeline_unittest.cpp index 53629c246d26..3b073222e227 100644 --- a/media/webrtc/signaling/gtest/mediapipeline_unittest.cpp +++ b/media/webrtc/signaling/gtest/mediapipeline_unittest.cpp @@ -132,7 +132,7 @@ class FakeAudioStreamTrack : public mozilla::dom::AudioStreamTrack { class LoopbackTransport : public MediaTransportHandler { public: - LoopbackTransport() { + LoopbackTransport() : MediaTransportHandler(nullptr) { SetState("mux", TransportLayer::TS_INIT, false); SetState("mux", TransportLayer::TS_INIT, true); SetState("non-mux", TransportLayer::TS_INIT, false); @@ -157,9 +157,9 @@ class LoopbackTransport : public MediaTransportHandler { void EnterPrivateMode() override {} void ExitPrivateMode() override {} - nsresult Init(const std::string& aName, - const nsTArray& aIceServers, - dom::RTCIceTransportPolicy aIcePolicy) override { + nsresult CreateIceCtx(const std::string& aName, + const nsTArray& aIceServers, + dom::RTCIceTransportPolicy aIcePolicy) override { return NS_OK; } @@ -213,38 +213,17 @@ class LoopbackTransport : public MediaTransportHandler { peer_->SignalPacketReceived(aTransportId, aPacket); } - TransportLayer::State GetState(const std::string& aTransportId, - bool aRtcp) const override { - if (aRtcp) { - auto it = mRtcpStates.find(aTransportId); - if (it != mRtcpStates.end()) { - return it->second; - } - } else { - auto it = mRtpStates.find(aTransportId); - if (it != mRtpStates.end()) { - return it->second; - } - } - - return TransportLayer::TS_NONE; - } - void SetState(const std::string& aTransportId, TransportLayer::State aState, bool aRtcp) { if (aRtcp) { - mRtcpStates[aTransportId] = aState; - SignalRtcpStateChange(aTransportId, aState); + MediaTransportHandler::OnRtcpStateChange(aTransportId, aState); } else { - mRtpStates[aTransportId] = aState; - SignalStateChange(aTransportId, aState); + MediaTransportHandler::OnStateChange(aTransportId, aState); } } private: RefPtr peer_; - std::map mRtpStates; - std::map mRtcpStates; }; class TestAgent { diff --git a/media/webrtc/signaling/src/common/moz.build b/media/webrtc/signaling/src/common/moz.build index acd3ea76bc61..4a77c364cc4e 100644 --- a/media/webrtc/signaling/src/common/moz.build +++ b/media/webrtc/signaling/src/common/moz.build @@ -5,6 +5,10 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. include('/media/webrtc/webrtc.mozbuild') +EXPORTS.mozilla.dom += [ + 'CandidateInfo.h' +] + LOCAL_INCLUDES += [ '/media/mtransport/third_party/nrappkit/src/util/libekr', '/media/webrtc/trunk', diff --git a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp index 85d4db4bcad4..e6dcfa51df5d 100644 --- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp +++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp @@ -702,7 +702,7 @@ void MediaPipeline::CheckTransportStates() { } } -void MediaPipeline::SendPacket(MediaPacket& packet) { +void MediaPipeline::SendPacket(MediaPacket&& packet) { ASSERT_ON_THREAD(mStsThread); MOZ_ASSERT(mRtpState == TransportLayer::TS_OPEN); MOZ_ASSERT(!mTransportId.empty()); @@ -1284,7 +1284,7 @@ void MediaPipeline::PipelineTransport::SendRtpRtcpPacket_s( ("%s sending %s packet", mPipeline->mDescription.c_str(), (isRtp ? "RTP" : "RTCP"))); - mPipeline->SendPacket(packet); + mPipeline->SendPacket(std::move(packet)); } nsresult MediaPipeline::PipelineTransport::SendRtcpPacket(const uint8_t* aData, diff --git a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.h b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.h index c075526aebee..7cb5b37dc97f 100644 --- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.h +++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.h @@ -197,7 +197,7 @@ class MediaPipeline : public sigslot::has_slots<> { virtual void OnRtpPacketReceived(){}; void IncrementRtcpPacketsReceived(); - virtual void SendPacket(MediaPacket& packet); + virtual void SendPacket(MediaPacket&& packet); // Process slots on transports void RtpStateChange(const std::string& aTransportId, TransportLayer::State); diff --git a/media/webrtc/signaling/src/peerconnection/MediaTransportHandler.cpp b/media/webrtc/signaling/src/peerconnection/MediaTransportHandler.cpp index 227be8f31378..5fddab52e9e7 100644 --- a/media/webrtc/signaling/src/peerconnection/MediaTransportHandler.cpp +++ b/media/webrtc/signaling/src/peerconnection/MediaTransportHandler.cpp @@ -3,6 +3,7 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "MediaTransportHandler.h" +#include "MediaTransportHandlerIPC.h" #include "nricemediastream.h" #include "nriceresolver.h" #include "transportflow.h" @@ -29,6 +30,8 @@ // DTLS #include "signaling/src/sdp/SdpAttribute.h" +#include "runnable_utils.h" + #include "mozilla/Telemetry.h" #include "mozilla/dom/RTCStatsReportBinding.h" @@ -48,16 +51,16 @@ static const char* mthLogTag = "MediaTransportHandler"; class MediaTransportHandlerSTS : public MediaTransportHandler, public sigslot::has_slots<> { public: - MediaTransportHandlerSTS(); + explicit MediaTransportHandlerSTS(nsISerialEventTarget* aCallbackThread); RefPtr GetIceLog(const nsCString& aPattern) override; void ClearIceLog() override; void EnterPrivateMode() override; void ExitPrivateMode() override; - nsresult Init(const std::string& aName, - const nsTArray& aIceServers, - dom::RTCIceTransportPolicy aIcePolicy) override; + nsresult CreateIceCtx(const std::string& aName, + const nsTArray& aIceServers, + dom::RTCIceTransportPolicy aIcePolicy) override; void Destroy() override; // We will probably be able to move the proxy lookup stuff into @@ -101,9 +104,6 @@ class MediaTransportHandlerSTS : public MediaTransportHandler, void SendPacket(const std::string& aTransportId, MediaPacket&& aPacket) override; - TransportLayer::State GetState(const std::string& aTransportId, - bool aRtcp) const override; - RefPtr GetIceStats( const std::string& aTransportId, DOMHighResTimeStamp aNow, std::unique_ptr&& aReport) override; @@ -121,6 +121,15 @@ class MediaTransportHandlerSTS : public MediaTransportHandler, RefPtr mRtcpFlow; }; + using MediaTransportHandler::OnAlpnNegotiated; + using MediaTransportHandler::OnCandidate; + using MediaTransportHandler::OnConnectionStateChange; + using MediaTransportHandler::OnEncryptedSending; + using MediaTransportHandler::OnGatheringStateChange; + using MediaTransportHandler::OnPacketReceived; + using MediaTransportHandler::OnRtcpStateChange; + using MediaTransportHandler::OnStateChange; + void OnGatheringStateChange(NrIceCtx* aIceCtx, NrIceCtx::GatheringState aState); void OnConnectionStateChange(NrIceCtx* aIceCtx, @@ -141,23 +150,25 @@ class MediaTransportHandlerSTS : public MediaTransportHandler, RefPtr mIceCtx; RefPtr mDNSResolver; std::map mTransports; - std::map mStateCache; - std::map mRtcpStateCache; bool mProxyOnly = false; }; /* static */ -already_AddRefed MediaTransportHandler::Create() { +already_AddRefed MediaTransportHandler::Create( + nsISerialEventTarget* aCallbackThread) { RefPtr result; - if (Preferences::GetBool("media.peerconnection.mtransport_process")) { - // TODO: Return a MediaTransportHandlerIPC + if (XRE_IsContentProcess() && + Preferences::GetBool("media.peerconnection.mtransport_process")) { + result = new MediaTransportHandlerIPC(aCallbackThread); } else { - result = new MediaTransportHandlerSTS; + result = new MediaTransportHandlerSTS(aCallbackThread); } return result.forget(); } -MediaTransportHandlerSTS::MediaTransportHandlerSTS() { +MediaTransportHandlerSTS::MediaTransportHandlerSTS( + nsISerialEventTarget* aCallbackThread) + : MediaTransportHandler(aCallbackThread) { nsresult rv; mStsThread = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); if (!mStsThread) { @@ -284,18 +295,17 @@ static nsresult addNrIceServer(const nsString& aIceUrl, return NS_OK; } -nsresult MediaTransportHandlerSTS::Init( - const std::string& aName, const nsTArray& aIceServers, - dom::RTCIceTransportPolicy aIcePolicy) { - std::vector stunServers; - std::vector turnServers; - - nsresult rv; +/* static */ +nsresult MediaTransportHandler::ConvertIceServers( + const nsTArray& aIceServers, + std::vector* aStunServers, + std::vector* aTurnServers) { for (const auto& iceServer : aIceServers) { NS_ENSURE_STATE(iceServer.mUrls.WasPassed()); NS_ENSURE_STATE(iceServer.mUrls.Value().IsStringSequence()); for (const auto& iceUrl : iceServer.mUrls.Value().GetAsStringSequence()) { - rv = addNrIceServer(iceUrl, iceServer, &stunServers, &turnServers); + nsresult rv = + addNrIceServer(iceUrl, iceServer, aStunServers, aTurnServers); if (NS_FAILED(rv)) { CSFLogError(LOGTAG, "%s: invalid STUN/TURN server: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(iceUrl).get()); @@ -304,6 +314,19 @@ nsresult MediaTransportHandlerSTS::Init( } } + return NS_OK; +} + +nsresult MediaTransportHandlerSTS::CreateIceCtx( + const std::string& aName, const nsTArray& aIceServers, + dom::RTCIceTransportPolicy aIcePolicy) { + std::vector stunServers; + std::vector turnServers; + nsresult rv = ConvertIceServers(aIceServers, &stunServers, &turnServers); + if (NS_FAILED(rv)) { + return rv; + } + // This stuff will probably live on the other side of IPC; errors down here // will either need to be ignored, or plumbed back in some way other than // the return. @@ -357,6 +380,13 @@ nsresult MediaTransportHandlerSTS::Init( } void MediaTransportHandlerSTS::Destroy() { + if (!mStsThread->IsOnCurrentThread()) { + mStsThread->Dispatch(WrapRunnable(RefPtr(this), + &MediaTransportHandlerSTS::Destroy), + NS_DISPATCH_NORMAL); + return; + } + disconnect_all(); if (mIceCtx) { NrIceStats stats = mIceCtx->Destroy(); @@ -381,12 +411,28 @@ void MediaTransportHandlerSTS::Destroy() { void MediaTransportHandlerSTS::SetProxyServer( NrSocketProxyConfig&& aProxyConfig) { + if (!mStsThread->IsOnCurrentThread()) { + mStsThread->Dispatch(NewRunnableMethod( + __func__, this, &MediaTransportHandlerSTS::SetProxyServer, + std::move(aProxyConfig))); + return; + } + mIceCtx->SetProxyServer(std::move(aProxyConfig)); } void MediaTransportHandlerSTS::EnsureProvisionalTransport( const std::string& aTransportId, const std::string& aUfrag, const std::string& aPwd, size_t aComponentCount) { + if (!mStsThread->IsOnCurrentThread()) { + mStsThread->Dispatch( + WrapRunnable(RefPtr(this), + &MediaTransportHandlerSTS::EnsureProvisionalTransport, + aTransportId, aUfrag, aPwd, aComponentCount), + NS_DISPATCH_NORMAL); + return; + } + RefPtr stream(mIceCtx->GetStream(aTransportId)); if (!stream) { CSFLogDebug(LOGTAG, "%s: Creating ICE media stream=%s components=%u", @@ -420,6 +466,17 @@ void MediaTransportHandlerSTS::ActivateTransport( const nsTArray& aKeyDer, const nsTArray& aCertDer, SSLKEAType aAuthType, bool aDtlsClient, const DtlsDigestList& aDigests, bool aPrivacyRequested) { + if (!mStsThread->IsOnCurrentThread()) { + mStsThread->Dispatch( + WrapRunnable(RefPtr(this), + &MediaTransportHandlerSTS::ActivateTransport, aTransportId, + aLocalUfrag, aLocalPwd, aComponentCount, aUfrag, aPassword, + aKeyDer, aCertDer, aAuthType, aDtlsClient, aDigests, + aPrivacyRequested), + NS_DISPATCH_NORMAL); + return; + } + MOZ_ASSERT(aComponentCount); RefPtr dtlsIdentity( DtlsIdentity::Deserialize(aKeyDer, aCertDer, aAuthType)); @@ -494,6 +551,15 @@ void MediaTransportHandlerSTS::ActivateTransport( void MediaTransportHandlerSTS::StartIceGathering( bool aDefaultRouteOnly, const nsTArray& aStunAddrs) { + if (!mStsThread->IsOnCurrentThread()) { + mStsThread->Dispatch( + WrapRunnable(RefPtr(this), + &MediaTransportHandlerSTS::StartIceGathering, + aDefaultRouteOnly, aStunAddrs), + NS_DISPATCH_NORMAL); + return; + } + // Belt and suspenders - in e10s mode, the call below to SetStunAddrs // needs to have the proper flags set on ice ctx. For non-e10s, // setting those flags happens in StartGathering. We could probably @@ -517,12 +583,20 @@ void MediaTransportHandlerSTS::StartIceGathering( // If there are no streams, we're probably in a situation where we've rolled // back while still waiting for our proxy configuration to come back. Make // sure content knows that the rollback has stuck wrt gathering. - SignalGatheringStateChange(dom::PCImplIceGatheringState::Complete); + OnGatheringStateChange(dom::PCImplIceGatheringState::Complete); } void MediaTransportHandlerSTS::StartIceChecks( bool aIsControlling, bool aIsOfferer, const std::vector& aIceOptions) { + if (!mStsThread->IsOnCurrentThread()) { + mStsThread->Dispatch(WrapRunnable(RefPtr(this), + &MediaTransportHandlerSTS::StartIceChecks, + aIsControlling, aIsOfferer, aIceOptions), + NS_DISPATCH_NORMAL); + return; + } + nsresult rv = mIceCtx->ParseGlobalAttributes(aIceOptions); if (NS_FAILED(rv)) { CSFLogError(LOGTAG, "%s: couldn't parse global parameters", __FUNCTION__); @@ -546,6 +620,15 @@ void MediaTransportHandlerSTS::StartIceChecks( void MediaTransportHandlerSTS::AddIceCandidate(const std::string& aTransportId, const std::string& aCandidate) { + if (!mStsThread->IsOnCurrentThread()) { + mStsThread->Dispatch( + WrapRunnable(RefPtr(this), + &MediaTransportHandlerSTS::AddIceCandidate, aTransportId, + aCandidate), + NS_DISPATCH_NORMAL); + return; + } + RefPtr stream(mIceCtx->GetStream(aTransportId)); if (!stream) { CSFLogError(LOGTAG, "No ICE stream for candidate with transport id %s: %s", @@ -563,16 +646,33 @@ void MediaTransportHandlerSTS::AddIceCandidate(const std::string& aTransportId, } void MediaTransportHandlerSTS::UpdateNetworkState(bool aOnline) { + if (!mStsThread->IsOnCurrentThread()) { + mStsThread->Dispatch( + WrapRunnable(RefPtr(this), + &MediaTransportHandlerSTS::UpdateNetworkState, aOnline), + NS_DISPATCH_NORMAL); + return; + } + mIceCtx->UpdateNetworkState(aOnline); } void MediaTransportHandlerSTS::RemoveTransportsExcept( const std::set& aTransportIds) { + if (!mStsThread->IsOnCurrentThread()) { + mStsThread->Dispatch( + WrapRunnable(RefPtr(this), + &MediaTransportHandlerSTS::RemoveTransportsExcept, + aTransportIds), + NS_DISPATCH_NORMAL); + return; + } + for (auto it = mTransports.begin(); it != mTransports.end();) { if (!aTransportIds.count(it->first)) { if (it->second.mFlow) { - SignalStateChange(it->first, TransportLayer::TS_NONE); - SignalRtcpStateChange(it->first, TransportLayer::TS_NONE); + OnStateChange(it->first, TransportLayer::TS_NONE); + OnRtcpStateChange(it->first, TransportLayer::TS_NONE); } mIceCtx->DestroyStream(it->first); it = mTransports.erase(it); @@ -585,6 +685,13 @@ void MediaTransportHandlerSTS::RemoveTransportsExcept( void MediaTransportHandlerSTS::SendPacket(const std::string& aTransportId, MediaPacket&& aPacket) { + if (!mStsThread->IsOnCurrentThread()) { + mStsThread->Dispatch(NewRunnableMethod( + __func__, this, &MediaTransportHandlerSTS::SendPacket, aTransportId, + std::move(aPacket))); + return; + } + MOZ_ASSERT(aPacket.type() != MediaPacket::UNCLASSIFIED); RefPtr flow = GetTransportFlow(aTransportId, aPacket.type() == MediaPacket::RTCP); @@ -620,45 +727,191 @@ void MediaTransportHandlerSTS::SendPacket(const std::string& aTransportId, } } -TransportLayer::State MediaTransportHandlerSTS::GetState( +TransportLayer::State MediaTransportHandler::GetState( const std::string& aTransportId, bool aRtcp) const { // TODO Bug 1520692: we should allow Datachannel to connect without // DTLS SRTP keys - RefPtr flow = GetTransportFlow(aTransportId, aRtcp); - if (flow) { - return flow->GetLayer(TransportLayerDtls::ID())->state(); + if (mCallbackThread) { + MOZ_ASSERT(mCallbackThread->IsOnCurrentThread()); + } + + const std::map* cache = nullptr; + if (aRtcp) { + cache = &mRtcpStateCache; + } else { + cache = &mStateCache; + } + + auto it = cache->find(aTransportId); + if (it != cache->end()) { + return it->second; } return TransportLayer::TS_NONE; } +void MediaTransportHandler::OnCandidate(const std::string& aTransportId, + const CandidateInfo& aCandidateInfo) { + if (mCallbackThread && !mCallbackThread->IsOnCurrentThread()) { + mCallbackThread->Dispatch(WrapRunnable(RefPtr(this), + &MediaTransportHandler::OnCandidate, + aTransportId, aCandidateInfo), + NS_DISPATCH_NORMAL); + return; + } + + SignalCandidate(aTransportId, aCandidateInfo); +} + +void MediaTransportHandler::OnAlpnNegotiated(const std::string& aAlpn) { + if (mCallbackThread && !mCallbackThread->IsOnCurrentThread()) { + mCallbackThread->Dispatch( + WrapRunnable(RefPtr(this), + &MediaTransportHandler::OnAlpnNegotiated, aAlpn), + NS_DISPATCH_NORMAL); + return; + } + + SignalAlpnNegotiated(aAlpn); +} + +void MediaTransportHandler::OnGatheringStateChange( + dom::PCImplIceGatheringState aState) { + if (mCallbackThread && !mCallbackThread->IsOnCurrentThread()) { + mCallbackThread->Dispatch( + WrapRunnable(RefPtr(this), + &MediaTransportHandler::OnGatheringStateChange, aState), + NS_DISPATCH_NORMAL); + return; + } + + SignalGatheringStateChange(aState); +} + +void MediaTransportHandler::OnConnectionStateChange( + dom::PCImplIceConnectionState aState) { + if (mCallbackThread && !mCallbackThread->IsOnCurrentThread()) { + mCallbackThread->Dispatch( + WrapRunnable(RefPtr(this), + &MediaTransportHandler::OnConnectionStateChange, aState), + NS_DISPATCH_NORMAL); + return; + } + + SignalConnectionStateChange(aState); +} + +void MediaTransportHandler::OnPacketReceived(const std::string& aTransportId, + MediaPacket& aPacket) { + if (mCallbackThread && !mCallbackThread->IsOnCurrentThread()) { + mCallbackThread->Dispatch( + WrapRunnable(RefPtr(this), + &MediaTransportHandler::OnPacketReceived, aTransportId, + aPacket), + NS_DISPATCH_NORMAL); + return; + } + + SignalPacketReceived(aTransportId, aPacket); +} + +void MediaTransportHandler::OnEncryptedSending(const std::string& aTransportId, + MediaPacket& aPacket) { + if (mCallbackThread && !mCallbackThread->IsOnCurrentThread()) { + mCallbackThread->Dispatch( + WrapRunnable(RefPtr(this), + &MediaTransportHandler::OnEncryptedSending, aTransportId, + aPacket), + NS_DISPATCH_NORMAL); + return; + } + + SignalEncryptedSending(aTransportId, aPacket); +} + +void MediaTransportHandler::OnStateChange(const std::string& aTransportId, + TransportLayer::State aState) { + if (mCallbackThread && !mCallbackThread->IsOnCurrentThread()) { + mCallbackThread->Dispatch( + WrapRunnable(RefPtr(this), + &MediaTransportHandler::OnStateChange, aTransportId, + aState), + NS_DISPATCH_NORMAL); + return; + } + + if (aState == TransportLayer::TS_NONE) { + mStateCache.erase(aTransportId); + } else { + mStateCache[aTransportId] = aState; + } + SignalStateChange(aTransportId, aState); +} + +void MediaTransportHandler::OnRtcpStateChange(const std::string& aTransportId, + TransportLayer::State aState) { + if (mCallbackThread && !mCallbackThread->IsOnCurrentThread()) { + mCallbackThread->Dispatch( + WrapRunnable(RefPtr(this), + &MediaTransportHandler::OnRtcpStateChange, aTransportId, + aState), + NS_DISPATCH_NORMAL); + return; + } + + if (aState == TransportLayer::TS_NONE) { + mRtcpStateCache.erase(aTransportId); + } else { + mRtcpStateCache[aTransportId] = aState; + } + SignalRtcpStateChange(aTransportId, aState); +} + RefPtr MediaTransportHandlerSTS::GetIceStats( const std::string& aTransportId, DOMHighResTimeStamp aNow, std::unique_ptr&& aReport) { - for (const auto& stream : mIceCtx->GetStreams()) { - if (aTransportId.empty() || aTransportId == stream->GetId()) { - GetIceStats(*stream, aNow, aReport.get()); - } - } - return StatsPromise::CreateAndResolve(std::move(aReport), __func__); + return InvokeAsync( + mStsThread, __func__, + [=, aReport = std::move(aReport), + self = RefPtr(this)]() mutable { + if (mIceCtx) { + for (const auto& stream : mIceCtx->GetStreams()) { + if (aTransportId.empty() || aTransportId == stream->GetId()) { + GetIceStats(*stream, aNow, aReport.get()); + } + } + } + return StatsPromise::CreateAndResolve(std::move(aReport), __func__); + }); } RefPtr MediaTransportHandlerSTS::GetIceLog(const nsCString& aPattern) { - RLogConnector* logs = RLogConnector::GetInstance(); - nsAutoPtr> result(new std::deque); - // Might not exist yet. - if (logs) { - logs->Filter(aPattern.get(), 0, result); - } - dom::Sequence converted; - for (auto& line : *result) { - converted.AppendElement(NS_ConvertUTF8toUTF16(line.c_str()), fallible); - } - return IceLogPromise::CreateAndResolve(std::move(converted), __func__); + return InvokeAsync( + mStsThread, __func__, [=, self = RefPtr(this)] { + dom::Sequence converted; + RLogConnector* logs = RLogConnector::GetInstance(); + nsAutoPtr> result(new std::deque); + // Might not exist yet. + if (logs) { + logs->Filter(aPattern.get(), 0, result); + } + for (auto& line : *result) { + converted.AppendElement(NS_ConvertUTF8toUTF16(line.c_str()), + fallible); + } + return IceLogPromise::CreateAndResolve(std::move(converted), __func__); + }); } void MediaTransportHandlerSTS::ClearIceLog() { + if (!mStsThread->IsOnCurrentThread()) { + mStsThread->Dispatch(WrapRunnable(RefPtr(this), + &MediaTransportHandlerSTS::ClearIceLog), + NS_DISPATCH_NORMAL); + return; + } + RLogConnector* logs = RLogConnector::GetInstance(); if (logs) { logs->Clear(); @@ -666,10 +919,26 @@ void MediaTransportHandlerSTS::ClearIceLog() { } void MediaTransportHandlerSTS::EnterPrivateMode() { + if (!mStsThread->IsOnCurrentThread()) { + mStsThread->Dispatch( + WrapRunnable(RefPtr(this), + &MediaTransportHandlerSTS::EnterPrivateMode), + NS_DISPATCH_NORMAL); + return; + } + RLogConnector::CreateInstance()->EnterPrivateMode(); } void MediaTransportHandlerSTS::ExitPrivateMode() { + if (!mStsThread->IsOnCurrentThread()) { + mStsThread->Dispatch( + WrapRunnable(RefPtr(this), + &MediaTransportHandlerSTS::ExitPrivateMode), + NS_DISPATCH_NORMAL); + return; + } + auto* log = RLogConnector::GetInstance(); MOZ_ASSERT(log); if (log) { @@ -712,6 +981,8 @@ static void ToRTCIceCandidateStats( void MediaTransportHandlerSTS::GetIceStats( const NrIceMediaStream& aStream, DOMHighResTimeStamp aNow, dom::RTCStatsReportInternal* aReport) const { + MOZ_ASSERT(mStsThread->IsOnCurrentThread()); + NS_ConvertASCIItoUTF16 transportId(aStream.GetId().c_str()); std::vector candPairs; @@ -877,7 +1148,7 @@ void MediaTransportHandlerSTS::OnGatheringStateChange( OnCandidateFound(stream, ""); } } - SignalGatheringStateChange(toDomIceGatheringState(aState)); + OnGatheringStateChange(toDomIceGatheringState(aState)); } static mozilla::dom::PCImplIceConnectionState toDomIceConnectionState( @@ -903,7 +1174,7 @@ static mozilla::dom::PCImplIceConnectionState toDomIceConnectionState( void MediaTransportHandlerSTS::OnConnectionStateChange( NrIceCtx* aIceCtx, NrIceCtx::ConnectionState aState) { - SignalConnectionStateChange(toDomIceConnectionState(aState)); + OnConnectionStateChange(toDomIceConnectionState(aState)); } // The stuff below here will eventually go into the MediaTransportChild class @@ -931,7 +1202,7 @@ void MediaTransportHandlerSTS::OnCandidateFound(NrIceMediaStream* aStream, info.mDefaultPortRtcp = defaultRtcpCandidate.cand_addr.port; } - SignalCandidate(aStream->GetId(), info); + OnCandidate(aStream->GetId(), info); } void MediaTransportHandlerSTS::OnStateChange(TransportLayer* aLayer, @@ -939,36 +1210,26 @@ void MediaTransportHandlerSTS::OnStateChange(TransportLayer* aLayer, if (aState == TransportLayer::TS_OPEN) { MOZ_ASSERT(aLayer->id() == TransportLayerDtls::ID()); TransportLayerDtls* dtlsLayer = static_cast(aLayer); - SignalAlpnNegotiated(dtlsLayer->GetNegotiatedAlpn()); + OnAlpnNegotiated(dtlsLayer->GetNegotiatedAlpn()); } // DTLS state indicates the readiness of the transport as a whole, because // SRTP uses the keys from the DTLS handshake. - if (aState == TransportLayer::TS_NONE) { - mStateCache.erase(aLayer->flow_id()); - } else { - mStateCache[aLayer->flow_id()] = aState; - } - SignalStateChange(aLayer->flow_id(), aState); + MediaTransportHandler::OnStateChange(aLayer->flow_id(), aState); } void MediaTransportHandlerSTS::OnRtcpStateChange(TransportLayer* aLayer, TransportLayer::State aState) { - if (aState == TransportLayer::TS_NONE) { - mRtcpStateCache.erase(aLayer->flow_id()); - } else { - mRtcpStateCache[aLayer->flow_id()] = aState; - } - SignalRtcpStateChange(aLayer->flow_id(), aState); + MediaTransportHandler::OnRtcpStateChange(aLayer->flow_id(), aState); } void MediaTransportHandlerSTS::PacketReceived(TransportLayer* aLayer, MediaPacket& aPacket) { - SignalPacketReceived(aLayer->flow_id(), aPacket); + OnPacketReceived(aLayer->flow_id(), aPacket); } void MediaTransportHandlerSTS::EncryptedPacketSending(TransportLayer* aLayer, MediaPacket& aPacket) { - SignalEncryptedSending(aLayer->flow_id(), aPacket); + OnEncryptedSending(aLayer->flow_id(), aPacket); } } // namespace mozilla diff --git a/media/webrtc/signaling/src/peerconnection/MediaTransportHandler.h b/media/webrtc/signaling/src/peerconnection/MediaTransportHandler.h index 5dd2ef819cb7..d28cdcfdfede 100644 --- a/media/webrtc/signaling/src/peerconnection/MediaTransportHandler.h +++ b/media/webrtc/signaling/src/peerconnection/MediaTransportHandler.h @@ -15,6 +15,7 @@ #include "nricectx.h" // Need some enums #include "nsDOMNavigationTiming.h" // DOMHighResTimeStamp #include "signaling/src/common/CandidateInfo.h" +#include "nr_socket_proxy_config.h" #include "nsString.h" @@ -37,8 +38,20 @@ struct RTCStatsReportInternal; class MediaTransportHandler { public: // Creates either a MediaTransportHandlerSTS or a MediaTransportHandlerIPC, - // as appropriate. - static already_AddRefed Create(); + // as appropriate. If you want signals to fire on a specific thread, pass + // the event target here, otherwise they will fire on whatever is convenient. + // Note: This also determines what thread the state cache is updated on! + // Don't call GetState on any other thread! + static already_AddRefed Create( + nsISerialEventTarget* aCallbackThread); + + explicit MediaTransportHandler(nsISerialEventTarget* aCallbackThread) + : mCallbackThread(aCallbackThread) {} + + static nsresult ConvertIceServers( + const nsTArray& aIceServers, + std::vector* aStunServers, + std::vector* aTurnServers); typedef MozPromise, nsresult, true> IceLogPromise; @@ -50,11 +63,12 @@ class MediaTransportHandler { virtual void EnterPrivateMode() = 0; virtual void ExitPrivateMode() = 0; - virtual nsresult Init(const std::string& aName, - const nsTArray& aIceServers, - dom::RTCIceTransportPolicy aIcePolicy) = 0; virtual void Destroy() = 0; + virtual nsresult CreateIceCtx(const std::string& aName, + const nsTArray& aIceServers, + dom::RTCIceTransportPolicy aIcePolicy) = 0; + // We will probably be able to move the proxy lookup stuff into // this class once we move mtransport to its own process. virtual void SetProxyServer(NrSocketProxyConfig&& aProxyConfig) = 0; @@ -95,9 +109,6 @@ class MediaTransportHandler { virtual void UpdateNetworkState(bool aOnline) = 0; - virtual TransportLayer::State GetState(const std::string& aTransportId, - bool aRtcp) const = 0; - // dom::RTCStatsReportInternal doesn't have move semantics. typedef MozPromise, nsresult, true> @@ -118,8 +129,26 @@ class MediaTransportHandler { SignalRtcpStateChange; NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaTransportHandler) + TransportLayer::State GetState(const std::string& aTransportId, + bool aRtcp) const; + protected: + void OnCandidate(const std::string& aTransportId, + const CandidateInfo& aCandidateInfo); + void OnAlpnNegotiated(const std::string& aAlpn); + void OnGatheringStateChange(dom::PCImplIceGatheringState aState); + void OnConnectionStateChange(dom::PCImplIceConnectionState aState); + void OnPacketReceived(const std::string& aTransportId, MediaPacket& aPacket); + void OnEncryptedSending(const std::string& aTransportId, + MediaPacket& aPacket); + void OnStateChange(const std::string& aTransportId, + TransportLayer::State aState); + void OnRtcpStateChange(const std::string& aTransportId, + TransportLayer::State aState); virtual ~MediaTransportHandler() = default; + std::map mStateCache; + std::map mRtcpStateCache; + RefPtr mCallbackThread; }; } // namespace mozilla diff --git a/media/webrtc/signaling/src/peerconnection/MediaTransportHandlerIPC.cpp b/media/webrtc/signaling/src/peerconnection/MediaTransportHandlerIPC.cpp new file mode 100644 index 000000000000..0664ca22605c --- /dev/null +++ b/media/webrtc/signaling/src/peerconnection/MediaTransportHandlerIPC.cpp @@ -0,0 +1,400 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "MediaTransportHandlerIPC.h" +#include "nsThreadUtils.h" +#include "mozilla/net/SocketProcessBridgeChild.h" +#include "mozilla/RefPtr.h" + +namespace mozilla { + +static const char* mthipcLogTag = "MediaTransportHandler"; +#ifdef LOGTAG +#undef LOGTAG +#endif +#define LOGTAG mthipcLogTag + +class MediaTransportHandlerChild : public dom::PMediaTransportChild { + public: + explicit MediaTransportHandlerChild(MediaTransportHandlerIPC* aUser); + virtual ~MediaTransportHandlerChild(); + mozilla::ipc::IPCResult RecvOnCandidate( + const string& transportId, const CandidateInfo& candidateInfo) override; + mozilla::ipc::IPCResult RecvOnAlpnNegotiated(const string& alpn) override; + mozilla::ipc::IPCResult RecvOnGatheringStateChange(const int& state) override; + mozilla::ipc::IPCResult RecvOnConnectionStateChange( + const int& state) override; + mozilla::ipc::IPCResult RecvOnPacketReceived( + const string& transportId, const MediaPacket& packet) override; + mozilla::ipc::IPCResult RecvOnEncryptedSending( + const string& transportId, const MediaPacket& packet) override; + mozilla::ipc::IPCResult RecvOnStateChange(const string& transportId, + const int& state) override; + mozilla::ipc::IPCResult RecvOnRtcpStateChange(const string& transportId, + const int& state) override; + + private: + RefPtr mUser; +}; + +MediaTransportHandlerIPC::MediaTransportHandlerIPC( + nsISerialEventTarget* aCallbackThread) + : MediaTransportHandler(aCallbackThread) { + mInitPromise = net::SocketProcessBridgeChild::GetSocketProcessBridge()->Then( + GetMainThreadSerialEventTarget(), __func__, + [this, self = RefPtr(this)]( + const RefPtr& aBridge) { + mChild = new MediaTransportHandlerChild(this); + // SocketProcessBridgeChild owns mChild! When it is done with it, + // mChild will let us know it it going away. + aBridge->SetEventTargetForActor(mChild, GetMainThreadEventTarget()); + aBridge->SendPMediaTransportConstructor(mChild); + return InitPromise::CreateAndResolve(true, __func__); + }, + [=](const nsCString& aError) { + CSFLogError(LOGTAG, + "MediaTransportHandlerIPC async init failed! Webrtc " + "networking will not work! Error was %s", + aError.get()); + NS_WARNING( + "MediaTransportHandlerIPC async init failed! Webrtc networking " + "will not work!"); + return InitPromise::CreateAndReject(aError, __func__); + }); +} + +RefPtr +MediaTransportHandlerIPC::GetIceLog(const nsCString& aPattern) { + return mInitPromise->Then( + GetMainThreadSerialEventTarget(), __func__, + [=, self = RefPtr(this)](bool /* dummy */) { + if (!mChild) { + return IceLogPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); + } + // Compiler has trouble deducing the return type here for some reason, + // so we use a temp variable as a hint. + // SendGetIceLog _almost_ returns an IceLogPromise; the reject value + // differs (ipc::ResponseRejectReason vs nsresult) so we need to + // convert. + RefPtr promise = mChild->SendGetIceLog(aPattern)->Then( + GetMainThreadSerialEventTarget(), __func__, + [](WebrtcGlobalLog&& aLogLines) { + return IceLogPromise::CreateAndResolve(std::move(aLogLines), + __func__); + }, + [](ipc::ResponseRejectReason aReason) { + return IceLogPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); + }); + return promise; + }, + [](const nsCString& aError) { + return IceLogPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); + }); +} + +void MediaTransportHandlerIPC::ClearIceLog() { + mInitPromise->Then( + GetMainThreadSerialEventTarget(), __func__, + [=, self = RefPtr(this)](bool /*dummy*/) { + if (mChild) { + mChild->SendClearIceLog(); + } + }, + [](const nsCString& aError) {}); +} + +void MediaTransportHandlerIPC::EnterPrivateMode() { + mInitPromise->Then( + GetMainThreadSerialEventTarget(), __func__, + [=, self = RefPtr(this)](bool /*dummy*/) { + if (mChild) { + mChild->SendEnterPrivateMode(); + } + }, + [](const nsCString& aError) {}); +} + +void MediaTransportHandlerIPC::ExitPrivateMode() { + mInitPromise->Then( + GetMainThreadSerialEventTarget(), __func__, + [=, self = RefPtr(this)](bool /*dummy*/) { + if (mChild) { + mChild->SendExitPrivateMode(); + } + }, + [](const nsCString& aError) {}); +} + +nsresult MediaTransportHandlerIPC::CreateIceCtx( + const std::string& aName, const nsTArray& aIceServers, + dom::RTCIceTransportPolicy aIcePolicy) { + // Run some validation on this side of the IPC boundary so we can return + // errors synchronously. We don't actually use the results. It might make + // sense to move this check to PeerConnection and have this API take the + // converted form, but we would need to write IPC serialization code for + // the NrIce*Server types. + std::vector stunServers; + std::vector turnServers; + nsresult rv = ConvertIceServers(aIceServers, &stunServers, &turnServers); + if (NS_FAILED(rv)) { + return rv; + } + + mInitPromise->Then( + GetMainThreadSerialEventTarget(), __func__, + [=, self = RefPtr(this)](bool /*dummy*/) { + if (mChild) { + mChild->SendCreateIceCtx(aName, aIceServers, aIcePolicy); + } + }, + [](const nsCString& aError) {}); + + return NS_OK; +} + +void MediaTransportHandlerIPC::Destroy() { + mInitPromise->Then( + GetMainThreadSerialEventTarget(), __func__, + [=, self = RefPtr(this)](bool /*dummy*/) { + if (mChild) { + MediaTransportHandlerChild::Send__delete__(mChild); + mChild = nullptr; + } + }, + [](const nsCString& aError) {}); +} + +// We will probably be able to move the proxy lookup stuff into +// this class once we move mtransport to its own process. +void MediaTransportHandlerIPC::SetProxyServer( + NrSocketProxyConfig&& aProxyConfig) { + mInitPromise->Then( + GetMainThreadSerialEventTarget(), __func__, + [aProxyConfig = std::move(aProxyConfig), this, + self = RefPtr(this)](bool /*dummy*/) mutable { + if (mChild) { + mChild->SendSetProxyServer(aProxyConfig.GetBrowser(), + aProxyConfig.GetAlpn()); + } + }, + [](const nsCString& aError) {}); +} + +void MediaTransportHandlerIPC::EnsureProvisionalTransport( + const std::string& aTransportId, const std::string& aLocalUfrag, + const std::string& aLocalPwd, size_t aComponentCount) { + mInitPromise->Then( + GetMainThreadSerialEventTarget(), __func__, + [=, self = RefPtr(this)](bool /*dummy*/) { + if (mChild) { + mChild->SendEnsureProvisionalTransport(aTransportId, aLocalUfrag, + aLocalPwd, aComponentCount); + } + }, + [](const nsCString& aError) {}); +} + +// We set default-route-only as late as possible because it depends on what +// capture permissions have been granted on the window, which could easily +// change between Init (ie; when the PC is created) and StartIceGathering +// (ie; when we set the local description). +void MediaTransportHandlerIPC::StartIceGathering( + bool aDefaultRouteOnly, + // TODO(bug 1522205): It probably makes sense to look this up internally + const nsTArray& aStunAddrs) { + mInitPromise->Then( + GetMainThreadSerialEventTarget(), __func__, + [=, self = RefPtr(this)](bool /*dummy*/) { + if (mChild) { + mChild->SendStartIceGathering(aDefaultRouteOnly, aStunAddrs); + } + }, + [](const nsCString& aError) {}); +} + +void MediaTransportHandlerIPC::ActivateTransport( + const std::string& aTransportId, const std::string& aLocalUfrag, + const std::string& aLocalPwd, size_t aComponentCount, + const std::string& aUfrag, const std::string& aPassword, + const nsTArray& aKeyDer, const nsTArray& aCertDer, + SSLKEAType aAuthType, bool aDtlsClient, const DtlsDigestList& aDigests, + bool aPrivacyRequested) { + mInitPromise->Then( + GetMainThreadSerialEventTarget(), __func__, + [=, self = RefPtr(this)](bool /*dummy*/) { + if (mChild) { + mChild->SendActivateTransport( + aTransportId, aLocalUfrag, aLocalPwd, aComponentCount, aUfrag, + aPassword, aKeyDer, aCertDer, aAuthType, aDtlsClient, aDigests, + aPrivacyRequested); + } + }, + [](const nsCString& aError) {}); +} + +void MediaTransportHandlerIPC::RemoveTransportsExcept( + const std::set& aTransportIds) { + std::vector transportIds(aTransportIds.begin(), + aTransportIds.end()); + mInitPromise->Then( + GetMainThreadSerialEventTarget(), __func__, + [=, self = RefPtr(this)](bool /*dummy*/) { + if (mChild) { + mChild->SendRemoveTransportsExcept(transportIds); + } + }, + [](const nsCString& aError) {}); +} + +void MediaTransportHandlerIPC::StartIceChecks( + bool aIsControlling, bool aIsOfferer, + const std::vector& aIceOptions) { + mInitPromise->Then( + GetMainThreadSerialEventTarget(), __func__, + [=, self = RefPtr(this)](bool /*dummy*/) { + if (mChild) { + mChild->SendStartIceChecks(aIsControlling, aIsOfferer, aIceOptions); + } + }, + [](const nsCString& aError) {}); +} + +void MediaTransportHandlerIPC::SendPacket(const std::string& aTransportId, + MediaPacket&& aPacket) { + mInitPromise->Then( + GetMainThreadSerialEventTarget(), __func__, + [this, self = RefPtr(this), aTransportId, + aPacket = std::move(aPacket)](bool /*dummy*/) mutable { + if (mChild) { + mChild->SendSendPacket(aTransportId, aPacket); + } + }, + [](const nsCString& aError) {}); +} + +void MediaTransportHandlerIPC::AddIceCandidate(const std::string& aTransportId, + const std::string& aCandidate) { + mInitPromise->Then( + GetMainThreadSerialEventTarget(), __func__, + [=, self = RefPtr(this)](bool /*dummy*/) { + if (mChild) { + mChild->SendAddIceCandidate(aTransportId, aCandidate); + } + }, + [](const nsCString& aError) {}); +} + +void MediaTransportHandlerIPC::UpdateNetworkState(bool aOnline) { + mInitPromise->Then( + GetMainThreadSerialEventTarget(), __func__, + [=, self = RefPtr(this)](bool /*dummy*/) { + if (mChild) { + mChild->SendUpdateNetworkState(aOnline); + } + }, + [](const nsCString& aError) {}); +} + +RefPtr +MediaTransportHandlerIPC::GetIceStats( + const std::string& aTransportId, DOMHighResTimeStamp aNow, + std::unique_ptr&& aReport) { + return mInitPromise->Then( + GetMainThreadSerialEventTarget(), __func__, + [aReport = std::move(aReport), aTransportId, aNow, this, + self = RefPtr(this)](bool /*dummy*/) mutable { + if (!mChild) { + return StatsPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); + } + RefPtr promise = + mChild->SendGetIceStats(aTransportId, aNow, *aReport) + ->Then(GetMainThreadSerialEventTarget(), __func__, + [](const dom::MovableRTCStatsReportInternal& aReport) { + std::unique_ptr report( + new dom::RTCStatsReportInternal(aReport)); + return StatsPromise::CreateAndResolve( + std::move(report), __func__); + }, + [](ipc::ResponseRejectReason aReason) { + return StatsPromise::CreateAndReject(NS_ERROR_FAILURE, + __func__); + }); + return promise; + }, + [](const nsCString& aError) { + return StatsPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); + }); +} + +MediaTransportHandlerChild::MediaTransportHandlerChild( + MediaTransportHandlerIPC* aUser) + : mUser(aUser) {} + +MediaTransportHandlerChild::~MediaTransportHandlerChild() { + MOZ_ASSERT(GetMainThreadEventTarget()->IsOnCurrentThread()); + mUser->mChild = nullptr; +} + +mozilla::ipc::IPCResult MediaTransportHandlerChild::RecvOnCandidate( + const string& transportId, const CandidateInfo& candidateInfo) { + MOZ_ASSERT(GetMainThreadEventTarget()->IsOnCurrentThread()); + mUser->OnCandidate(transportId, candidateInfo); + return ipc::IPCResult::Ok(); +} + +mozilla::ipc::IPCResult MediaTransportHandlerChild::RecvOnAlpnNegotiated( + const string& alpn) { + MOZ_ASSERT(GetMainThreadEventTarget()->IsOnCurrentThread()); + mUser->OnAlpnNegotiated(alpn); + return ipc::IPCResult::Ok(); +} + +mozilla::ipc::IPCResult MediaTransportHandlerChild::RecvOnGatheringStateChange( + const int& state) { + MOZ_ASSERT(GetMainThreadEventTarget()->IsOnCurrentThread()); + mUser->OnGatheringStateChange( + static_cast(state)); + return ipc::IPCResult::Ok(); +} + +mozilla::ipc::IPCResult MediaTransportHandlerChild::RecvOnConnectionStateChange( + const int& state) { + MOZ_ASSERT(GetMainThreadEventTarget()->IsOnCurrentThread()); + mUser->OnConnectionStateChange( + static_cast(state)); + return ipc::IPCResult::Ok(); +} + +mozilla::ipc::IPCResult MediaTransportHandlerChild::RecvOnPacketReceived( + const string& transportId, const MediaPacket& packet) { + MOZ_ASSERT(GetMainThreadEventTarget()->IsOnCurrentThread()); + MediaPacket copy(packet); // Laaaaaame! Might be safe to const_cast? + mUser->OnPacketReceived(transportId, copy); + return ipc::IPCResult::Ok(); +} + +mozilla::ipc::IPCResult MediaTransportHandlerChild::RecvOnEncryptedSending( + const string& transportId, const MediaPacket& packet) { + MOZ_ASSERT(GetMainThreadEventTarget()->IsOnCurrentThread()); + MediaPacket copy(packet); // Laaaaaame! Might be safe to const_cast? + mUser->OnEncryptedSending(transportId, copy); + return ipc::IPCResult::Ok(); +} + +mozilla::ipc::IPCResult MediaTransportHandlerChild::RecvOnStateChange( + const string& transportId, const int& state) { + MOZ_ASSERT(GetMainThreadEventTarget()->IsOnCurrentThread()); + mUser->OnStateChange(transportId, static_cast(state)); + return ipc::IPCResult::Ok(); +} + +mozilla::ipc::IPCResult MediaTransportHandlerChild::RecvOnRtcpStateChange( + const string& transportId, const int& state) { + MOZ_ASSERT(GetMainThreadEventTarget()->IsOnCurrentThread()); + mUser->OnRtcpStateChange(transportId, + static_cast(state)); + return ipc::IPCResult::Ok(); +} + +} // namespace mozilla diff --git a/media/webrtc/signaling/src/peerconnection/MediaTransportHandlerIPC.h b/media/webrtc/signaling/src/peerconnection/MediaTransportHandlerIPC.h new file mode 100644 index 000000000000..433ca2412218 --- /dev/null +++ b/media/webrtc/signaling/src/peerconnection/MediaTransportHandlerIPC.h @@ -0,0 +1,91 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _MTRANSPORTHANDLER_IPC_H__ +#define _MTRANSPORTHANDLER_IPC_H__ + +#include "signaling/src/peerconnection/MediaTransportHandler.h" +#include "mozilla/dom/PMediaTransportChild.h" + +namespace mozilla { + +class MediaTransportHandlerChild; + +// Implementation of MediaTransportHandler that uses IPC (PMediaTransport) to +// talk to mtransport on another process. +class MediaTransportHandlerIPC : public MediaTransportHandler { + public: + explicit MediaTransportHandlerIPC(nsISerialEventTarget* aCallbackThread); + RefPtr GetIceLog(const nsCString& aPattern) override; + void ClearIceLog() override; + void EnterPrivateMode() override; + void ExitPrivateMode() override; + + nsresult CreateIceCtx(const std::string& aName, + const nsTArray& aIceServers, + dom::RTCIceTransportPolicy aIcePolicy) override; + void Destroy() override; + + // We will probably be able to move the proxy lookup stuff into + // this class once we move mtransport to its own process. + void SetProxyServer(NrSocketProxyConfig&& aProxyConfig) override; + + void EnsureProvisionalTransport(const std::string& aTransportId, + const std::string& aLocalUfrag, + const std::string& aLocalPwd, + size_t aComponentCount) override; + + // We set default-route-only as late as possible because it depends on what + // capture permissions have been granted on the window, which could easily + // change between Init (ie; when the PC is created) and StartIceGathering + // (ie; when we set the local description). + void StartIceGathering(bool aDefaultRouteOnly, + // TODO: It probably makes sense to look + // this up internally + const nsTArray& aStunAddrs) override; + + void ActivateTransport( + const std::string& aTransportId, const std::string& aLocalUfrag, + const std::string& aLocalPwd, size_t aComponentCount, + const std::string& aUfrag, const std::string& aPassword, + const nsTArray& aKeyDer, const nsTArray& aCertDer, + SSLKEAType aAuthType, bool aDtlsClient, const DtlsDigestList& aDigests, + bool aPrivacyRequested) override; + + void RemoveTransportsExcept( + const std::set& aTransportIds) override; + + void StartIceChecks(bool aIsControlling, bool aIsOfferer, + const std::vector& aIceOptions) override; + + void SendPacket(const std::string& aTransportId, + MediaPacket&& aPacket) override; + + void AddIceCandidate(const std::string& aTransportId, + const std::string& aCandidate) override; + + void UpdateNetworkState(bool aOnline) override; + + RefPtr GetIceStats( + const std::string& aTransportId, DOMHighResTimeStamp aNow, + std::unique_ptr&& aReport) override; + + private: + friend class MediaTransportHandlerChild; + + // We do not own this; it will tell us when it is going away. + MediaTransportHandlerChild* mChild = nullptr; + + // |mChild| can only be initted asynchronously, |mInitPromise| resolves + // when that happens. The |Then| calls make it convenient to dispatch API + // calls to main, which is a bonus. + // Init promise is not exclusive; this lets us call |Then| on it for every + // API call we get, instead of creating another promise each time. + typedef MozPromise InitPromise; + RefPtr mInitPromise; +}; + +} // namespace mozilla + +#endif //_MTRANSPORTHANDLER_IPC_H__ diff --git a/media/webrtc/signaling/src/peerconnection/MediaTransportHandlerParent.cpp b/media/webrtc/signaling/src/peerconnection/MediaTransportHandlerParent.cpp new file mode 100644 index 000000000000..11b87dbc6a8c --- /dev/null +++ b/media/webrtc/signaling/src/peerconnection/MediaTransportHandlerParent.cpp @@ -0,0 +1,260 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "MediaTransportHandlerParent.h" +#include "signaling/src/peerconnection/MediaTransportHandler.h" + +#include "nss.h" // For NSS_NoDB_Init +#include "mozilla/PublicSSL.h" // For psm::InitializeCipherSuite + +namespace mozilla { + +MediaTransportHandlerParent::MediaTransportHandlerParent() + : mImpl(MediaTransportHandler::Create(GetMainThreadSerialEventTarget())) { + // We cannot register PMediaTransportParent's Send* API to these signals, + // because this API returns must-use bools, and the params are in some cases + // slightly different. + mImpl->SignalCandidate.connect(this, + &MediaTransportHandlerParent::OnCandidate); + mImpl->SignalAlpnNegotiated.connect( + this, &MediaTransportHandlerParent::OnAlpnNegotiated); + mImpl->SignalGatheringStateChange.connect( + this, &MediaTransportHandlerParent::OnGatheringStateChange); + mImpl->SignalConnectionStateChange.connect( + this, &MediaTransportHandlerParent::OnConnectionStateChange); + mImpl->SignalPacketReceived.connect( + this, &MediaTransportHandlerParent::OnPacketReceived); + mImpl->SignalEncryptedSending.connect( + this, &MediaTransportHandlerParent::OnEncryptedSending); + mImpl->SignalStateChange.connect(this, + &MediaTransportHandlerParent::OnStateChange); + mImpl->SignalRtcpStateChange.connect( + this, &MediaTransportHandlerParent::OnRtcpStateChange); +} + +MediaTransportHandlerParent::~MediaTransportHandlerParent() { + MOZ_RELEASE_ASSERT(!mImpl); +} + +void MediaTransportHandlerParent::OnCandidate( + const std::string& aTransportId, const CandidateInfo& aCandidateInfo) { + NS_ENSURE_TRUE_VOID(SendOnCandidate(aTransportId, aCandidateInfo)); +} + +void MediaTransportHandlerParent::OnAlpnNegotiated(const std::string& aAlpn) { + NS_ENSURE_TRUE_VOID(SendOnAlpnNegotiated(aAlpn)); +} + +void MediaTransportHandlerParent::OnGatheringStateChange( + dom::PCImplIceGatheringState aState) { + NS_ENSURE_TRUE_VOID(SendOnGatheringStateChange(static_cast(aState))); +} + +void MediaTransportHandlerParent::OnConnectionStateChange( + dom::PCImplIceConnectionState aState) { + NS_ENSURE_TRUE_VOID(SendOnConnectionStateChange(static_cast(aState))); +} + +void MediaTransportHandlerParent::OnPacketReceived( + const std::string& aTransportId, MediaPacket& aPacket) { + NS_ENSURE_TRUE_VOID(SendOnPacketReceived(aTransportId, aPacket)); +} + +void MediaTransportHandlerParent::OnEncryptedSending( + const std::string& aTransportId, MediaPacket& aPacket) { + NS_ENSURE_TRUE_VOID(SendOnEncryptedSending(aTransportId, aPacket)); +} + +void MediaTransportHandlerParent::OnStateChange(const std::string& aTransportId, + TransportLayer::State aState) { + NS_ENSURE_TRUE_VOID(SendOnStateChange(aTransportId, aState)); +} + +void MediaTransportHandlerParent::OnRtcpStateChange( + const std::string& aTransportId, TransportLayer::State aState) { + NS_ENSURE_TRUE_VOID(SendOnRtcpStateChange(aTransportId, aState)); +} + +mozilla::ipc::IPCResult MediaTransportHandlerParent::RecvGetIceLog( + const nsCString& pattern, GetIceLogResolver&& aResolve) { + MOZ_ASSERT(GetMainThreadEventTarget()->IsOnCurrentThread()); + mImpl->GetIceLog(pattern)->Then( + GetMainThreadSerialEventTarget(), __func__, + // IPDL doesn't give us a reject function, so we cannot reject async, so + // we are forced to resolve with an empty result. Laaaaaaame. + [aResolve = std::move(aResolve)]( + MediaTransportHandler::IceLogPromise::ResolveOrRejectValue&& + aResult) mutable { + WebrtcGlobalLog logLines; + if (aResult.IsResolve()) { + logLines = std::move(aResult.ResolveValue()); + } + aResolve(logLines); + }); + + return ipc::IPCResult::Ok(); +} + +mozilla::ipc::IPCResult MediaTransportHandlerParent::RecvClearIceLog() { + MOZ_ASSERT(GetMainThreadEventTarget()->IsOnCurrentThread()); + mImpl->ClearIceLog(); + return ipc::IPCResult::Ok(); +} + +mozilla::ipc::IPCResult MediaTransportHandlerParent::RecvEnterPrivateMode() { + MOZ_ASSERT(GetMainThreadEventTarget()->IsOnCurrentThread()); + mImpl->EnterPrivateMode(); + return ipc::IPCResult::Ok(); +} + +mozilla::ipc::IPCResult MediaTransportHandlerParent::RecvExitPrivateMode() { + MOZ_ASSERT(GetMainThreadEventTarget()->IsOnCurrentThread()); + mImpl->ExitPrivateMode(); + return ipc::IPCResult::Ok(); +} + +mozilla::ipc::IPCResult MediaTransportHandlerParent::RecvCreateIceCtx( + const string& name, nsTArray&& iceServers, + const RTCIceTransportPolicy& icePolicy) { + MOZ_ASSERT(GetMainThreadEventTarget()->IsOnCurrentThread()); + static bool nssStarted = false; + if (!nssStarted) { + if (NSS_NoDB_Init(nullptr) != SECSuccess) { + MOZ_CRASH(); + return ipc::IPCResult::Fail(WrapNotNull(this), __func__, + "NSS_NoDB_Init failed"); + } + + if (NS_FAILED(mozilla::psm::InitializeCipherSuite())) { + MOZ_CRASH(); + return ipc::IPCResult::Fail(WrapNotNull(this), __func__, + "InitializeCipherSuite failed"); + } + + mozilla::psm::DisableMD5(); + } + + nssStarted = true; + + nsresult rv = mImpl->CreateIceCtx(name, iceServers, icePolicy); + if (NS_FAILED(rv)) { + return ipc::IPCResult::Fail(WrapNotNull(this), __func__, + "MediaTransportHandler::Init failed"); + } + return ipc::IPCResult::Ok(); +} + +mozilla::ipc::IPCResult MediaTransportHandlerParent::RecvSetProxyServer( + const PBrowserOrId& browserOrId, const nsCString& alpn) { + MOZ_ASSERT(GetMainThreadEventTarget()->IsOnCurrentThread()); + mImpl->SetProxyServer(NrSocketProxyConfig(browserOrId, alpn)); + return ipc::IPCResult::Ok(); +} + +mozilla::ipc::IPCResult +MediaTransportHandlerParent::RecvEnsureProvisionalTransport( + const string& transportId, const string& localUfrag, const string& localPwd, + const int& componentCount) { + MOZ_ASSERT(GetMainThreadEventTarget()->IsOnCurrentThread()); + mImpl->EnsureProvisionalTransport(transportId, localUfrag, localPwd, + componentCount); + return ipc::IPCResult::Ok(); +} + +mozilla::ipc::IPCResult MediaTransportHandlerParent::RecvStartIceGathering( + const bool& defaultRouteOnly, const net::NrIceStunAddrArray& stunAddrs) { + MOZ_ASSERT(GetMainThreadEventTarget()->IsOnCurrentThread()); + mImpl->StartIceGathering(defaultRouteOnly, stunAddrs); + return ipc::IPCResult::Ok(); +} + +mozilla::ipc::IPCResult MediaTransportHandlerParent::RecvActivateTransport( + const string& transportId, const string& localUfrag, const string& localPwd, + const int& componentCount, const string& remoteUfrag, + const string& remotePwd, nsTArray&& keyDer, + nsTArray&& certDer, const int& authType, const bool& dtlsClient, + const DtlsDigestList& digests, const bool& privacyRequested) { + MOZ_ASSERT(GetMainThreadEventTarget()->IsOnCurrentThread()); + mImpl->ActivateTransport(transportId, localUfrag, localPwd, componentCount, + remoteUfrag, remotePwd, keyDer, certDer, + static_cast(authType), dtlsClient, + digests, privacyRequested); + return ipc::IPCResult::Ok(); +} + +mozilla::ipc::IPCResult MediaTransportHandlerParent::RecvRemoveTransportsExcept( + const StringVector& transportIds) { + MOZ_ASSERT(GetMainThreadEventTarget()->IsOnCurrentThread()); + std::set ids(transportIds.begin(), transportIds.end()); + mImpl->RemoveTransportsExcept(ids); + return ipc::IPCResult::Ok(); +} + +mozilla::ipc::IPCResult MediaTransportHandlerParent::RecvStartIceChecks( + const bool& isControlling, const bool& isOfferer, + const StringVector& iceOptions) { + MOZ_ASSERT(GetMainThreadEventTarget()->IsOnCurrentThread()); + mImpl->StartIceChecks(isControlling, isOfferer, iceOptions); + return ipc::IPCResult::Ok(); +} + +mozilla::ipc::IPCResult MediaTransportHandlerParent::RecvSendPacket( + const string& transportId, const MediaPacket& packet) { + MOZ_ASSERT(GetMainThreadEventTarget()->IsOnCurrentThread()); + MediaPacket copy(packet); // Laaaaaaame. + mImpl->SendPacket(transportId, std::move(copy)); + return ipc::IPCResult::Ok(); +} + +mozilla::ipc::IPCResult MediaTransportHandlerParent::RecvAddIceCandidate( + const string& transportId, const string& candidate) { + MOZ_ASSERT(GetMainThreadEventTarget()->IsOnCurrentThread()); + mImpl->AddIceCandidate(transportId, candidate); + return ipc::IPCResult::Ok(); +} + +mozilla::ipc::IPCResult MediaTransportHandlerParent::RecvUpdateNetworkState( + const bool& online) { + MOZ_ASSERT(GetMainThreadEventTarget()->IsOnCurrentThread()); + mImpl->UpdateNetworkState(online); + return ipc::IPCResult::Ok(); +} + +mozilla::ipc::IPCResult MediaTransportHandlerParent::RecvGetIceStats( + const string& transportId, const double& now, + const RTCStatsReportInternal& reportIn, GetIceStatsResolver&& aResolve) { + MOZ_ASSERT(GetMainThreadEventTarget()->IsOnCurrentThread()); + // Copy, because we are handed a const reference (lame), and put in a + // unique_ptr because RTCStatsReportInternal doesn't have move semantics + // (also lame). + std::unique_ptr report( + new dom::RTCStatsReportInternal(reportIn)); + + mImpl->GetIceStats(transportId, now, std::move(report)) + ->Then( + GetMainThreadSerialEventTarget(), __func__, + // IPDL doesn't give us a reject function, so we cannot reject async, + // so we are forced to resolve with an unmodified result. Laaaaaaame. + [aResolve = std::move(aResolve), + reportIn](MediaTransportHandler::StatsPromise::ResolveOrRejectValue&& + aResult) { + if (aResult.IsResolve()) { + MovableRTCStatsReportInternal copy(*aResult.ResolveValue()); + aResolve(copy); + } else { + aResolve(MovableRTCStatsReportInternal(reportIn)); + } + }); + + return ipc::IPCResult::Ok(); +} + +void MediaTransportHandlerParent::ActorDestroy(ActorDestroyReason aWhy) { + MOZ_ASSERT(GetMainThreadEventTarget()->IsOnCurrentThread()); + disconnect_all(); + mImpl->Destroy(); + mImpl = nullptr; +} + +} // namespace mozilla diff --git a/media/webrtc/signaling/src/peerconnection/MediaTransportHandlerParent.h b/media/webrtc/signaling/src/peerconnection/MediaTransportHandlerParent.h new file mode 100644 index 000000000000..570e1cf93588 --- /dev/null +++ b/media/webrtc/signaling/src/peerconnection/MediaTransportHandlerParent.h @@ -0,0 +1,78 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _MTRANSPORTHANDLER_PARENT_H__ +#define _MTRANSPORTHANDLER_PARENT_H__ + +#include "mozilla/dom/PMediaTransportParent.h" +#include "signaling/src/peerconnection/MediaTransportHandler.h" +#include "sigslot.h" + +namespace mozilla { + +class MediaTransportHandlerParent : public dom::PMediaTransportParent, + public sigslot::has_slots<> { + public: + MediaTransportHandlerParent(); + virtual ~MediaTransportHandlerParent(); + + void OnCandidate(const std::string& aTransportId, + const CandidateInfo& aCandidateInfo); + void OnAlpnNegotiated(const std::string& aAlpn); + void OnGatheringStateChange(dom::PCImplIceGatheringState aState); + void OnConnectionStateChange(dom::PCImplIceConnectionState aState); + void OnPacketReceived(const std::string& aTransportId, MediaPacket& aPacket); + void OnEncryptedSending(const std::string& aTransportId, + MediaPacket& aPacket); + void OnStateChange(const std::string& aTransportId, + TransportLayer::State aState); + void OnRtcpStateChange(const std::string& aTransportId, + TransportLayer::State aState); + + mozilla::ipc::IPCResult RecvGetIceLog(const nsCString& pattern, + GetIceLogResolver&& aResolve) override; + mozilla::ipc::IPCResult RecvClearIceLog() override; + mozilla::ipc::IPCResult RecvEnterPrivateMode() override; + mozilla::ipc::IPCResult RecvExitPrivateMode() override; + mozilla::ipc::IPCResult RecvCreateIceCtx( + const string& name, nsTArray&& iceServers, + const RTCIceTransportPolicy& icePolicy) override; + mozilla::ipc::IPCResult RecvSetProxyServer(const PBrowserOrId& browserOrId, + const nsCString& alpn) override; + mozilla::ipc::IPCResult RecvEnsureProvisionalTransport( + const string& transportId, const string& localUfrag, + const string& localPwd, const int& componentCount) override; + mozilla::ipc::IPCResult RecvStartIceGathering( + const bool& defaultRouteOnly, + const net::NrIceStunAddrArray& stunAddrs) override; + mozilla::ipc::IPCResult RecvActivateTransport( + const string& transportId, const string& localUfrag, + const string& localPwd, const int& componentCount, + const string& remoteUfrag, const string& remotePwd, + nsTArray&& keyDer, nsTArray&& certDer, + const int& authType, const bool& dtlsClient, + const DtlsDigestList& digests, const bool& privacyRequested) override; + mozilla::ipc::IPCResult RecvRemoveTransportsExcept( + const StringVector& transportIds) override; + mozilla::ipc::IPCResult RecvStartIceChecks( + const bool& isControlling, const bool& isOfferer, + const StringVector& iceOptions) override; + mozilla::ipc::IPCResult RecvSendPacket(const string& transportId, + const MediaPacket& packet) override; + mozilla::ipc::IPCResult RecvAddIceCandidate(const string& transportId, + const string& candidate) override; + mozilla::ipc::IPCResult RecvUpdateNetworkState(const bool& online) override; + mozilla::ipc::IPCResult RecvGetIceStats( + const string& transportId, const double& now, + const RTCStatsReportInternal& reportIn, + GetIceStatsResolver&& aResolve) override; + + void ActorDestroy(ActorDestroyReason aWhy) override; + + private: + RefPtr mImpl; + RefPtr mStsThread; +}; +} // namespace mozilla +#endif //_MTRANSPORTHANDLER_PARENT_H__ diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionCtx.h b/media/webrtc/signaling/src/peerconnection/PeerConnectionCtx.h index 2ef8034895dc..5eb0e633abf1 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionCtx.h +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionCtx.h @@ -72,7 +72,9 @@ class PeerConnectionCtx { std::map mPeerConnections; PeerConnectionCtx() - : mGMPReady(false), mTransportHandler(MediaTransportHandler::Create()) {} + : mGMPReady(false), + mTransportHandler( + MediaTransportHandler::Create(GetMainThreadSerialEventTarget())) {} // This is a singleton, so don't copy construct it, etc. PeerConnectionCtx(const PeerConnectionCtx& other) = delete; void operator=(const PeerConnectionCtx& other) = delete; diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp index 7627df13026c..d274f41e2169 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp @@ -308,7 +308,7 @@ PeerConnectionImpl::PeerConnectionImpl(const GlobalObject* aGlobal) mSTSThread(nullptr), mForceIceTcp(false), mMedia(nullptr), - mTransportHandler(MediaTransportHandler::Create()), + mTransportHandler(nullptr), mUuidGen(MakeUnique()), mIceRestartCount(0), mIceRollbackCount(0), @@ -403,6 +403,10 @@ nsresult PeerConnectionImpl::Initialize(PeerConnectionObserver& aObserver, mSTSThread = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &res); MOZ_ASSERT(mSTSThread); + // We do callback handling on STS instead of main to avoid media jank. + // Someday, we may have a dedicated thread for this. + mTransportHandler = MediaTransportHandler::Create(mSTSThread); + // Initialize NSS if we are in content process. For chrome process, NSS should // already been initialized. if (XRE_IsParentProcess()) { @@ -464,8 +468,8 @@ nsresult PeerConnectionImpl::Initialize(PeerConnectionObserver& aObserver, iceServers = aConfiguration.mIceServers.Value(); } - res = mTransportHandler->Init("PC:" + GetName(), iceServers, - aConfiguration.mIceTransportPolicy); + res = mTransportHandler->CreateIceCtx("PC:" + GetName(), iceServers, + aConfiguration.mIceTransportPolicy); if (NS_FAILED(res)) { CSFLogError(LOGTAG, "%s: Failed to init mtransport", __FUNCTION__); return NS_ERROR_FAILURE; diff --git a/media/webrtc/signaling/src/peerconnection/moz.build b/media/webrtc/signaling/src/peerconnection/moz.build index 05c99eaaa3cb..9237ec3bc504 100644 --- a/media/webrtc/signaling/src/peerconnection/moz.build +++ b/media/webrtc/signaling/src/peerconnection/moz.build @@ -24,6 +24,8 @@ LOCAL_INCLUDES += [ UNIFIED_SOURCES += [ 'MediaTransportHandler.cpp', + 'MediaTransportHandlerIPC.cpp', + 'MediaTransportHandlerParent.cpp', 'PacketDumper.cpp', 'PeerConnectionCtx.cpp', 'PeerConnectionImpl.cpp', diff --git a/netwerk/ipc/NeckoChild.cpp b/netwerk/ipc/NeckoChild.cpp index 36a111249cd5..9ec53e013683 100644 --- a/netwerk/ipc/NeckoChild.cpp +++ b/netwerk/ipc/NeckoChild.cpp @@ -24,6 +24,7 @@ #include "mozilla/dom/network/UDPSocketChild.h" #include "mozilla/net/AltDataOutputStreamChild.h" #include "mozilla/net/TrackingDummyChannelChild.h" +#include "mozilla/net/SocketProcessBridgeChild.h" #ifdef MOZ_WEBRTC # include "mozilla/net/StunAddrsRequestChild.h" # include "mozilla/net/WebrtcProxyChannelChild.h" @@ -67,6 +68,7 @@ void NeckoChild::InitNeckoChild() { } gNeckoChild = cpc->SendPNeckoConstructor(); NS_ASSERTION(gNeckoChild, "PNecko Protocol init failed!"); + SocketProcessBridgeChild::GetSocketProcessBridge(); } } diff --git a/netwerk/ipc/PSocketProcessBridge.ipdl b/netwerk/ipc/PSocketProcessBridge.ipdl index 0f89c6b57e42..938315ed4f58 100644 --- a/netwerk/ipc/PSocketProcessBridge.ipdl +++ b/netwerk/ipc/PSocketProcessBridge.ipdl @@ -5,6 +5,7 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ include protocol PBackground; +include protocol PMediaTransport; namespace mozilla { namespace net { @@ -19,9 +20,13 @@ namespace net { */ nested(upto inside_cpow) sync protocol PSocketProcessBridge { + manages PMediaTransport; + parent: async InitBackground(Endpoint aEndpoint); + async PMediaTransport(); + both: async Test(); }; diff --git a/netwerk/ipc/SocketProcessBridgeChild.cpp b/netwerk/ipc/SocketProcessBridgeChild.cpp index 2a41689d76b3..bef609409ff2 100644 --- a/netwerk/ipc/SocketProcessBridgeChild.cpp +++ b/netwerk/ipc/SocketProcessBridgeChild.cpp @@ -9,6 +9,7 @@ #include "mozilla/net/NeckoChild.h" #include "nsIObserverService.h" #include "nsThreadUtils.h" +#include "mozilla/dom/PMediaTransportChild.h" namespace mozilla { namespace net { @@ -47,35 +48,49 @@ SocketProcessBridgeChild::GetSingleton() { } // static -void SocketProcessBridgeChild::EnsureSocketProcessBridge( - std::function&& aOnSuccess, std::function&& aOnFailure) { - MOZ_ASSERT(IsNeckoChild() && gNeckoChild); +RefPtr +SocketProcessBridgeChild::GetSocketProcessBridge() { MOZ_ASSERT(NS_IsMainThread()); if (!gNeckoChild) { - aOnFailure(); - return; + return GetPromise::CreateAndReject(nsCString("No NeckoChild!"), __func__); } if (sSocketProcessBridgeChild) { - aOnSuccess(); - return; + return GetPromise::CreateAndResolve(sSocketProcessBridgeChild, __func__); } - gNeckoChild->SendInitSocketProcessBridge()->Then( + return gNeckoChild->SendInitSocketProcessBridge()->Then( GetMainThreadSerialEventTarget(), __func__, - [onSuccess = std::move(aOnSuccess), onFailure = std::move(aOnFailure)]( - Endpoint&& aEndpoint) { - if (aEndpoint.IsValid()) { - if (SocketProcessBridgeChild::Create(std::move(aEndpoint))) { - onSuccess(); - return; + [](NeckoChild::InitSocketProcessBridgePromise::ResolveOrRejectValue&& + aResult) { + if (!sSocketProcessBridgeChild) { + if (aResult.IsReject()) { + return GetPromise::CreateAndReject( + nsCString("SendInitSocketProcessBridge failed"), __func__); + } + + if (!aResult.ResolveValue().IsValid()) { + return GetPromise::CreateAndReject( + nsCString( + "SendInitSocketProcessBridge resolved with an invalid " + "endpoint!"), + __func__); + } + + if (!SocketProcessBridgeChild::Create( + std::move(aResult.ResolveValue()))) { + return GetPromise::CreateAndReject( + nsCString("SendInitSocketProcessBridge resolved with a valid " + "endpoint, " + "but SocketProcessBridgeChild::Create failed!"), + __func__); } } - onFailure(); - }, - [onFailure = std::move(aOnFailure)]( - const mozilla::ipc::ResponseRejectReason) { onFailure(); }); + + return GetPromise::CreateAndResolve(sSocketProcessBridgeChild, + __func__); + }); } SocketProcessBridgeChild::SocketProcessBridgeChild( @@ -133,5 +148,21 @@ void SocketProcessBridgeChild::DeferredDestroy() { sSocketProcessBridgeChild = nullptr; } +dom::PMediaTransportChild* +SocketProcessBridgeChild::AllocPMediaTransportChild() { + // We don't allocate here: MediaTransportHandlerIPC is in charge of that, + // so we don't need to know the implementation particulars here. + MOZ_ASSERT_UNREACHABLE( + "The only thing that ought to be creating a PMediaTransportChild is " + "MediaTransportHandlerIPC!"); + return nullptr; +} + +bool SocketProcessBridgeChild::DeallocPMediaTransportChild( + dom::PMediaTransportChild* aActor) { + delete aActor; + return true; +} + } // namespace net } // namespace mozilla diff --git a/netwerk/ipc/SocketProcessBridgeChild.h b/netwerk/ipc/SocketProcessBridgeChild.h index f899776d306a..61b9b2237eb2 100644 --- a/netwerk/ipc/SocketProcessBridgeChild.h +++ b/netwerk/ipc/SocketProcessBridgeChild.h @@ -22,10 +22,10 @@ class SocketProcessBridgeChild final : public PSocketProcessBridgeChild, NS_DECL_ISUPPORTS NS_DECL_NSIOBSERVER - static bool Create(Endpoint&& aEndpoint); static already_AddRefed GetSingleton(); - static void EnsureSocketProcessBridge(std::function&& aOnSuccess, - std::function&& aOnFailure); + typedef MozPromise, nsCString, false> + GetPromise; + static RefPtr GetSocketProcessBridge(); mozilla::ipc::IPCResult RecvTest(); void ActorDestroy(ActorDestroyReason aWhy) override; @@ -34,8 +34,12 @@ class SocketProcessBridgeChild final : public PSocketProcessBridgeChild, bool Inited() const { return mInited; }; ProcessId SocketProcessPid() const { return mSocketProcessPid; }; + dom::PMediaTransportChild* AllocPMediaTransportChild() override; + bool DeallocPMediaTransportChild(dom::PMediaTransportChild* aActor) override; + private: DISALLOW_COPY_AND_ASSIGN(SocketProcessBridgeChild); + static bool Create(Endpoint&& aEndpoint); explicit SocketProcessBridgeChild( Endpoint&& aEndpoint); virtual ~SocketProcessBridgeChild(); diff --git a/netwerk/ipc/SocketProcessBridgeParent.cpp b/netwerk/ipc/SocketProcessBridgeParent.cpp index 046f3a0daadd..f22ac4947a7b 100644 --- a/netwerk/ipc/SocketProcessBridgeParent.cpp +++ b/netwerk/ipc/SocketProcessBridgeParent.cpp @@ -8,6 +8,9 @@ #include "mozilla/ipc/BackgroundParent.h" #include "SocketProcessChild.h" +#ifdef MOZ_WEBRTC +#include "signaling/src/peerconnection/MediaTransportHandlerParent.h" +#endif namespace mozilla { namespace net { @@ -56,5 +59,21 @@ void SocketProcessBridgeParent::DeferredDestroy() { SocketProcessChild::GetSingleton()->DestroySocketProcessBridgeParent(mId); } +dom::PMediaTransportParent* +SocketProcessBridgeParent::AllocPMediaTransportParent() { +#ifdef MOZ_WEBRTC + return new MediaTransportHandlerParent; +#endif + return nullptr; +} + +bool SocketProcessBridgeParent::DeallocPMediaTransportParent( + dom::PMediaTransportParent* aActor) { +#ifdef MOZ_WEBRTC + delete aActor; +#endif + return true; +} + } // namespace net } // namespace mozilla diff --git a/netwerk/ipc/SocketProcessBridgeParent.h b/netwerk/ipc/SocketProcessBridgeParent.h index 4ad87058c16d..3373f3a962bb 100644 --- a/netwerk/ipc/SocketProcessBridgeParent.h +++ b/netwerk/ipc/SocketProcessBridgeParent.h @@ -29,6 +29,10 @@ class SocketProcessBridgeParent final : public PSocketProcessBridgeParent { void ActorDestroy(ActorDestroyReason aWhy) override; void DeferredDestroy(); + dom::PMediaTransportParent* AllocPMediaTransportParent() override; + bool DeallocPMediaTransportParent( + dom::PMediaTransportParent* aActor) override; + private: ~SocketProcessBridgeParent(); diff --git a/netwerk/ipc/moz.build b/netwerk/ipc/moz.build index 4eb6fbc780c9..59c5177f2ad6 100644 --- a/netwerk/ipc/moz.build +++ b/netwerk/ipc/moz.build @@ -62,6 +62,8 @@ FINAL_LIBRARY = 'xul' LOCAL_INCLUDES += [ '/caps', '/dom/base', + '/media/mtransport', + '/media/webrtc', '/modules/libjar', '/netwerk/base', '/netwerk/protocol/http',