使用信令实现Hello World WebRTC DataChannel示例 [英] Working Hello World WebRTC DataChannel Examples with Signaling Implemented

查看:128
本文介绍了使用信令实现Hello World WebRTC DataChannel示例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目的是成为社区Wiki 帖子,保持最新,因此对使用WebRTC DataChannel实现JSON消息浏览器到浏览器(p2p)的通信感兴趣的开发人员有简单而实用的示例。



WebRTC DataChannels是实验性的,仍在选秀中。目前网络似乎是过时的WebRTC示例的雷区,如果开发人员正在尝试学习RTCDataChannel API,那就更是如此。



简单而实用的1页示例今天在WebRTC 兼容的浏览器上工作似乎很难找到。例如,一些示例忽略了信号实现,其他仅适用于单个浏览器(例如Chrome-Chrome),很多已过时,其他如此复杂,它们为入门创造了障碍。



请发布符合以下条件的示例(如果是不符合请注明):


  1. 客户端代码为1页(200行或更少)

  2. 服务器端代码为1页,引用了技术(例如node.js,php,python等)。

  3. 实现了信令机制并引用了协议技术(例如WebSockets,长轮询 GCM 等。)

  4. 跨浏览器运行的代码(Chrome,Firefox,Opera和/或 Bowser

  5. 最小选项,错误处理, abstraction 等 - 意图是一个基本的例子


解决方案

这是一个使用HTML5 WebSockets进行信令和node.js后端的工作示例



<信令技术: WebSockets

客户端:纯html / javascript

服务器: node.js ws

最后一次测试: Firefox 40.0.2 Chrome 44.0.2403.157 m Opera 31.0.1889.174






客户端代码:

 < html> 
< head>
< / head>
< body>
< p id ='msg'>在其他浏览器中点击以下内容windows< / p>
< button type ='button'onclick ='init(false)'>我是Answerer Peer(点击第一个)< / button>
< button type ='button 'onclick ='init(true)'> I AM Offerer Peer< / button>

< script>
(function(){
var offererId ='Gandalf', //注意:客户端ID冲突可能发生
answererId ='Saruman',//没有websocket清理代码存在
ourId,peerId,
RTC_IS_MOZILLA = !! window.mozRTCPeerConnection,
RTCPeerConnection = window.RTCPeerConnection || window.webkitRTCPeerConnection || window.mozRTCPeerConnection || window.msRTCPeerConnection,
RTCSessionDescription = window.RTCSessionDescription || window.mozRTCSessionDescription || window.msRTCSessionDescription,
RTCIceCandidate = window.RTCIceCandidate || window.mozRTCIceCandidate || window.msRTCIceCandidate,
rtcpeerconn = new RTCPeerConnection(
{iceServers:[{'url':'stun:stun.services.mozilla.com'},{'url':'stun:stun.l .google.com:19302'}]},
{可选:[{RtpDataChannels:false}]}
),
rtcdatachannel,
websocket = new WebSocket('ws: //'+ window.location.hostname +':8000'),
comready,onerror;

window.init = function(weAreOfferer){
ourId = weAreOfferer? offererId:answererId;
peerId = weAreOfferer? answererId:offererId;

websocket.send(JSON.stringify({
inst:'init',
id:ourId
}));

if(weAreOfferer){

rtcdatachannel = rtcpeerconn.createDataChannel(offererId + answererId);
rtcdatachannel.onopen = comready;
rtcdatachannel.onerror = onerror;

rtcpeerconn.createOffer(function(offer){
rtcpeerconn.setLocalDescription(offer,function(){
var output = offer.toJSON();
if(b) typeof output ==='string')output = JSON.parse(output); // normalize:RTCSessionDescription.toJSON返回FF中的json str,但Chrome中的json obj

websocket.send(JSON) .stringify({
inst:'send',
peerId:peerId,
message:output
}));
},onerror);
},onerror);
}
};

rtcpeerconn.ondatachannel = function(event){
rtcdatachannel = event.channel;
rtcdatachannel.onopen = comready;
rtcdatachannel.onerror = onerror;
};

websocket.onmessage = function(输入){
var message = JSON.parse(input.data);

if(message.type && message.type ==='offer'){
var offer = new RTCSessionDescription(message);

rtcpeerconn.setRemoteDescription(offer,function(){
rtcpeerconn.createAnswer(function(answer){
rtcpeerconn.setLocalDescription(answer,function(){
var output = answer.toJSON();
if(typeof output ==='string')output = JSON.parse(output); // normalize:RTCSessionDescription.toJSON返回FF中的json str,但是json obj in Chrome

websocket.send(JSON.stringify({
inst:'send',
peerId:peerId,
message:output
})) ;
},onerror);
},onerror);
},onerror);
} else if(message.type && message.type ==='answer'){
var answer = new RTCSessionDescription(message);
rtcpeerconn.setRemoteDescription(answer,function(){/ *处理程序需要但我们无关* /},onerror);
}否则if(rtcpeerconn.remoteDescription){
//忽略冰候选者,直到远程描述被设置为
rtcpeerconn.addIceCandidate(new RTCIceCandidate(message.candidate));
}
};

rtcpeerconn.onicecandidate = function(event){
if(!event ||!event.candidate)return;
websocket.send(JSON.stringify({
inst:'send',
peerId:peerId,
message:{candidate:event.candidate}
}) );
};当RTC信令完成且RTCDataChannel准备就绪时调用

/ ** * /
comready = function(){
rtcdatachannel.send('hello world!');
rtcdatachannel.onmessage = function(event){
document.getElementById('msg')。innerHTML ='RTCDataChannel peer'+ peerId +'say:'+ event.data;
}
};

/ **全局错误函数* /
onerror = websocket.onerror = function(e){
console.log('====== WEBRTC ERROR == ====',参数);
document.getElementById('msg')。innerHTML ='====== WEBRTC ERROR ======< br>'+ e;
抛出新错误(e);
};
})();
< / script>
< / body>
< / html>

服务器端代码:

  var server = require('http')。createServer(),
express = require('express'),
app = express(),
WebSocketServer = require('ws')。Server,
wss = new WebSocketServer({server:server,port:8000 });

app.use(express.static(__ dirname +'/ static')); //客户端代码进入静态目录

var clientMap = {};

wss.on('connection',function(ws){
ws.on('message',function(inputStr){
var input = JSON.parse(inputStr) );
if(input.inst =='init'){
clientMap [input.id] = ws;
} else if(input.inst =='send'){
clientMap [input.peerId] .send(JSON.stringify(input.message));
}
});
});

server.on('request',app);
server.listen(80,YOUR_HOSTNAME_OR_IP_HERE,function(){console.log('Listening on'+ server.address()。port)});


The intent is for this to become a Community Wiki post that is kept up-to-date so developers interested in implementing communication of JSON messages browser-to-browser (p2p) with WebRTC DataChannels have simple yet functional examples.

WebRTC DataChannels are experimental and still in draft. It seems that currently the web is a minefield of outdated WebRTC examples and even more so if a developer is trying to learn the RTCDataChannel API.

Simple yet functional 1-page examples that work today across WebRTC compliant browsers seem very difficult to find. For example, some examples leave out a signaling implementation, others only work for a single browser (e.g. Chrome-Chrome), many are outdated due to recent API changes, and others are so complex they create a barrier to getting started.

Please post examples that meet the following criteria (if something is not met please specify):

  1. Client-side code is 1-page (200 lines or less)
  2. Server-side code is 1-page and technology is referenced (e.g. node.js, php, python, etc.)
  3. Signaling mechanism is implemented and protocol technology is referenced (e.g. WebSockets, long polling, GCM, etc.)
  4. Working code that runs cross-browser (Chrome, Firefox, Opera, and/or Bowser)
  5. Minimal options, error handling, abstraction, etc. -- the intent is an elementary example

解决方案

Here is a working example that uses HTML5 WebSockets for signaling and a node.js backend

signaling technology: WebSockets
client: pure html/javascript
server: node.js, ws
last tested on: Firefox 40.0.2, Chrome 44.0.2403.157 m, Opera 31.0.1889.174


client-side code:

<html>
<head>
</head>
<body>
    <p id='msg'>Click the following in different browser windows</p>
    <button type='button' onclick='init(false)'>I AM Answerer Peer (click first)</button>
    <button type='button' onclick='init(true)'>I AM Offerer Peer</button>

<script>
    (function() {   
        var offererId = 'Gandalf',   // note: client id conflicts can happen
            answererId = 'Saruman',  //       no websocket cleanup code exists
            ourId, peerId,
            RTC_IS_MOZILLA = !!window.mozRTCPeerConnection,
            RTCPeerConnection = window.RTCPeerConnection || window.webkitRTCPeerConnection || window.mozRTCPeerConnection || window.msRTCPeerConnection,
            RTCSessionDescription = window.RTCSessionDescription || window.mozRTCSessionDescription || window.msRTCSessionDescription,
            RTCIceCandidate = window.RTCIceCandidate || window.mozRTCIceCandidate || window.msRTCIceCandidate,
            rtcpeerconn = new RTCPeerConnection(
                    {iceServers: [{ 'url': 'stun:stun.services.mozilla.com'}, {'url': 'stun:stun.l.google.com:19302'}]}, 
                    {optional: [{RtpDataChannels: false}]}
                ),
            rtcdatachannel, 
            websocket = new WebSocket('ws://' + window.location.hostname + ':8000'),
            comready, onerror;

        window.init = function(weAreOfferer) {
            ourId = weAreOfferer ? offererId : answererId;
            peerId = weAreOfferer ? answererId : offererId;

            websocket.send(JSON.stringify({
                inst: 'init', 
                id: ourId
            }));

            if(weAreOfferer) {

                rtcdatachannel = rtcpeerconn.createDataChannel(offererId+answererId);
                rtcdatachannel.onopen = comready;
                rtcdatachannel.onerror = onerror;

                rtcpeerconn.createOffer(function(offer) {
                    rtcpeerconn.setLocalDescription(offer, function() {
                        var output = offer.toJSON();
                        if(typeof output === 'string') output = JSON.parse(output); // normalize: RTCSessionDescription.toJSON returns a json str in FF, but json obj in Chrome

                        websocket.send(JSON.stringify({
                            inst: 'send', 
                            peerId: peerId, 
                            message: output
                        }));
                    }, onerror);
                }, onerror);
            }
        };

        rtcpeerconn.ondatachannel = function(event) {
            rtcdatachannel = event.channel;
            rtcdatachannel.onopen = comready;
            rtcdatachannel.onerror = onerror;
        };

        websocket.onmessage = function(input) {
            var message = JSON.parse(input.data);

            if(message.type && message.type === 'offer') {
                var offer = new RTCSessionDescription(message);

                rtcpeerconn.setRemoteDescription(offer, function() {
                    rtcpeerconn.createAnswer(function(answer) {
                        rtcpeerconn.setLocalDescription(answer, function() {
                            var output = answer.toJSON();
                            if(typeof output === 'string') output = JSON.parse(output); // normalize: RTCSessionDescription.toJSON returns a json str in FF, but json obj in Chrome

                            websocket.send(JSON.stringify({
                                inst: 'send',
                                peerId: peerId,
                                message: output
                            }));
                        }, onerror);
                    }, onerror);                
                }, onerror);
            } else if(message.type && message.type === 'answer') {              
                var answer = new RTCSessionDescription(message);
                rtcpeerconn.setRemoteDescription(answer, function() {/* handler required but we have nothing to do */}, onerror);
            } else if(rtcpeerconn.remoteDescription) {
                // ignore ice candidates until remote description is set
                rtcpeerconn.addIceCandidate(new RTCIceCandidate(message.candidate));
            }
        };

        rtcpeerconn.onicecandidate = function (event) {
            if (!event || !event.candidate) return;
            websocket.send(JSON.stringify({
                inst: 'send',
                peerId: peerId,
                message: {candidate: event.candidate}
            }));
        };

        /** called when RTC signaling is complete and RTCDataChannel is ready */
        comready = function() {
            rtcdatachannel.send('hello world!');
            rtcdatachannel.onmessage = function(event) {
                document.getElementById('msg').innerHTML = 'RTCDataChannel peer ' + peerId + ' says: ' + event.data;    
            }
        };

        /** global error function */
        onerror = websocket.onerror = function(e) {
            console.log('====== WEBRTC ERROR ======', arguments);
            document.getElementById('msg').innerHTML = '====== WEBRTC ERROR ======<br>' + e;
            throw new Error(e);
        };
    })();
</script>
</body>
</html>

server-side code:

var server = require('http').createServer(), 
    express = require('express'),    
    app = express(),
    WebSocketServer = require('ws').Server,
    wss = new WebSocketServer({ server: server, port: 8000 });

app.use(express.static(__dirname + '/static')); // client code goes in static directory

var clientMap = {};

wss.on('connection', function (ws) {
    ws.on('message', function (inputStr) {
        var input = JSON.parse(inputStr);
        if(input.inst == 'init') {
            clientMap[input.id] = ws;
        } else if(input.inst == 'send') {
            clientMap[input.peerId].send(JSON.stringify(input.message));
        }
    });
});

server.on('request', app);
server.listen(80, YOUR_HOSTNAME_OR_IP_HERE, function () { console.log('Listening on ' + server.address().port) });

这篇关于使用信令实现Hello World WebRTC DataChannel示例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆