(研) WebRTC 桌面共享 [2022.9.12]

文章记录学习过程,但并不一定有结果,会不断更新,也可能会挖坑。

看到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 实现库。有不少的示例,然而都还看不懂。

相关文章