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实现点对点视频通讯的更多相关文章

  1. webrtc笔记(3): 多人视频通讯常用架构Mesh/MCU/SFU

    问题:为什么要搞这么多架构? webrtc虽然是一项主要使用p2p的实时通讯技术,本应该是无中心化节点的,但是在一些大型多人通讯场景,如果都使用端对端直连,端上会遇到很带宽和性能的问题,所以就有了下图 ...

  2. 使用WebRTC搭建前端视频聊天室——点对点通信篇

    WebRTC给我们带来了浏览器中的视频.音频聊天体验.但个人认为,它最实用的特性莫过于DataChannel——在浏览器之间建立一个点对点的数据通道.在DataChannel之前,浏览器到浏览器的数据 ...

  3. 使用WebRTC搭建前端视频聊天室——信令篇

    博客原文地址 建议看这篇之前先看一下使用WebRTC搭建前端视频聊天室——入门篇 如果需要搭建实例的话可以参照SkyRTC-demo:github地址 其中使用了两个库:SkyRTC(github地址 ...

  4. JMeter扩展Java请求实现WebRTC本地音视频推流压测脚本

    WebRTC是Web Real-Time Communication缩写,指网页即时通讯,是一个支持Web浏览器进行实时语音或视频对话的API,实现了基于网页的视频会议,比如声网的Agora Web ...

  5. 使用WebRTC搭建前端视频聊天室——数据通道篇

    本文翻译自WebRTC data channels 在两个浏览器中,为聊天.游戏.或是文件传输等需求发送信息是十分复杂的.通常情况下,我们需要建立一台服务器来转发数据,当然规模比较大的情况下,会扩展成 ...

  6. 使用WebRTC搭建前端视频聊天室

    在两个浏览器中,为聊天.游戏.或是文件传输等需求发送信息是十分复杂的.通常情况下,我们需要建立一台服务器来转发数据,当然规模比较大的情况下,会扩展成多个数据中心.这种情况下很容易出现很高的延迟,同时难 ...

  7. WebRTC:一个视频聊天的简单例子

    相关API简介 在前面的章节中,已经对WebRTC相关的重要知识点进行了介绍,包括涉及的网络协议.会话描述协议.如何进行网络穿透等,剩下的就是WebRTC的API了. WebRTC通信相关的API非常 ...

  8. WebRTC搭建前端视频聊天室——数据通道篇

    本文翻译自WebRTC data channels 在两个浏览器中,为聊天.游戏.或是文件传输等需求发送信息是十分复杂的.通常情况下,我们需要建立一台服务器来转发数据,当然规模比较大的情况下,会扩展成 ...

  9. springboot+kurento+coturn+contos的视频通讯服务搭建

    springboot+kurento+coturn+contos的视频通讯服务搭建 服务器CentOS Linux release 7.9.2009 (Core) 本案例成功于20210628 1.默 ...

随机推荐

  1. Summer training #2

    A:不管有没有负数 一顿操作之后肯定只有正数 又因为A=A-B 所以最大值是一直在减小的 所以一定有结果 B:..一开始以为求min操作数 WA了2发 直接求所有数的GCD如果所有数的GCD都不是1的 ...

  2. 异步IO框架:asyncio 中篇

    上一节我们首先介绍了,如何创建一个协程对象.主要有两种方法 通过async关键字, 通过@asyncio.coroutine 装饰函数. 然后有了协程对象,就需要一个事件循环容器来运行我们的协程.其主 ...

  3. 浅谈浏览器存储(cookie、localStorage、sessionStorage)

    今天我们从前端的角度了解一下浏览器存储,我们常见且常用的存储方式主要由两种:cookie.webStorage(localStorage和sessionStorage).下面我们来一一认识它们. Co ...

  4. windows设置自动清理log

    @echo off set srcDir="D:\xx\xx\xx" set daysAgo=5 forfiles /p %srcDir% /s /m *.* /d -%daysA ...

  5. Linux Bonding

    https://www.cnblogs.com/huangweimin/articles/6527058.html 管理   linux下网卡bonding配置   章节 bonding技术 cent ...

  6. MySQL 关于索引的操作

    -- 索引分类? 1.普通索引 2.唯一索引 3.全文索引 4.组合索引 普通索引:仅加速查询,最基本的索引,没有任何限制 唯一索引:加速查询 + 列值唯一(可以有null) 全文索引:仅适用于MyI ...

  7. java 获取随机数的方法

    方法一: (数据类型)(最小值 + Math.random()*(最大值-最小值+1) ); 示例: (int)(1+Math.random()*(10-1+1)): 获取int类型 1-10的随机数 ...

  8. docker下安装运行mysql的过程以mysql5.7为例

    一.查找mysql资源 docker search mysql 其实这步顶多是看看有哪些mysql资源,除非你自己commit过一个特定的版本,否则直接执行下一步 二.安装mysql docker p ...

  9. django之表多对多建立方式、form组件、钩子函数 08

    目录 多对多三种创建方式 1.全自动(用ManyToManyField创建第三张表) 2.纯手写 3.半自动 form组件 引入 form组件的使用 forms组件渲染标签 form表单展示信息 fo ...

  10. mysql 查看删除触发器等操作

    mysql 查看删除触发器等操作 平时很少操作触发器,源于昨晚的一次故障,使用pt-online-change-schema修改大表过程中出现异常,再次执行时,提示已经存在触发器,导致失败. 这里推荐 ...