带有Google Channel API的RTCDataChannel

时间:2015-01-30 00:45:03

标签: javascript google-app-engine webrtc channel-api rtcdatachannel

我尝试关注this example by Dan Ristic RTCDataChannel与Google Channel API进行RTCDataChannel.onopen浏览器p2p通信,以发送信号。它似乎在默默地失败 - 我无法触发RTCPeerConnection.onicecandidateRTCPeerConnection.ondatachannel<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> 事件。

客户端JS / 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()

App Engine Python:

[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"}

浏览器控制台:

{{1}}

3 个答案:

答案 0 :(得分:4)

Firefox不支持(也绝不会)支持RtpDataChannels。它仅支持符合规范(和更高级)的SCTP数据通道。删除可选约束应该将您切换到它们而不需要进行其他更改。

您的SDP似乎有sctp线,这有点奇怪。 http://googlechrome.github.io/webrtc/samples/web/content/datachannel/上的Google示例 使用rtp数据通道时不会。

答案 1 :(得分:1)

对于初学者,您在数据通道创建的另一侧缺少peerConnection.onDataChannel

代码如下:

answerer.ondatachannel = function (event) {
        answererDataChannel = event.channel;
        answererDataChannel.binaryType = 'blob';
        setChannelEvents(answererDataChannel, 'answerer');
    };

...


function setChannelEvents(channel, channelNameForConsoleOutput) {
    channel.onmessage = function (event) {
        console.debug(channelNameForConsoleOutput, 'received a message:', event.data);
    };
    channel.onopen = function () {
        channel.send('first text message over SCTP data ports');
    };
}

完整代码,您可以查看此link

答案 2 :(得分:0)

经过几个小时的尝试,我能够将我的原始示例用于Chrome 40.0.2214.93和Opera 27.0(撰写本文时的最新版本)。 why doesn't “onicecandidate” work?帮了很多忙。我没有运气在Firefox上工作:

<html>
<head>
<script src="https://code.jquery.com/jquery-2.1.3.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 = "123456",
            weAreHost,
            optionalRtpDataChannels = {
                optional: [{RtpDataChannels: true}]
            },
            mediaConstraints = {
                    optional: [],
                    mandatory: {
                        OfferToReceiveAudio: false,
                        OfferToReceiveVideo: false
                    }
                };

        // 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("######### SUCCESS ######### RTCDataChannel Open!");
            }

            dataChannel.error = function(event) {
                console.log("data channel error:", event)
            }
        }

        function error(e) {
            console.log(arguments);
            throw new Error(e);
        }

        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);          
            var self = this;

            if(message.type && message.type === "offer") {
                var offer = new RTCSessionDescription(message);
                this.peerConnection.setRemoteDescription(offer, function() {
                    self.peerConnection.createAnswer(function(answer) {
                        self.peerConnection.setLocalDescription(answer, function() {
                            self.send(answer);
                        }, error);
                    }, error, mediaConstraints);
                });
            } else if(message.type && message.type === "answer") {
                var answer = new RTCSessionDescription(message);
                this.peerConnection.setRemoteDescription(answer, function(){            
                }, error);
            } 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 = error;

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

                        // create offer and send to host
                        connection.createOffer(function (offer) {                           
                            connection.setLocalDescription(offer, function() {                          
                                signalingChannel.send(offer);
                            }, error);
                        }, error, mediaConstraints);
                    }           
                };
            }, "json").fail(error);
        };

        // 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>
    <br>
    <p id="print">PRINT SIGNALING STATE<p>
</body>
</html>

我决定和PeerJS一起使用免费的Heroku服务器进行信号传输。在我看来,WebRTC现在太不稳定,无法直接使用。以下适用于Chrome / FF / Opera:

<html>
<head>
<script src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
<script src="http://cdn.peerjs.com/0.3.9/peer.js"></script>
<script>
    $(document).ready(function(){

        var SESSION_ID = "1234";

        // Create a button on the page so only one client initiates the connection.         
        $("#i-am-host").click(function() {

            var host = new Peer('host'+SESSION_ID, {host: 'my-peerjs.herokuapp.com', port: 80});
            host.on("connection", function(conn) {
                conn.on('data', function(data) {
                    console.log(data);
                });
            });

        });
        $("#i-am-client").click(function() {

            var client = new Peer('client'+SESSION_ID, {host: 'my-peerjs.herokuapp.com', port: 80});
            var conn = client.connect('host'+SESSION_ID);
            conn.on("open", function(){
                conn.send("SUCCESS!!");
            });     
        });
    });
</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>