不急不徐,持之以恒。

http://blog.gopersist.com/

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  24 随笔 :: 0 文章 :: 52 评论 :: 0 Trackbacks
在学习WebRTC时,网上的示例大多代码较多,以下是参考那些代码简化的一个WebRTC一对一的示例,在chrome 37下测试通过。其中iceServer可省略,没有iceServer时在同一个局域网下仍可通讯。

客户端代码:
<html>
<body>
    Local: <br>
    <video id="localVideo" autoplay></video><br>
    Remote: <br>
    <video id="remoteVideo" autoplay></video>

    <script>
        
// 仅仅用于控制哪一端的浏览器发起offer,#号后面有值的一方发起
        var isCaller = window.location.href.split('#')[1];

        
// 与信令服务器的WebSocket连接
        var socket = new WebSocket("ws://127.0.0.1:3000");

        
// stun和turn服务器
        var iceServer = {
            
"iceServers": [{
                
"url""stun:stun.l.google.com:19302"
            }, {
                
"url""turn:numb.viagenie.ca",
                
"username""webrtc@live.com",
                
"credential""muazkh"
            }]
        };

        
// 创建PeerConnection实例 (参数为null则没有iceserver,即使没有stunserver和turnserver,仍可在局域网下通讯)
        var pc = new webkitRTCPeerConnection(iceServer);

        
// 发送ICE候选到其他客户端
        pc.onicecandidate = function(event){
            
if (event.candidate !== null) {
                socket.send(JSON.stringify({
                    
"event""_ice_candidate",
                    
"data": {
                        
"candidate": event.candidate
                    }
                }));
            }
        };

        
// 如果检测到媒体流连接到本地,将其绑定到一个video标签上输出
        pc.onaddstream = function(event){
            document.getElementById('remoteVideo').src 
= URL.createObjectURL(event.stream);
        };

        
// 发送offer和answer的函数,发送本地session描述
        var sendOfferFn = function(desc){
            pc.setLocalDescription(desc);
            socket.send(JSON.stringify({ 
                
"event""_offer",
                
"data": {
                    
"sdp": desc
                }
            }));
        },
        sendAnswerFn 
= function(desc){
            pc.setLocalDescription(desc);
            socket.send(JSON.stringify({ 
                
"event""_answer",
                
"data": {
                    
"sdp": desc
                }
            }));
        };

        
// 获取本地音频和视频流
        navigator.webkitGetUserMedia({
            
"audio"true,
            
"video"true
        }, 
function(stream){
            
//绑定本地媒体流到video标签用于输出
            document.getElementById('localVideo').src = URL.createObjectURL(stream);
            
//向PeerConnection中加入需要发送的流
            pc.addStream(stream);
            
//如果是发起方则发送一个offer信令
            if(isCaller){
                pc.createOffer(sendOfferFn, 
function (error) {
                    console.log('Failure callback: ' 
+ error);
                });
            }
        }, 
function(error){
            
//处理媒体流创建失败错误
            console.log('getUserMedia error: ' + error);
        });

        
//处理到来的信令
        socket.onmessage = function(event){
            
var json = JSON.parse(event.data);
            console.log('onmessage: ', json);
            
//如果是一个ICE的候选,则将其加入到PeerConnection中,否则设定对方的session描述为传递过来的描述
            if( json.event === "_ice_candidate" ){
                pc.addIceCandidate(
new RTCIceCandidate(json.data.candidate));
            } 
else {
                pc.setRemoteDescription(
new RTCSessionDescription(json.data.sdp));
                
// 如果是一个offer,那么需要回复一个answer
                if(json.event === "_offer") {
                    pc.createAnswer(sendAnswerFn, 
function (error) {
                        console.log('Failure callback: ' 
+ error);
                    });
                }
            }
        };
    
</script>
</body>
</html>

实现WebRTC时,信令服务器是必须的,它帮助客户端之间进行沟通。
这里使用Node.js的ws模块来实现一个WebSocket服务作为信令服务器。另外使用express模块让它提供html页面的访问。
server.js代码如下:
var express = require('express'),
app = express(),
server = require('http').createServer(app);

server.listen(3000);

app.get('/', function(req, res) {
    res.sendfile(__dirname + '/webrtc.html');
});

var WebSocketServer = require('ws').Server,
wss = new WebSocketServer({server: server});

// 存储socket的数组,这里只能有2个socket,每次测试需要重启,否则会出错
var wsc = [],
index = 1;

// 有socket连入
wss.on('connection', function(ws) {
    console.log('connection');

    // 将socket存入数组
    wsc.push(ws);

    // 记下对方socket在数组中的下标,因为这个测试程序只允许2个socket
    // 所以第一个连入的socket存入0,第二个连入的就是存入1
    // otherIndex就反着来,第一个socket的otherIndex下标为1,第二个socket的otherIndex下标为0
    var otherIndex = index--,
    desc = null;

    if (otherIndex == 1) {
        desc = 'first socket';
    } else {
        desc = 'second socket';
    }

    // 转发收到的消息
    ws.on('message', function(message) {
        var json = JSON.parse(message);
        console.log('received (' + desc + '): ', json);

        wsc[otherIndex].send(message, function (error) {
            if (error) {
                console.log('Send message error (' + desc + '): ', error);
            }
        });
    });
});

使用npm安装需要的模块后使用node server.js启动服务。
测试时使用Chrome浏览器:
第一个浏览器窗口访问页面:http://127.0.0.1:3000,在弹出的提示中允许使用摄像头和麦克风。
第二个浏览器窗口访问页面:http://127.0.0.1:3000#true,#true表示它是一个发起方,在弹出的提示中同样允许使用摄像头和麦克风。
这时页面中应当可以看到2个画面,一个是本地的,一个是远端的。

将代码中的IP稍做调整后部署到外网,即可在2个不同的地点访问这个页面进行实时通讯。


微信订阅号:
源文地址:http://blog.gopersist.com/2014/10/21/webrtc-simple/
posted on 2014-10-21 17:21 老林 阅读(43300) 评论(6)  编辑  收藏 所属分类: 即时通讯(IM)

评论

# re: 最简单的WebRTC示例[未登录] 2014-11-17 11:20 eric
WebRTC需要stun,turn,ice服务器的支持。stun和turn是发现对方公网ip的方式,ice是一个统一的框架,将stun和turn的实现放在一起。但我在网上搜索ice server好像开源的几乎没有。希望多多交流:ericmmgg@126.com。  回复  更多评论
  

# re: 最简单的WebRTC示例 2014-11-24 18:36 xy.lin
@eric
stun用来发现公网IP,也要判断路由器行为和防火墙。turn是在无法进行p2p时提供数据中转服务。rfc5766-turn-server是一个开源项目,同时提供了上面的功能。  回复  更多评论
  

# re: 最简单的WebRTC示例[未登录] 2015-05-14 14:08 danny
请问楼主,当使用new webkitRTCPeerConnection建立connection后,candidate信息是connection主动去探测的么,如果探测有返回,就会调用onicecandidate()?  回复  更多评论
  

# re: 最简单的WebRTC示例[未登录] 2015-11-18 13:39
挺好的例子,不过我自己测试发现,在同一台机器上显示不了对端的视频,两台机器上可以互通。  回复  更多评论
  

# re: 最简单的WebRTC示例 2016-05-26 11:27 keithwind
是不是onicecandidate和onaddstream的代码内容反调了,我没测试,但是感觉流程执行不对  回复  更多评论
  

# re: 最简单的WebRTC示例 2016-05-26 17:43 keithwind
if(json.event === "_offer")
比较错了,所以看不到,少一个下划线  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航: