Skip to content

信令

信令是 WebRTC 建立连接之前交换 SDP 和 ICE candidate 的过程。WetRTC 通过 SignalChannel 接口将信令传输与业务逻辑解耦,你可以自由选择任何传输方式。

SignalChannel 接口

ts
interface SignalChannel {
  /** 发送信令消息到远端 */
  send(data: SignalMessage): Promise<void>

  /** 接收远端信令消息,返回取消监听的函数 */
  onMessage(handler: (data: SignalMessage) => void): () => void
}

interface SignalMessage {
  type: 'offer' | 'answer' | 'ice-candidate' | 'bye'
  sdp?: string
  candidate?: RTCIceCandidateInit
}

示例:WebSocket

ts
const ws = new WebSocket('wss://signal.example.com')

const signal: SignalChannel = {
  async send(data) {
    ws.send(JSON.stringify(data))
  },
  onMessage(handler) {
    const listener = (e: MessageEvent) => handler(JSON.parse(e.data))
    ws.addEventListener('message', listener)
    return () => ws.removeEventListener('message', listener)
  }
}

const rtc = new WetRTC({ signal })
await rtc.connect()

示例:Socket.IO

ts
import { io } from 'socket.io-client'

const socket = io('https://signal.example.com')

const signal: SignalChannel = {
  async send(data) {
    socket.emit('signal', data)
  },
  onMessage(handler) {
    socket.on('signal', handler)
    return () => socket.off('signal', handler)
  }
}

示例:HTTP 长轮询

ts
let polling = true

const signal: SignalChannel = {
  async send(data) {
    await fetch('/api/signal', {
      method: 'POST',
      body: JSON.stringify(data),
    })
  },
  onMessage(handler) {
    const poll = async () => {
      while (polling) {
        const res = await fetch('/api/signal/poll')
        if (res.ok) {
          handler(await res.json())
        }
        await new Promise(r => setTimeout(r, 1000))
      }
    }
    poll()
    return () => { polling = false }
  }
}

基类:BaseSignalChannel

如果你的项目中多处使用信令,可以继承 BaseSignalChannel 获得事件能力:

ts
import { BaseSignalChannel } from '@wetspace/wetrtc'

class MySignal extends BaseSignalChannel {
  async send(data: SignalMessage) { /* ... */ }
  onMessage(handler) { /* ... */ }
}

const signal = new MySignal()
signal.on('error', (err) => console.error('信令错误:', err))
signal.on('closed', () => console.log('信令通道关闭'))

信令配置

通过 signalConfig 配置信令超时等行为:

ts
const rtc = new WetRTC({
  signal,
  signalConfig: {
    offerTimeout: 10_000,   // offer 超时 (ms)
    answerTimeout: 10_000,  // answer 超时 (ms)
    iceTimeout: 5_000,      // ICE 收集超时 (ms)
  }
})

生产示例:virt-screen + Socket.IO

monorepo 中的 WET 扩展屏 使用 NestJS WebSocket Gateway 转发 WetRTC 信令,并扩展 join-room / peer-left 等房间事件。完整流程、双端 initiator/polite 配对与代码片段见 virt-screen 集成示例

核心 SignalChannel 实现见文档片段 docs/_snippets/virt-screen/signal-channel-socketio.ts(对应源码 virt-screen/src/renderer/composables/useSignalChannel.ts)。

Released under the MIT License.