webrtc初探1
目标
可以实现双方视频通话和聊天
效果
代码
呼叫方
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>Documenttitle>
<style>
.wrapp {
width: 100%;
text-align: center;
border: red solid 1px;
}
.videos {
display: flex;
}
.video {
display: flex;
justify-content: center;
align-items: center;
width: 50%;
border: red solid 1px;
height: 120px;
position: relative;
}
.msgs {
background-color: pink;
width: 100%;
height: 200px;
margin: auto;
overflow-y: scroll;
padding: 10px;
box-sizing: border-box;
}
.ipt {
padding: 20px;
}
.open-video {
left: 10px;
top: 10px;
position: absolute;
z-index: 2;
}
.msg-content {
display: flex;
margin-bottom: 10px;
}
.head {
border-radius: 50%;
width: 30px;
height: 30px;
}
.me {
background-color: white;
margin-left: 8px;
}
.other {
margin-right: 8px;
background-color: green;
}
.msg-ctxtype-me {
flex-direction: row-reverse;
}
.content {
background-color: #95ec69;
padding: 4px;
width: 50%;
border-radius: 4px;
}
style>
head>
<body>
<h1>发起端h1>
<div class="wrapp">
<div class="videos">
<div class="video">
<video class="local-video" autoplay width="160" height="120">video>
div>
<div class="video">
<video class="remote-video" autoplay width="160" height="120">video>
div>
div>
<div class="msgs">div>
<div class="ipt">
<input type="text"> <button onclick="sendMsg()">发送button>
div>
div>
<script>
// import {ws} from ‘./helper.js‘;
const ws = new WebSocket("wss://dshvv.com:8888/my_ws");
let icecandidated = false;
const lc = new RTCPeerConnection()
/*
* 处理文字聊天消息相关
*/
const dc = lc.createDataChannel("channel");
const msgs = []; //所有的聊天内容 消息容器
const updateMsgs = () => { // 每当有新消息时,更新聊天展示
let el = ‘‘;
msgs.forEach((msg) => {
el += `<div class=‘msg-content msg-ctxtype-${msg.type}‘>
<div class=‘head ${msg.type}‘></div>
<div class=‘content‘>${msg.content}</div>
</div>`
})
msgsEl.innerHTML = el;
document.querySelector(‘.msgs‘).lastChild.scrollIntoView(true);
}
// 收到新消息
dc.onmessage = e => {
msgs.push({
type: ‘other‘,
content: e.data
});
updateMsgs();
}
// 发送消息
const sendMsg = () => {
const content = document.querySelector(‘input‘).value;
msgs.push({
type: ‘me‘,
content
});
dc.send(content);
updateMsgs();
}
// 文字消息链接初始化
dc.onopen = e => {
msgs.push({
type: ‘me‘,
content: ‘初始化链接成功‘
});
updateMsgs();
}
const msgsEl = document.querySelector(‘.msgs‘);
/*
* 认证唯一标识相关
*/
ws.onopen = async () => {
lc.onicecandidate = e => {
if (!icecandidated) {
ws.send(JSON.stringify({// 将LocalDescription发给别人
event: "offer",
data: { sdp: lc.localDescription }
}));
icecandidated = true;
}
}
lc.createOffer().then(o => lc.setLocalDescription(o)).then(a => console.log("set successfully!"))
}
ws.onmessage = (e) => {
const msg = JSON.parse(e.data);
if (msg.event === "answer") {
const answer = msg.data.sdp;
lc.setRemoteDescription(answer)
}
}
/*
* 视频推送
*/
const openVideo = document.querySelector(‘.open-video‘);
navigator.mediaDevices.getUserMedia({ audio: true, video: true }).then((localStream) => {
document.querySelector(‘.local-video‘).srcObject = localStream;
for (const track of localStream.getTracks()) {
lc.addTrack(track, localStream);
console.log(‘添加本地媒体流到本地peer connection‘);
}
});
lc.ontrack = async (event) => {
const remoteVideo = document.querySelector(‘.remote-video‘);
remoteVideo.srcObject = event.streams[0];
};
script>
body>
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>Documenttitle>
<style>
.wrapp {
width: 100%;
text-align: center;
border: red solid 1px;
}
.videos {
display: flex;
}
.video {
display: flex;
justify-content: center;
align-items: center;
width: 50%;
border: red solid 1px;
height: 120px;
position: relative;
}
.msgs {
background-color: pink;
width: 100%;
height: 200px;
margin: auto;
overflow-y: scroll;
padding: 10px;
box-sizing: border-box;
}
.ipt {
padding: 20px;
}
.open-video {
left: 10px;
top: 10px;
position: absolute;
z-index: 2;
}
.msg-content {
display: flex;
margin-bottom: 10px;
}
.head {
border-radius: 50%;
width: 30px;
height: 30px;
}
.me {
background-color: white;
margin-left: 8px;
}
.other {
margin-right: 8px;
background-color: green;
}
.msg-ctxtype-me {
flex-direction: row-reverse;
}
.content {
background-color: #95ec69;
padding: 4px;
width: 50%;
border-radius: 4px;
}
style>
head>
<body>
<h1>接收端h1>
<div class="wrapp">
<div class="videos">
<div class="video">
<video class="local-video" autoplay width="160" height="120">video>
div>
<div class="video">
<video class="remote-video" autoplay width="160" height="120">video>
div>
div>
<div class="msgs">div>
<div class="ipt">
<input type="text"> <button onclick="sendMsg()">发送button>
div>
div>
<script>
// import {ws} from ‘./helper.js‘;
const ws = new WebSocket("wss://dshvv.com:8888/my_ws");
let icecandidated = false;
const rc = new RTCPeerConnection();
/*
* 认证唯一标识相关
*/
rc.onicecandidate = e => {
console.log(‘onicecandidate执行,回应answer‘);
if (!icecandidated) {
ws.send(JSON.stringify({
event: "answer",
data: { sdp: rc.localDescription }
}));
icecandidated = true;
}
}
ws.onmessage = (e) => {
const msg = JSON.parse(e.data);
if (msg.event === "offer") {
const offer = msg.data.sdp;
rc.setRemoteDescription(offer).then(a => console.log("offer set!"))
rc.createAnswer().then(a => rc.setLocalDescription(a)).then(a => console.log("answer create!"))
}
}
/*
* 处理文字聊天消息相关
*/
const msgs = []; //所有的聊天内容 消息容器
const msgsEl = document.querySelector(‘.msgs‘);
const updateMsgs = () => { // 每当有新消息时,更新聊天展示
let el = ‘‘;
msgs.forEach((msg) => {
el += `<div class=‘msg-content msg-ctxtype-${msg.type}‘>
<div class=‘head ${msg.type}‘></div>
<div class=‘content‘>${msg.content}</div>
</div>`
})
msgsEl.innerHTML = el;
document.querySelector(‘.msgs‘).lastChild.scrollIntoView(true);
}
rc.ondatachannel = e => {
console.log(e);
rc.dc = e.channel;
rc.dc.onmessage = e => {
console.log("new message from client!" + e.data);
msgs.push({
type: ‘other‘,
content: e.data
});
updateMsgs();
}
rc.dc.onopen = e => {
console.log(‘初始化链接成功‘,e);
msgs.push({
type: ‘me‘,
content: ‘初始化链接成功‘
});
updateMsgs();
}
}
const sendMsg = () => {
const content = document.querySelector(‘input‘).value;
msgs.push({
type: ‘me‘,
content
});
rc.dc.send(content);
updateMsgs();
}
/*
* 视频接收
*/
navigator.mediaDevices.getUserMedia({ audio: true, video: true }).then((localStream) => {
document.querySelector(‘.local-video‘).srcObject = localStream;
for (const track of localStream.getTracks()) {
rc.addTrack(track, localStream);
console.log(‘添加本地媒体流到本地peer connection‘);
}
});
rc.ontrack = async (event) => {
const remoteVideo = document.querySelector(‘.remote-video‘);
remoteVideo.srcObject = event.streams[0];
};
script>
body>
html>
原文:https://www.cnblogs.com/dshvv/p/14805772.html