WebRTC

ブラウザ間でP2P(または SFU 経由)の音声・動画・データをやり取りする仕組み。 ビデオ会議・ライブ配信・低遅延ゲーム・ファイル直接転送・画面共有まで。

3 つの主要 API

カメラ・マイクの取得

const stream = await navigator.mediaDevices.getUserMedia({
  video: { width: 1280, height: 720, facingMode: "user" },
  audio: { echoCancellation: true, noiseSuppression: true },
})

document.querySelector("#preview").srcObject = stream

// 停止
stream.getTracks().forEach((t) => t.stop())

デバイス一覧

const devices = await navigator.mediaDevices.enumerateDevices()
const cams = devices.filter((d) => d.kind === "videoinput")
const mics = devices.filter((d) => d.kind === "audioinput")

await navigator.mediaDevices.getUserMedia({
  video: { deviceId: { exact: cams[1].deviceId } },
})

画面共有

const screen = await navigator.mediaDevices.getDisplayMedia({
  video: { frameRate: 30 },
  audio: true,        // 一部 OS のみ
})

P2P 接続の流れ

  1. シグナリングサーバ(WebSocket 等)で 2 ピアを繋げる場を提供
  2. 呼ぶ側が RTCPeerConnection を作成 → Offer SDP を生成
  3. シグナリング経由で Offer を相手へ送信
  4. 相手が RTCPeerConnection を作って Offer を受け取り → Answer SDP を返す
  5. 双方が ICE candidates を交換
  6. P2P 接続確立 → メディア / データの送受信

シンプルな実装

const pc = new RTCPeerConnection({
  iceServers: [
    { urls: "stun:stun.l.google.com:19302" },
    {
      urls: "turn:turn.example.com:3478",
      username: "user",
      credential: "pass",
    },
  ],
})

// ローカルストリーム追加
stream.getTracks().forEach((t) => pc.addTrack(t, stream))

// 相手のストリーム
pc.ontrack = (e) => {
  remoteVideo.srcObject = e.streams[0]
}

// ICE candidate を相手に送る
pc.onicecandidate = (e) => {
  if (e.candidate) signaling.send({ type: "ice", candidate: e.candidate })
}

// Offer を作成
const offer = await pc.createOffer()
await pc.setLocalDescription(offer)
signaling.send({ type: "offer", sdp: offer })

// 相手から Answer / ICE が来たら
signaling.onMessage(async (msg) => {
  if (msg.type === "answer") {
    await pc.setRemoteDescription(msg.sdp)
  } else if (msg.type === "ice") {
    await pc.addIceCandidate(msg.candidate)
  }
})

STUN / TURN

シグナリング

WebRTC 自体にシグナリング機能は無い。WebSocket / Firebase / Pusher 等で自前で繋ぐ。 単純な部屋制御 + メッセージ転送だけで OK。

RTCDataChannel

テキスト・バイナリの双方向通信。P2P で WebSocket 並みの API

// 呼ぶ側
const dc = pc.createDataChannel("chat", { ordered: true })
dc.onopen = () => dc.send("hello")
dc.onmessage = (e) => console.log(e.data)

// 受ける側
pc.ondatachannel = (e) => {
  const ch = e.channel
  ch.onmessage = (e) => console.log(e.data)
}

オプション

SFU と MCU

多人数会議は純粋 P2P では破綻(10 人で 90 ストリーム)。中継サーバを使う:

OSS SFU: mediasoup / Janus / LiveKit / Pion。SaaS: Daily / Agora / Twilio Video / 100ms

主要なライブラリ・SaaS

名前特徴
simple-peerピア通信を薄くラップ
PeerJSシグナリングサーバ込み
LiveKitOSS の SFU + Cloud。大規模会議
DailyVideo API SaaS
AgoraSaaS。グローバル展開強い
100msSaaS。エンタープライズ
Twilio VideoSaaS。古典
mediasoupOSS SFU。Node.js
PionGo 製の WebRTC 実装

セキュリティ

権限とパーミッション

ローカル開発の注意

典型用途

WHIP / WHEP

WebRTC を放送風に使う新標準。WHIP(送信)/ WHEP(受信)。 OBS や HLS / RTMP の代替として注目されている(低遅延)。

学び方

- webrtc.org 公式のサンプル
- WebRTC for the Curious(無料書籍)
- サンプルコードを動かすのが圧倒的に早い
- 本格的な多人数会議はライブラリ / SaaS に頼るのが現実的