【问题标题】:Working Hello World WebRTC DataChannel Examples with Signaling Implemented已实现信令的工作 Hello World WebRTC 数据通道示例
【发布时间】:2015-11-17 07:20:06
【问题描述】:

其目的是使其成为Community Wiki 帖子并保持最新状态,以便有兴趣使用 WebRTC 数据通道实现浏览器到浏览器 (p2p) 的 JSON 消息通信的开发人员拥有简单但实用的示例。

WebRTC 数据通道处于试验阶段,仍处于草稿阶段。目前,网络似乎是过时 WebRTC 示例的雷区,如果开发人员正在尝试学习 RTCDataChannel API,则更是如此。

现在在 WebRTC compliant browsers 上运行的简单但功能强大的 1 页示例似乎很难找到。例如,some examples 省略了信号实现,others 仅适用于单个浏览器(例如 Chrome-Chrome),many 由于最近的 API 更改而过时,others 非常复杂以至于造成了障碍开始吧。

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

  1. 客户端代码为 1 页(200 行或更少)
  2. 服务器端代码为 1 页,并引用了技术(例如 node.js、php、python 等)
  3. 实现了信令机制,引用了协议技术(如WebSockets、long pollingGCM等)
  4. 跨浏览器(Chrome、Firefox、Opera 和/或Bowser)运行的工作代码
  5. 最小选项、错误处理、abstraction 等 -- 意图是一个基本示例

【问题讨论】:

    标签: javascript webrtc p2p rtcdatachannel


    【解决方案1】:

    这是一个使用 HTML5 WebSockets 发送信号和一个 node.js 后端的工作示例

    信令技术:WebSockets
    客户:pure html/javascript
    服务器:node.js, ws
    最后测试:Firefox 40.0.2Chrome 44.0.2403.157 mOpera 31.0.1889.174


    客户端代码:

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

    服务器端代码:

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

    【讨论】:

    • 收到错误 WebSocket 已处于 CLOSING 或 CLOSED 状态
    • 收到错误 WebSocket 已处于 CLOSING 或 CLOSED 状态。在这行代码上你能告诉我为什么 websocket.send(JSON.stringify({ inst: 'init', id: ourId }));我是 websockets 的新手,wrtc 创建了两个两个文件,一个是前端服务器,一个 html 文件用于客户端,并在两个不同的浏览器中打开。
    • 阅读您的答案后,我比阅读规范和大量标题列表后更了解 webrtc,谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-12
    • 1970-01-01
    • 2018-09-03
    • 1970-01-01
    • 2019-07-25
    • 1970-01-01
    相关资源
    最近更新 更多