# ICE コネクションステート機能

## 概要

ICE コネクションステート機能は Sora に ICE コネクションによる状態管理を持たせた機能です。

## 前提

この機能はクライアント側が意識する必要はありません。

## 挙動

Sora は WebRTC が確立した後に TURN 上で ICE コネクションステートを更新し続けます。
ステートの更新には `STUN Binding-Request` と `STUN Binding-Success` を利用します。

- Sora は 2.5 秒間隔で `STUN Binding-Request` をクライアントへ送ります- `STUN Binding-Success` が 2.5 秒以内に一度も返ってこない場合、状態を `connected` から `checking` へ遷移します
- 状態が `checking` へ遷移した場合、 Sora は 1 秒間隔で `STUN Binding-Request` をクライアントへ送ります- `STUN Binding-Success` が 5 秒以内に一度も返ってこない場合、状態を `checking` から `disconnected` へ遷移します
  - この 5 秒は `sora.conf` にて [default_ice_connection_state_disconnected_timeout](SORA_CONF.html#420a1e) で変更できます
  - さらに認証ウェブフック成功時の [ice_connection_state_disconnected_timeout_ms の払い出し](AUTH_WEBHOOK_RETURN.html#38a86f) で上書きできます
- 状態が `disconnected` に遷移した場合、 Sora は 50 ミリ秒間隔で `STUN Binding-Request` をクライアントへ送ります- `STUN Binding-Success` が 10 秒以内に一度も返ってこない場合、状態を `disconnected` から `failed` へ遷移します
  - この 10 秒は `sora.conf` にて [default_ice_connection_state_failed_timeout](SORA_CONF.html#d6f965) で変更できます
  - さらに認証ウェブフック成功時の [ice_connection_state_failed_timeout_ms の払い出し](AUTH_WEBHOOK_RETURN.html#1f5eb9) で上書きできます
  - このタイミングで `sora.jsonl` に `warning` として `ICE-CONNECTION-STATE-DISCONNECTED` が出力されます
- 状態が `failed` に遷移した場合、Sora はクライアントの接続を切断します- このタイミングで `sora.jsonl` に `error` として `ICE-CONNECTION-STATE-FAILED` が出力されます

## 設定

ICE コネクションステート機能は無効にすることはできません。

ただし、切断や失敗までの判定時間を `sora.conf` にてデフォルト値から変更できます。

### default_ice_connection_state_disconnected_timeout

この値は Sora が ICE コネクションステートを disconnected へと遷移する際にクライアントからの応答を待つ時間です。

デフォルトでは `5 s` が設定されています。

詳細は [default_ice_connection_state_disconnected_timeout](SORA_CONF.html#420a1e) をご確認ください。

### default_ice_connection_state_failed_timeout

この値は Sora が ICE コネクションステートを failed へと遷移する際にクライアントからの応答を待つ時間です。

デフォルトでは `10 s` が設定されています。

詳細は [default_ice_connection_state_failed_timeout](SORA_CONF.html#d6f965) をご確認ください。


## シグナリング通知

> **警告**
>
> この機能は実験的機能です。

シグナリング通知経由で、それぞれのクライアントの ICE コネクションステートの変更を送信する機能です。

この機能を有効にするには `sora.conf` の [signaling_notify_ice_connection_state](SORA_CONF.html#e65192) を `true` に設定してください。

機能を有効にした場合、ICE コネクションの状態変更時に、自分を含むチャネル参加者全員に対して、
シグナリング通知 `ice-connection-state.changed` が送信されるようになります。

さらに `connection.created` の `data` に `ice_connection_state` が含まれるようになり、
既にチャネルに参加しているクライアントの `ice_connection_state` を取得できるようになります。

### 認証成功時の `signaling_notify_ice_connection_state` の払い出し

シグナリング通知 `ice-connection-state.changed` を送信するかどうかは、
[signaling_notify_ice_connection_state](SORA_CONF.html#e65192) の値が採用されますが、
認証成功時の払い出しに `signaling_notify_ice_connection_state` を指定することで変更する事ができます。

> **注釈**
>
> [signaling_notify_ice_connection_state](SORA_CONF.html#e65192) を `false` に設定したとしても、
> 認証成功時の払い出しに `signaling_notify_ice_connection_state` を `true` で指定した場合は、
> シグナリング通知 `ice-connection-state.changed` が送信されます。

### シグナリング通知 `ice-connection-state.changed`

自分が接続した時は `connection.created` のシグナリング通知の後に、
シグナリング通知 `ice-connection-state.changed` が送信されます。

以下の 4 つのタイミングで通知がチャネルに参加している他のコネクションへ送信されます。

1. connected から checking になった時- `ice-connection-state.changed` で `current_state` に `checking` 、 `previous_state` に `connected` が入ります
2. checking から connected になった時- `ice-connection-state.changed` で `current_state` に `connected` 、 `previous_state` に `checking` が入ります
3. checking から disconnected になった時- `ice-connection-state.changed` で `current_state` に `disconnected` 、 `previous_state` に `checking` が入ります
4. disconnected から checking になった時- `ice-connection-state.changed` で `current_state` に `checking` 、 `previous_state` に `disconnected` が入ります

```javascript
{
  "connection_id": "JA0H99CB490C9EEV8AAVBNSBWG",
  "timestamp": "2024-10-15T01:04:50.039752Z",
  "type": "notify",
  "event_type": "ice-connection-state.changed",
  "current_state": "connected",
  "previous_state": "checking"
}
```

### `connection.created` の `data` の `ice_connection_state`

シグナリング通知 `connection.created` の `data` に `ice_connection_state` が含まれるようにするには、
`sora.conf` の [signaling_notify_ice_connection_state](SORA_CONF.html#e65192) を `true` に設定する必要があります。

```javascript
{
  // 色々省略
  "connection_id": "ZE6QPYMF1N4473AN1AH5KY6T3C",
  "data": [
    {
      "connection_id": "JA0H99CB490C9EEV8AAVBNSBWG",
      "timestamp": "2024-10-15T01:04:50.036927Z",
      "bundle_id": "JA0H99CB490C9EEV8AAVBNSBWG",
      "client_id": "JA0H99CB490C9EEV8AAVBNSBWG",
      // 既存参加者の ice_connection_state が含まれる
      "ice_connection_state": "connected"
    }
  ],
  "timestamp": "2024-10-15T01:05:17.317571Z",
  "type": "notify",
  "session_id": "HC3DTTQH1946DC9HYKAE2AAHS8",
  "role": "sendrecv",
  "event_type": "connection.created",
}
```

## 認証成功時の払い出し

Sora は、認証成功時のタイミングで `ice_connection_state_disconnected_timeout_ms` と `ice_connection_state_failed_timeout_ms` を認証サーバーから払い出すことができます。

### ice_connection_state_disconnected_timeout_ms の払い出し

ice_connection_state_disconnected_timeout_ms の値は `sora.conf` の [default_ice_connection_state_disconnected_timeout](SORA_CONF.html#420a1e) の値を上書きします。

```javascript
{
  "allowed": true,
  "ice_connection_state_disconnected_timeout_ms": 10000,
}
```

### ice_connection_state_failed_timeout_ms の払い出し

ice_connection_state_failed_timeout_ms の値は `sora.conf` の [default_ice_connection_state_failed_timeout](SORA_CONF.html#d6f965) の値を上書きします。

```javascript
{
  "allowed": true,
  "ice_connection_state_failed_timeout_ms": 20000,
}
```

## ウェブフック

コネクションの状態が `checking` と `disconnected` だった合計時間をイベントウェブフックで取得できます。

- 取得可能なイベントウェブフック- `connection.created`
  - `connection.updated`
  - `connection.destroyed`
- `data.ice_connection_state.total_checking_duration_ms` に `checking` だった合計時間(ミリ秒)の合計が入ります
- `data.ice_connection_state.total_disconnected_duration_ms` に `disconnected` だった合計時間(ミリ秒)の合計が入ります

```javascript
{
  // 色々省略してます
  "type": "connection.destroyed",
  "channel_id": "sora",
  "connection_id": "GS4Q8PQ5PS3EXC30T6PM2R7Y20",
  "timestamp": "2023-08-16T05:42:13.970729Z",
  "bundle_id": "GS4Q8PQ5PS3EXC30T6PM2R7Y20",
  "client_id": "GS4Q8PQ5PS3EXC30T6PM2R7Y20",
  "data": {
    "ice_connection_state": {
      "total_checking_duration_ms": 5002,
      "total_disconnected_duration_ms": 10002
    }
  }
}
```

## テスト

ICE コネクションステートのテストをしたい場合は [LockIceConnectionState](TEST_API.html#8b5622) API を利用してください。

## ステート図

> **重要**
>
> 図のタイムアウト値はデフォルト値を採用しています。

```mermaid
stateDiagram
    New --> Checking
    Checking --> Connected: 応答あり
    Checking --> Disconnected: 5 秒間応答なし
    Disconnected --> Failed: 10 秒間応答なし
    Connected --> Checking: 2.5 秒応答なし
    Disconnected --> Checking: 応答あり
    Connected --> Closed: 正常終了
```

## シーケンス図

> **重要**
>
> 図のタイムアウト値はデフォルト値を採用しています。

### connected

正常な接続状態である connected を継続しているシーケンス図です。

```mermaid
sequenceDiagram
    participant C as クライアント
    participant S as Sora
    note over C,S: WebRTC 確立
    note over S: ICE State connected
    S->>+C: STUN Binding-Request
    C-->>-S: STUN Binding-Success
    note left of S: 2.5 秒経過
    S->>+C: STUN Binding-Request
    C-->>-S: STUN Binding-Success
    note left of S: 2.5 秒経過
    S->>+C: STUN Binding-Request
    C-->>-S: STUN Binding-Success
```

### connected -> checking

正常な接続状態である connected から一時的に反応が無く checking 状態へ切り替わるシーケンス図です。

```mermaid
sequenceDiagram
    participant C as クライアント
    participant S as Sora
    note over C,S: WebRTC 確立
    note over S: ICE State connected
    S->>C: STUN Binding-Request
    note left of S: 2.5 秒経過したが反応がない
    note over S: ICE State checking
    S->>C: STUN Binding-Request
    note left of S: 1.0 秒経過
    S->>C: STUN Binding-Request
    note left of S: 1.0 秒経過
    S->>C: STUN Binding-Request
```

### checking -> disconnected

一時的に反応が無い checking の状態が続いたため、
切断判断をするために短い間隔で疎通パケットを送信する disconnected 状態へ切り替わるシーケンス図です。

```mermaid
sequenceDiagram
    participant C as クライアント
    participant S as Sora
    note over C,S: WebRTC 確立
    note over S: ICE State connected
    S->>C: STUN Binding-Request
    note left of S: 2.5 秒経過したが反応がない
    note over S: ICE State checking
    S->>C: STUN Binding-Request
    note left of S: 1.0 秒間隔で 5 秒間送り続けてるが反応がない
    note over S: ICE State disconnected
    S->>C: STUN Binding-Request
    note left of S: 50 ミリ秒
    S->>C: STUN Binding-Request
```

### disconnected -> failed

切断判断をするため短い間隔で疎通パケットを送り続けたが、反応が無かったため failed へと切り替わるシーケンス図です。

```mermaid
sequenceDiagram
    participant C as クライアント
    participant S as Sora
    note over C,S: WebRTC 確立
    note over S: ICE State connected
    S->>C: STUN Binding-Request
    note left of S: 2.5 秒経過したが反応がない
    note over S: ICE State checking
    S->>C: STUN Binding-Request
    note left of S: 1 秒間隔で 5 秒間送り続けてるが反応がない
    note over S: ICE State disconnected
    S->>C: STUN Binding-Request
    note left of S: 50 ミリ秒間隔で 10 秒間送り続けてるが反応がない
    note over S: ICE State failed
    note left of S: S はクライアントを切断したと見なし切断処理を行う
```

### disconnected -> checking -> connected

一定時間、不通になっていたため状態が disconnected になっていましたが、
checking を経て connected まで状態が戻るシーケンス図です。

```mermaid
sequenceDiagram
    participant C as クライアント
    participant S as Sora
    note over C,S: WebRTC 確立
    note over S: ICE State connected
    S->>C: STUN Binding-Request
    note left of S: 2.5 秒経過したが反応がない
    note over S: ICE State checking
    S->>C: STUN Binding-Request
    note left of S: 1 秒間隔で 5 秒間送り続けてるが反応がない
    note over S: ICE State disconnected
    S->>C: STUN Binding-Request
    note left of S: 50 ミリ秒間隔で 10 秒間送り続ける
    C-->>S: STUN Binding-Success
    note over S: ICE State checking
    S->>C: STUN Binding-Request
    note left of S: 1 秒間隔で 5 秒間送り続ける
    C-->>S: STUN Binding-Success
    note over S: ICE State connected
    S->>C: STUN Binding-Request
    note left of S: 2.5 秒間隔で送り続ける
    C-->>S: STUN Binding-Success
```
