Skip to content

快速开始

安装

bash
pnpm add @wetspace/wetrtc
# or
npm install @wetspace/wetrtc
# or
yarn add @wetspace/wetrtc

基本用法

WetRTC 需要一个信令通道来交换 SDP 和 ICE 候选。你需要实现 SignalChannel 接口,传输层可任选 WebSocket、SSE + HTTP 或纯 HTTP 长轮询:

WebSocket

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

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

export 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)
  },
}

SSE + HTTP

发送走 POST,接收走 EventSource(Server-Sent Events)。适合只需服务端→客户端推送、客户端→服务端用 HTTP 的场景:

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

const ROOM_ID = 'my-room'
const BASE = 'https://signal.example.com'

/** 服务端约定:POST 发送信令,GET /events 以 SSE 推送远端消息 */
export const signal: SignalChannel = {
  async send(data) {
    await fetch(`${BASE}/api/signal?room=${ROOM_ID}`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(data),
    })
  },
  onMessage(handler) {
    const es = new EventSource(`${BASE}/api/signal/events?room=${ROOM_ID}`)
    es.onmessage = (e) => handler(JSON.parse(e.data))
    es.onerror = () => es.close()
    return () => es.close()
  },
}

HTTP 长轮询

不依赖 WebSocket 或 SSE,仅用 fetch 实现。/poll 端点应在无消息时挂起连接,有信令时立即返回:

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

const ROOM_ID = 'my-room'
const BASE = 'https://signal.example.com'

/** 服务端约定:POST 发送信令,GET /poll 长轮询拉取远端消息(无消息时挂起,有消息立即返回) */
export const signal: SignalChannel = {
  async send(data) {
    await fetch(`${BASE}/api/signal?room=${ROOM_ID}`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(data),
    })
  },
  onMessage(handler) {
    let active = true

    const poll = async () => {
      while (active) {
        try {
          const res = await fetch(`${BASE}/api/signal/poll?room=${ROOM_ID}`)
          if (res.ok) {
            const msg = await res.json()
            if (msg) handler(msg)
          }
        } catch {
          await new Promise((r) => setTimeout(r, 1000))
        }
      }
    }

    poll()
    return () => {
      active = false
    }
  },
}

创建实例并连接:

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

declare const signal: SignalChannel
declare const remoteVideo: HTMLVideoElement

const rtc = new WetRTC({
  signal,
  direction: 'sendrecv',
  iceServers: [{ urls: 'stun:stun.l.google.com:19302' }],
})

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

await rtc.connect()

连接方向

方向说明
sendrecv双向(默认),可发送和接收媒体
sendonly仅发送,不接收远端媒体
recvonly仅接收,不发送本地媒体

生命周期

ts
// rtc 为已创建的 WetRTC 实例
declare const rtc: import('@wetspace/wetrtc').WetRTC

await rtc.connect()
await rtc.disconnect()
await rtc.connect()
rtc.dispose()

下一步

Released under the MIT License.