Bug 798825: Add DataChannel DOM interfaces to RTCPeerConnection; r=smaug

This commit is contained in:
Anant Narayanan 2012-10-07 01:34:30 -04:00
Родитель dd86d9ae3a
Коммит be9228b287
5 изменённых файлов: 218 добавлений и 65 удалений

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

@ -146,6 +146,11 @@ function PeerConnection() {
this.onstatechange = null;
this.ongatheringchange = null;
this.onicechange = null;
// Data channel.
this.ondatachannel = null;
this.onconnection = null;
this.onclosedconnection = null;
}
PeerConnection.prototype = {
classID: PC_CID,
@ -397,6 +402,42 @@ PeerConnection.prototype = {
args: [],
wait: false
});
},
createDataChannel: function(label, dict) {
if (dict &&
dict.maxRetransmitTime != undefined &&
dict.maxRetransmitNum != undefined) {
throw new Error("Both maxRetransmitTime and maxRetransmitNum cannot be provided");
}
// Must determine the type where we still know if entries are undefined.
let type;
if (dict.maxRetransmitTime != undefined) {
type = Ci.IPeerConnection.DATACHANNEL_PARTIAL_RELIABLE_TIMED;
} else if (dict.maxRetransmitNum != undefined) {
type = Ci.IPeerConnection.DATACHANNEL_PARTIAL_RELIABLE_REXMIT;
} else {
type = Ci.IPeerConnection.DATACHANNEL_RELIABLE;
}
// Synchronous since it doesn't block.
let channel = this._pc.createDataChannel(
label, type, dict.outOfOrderAllowed, dict.maxRetransmitTime,
dict.maxRetransmitNum
);
return channel;
},
connectDataConnection: function(localport, remoteport, numstreams) {
if (numstreams == undefined || numstreams <= 0) {
numstreams = 16;
}
this._queueOrRun({
func: this._pc.connectDataConnection,
args: [localport, remoteport, numstreams],
wait: false
});
}
};
@ -567,6 +608,33 @@ PeerConnectionObserver.prototype = {
} catch(e) {}
}
this._dompc._executeNext();
},
notifyDataChannel: function(channel) {
if (this._dompc.ondatachannel) {
try {
this._dompc.ondatachannel.onCallback(channel);
} catch(e) {}
}
this._dompc._executeNext();
},
notifyConnection: function() {
if (this._dompc.onconnection) {
try {
this._dompc.onconnection.onCallback();
} catch(e) {}
}
this._dompc._executeNext();
},
notifyClosedConnection: function() {
if (this._dompc.onclosedconnection) {
try {
this._dompc.onclosedconnection.onCallback();
} catch(e) {}
}
this._dompc._executeNext();
}
};

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

@ -2,6 +2,7 @@
#include "nsIDOMWindow.idl"
interface nsIDOMMediaStream;
interface nsIDOMDataChannel;
/* Do not confuse with nsIDOMRTCPeerConnection. This interface is purely for
* communication between the PeerConnection JS DOM binding and the C++
@ -9,7 +10,7 @@ interface nsIDOMMediaStream;
*
* See media/webrtc/signaling/include/PeerConnectionImpl.h
*/
[scriptable, uuid(84efc76f-41d9-496a-9444-2965d179d419)]
[scriptable, uuid(e61821ba-7772-4973-b583-1715e4bbaeed)]
interface IPeerConnectionObserver : nsISupports
{
/* Constants */
@ -28,6 +29,11 @@ interface IPeerConnectionObserver : nsISupports
void onSetLocalDescriptionError(in unsigned long code);
void onSetRemoteDescriptionError(in unsigned long code);
/* Data channel callbacks */
void notifyDataChannel(in nsIDOMDataChannel channel);
void notifyConnection();
void notifyClosedConnection();
/* Notification of one of several types of state changed */
void onStateChange(in unsigned long state);
@ -45,7 +51,7 @@ interface IPeerConnectionObserver : nsISupports
void foundIceCandidate(in string candidate);
};
[scriptable, uuid(942366a9-80fe-4cac-ac97-4fbca45bcbff)]
[scriptable, uuid(cb3f0048-1009-11e2-b822-87ee49eface7)]
interface IPeerConnection : nsISupports
{
const unsigned long kHintAudio = 0x00000001;
@ -94,4 +100,11 @@ interface IPeerConnection : nsISupports
readonly attribute unsigned long iceState;
readonly attribute unsigned long readyState;
readonly attribute unsigned long sipccState;
/* Data channels */
nsIDOMDataChannel createDataChannel(in ACString label,
in unsigned short type, in boolean outOfOrderAllowed,
in unsigned short maxTime, in unsigned short maxNum);
void connectDataConnection(in unsigned short localport,
in unsigned short remoteport, in unsigned short numstreams);
};

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

@ -5,6 +5,8 @@
#include "nsISupports.idl"
#include "nsIDOMMediaStream.idl"
interface nsIDOMDataChannel;
[scriptable, function, uuid(eb9c563c-3b09-4565-9317-eca96ae0c538)]
interface RTCPeerConnectionCallback : nsISupports
{
@ -33,7 +35,7 @@ interface nsIDOMRTCIceCandidate : nsISupports
};
/* See http://dev.w3.org/2011/webrtc/editor/webrtc.html */
[scriptable, uuid(94628e70-e96f-4170-871c-f993a49f065a)]
[scriptable, uuid(807b9b54-25a1-421e-9133-27ae6efcfcfd)]
interface nsIDOMRTCPeerConnection : nsISupports
{
void createOffer(in RTCPeerConnectionCallback successCallback,
@ -84,4 +86,13 @@ interface nsIDOMRTCPeerConnection : nsISupports
attribute RTCPeerConnectionCallback onstatechange;
attribute RTCPeerConnectionCallback ongatheringchange;
attribute RTCPeerConnectionCallback onicechange;
/* Data channels */
nsIDOMDataChannel createDataChannel([optional] in ACString label,
[optional] in jsval options);
void connectDataConnection(in unsigned short localport,
in unsigned short remoteport, [optional] in unsigned short numstreams);
attribute RTCPeerConnectionCallback ondatachannel;
attribute RTCPeerConnectionCallbackVoid onconnection;
attribute RTCPeerConnectionCallbackVoid onclosedconnection;
};

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

@ -66,21 +66,21 @@ typedef enum {
class PeerConnectionObserverDispatch : public nsRunnable {
public:
PeerConnectionObserverDispatch(CSF::CC_CallInfoPtr info,
nsRefPtr<PeerConnectionImpl> pc,
IPeerConnectionObserver* observer) :
mType(PC_OBSERVER_CALLBACK), mInfo(info), mChannel(nullptr), mPC(pc), mObserver(observer) {}
PeerConnectionObserverDispatch(CSF::CC_CallInfoPtr aInfo,
nsRefPtr<PeerConnectionImpl> aPC,
IPeerConnectionObserver* aObserver) :
mType(PC_OBSERVER_CALLBACK), mInfo(aInfo), mChannel(nullptr), mPC(aPC), mObserver(aObserver) {}
PeerConnectionObserverDispatch(PeerConnectionObserverType type,
nsRefPtr<nsIDOMDataChannel> channel,
nsRefPtr<PeerConnectionImpl> pc,
IPeerConnectionObserver* observer) :
mType(type), mInfo(nullptr), mChannel(channel), mPC(pc), mObserver(observer) {}
PeerConnectionObserverDispatch(PeerConnectionObserverType aType,
nsRefPtr<nsIDOMDataChannel> aChannel,
nsRefPtr<PeerConnectionImpl> aPC,
IPeerConnectionObserver* aObserver) :
mType(aType), mInfo(nullptr), mChannel(aChannel), mPC(aPC), mObserver(aObserver) {}
PeerConnectionObserverDispatch(PeerConnectionObserverType type,
nsRefPtr<PeerConnectionImpl> pc,
IPeerConnectionObserver* observer) :
mType(type), mInfo(nullptr), mPC(pc), mObserver(observer) {}
PeerConnectionObserverDispatch(PeerConnectionObserverType aType,
nsRefPtr<PeerConnectionImpl> aPC,
IPeerConnectionObserver* aObserver) :
mType(aType), mInfo(nullptr), mPC(aPC), mObserver(aObserver) {}
~PeerConnectionObserverDispatch(){}
@ -173,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
@ -362,11 +362,11 @@ PeerConnectionImpl::CreateRemoteSourceStreamInfo(PRUint32 aHint, RemoteSourceStr
}
NS_IMETHODIMP
PeerConnectionImpl::Initialize(IPeerConnectionObserver* observer,
PeerConnectionImpl::Initialize(IPeerConnectionObserver* aObserver,
nsIDOMWindow* aWindow,
nsIThread* thread) {
MOZ_ASSERT(observer);
mPCObserver = observer;
nsIThread* aThread) {
MOZ_ASSERT(aObserver);
mPCObserver = aObserver;
#ifdef MOZILLA_INTERNAL_API
// Currently no standalone unit tests for DataChannel,
@ -377,7 +377,7 @@ PeerConnectionImpl::Initialize(IPeerConnectionObserver* observer,
#endif
// The thread parameter can be passed in as NULL
mThread = thread;
mThread = aThread;
PeerConnectionCtx *pcctx = PeerConnectionCtx::GetInstance();
MOZ_ASSERT(pcctx);
@ -509,24 +509,24 @@ PeerConnectionImpl::Initialize(IPeerConnectionObserver* observer,
}
nsresult
PeerConnectionImpl::CreateFakeMediaStream(PRUint32 hint, nsIDOMMediaStream** retval)
PeerConnectionImpl::CreateFakeMediaStream(PRUint32 aHint, nsIDOMMediaStream** aRetval)
{
MOZ_ASSERT(retval);
MOZ_ASSERT(aRetval);
bool mute = false;
// Hack to allow you to mute the stream
if (hint & MEDIA_STREAM_MUTE) {
if (aHint & MEDIA_STREAM_MUTE) {
mute = true;
hint &= ~MEDIA_STREAM_MUTE;
aHint &= ~MEDIA_STREAM_MUTE;
}
nsresult res;
if (!mThread || NS_IsMainThread()) {
res = MakeMediaStream(hint, retval);
res = MakeMediaStream(aHint, aRetval);
} else {
mThread->Dispatch(WrapRunnableRet(
this, &PeerConnectionImpl::MakeMediaStream, hint, retval, &res
this, &PeerConnectionImpl::MakeMediaStream, aHint, aRetval, &res
), NS_DISPATCH_SYNC);
}
@ -535,11 +535,11 @@ PeerConnectionImpl::CreateFakeMediaStream(PRUint32 hint, nsIDOMMediaStream** ret
}
if (!mute) {
if (hint & nsDOMMediaStream::HINT_CONTENTS_AUDIO) {
new Fake_AudioGenerator(static_cast<nsDOMMediaStream*>(*retval));
if (aHint & nsDOMMediaStream::HINT_CONTENTS_AUDIO) {
new Fake_AudioGenerator(static_cast<nsDOMMediaStream*>(*aRetval));
} else {
#ifdef MOZILLA_INTERNAL_API
new Fake_VideoGenerator(static_cast<nsDOMMediaStream*>(*retval));
new Fake_VideoGenerator(static_cast<nsDOMMediaStream*>(*aRetval));
#endif
}
}
@ -547,6 +547,67 @@ PeerConnectionImpl::CreateFakeMediaStream(PRUint32 hint, nsIDOMMediaStream** ret
return NS_OK;
}
// Data channels won't work without a window, so in order for the C++ unit
// tests to work (it doesn't have a window available) we ifdef the following
// two implementations.
NS_IMETHODIMP
PeerConnectionImpl::ConnectDataConnection(PRUint16 aLocalport,
PRUint16 aRemoteport,
PRUint16 aNumstreams)
{
#ifdef MOZILLA_INTERNAL_API
mDataConnection = new mozilla::DataChannelConnection(this);
NS_ENSURE_TRUE(mDataConnection,NS_ERROR_FAILURE);
if (!mDataConnection->Init(aLocalport, aNumstreams, true)) {
CSFLogError(logTag,"%s DataConnection Init Failed",__FUNCTION__);
return NS_ERROR_FAILURE;
}
// XXX Fix! Get the correct flow for DataChannel. Also error handling.
nsRefPtr<TransportFlow> flow = GetTransportFlow(1,false).get();
CSFLogDebugS(logTag, "Transportflow[1] = " << flow.get());
if (!mDataConnection->ConnectDTLS(flow, aLocalport, aRemoteport)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
#else
return NS_ERROR_FAILURE;
#endif
}
NS_IMETHODIMP
PeerConnectionImpl::CreateDataChannel(const nsACString& aLabel,
PRUint16 aType,
bool outOfOrderAllowed,
PRUint16 aMaxTime,
PRUint16 aMaxNum,
nsIDOMDataChannel** aRetval)
{
MOZ_ASSERT(aRetval);
#ifdef MOZILLA_INTERNAL_API
mozilla::DataChannel* dataChannel;
mozilla::DataChannelConnection::Type theType =
static_cast<mozilla::DataChannelConnection::Type>(aType);
if (!mDataConnection) {
return NS_ERROR_FAILURE;
}
dataChannel = mDataConnection->Open(
aLabel, theType, !outOfOrderAllowed,
aType == mozilla::DataChannelConnection::PARTIAL_RELIABLE_REXMIT ? aMaxNum :
(aType == mozilla::DataChannelConnection::PARTIAL_RELIABLE_TIMED ? aMaxTime : 0),
nullptr, nullptr
);
NS_ENSURE_TRUE(dataChannel,NS_ERROR_FAILURE);
CSFLogDebugS(logTag, __FUNCTION__ << ": making DOMDataChannel");
return NS_NewDOMDataChannel(dataChannel, mWindow, aRetval);
#else
return NS_OK;
#endif
}
void
PeerConnectionImpl::NotifyConnection()
{
@ -619,42 +680,42 @@ PeerConnectionImpl::NotifyDataChannel(mozilla::DataChannel *aChannel)
* CC_SDP_DIRECTION_SENDRECV will not be used when Constraints are implemented
*/
NS_IMETHODIMP
PeerConnectionImpl::CreateOffer(const char* hints) {
MOZ_ASSERT(hints);
PeerConnectionImpl::CreateOffer(const char* aHints) {
MOZ_ASSERT(aHints);
CheckIceState();
mRole = kRoleOfferer; // TODO(ekr@rtfm.com): Interrogate SIPCC here?
mCall->createOffer(hints);
mCall->createOffer(aHints);
return NS_OK;
}
NS_IMETHODIMP
PeerConnectionImpl::CreateAnswer(const char* hints, const char* offer) {
MOZ_ASSERT(hints);
MOZ_ASSERT(offer);
PeerConnectionImpl::CreateAnswer(const char* aHints, const char* aOffer) {
MOZ_ASSERT(aHints);
MOZ_ASSERT(aOffer);
CheckIceState();
mRole = kRoleAnswerer; // TODO(ekr@rtfm.com): Interrogate SIPCC here?
mCall->createAnswer(hints, offer);
mCall->createAnswer(aHints, aOffer);
return NS_OK;
}
NS_IMETHODIMP
PeerConnectionImpl::SetLocalDescription(PRInt32 action, const char* sdp) {
MOZ_ASSERT(sdp);
PeerConnectionImpl::SetLocalDescription(PRInt32 aAction, const char* aSDP) {
MOZ_ASSERT(aSDP);
CheckIceState();
mLocalRequestedSDP = sdp;
mCall->setLocalDescription((cc_jsep_action_t)action, mLocalRequestedSDP);
mLocalRequestedSDP = aSDP;
mCall->setLocalDescription((cc_jsep_action_t)aAction, mLocalRequestedSDP);
return NS_OK;
}
NS_IMETHODIMP
PeerConnectionImpl::SetRemoteDescription(PRInt32 action, const char* sdp) {
MOZ_ASSERT(sdp);
PeerConnectionImpl::SetRemoteDescription(PRInt32 action, const char* aSDP) {
MOZ_ASSERT(aSDP);
CheckIceState();
mRemoteRequestedSDP = sdp;
mRemoteRequestedSDP = aSDP;
mCall->setRemoteDescription((cc_jsep_action_t)action, mRemoteRequestedSDP);
return NS_OK;
}
@ -753,9 +814,9 @@ PeerConnectionImpl::RemoveStream(nsIDOMMediaStream* aMediaStream)
}
NS_IMETHODIMP
PeerConnectionImpl::AddIceCandidate(const char* candidate, const char* mid, unsigned short level) {
PeerConnectionImpl::AddIceCandidate(const char* aCandidate, const char* aMid, unsigned short aLevel) {
CheckIceState();
mCall->addICECandidate(candidate, mid, level);
mCall->addICECandidate(aCandidate, aMid, aLevel);
return NS_OK;
}
@ -805,56 +866,56 @@ PeerConnectionImpl::GetFingerprint(char** fingerprint)
*/
NS_IMETHODIMP
PeerConnectionImpl::GetLocalDescription(char** sdp)
PeerConnectionImpl::GetLocalDescription(char** aSDP)
{
MOZ_ASSERT(sdp);
MOZ_ASSERT(aSDP);
char* tmp = new char[mLocalSDP.size() + 1];
std::copy(mLocalSDP.begin(), mLocalSDP.end(), tmp);
tmp[mLocalSDP.size()] = '\0';
*sdp = tmp;
*aSDP = tmp;
return NS_OK;
}
NS_IMETHODIMP
PeerConnectionImpl::GetRemoteDescription(char** sdp)
PeerConnectionImpl::GetRemoteDescription(char** aSDP)
{
MOZ_ASSERT(sdp);
MOZ_ASSERT(aSDP);
char* tmp = new char[mRemoteSDP.size() + 1];
std::copy(mRemoteSDP.begin(), mRemoteSDP.end(), tmp);
tmp[mRemoteSDP.size()] = '\0';
*sdp = tmp;
*aSDP = tmp;
return NS_OK;
}
NS_IMETHODIMP
PeerConnectionImpl::GetReadyState(PRUint32* state)
PeerConnectionImpl::GetReadyState(PRUint32* aState)
{
MOZ_ASSERT(state);
MOZ_ASSERT(aState);
*state = mReadyState;
*aState = mReadyState;
return NS_OK;
}
NS_IMETHODIMP
PeerConnectionImpl::GetSipccState(PRUint32* state)
PeerConnectionImpl::GetSipccState(PRUint32* aState)
{
MOZ_ASSERT(state);
MOZ_ASSERT(aState);
PeerConnectionCtx* pcctx = PeerConnectionCtx::GetInstance();
*state = pcctx ? pcctx->sipcc_state() : kIdle;
*aState = pcctx ? pcctx->sipcc_state() : kIdle;
return NS_OK;
}
NS_IMETHODIMP
PeerConnectionImpl::GetIceState(PRUint32* state)
PeerConnectionImpl::GetIceState(PRUint32* aState)
{
MOZ_ASSERT(state);
MOZ_ASSERT(aState);
*state = mIceState;
*aState = mIceState;
return NS_OK;
}

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

@ -1178,7 +1178,7 @@ DataChannelConnection::HandleAssociationChangeEvent(const struct sctp_assoc_chan
LOG(("Association change: streams (in/out) = (%u/%u)",
sac->sac_inbound_streams, sac->sac_outbound_streams));
NS_ENSURE_TRUE(sizeof(*sac) >= sac->sac_length, /* */);
NS_ENSURE_TRUE_VOID(sac);
n = sac->sac_length - sizeof(*sac);
if (((sac->sac_state == SCTP_COMM_UP) ||
(sac->sac_state == SCTP_RESTART)) && (n > 0)) {