webrtc 点对点聊天 不需要服务器
selfl.html
点击查看代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>视频聊天</title>
<link rel="stylesheet" type="text/css" href="css/common.css"/>
<link rel="stylesheet" type="text/css" href="css/jquery-ui.css"/>
<script src="./js/peerjs.min.js"></script>
<script src="./js/jquery-1.12.4.js"></script>
<script src="./js/jquery-ui.js"></script>
<script src="./js/util.js"></script>
<script>
var peer = null
var startId = null
var receiveId = null
var conn = null
var localStream = null
//页面加载后
window.onload = function () {
var videoSelect = document.querySelector('select#videoSelect')
var localVideo = document.querySelector('video#localVideo')
var remoteVideo = document.querySelector('video#remoteVideo')
var lblFrom = document.querySelector('label#lblFrom')
var tip = document.querySelector('#tip')
if (!navigator.mediaDevices ||
!navigator.mediaDevices.getUserMedia) {
console.log('webrtc is not supported!')
alert('webrtc is not supported!')
return
}
//获取摄像头列表
navigator.mediaDevices
.enumerateDevices()
.then(getDevices)
.catch(handleError)
//改变摄像头重新获取流
videoSelect.onchange = function () {
start()
pleaseCallMe() //让那边重新call 就能同步画面
}
start() //默认直接获取流
$('#dialog-confirm').hide() //隐藏接收提示框
//每次使用同一个startId
if (localStorage.getItem('startId') == null) {
startId = new Date().getTime()
localStorage.setItem('startId', startId)
} else {
startId = localStorage.getItem('startId')
}
peer = new Peer(startId)
console.log(peer)
peer.on('open', function (id) {
startId = id
console.log('My peer ID is: ' + id)
console.log(`接收端链接${location.href.replace('self', 'target')}?startId=${startId}`)
document.getElementById('receivedUrl').innerHTML = `<a target="_blank" href="${location.href.replace('self', 'target')}?startId=${startId}">${location.href.replace('self', 'target')}?startId=${startId}</a>`
})
peer.on('call', function (call) {
console.log('oncall')
call.answer(localStream)
})
peer.on('connection', function (conn) {
console.log('被连接', conn)
receiveId = conn.peer
conn.on('data', (data) => {
var msg = JSON.parse(data)
console.log('收到消息', msg)
//收到视频邀请时,弹出询问对话框
if (msg.action === 'call') {
console.log('call')
tip.innerHTML = '被别人call'
lblFrom.innerText = msg.from
$('#dialog-confirm').dialog({
resizable: false,
height: 'auto',
width: 400,
modal: true,
buttons: {
'Accept': function () {
$(this).dialog('close')
sendMessage(msg.to, msg.from, 'accept')
},
Cancel: function () {
$(this).dialog('close')
}
}
})
}
//接受视频通话邀请后,通知另一端
if (msg.action === 'accept-ok') {
console.log('accept-ok call => ' + JSON.stringify(msg))
var call = peer.call(receiveId, localStream)
call.on('stream', function (stream) {
console.log('received remote stream')
remoteVideo.srcObject = stream
})
tip.innerHTML = '已连接'
}
})
})
}
</script>
</head>
<body>
<div class="container" style="text-align: center;">
<h1>基于PeerJS的点对点视频聊天程序</h1>
<p>
<span style="font-weight: 700;">切换设备</span>
<select id="videoSelect" style="width:100px"></select>
</p>
<p>
把下方链接发送给你对象即可开始视频啦<br/>
<span>对象链接:</span><span id="receivedUrl">生成中...</span>
</p>
<div style="display: flex;flex-flow: wrap;justify-content: center;">
<div style="border: 5px solid #ccc;">
<h4>你的画面</h4>
<video id="localVideo" autoplay controls></video>
</div>
<div style="border: 5px solid #ccc;">
<h4>对象画面</h4>
<video id="remoteVideo" autoplay controls></video>
</div>
</div>
<div id="dialog-confirm" title="接受视频通话吗?">
<p>
<span class="ui-icon ui-icon-info" style="float:left; margin:12px 12px 20px 0;"></span><label
id="lblFrom"></label>
打你,是否接受?
</p>
</div>
<div id="tip">
等待分享链接给对象...
</div>
</div>
</body>
</html>
target.html
点击查看代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>视频聊天</title>
<link rel="stylesheet" type="text/css" href="css/common.css"/>
<link rel="stylesheet" type="text/css" href="css/jquery-ui.css"/>
<script src="./js/peerjs.min.js"></script>
<script src="./js/jquery-1.12.4.js"></script>
<script src="./js/jquery-ui.js"></script>
<script src="./js/util.js"></script>
<script>
var peer = null
var startId = null
var receiveId = null
var conn = null
var localStream = null
//页面加载后
window.onload = function () {
var videoSelect = document.querySelector('select#videoSelect')
var localVideo = document.querySelector('video#localVideo')
var remoteVideo = document.querySelector('video#remoteVideo')
var lblFrom = document.querySelector('label#lblFrom')
var tip = document.querySelector('#tip')
if (!navigator.mediaDevices ||
!navigator.mediaDevices.getUserMedia) {
console.log('webrtc is not supported!')
alert('webrtc is not supported!')
return
}
//获取摄像头列表
navigator.mediaDevices
.enumerateDevices()
.then(getDevices)
.catch(handleError)
//改变摄像头重新获取流
videoSelect.onchange = function () {
start()
pleaseCallMe() //让那边重新call 就能同步画面
}
start() //默认直接获取流
$('#dialog-confirm').hide() //隐藏接收提示框
//每次使用同一个startId
if (localStorage.getItem('startId') == null) {
startId = new Date().getTime()
localStorage.setItem('startId', startId)
} else {
startId = localStorage.getItem('startId')
}
peer = new Peer(startId)
console.log(peer)
peer.on('open', function (id) {
startId = id
console.log('My peer ID is: ' + id)
console.log(`接收端链接${location.href.replace('self', 'target')}?startId=${startId}`)
document.getElementById('receivedUrl').innerHTML = `<a target="_blank" href="${location.href.replace('self', 'target')}?startId=${startId}">${location.href.replace('self', 'target')}?startId=${startId}</a>`
})
peer.on('call', function (call) {
console.log('oncall')
call.answer(localStream)
})
peer.on('connection', function (conn) {
console.log('被连接', conn)
receiveId = conn.peer
conn.on('data', (data) => {
var msg = JSON.parse(data)
console.log('收到消息', msg)
//收到视频邀请时,弹出询问对话框
if (msg.action === 'call') {
console.log('call')
tip.innerHTML = '被别人call'
lblFrom.innerText = msg.from
$('#dialog-confirm').dialog({
resizable: false,
height: 'auto',
width: 400,
modal: true,
buttons: {
'Accept': function () {
$(this).dialog('close')
sendMessage(msg.to, msg.from, 'accept')
},
Cancel: function () {
$(this).dialog('close')
}
}
})
}
//接受视频通话邀请后,通知另一端
if (msg.action === 'accept-ok') {
console.log('accept-ok call => ' + JSON.stringify(msg))
var call = peer.call(receiveId, localStream)
call.on('stream', function (stream) {
console.log('received remote stream')
remoteVideo.srcObject = stream
})
tip.innerHTML = '已连接'
}
})
})
}
</script>
</head>
<body>
<div class="container" style="text-align: center;">
<h1>基于PeerJS的点对点视频聊天程序</h1>
<p>
<span style="font-weight: 700;">切换设备</span>
<select id="videoSelect" style="width:100px"></select>
</p>
<p>
把下方链接发送给你对象即可开始视频啦<br/>
<span>对象链接:</span><span id="receivedUrl">生成中...</span>
</p>
<div style="display: flex;flex-flow: wrap;justify-content: center;">
<div style="border: 5px solid #ccc;">
<h4>你的画面</h4>
<video id="localVideo" autoplay controls></video>
</div>
<div style="border: 5px solid #ccc;">
<h4>对象画面</h4>
<video id="remoteVideo" autoplay controls></video>
</div>
</div>
<div id="dialog-confirm" title="接受视频通话吗?">
<p>
<span class="ui-icon ui-icon-info" style="float:left; margin:12px 12px 20px 0;"></span><label
id="lblFrom"></label>
打你,是否接受?
</p>
</div>
<div id="tip">
等待分享链接给对象...
</div>
</div>
</body>
</html>
公共函数 util.js
点击查看代码
//获取url后面的参数
getRequest = function () {
var url = location.search
var theRequest = new Object()
if (url.indexOf('?') != -1) {
let str = url.substr(1)
let strs = str.split('&')
for (let i = 0; i < strs.length; i++) {
theRequest[strs[i].split('=')[0]] = unescape(strs[i].split('=')[1])
}
}
return theRequest
}
//绑定摄像头列表到下拉框
function getDevices (deviceInfos) {
if (deviceInfos === undefined) {
return
}
console.log(`设备信息${deviceInfos}`)
for (let i = 0; i !== deviceInfos.length; ++i) {
const deviceInfo = deviceInfos[i]
const option = document.createElement('option')
option.value = deviceInfo.deviceId
if (deviceInfo.kind === 'videoinput') {
option.text = deviceInfo.label || `camera ${videoSelect.length + 1}`
console.log(option)
videoSelect.appendChild(option)
}
}
}
//获取设备错误
function handleError (error) {
console.log('navigator.MediaDevices.getUserMedia error: ', error.message, error.name)
}
//获取流
function getStream (stream) {
console.log('received local stream')
localStream = stream
localVideo.srcObject = localStream //显示到页面
}
//开启本地摄像头
function start () {
if (localStream) { //停止
localStream.getTracks().forEach(track => {
track.stop()
})
}
const videoSource = videoSelect.value
const constraints = {
audio: true,
video: { width: 6020, deviceId: videoSource ? { exact: videoSource } : undefined }
}
navigator.mediaDevices
.getUserMedia(constraints)
.then(getStream)
.then(getDevices)
.catch(handleError)
}
//封装发送消息
function sendMessage (from, to, action) {
var message = { 'from': from, 'to': to, 'action': action }
if (!conn) {
conn = peer.connect(receiveId)
conn.on('open', () => {
conn.send(JSON.stringify(message))
console.log('发消息', message)
})
}
if (conn.open) {
conn.send(JSON.stringify(message))
console.log(message)
}
}
//当此端改变摄像头 请求那边重新call一次 不然画面传不过去
function pleaseCallMe () {
sendMessage(startId, receiveId, 'pleaseCallMe')
}
点击查看代码
.w60 {
width: 60px;
}
.w120 {
width: 120px;
}
.align_right {
text-align: right;
background-color: beige;
line-height: 150%;
padding: 3px
}
.align_left {
text-align: left;
line-height: 150%;
padding: 3px
}
.chatMessageBox {
height: 200px;
overflow-y: scroll;
vertical-align: top
}
video{
width:320px;
height:240px
}
#container {
position: relative;
}
#demoCanvas {
border: 1px solid #000;
}
本文来自博客园,作者:vx_guanchaoguo0,转载请注明原文链接:https://www.cnblogs.com/guanchaoguo/p/16311574.html