Bug 1521879 - Part 1: IPC-based MediaTransport implementation r=mjf

Differential Revision: https://phabricator.services.mozilla.com/D17273

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Byron Campen [:bwc] 2019-02-21 16:42:12 +00:00
Родитель 90f0dafc2a
Коммит 4604113749
32 изменённых файлов: 1714 добавлений и 129 удалений

Просмотреть файл

@ -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 += [

Просмотреть файл

@ -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

Просмотреть файл

@ -14,6 +14,24 @@ typedef mozilla::dom::RTCStatsReportInternal StatsReport;
typedef nsTArray<nsAutoPtr<StatsReport>> RTCReports;
typedef mozilla::dom::Sequence<nsString> 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 <typename T>
@ -50,6 +68,21 @@ struct ParamTraits<mozilla::dom::RTCIceCandidateType>
mozilla::dom::RTCIceCandidateType::Host,
mozilla::dom::RTCIceCandidateType::EndGuard_> {};
template <>
struct ParamTraits<mozilla::dom::MovableRTCStatsReportInternal> {
typedef mozilla::dom::MovableRTCStatsReportInternal paramType;
static void Write(Message* aMsg, const paramType& aParam) {
WriteParam(
aMsg, static_cast<const mozilla::dom::RTCStatsReportInternal&>(aParam));
}
static bool Read(const Message* aMsg, PickleIterator* aIter,
paramType* aResult) {
return ReadParam(
aMsg, aIter,
static_cast<mozilla::dom::RTCStatsReportInternal*>(aResult));
}
};
template <>
struct ParamTraits<mozilla::dom::RTCStatsReportInternal> {
typedef mozilla::dom::RTCStatsReportInternal paramType;

Просмотреть файл

@ -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 <vector>
namespace mozilla {
typedef std::vector<std::string> StringVector;
}
namespace IPC {
template <typename T>
struct ParamTraits<std::vector<T>> {
typedef std::vector<T> 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<mozilla::dom::OwningStringOrStringSequence> {
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 <typename T>
struct WebidlEnumSerializer
: public ContiguousEnumSerializer<T, T(0), T::EndGuard_> {};
template <>
struct ParamTraits<mozilla::dom::RTCIceCredentialType>
: public WebidlEnumSerializer<mozilla::dom::RTCIceCredentialType> {};
template <>
struct ParamTraits<mozilla::dom::RTCIceTransportPolicy>
: public WebidlEnumSerializer<mozilla::dom::RTCIceTransportPolicy> {};
// 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 <typename T0, typename... Tn>
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 <typename T0, typename... Tn>
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<Type> { \
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_

Просмотреть файл

@ -53,6 +53,10 @@ if CONFIG['MOZ_WEBRTC']:
'/media/webrtc/trunk/webrtc'
]
IPDL_SOURCES += [
'PMediaTransport.ipdl',
]
XPIDL_SOURCES += [
'nsITabSource.idl'
]

Просмотреть файл

@ -19,6 +19,7 @@
#include "mozilla/Sprintf.h"
#include "mozilla/dom/CryptoBuffer.h"
#include "mozilla/dom/CryptoKey.h"
#include "ipc/IPCMessageUtils.h"
namespace mozilla {

Просмотреть файл

@ -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<uint8_t>& value)
: algorithm_(algorithm), value_(value) {

Просмотреть файл

@ -7,9 +7,15 @@
#include "mediapacket.h"
#include <cstring>
#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<uint8_t[]> 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<uint8_t[]> 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>(type);
return true;
}
static bool IsRtp(const uint8_t* data, size_t len) {
if (len < 2) return false;

Просмотреть файл

@ -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<uint8_t[]>&& 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<uint8_t[]> data_;
size_t len_ = 0;
@ -80,4 +93,21 @@ class MediaPacket {
Type type_ = UNCLASSIFIED;
};
} // namespace mozilla
namespace IPC {
template <typename>
struct ParamTraits;
template <>
struct ParamTraits<mozilla::MediaPacket> {
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__

Просмотреть файл

@ -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) {

Просмотреть файл

@ -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;

Просмотреть файл

@ -44,6 +44,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <netinet/in.h>
#endif
#include "r_types.h"
/* Length of a string hex representation of a MD5 hash */
#define MAXIFNAME 33

Просмотреть файл

@ -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<dom::RTCIceServer>& aIceServers,
dom::RTCIceTransportPolicy aIcePolicy) override {
nsresult CreateIceCtx(const std::string& aName,
const nsTArray<dom::RTCIceServer>& 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<MediaTransportHandler> peer_;
std::map<std::string, TransportLayer::State> mRtpStates;
std::map<std::string, TransportLayer::State> mRtcpStates;
};
class TestAgent {

Просмотреть файл

@ -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',

Просмотреть файл

@ -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,

Просмотреть файл

@ -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);

Просмотреть файл

@ -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<IceLogPromise> GetIceLog(const nsCString& aPattern) override;
void ClearIceLog() override;
void EnterPrivateMode() override;
void ExitPrivateMode() override;
nsresult Init(const std::string& aName,
const nsTArray<dom::RTCIceServer>& aIceServers,
dom::RTCIceTransportPolicy aIcePolicy) override;
nsresult CreateIceCtx(const std::string& aName,
const nsTArray<dom::RTCIceServer>& 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<StatsPromise> GetIceStats(
const std::string& aTransportId, DOMHighResTimeStamp aNow,
std::unique_ptr<dom::RTCStatsReportInternal>&& aReport) override;
@ -121,6 +121,15 @@ class MediaTransportHandlerSTS : public MediaTransportHandler,
RefPtr<TransportFlow> 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<NrIceCtx> mIceCtx;
RefPtr<NrIceResolver> mDNSResolver;
std::map<std::string, Transport> mTransports;
std::map<std::string, TransportLayer::State> mStateCache;
std::map<std::string, TransportLayer::State> mRtcpStateCache;
bool mProxyOnly = false;
};
/* static */
already_AddRefed<MediaTransportHandler> MediaTransportHandler::Create() {
already_AddRefed<MediaTransportHandler> MediaTransportHandler::Create(
nsISerialEventTarget* aCallbackThread) {
RefPtr<MediaTransportHandler> 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<dom::RTCIceServer>& aIceServers,
dom::RTCIceTransportPolicy aIcePolicy) {
std::vector<NrIceStunServer> stunServers;
std::vector<NrIceTurnServer> turnServers;
nsresult rv;
/* static */
nsresult MediaTransportHandler::ConvertIceServers(
const nsTArray<dom::RTCIceServer>& aIceServers,
std::vector<NrIceStunServer>* aStunServers,
std::vector<NrIceTurnServer>* 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<dom::RTCIceServer>& aIceServers,
dom::RTCIceTransportPolicy aIcePolicy) {
std::vector<NrIceStunServer> stunServers;
std::vector<NrIceTurnServer> 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<MediaTransportHandlerSTS>(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<NrSocketProxyConfig&&>(
__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<MediaTransportHandlerSTS>(this),
&MediaTransportHandlerSTS::EnsureProvisionalTransport,
aTransportId, aUfrag, aPwd, aComponentCount),
NS_DISPATCH_NORMAL);
return;
}
RefPtr<NrIceMediaStream> 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<uint8_t>& aKeyDer, const nsTArray<uint8_t>& aCertDer,
SSLKEAType aAuthType, bool aDtlsClient, const DtlsDigestList& aDigests,
bool aPrivacyRequested) {
if (!mStsThread->IsOnCurrentThread()) {
mStsThread->Dispatch(
WrapRunnable(RefPtr<MediaTransportHandlerSTS>(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(
DtlsIdentity::Deserialize(aKeyDer, aCertDer, aAuthType));
@ -494,6 +551,15 @@ void MediaTransportHandlerSTS::ActivateTransport(
void MediaTransportHandlerSTS::StartIceGathering(
bool aDefaultRouteOnly, const nsTArray<NrIceStunAddr>& aStunAddrs) {
if (!mStsThread->IsOnCurrentThread()) {
mStsThread->Dispatch(
WrapRunnable(RefPtr<MediaTransportHandlerSTS>(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<std::string>& aIceOptions) {
if (!mStsThread->IsOnCurrentThread()) {
mStsThread->Dispatch(WrapRunnable(RefPtr<MediaTransportHandlerSTS>(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<MediaTransportHandlerSTS>(this),
&MediaTransportHandlerSTS::AddIceCandidate, aTransportId,
aCandidate),
NS_DISPATCH_NORMAL);
return;
}
RefPtr<NrIceMediaStream> 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<MediaTransportHandlerSTS>(this),
&MediaTransportHandlerSTS::UpdateNetworkState, aOnline),
NS_DISPATCH_NORMAL);
return;
}
mIceCtx->UpdateNetworkState(aOnline);
}
void MediaTransportHandlerSTS::RemoveTransportsExcept(
const std::set<std::string>& aTransportIds) {
if (!mStsThread->IsOnCurrentThread()) {
mStsThread->Dispatch(
WrapRunnable(RefPtr<MediaTransportHandlerSTS>(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<std::string, MediaPacket&&>(
__func__, this, &MediaTransportHandlerSTS::SendPacket, aTransportId,
std::move(aPacket)));
return;
}
MOZ_ASSERT(aPacket.type() != MediaPacket::UNCLASSIFIED);
RefPtr<TransportFlow> 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<TransportFlow> flow = GetTransportFlow(aTransportId, aRtcp);
if (flow) {
return flow->GetLayer(TransportLayerDtls::ID())->state();
if (mCallbackThread) {
MOZ_ASSERT(mCallbackThread->IsOnCurrentThread());
}
const std::map<std::string, TransportLayer::State>* 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<MediaTransportHandler>(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<MediaTransportHandler>(this),
&MediaTransportHandler::OnAlpnNegotiated, aAlpn),
NS_DISPATCH_NORMAL);
return;
}
SignalAlpnNegotiated(aAlpn);
}
void MediaTransportHandler::OnGatheringStateChange(
dom::PCImplIceGatheringState aState) {
if (mCallbackThread && !mCallbackThread->IsOnCurrentThread()) {
mCallbackThread->Dispatch(
WrapRunnable(RefPtr<MediaTransportHandler>(this),
&MediaTransportHandler::OnGatheringStateChange, aState),
NS_DISPATCH_NORMAL);
return;
}
SignalGatheringStateChange(aState);
}
void MediaTransportHandler::OnConnectionStateChange(
dom::PCImplIceConnectionState aState) {
if (mCallbackThread && !mCallbackThread->IsOnCurrentThread()) {
mCallbackThread->Dispatch(
WrapRunnable(RefPtr<MediaTransportHandler>(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<MediaTransportHandler>(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<MediaTransportHandler>(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<MediaTransportHandler>(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<MediaTransportHandler>(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<MediaTransportHandler::StatsPromise>
MediaTransportHandlerSTS::GetIceStats(
const std::string& aTransportId, DOMHighResTimeStamp aNow,
std::unique_ptr<dom::RTCStatsReportInternal>&& 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<MediaTransportHandlerSTS>(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<MediaTransportHandler::IceLogPromise>
MediaTransportHandlerSTS::GetIceLog(const nsCString& aPattern) {
RLogConnector* logs = RLogConnector::GetInstance();
nsAutoPtr<std::deque<std::string>> result(new std::deque<std::string>);
// Might not exist yet.
if (logs) {
logs->Filter(aPattern.get(), 0, result);
}
dom::Sequence<nsString> 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<MediaTransportHandlerSTS>(this)] {
dom::Sequence<nsString> converted;
RLogConnector* logs = RLogConnector::GetInstance();
nsAutoPtr<std::deque<std::string>> result(new std::deque<std::string>);
// 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<MediaTransportHandlerSTS>(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<MediaTransportHandlerSTS>(this),
&MediaTransportHandlerSTS::EnterPrivateMode),
NS_DISPATCH_NORMAL);
return;
}
RLogConnector::CreateInstance()->EnterPrivateMode();
}
void MediaTransportHandlerSTS::ExitPrivateMode() {
if (!mStsThread->IsOnCurrentThread()) {
mStsThread->Dispatch(
WrapRunnable(RefPtr<MediaTransportHandlerSTS>(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<NrIceCandidatePair> 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<TransportLayerDtls*>(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

Просмотреть файл

@ -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<MediaTransportHandler> 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<MediaTransportHandler> Create(
nsISerialEventTarget* aCallbackThread);
explicit MediaTransportHandler(nsISerialEventTarget* aCallbackThread)
: mCallbackThread(aCallbackThread) {}
static nsresult ConvertIceServers(
const nsTArray<dom::RTCIceServer>& aIceServers,
std::vector<NrIceStunServer>* aStunServers,
std::vector<NrIceTurnServer>* aTurnServers);
typedef MozPromise<dom::Sequence<nsString>, 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<dom::RTCIceServer>& aIceServers,
dom::RTCIceTransportPolicy aIcePolicy) = 0;
virtual void Destroy() = 0;
virtual nsresult CreateIceCtx(const std::string& aName,
const nsTArray<dom::RTCIceServer>& 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<std::unique_ptr<dom::RTCStatsReportInternal>, 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<std::string, TransportLayer::State> mStateCache;
std::map<std::string, TransportLayer::State> mRtcpStateCache;
RefPtr<nsISerialEventTarget> mCallbackThread;
};
} // namespace mozilla

Просмотреть файл

@ -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<MediaTransportHandlerIPC> mUser;
};
MediaTransportHandlerIPC::MediaTransportHandlerIPC(
nsISerialEventTarget* aCallbackThread)
: MediaTransportHandler(aCallbackThread) {
mInitPromise = net::SocketProcessBridgeChild::GetSocketProcessBridge()->Then(
GetMainThreadSerialEventTarget(), __func__,
[this, self = RefPtr<MediaTransportHandlerIPC>(this)](
const RefPtr<net::SocketProcessBridgeChild>& 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<MediaTransportHandler::IceLogPromise>
MediaTransportHandlerIPC::GetIceLog(const nsCString& aPattern) {
return mInitPromise->Then(
GetMainThreadSerialEventTarget(), __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(
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<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
if (mChild) {
mChild->SendClearIceLog();
}
},
[](const nsCString& aError) {});
}
void MediaTransportHandlerIPC::EnterPrivateMode() {
mInitPromise->Then(
GetMainThreadSerialEventTarget(), __func__,
[=, self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
if (mChild) {
mChild->SendEnterPrivateMode();
}
},
[](const nsCString& aError) {});
}
void MediaTransportHandlerIPC::ExitPrivateMode() {
mInitPromise->Then(
GetMainThreadSerialEventTarget(), __func__,
[=, self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
if (mChild) {
mChild->SendExitPrivateMode();
}
},
[](const nsCString& aError) {});
}
nsresult MediaTransportHandlerIPC::CreateIceCtx(
const std::string& aName, 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(
GetMainThreadSerialEventTarget(), __func__,
[=, self = RefPtr<MediaTransportHandlerIPC>(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<MediaTransportHandlerIPC>(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<MediaTransportHandlerIPC>(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<MediaTransportHandlerIPC>(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<NrIceStunAddr>& aStunAddrs) {
mInitPromise->Then(
GetMainThreadSerialEventTarget(), __func__,
[=, self = RefPtr<MediaTransportHandlerIPC>(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<uint8_t>& aKeyDer, const nsTArray<uint8_t>& aCertDer,
SSLKEAType aAuthType, bool aDtlsClient, const DtlsDigestList& aDigests,
bool aPrivacyRequested) {
mInitPromise->Then(
GetMainThreadSerialEventTarget(), __func__,
[=, self = RefPtr<MediaTransportHandlerIPC>(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<std::string>& aTransportIds) {
std::vector<std::string> transportIds(aTransportIds.begin(),
aTransportIds.end());
mInitPromise->Then(
GetMainThreadSerialEventTarget(), __func__,
[=, self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
if (mChild) {
mChild->SendRemoveTransportsExcept(transportIds);
}
},
[](const nsCString& aError) {});
}
void MediaTransportHandlerIPC::StartIceChecks(
bool aIsControlling, bool aIsOfferer,
const std::vector<std::string>& aIceOptions) {
mInitPromise->Then(
GetMainThreadSerialEventTarget(), __func__,
[=, self = RefPtr<MediaTransportHandlerIPC>(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<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) {
mInitPromise->Then(
GetMainThreadSerialEventTarget(), __func__,
[=, self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
if (mChild) {
mChild->SendAddIceCandidate(aTransportId, aCandidate);
}
},
[](const nsCString& aError) {});
}
void MediaTransportHandlerIPC::UpdateNetworkState(bool aOnline) {
mInitPromise->Then(
GetMainThreadSerialEventTarget(), __func__,
[=, self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) {
if (mChild) {
mChild->SendUpdateNetworkState(aOnline);
}
},
[](const nsCString& aError) {});
}
RefPtr<MediaTransportHandler::StatsPromise>
MediaTransportHandlerIPC::GetIceStats(
const std::string& aTransportId, DOMHighResTimeStamp aNow,
std::unique_ptr<dom::RTCStatsReportInternal>&& aReport) {
return mInitPromise->Then(
GetMainThreadSerialEventTarget(), __func__,
[aReport = std::move(aReport), aTransportId, aNow, this,
self = RefPtr<MediaTransportHandlerIPC>(this)](bool /*dummy*/) mutable {
if (!mChild) {
return StatsPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
}
RefPtr<StatsPromise> promise =
mChild->SendGetIceStats(aTransportId, aNow, *aReport)
->Then(GetMainThreadSerialEventTarget(), __func__,
[](const dom::MovableRTCStatsReportInternal& aReport) {
std::unique_ptr<dom::RTCStatsReportInternal> 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<dom::PCImplIceGatheringState>(state));
return ipc::IPCResult::Ok();
}
mozilla::ipc::IPCResult MediaTransportHandlerChild::RecvOnConnectionStateChange(
const int& state) {
MOZ_ASSERT(GetMainThreadEventTarget()->IsOnCurrentThread());
mUser->OnConnectionStateChange(
static_cast<dom::PCImplIceConnectionState>(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<TransportLayer::State>(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<TransportLayer::State>(state));
return ipc::IPCResult::Ok();
}
} // namespace mozilla

Просмотреть файл

@ -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<IceLogPromise> GetIceLog(const nsCString& aPattern) override;
void ClearIceLog() override;
void EnterPrivateMode() override;
void ExitPrivateMode() override;
nsresult CreateIceCtx(const std::string& aName,
const nsTArray<dom::RTCIceServer>& 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<NrIceStunAddr>& 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<uint8_t>& aKeyDer, const nsTArray<uint8_t>& aCertDer,
SSLKEAType aAuthType, bool aDtlsClient, const DtlsDigestList& aDigests,
bool aPrivacyRequested) override;
void RemoveTransportsExcept(
const std::set<std::string>& aTransportIds) override;
void StartIceChecks(bool aIsControlling, bool aIsOfferer,
const std::vector<std::string>& 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<StatsPromise> GetIceStats(
const std::string& aTransportId, DOMHighResTimeStamp aNow,
std::unique_ptr<dom::RTCStatsReportInternal>&& 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<bool, nsCString, false> InitPromise;
RefPtr<InitPromise> mInitPromise;
};
} // namespace mozilla
#endif //_MTRANSPORTHANDLER_IPC_H__

Просмотреть файл

@ -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<int>(aState)));
}
void MediaTransportHandlerParent::OnConnectionStateChange(
dom::PCImplIceConnectionState aState) {
NS_ENSURE_TRUE_VOID(SendOnConnectionStateChange(static_cast<int>(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<RTCIceServer>&& 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<uint8_t>&& keyDer,
nsTArray<uint8_t>&& 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<SSLKEAType>(authType), dtlsClient,
digests, privacyRequested);
return ipc::IPCResult::Ok();
}
mozilla::ipc::IPCResult MediaTransportHandlerParent::RecvRemoveTransportsExcept(
const StringVector& transportIds) {
MOZ_ASSERT(GetMainThreadEventTarget()->IsOnCurrentThread());
std::set<std::string> 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<dom::RTCStatsReportInternal> 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

Просмотреть файл

@ -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<RTCIceServer>&& 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<uint8_t>&& keyDer, nsTArray<uint8_t>&& 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<MediaTransportHandler> mImpl;
RefPtr<nsIEventTarget> mStsThread;
};
} // namespace mozilla
#endif //_MTRANSPORTHANDLER_PARENT_H__

Просмотреть файл

@ -72,7 +72,9 @@ class PeerConnectionCtx {
std::map<const std::string, PeerConnectionImpl*> 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;

Просмотреть файл

@ -308,7 +308,7 @@ PeerConnectionImpl::PeerConnectionImpl(const GlobalObject* aGlobal)
mSTSThread(nullptr),
mForceIceTcp(false),
mMedia(nullptr),
mTransportHandler(MediaTransportHandler::Create()),
mTransportHandler(nullptr),
mUuidGen(MakeUnique<PCUuidGenerator>()),
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;

Просмотреть файл

@ -24,6 +24,8 @@ LOCAL_INCLUDES += [
UNIFIED_SOURCES += [
'MediaTransportHandler.cpp',
'MediaTransportHandlerIPC.cpp',
'MediaTransportHandlerParent.cpp',
'PacketDumper.cpp',
'PeerConnectionCtx.cpp',
'PeerConnectionImpl.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();
}
}

Просмотреть файл

@ -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<PBackgroundParent> aEndpoint);
async PMediaTransport();
both:
async Test();
};

Просмотреть файл

@ -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<void()>&& aOnSuccess, std::function<void()>&& aOnFailure) {
MOZ_ASSERT(IsNeckoChild() && gNeckoChild);
RefPtr<SocketProcessBridgeChild::GetPromise>
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<PSocketProcessBridgeChild>&& 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

Просмотреть файл

@ -22,10 +22,10 @@ class SocketProcessBridgeChild final : public PSocketProcessBridgeChild,
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
static bool Create(Endpoint<PSocketProcessBridgeChild>&& aEndpoint);
static already_AddRefed<SocketProcessBridgeChild> GetSingleton();
static void EnsureSocketProcessBridge(std::function<void()>&& aOnSuccess,
std::function<void()>&& aOnFailure);
typedef MozPromise<RefPtr<SocketProcessBridgeChild>, nsCString, false>
GetPromise;
static RefPtr<GetPromise> 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<PSocketProcessBridgeChild>&& aEndpoint);
explicit SocketProcessBridgeChild(
Endpoint<PSocketProcessBridgeChild>&& aEndpoint);
virtual ~SocketProcessBridgeChild();

Просмотреть файл

@ -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

Просмотреть файл

@ -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();

Просмотреть файл

@ -62,6 +62,8 @@ FINAL_LIBRARY = 'xul'
LOCAL_INCLUDES += [
'/caps',
'/dom/base',
'/media/mtransport',
'/media/webrtc',
'/modules/libjar',
'/netwerk/base',
'/netwerk/protocol/http',