mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
Bug 694807: Implement PeerConnection C++ module; r=jst,jesup,ekr
This commit is contained in:
parent
892bf6da06
commit
e61ba69837
@ -5250,8 +5250,8 @@ dnl enable once Signaling lands
|
||||
MOZ_WEBRTC_IN_LIBXUL=1
|
||||
fi
|
||||
dnl enable once PeerConnection lands
|
||||
dnl MOZ_PEERCONNECTION=1
|
||||
dnl AC_DEFINE(MOZ_PEERCONNECTION)
|
||||
MOZ_PEERCONNECTION=1
|
||||
AC_DEFINE(MOZ_PEERCONNECTION)
|
||||
MOZ_SCTP=1
|
||||
MOZ_SRTP=1
|
||||
AC_DEFINE(MOZ_SCTP)
|
||||
|
@ -43,9 +43,10 @@ nsDOMMediaStream::GetCurrentTime(double *aCurrentTime)
|
||||
}
|
||||
|
||||
already_AddRefed<nsDOMMediaStream>
|
||||
nsDOMMediaStream::CreateInputStream()
|
||||
nsDOMMediaStream::CreateInputStream(PRUint32 aHintContents)
|
||||
{
|
||||
nsRefPtr<nsDOMMediaStream> stream = new nsDOMMediaStream();
|
||||
stream->SetHintContents(aHintContents);
|
||||
MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
|
||||
stream->mStream = gm->CreateInputStream(stream);
|
||||
return stream.forget();
|
||||
|
@ -38,6 +38,7 @@ ifdef MOZ_WEBRTC
|
||||
LOCAL_INCLUDES += \
|
||||
-I$(topsrcdir)/media/webrtc/trunk/src \
|
||||
$(NULL)
|
||||
DIRS += bridge
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/config.mk
|
||||
|
97
dom/media/bridge/IPeerConnection.idl
Normal file
97
dom/media/bridge/IPeerConnection.idl
Normal file
@ -0,0 +1,97 @@
|
||||
#include "nsIThread.idl"
|
||||
#include "nsIDOMWindow.idl"
|
||||
|
||||
interface nsIDOMMediaStream;
|
||||
|
||||
/* Do not confuse with nsIDOMRTCPeerConnection. This interface is purely for
|
||||
* communication between the PeerConnection JS DOM binding and the C++
|
||||
* implementation in SIPCC.
|
||||
*
|
||||
* See media/webrtc/signaling/include/PeerConnectionImpl.h
|
||||
*/
|
||||
[scriptable, uuid(84efc76f-41d9-496a-9444-2965d179d419)]
|
||||
interface IPeerConnectionObserver : nsISupports
|
||||
{
|
||||
/* Constants */
|
||||
const long kReadyState = 0x1;
|
||||
const long kIceState = 0x2;
|
||||
const long kSdpState = 0x3;
|
||||
const long kSipccState = 0x4;
|
||||
|
||||
/* JSEP callbacks */
|
||||
void onCreateOfferSuccess(in string offer);
|
||||
void onCreateOfferError(in unsigned long code);
|
||||
void onCreateAnswerSuccess(in string answer);
|
||||
void onCreateAnswerError(in unsigned long code);
|
||||
void onSetLocalDescriptionSuccess(in unsigned long code);
|
||||
void onSetRemoteDescriptionSuccess(in unsigned long code);
|
||||
void onSetLocalDescriptionError(in unsigned long code);
|
||||
void onSetRemoteDescriptionError(in unsigned long code);
|
||||
|
||||
/* Notification of one of several types of state changed */
|
||||
void onStateChange(in unsigned long state);
|
||||
|
||||
/* Changes to MediaStreams */
|
||||
void onAddStream(in nsIDOMMediaStream stream, in string type);
|
||||
void onRemoveStream();
|
||||
void onAddTrack();
|
||||
void onRemoveTrack();
|
||||
|
||||
/* When SDP is parsed and a candidate line is found this method is called.
|
||||
* It should hook back into the media transport to notify it of ICE candidates
|
||||
* listed in the SDP PeerConnectionImpl does not parse ICE candidates, just
|
||||
* pulls them out of the SDP.
|
||||
*/
|
||||
void foundIceCandidate(in string candidate);
|
||||
};
|
||||
|
||||
[scriptable, uuid(942366a9-80fe-4cac-ac97-4fbca45bcbff)]
|
||||
interface IPeerConnection : nsISupports
|
||||
{
|
||||
const unsigned long kHintAudio = 0x00000001;
|
||||
const unsigned long kHintVideo = 0x00000002;
|
||||
|
||||
const long kActionNone = -1;
|
||||
const long kActionOffer = 0;
|
||||
const long kActionAnswer = 1;
|
||||
const long kActionPRAnswer = 2;
|
||||
|
||||
const long kIceGathering = 0;
|
||||
const long kIceWaiting = 1;
|
||||
const long kIceChecking = 2;
|
||||
const long kIceConnected = 3;
|
||||
const long kIceFailed = 4;
|
||||
|
||||
/* Must be called first. Observer events will be dispatched on the thread provided */
|
||||
void initialize(in IPeerConnectionObserver observer, in nsIDOMWindow window,
|
||||
[optional] in nsIThread thread);
|
||||
|
||||
/* JSEP calls */
|
||||
void createOffer(in string hints);
|
||||
void createAnswer(in string hints, in string offer);
|
||||
void setLocalDescription(in long action, in string sdp);
|
||||
void setRemoteDescription(in long action, in string sdp);
|
||||
|
||||
/* Adds the stream created by GetUserMedia */
|
||||
void addStream(in nsIDOMMediaStream stream);
|
||||
void removeStream(in nsIDOMMediaStream stream);
|
||||
void closeStreams();
|
||||
|
||||
/* As the ICE candidates roll in this one should be called each time
|
||||
* in order to keep the candidate list up-to-date for the next SDP-related
|
||||
* call PeerConnectionImpl does not parse ICE candidates, just sticks them
|
||||
* into the SDP.
|
||||
*/
|
||||
void addIceCandidate(in string candidate, in string mid, in unsigned short level);
|
||||
|
||||
/* Puts the SIPCC engine back to 'kIdle', shuts down threads, deletes state */
|
||||
void close();
|
||||
|
||||
/* Attributes */
|
||||
readonly attribute string localDescription;
|
||||
readonly attribute string remoteDescription;
|
||||
|
||||
readonly attribute unsigned long iceState;
|
||||
readonly attribute unsigned long readyState;
|
||||
readonly attribute unsigned long sipccState;
|
||||
};
|
37
dom/media/bridge/Makefile.in
Normal file
37
dom/media/bridge/Makefile.in
Normal file
@ -0,0 +1,37 @@
|
||||
# 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/.
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = peerconnection
|
||||
XPIDL_MODULE = peerconnection
|
||||
LIBRARY_NAME = peerconnection
|
||||
MODULE_NAME = peerconnection
|
||||
|
||||
IS_COMPONENT = 1
|
||||
EXPORT_LIBRARY = 1
|
||||
LIBXUL_LIBRARY = 1
|
||||
|
||||
XPIDLSRCS = IPeerConnection.idl
|
||||
|
||||
CPPSRCS = \
|
||||
MediaModule.cpp \
|
||||
$(NULL)
|
||||
|
||||
LOCAL_INCLUDES += \
|
||||
-I$(topsrcdir)/media/mtransport \
|
||||
-I$(topsrcdir)/media/webrtc/signaling/include \
|
||||
-I$(topsrcdir)/media/webrtc/signaling/src/sipcc/include \
|
||||
-I$(topsrcdir)/media/webrtc/signaling/src/peerconnection \
|
||||
-I$(topsrcdir)/media/webrtc/signaling/src/mediapipeline \
|
||||
-I$(topsrcdir)/media/webrtc/signaling/src/media-conduit \
|
||||
-I$(topsrcdir)/ipc/chromium/src \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
46
dom/media/bridge/MediaModule.cpp
Normal file
46
dom/media/bridge/MediaModule.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
/* 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 "base/linked_ptr.h"
|
||||
|
||||
#include "mozilla/ModuleUtils.h"
|
||||
#include "nsIClassInfoImpl.h"
|
||||
|
||||
#ifdef MOZ_WEBRTC
|
||||
|
||||
#include "PeerConnectionImpl.h"
|
||||
|
||||
#define PEERCONNECTION_CID \
|
||||
{0xb93af7a1, 0x3411, 0x44a8, {0xbd, 0x0a, 0x8a, 0xf3, 0xdd, 0xe4, 0xd8, 0xd8}}
|
||||
|
||||
#define PEERCONNECTION_CONTRACTID "@mozilla.org/peerconnection;1"
|
||||
|
||||
namespace sipcc
|
||||
{
|
||||
// Factory defined in sipcc::, defines sipcc::PeerConnectionImplConstructor
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(PeerConnectionImpl)
|
||||
}
|
||||
|
||||
// Defines kPEERCONNECTION_CID
|
||||
NS_DEFINE_NAMED_CID(PEERCONNECTION_CID);
|
||||
|
||||
static const mozilla::Module::CIDEntry kCIDs[] = {
|
||||
{ &kPEERCONNECTION_CID, false, NULL, sipcc::PeerConnectionImplConstructor },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static const mozilla::Module::ContractIDEntry kContracts[] = {
|
||||
{ PEERCONNECTION_CONTRACTID, &kPEERCONNECTION_CID },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static const mozilla::Module kModule = {
|
||||
mozilla::Module::kVersion,
|
||||
kCIDs,
|
||||
kContracts
|
||||
};
|
||||
|
||||
NSMODULE_DEFN(peerconnection) = &kModule;
|
||||
|
||||
#endif
|
@ -3,6 +3,8 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
#include "vcm.h"
|
||||
#include "CSFLog.h"
|
||||
@ -171,15 +173,15 @@ public:
|
||||
}
|
||||
case PC_OBSERVER_CONNECTION:
|
||||
CSFLogDebugS(logTag, __FUNCTION__ << ": Delivering PeerConnection onconnection");
|
||||
mObserver->NotifyConnection();
|
||||
//mObserver->NotifyConnection();
|
||||
break;
|
||||
case PC_OBSERVER_CLOSEDCONNECTION:
|
||||
CSFLogDebugS(logTag, __FUNCTION__ << ": Delivering PeerConnection onclosedconnection");
|
||||
mObserver->NotifyClosedConnection();
|
||||
//mObserver->NotifyClosedConnection();
|
||||
break;
|
||||
case PC_OBSERVER_DATACHANNEL:
|
||||
CSFLogDebugS(logTag, __FUNCTION__ << ": Delivering PeerConnection ondatachannel");
|
||||
mObserver->NotifyDataChannel(mChannel);
|
||||
//mObserver->NotifyDataChannel(mChannel);
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
NS_DataChannelAppReady(mChannel);
|
||||
#endif
|
||||
@ -474,7 +476,7 @@ PeerConnectionImpl::Initialize(IPeerConnectionObserver* observer,
|
||||
// DTLS identity
|
||||
unsigned char fingerprint[DTLS_FINGERPRINT_LENGTH];
|
||||
size_t fingerprint_length;
|
||||
res = mIdentity->ComputeFingerprint("sha-256",
|
||||
res = mIdentity->ComputeFingerprint("sha-1",
|
||||
fingerprint,
|
||||
sizeof(fingerprint),
|
||||
&fingerprint_length);
|
||||
@ -484,7 +486,7 @@ PeerConnectionImpl::Initialize(IPeerConnectionObserver* observer,
|
||||
return res;
|
||||
}
|
||||
|
||||
mFingerprint = "sha-256 " + mIdentity->FormatFingerprint(fingerprint,
|
||||
mFingerprint = "sha-1 " + mIdentity->FormatFingerprint(fingerprint,
|
||||
fingerprint_length);
|
||||
|
||||
// Find the STS thread
|
||||
@ -506,7 +508,7 @@ PeerConnectionImpl::Initialize(IPeerConnectionObserver* observer,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsresult
|
||||
PeerConnectionImpl::CreateFakeMediaStream(PRUint32 hint, nsIDOMMediaStream** retval)
|
||||
{
|
||||
MOZ_ASSERT(retval);
|
||||
@ -545,153 +547,6 @@ PeerConnectionImpl::CreateFakeMediaStream(PRUint32 hint, nsIDOMMediaStream** ret
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PeerConnectionImpl::ConnectDataConnection(PRUint16 localport, PRUint16 remoteport, PRUint16 numstreams)
|
||||
{
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
mDataConnection = new mozilla::DataChannelConnection(this);
|
||||
NS_ENSURE_TRUE(mDataConnection,NS_ERROR_FAILURE);
|
||||
if(!mDataConnection->Init(localport, numstreams, true))
|
||||
{
|
||||
CSFLogError(logTag,"%s DataConnection Init Failed",__FUNCTION__);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// XXX errors?
|
||||
// XXX Fix! get the correct flow for DataChannel
|
||||
nsRefPtr<TransportFlow> flow = GetTransportFlow(2,false).get();
|
||||
CSFLogDebugS(logTag, "Transportflow[2] = " << flow.get());
|
||||
if(!mDataConnection->ConnectDTLS(flow, localport, remoteport))
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// XXX errors?
|
||||
return NS_OK;
|
||||
#else
|
||||
return NS_ERROR_FAILURE;
|
||||
#endif
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PeerConnectionImpl::CreateDataChannel(const nsACString& label,
|
||||
PRUint16 type,
|
||||
bool outOfOrderAllowed,
|
||||
PRUint16 maxTime,
|
||||
PRUint16 maxNum,
|
||||
nsIDOMDataChannel** aRetval)
|
||||
{
|
||||
MOZ_ASSERT(aRetval);
|
||||
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
mozilla::DataChannel *aDataChannel;
|
||||
mozilla::DataChannelConnection::Type theType = (mozilla::DataChannelConnection::Type) type;
|
||||
|
||||
if (!mDataConnection) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
aDataChannel = mDataConnection->Open(label,
|
||||
theType, !outOfOrderAllowed,
|
||||
type == mozilla::DataChannelConnection::PARTIAL_RELIABLE_REXMIT ? maxNum :
|
||||
(type == mozilla::DataChannelConnection::PARTIAL_RELIABLE_TIMED ? maxTime : 0),
|
||||
NULL, NULL);
|
||||
NS_ENSURE_TRUE(aDataChannel,NS_ERROR_FAILURE);
|
||||
|
||||
CSFLogDebugS(logTag, __FUNCTION__ << ": making DOMDataChannel");
|
||||
|
||||
return NS_NewDOMDataChannel(aDataChannel,
|
||||
mWindow,
|
||||
aRetval);
|
||||
#else
|
||||
return NS_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
// XXX Temporary - remove
|
||||
NS_IMETHODIMP
|
||||
PeerConnectionImpl::Listen(unsigned short port, PRUint16 numstreams)
|
||||
{
|
||||
CSFLogDebugS(logTag, __FUNCTION__ << ": port: " << port << ", numstreams: " << numstreams);
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
if (!mDataConnection) {
|
||||
mDataConnection = new mozilla::DataChannelConnection(this);
|
||||
if(!mDataConnection->Init(port, numstreams, false)) {
|
||||
CSFLogError(logTag,"%s DataConnection Init Failed",__FUNCTION__);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
listenPort = port;
|
||||
PR_CreateThread(
|
||||
PR_SYSTEM_THREAD,
|
||||
PeerConnectionImpl::ListenThread, this,
|
||||
PR_PRIORITY_NORMAL,
|
||||
PR_GLOBAL_THREAD,
|
||||
PR_JOINABLE_THREAD, 0
|
||||
);
|
||||
|
||||
CSFLogDebugS(logTag, __FUNCTION__ << ": returned");;
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// XXX Temporary - remove
|
||||
void
|
||||
PeerConnectionImpl::ListenThread(void *aData)
|
||||
{
|
||||
MOZ_ASSERT(aData);
|
||||
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
sipcc::PeerConnectionImpl *ctx = static_cast<sipcc::PeerConnectionImpl*>(aData);
|
||||
|
||||
ctx->mDataConnection->Listen(ctx->listenPort);
|
||||
#endif
|
||||
CSFLogDebugS(logTag, __FUNCTION__ << ": finished");
|
||||
}
|
||||
|
||||
// XXX Temporary - remove
|
||||
NS_IMETHODIMP
|
||||
PeerConnectionImpl::Connect(const nsAString &addr, PRUint16 localport, PRUint16 remoteport, PRUint16 numstreams)
|
||||
{
|
||||
CSFLogDebugS(logTag, __FUNCTION__);
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
char *s = ToNewCString(addr);
|
||||
if (!mDataConnection) {
|
||||
mDataConnection = new mozilla::DataChannelConnection(this);
|
||||
if(!mDataConnection->Init(localport, numstreams, false))
|
||||
{
|
||||
CSFLogError(logTag,"%s DataConnection Init Failed",__FUNCTION__);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
connectStr = s;
|
||||
connectPort = remoteport;
|
||||
PR_CreateThread(
|
||||
PR_SYSTEM_THREAD,
|
||||
PeerConnectionImpl::ConnectThread, this,
|
||||
PR_PRIORITY_NORMAL,
|
||||
PR_GLOBAL_THREAD,
|
||||
PR_JOINABLE_THREAD, 0
|
||||
);
|
||||
|
||||
CSFLogDebugS(logTag, __FUNCTION__ << ": returned");;
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// XXX Temporary - remove
|
||||
void
|
||||
PeerConnectionImpl::ConnectThread(void *aData)
|
||||
{
|
||||
MOZ_ASSERT(aData);
|
||||
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
sipcc::PeerConnectionImpl *ctx = static_cast<sipcc::PeerConnectionImpl*>(aData);
|
||||
|
||||
ctx->mDataConnection->Connect(ctx->connectStr,ctx->connectPort);
|
||||
#endif
|
||||
CSFLogDebugS(logTag, __FUNCTION__ << ": finished");
|
||||
}
|
||||
|
||||
void
|
||||
PeerConnectionImpl::NotifyConnection()
|
||||
{
|
||||
@ -746,7 +601,7 @@ PeerConnectionImpl::NotifyDataChannel(mozilla::DataChannel *aChannel)
|
||||
nsCOMPtr<nsIDOMDataChannel> domchannel;
|
||||
nsresult rv = NS_NewDOMDataChannel(aChannel, mWindow,
|
||||
getter_AddRefs(domchannel));
|
||||
NS_ENSURE_SUCCESS(rv,/**/);
|
||||
NS_ENSURE_SUCCESS(rv,);
|
||||
if (mPCObserver) {
|
||||
PeerConnectionObserverDispatch* runnable =
|
||||
new PeerConnectionObserverDispatch(PC_OBSERVER_DATACHANNEL, domchannel.get(),
|
||||
@ -914,13 +769,14 @@ PeerConnectionImpl::CloseStreams() {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
NS_IMETHODIMP
|
||||
PeerConnectionImpl::SetRemoteFingerprint(const char* hash, const char* fingerprint)
|
||||
{
|
||||
MOZ_ASSERT(hash);
|
||||
MOZ_ASSERT(fingerprint);
|
||||
|
||||
if (fingerprint != NULL && (strcmp(hash, "sha-256") == 0)) {
|
||||
if (fingerprint != NULL && (strcmp(hash, "sha-1") == 0)) {
|
||||
mRemoteFingerprint = std::string(fingerprint);
|
||||
CSFLogDebugS(logTag, "Setting remote fingerprint to " << mRemoteFingerprint);
|
||||
return NS_OK;
|
||||
@ -930,10 +786,6 @@ PeerConnectionImpl::SetRemoteFingerprint(const char* hash, const char* fingerpri
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @fingerprint[out]: Ownership of this parameter
|
||||
* is responsibility of the caller.
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
PeerConnectionImpl::GetFingerprint(char** fingerprint)
|
||||
{
|
||||
@ -950,6 +802,7 @@ PeerConnectionImpl::GetFingerprint(char** fingerprint)
|
||||
*fingerprint = tmp;
|
||||
return NS_OK;
|
||||
}
|
||||
*/
|
||||
|
||||
NS_IMETHODIMP
|
||||
PeerConnectionImpl::GetLocalDescription(char** sdp)
|
||||
|
@ -6,6 +6,7 @@
|
||||
#define _PEER_CONNECTION_IMPL_H_
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <cmath>
|
||||
@ -366,6 +367,9 @@ public:
|
||||
// Get the DTLS identity
|
||||
mozilla::RefPtr<DtlsIdentity> const GetIdentity() { return mIdentity; }
|
||||
|
||||
// Create a fake media stream
|
||||
nsresult CreateFakeMediaStream(PRUint32 hint, nsIDOMMediaStream** retval);
|
||||
|
||||
private:
|
||||
PeerConnectionImpl(const PeerConnectionImpl&rhs);
|
||||
PeerConnectionImpl& operator=(PeerConnectionImpl);
|
||||
|
@ -164,6 +164,12 @@
|
||||
#define PROFILER_MODULE
|
||||
#endif
|
||||
|
||||
#if defined(MOZ_WEBRTC)
|
||||
#define PEERCONNECTION_MODULE MODULE(peerconnection)
|
||||
#else
|
||||
#define PEERCONNECTION_MODULE
|
||||
#endif
|
||||
|
||||
#define XUL_MODULES \
|
||||
MODULE(nsUConvModule) \
|
||||
MODULE(nsI18nModule) \
|
||||
@ -221,6 +227,7 @@
|
||||
MODULE(nsTelemetryModule) \
|
||||
MODULE(jsinspector) \
|
||||
MODULE(jsdebugger) \
|
||||
PEERCONNECTION_MODULE \
|
||||
/* end of list */
|
||||
|
||||
#define MODULE(_name) \
|
||||
|
Loading…
Reference in New Issue
Block a user