# WHIP 機能









## 概要

[RFC 9725](https://datatracker.ietf.org/doc/html/rfc9725) で定義されている WHIP (WebRTC-HTTP Ingestion Protocol) を利用した WebRTC 配信に対応しています。

ここでは Sora や WHIP 仕様について説明します。

## 注意

- Sora の WHIP は [RFC 9725](https://datatracker.ietf.org/doc/html/rfc9725) 準拠を前提としています- ただし [OBS Studio](https://obsproject.com/) の WHIP での動作を優先しているため、 RFC の WHIP 仕様とは異なる場合があります
- Sora SDK は WHIP へ対応していません
- 現時点では WHIP を利用した接続の統計ウェブフックの送信には対応していません


### OBS Studio と組み合わせて利用する際の注意

Sora 2025.2.0 以前と [OBS Studio 32.1](https://github.com/obsproject/obs-studio/releases/tag/32.1.0) 以降 の組み合わせでは、 OBS Studio の WHIP が利用できなくなる不具合が発生することを確認しています。

- [OBS Studio 32.1](https://github.com/obsproject/obs-studio/releases/tag/32.1.0) 以降を利用される場合は、Sora 2025.2.1 以降のバージョンをご利用ください
- Sora 2025.2.0 以前のバージョンを利用される場合は、 [OBS Studio 32.0](https://github.com/obsproject/obs-studio/releases/tag/32.0.0) をご利用ください

### WHIP クライアントのお問い合わせについて

WHIP クライアントに関する質問などの報告は Discord の利用をお願いします。

**URL**: 

Sora の WHIP クライアントについての質問やバグ報告は Discord の `#sora-sdk-faq` チャンネルにお願いします。

### 映像コーデックパラメータについて

WHIP では映像コーデックのパラメーターを認証払い出し時に指定しても有効になりません。

## WHIP とは何か

> **参考**
>
> [WebRTC-HTTP ingestion protocol (WHIP)](https://datatracker.ietf.org/doc/html/draft-ietf-wish-whip)

WHIP は WebRTC-HTTP ingestion protocol の略で、
WebRTC では標準化されていないシグナリングをブロードキャスト/ストリーミング系の配信ツール向けに規定した規格です。

WHIP は仕様を小さくして、実装を簡単にすることで配信ツールが取り込みやすくしています。

クライアントが HTTP POST で Offer SDP を送信して、Answer SDP を受け取るというシンプルなシグナリング規格です。

2023 年 12 月リリースの [OBS Studio 30.0](https://github.com/obsproject/obs-studio/releases/tag/30.0.0) にて WebRTC/WHIP が正式にサポートされました。

最新版は以下からダウンロードができます。



### WHIP のシーケンス図

```mermaid
sequenceDiagram
  participant OBS as "OBS Studio"
  participant WE as WHIP Endpoint
  participant MS as Media Server
  participant WS as WHIP Session
  OBS->>+WE: HTTP POST (SDP Offer)
  WE-->>-OBS: HTTP 201 Created (SDP Answer)
  note over OBS,MS: WebRTC Connection
  OBS->>+WS: HTTP DELETE
  WS->>-OBS: HTTP 200 OK
```

### Sora の WHIP のシーケンス図

Sora では WHIP エンドポイント、WHIP セッション、メディアサーバーすべてを Sora が担当します。

```mermaid
sequenceDiagram
   participant OBS as "OBS Studio"
   participant S as Sora
   participant A as App
   OBS->>+S: HTTP POST (SDP Offer)
   S->>+A: 認証ウェブフック
   A-->>-S: 200 OK<br>allowed : true
   S-->>-OBS: HTTP 201 Created (SDP Answer)
   note over OBS,S: WebRTC Connection
   S->>+A: イベントウェブフック<br>connection.created
   A-->>-S: 200 OK
   OBS->>+S: HTTP DELETE
   S->>+A: イベントウェブフック<br>connection.destroyed
   A-->>-S: 200 OK
   S->>-OBS: HTTP 200 OK
```

## OBS Studio の WHIP 対応について

> **警告**
>
> OBS Studio の WHIP 対応については Discord  の #sora-sdk-faq にてご相談ください。

2025 年 12 月 時点での OBS Studio の WHIP 対応では輻輳制御が実装されていません。
これは OBS Studio が WHIP 対応のために利用している [libdatachannel](https://libdatachannel.org/) が輻輳制御に対応していないためです。

そのため、回線が不安定になったとしても、ビットレートを下げたりするといったことは行いません。

### サイマルキャスト対応

> **注意**
>
> OBS Studio の WHIP サイマルキャスト機能は OBS Studio 32.1.0 から利用できます。
> しかし Sora の WHIP 機能は OBS Studio のサイマルキャスト機能に未対応です。
> 次の Sora のリリースで対応予定です。

## OBS Studio 以外の WHIP クライアントへの対応について

> **重要**
>
> Sora の WHIP 実装は OBS Studio の WHIP 対応を優先しています。

新しい WHIP クライアントへの対応は有償での優先実装として対応を検討できますので、
対応希望の WHIP クライアントと優先実装については、サポートまでメールにてご連絡ください。

### ブラウザでの WHIP 対応

ブラウザからの WHIP 接続は条件付きでサポートしています。

- 音声は `Opus` のみ
- 映像は `AV1` / `H.264` / `H.265` のみ
- コーデックは音声、映像ともに 1 つのみ- `setCodecPreferences` を利用して 1 つのみを指定してください
- `mode` は `sendonly` のみ- `offer` は `a=sendonly` のみ
- `Link` ヘッダーを利用した TURN 接続のみ

### FFmpeg での WHIP 対応

> **重要**
>
> 現時点で Sora は FFmpeg での WHIP には対応していません。

FFmpeg の WHIP 対応は仕様がとても古く RFC 9725 に準拠していないため、2025 年 12 月 時点での実装では対応は難しいと考えています。

## Sora での利用方法

`sora.conf` にて [whip](SORA_CONF.html#615414) を `true` に指定してください。

```ini
whip = true
```

### Bearer トークンを利用した認証機能を利用する場合

`sora.conf` にて [whip_bearer_token_metadata_key](SORA_CONF.html#699f57) を指定してください。

```ini
whip_bearer_token_metadata_key = whip_access_token
```

例えば、 `access_token` という文字列を指定した場合、
WHIP 接続時、認証ウェブフックに `"metadata": {"access_token": "<bearer_token>"}` が入ってきます。
`whip_token` を指定した場合は `"metadata": {"whip_token": "<bearer_token>"}` が入ってきます。

`whip_bearer_token_metadata_key` が未指定の場合は、
Bearer トークンが WHIP 接続時に送られてきたとしても Sora は無視して、
`metadata` も生成しません。

## OBS Studio での WHIP 利用方法

OBS Studio での利用方法は以下の通りです。

![image](https://i.gyazo.com/f68934ea04634b0b845f3ae0d17ca4b3.jpg)

1. サービスに WHIP を選ぶ
2. サーバーに Sora が提供する WHIP エンドポイント URL を指定する- デフォルトでは `http://127.0.0.1:5000/whip/<channel_id>`
3. Bearer トークンには好きな文字列を指定する- Sora の認証ウェブフックの項目 `whip_bearer_token_metadata_key` で指定した値をキーとして、`"metadata": {"<whip_bearer_token_metadata_key>": "<bearer_token>"}` が認証サーバーに送信されます

### 切断方法

`Location` ヘッダーに入ってくるセッション URL に DELETE リクエストを送ることで切断できます。

OBS Studio は配信終了することで切断リクエストを送りますので、意識する必要はありません。

## Sora の OBS Studio (WHIP) の挙動

- Sora は WHIP エンドポイント URL を提供します- デフォルトでは `http://127.0.0.1:5000/whip/<channel_id>` です
- Sora の WHIP エンドポイントからの配信は、マルチストリームかつ配信のみ(sendonly)として扱われます
- Sora の WHIP エンドポイントを利用した配信では、シグナリング通知は現時点では利用できません
- Sora の WHIP セッション URL は WHIP エンドポイントのレスポンスに含まれる Location ヘッダーにて払い出されます

## WHIP エンドポイント URL

Sora の OBS Studio (WHIP) 対応は `"role": "sendonly"` として機能します。

### チャネル ID の指定

OBS Studio ではリクエスト時に JSON でチャネル ID を指定することができません。そのため WHIP エンドポイント URL に `channel_id` を含めて指定します。
channel_id に URL に利用できない文字が含まれている場合は URL エンコードしてください。

`HTTP POST https://sora.example.com/whip/<channel_id>`

`channel_id` が sora の WHIP エンドポイント URL 例:

```
https://sora.example.com/whip/sora
```

WHIP エンドポイントへの HTTP リクエストに対するレスポンスコードは 201 Created です。

## WHIP セッション URL

Sora では WHIP セッション URL は WHIP エンドポイントのレスポンスに含まれる Location ヘッダーにて払い出されます。

以下は切断する例です。

`HTTP DELETE https://sora.example.com/whip-session/<channel_id>/<secret>`

以下は Trickle ICE を利用する例です。

`HTTP PATCH https://sora.example.com/whip-session/<channel_id>/<secret>`

`<secret>` は 32 バイトのランダムな値を base32 でエンコードした文字列です。

WHIP セッション URL 例:

```
https://sora.example.com/whip-session/sora/QBF6AFDWZGWM97BNS5YCBSXM54M01D0TFQ48MC9Z3ZJG8YPRQ1Z0
```

> **注釈**
>
> OBS Studio に Bearer トークンを指定した場合は、WHIP セッション URL にも Bearer トークンは送られます

## 認証仕様

WHIP では認証に Bearer トークンを指定することができます。

OBS Studio でも認証情報に Bearer トークンを指定できます。

Sora は `sora.conf` で `whip_bearer_token_metadata_key` に文字列を指定していた場合、
OBS Studio の HTTP POST 時に Authentication ヘッダーで送られてきた Bearer トークンを、
認証ウェブフックの `metadata` に `{"<whip_bearer_token_metadata_key>": "<bearer_token>"}` を設定して認証サーバーに送信します。

Sora 自体は Bearer トークンのチェックやデコードなどは行いません。これらは認証ウェブフックのリクエストを受信した認証サーバーが行う必要があります。

## ウェブフック仕様

### whip

`true` が入ってきます。

### ignore_disconnect_websocket

`false` が入ってきます。

### metadata

`sora.conf` にて `whip_bearer_token_metadata_key` に指定した文字列をキーとして `metadata` に入ってきます。

```ini
whip_bearer_token_metadata_key = whip_bearer_token
```

もし文字列を `whip_bearer_token` にしていた場合は、
`"metadata": {"whip_bearer_token": "<bearer-token>"}` が送られてきます。

OBS Studio 側に設定した Bearer Token の値がそのまま入ってきます。

### role

`sendonly` が入ってきます。

### channel_id

WHIP エンドポイント URL に渡した値が利用されます。


> **注釈**
>
> URL デコード済みの値が入ります

### client_id

WHIP エンドポイント URL にクエリ文字列として `client_id=<client_id>` を指定した場合、その値が利用されます。

> **注釈**
>
> URL デコード済みの値が入ります

### bundle_id

WHIP エンドポイント URL にクエリ文字列として `bundle_id=<bundle_id>` を指定した場合、その値が利用されます。

> **注釈**
>
> URL デコード済みの値が入ります

### spotlight

WHIP エンドポイント URL にクエリ文字列として `spotlight=<boolean>` を指定した場合、その値が利用されます。

既知の問題として `spotlight = true` を指定して接続した場合、音声がそのままでは配信されません。 [FocusSpotlightFixed](API_SPOTLIGHT.html#beaf88) API を利用して OBS Studio の接続にフォーカスを当てる必要があります。

詳細は [既知の問題 - OBS Studio 対応機能](KNOWN_ISSUES.html#275fa8) をご確認ください。

> **注釈**
>
> URL デコード済みの値が入ります

### audio / video

OBS Studio 側で指定した値を利用します。
OBS Studio では音声は Opus のみ、映像は AV1 と H.264 と H.265 が利用できます。

- `audio: true`
- `audio_codec_type: "OPUS"`
- `video: true`
- `video_codec_type: "AV1" | "H264" | "H265"`

OBS Studio 利用時にはビットレートの指定できないため、
Sora のデフォルトの値が入ってきますが、 OBS Studio の WHIP 実装では SDP での最大ビットレートを無視します。
そのため OBS Studio 側で設定したビットレートで配信が行われます。

> **注釈**
>
> H.265 は [OBS Studio 30.2](https://github.com/obsproject/obs-studio/releases/tag/30.2.0) から利用できます

### simulcast

> **注意**
>
> 現時点では OBS Studio の WHIP 対応はサイマルキャストに未対応です。OBS Studio 側の対応待ちです。

現時点では `false` が入ってきます。

### sora_client

OBS Studio WHIP で User-Agent として送られてくる情報を `sora_client` に含めています。

```javascript
"sora_client": {
  "raw": "Mozilla/5.0 (OBS-Studio/30.1.0; Mac OS X; ja-JP)",
  "type": "OBS-Studio-WHIP",
  "version": "30.1.0",
  "environment": "Mozilla/5.0 (OBS-Studio/30.1.0; Mac OS X; ja-JP)"
},
```

### その他

- `e2ee: false`
- `spotlight: false`
- `data_channel_signaling: false`
- `ignore_disconnect_webhook: false`
- `turn_transport_type: udp`- [OBS Studio 30.2](https://github.com/obsproject/obs-studio/releases/tag/30.2.0) での TURN 対応は TURN-UDP のみのため `tcp` になる事はありません

## 認証ウェブフック成功時の払い出し

基本的には OBS Studio で指定した値がそのまま利用されますので、
以下の値以外は指定しないでください。

- client_id
- bundle_id
- event_metadata
- recording_block
- signaling_notify_metadata
- connection_lifetime
- cluster_affinity
- playout_delay_min_delay
- playout_delay_max_delay
- rtp_packet_loss_simulator_incoming
- turn_tcp_only- ただし 2025 年 12 月 現在では OBS Studio WHIP は TURN-TCP には対応していません
- turn_tls_only- ただし 2025 年 12 月 現在では OBS Studio WHIP は TURN-TLS には対応していません

## クラスター利用時の認証ウェブフックの挙動

クラスター利用時に、 WHIP で接続したノードではないノードに接続を振り分ける場合、
Sora は認証情報を担当ノードに Proxy を行います。

接続は接続したノードで行われますが、認証ウェブフックは担当ノードから送信されます。
その後 WebRTC 接続確立は担当ノードと行います。

### シーケンス図

```mermaid
sequenceDiagram
   participant O as "OBS Studio (WHIP)"
   participant S1 as Sora 1
   participant S2 as Sora 2
   participant A as App
   O->>+S1: HTTP POST<br>https://sora-02.example.com/whip/sora<br>Offer SDP
   Note over S1: 担当ノードは Sora 2
   S1->>+S2: ノード間通信で認証処理を Proxy
   S2->>+A: 認証ウェブフック<br>"channel_id": "sora"<br>"role": "sendonly"
   A-->>-S2: "allowed": true
   S2-->>-S1: Sora 2 の IP アドレス
   S1-->>-O: HTTP 201 Created<br>Answer SDP<br>Candidate: Sora 2 IP アドレス
   note over O,S2: WebRTC 確立
   S1->>+A: イベントウェブフック<br>"connection.created"
   A-->>-S2: HTTP 200 OK
   O-)S2: SRTP
   O-)S2: SRTP
   O->>+S2: HTTP DELETE<br>https://sora-02.example.com/whip/sora/<secret>
   S2-->>-O: HTTP 200 OK
   note over O,S2: WebRTC 終了
```


## TURN の利用

Sora はデフォルトで WHIP 利用時に `Link` ヘッダーに TURN URLs を払い出し、 **TURN のみの通信** を行います。 TURN の利用を無効にすることはできません。

> **注釈**
>
> 今後 TURN の仕組みを実装していないクライアント向けにシグナリングの query-string に `turn=false` を追加することで、TURN を無効にすることができるようにすることを検討しています。

### OBS Studio の TURN 機能

OBS Studio は 2024 年 7 月にリリースされた [OBS Studio 30.2](https://github.com/obsproject/obs-studio/releases/tag/30.2.0) で TURN に対応しており、Sora の WHIP は TURN を前提としているため、これより古い OBS Studio は利用できません。

> **警告**
>
> OBS Studio で WebRTC を実現している libdatachannel が利用している ICE ライブラリの [libjuice](https://github.com/paullouisageneau/libjuice) は、TURN-UDP のみに対応しています。そのため TURN-TCP や TURN-TLS には対応していません。

## 録画利用時の注意

- OBS Studio WHIP で H.264 を利用している場合、 x264 以外を利用することを推奨します


## クラスター利用時の挙動

クラスター利用時に、接続したノードが指定した `channel_id` の担当ノードではない場合、
担当ノードの TURN URLs を Link ヘッダーにて払い出します。

## シーケンス図

### 単独

```mermaid
sequenceDiagram
    participant O as "OBS Studio"
    participant S as Sora
    participant A as App
    O->>+S: HTTP POST https://sora.example.com/whip/<channel_id><br>Offer SDP
    S->>+A: 認証ウェブフック<br><br>"channel_id": "<channel_id>""role": "sendonly"
    A-->>-S: "allowed": true
    S-->>-O: HTTP 201 Created<br>Answer SDP
    Note left of S: このタイミングで Link ヘッダーで、<br>TURN URLs を払い出す
    note over O,S: ICE 確立
    note over O,S: DTLS 確立
    note over O,S: WebRTC 確立
    S->>+A: イベントウェブフック<br>"connection.created"
    A-->>-S: HTTP 200 OK
    O-)S: SRTP
    O-)S: SRTP
    O->>+S: HTTP DELETE https://sora.example.com/whip/<channel_id>/<secret>
    S-->>-O: HTTP 200 OK
    note over O,S: WebRTC 終了
```

### クラスターかつロードバランサー

クラスターを利用する場合、OBS Studio に設定する WHIP エンドポイントはロードバランサーが提供するエンドポイントをお勧めしています。

このシーケンス図では Sora が 2 ノードになっていますが、最低 3 ノード必要です。

```mermaid
sequenceDiagram
   participant O as "OBS Studio (WHIP)"
   participant B as ブラウザ
   participant LB as LB
   participant S1 as Sora 1
   participant S2 as Sora 2
   participant A as App
   B->>LB: WSS<br>https://sora.example.com/signaling<br>
   LB->>S1: WSS<br>https://node1.sora.example.com/signaling<br>
   note over B,S1: WebSocket 確立
   B->>+S1: WSS "type": "connect"
   S1->>+A: 認証ウェブフック<br>"channel_id": "sora"<br>"role": "recvonly"
   A-->>-S1: "allowed": true
   S1-)-B: "type": "offer"
   B-)S1: "type": "answer"
   note over B,S2: WebRTC 確立
   O->>+LB: HTTP POST<br>https://sora.example.com/whip/sora<br>Offer SDP
   LB->>+S2: HTTP POST<br>https://node2.sora.example.com/whip/sora<br>Offer SDP
   S2-->>-LB: HTTP 307 Temporary Redirect<br>location: https://node1.sora.example.com/whip/sora
   LB-->>-O: HTTP 307 Temporary Redirect<br>location: https://node1.sora.example.com/whip/sora
   O->>+LB: HTTP POST<br>https://node1.sora.example.com/whip/sora<br>Offer SDP
   LB->>+S1: HTTP POST<br>https://node1.sora.example.com/whip/sora<br>Offer SDP
   S1->>+A: 認証ウェブフック<br>"channel_id": "sora"<br>"role": "sendonly"
   A-->>-S1: "allowed": true
   S1-->>-LB:  HTTP 201 Created<br>Answer SDP
   LB-->>-O: HTTP 201 Created<br>Answer SDP
   %% Note left of S2: このタイミングで Link ヘッダーで、<br>TURN URLs を払い出す
   note over O,S2: WebRTC 確立
   S1->>+A: イベントウェブフック<br>"connection.created"
   A-->>-S1: HTTP 200 OK
   O-)S1: SRTP
   S1-)B: SRTP
   O-)S1: SRTP
   S1-)B: SRTP
   O->>+S1: HTTP DELETE<br>https://node2.sora.example.com/whip-resource/sora/<secret>
   S1-->>-O: HTTP 200 OK
   note over O,S2: WebRTC 終了
```
