summaryrefslogtreecommitdiffstats
path: root/dom/media/webrtc/jsapi/MediaTransportHandlerIPC.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/webrtc/jsapi/MediaTransportHandlerIPC.cpp')
-rw-r--r--dom/media/webrtc/jsapi/MediaTransportHandlerIPC.cpp426
1 files changed, 426 insertions, 0 deletions
diff --git a/dom/media/webrtc/jsapi/MediaTransportHandlerIPC.cpp b/dom/media/webrtc/jsapi/MediaTransportHandlerIPC.cpp
new file mode 100644
index 0000000000..0848080a8f
--- /dev/null
+++ b/dom/media/webrtc/jsapi/MediaTransportHandlerIPC.cpp
@@ -0,0 +1,426 @@
+/* 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 "mozilla/dom/MediaTransportChild.h"
+#include "nsThreadUtils.h"
+#include "mozilla/net/SocketProcessBridgeChild.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/ipc/BackgroundChild.h"
+#include "mozilla/ipc/PBackgroundChild.h"
+#include "common/browser_logging/CSFLog.h"
+
+namespace mozilla {
+
+static const char* mthipcLogTag = "MediaTransportHandler";
+#ifdef LOGTAG
+# undef LOGTAG
+#endif
+#define LOGTAG mthipcLogTag
+
+MediaTransportHandlerIPC::MediaTransportHandlerIPC(
+ nsISerialEventTarget* aCallbackThread)
+ : MediaTransportHandler(aCallbackThread) {
+ mInitPromise = net::SocketProcessBridgeChild::GetSocketProcessBridge()->Then(
+ mCallbackThread, __func__,
+ [this, self = RefPtr<MediaTransportHandlerIPC>(this)](
+ const RefPtr<net::SocketProcessBridgeChild>& aBridge) {
+ ipc::PBackgroundChild* actor =
+ ipc::BackgroundChild::GetOrCreateSocketActorForCurrentThread();
+ // An actor that can't send is possible if the socket process has
+ // crashed but hasn't been reconnected properly. See
+ // SocketProcessBridgeChild::ActorDestroy for more info.
+ if (!actor || !actor->CanSend()) {
+ NS_WARNING(
+ "MediaTransportHandlerIPC async init failed! Webrtc networking "
+ "will not work!");
+ return InitPromise::CreateAndReject(
+ nsCString("GetOrCreateSocketActorForCurrentThread failed!"),
+ __func__);
+ }
+ MediaTransportChild* child = new MediaTransportChild(this);
+ // PBackgroungChild owns mChild! When it is done with it,
+ // mChild will let us know it it going away.
+ mChild = actor->SendPMediaTransportConstructor(child);
+ CSFLogDebug(LOGTAG, "%s Init done", __func__);
+ 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<MediaTransportHandler::IceLogPromise>
+MediaTransportHandlerIPC::GetIceLog(const nsCString& aPattern) {
+ return mInitPromise->Then(
+ mCallbackThread, __func__,
+ [=, self = RefPtr<MediaTransportHandlerIPC>(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<IceLogPromise> promise = mChild->SendGetIceLog(aPattern)->Then(
+ mCallbackThread, __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(
+ mCallbackThread, __func__,
+ [=, self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
+ if (mChild) {
+ mChild->SendClearIceLog();
+ }
+ },
+ [](const nsCString& aError) {});
+}
+
+void MediaTransportHandlerIPC::EnterPrivateMode() {
+ mInitPromise->Then(
+ mCallbackThread, __func__,
+ [=, self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
+ if (mChild) {
+ mChild->SendEnterPrivateMode();
+ }
+ },
+ [](const nsCString& aError) {});
+}
+
+void MediaTransportHandlerIPC::ExitPrivateMode() {
+ mInitPromise->Then(
+ mCallbackThread, __func__,
+ [=, self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
+ if (mChild) {
+ mChild->SendExitPrivateMode();
+ }
+ },
+ [](const nsCString& aError) {});
+}
+
+void MediaTransportHandlerIPC::CreateIceCtx(const std::string& aName) {
+ CSFLogDebug(LOGTAG, "MediaTransportHandlerIPC::CreateIceCtx start");
+
+ mInitPromise->Then(
+ mCallbackThread, __func__,
+ [=, self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
+ if (mChild) {
+ CSFLogDebug(LOGTAG, "%s starting", __func__);
+ if (NS_WARN_IF(!mChild->SendCreateIceCtx(aName))) {
+ CSFLogError(LOGTAG, "%s failed!", __func__);
+ }
+ }
+ },
+ [](const nsCString& aError) {});
+}
+
+nsresult MediaTransportHandlerIPC::SetIceConfig(
+ const nsTArray<dom::RTCIceServer>& 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<NrIceStunServer> stunServers;
+ std::vector<NrIceTurnServer> turnServers;
+ nsresult rv = ConvertIceServers(aIceServers, &stunServers, &turnServers);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ mInitPromise->Then(
+ mCallbackThread, __func__,
+ [=, iceServers = aIceServers.Clone(),
+ self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
+ if (mChild) {
+ if (NS_WARN_IF(!mChild->SendSetIceConfig(std::move(iceServers),
+ aIcePolicy))) {
+ CSFLogError(LOGTAG, "%s failed!", __func__);
+ }
+ }
+ },
+ [](const nsCString& aError) {});
+
+ return NS_OK;
+}
+
+void MediaTransportHandlerIPC::Destroy() {
+ if (mChild) {
+ MediaTransportChild::Send__delete__(mChild);
+ mChild = nullptr;
+ }
+ delete this;
+}
+
+// We will probably be able to move the proxy lookup stuff into
+// this class once we move mtransport to its own process.
+void MediaTransportHandlerIPC::SetProxyConfig(
+ NrSocketProxyConfig&& aProxyConfig) {
+ mInitPromise->Then(
+ mCallbackThread, __func__,
+ [aProxyConfig = std::move(aProxyConfig), this,
+ self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) mutable {
+ if (mChild) {
+ mChild->SendSetProxyConfig(aProxyConfig.GetConfig());
+ }
+ },
+ [](const nsCString& aError) {});
+}
+
+void MediaTransportHandlerIPC::EnsureProvisionalTransport(
+ const std::string& aTransportId, const std::string& aLocalUfrag,
+ const std::string& aLocalPwd, int aComponentCount) {
+ mInitPromise->Then(
+ mCallbackThread, __func__,
+ [=, self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
+ if (mChild) {
+ mChild->SendEnsureProvisionalTransport(aTransportId, aLocalUfrag,
+ aLocalPwd, aComponentCount);
+ }
+ },
+ [](const nsCString& aError) {});
+}
+
+void MediaTransportHandlerIPC::SetTargetForDefaultLocalAddressLookup(
+ const std::string& aTargetIp, uint16_t aTargetPort) {
+ mInitPromise->Then(
+ mCallbackThread, __func__,
+ [=, self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
+ if (mChild) {
+ mChild->SendSetTargetForDefaultLocalAddressLookup(aTargetIp,
+ aTargetPort);
+ }
+ },
+ [](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, bool aObfuscateHostAddresses,
+ // TODO(bug 1522205): It probably makes sense to look this up internally
+ const nsTArray<NrIceStunAddr>& aStunAddrs) {
+ mInitPromise->Then(
+ mCallbackThread, __func__,
+ [=, stunAddrs = aStunAddrs.Clone(),
+ self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
+ if (mChild) {
+ mChild->SendStartIceGathering(aDefaultRouteOnly,
+ aObfuscateHostAddresses, stunAddrs);
+ }
+ },
+ [](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<uint8_t>& aKeyDer, const nsTArray<uint8_t>& aCertDer,
+ SSLKEAType aAuthType, bool aDtlsClient, const DtlsDigestList& aDigests,
+ bool aPrivacyRequested) {
+ mInitPromise->Then(
+ mCallbackThread, __func__,
+ [=, keyDer = aKeyDer.Clone(), certDer = aCertDer.Clone(),
+ self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
+ if (mChild) {
+ mChild->SendActivateTransport(aTransportId, aLocalUfrag, aLocalPwd,
+ aComponentCount, aUfrag, aPassword,
+ keyDer, certDer, aAuthType, aDtlsClient,
+ aDigests, aPrivacyRequested);
+ }
+ },
+ [](const nsCString& aError) {});
+}
+
+void MediaTransportHandlerIPC::RemoveTransportsExcept(
+ const std::set<std::string>& aTransportIds) {
+ std::vector<std::string> transportIds(aTransportIds.begin(),
+ aTransportIds.end());
+ mInitPromise->Then(
+ mCallbackThread, __func__,
+ [=, self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
+ if (mChild) {
+ mChild->SendRemoveTransportsExcept(transportIds);
+ }
+ },
+ [](const nsCString& aError) {});
+}
+
+void MediaTransportHandlerIPC::StartIceChecks(
+ bool aIsControlling, const std::vector<std::string>& aIceOptions) {
+ mInitPromise->Then(
+ mCallbackThread, __func__,
+ [=, self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
+ if (mChild) {
+ mChild->SendStartIceChecks(aIsControlling, aIceOptions);
+ }
+ },
+ [](const nsCString& aError) {});
+}
+
+void MediaTransportHandlerIPC::SendPacket(const std::string& aTransportId,
+ MediaPacket&& aPacket) {
+ mInitPromise->Then(
+ mCallbackThread, __func__,
+ [this, self = RefPtr<MediaTransportHandlerIPC>(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,
+ const std::string& aUfrag, const std::string& aObfuscatedAddress) {
+ mInitPromise->Then(
+ mCallbackThread, __func__,
+ [=, self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
+ if (mChild) {
+ mChild->SendAddIceCandidate(aTransportId, aCandidate, aUfrag,
+ aObfuscatedAddress);
+ }
+ },
+ [](const nsCString& aError) {});
+}
+
+void MediaTransportHandlerIPC::UpdateNetworkState(bool aOnline) {
+ mInitPromise->Then(
+ mCallbackThread, __func__,
+ [=, self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
+ if (mChild) {
+ mChild->SendUpdateNetworkState(aOnline);
+ }
+ },
+ [](const nsCString& aError) {});
+}
+
+RefPtr<dom::RTCStatsPromise> MediaTransportHandlerIPC::GetIceStats(
+ const std::string& aTransportId, DOMHighResTimeStamp aNow) {
+ return mInitPromise
+ ->Then(
+ mCallbackThread, __func__,
+ [aTransportId, aNow, this,
+ self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
+ if (!mChild) {
+ return dom::RTCStatsPromise::CreateAndReject(NS_ERROR_FAILURE,
+ __func__);
+ }
+ RefPtr<dom::RTCStatsPromise> promise =
+ mChild->SendGetIceStats(aTransportId, aNow)
+ ->Then(
+ mCallbackThread, __func__,
+ [](const dom::RTCStatsCollection& aStats) {
+ UniquePtr<dom::RTCStatsCollection> stats(
+ new dom::RTCStatsCollection(aStats));
+ return dom::RTCStatsPromise::CreateAndResolve(
+ std::move(stats), __func__);
+ },
+ [](ipc::ResponseRejectReason aReason) {
+ return dom::RTCStatsPromise::CreateAndReject(
+ NS_ERROR_FAILURE, __func__);
+ });
+ return promise;
+ },
+ [](const nsCString& aError) {
+ return dom::RTCStatsPromise::CreateAndReject(NS_ERROR_FAILURE,
+ __func__);
+ })
+ ->Then(mCallbackThread, __func__,
+ [](dom::RTCStatsPromise::ResolveOrRejectValue&& aValue) {
+ // Eat errors! Caller is using MozPromise::All, and we don't
+ // want the whole thing to fail if this fails.
+ if (aValue.IsResolve()) {
+ return dom::RTCStatsPromise::CreateAndResolve(
+ std::move(aValue.ResolveValue()), __func__);
+ }
+ UniquePtr<dom::RTCStatsCollection> empty(
+ new dom::RTCStatsCollection);
+ return dom::RTCStatsPromise::CreateAndResolve(std::move(empty),
+ __func__);
+ });
+}
+
+MediaTransportChild::MediaTransportChild(MediaTransportHandlerIPC* aUser)
+ : mUser(aUser) {}
+
+MediaTransportChild::~MediaTransportChild() { mUser->mChild = nullptr; }
+
+mozilla::ipc::IPCResult MediaTransportChild::RecvOnCandidate(
+ const string& transportId, const CandidateInfo& candidateInfo) {
+ mUser->OnCandidate(transportId, candidateInfo);
+ return ipc::IPCResult::Ok();
+}
+
+mozilla::ipc::IPCResult MediaTransportChild::RecvOnAlpnNegotiated(
+ const string& alpn) {
+ mUser->OnAlpnNegotiated(alpn);
+ return ipc::IPCResult::Ok();
+}
+
+mozilla::ipc::IPCResult MediaTransportChild::RecvOnGatheringStateChange(
+ const int& state) {
+ mUser->OnGatheringStateChange(static_cast<dom::RTCIceGatheringState>(state));
+ return ipc::IPCResult::Ok();
+}
+
+mozilla::ipc::IPCResult MediaTransportChild::RecvOnConnectionStateChange(
+ const int& state) {
+ mUser->OnConnectionStateChange(
+ static_cast<dom::RTCIceConnectionState>(state));
+ return ipc::IPCResult::Ok();
+}
+
+mozilla::ipc::IPCResult MediaTransportChild::RecvOnPacketReceived(
+ const string& transportId, const MediaPacket& packet) {
+ mUser->OnPacketReceived(transportId, packet);
+ return ipc::IPCResult::Ok();
+}
+
+mozilla::ipc::IPCResult MediaTransportChild::RecvOnEncryptedSending(
+ const string& transportId, const MediaPacket& packet) {
+ mUser->OnEncryptedSending(transportId, packet);
+ return ipc::IPCResult::Ok();
+}
+
+mozilla::ipc::IPCResult MediaTransportChild::RecvOnStateChange(
+ const string& transportId, const int& state) {
+ mUser->OnStateChange(transportId, static_cast<TransportLayer::State>(state));
+ return ipc::IPCResult::Ok();
+}
+
+mozilla::ipc::IPCResult MediaTransportChild::RecvOnRtcpStateChange(
+ const string& transportId, const int& state) {
+ mUser->OnRtcpStateChange(transportId,
+ static_cast<TransportLayer::State>(state));
+ return ipc::IPCResult::Ok();
+}
+
+} // namespace mozilla