webRTC 初探

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


})

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 阅读redux源码

    提供了和双向绑定思想不同的单向数据流,应用状态可以预测,可以回溯,易于调试。使用redux之初的人可能会很不适应,改变一个状态,至少写三个方法,从这点上不如写其...

    frontoldman
  • 如何用d3生成一个饼图

    frontoldman
  • Rxjs 响应式编程-第四章 构建完整的Web应用程序

    在本章中,我们将构建一个典型的Web应用程序,在前端和后端使用RxJS。我们将转换文档对象模型(DOM)并使用Node.js服务器中的WebSockets进行客...

    frontoldman
  • JavaScript之使用JavaScript模仿oop编程

    wfaceboss
  • 编程小知识之 JavaScript 调用堆栈

    console 支持 trace 方法,使用该方法可以向控制台输出当前的调用堆栈.

    用户2615200
  • 设计模式(5)[JS版]-JavaScript如何实现工厂方法模式?

    在基于类的编程中,工厂方法模式是一种创建模式,该模式使用工厂方法来处理创建对象的问题,而不必指定将要创建的对象的确切类。这是通过调用工厂方法来创建对象的,而不是...

    AlbertYang
  • Promise 的四种常用方法。

    看到项目里不少人用了Promise 的库类,比如 bluebird、q 、jQuery.Deffered 等 polyfill promise 方式,使用的时...

    前端博客 : alili.tech
  • 理解JavaScript立即执行函数

    立即执行函数通常包含两种使用格式,具体使用那一种风格可以根据个人习惯和团队规范选择:

    伯爵
  • JavaScript斐波纳契数列非递归算法

    一般斐波纳契数列采用递归或是数组缓存的方式,这里的方法不考虑重复计算斐波纳契数列的情况。

    meteoric
  • 命名函数表达式

    好文章,可惜中文译文已经无法访问了。不过在cssrain上找到一篇:www.cssrain.cn/demo/named%20function%20express...

    meteoric

扫码关注云+社区

领取腾讯云代金券