webrtc实现点对点视频通讯
html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>webrtc</title>
<style>
#yours{
width:300px;
position:absolute;
top:200px;
left:100px;
}
#theirs{
width:300px;
position:absolute;
top:200px;
left:400px;
}
</style>
</head>
<body>
<button onclick="createOffer()">建立连接</button>
<video id="yours" autoplay></video>
<video id="theirs" autoplay></video> </body> <script src="./lib/jquery.min.js"></script>
<script src="./lib/webrtc.js"></script> </html>
webrtc.js
var websocket; function randomNum(minNum,maxNum){
switch(arguments.length){
case :
return parseInt(Math.random()*minNum+,);
break;
case :
return parseInt(Math.random()*(maxNum-minNum+)+minNum,);
break;
default:
return ;
break;
}
}
const userid = 'user' + randomNum(,); function hasUserMedia() {
navigator.getUserMedia = navigator.getUserMedia || navigator.msGetUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
return !!navigator.getUserMedia;
}
function hasRTCPeerConnection() {
window.RTCPeerConnection = window.RTCPeerConnection || window.webkitRTCPeerConnection || window.mozRTCPeerConnection || window.msRTCPeerConnection;
return !!window.RTCPeerConnection;
} var yourVideo = document.getElementById("yours");
var theirVideo = document.getElementById("theirs");
var Connection; function startPeerConnection() {
//return;
var config = {
'iceServers': [
//{ 'urls': 'stun:stun.xten.com:3478' },
//{ 'urls': 'stun:stun.voxgratia.org:3478' },
{ 'url': 'stun:stun.l.google.com:19302' }
]
};
config = {
iceServers: [
{ urls: 'stun:stun.l.google.com:19302' },
{ urls: 'stun:global.stun.twilio.com:3478?transport=udp' }
],
//sdpSemantics: 'unified-plan'
};
// {
// "iceServers": [{
// "url": "stun:stun.1.google.com:19302"
// }]
// };
Connection = new RTCPeerConnection(config);
Connection.onicecandidate = function(e) {
console.log('onicecandidate');
if (e.candidate) {
websocket.send(JSON.stringify({
"userid":userid,
"event": "_ice_candidate",
"data": {
"candidate": e.candidate
}
}));
}
}
Connection.onaddstream = function(e) {
console.log('onaddstream'); //theirVideo.src = window.URL.createObjectURL(e.stream);
theirVideo.srcObject = e.stream;
}
} createSocket();
startPeerConnection(); if (hasUserMedia()) {
navigator.getUserMedia({ video: true, audio: false },
stream => {
yourVideo.srcObject = stream;
window.stream = stream;
Connection.addStream(stream)
},
err => {
console.log(err);
})
} function createOffer(){
//发送offer和answer的函数,发送本地session描述
Connection.createOffer().then(offer => {
Connection.setLocalDescription(offer);
websocket.send(JSON.stringify({
"userid":userid,
"event": "offer",
"data": {
"sdp": offer
}
}));
});
} function createSocket(){
//websocket = null;
websocket = new WebSocket('wss://www.ecoblog.online/wss');
eventBind();
};
function eventBind() {
//连接成功
websocket.onopen = function(e) {
console.log('连接成功')
};
//server端请求关闭
websocket.onclose = function(e) {
console.log('close')
};
//error
websocket.onerror = function(e) { };
//收到消息
websocket.onmessage = (event)=> {
if(event.data == "new user") {
location.reload();
} else {
var json = JSON.parse(event.data);
console.log('onmessage: ', json);
if(json.userid !=userid){
//如果是一个ICE的候选,则将其加入到PeerConnection中,否则设定对方的session描述为传递过来的描述
if(json.event === "_ice_candidate"&&json.data.candidate) {
Connection.addIceCandidate(new RTCIceCandidate(json.data.candidate));
}else if(json.event ==='offer'){
Connection.setRemoteDescription(json.data.sdp);
Connection.createAnswer().then(answer => {
Connection.setLocalDescription(answer);
console.log(window.stream)
websocket.send(JSON.stringify({
"userid":userid,
"event": "answer",
"data": {
"sdp": answer
}
}));
})
}else if(json.event ==='answer'){
Connection.setRemoteDescription(json.data.sdp);
console.log(window.stream) }
}
}
};
}
建立连接的过程:
1⃣️两个浏览器都打开该页面,连接到同一个socket('wss://www.ecoblog.online/wss');
注意:webrtc只能在localhost或者https下使用,所以线上环境的话,我们的socket服务以及html页面都必须是要有https证书的;
对于wss,利用反向代理,在nginx的站点配置下如下配置/wss:
正如你所看到的那样,socket服务开在12345端口,所以还要去阿里云网站开一个这个端口的出入站规则;
另外centos的防火墙对该端口开放,或者直接关闭防火墙(自行百度)
socket服务写得比较简陋,但已够用,功能就是把收到的信息发给当前连接的所有c端
2⃣️两个c端已经和socket建立连接,然后任意其中一端点击“建立连接”
此时点击建立连接的端就是offer(携带信号源信息),发给另外一个端,另外一个端收到offer之后,发出响应answer(携带信号源信息),offer端收到answer端信息进行存储;
这样每个端都有了自己的信息和对方的信息,
3⃣️candidata信息的发送
其实这块,网上有的说法是offer发出answer发出后设置了localDescription和remoteDescription后就会触发onicecandidate,但是我测试的时候貌似没有,所以
我这里是在获取摄像头信息后通过
Connection.addStream(stream)
来触发Connection.onicecandidate,在这个事件监听的回调里,发出自身端的candidata给对方,如此一来,双方都有了对方的localDescription、remoteDescription和candidata;
三者齐全之后,就会触发Connection.onaddstream,这样,直接通过:
theirVideo.srcObject = e.stream;
把流写到video里面去,这样就能展示对方的视频信息了:
但是这样,只能在局域网内使用,如果要在公网使用的话,还要一个穿透服务器,网上找的一些免费的好像都不能用了?还是说我写得有问题?
具体的可百度,webrtc搭建stun服务器
webrtc实现点对点视频通讯的更多相关文章
- webrtc笔记(3): 多人视频通讯常用架构Mesh/MCU/SFU
问题:为什么要搞这么多架构? webrtc虽然是一项主要使用p2p的实时通讯技术,本应该是无中心化节点的,但是在一些大型多人通讯场景,如果都使用端对端直连,端上会遇到很带宽和性能的问题,所以就有了下图 ...
- 使用WebRTC搭建前端视频聊天室——点对点通信篇
WebRTC给我们带来了浏览器中的视频.音频聊天体验.但个人认为,它最实用的特性莫过于DataChannel——在浏览器之间建立一个点对点的数据通道.在DataChannel之前,浏览器到浏览器的数据 ...
- 使用WebRTC搭建前端视频聊天室——信令篇
博客原文地址 建议看这篇之前先看一下使用WebRTC搭建前端视频聊天室——入门篇 如果需要搭建实例的话可以参照SkyRTC-demo:github地址 其中使用了两个库:SkyRTC(github地址 ...
- JMeter扩展Java请求实现WebRTC本地音视频推流压测脚本
WebRTC是Web Real-Time Communication缩写,指网页即时通讯,是一个支持Web浏览器进行实时语音或视频对话的API,实现了基于网页的视频会议,比如声网的Agora Web ...
- 使用WebRTC搭建前端视频聊天室——数据通道篇
本文翻译自WebRTC data channels 在两个浏览器中,为聊天.游戏.或是文件传输等需求发送信息是十分复杂的.通常情况下,我们需要建立一台服务器来转发数据,当然规模比较大的情况下,会扩展成 ...
- 使用WebRTC搭建前端视频聊天室
在两个浏览器中,为聊天.游戏.或是文件传输等需求发送信息是十分复杂的.通常情况下,我们需要建立一台服务器来转发数据,当然规模比较大的情况下,会扩展成多个数据中心.这种情况下很容易出现很高的延迟,同时难 ...
- WebRTC:一个视频聊天的简单例子
相关API简介 在前面的章节中,已经对WebRTC相关的重要知识点进行了介绍,包括涉及的网络协议.会话描述协议.如何进行网络穿透等,剩下的就是WebRTC的API了. WebRTC通信相关的API非常 ...
- WebRTC搭建前端视频聊天室——数据通道篇
本文翻译自WebRTC data channels 在两个浏览器中,为聊天.游戏.或是文件传输等需求发送信息是十分复杂的.通常情况下,我们需要建立一台服务器来转发数据,当然规模比较大的情况下,会扩展成 ...
- springboot+kurento+coturn+contos的视频通讯服务搭建
springboot+kurento+coturn+contos的视频通讯服务搭建 服务器CentOS Linux release 7.9.2009 (Core) 本案例成功于20210628 1.默 ...
随机推荐
- java线程基础巩固---同步代码块以及同步方法之间的区别和关系
在上一次中[http://www.cnblogs.com/webor2006/p/8040369.html]采用同步代码块的方式来实现对线程的同步,如下: 对于同步方法我想都知道,就是将同步关键字声明 ...
- 【安徽集训】Emerald
Description \(n\) 座城市在数轴上,第 \(i\) 座城市有一条连向第 \(i+1\) 座城市的单向边.每座城市有一个类型 A/B 以及一个非负整数人口,A 类城市的人觉得自己的城市比 ...
- P2634 树上路径长度为3的倍数的点对数 点分治
在计算答案的时候维护一个数组num num[i]为当前所有点距离根距离%3的数量 则当前块的答案为num[0]*num[0]+2*num[1]*num[2] #include<bits/stdc ...
- 第六章 组件 58 组件切换-使用v-if和v-else结合flag进行切换
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8&quo ...
- LeetCode 69 x 的平方根
链接:https://leetcode-cn.com/problems/sqrtx 实现 int sqrt(int x) 函数. 计算并返回 x 的平方根,其中 x 是非负整数. 由于返回类型是整数, ...
- css全部理解
如何设置标签样式 给标签设置长宽 只有块儿级标签才可以设置长宽 行内标签设置了没有任何作用(仅仅只取决于内部文本值) 字体颜色 color后面可以跟多种颜色数据 颜色英文 red #06a0de 直接 ...
- Struts2标签:s:password 修改时密码为空的问题
s:password 有个属性showPassword默认为false,想要密码显示,设置标签属性 showPassword="true" 即可.
- python中的apply(),applymap(),map() 的用法和区别
平时在处理df series格式的时候并没有注意 map和apply的差异 总感觉没啥却别.不过还是有区别的.下面总结一下: import pandas as pd df1= pd.DataFrame ...
- hive日期函数-杂谈(一)
来到广发返现由于历史遗留问题很多时间格式十分杂乱 我将总结一下时间日期的事情 1.hive原生时间函数的功能 2.一些基本业务时间范围的指标的sql案例 3.自定义udf函数让后来人更方便
- mysql 导入SQL文件报错
----MySQL导入数据的时候,总是报错,本地测试都没办法测试---- 导出SQL文件正常, 在导入SQL文件的时候, 报错-----大部分数据表导入成功, 个别的失败 在网上看到很多建议: 建议别 ...