网页版WebRTC多人聊天Demo
本文基于Codelab中step7,在其基础上作简单修改,使其支持多人视频通讯,本文暂时只支持星状结构三人聊天,多人聊天可以在基础上扩展,原理相同。
一.源码分析
该工程包括三个文件:server.js,main.js,index.html。
1.server.js
if (numClients == 0){socket.join(room);socket.emit('created', room);} else if (numClients == 1) {io.sockets.in(room).emit('join', room);socket.join(room);socket.emit('joined', room);} else { // max two clientssocket.emit('full', room);}socket.emit('emit(): client ' + socket.id + ' joined room ' + room);socket.broadcast.emit('broadcast(): client ' + socket.id + ' joined room ' + room);
后台服务代码,负责异步消息通讯。当有新用户加入房间时,向客户端发送消息,客户端接收到消息后作相应的处理。
2.index.html
网站主页,包括两块视频区域和文本区域。
<!DOCTYPE html>
<html>
<head><meta name='keywords' content='WebRTC, HTML5, JavaScript' />
<meta name='description' content='WebRTC Reference App' />
<meta name='viewport' content='width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1'><base target='_blank'><title>WebRTC client</title><link rel='stylesheet' href='css/main.css' /> </head><body><div id='container' class='main' ><div id='videos' class='videos'><video id='localVideo' class='localVideo' autoplay muted></video><video id='remoteVideo' class='remoteVideo' autoplay></video></div><div id='textareas'><textarea id="dataChannelSend" disabled placeholder="Press Start, enter some text, then press Send."></textarea><textarea id="dataChannelReceive" disabled></textarea></div><button id="sendButton" disabled>Send</button></div><script src='/socket.io/socket.io.js'></script>
<script src='js/lib/adapter.js'></script>
<script src='js/main.js'></script></body>
</html>
3.main.js
核心代码区域,包括房间的创建,RTCPeerConnection创建和两点间的视频通话。
3.1消息处理
socket.on('created', function (room){console.log('Created room ' + room);isInitiator = true;
});socket.on('full', function (room){console.log('Room ' + room + ' is full');
});socket.on('join', function (room){console.log('Another peer made a request to join room ' + room);console.log('This peer is the initiator of room ' + room + '!');isChannelReady = true;
});socket.on('joined', function (room){console.log('This peer has joined room ' + room);isChannelReady = true;
});socket.on('message', function (message){console.log('Received message:', message);if (message === 'got user media') {maybeStart();} else if (message.type === 'offer') {if (!isInitiator && !isStarted) {maybeStart();}pc.setRemoteDescription(new RTCSessionDescription(message));doAnswer();} else if (message.type === 'answer' && isStarted) {pc.setRemoteDescription(new RTCSessionDescription(message));} else if (message.type === 'candidate' && isStarted) {var candidate = new RTCIceCandidate({sdpMLineIndex:message.label,candidate:message.candidate});pc.addIceCandidate(candidate);} else if (message === 'bye' && isStarted) {handleRemoteHangup();}
});
3.2peerconnection创建和通讯
function createPeerConnection() {try {pc = new RTCPeerConnection(pc_config, pc_constraints);pc.onicecandidate = handleIceCandidate;console.log('Created RTCPeerConnnection with:\n' +'  config: \'' + JSON.stringify(pc_config) + '\';\n' +'  constraints: \'' + JSON.stringify(pc_constraints) + '\'.');} catch (e) {console.log('Failed to create PeerConnection, exception: ' + e.message);alert('Cannot create RTCPeerConnection object.');return;}pc.onaddstream = handleRemoteStreamAdded;pc.onremovestream = handleRemoteStreamRemoved;if (isInitiator) {try {// Reliable Data Channels not yet supported in ChromesendChannel = pc.createDataChannel("sendDataChannel",{reliable: false});sendChannel.onmessage = handleMessage;trace('Created send data channel');} catch (e) {alert('Failed to create data channel. ' +'You need Chrome M25 or later with RtpDataChannel enabled');trace('createDataChannel() failed with exception: ' + e.message);}sendChannel.onopen = handleSendChannelStateChange;sendChannel.onclose = handleSendChannelStateChange;console.log('....................this is  a initiator = true....................');} else {pc.ondatachannel = gotReceiveChannel;console.log('....................this is not a initiator = false....................');}
}
3.3 视频源的输出展现
function handleRemoteStreamAdded(event) {console.log('Remote stream added.');// reattachMediaStream(miniVideo, localVideo);
  attachMediaStream(remoteVideo, event.stream);remoteStream = event.stream;
//  waitForRemoteVideo();
}
二.
简单工作流程介绍与修改思路

1. 工作过程如下:

1.1.浏览器A访问主页,允许访问摄像头音频设备,server接收到'create or join'消息,计算此时连接到服务器的客户端数量,此时数量为0,则向客户端发送'created'消息。
1.2.浏览器A接收到'created'消息,将isInitiator设为true,该值为true表示该客户断是peerconnection的发起者。
1.3.浏览器B访问主页,允许访问摄像头音频设备,server接收到'create or join'消息,计算此时连接到服务器的客户端数量,此时数量为1,则向客户端发送join和joined消息。
1.4.浏览器A和浏览器B都接收到join和joined消息,设置isChannelReady=true,表示此时准备好建立连接。浏览器A发起peerconnection连接doCall,浏览器B回应peerconnection连接doAnswer,A和B建立P2P连接。
1.5.A和B分别将来自本地和远端的视频stream显示在页面上。
注意:浏览器A和浏览器B都接受来自server相同的消息,而两者在接收到相同的消息后的处理却不一样(main.js代码是一样的),一个是发起者,一个是应答者。可以使用状态机来理解,程序所处状态不一样,虽然接收到相同的命令,但可以做出不同的处理(通过isInitiator变量区分不同的状态)。
2.三人聊天室的实现
简单起见,我们暂时先实现三人视频通讯,使用星状结构。下面是修改思路:
a.A和B以及建立连接,此时如C加入,可以将A和C建立连接,同时保持A和B之前的连接。此时,A能看到B和C,而B和C只能看到A。
b.如果A B C三者需要互相看到,则需要A将B的视频传给C,并将C的视频传给B。
本文暂时只实现A与B通讯,A与C通讯,BC之间不能通讯。下面是具体的代码修改步骤:
2.1server.js
if (numClients == 0){socket.join(room);socket.emit('created', room);} else if (numClients <=2 ) { //第三个用户加入后仍然发送join joined消息io.sockets.in(room).emit('join', room);socket.join(room);socket.emit('joined', room);} else { // max two clientssocket.emit('full', room);}
2.2index.html
可以采用动态方式添加,这里简单起见直接增加一路视频实现块。
<div id='videos' class='videos'><video id='localVideo' class='localVideo' autoplay muted></video> //本地视频 A</div><div ><video id='remoteVideo' class='remoteVideo' autoplay></video>// remote视频B</div><div ><video id='remoteVideo2' class='remoteVideo2' autoplay></video> //remote视频c</div>
2.3 main.js
   a.增加一个全局变量isPeerEstablished
用来表示该客户端是否已经创建了PeerConnection。isPeerEstablished和isInitiator两者可以区分发起者和应答者,因为具有超过2个客户端,所以必须使用isPeerEstablished来选择尚未创建连接的客户端作为应答者。
     var isPeerEstablished=false;
   b.处理message机制修改
在判断条件里面加入(!isPeerEstablished||isInitiator)表示尚未创建链接C和发起者A才会执行peerconnection。保证新加入者C和A创建链接,同时保持A和B的连接。
socket.on('message', function (message){console.log('Received message:', message);if (message === 'got user media'&&(!isPeerEstablished||isInitiator)) {maybeStart();} else if (message.type === 'offer'&&(!isPeerEstablished||isInitiator)) {    if (!isInitiator && !isStarted) {     maybeStart();}pc.setRemoteDescription(new RTCSessionDescription(message));doAnswer();} else if (message.type === 'answer' && isStarted&&(!isPeerEstablished||isInitiator)) {pc.setRemoteDescription(new RTCSessionDescription(message));} else if (message.type === 'candidate' && isStarted&&(!isPeerEstablished||isInitiator)) {var candidate = new RTCIceCandidate({sdpMLineIndex:message.label,candidate:message.candidate});pc.addIceCandidate(candidate);} else if (message === 'bye' && isStarted) {      handleRemoteHangup();}
});

c.视频流展现

如果isInitiator和isPeerEstablished都为true,说明此时A和B已经建立链接。此时,应该将新的视频流显示在remoteVideo2中。其他情况将视频流展示在remoteVideo中。
function handleRemoteStreamAdded(event) {console.log('Remote stream added.');// reattachMediaStream(miniVideo, localVideo);
if(isInitiator&&isPeerEstablished){attachMediaStream(remoteVideo2, event.stream);remoteStream2 = event.stream;
}else{attachMediaStream(remoteVideo, event.stream);remoteStream = event.stream;
}
isPeerEstablished=true;
//  waitForRemoteVideo();
}
d.其他两处修改
var remoteVideo2 = document.querySelector('#remoteVideo2');......function handleRemoteHangup() {console.log('Session terminated.');stop();//isInitiator = false;  //总是保持A的发起者角色
}
三人聊天效果图:

网页版WebRTC多人聊天Demo相关推荐

  1. php qq对话,PHP WEB版QQ多人聊天

    制作WEB版QQ多人聊天过程中, 无法将数据插入数据库,查找了多遍,实在不知哪里有错误,请各位老师帮忙看一下,给指点,非常感谢! 下面是各文件: //my.js function getXmlHttp ...

  2. WebSocket实现简易版的多人聊天室

    一.websocket简介           WebSocket是一种在单个TCP连接上进行全双工通信的协议.WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推 ...

  3. metaRTC的p2p版webrtc远程屏幕控制demo

    概述 同时支持windows/linux/android操作系统远程桌面控制p2p版云桌面,不需要服务器(sfu版本为另一个版本),支持Nvidia和Intel的GPU编码,采用datachannel ...

  4. vue仿微信网页版|vue+web端聊天室|仿微信客户端vue版

    一.项目介绍 基于Vue2.5.6+Vuex+vue-cli+vue-router+vue-gemini-scrollbar+swiper+elementUI等技术混合架构开发的仿微信web端聊天室- ...

  5. Mac和网页版Skype更新聊天机器人功能

    近日,微软正式宣布,Mac版以及网页版Skype正式加入聊天机器人功能. Skype团队通过不懈的努力,制作了一个应用程序中的以及网页上的聊天机器人.运用聊天机器人这种方式,微软能够更好的为用户提供服 ...

  6. 为什么你会被限制登录网页版微信?

    有一个词叫做"三月爬虫",指的是有些学生临到毕业了,需要收集数据写毕业论文,于是在网上随便找了几篇教程,学了点requests甚至是urllib和正则表达式的皮毛,就开始写爬虫疯狂 ...

  7. (Agora声网)多人视频聊天应用的开发(三)多人聊天

    转载于:Android多人视频聊天应用的开发(三)多人聊天-玖哥的书房-51CTO博客 http://blog.51cto.com/dongfeng9ge/2104587 本系列文章结合声网官方在Gi ...

  8. Android多人视频聊天应用的开发(三)多人聊天

    在上一篇<Android多人视频聊天应用的开发(二)一对一聊天>中我们学习了如何使用声网Agora SDK进行一对一的聊天,本篇主要讨论如何使用Agora SDK进行多人聊天.主要需要实现 ...

  9. 再见,itchat!再见,网页版微信!

    点击上方"编程派",选择设为"设为星标" 优质文章,第一时间送达! 有一个词叫做"三月爬虫",指的是有些学生临到毕业了,需要收集数据写毕业论 ...

  10. 打开浏览器直接开始远程协助!RemoteCall网页版功能介绍

    RemoteCall网页版远程技术支持软件 RemoteCall网页版远程支持是什么? RemoteCall网页版是无需安装程序,基于网络浏览器来实现远程连接的RemoteCall远程支持软件独家功能 ...

最新文章

  1. vim编辑二进制文件
  2. 全球首个AI设计药物诞生,淘宝新增垃圾识别功能……
  3. 博图如何读取mysql数据_博途使用小结:从SQL中读取数据并给变量赋值
  4. ecplise常用快捷键
  5. python安装报错ox000007b_Python沙箱逃逸的n种姿势
  6. 网络编程之 TCP / UDP 及其流程比较
  7. eclipse使用技巧---使用正则表达式查找替换
  8. deepin linux 2014 硬盘安装教程,Linux Deepin的硬盘安装
  9. Matlab如何实现建立ROS节点并进行实时通讯
  10. linux方面的杂谈
  11. mysql8.0.15安装方法 mysql8安装教程
  12. echart markline 设置不同颜色_小学信息技术《设置文档格式》教案
  13. 利用GridView显示主细表并一次编辑明细表所有数据的例子(转)
  14. centos7 小图标_Centos7 桌面图标设置
  15. 山西大同大学教务处学生端--送给学弟,学妹的礼物,可在PC端,手机端操作
  16. with admin option和with grant option的区别与用法
  17. python气象卫星云图解析_python下载卫星云图合成gif
  18. [kuangbin带你飞]专题四 最短路练习 R
  19. mysql独立开发_TickyCMS: TickyCMS是由罗敏贵独自开发的一款基于PHP+Mysql架构的轻量级开源内容管理系统。...
  20. 软件机器人失控:40%的bot程序都是恶意的

热门文章

  1. 【吐槽】火车票一票难求啊
  2. 常见Struts、Hibernate、Spring、J2EE、ibatis、Oracle等开发框架架构图及其简介
  3. web of knowledge分析文献引用情况(引)
  4. SQL查询1-12月的数据
  5. adb.exe可能被其他程序关闭_苹果说关闭后台 反而会缩短电池寿命?!
  6. shell自动收集服务器硬件系统信息通过web页面显示
  7. flex布局——回顾
  8. .Net码农就业求职储备(新手进阶)
  9. LinkedHashMap与HashMap的使用比较
  10. 漂亮女生应聘华为的真实过程