1

webRTC介绍

webRTC是英文Web Real-Time Communication的缩写,中文翻译网页实时通信,是浏览器不需要服务器的中转,可以直接通信的技术

webRTC 应用

网上的很多教程都会包含实时视频的介绍,不过我感觉视频看起来很酷,不过却不是webRTC的使用难点,却明显增加webRTC的使用复杂度,可以略过

webRTC是客户端对客户端的单对单实时通信,但是还是需要服务器,就好比一个婚介所的作用

下面我们通过socket.io作为服务器端实现简单的聊天功能

实现步骤

  1. 发起方向服务器发出通知并初始化RTCPeerConnection

  2. 服务器接收到通知通知接收并初始化RTCPeerConnection

  3. 双方都监听onicecandidate事件,并在回调里面把event.candidate上传到服务器

  4. 双发都监听ondatachannel事件,并在回调里面给event.channel监听onmessage事件

  5. 发起方调用createOffer方法,并在这个方法的回调中给自己的RTCPeerConnection实例设置setLocalDescription,并向服务器发送自己的Description

  6. 接收方在服务器推送给自己的消息里面把5中的Description设置为自己的RTCPeerConnection实例的RemoteDescription,并调用createAnswer方法,在此方法的回调之中设置setLocalDescription,并把自己的Description上传到服务器

  7. 发起方接收到服务器推送给自己的Description,设置为LocalDescription,至此双方连接建立

双方可以调用自己的channel的send方法发送文本消息

至于调用视频和音频,我觉着这部分使用起来比较简单,不绕

步骤就是一方的开启视频,获取视频流,添加到RTCPeerConnection实例中,连接的另外一方监听onaddstream事件,获取视频流,OK

多人会话的话,同一个RTCPeerConnection实例是不能够多人会话的。如果要多人会话,就要单对单建立多个连接。同样的步骤执行多次就可以了

客户端代码

html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>


<table width="800px">
  <tr>
    <td>
      <video id="myVideo"></video>
    </td>
    <td>
      <div style="height: 200px;overflow: auto"></div>
    </td>
  </tr>
  <tr>
    <td></td>
    <td>
      <textarea style="height: 200px;width: 400px" id="textarea"></textarea>
    </td>
  </tr>
</table>


<button id="start">开始</button>
<button id="stop">结束</button>
<button id="send">发送</button>

<script src='/socket.io/socket.io.js'></script>
<script src="js/index.js"></script>


</body>
</html>

js

var video = document.getElementById('video')
var localPeerConnection, remotePeerConnection
var localChannel

var socket = io.connect('http://localhost:8181')

// 打开页面即开启等待模式
startWaiting()

function startWaiting() {
  
  var servers = {
    "iceServers": [{
      "url": "stun:stun.l.google.com:19302"
    }]
  }

  var pc_constraints = {
    optional: [{
      DtlsSrtpKeyAgreement: true
    }]
  }

  localPeerConnection = new RTCPeerConnection(servers, pc_constraints)

  localChannel = localPeerConnection.createDataChannel('sendDataChannel', { reliable: true })

  localPeerConnection.onicecandidate = function(event) {
    if (event.candidate) {
      socket.emit('onicecandidate', event.candidate)
    }
  }

  localChannel.onopen = function() {
    console.log('open')
  }

  localChannel.onclose = function() {
    console.log('close')
  }

  localPeerConnection.ondatachannel = function(event) {
    console.log(event.channel)

    event.channel.onmessage = function(msg) {
      console.log('event msg', msg)
    }
  }


  socket.on('offer', function(desc) {
    console.log('offer: ', desc)
    localPeerConnection.setRemoteDescription(desc)
    setRemote = true
    localPeerConnection.createAnswer(function(desc) {
       localPeerConnection.setLocalDescription(desc)
       socket.emit('answer', desc)
    }, function(error){console.log(error)})
  })

  socket.on('answer', function(desc) {
    console.log('answer: ', desc)
    localPeerConnection.setRemoteDescription(desc)
    console.log('answer end')
    setRemote = true
  })

  socket.on('onicecandidate', function(icecandidate) {
    localPeerConnection.addIceCandidate(icecandidate)
  })




}

document.getElementById('start').onclick = function() {
  localPeerConnection.createOffer(function(desc) {
    localPeerConnection.setLocalDescription(desc)
    socket.emit('offer', desc)
  }, function(error){console.log(error)})
}

document.getElementById('send').onclick = function() {
  var value = document.getElementById('textarea').value
  localChannel.send(value)
}

服务端代码

var static = require('node-static')

var http = require('http')

var file = new(static.Server)()

var app = http.createServer(function (req, res) {
  file.serve(req, res);
}).listen(8181);

var io = require('socket.io').listen(app)

io.sockets.on('connection', function(socket) {

  socket.on('offer',function(desc) {
    socket.broadcast.emit('offer', desc)
  })

  socket.on('answer',function(desc) {
    socket.broadcast.emit('answer', desc)
  })

  socket.on('onicecandidate', function(candidate) {
    socket.broadcast.emit('onicecandidate', candidate)
  })

  socket.on('message', function(message) {
    socket.broadcast.to(message.channel).emit('message', message.message)
  })


})

frontoldman
4.5k 声望1.3k 粉丝

前端开发者