Skip to content

屏幕分享

使用 WetRTC 实现屏幕分享功能。若只想在浏览器中体验桌面捕获,可先查看 桌面媒体捕获

需要降低操作延迟时,请参阅 低延迟屏幕共享

生产级参考

Electron + Socket.IO + 手机接收的完整实现见 virt-screen 集成示例(提炼自 virt-screen/ 源码,含双端 initiator/polite 配对与信令事件表)。

发送端

ts
import { WetRTC, type SignalChannel } from '@wetspace/wetrtc'

declare const signal: SignalChannel

const rtc = new WetRTC({
  signal,
  direction: 'sendonly',
  logLevel: 'info',
})

const screenStream = await rtc.media.getDisplayMedia({
  width: 1920,
  height: 1080,
  frameRate: 30,
  audio: true,
})

for (const track of screenStream.getTracks()) {
  rtc.addTrack(track, screenStream)
}

screenStream.getVideoTracks()[0].addEventListener('ended', () => {
  console.log('屏幕分享已停止')
  rtc.disconnect()
})

await rtc.connect()

接收端

ts
import { WetRTC, type SignalChannel } from '@wetspace/wetrtc'

declare const signal: SignalChannel
declare const remoteVideo: HTMLVideoElement

const rtc = new WetRTC({
  signal,
  direction: 'recvonly',
})

rtc.on('track', (ev) => {
  remoteVideo.srcObject = ev.streams[0]
})

await rtc.connect()

低延迟配置

发送端与接收端可组合 videoEncodingpreferredVideoCodecapplyReceiverPlayoutDelay

ts
import { WetRTC, type SignalChannel } from '@wetspace/wetrtc'

declare const signal: SignalChannel

const rtc = new WetRTC({
  signal,
  direction: 'sendonly',
  initiator: false,
  polite: true,
  preferredVideoCodec: 'h264',
  videoEncoding: {
    contentHint: 'motion',
    maxFrameRate: 30,
    maxBitrate: 4_000_000,
    degradationPreference: 'maintain-framerate',
  },
})

const screenStream = await rtc.media.getDisplayMedia({
  width: 1920,
  height: 1080,
  frameRate: 30,
  audio: false,
})

for (const track of screenStream.getVideoTracks()) {
  rtc.addTrack(track, screenStream)
}

await rtc.connect()
ts
import {
  WetRTC,
  applyReceiverPlayoutDelay,
  type SignalChannel,
} from '@wetspace/wetrtc'

declare const signal: SignalChannel
declare const videoEl: HTMLVideoElement

const rtc = new WetRTC({
  signal,
  direction: 'recvonly',
  initiator: true,
  polite: false,
  preferredVideoCodec: 'h264',
})

rtc.on('statechange', (state) => {
  if (state === 'connected') {
    applyReceiverPlayoutDelay(rtc.peerConnection!, 0)
  }
})

rtc.on('track', (ev) => {
  if (ev.streams[0]) {
    videoEl.srcObject = ev.streams[0]
    applyReceiverPlayoutDelay(rtc.peerConnection!, 0)
  }
})

await rtc.connect()

Electron 屏幕分享

在 Electron 中使用 desktopCapturer 获取屏幕源:

ts
// main process
import { desktopCapturer } from 'electron'

const sources = await desktopCapturer.getSources({ types: ['screen'] })

// renderer process
declare const rtc: import('@wetspace/wetrtc').WetRTC

const sourceId = sources[0].id

const screenStream = await rtc.media.getDisplayMedia({
  sourceId,
  audio: false,
})

Released under the MIT License.