# イベントウェブフック

## 概要

Sora は、予め設定しておいた URL に、シグナリングの接続や切断、
録画の終了といった様々なイベントを通知するウェブフックの機能を持っています。

この機能を使うことで、Sora のイベントをアプリケーション側と簡単に連携することが可能です。

## 注意

`sora.conf` の [event_webhook_url](SORA_CONF.html#e1a4d2) を有効にしない場合でも `log/event_webhook.log` は生成されます。

## 設定

### ウェブフック通知先のサーバーがベーシック認証を利用している場合

もしウェブフック通知先のサーバーがベーシック認証を利用している場合は `sora.conf` にて [webhook_basic_authn](SORA_CONF.html#081a9f) に `true` を設定することでベーシック認証を利用できます。

[webhook_basic_authn_user_id](SORA_CONF.html#a107fd) と [webhook_basic_authn_password](SORA_CONF.html#f70fe9) に使用するユーザー ID とパスワードを設定して下さい。

### ウェブフック通知先のサーバーが自己署名証明書などを利用している場合

**この設定はおすすめしません**

デフォルトでは自己署名証明書などの正規の認証局から発行されていない証明書を利用した場合には、信頼できないと判断しエラーになります。

もし自己署名証明書を利用したサーバーがウェブフックの通知先になる場合は、
`sora.conf` にて [webhook_insecure](SORA_CONF.html#676769) に `true` を設定することで証明書のチェックを行わないようになります。

### event_webhook_url

**デフォルト**: 未設定

イベント通知の送り先の URL です。イベントウェブフック機能を利用する場合は指定してください。

この URL には HTTPS の URL を指定することも可能です。

HTTPS の URL を指定する場合は、通知先のアプリケーションには正規の認証局から発行された証明書を利用してください。

HTTP のレスポンスは 200 OK 等の 200 番台のステータスコードの必要があります。

## HTTP ヘッダー

> **注釈**
>
> JSON のパース時の判断などに利用してください。

イベントウェブフックの HTTP ヘッダー に `x-sora-event-webhook-type` というヘッダー名でイベントウェブフックのタイプが入ってきます。

`type` が `connection.created` の場合は `x-sora-event-webhook-type: connection.created` のように値が入ってきます。

## 接続イベント

- `connection.created` と `connection.destroyed` はセットです。
- `connection.created` が通知されずに `connection.destroyed` が通知されることはありません。
- `connection.created` が通知された場合、 `connection.destroyed` が **必ず** 通知されます。
- `connection.created` の後に `connection.destroyed` が通知されます。順番は保証されます。

### 共通項目

- id- イベント毎の ID です
- version- Sora のバージョンが `文字列` で入ってきます
- label- sora.conf の label で指定した値が入ってきます
- node_name- Sora のノード名が入ってきます
- minutes- 接続経過時間 (分) が入ってきます
- created_time- connection.created 時の時間が UNIX 時間形式で入ってきます
- created_timestamp- connection.created 時の時間が RFC 3339 UTC 形式 (マイクロ秒) で入ってきます
- total_received_bytes- Sora がクライアントから受信したパケットの合計数です
- total_sent_bytes- Sora がクライアントへ送信したパケットの合計数です
- turn_transport_type- udp か tcp が入ってきます
  - TURN-UDP または TURN-TCP (TURN-TLS 含む) のどちらを使用したかがわかります
- audio- false の場合は audio を使用しません
  - コーデックやビットレートが入ってくる場合は {"codec_type": "OPUS", "bit_rate": 32} が入ってきます
  - コーデックの種類は OPUS です
  - ビットレートはクライアントが送ってこない場合は含まれません- もし default_audio_bit_rate に値を指定していた場合はその値が使用されます
    - 最小が 6 で、最大が 510 です
- video- false の場合は video を使用しません
  - コーデックやビットレートが入ってくる場合は {"codec_type": "VP9", "bit_rate": 100} が入ってきます- コーデックの種類は VP8、VP9、H264 の 3 種類です
    - ビットレートはクライアントが送ってこない場合は `sora.conf` の [default_video_bit_rate](SORA_CONF.html#620132) が使用されます- デフォルトは 500 です
      - 最小が 1 で、最大が 30000 です
      - 15000 より大きい値は現時点でサポート外です
- multistream- true の場合はマルチストリームが有効な接続です
- simulcast- true の場合はサイマルキャストが有効な接続です
- spotlight- true の場合はスポットライトが有効な接続です
- role- `sendrecv` (送受信) / `sendonly` (送信のみ) / `recvonly` (受信のみ)
- event_metadata- この項目はオプションです
  - サーバーが定義を自由にできる値です
  - 認証サーバーから event_metadata を返した値が含まれます
  - 詳細は [event_metadata の払い出し](AUTH_WEBHOOK_RETURN.html#8b1b1f) をご確認ください
- channel_id- コネクションが接続しているチャネル ID です
- session_id- コネクションが接続しているチャネル の現在のセッションの ID です
  - UUIDv4 を Base32 でエンコードした 26 バイトの文字列です
- client_id- コネクションに割り当てられたクライアント ID です
- bundle_id- コネクションに割り当てられたバンドル ID です
- connection_id- コネクションに割り当てられたユニークな ID です
  - UUIDv4 を Base32 でエンコードした 26 バイトの文字列です


### connection.created

**接続通知**

シグナリングの接続が成功して、WebRTC としての通信が開始可能になった状態を通知します。

- data.channel_connections- 現在そのチャネルに接続しているクライアントの接続数です
  - 自分は含まれません
- data.channel_sendrecv_connections- 現在そのチャネルで送受信している配信者の接続数です
  - 自分は含まれません
- data.channel_sendonly_connections- 現在そのチャネルを送信のみしている配信者の接続数です
  - 自分は含まれません
- data.channel_recvonly_connections- 現在そのチャネルを受信のみしている視聴者の接続数です
  - 自分は含まれません

```json
{
  "type": "connection.created",
  "channel_id": "sora",
  "sesison_id": "<Base32-UUIDv4>",
  "bundle_id": "<Base32-UUIDv4 または指定した文字列>",
  "connection_id": "<Base32-UUIDv4>",
  "timestamp": "<UTC RFC3339 Timestamp>",
  "client_id": "<Base32-UUIDv4 または指定した文字列>",
  "event_metadata": "<JSON Object>",
  "data": {
    "created_time": "<UNIX-Time>",
    "created_timestamp": "<UTC RFC3339 Timestamp>",
    "audio": {
      "codec_type": "OPUS"
    },
    "channel_connections": "<Intger>",
    "channel_recvonly_connections": "<Intger>",
    "channel_sendonly_connections": "<Intger>",
    "channel_sendrecv_connections": "<Intger>",
    "minutes": 0,
    "total_received_bytes": 0,
    "total_sent_bytes": 0,
    "turn_transport_type": "tcp",
    "video": {
      "bit_rate": 500,
      "codec_type": "VP9"
    }
  },
  "id": "<Base32-UUIDv4>",
  "label": "WebRTC SFU Sora",
  "multistream": false,
  "node_name": "node1@192.0.2.10",
  "role": "sendonly",
  "simulcast": false,
  "spotlight": false,
  "version": "2022.1"
}
```


### connection.destroyed

**切断通知**

シグナリングの接続が切断したことを通知します。

- data.type_disconnect_reason- `"type": "disconnect"` 送信時に `"reason"` に指定した **文字列** が入ります
  - `"reason"` を指定していなかった場合、この項目は含まれません
- data.disconnect_api_reason- DisconnectChannel API または Disconnect API を利用して切断した際、オプションの `"reason"` に指定した **JSON オブジェクト** がこの `"reason"` に含まれます
  - `"reason"` を指定していなかった場合、この項目は含まれません
- data.reason- 基本的には `data.disconnect_api_reason` と同様です
  - ただし `"reason"` を指定していなかった場合に、項目が省略されるのではなく、値に null が入る点が異なっています
- data.channel_connections- 現在そのチャネルに接続しているクライアントの接続数です
  - 自分は含まれません
- data.channel_sendrecv_connections- 現在そのチャネルで送受信している配信者の接続数です
  - 自分は含まれません
- data.channel_sendonly_connections- 現在そのチャネルを送信のみしている配信者の接続数です
  - 自分は含まれません
- data.channel_recvonly_connections- 現在そのチャネルを受信のみしている視聴者の接続数です
  - 自分は含まれません
- data.destroyed_time- connection.destroyed 時の時間が UNIX 時間形式で入ってきます
- data.destroyed_timestamp- connection.destroyed 時の時間が RFC 3339 UTC 形式 (マイクロ秒) で入ってきます

```json
{
  "type": "connection.destroyed",
  "channel_id": "sora",
  "sesison_id": "RH87Z6K7H135KE8BG5Z09TTBTM",
  "bundle_id": "FW0CJSHETX0RXAGX8WWEXNBQN8",
  "connection_id": "FW0CJSHETX0RXAGX8WWEXNBQN8",
  "timestamp": "<UTC RFC3339 Timestamp>",
  "client_id": "<Base32-UUIDv4 または指定した文字列>",
  "event_metadata": "<JSON Object>",
  "data": {
    "created_time": "<UNIX-Time>",
    "created_timestamp": "<UTC RFC3339 Timestamp>",
    "destroyed_time": "<UNIX-Time>",
    "destroyed_timestamp": "<UTC RFC3339 Timestamp>",
    "audio": {
      "codec_type": "OPUS"
    },
    "channel_connections": 0,
    "channel_recvonly_connections": 0,
    "channel_sendonly_connections": 0,
    "channel_sendrecv_connections": 0,
    "minutes": 1,
    "reason": null,
    "type_disconnect_reason": "NO-ERROR",
    "total_received_bytes": 6501144,
    "total_sent_bytes": 8482,
    "turn_transport_type": "tcp",
    "video": {
      "bit_rate": 500,
      "codec_type": "VP9"
    }
  },
  "id": "M9AF614GC97EZ3YNFWSBE2WN8R",
  "label": "WebRTC SFU Sora",
  "multistream": false,
  "node_name": "node1@192.0.2.10",
  "role": "sendonly",
  "simulcast": false,
  "spotlight": false,
  "version": "2022.1.0"
}
```


### connection.updated

**接続状態更新通知**

接続したタイミングから、クライアント毎の接続状態が、それぞれ 1 分間に 1 回送られてきます。

- data.channel_connections- 現在そのチャネルに接続しているクライアントの接続数です
  - 自分が含まれます
- data.channel_sendrecv_connections- 現在そのチャネルで送受信している配信者の接続数です
  - 自分が含まれます
- data.channel_sendonly_connections- 現在そのチャネルを送信のみしている配信者の接続数です
  - 自分が含まれます
- data.channel_recvonly_connections- 現在そのチャネルを受信のみしている視聴者の接続数です
  - 自分が含まれます

```json
{
  "type": "connection.updated",
  "channel_id": "sora",
  "sesison_id": "RH87Z6K7H135KE8BG5Z09TTBTM",
  "bundle_id": "FW0CJSHETX0RXAGX8WWEXNBQN8",
  "connection_id": "FW0CJSHETX0RXAGX8WWEXNBQN8",
  "timestamp": "2022-12-07T05:54:41.766169Z",
  "client_id": "FW0CJSHETX0RXAGX8WWEXNBQN8",
  "event_metadata": "<JSON>",
  "data": {
    "audio": {
      "codec_type": "OPUS"
    },
    "channel_connections": 1,
    "channel_recvonly_connections": 0,
    "channel_sendonly_connections": 1,
    "channel_sendrecv_connections": 0,
    "created_time": "<UNIX-Time>",
    "created_timestamp": "<UTC RFC3339 Timestamp>",
    "minutes": 1,
    "total_received_bytes": 4396378,
    "total_sent_bytes": 5686,
    "turn_transport_type": "tcp",
    "video": {
      "bit_rate": 500,
      "codec_type": "VP9"
    }
  },
  "id": "8PKRS4RAMX6H97ZZM33Q745TM8",
  "label": "WebRTC SFU Sora",
  "multistream": false,
  "node_name": "node1@192.0.2.10",
  "role": "sendonly",
  "simulcast": false,
  "spotlight": false,
  "version": "2022.1.0"
}
```


### connection.failed

**失敗通知**

> **重要**
>
> この通知を有効にする場合は、 `sora.conf` にて [ignore_connection_failed_webhook](SORA_CONF.html#45096a) を無効にする必要があります。

シグナリングが失敗したり、異常が起きたりした場合に通知されます。

```json
{
    "type": "connection.failed",
    "id": "<Base32-UUIDv4>",
    "role": "<sendrecv | sendonly | recvonly>",
    "channel_id": "<String>",
    "client_id": "<String or Base32-UUIDv4>",
    "bundle_id": "<String or Base32-UUIDv4>",
    "connection_id": "<Base32-UUIDv4>",
    "timestamp": "<UTC RFC3339 Timestamp>",
    "data": {
        "message": "<String>",
        "channel_connections": "<Integer>",
        "channel_sendrecv_connections": "<Integer>",
        "channel_sendonly_connections": "<Integer>",
        "channel_recvonly_connections": "<Integer>",
        "total_received_bytes": "<Integer>",
        "total_sent_bytes": "<Integer>"
    },
    "label": "<String>",
    "multistream": "<Boolean>",
    "node_name": "node1@192.0.2.10",
    "simulcast": "<Boolean>",
    "spotlight": "<Boolean>",
    "version": "<String>"
}
```

## 録画・録音イベント


### recording.report

> **重要**
>
> このイベントには `event_metadata` は含まれません

**録画報告通知**

- data.archives[].start_time_offset- StartRecording API を叩いてから何秒経過した後にこの録画が開始したかを表しています
- data.archives[].stop_time_offset- StartRecording API を叩いてから何秒経過した後にこの録画が終了したかを表しています
- data.metadata_filename- 2022 年 12 月リリースの Sora にて廃止されます
  - data.filename を利用してください
- data.metadata_file_path- 2022 年 12 月リリースの Sora にて廃止されます
  - data.file_path を利用してください
- data.metadata- StartRecording API で指定した metadata が入ります

#### 一括録画時 recording.report

```json
{
    "type": "recording.report",
    "id": "<Base32-UUIDv4>",
    "version": "<String>",
    "label": "<String>",
    "node_name": "<String>",
    "channel_id": "<String>",
    "timestamp": "<UTC RFC3339 Timestamp>",
    "data": {
        "channel_id": "<String>",
        "recording_id": "<Base32-UUIDv4>",
        "metadata": "<JSON-Object>",
        "split_only": "<Boolean>",
        "created_at": "<UNIX-Time>",
        "expire_time": "<Integer>",
        "expired_at": "<Integer>",
        "file_path": "<String>",
        "filename": "<String>",
        "metadata_file_path": "<String>",
        "metadata_filename": "<String>",
        "archives": [
            {
                "label": "<String>",
                "node_name": "<String>",
                "client_id": "<String or Base32-UUIDv4>",
                "bundle_id": "<String or Base32-UUIDv4>",
                "connection_id": "<Base32-UUIDv4>",
                "filename": "<String>",
                "file_path": "<String>",
                "metadata_file_path": "<String>",
                "metadata_filename": "<String>",
                "start_time_offset": "<Integer>",
                "start_timestamp": "<UTC RFC3339 Timestamp>",
                "stop_time_offset": "<Integer>",
                "stop_timestamp": "<UTC RFC3339 Timestamp>",
                "size": "<Integer>"
            },
            {
                "label": "<String>",
                "node_name": "<String>",
                "client_id": "<String or Base32-UUIDv4>",
                "bundle_id": "<String or Base32-UUIDv4>",
                "connection_id": "<Base32-UUIDv4>",
                "filename": "<String>",
                "file_path": "<String>",
                "metadata_file_path": "<String>",
                "metadata_filename": "<String>",
                "start_time_offset": "<Integer>",
                "start_timestamp": "<UTC RFC3339 Timestamp>",
                "stop_time_offset": "<Integer>",
                "stop_timestamp": "<UTC RFC3339 Timestamp>",
                "size": "<Integer>"
            }
        ]
    }
}
```

#### 分割録画時 recording.report

```json
{
    "type": "recording.report",
    "id": "<Base32-UUIDv4>",
    "version": "<String>",
    "label": "<String>",
    "node_name": "<String>",
    "channel_id": "<String>",
    "timestamp": "<UTC RFC3339 Timestamp>",
    "data": {
        "channel_id": "<String>",
        "recording_id": "<Base32-UUIDv4>",
        "metadata": "<JSON-Object>",
        "split_only": "<Boolean>",
        "split_duration": "<Integer>",
        "created_at": "<UNIX-Time>",
        "expire_time": "<Integer>",
        "expired_at": "<Integer>",
        "file_path": "<String>",
        "filename": "<String>",
        "metadata_file_path": "<String>",
        "metadata_filename": "<String>",
        "archives": [
            {
                "label": "<String>",
                "node_name": "<String>",
                "client_id": "<String or Base32-UUIDv4>",
                "bundle_id": "<String or Base32-UUIDv4>",
                "connection_id": "<Base32-UUIDv4>",
                "start_time_offset": "<Integer>",
                "start_timestamp": "<UTC RFC3339 Timestamp>",
                "stop_time_offset": "<Integer>",
                "stop_timestamp": "<UTC RFC3339 Timestamp>",
                "split_last_index": "<String>"
            },
            {
                "label": "<String>",
                "node_name": "<String>",
                "client_id": "<String or Base32-UUIDv4>",
                "bundle_id": "<String or Base32-UUIDv4>",
                "connection_id": "<Base32-UUIDv4>",
                "start_time_offset": "<Integer>",
                "start_timestamp": "<UTC RFC3339 Timestamp>",
                "stop_time_offset": "<Integer>",
                "stop_timestamp": "<UTC RFC3339 Timestamp>",
                "split_last_index": "<String>"
            }
        ]
    }
}
```

## 録画・録音保存イベント


### archive.available

**録画保存したファイルが利用可能になった通知**

- data.start_timestamp- この録画が開始された時間 (UTC) を RFC 3339 形式 (マイクロ秒) で表しています
- data.stop_timestamp- この録画が終了した時間(UTC) を RFC 3339 形式 (マイクロ秒) で表しています
- data.start_time- この録画が開始された時間を UNIX 時間形式で表しています
- data.stop_time- この録画が終了した時間を UNIX 時間形式で表しています
- data.start_time_offset- StartRecording API を叩いてから何秒経過した後にこの録画が開始したかを表しています
- data.stop_time_offset- StartRecording API を叩いてから何秒経過した後にこの録画が終了したかを表しています
- data.stats- サポート向けに、録画に使用したパケット情報の統計を格納しています
  - 内部向け情報のため、予告なく変更されることがあります

```json
{
    "type": "archive.available",
    "id": "<Base32-UUIDv4>",
    "version": "<String>",
    "label": "<String>",
    "node_name": "<String>",
    "channel_id": "<String>",
    "client_id": "<String or Base32-UUIDv4>",
    "bundle_id": "<String or Base32-UUIDv4>",
    "connection_id": "<Base32-UUIDv4>",
    "timestamp": "<UTC RFC3339 Timestamp>",
    "event_metadata": "<JSON>",
    "data": {
        "channel_id": "<String>",
        "recording_id": "<Base32-UUIDv4>",
        "client_id": "<String or Base32-UUIDv4>",
        "bundle_id": "<String or Base32-UUIDv4>",
        "connection_id": "<Base32-UUIDv4>",
        "created_at": "<Unix Time>",
        "filename": "<String>",
        "file_path": "<String>",
        "metadata_filename": "<String>",
        "metadata_file_path": "<String>",
        "size": "<Integer>",
        "audio": {
            "codec_type": "<String>"
        },
        "video": {
            "codec_type": "<String>",
            "bit_rate": "<Integer>",
            "height": "<Integer>",
            "width": "<Integer>"
        },
        "stats": {},
        "start_time": "<Unix Time>",
        "start_time_offset": "<Integer>",
        "start_timestamp": "<UTC RFC3339 Timestamp>",
        "stop_time": "<Unix Time>",
        "stop_time_offset": "<Integer>",
        "stop_timestamp": "<UTC RFC3339 Timestamp>",
    }
}
```


### split-archive.available

**分割された録画ファイルが利用可能になった通知**

- data.split_index- 分割された録画ファイルのインデックス
  - 0001 から始まり 9999 までいったら、その後は 10000, 10001 と増えていきます
- data.start_timestamp- 分割して出力された録画ファイルを開始された時間 (UTC) を RFC 3339 形式 (マイクロ秒) で表しています
- data.stop_timestamp- 分割して出力された録画ファイルを終了した時間 (UTC) を RFC 3339 形式 (マイクロ秒) で表しています
- data.start_time- 分割して出力された録画ファイルを開始した時間を UNIX 時間形式で表しています
- data.stop_time- 分割して出力された録画ファイルを終了した時間を UNIX 時間形式で表しています
- data.stats- サポート向けに、録画に使用したパケット情報の統計を格納しています
  - 内部向け情報のため、予告なく変更されることがあります

```json
{
    "type": "split-archive.available",
    "id": "<Base32-UUIDv4>",
    "version": "<String>",
    "label": "<String>",
    "channel_id": "<String>",
    "client_id": "<String or Base32-UUIDv4>",
    "bundle_id": "<String or Base32-UUIDv4>",
    "connection_id": "<Base32-UUIDv4>",
    "timestamp": "<UTC RFC3339 Timestamp>",
    "event_metadata": "<JSON>",
    "data": {
        "channel_id": "<String>",
        "recording_id": "<Base32-UUIDv4>",
        "split_index": "0001",
        "client_id": "<String or Base32-UUIDv4>",
        "bundle_id": "<String or Base32-UUIDv4>",
        "connection_id": "<Base32-UUIDv4>",
        "created_at": "<Unix Time>",
        "filename": "<String>",
        "file_path": "<String>",
        "metadata_filename": "<String>",
        "metadata_file_path": "<String>",
        "size": "<Integer>",
        "video": {
            "codec_type": "<String>",
            "bit_rate": "<Integer>",
            "height": "<Integer>",
            "width": "<Integer>"
        },
        "audio": {
            "codec_type": "<String>"
        },
        "stats": {
        },
        "start_time": "<Unix Time>",
        "start_timestamp": "<UTC RFC3339 Timestamp>",
        "stop_time": "<Unix Time>",
        "stop_timestamp": "<UTC RFC3339 Timestamp>",
    }
}
```

> **注釈**
>
> stats は省略しています


### split-archive.end

**分割された録画が終了した通知**

- data.start_time- 録画を開始した UNIX 時間形式で表しています
- data.stop_time- 録画を終了した UNIX 時間形式で表しています
- data.start_timestamp- 録画を開始した時間 (UTC) を RFC 3339 形式 (マイクロ秒) で表しています
- data.stop_timestamp- 録画を終了した時間 (UTC) を RFC 3339 形式 (マイクロ秒) で表しています
- data.stats- サポート向けに、録画に使用したパケット情報の統計を格納しています
  - 内部向け情報のため、予告なく変更されることがあります

```json
{
    "type": "split-archive.end",
    "id": "<Base32-UUIDv4>",
    "version": "<String>",
    "label": "<String>",
    "node_name": "<String>",
    "channel_id": "<String>",
    "client_id": "<String or Base32-UUIDv4>",
    "bundle_id": "<String or Base32-UUIDv4>",
    "connection_id": "<Base32-UUIDv4>",
    "timestamp": "<UTC RFC3339 Timestamp>",
    "event_metadata": "<JSON>",
    "data": {
        "split_last_index": "0001",
        "recording_id": "<Base32-UUIDv4>",
        "channel_id": "<String>",
        "client_id": "<String or Base32-UUIDv4>",
        "bundle_id": "<String or Base32-UUIDv4>",
        "connection_id": "<Base32-UUIDv4>",
        "video": {
            "codec_type": "<String>",
            "bit_rate": "<Integer>",
            "height": "<Integer>",
            "width": "<Integer>"
        },
        "audio": {
            "codec_type": "<String>",
            "bit_rate": "<Integer>"
        },
        "filename": "<String>",
        "file_path": "<String>",
        "stats": {},
        "start_time": "<Unix Time>",
        "start_timestamp": "<UTC RFC3339 Timestamp>",
        "stop_time": "<Unix Time>",
        "stop_timestamp": "<UTC RFC3339 Timestamp>",
    }
}
```


### archive.failed

**録画ファイル保存失敗通知**

```json
{
    "type": "archive.failed",
    "id": "<Base32-UUIDv4>",
    "version": "<String>",
    "label": "<String>",
    "node_name": "<String>",
    "timestamp": "<UTC RFC3339 Timestamp>",
    "channel_id": "<String>",
    "client_id": "<String or Base32-UUIDv4>",
    "bundle_id": "<String or Base32-UUIDv4>",
    "connection_id": "<Base32-UUIDv4>",
    "event_metadata": "<JSON>",
    "data": {
        "recording_id": "<Base32-UUIDv4>",
        "filename": "<String>",
        "file_path": "<String>",
        "video": {
            "codec_type": "<String>",
            "bit_rate": "<Integer>",
            "height": "<Integer>",
            "width": "<Integer>"
        },
        "audio": {
            "codec_type": "<String>"
        },
        "stats": {},
        "start_time": "<Unix Time>",
        "start_timestamp": "<UTC RFC3339 Timestamp>",
        "stop_time": "<Unix Time>",
        "stop_timestamp": "<UTC RFC3339 Timestamp>",
    }
}
```

## スポットライト機能

> **警告**
>
> スポットライト機能は実験的機能のため、正式版では仕様が変更される可能性があります


### spotlight.focused

**フォーカス通知**

フォーカスされた際にウェブフックが飛びます。

```json
{
  "type": "spotlight.focused",
  "channel_id": "sora",
  "bundle_id": "N5D19GJQX55PXC7VX31A05MZKC",
  "connection_id": "N5D19GJQX55PXC7VX31A05MZKC",
  "timestamp": "2022-12-08T06:21:04.130449Z",
  "audio": true,
  "client_id": "N5D19GJQX55PXC7VX31A05MZKC",
  "fixed": false,
  "id": "J35J78WGXS4NX77MYQWTEWEGNM",
  "label": "WebRTC SFU Sora",
  "version": "2022.1.0",
  "video": true
}
```


### spotlight.unfocused

**フォーカス解除通知**

フォーカスが外れた際にウェブフックが飛びます。

```json
{
  "type": "spotlight.unfocused",
  "channel_id": "sora",
  "bundle_id": "8JTV2Q53WS56Z3K19HDAV4QN1C",
  "connection_id": "8JTV2Q53WS56Z3K19HDAV4QN1C",
  "timestamp": "2022-12-08T06:21:04.142833Z",
  "audio": true,
  "client_id": "8JTV2Q53WS56Z3K19HDAV4QN1C",
  "id": "VSXG27VYZH7VXDQKB2XNW1HZN0",
  "label": "WebRTC SFU Sora",
  "version": "2022.1.0",
  "video": true
}
```


## シーケンス図


### connection.*

seqdiag {
    default_fontsize = 15;
    edge_length = 250;

    === 認証成功 ===

    クライアント <<- Sora [label = '"type": "offer"'];
    クライアント ->> Sora [label = '"type": "answer"', noactivate];

    === WebRTC 確立 ===

        Sora -> アプリケーションサーバー [label = 'イベントウェブフック\n"type": "connection.created"'];
        Sora <-- アプリケーションサーバー [label = '200 OK'];

    ... 接続から 1 分経過 ...

        Sora -> アプリケーションサーバー [label = 'イベントウェブフック\n"type": "connection.updated"'];
        Sora <-- アプリケーションサーバー [label = '200 OK'];

    クライアント ->> Sora [label = '"type": "disconnect"', noactivate];

        Sora -> アプリケーションサーバー [label = 'イベントウェブフック\n"type": "connection.destroyed"'];
        Sora <-- アプリケーションサーバー [label = '200 OK'];

    クライアント <<- Sora [label = 'WebSocket Close'];
}


### event_metadata

seqdiag {
    default_fontsize = 15;
    edge_length = 250;

    クライアント ->> Sora [label = '"type": "connect"'];
        Sora -> アプリケーションサーバー [label = '認証ウェブフック'];
        Sora <-- アプリケーションサーバー [label = '200 OK\n"allowed": true,\n"event_metadata": {"pk": 1}'];
    クライアント <<- Sora [label = '"type": "offer"'];
    クライアント ->> Sora [label = '"type": "answer"', noactivate];

    === WebRTC 確立 ===

        Sora -> アプリケーションサーバー [label = 'イベントウェブフック\n"type": "connection.created",\n"event_metadata": {"pk": 1}'];
        Sora <-- アプリケーションサーバー [label = '200 OK'];

    ... 接続から 1 分経過 ...

        Sora -> アプリケーションサーバー [label = 'イベントウェブフック\n"type": "connection.updated",\n"event_metadata": {"pk": 1}'];
        Sora <-- アプリケーションサーバー [label = '200 OK'];

    クライアント ->> Sora [label = '"type": "disconnect"', noactivate];

        Sora -> アプリケーションサーバー [label = 'イベントウェブフック\n"type": "connection.destroyed",\n"event_metadata": {"pk": 1}'];
        Sora <-- アプリケーションサーバー [label = '200 OK'];

    クライアント <<- Sora [label = 'WebSocket Close'];
}
