跳到主要内容

L3-屏幕共享与远程协助

把屏幕共享和 DataChannel 控制通道结合,做一个轻量级"远程协助"工具。被协助方共享屏幕,协助方在 DataChannel 里发鼠标/键盘事件回控。

重要:浏览器不允许网页直接操控被共享方的鼠标/键盘。完整远程控制需要被协助方装一个 native helper(推荐 Electron 应用)。本项目演示分两部分:纯浏览器版(仅"看 + 划重点")、Electron 版(真正控制)。

1. 学习目标

  • getDisplayMedia 采集屏幕。
  • 用 DataChannel 发送高频低延迟控制事件(鼠标位置、按键)。
  • 屏幕共享专用 codec / 帧率策略。
  • 注释绘制("画圈圈")的实现。

2. 架构

3. 屏幕共享配置要点

const screen = await navigator.mediaDevices.getDisplayMedia({
video: {
displaySurface: 'monitor',
frameRate: 15, // 屏幕共享 15fps 通常够
cursor: 'always',
},
audio: { // 系统声音(用户需勾选)
echoCancellation: false,
noiseSuppression: false,
},
selfBrowserSurface: 'exclude',
systemAudio: 'include',
});

发送端策略:

const sender = pc.getSenders().find(s => s.track === screen.getVideoTracks()[0]);
const params = sender.getParameters();
params.encodings[0].maxBitrate = 2_500_000;
params.degradationPreference = 'maintain-resolution'; // 重点:屏幕共享必须保分辨率
await sender.setParameters(params);

Codec 推荐:

  • 同 Chrome / Edge / Firefox 互通 → VP9 或 AV1(屏幕共享低码率高画质)。
  • 含 Safari → H.264 兜底。

4. DataChannel 控制协议

type Event =
| { t: 'mouse'; x: number; y: number; b?: 'l'|'r'|'m'; d?: 'down'|'up' }
| { t: 'wheel'; dx: number; dy: number }
| { t: 'key'; code: string; d: 'down'|'up'; mods: number }
| { t: 'annot'; shape: 'circle'|'arrow'|'free'; pts: [number, number][]; color: string }
| { t: 'cursor'; x: number; y: number; user: string };

DataChannel 配置:

const ctrl = pc.createDataChannel('ctrl', {
ordered: true,
maxPacketLifeTime: 100, // 100ms 内重传,否则丢
});

注释绘制只发顶点序列,不传位图——一张图几百 KB,顶点几十字节。

5. 纯浏览器版(仅看 + 注释)

不能控制对方鼠标,但可以:

  • 共享屏幕给对方看。
  • 协助方在屏幕画面上画圈圈、贴箭头,被协助方实时看到。
  • 双方语音通话。

适合:远程教学、会议演示、轻量答疑。

6. Electron 版(真正控制)

被协助方装 Electron 客户端,里面跑一个本地 WebRTC + 用 robotjs / nut.js 把控制事件落到操作系统:

// electron-side
import { mouse, keyboard, Button, Key } from '@nut-tree-fork/nut-js';

dc.onmessage = async (e) => {
const ev = JSON.parse(e.data);
if (ev.t === 'mouse') {
await mouse.move([{x: ev.x, y: ev.y}]);
if (ev.d === 'down') await mouse.pressButton(toBtn(ev.b));
if (ev.d === 'up') await mouse.releaseButton(toBtn(ev.b));
} else if (ev.t === 'key') {
if (ev.d === 'down') await keyboard.pressKey(toKey(ev.code));
if (ev.d === 'up') await keyboard.releaseKey(toKey(ev.code));
}
};

安全要点

  • Electron 客户端必须签名打包,避免恶意替换。
  • 控制连接前必须用户在被协助方明确点"允许"。
  • 协助方所有操作要落本地审计日志。
  • 紧急停止快捷键(如连按 Esc 三次)必须本地可控。

7. 目录结构

L3-屏幕共享与远程协助/
├── web/ # 纯浏览器版
│ ├── client/
│ │ ├── annotator.js # 画圈圈、箭头
│ │ └── viewer.js
│ └── server/ # 复用 L1 信令
├── electron/ # Electron 版
│ ├── main.js # 主进程:WebRTC + nut.js
│ ├── renderer.js # 渲染进程:UI + 授权
│ └── package.json
└── README.md

8. 验收 Checklist

  • 共享 1080p 屏幕在 200 kbps 下仍可读
  • 鼠标控制延迟 ≤ 100ms(端到端)
  • 注释绘制实时同步,无明显抖动
  • Electron 紧急停止快捷键秒级响应
  • 关闭共享后控制权立即收回

9. 参考资料