看到golang的屏幕共享库https://github.com/screego/server,稍用时间学习一下WebRTC。
这里有一篇稍详细的网文可以学习。
WebRTC 网页即时通讯 (Web Real-Time Communications) 是一项实时通讯技术,它允许网络应用或者站点,在不借助中间媒介的情况下,建立浏览器之间点对点(Peer-to-Peer)的连接,实现视频流和音频流或者其他任意数据的传输。
简单的说,就是 WebRTC 可以不借助媒体服务器,通过浏览器与浏览器直接连接(点对点),即可实现音视频传输。
相较而言,WebSocket 主要用于实时网页应用和聊天应用等,而在这上面 WebRTC 的优势在于:
WebRTC 是为高质量音视频实时通信设计的;
WebRTC 提供的浏览器端到端通信远比 WebSocket 提供的服务延迟更低。
实现上的区别
WebRTC 使用 UDP 协议,而 WebSocket 使用 TCP 协议;
WebRTC 可以同时提供高质量且低延迟的推流。
WebRTC 其实也使用了 WebSocket,不过是用于搭建 WebRTC的信令机制,但是在连接建立结束后,由于 WebRTC 是端到端连接,因此也不再需要额外服务器。
传统的通信方式:
WebRTC的通信方式:
要实现整个流程还是比较复杂:
STUN
NAT的会话穿越功能 Session Traversal Utilities for NAT 是一个允许位于 NAT 后的客户端找出自己的公网地址,判断出路由器阻止直连的限制方法的协议。
TURN
NAT的中继穿越方式 Traversal Using Relays around NAT 通过TURN服务器中继所有数据的方式来绕过“对称型NAT”
(看起来这是不能直连,只能曲线救国了:通过服务器中转。效率就差了。)
SDP
会话描述协议 Session Description Protocol 是一个描述多媒体连接内容的协议,如分辨率,格式,编码,加密算法等。所以在数据传输时两端都能够理解彼此的数据。
从技术上讲,SDP 并不是一个真正的协议,而是一种数据格式,用于描述在设备之间共享媒体的连接。
以下示例就可以共享出自己的浏览器窗口或者桌面。但并没有共享给别人,只在本地播放了视频流。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>getDisplayMedia</title>
<link rel="stylesheet" href="./index.css">
</head>
<body>
<div>
<video id="gum-local" autoplay playsinline muted></video>
<button id="startButton" disabled>Start</button>
<div id="errorMsg"></div>
</div>
<script src="./index.js"></script>
</body>
</html>
const startButton = document.getElementById('startButton');
if ((navigator.mediaDevices && 'getDisplayMedia' in navigator.mediaDevices)) {
startButton.disabled = false;
} else {
errorMsg('不支持getDisplayMedia');
}
startButton.addEventListener('click', () => {
navigator.mediaDevices.getDisplayMedia({video: true})
.then(handleSuccess, handleError);
});
function handleSuccess(stream) {
startButton.disabled = true;
const video = document.querySelector('video');
video.srcObject = stream;
console.log(stream);
// MediaStream { id: "{1abd7c20-2f8f-4265-a4a9-21638699d55c}", active: true, onaddtrack: null,onremovetrack: null }
// const videoTracks = stream.getVideoTracks(); // 视频流
// const audioTracks = stream.getAudioTracks(); // 音频流
// console.log(videoTracks);
// console.log(audioTracks);
// 检测用户已停止共享屏幕
// 通过浏览器UI共享屏幕。
stream.getVideoTracks()[0].addEventListener('ended', () => {
errorMsg('用户已结束共享屏幕');
startButton.disabled = false;
});
}
function handleError(error) {
errorMsg(`getDisplayMedia error: ${error.name}`, error);
}
function errorMsg(msg, error) {
const errorElement = document.querySelector('#errorMsg');
errorElement.innerHTML += `<p>${msg}</p>`;
if (typeof error !== 'undefined') {
console.error(error);
}
}
继续找了一个演示程序 https://github.com/sylvain121/webrtc-screen-remote,自建了STUN,有时成功,有时失败。关键是成功时,依然没有显示出桌面,鼠标倒是看到跟随服务端在移动。
经过分析发现:在它的lib/video/DesktopCapture.go中,Start()引用了github.com/kbinani/screenshot,这是一个常用的跨平台屏幕截取工具,但在我的Ubuntu下却没有截取到内容。
func (capture DesktopCapture) Start() {
go func() {
for range capture.ticker.C {
img, err := screenshot.Capture(capture.x, capture.y, capture.width, capture.height)
x, y, data, width, height, _ := CursorGet()
upLeft := image.Point{0, 0}
lowRight := image.Point{width, height}
i := image.NewRGBA(image.Rectangle{Min: upLeft, Max: lowRight})
i.Pix = data
if x > capture.x && x < capture.x+capture.width && y > capture.y && y < capture.y+capture.height {
offset := image.Pt(x-capture.x, y-capture.y)
b := img.Bounds()
final := image.NewRGBA(b)
draw.Draw(final, b, img, image.ZP, draw.Src)
draw.Draw(final, i.Bounds().Add(offset), i, image.ZP, draw.Over)
img = final
}
if err != nil {
fmt.Fprintf(os.Stderr, "%s\n", err.Error())
continue
}
capture.outputStream <- img
// save(img, fmt.Sprintf("%d.png", time.Now().Unix()))
}
}()
}
虽然我将截屏改为https://github.com/go-vgo/robotgo,但没有运行起来。
发现一个录制RTC的库https://github.com/muaz-khan/RecordRTC
RecordRTC 是用于音频/视频以及屏幕活动记录的 WebRTC JavaScript 库。演示地址:https://www.webrtc-experiment.com/RecordRTC/
Pion WebRTC[https://github.com/pion/webrtc] WebRTC API 的纯 Go 实现库。有不少的示例,然而都还看不懂。