完整代码 直接复制html打开使用
实现本地屏幕 和远端屏幕
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>123</title>
</head>
<body>
<div class="video-container">
<h2>本地捕获的屏幕共享流</h2>
<video id="srcVideo" playsinline controls muted loop class="srcVideo">
</video>
</div>
<div class="video-container">
<h2>远端传输过来的屏幕共享流渲染</h2>
<video id="shareStreamVideo" playsinline autoplay muted class="shareStreamVideo"></video>
</div>
</body>
<script>
const srcVideo = document.getElementById('srcVideo');
const shareStreamVideo = document.getElementById('shareStreamVideo');
let srcStream;
let shareStream;
// 定义捕获流的参数
let displayMediaOptions = {
video: {
width: {max: 1280},
height: {max: 720},
frameRate: {ideal: 15}
}
}
/*
捕获屏幕流可以使用navigator.mediaDevices.getDisplayMedia(displayMediaOptions)方法获取,
此方法为异步方法,会将屏幕流包装成一个Promise对象,解析Promise后会返回一个MediaStream对象,
我们可以从这个对象中取出视频或者音频Track进行流传输
*/
navigator.mediaDevices.getDisplayMedia({ video: true }).then(stream => {
srcStream = stream;
srcVideo.srcObject = stream;
srcVideo.play();
// 传输流
call();
});
function setVideoTrackContentHints(stream, hint) {
const track = stream.getVideoTracks()[0];
if ('contentHint' in track) {
track.contentHint = hint;
if (track.contentHint !== hint) {
console.log('Invalid video track contentHint: \'' + hint + '\'');
}
} else {
console.log('MediaStreamTrack contentHint attribute not supported');
}
}
function call() {
// 克隆流
shareStream = srcStream.clone();
// "detail"设置清晰度优先(也可使用"text"),如果需要设置流畅度优先,使用"motion"
setVideoTrackContentHints(shareStream, 'detail');
// 建立PeerConnection
establishPC(shareStreamVideo, shareStream);
}
function establishPC(videoTag, stream) {
// 创建两个PeerConnection模拟两个客户端,pc1相当于本地,pc2相当于远端
const pc1 = new RTCPeerConnection(null);
const pc2 = new RTCPeerConnection(null);
pc1.onicecandidate = e => {
// 可以理解为通知pc2连接pc1的地址
onIceCandidate(pc1, pc2, e);
};
// 可以理解为通知pc1接pc2地址
pc2.onicecandidate = e => {
onIceCandidate(pc2, pc1, e);
};
// 将需要传输的流添加给PeerConnection
stream.getTracks().forEach(track => pc1.addTrack(track, stream));
// 设置offer和answer,可理解为通知两边另一边的编解码等媒体信息
pc1.createOffer({ video: true }).then(desc => {
pc1.setLocalDescription(desc)
.then(() => pc2.setRemoteDescription(desc))
.then(() => pc2.createAnswer())
.then(answerDesc => onCreateAnswerSuccess(pc1, pc2, answerDesc))
.catch(onSetSessionDescriptionError);
})
.catch(e => console.log('Failed to create session description: ' + e.toString()));
// 远端接收到流,交给video去播放
pc2.ontrack = event => {
if (videoTag.srcObject !== event.streams[0]) {
videoTag.srcObject = event.streams[0];
}
};
}
function onSetSessionDescriptionError(error) {
console.log('Failed to set session description: ' + error.toString());
}
function onCreateAnswerSuccess(pc1, pc2, desc) {
pc2.setLocalDescription(desc)
.then(() => pc1.setRemoteDescription(desc))
.catch(onSetSessionDescriptionError);
}
function onIceCandidate(pc, otherPc, event) {
otherPc.addIceCandidate(event.candidate);
}
</script>
</html>