I'm trying to follow this example by Dan Ristic for RTCDataChannel
browser p2p communication with Google's Channel API for signaling. It seems to be failing silently - I can't get the RTCDataChannel.onopen
, RTCPeerConnection.onicecandidate
, or RTCPeerConnection.ondatachannel
events to fire.
<html>
<head>
<script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>
<script type="text/javascript" src="/_ah/channel/jsapi"></script>
<script>
$(document).ready(function(){
var IS_CHROME = !!window.webkitRTCPeerConnection,
RTCPeerConnection = window.webkitRTCPeerConnection || mozRTCPeerConnection,
RTCIceCandidate = window.RTCIceCandidate || RTCSessionDescription,
RTCSessionDescription = window.RTCSessionDescription || mozRTCSessionDescription,
SESSION_ID = "12345",
weAreHost,
optionalRtpDataChannels = {
optional: [{RtpDataChannels: true}]
},
mediaConstraints = {
optional: [],
mandatory: {
OfferToReceiveAudio: false, // Hmm!!
OfferToReceiveVideo: false // Hmm!!
}
};
// Signaling Channel Object
function SignalingChannel(peerConnection) {
// Setup the signaling channel here
this.peerConnection = peerConnection;
}
function setChannelEvents(dataChannel) {
dataChannel.onmessage = function (event) {
console.log("I got data channel message: ", event.data);
}
dataChannel.onopen = function (event) {
dataChannel.send("RTCDataChannel Open!");
}
dataChannel.error = function(event) {
console.log("data channel error:", event)
}
}
SignalingChannel.prototype.send = function(message) {
console.log("signal send:", message);
var url = "/api/signal/send/";
url += weAreHost ? "client"+SESSION_ID : "host"+SESSION_ID;
$.ajax({
type: "PUT",
url: url,
contentType: "application/json",
data: JSON.stringify(message)
});
};
SignalingChannel.prototype.onmessage = function(message) {
console.log("signal receive:", message);
// If we get a sdp we have to sign and return it
if (message.sdp != null) {
var that = this;
this.peerConnection.setRemoteDescription(new RTCSessionDescription(message), function () {
that.peerConnection.createAnswer(function (description) {
that.send(description);
}, null, mediaConstraints);
});
} else {
this.peerConnection.addIceCandidate(new RTCIceCandidate(message.candidate));
}
};
function initiateConnection(input) {
weAreHost = input;
// setup signaling mechanism with Google Channel API
var url = "/api/signal/init/";
url += weAreHost ? "host"+SESSION_ID : "client"+SESSION_ID;
$.post(url, "", function(response){
var channel = new goog.appengine.Channel(response.token);
var socket = channel.open();
socket.onerror = function(){console.log(arguments);};
socket.onclose = function(){console.log(arguments);};
var closeSocket = function() {
if(socket) return socket.close();
else return "google socket does not exist"
}
$(window).unload(closeSocket);
window.onbeforeunload = closeSocket;
socket.onopen = function() {
console.log("google socket opened");
// Create a peer connection object
var connection = new RTCPeerConnection({
iceServers: [
{ 'url': (IS_CHROME ? 'stun:stun.l.google.com:19302' : 'stun:23.21.150.121') }
]
}, optionalRtpDataChannels);
// Initiate a signaling channel between two users
var signalingChannel = new SignalingChannel(connection);
connection.onicecandidate = function (event) {
console.log("onicecandidate:", event);
if (!event || !event.candidate) return;
signalingChannel.send({candidate:event.candidate});
};
// Effectively set SignalingChannel as google channel socket inbound event handler
socket.onmessage = function(input) {
console.log("received from google:", input);
var message = $.parseJSON(input.data);
signalingChannel.onmessage(message);
};
// Only one client should initiate the connection, the other client should wait.
if(weAreHost) {
connection.ondatachannel = function(event) {
setChannelEvents(event.channel);
}
} else {
// Create client RTCDataChannel
var clientChannel = connection.createDataChannel("my_label", {reliable: false});
setChannelEvents(clientChannel);
connection.createOffer(function (description) {
signalingChannel.send(description);
}, function(error){
console.log(error);
}, mediaConstraints);
}
};
}, "json");
};
// Create a button on the page so only one client initiates the connection.
$("#i-am-host").click(function() {
initiateConnection(true);
});
$("#i-am-client").click(function() {
initiateConnection(false);
});
});
</script>
</head>
<body>
<p id="i-am-host" style="background-color: green;">I AM HOST</p>
<p id="i-am-client" style="background-color: blue;">I AM CLIENT</p>
</body>
</html>
from google.appengine.api import channel
from django.shortcuts import render
from django.http import HttpResponse
import json
def init(request, browser_id):
token = channel.create_channel(browser_id);
return HttpResponse(json.dumps({'token':token}))
def send(request, browser_id):
channel.send_message(browser_id, request.body)
return HttpResponse()
[HOST]
received from google:
Object {data: "{"sdp":"v=0\r\no=- 6804947085651458452 2 IN IP4 12…5000 webrtc-datachannel 1024\r\n","type":"offer"}"}
test.html:34
signal receive:
Object {sdp: "v=0
↵o=- 6804947085651458452 2 IN IP4 127.0.0.1
↵s…id:data
↵a=sctpmap:5000 webrtc-datachannel 1024
↵", type: "offer"}
test.html:22
signal send:
RTCSessionDescription {sdp: "v=0
↵o=- 600524556593905006 2 IN IP4 127.0.0.1
↵s=…id:data
↵a=sctpmap:5000 webrtc-datachannel 1024
↵", type: "answer"}
[CLIENT]
signal send:
RTCSessionDescription {sdp: "v=0
↵o=- 6804947085651458452 2 IN IP4 127.0.0.1
↵s…id:data
↵a=sctpmap:5000 webrtc-datachannel 1024
↵", type: "offer"}
test.html:82
received from google:
Object {data: "{"sdp":"v=0\r\no=- 600524556593905006 2 IN IP4 127…000 webrtc-datachannel 1024\r\n","type":"answer"}"}
test.html:34
signal receive: Object {sdp: "v=0
↵o=- 600524556593905006 2 IN IP4 127.0.0.1
↵s=…id:data
↵a=sctpmap:5000 webrtc-datachannel 1024
↵", type: "answer"}
Firefox does not (and never will) support RtpDataChannels. It only supports the spec-compliant (and more advanced) SCTP datachannels. Removing the optional constraint should switch you over to them without requiring other changes.
It is somewhat odd that your SDP appears to have sctp lines in it. The google sample at http://googlechrome.github.io/webrtc/samples/web/content/datachannel/ does not when using rtp data channels.