# 転送フィルター機能

> **注釈**
>
> 転送とは Sora がクライアントから受信した音声や映像を他のクライアントに送信することを意味します。

## 概要

転送フィルター機能は、Sora 側でクライアントへ転送する音声や映像のパケットをフィルターする機能です。

## 目的

転送フィルター機能を使うことで、Sora から音声や映像のパケットをクライアントへ転送しなくなるため、
クライアントやサーバー側の負荷を減らすことができます。

また、接続直後に音声や映像を転送しなくすることもできます。
そのため、何らかのアクションを取ってから音声と映像を流し始めることができるようになります。

## 注意

### 利用可能なロール

この機能は `role` が `sendrecv` または `recvonly` の場合にのみ利用できます。

### データチャネルを利用したメッセージング

データチャネルを利用したメッセージング機能は転送フィルター機能の対象外です。

## 機能

> **注釈**
>
> チャネル単位、コネクション単位でフィルターが設定できます。

- 転送フィルターのルール指定は、チャネル単位、コネクション単位で指定できます
- 転送フィルターのルールにはコネクション ID とクライアント ID と種類 (音声、映像) が指定できます
- **転送フィルタールール** に指定するコネクション ID は 音声や映像の **送信元の** コネクション ID です。
- **転送フィルタールール** に指定するクライアント ID は 音声や映像の **送信元の** クライアント ID です。
- シグナリング指定時や認証成功時に **そのコネクションに対するフィルター** を指定できます
- 転送フィルター更新時に転送フィルターのバージョンを確認し、一致した場合のみ更新することができます
- 転送フィルターにメタデータを持たせることができます


## 転送フィルタールールの仕様

シグナリング、認証成功時の払い出し、セッション払い出し、API で共通のフィルタールールについて説明します。

フィルターは AND と OR が指定できます。ルールはリストとオブジェクトを利用して設定します。

> **重要**
>
> 転送フィルターのルールでは転送先のコネクション ID やクライアント ID を指定することはできません。
> 指定できるのは Sora に音声や映像を送信しているコネクションやクライアントの ID のみです。

### チャネル単位でフィルターを設定する

[CreateChannelForwardingFilter](API_FORWARDING_FILTER.html#fe98d1) API またはセッション生成時の払い出しを利用することで、
指定したチャネルに参加している **すべてのコネクションへ音声や映像を送信するかどうか** を設定できます。

### コネクション単位でフィルター設定する

[CreateConnectionForwardingFilter](API_FORWARDING_FILTER.html#d80a51) API 、シグナリング接続時の指定、または認証成功時の払い出しを利用することで、
指定したチャネルの **指定したコネクションへ音声や映像を送信するかどうか** を設定できます。

特定のコネクションに対してあるコネクションの映像を送りたくないなどができるようになります。

### 1 チャネルや 1 コネクションに複数の転送フィルターを設定する

複数のフィルターを設定したい場合は [マルチ転送フィルター機能](MULTI_FORWARDING_FILTER.html) をご確認ください。

### OR と AND

トップレベルリストは OR を表しており、リストのリストでは AND を表しています。

`[[rule_1], [rule_2, rule_3]]`

この場合は `(rule_1 OR (rule_2 AND rule_3))` という転送フィルタールールが適用されます。

`[[rule_1, rule_2]]`

この場合は `(rule_1 AND rule_2)` という転送フィルタールールが適用されます。

> **警告**
>
> `[[[rule_1, rule_2], [rule_3]], [rule_5]]` のような 3 階層のルールは定義できません。
> 転送フィルターのルールで利用できるリストの階層は 2 階層までとなります。

### action について

転送フィルターには `action` を指定できます。

アクションには `block` と `allow` が指定できます。

- `block` を指定した場合は、 rules にマッチした条件でのみ転送をブロックします
- `allow` を指定した場合は、 rules にマッチした条件でのみ転送を許可します

デフォルトでは `block` になります。

> **重要**
>
> `block` と `allow` では `allow` が優先されます。
> * チャネルで `block` 、コネクションで `allow` が指定されていた場合、コネクションの `allow` のみが適用されます
> * チャネルで `allow` 、コネクションで `block` が指定されていた場合、チャネルの `allow` のみが適用されます
> * チャネルで `allow` 、コネクションで `allow` が指定されていた場合、両方の `allow` が適用されます

#### ケース 1

チャネル単位の転送フィルターでは映像を `block` にして設定している状態で、
ある接続の転送フィルターでは映像を `allow` に設定した場合、
その接続では `allow` の転送フィルターだけが有効になり、その接続に映像が転送されます。

#### ケース 2

チャネル単位の転送フィルターでは映像を `allow` にして設定している状態で、
ある接続の転送フィルターでは音声を `allow` に設定した場合、
その接続には音声と映像が転送されます。

### version について

転送フィルターに文字列でバージョンを `version` 項目で指定することができます。これはオプションです。

転送フィルター作成時に `version` を指定した場合、
転送フィルターを更新するには `expected_version` と `desired_version` を指定する必要があります。

`expected_version` は更新する転送フィルターの `version` を指定します。
転送フィルターのバージョンが異なった場合、転送フィルターの更新は失敗します。

転送フィルターのバージョンが一致した場合、転送フィルターの更新は成功します。
`desired_version` の値が、新しい `version` の値となります。

`version` を利用することで転送フィルターを並列で実行されても期待した値に変更することができるようになります。

### metadata について

転送フィルターにはメタデータを `metadata` 項目を指定することができます。これはオプションです。

転送フィルター作成、または更新時に `metadata` に JSON 値を指定することができます。
この `metadata` は転送フィルターの挙動には影響せず、転送フィルターの情報を自由に書き込める項目です。

`metadata` を利用することで転送フィルターに関する情報を自由に管理することができるようになります。

### rules の書き方

**すべての項目は必須です**

- field- フィールドには `connection_id` と `client_id` と `kind` が指定できます
  - `connection_id`- フィルターの対象となる音声や映像の **送信元の** コネクション ID を指定してください
  - `client_id`- フィルターの対象となる音声や映像の **送信元の** クライアント ID を指定してください
  - `kind`- フィルターに音声や映像を指定できます
- operator- オペレーターには `is_in` と `is_not_in` が指定できます
  - `is_in`- values に指定されたリストに含まれる値にマッチしている場合は転送フィルターの対象とする
  - `is_not_in`- values に指定されたリストに含まれる値にマッチしていない場合は転送フィルターの対象とする
- values- バリューにはかならず文字列のリスト `["string", ...]` を指定してください
  - `field` に合った値を指定してください
  - `field` が `kind` の場合は `"audio"` または `"video"` を指定してください

```javascript
{
  "action": "block",
  "rules": [
    // チャネルに接続しているすべてのクライアントへ connection_id "S8YEN0TSE13JDC2991NG4XZ150" からの音声と映像をブロックし転送しない
    // また
    // チャネルに接続しているすべてのクライアントへ client_id が "screen-share" の音声をブロックし転送しない
    [
      {
        "field": "connection_id",
        "operator": "is_in",
        "values": ["S8YEN0TSE13JDC2991NG4XZ150"]
      }
    ],
    [
      {
        "field": "client_id",
        "operator": "is_in",
        "values": ["screen-share"]
      },
      {
        "field": "kind",
        "operator": "is_in",
        "values": ["audio"]
      }
    ]
  ]
}
```

### field に `connection_id` を指定した場合

`kind` を指定しなくても `audio` と `video` がブロックされます。

```javascript
{
  "action": "block",
  "rules": [
    // チャネルに接続しているすべてのコネクションへ connection_id "S8YEN0TSE13JDC2991NG4XZ150" からの音声と映像をブロックし転送しない
    [
      {
        "field": "connection_id",
        "operator": "is_in",
        "values": ["S8YEN0TSE13JDC2991NG4XZ150"]
      }
    ]
  ]
}
```

### 送信元の指定をせずすべての音声と映像をブロックする

`kind` を指定することで送信元の指定がないフィルターを作成できます。
音声と映像の両方をブロックするので  `values` に `audio` と `video` 両方を指定しています。

```javascript
{
  "action": "block",
  "rules": [
    // チャネルに接続しているすべてのコネクションに対して音声と映像をブロックし転送しない
    [
      {
        "field": "kind",
        "operator": "is_in",
        "values": ["audio", "video"]
      }
    ]
  ]
}
```

## フィルタールールの適用

- チャネル単位でのフィルター- 転送フィルターのルールにマッチした条件で、すべてのコネクションに対して転送するかどうか
- コネクション単位でのフィルター- 転送フィルターのルールでマッチした条件で、指定した `connection_id` に対して転送するかどうか
- フィルターの優先度- チャネル単位でフィルターとコネクション単位でのフィルターに優先度はない
  - 優先度は `allow` と `block` にだけあり `allow` が優先される


## 転送フィルター共通 API の仕様

### ListForwardingFilters API

指定したチャネルのチャネルとコネクション両方の転送フィルターを確認できます。

- channel_id- string
  - 必須
- blocked- boolean
  - オプション
  - ブロック状況を表示するかどうかを指定します

```
$ curl -sS \
    -X POST \
    http://127.0.0.1:3000/ \
    -H "x-sora-target: Sora_20230628.ListForwardingFilters" \
    --json '{"channel_id":"sora","blocked":true}' \
    | jq .
{
  "channel_forwarding_filters": [
    {
      "action": "block",
      "rules": [
        [{"field": "kind", "operator": "is_in", "values": ["audio", "video"]}]
      ]
    }
  ],
  "connection_forwarding_filters": [
    {
      "connection_id": "9PZ98RZV1H3RSEZ82SBBC289F8",
      "action": "allow",
      "rules": [
        [{"field": "kind", "operator": "is_in", "values": ["audio"]}]
      ]
    },
    {
      "connection_id": "8QA9YX7ZJX3150ZJ87874TBFMG",
      "action": "allow",
      "rules": [
        [{"field": "kind", "operator": "is_in", "values": ["audio"]}]
      ]
    }
  ],
  "blocked": [
    {
      "destination_connection_id": "9PZ98RZV1H3RSEZ82SBBC289F8",
      "source_connection_id_list": [
        "2VJPS671HH1EH3HNY13SXHS5RG"
      ],
      "kind": "audio"
    },
    {
      "destination_connection_id": "9PZ98RZV1H3RSEZ82SBBC289F8",
      "source_connection_id_list": [
        "2VJPS671HH1EH3HNY13SXHS5RG",
        "C4D50FG8Q16BF4YCTT0V8YGSXM"
      ],
      "kind": "video"
    }
  ]
}
```

## チャネル単位の転送フィルター API の仕様

### CreateChannelForwardingFilter API

指定したチャネルに対して Sora の転送フィルターを作成する API です。

- channel_id- string
  - 必須
- rules- `[[object, ...], [object, ...]]`
  - 必須
  - 転送フィルターのルールを指定します
- action - string
  - オプション
  - `block` または `allow`
  - デフォルトは `block`
- version- string
  - オプション
  - 転送フィルターのバージョンを指定します
- metadata- JSONValue
  - オプション
  - 転送フィルターのメタデータを指定します
- name- string (最大 255 バイト)
  - オプション
  - 転送フィルターの名前を指定します
- priority- integer (0-32767)
  - オプション
  - 転送フィルターの優先度を指定します

```
$ curl -sS \
    -X POST \
    http://127.0.0.1:3000/ \
    -H "x-sora-target: Sora_20230628.CreateChannelForwardingFilter" \
    --json '{"channel_id":"sora","rules":[[{"field":"client_id","operator":"is_in","values":["screen-share"]},{"field":"kind","operator":"is_in","values":["video"]}]]}' \
    | jq .
```

### UpdateChannelForwardingFilter API

指定したチャネルの転送フィルターを更新します。

- channel_id- string
  - 必須
- rules- `[[object, ...], [object, ...]]`
  - 必須
  - 転送フィルターのルールを指定します
- action - string
  - オプション
  - `block` または `allow`
  - デフォルトは `block`
- expected_version- string
  - オプション
  - 転送フィルターの期待するバージョンを指定します
- desired_version- string
  - オプション
  - 転送フィルターの更新成功後のバージョンを指定します
- metadata- JSONValue
  - オプション
  - 転送フィルターのメタデータを指定します
- name- string (最大 255 バイト)
  - オプション
  - 転送フィルターの名前を指定します
- priority- integer (0-32767)
  - オプション
  - 転送フィルターの優先度を指定します

```
$ curl -sS \
    -X POST \
    http://127.0.0.1:3000/ \
    -H "x-sora-target: Sora_20230628.UpdateChannelForwardingFilter" \
    --json '{"channel_id":"sora","rules":[[{"field":"connection_id","operator":"is_in","values":["RAV7EG7Z693NDCZFGGXZS7WBRC"]}],[{"field":"client_id","operator":"is_in","values":["screen-share"]},{"field":"kind","operator":"is_in","values":["video"]}]]}' \
    | jq .
```

### DeleteChannelForwardingFilter API

指定したチャネルの転送フィルターを削除します。

- channel_id- string
  - 必須
- name- string (最大 255 バイト)
  - オプション
  - 転送フィルターの名前を指定します

```
$ curl -sS \
    -X POST \
    http://127.0.0.1:3000/ \
    -H "x-sora-target: Sora_20230628.DeleteChannelForwardingFilter" \
    --json '{"channel_id":"sora"}' \
    | jq .
```

## コネクション単位の転送フィルター API の仕様

### CreateConnectionForwardingFilter API

指定したチャネルの特定のコネクションの転送フィルターを作成します。

- channel_id- string
  - 必須
- connection_id- string
  - 必須
- rules- `[[object, ...], [object, ...]]`
  - 必須
  - 転送フィルターのルールを指定します
- action - string
  - オプション
  - `block` または `allow`
  - デフォルトは `block`
- version- string
  - オプション
  - 転送フィルターのバージョンを指定します
- metadata- JSONValue
  - オプション
  - 転送フィルターのメタデータを指定します
- name- string (最大 255 バイト)
  - オプション
  - 転送フィルターの名前を指定します
- priority- integer (0-32767)
  - オプション
  - 転送フィルターの優先度を指定します

```
$ curl -sS \
    -X POST \
    http://127.0.0.1:3000/ \
    -H "x-sora-target: Sora_20230628.CreateConnectionForwardingFilter" \
    --json '{"channel_id":"sora","connection_id":"T9J5FM3NTH6JH4JKFGTSHB1BA0","rules":[[{"field":"client_id","operator":"is_in","values":["screen-share"]},{"field":"kind","operator":"is_in","values":["video"]}]]}' \
    | jq .
```

### UpdateConnectionForwardingFilter API

指定したチャネルの特定のコネクションの転送フィルターを更新します。

- channel_id- string
  - 必須
- connection_id- string
  - 必須
- rules- `[[object, ...], [object, ...]]`
  - 必須
  - 転送フィルターのルールを指定します
- action - string
  - オプション
  - `block` または `allow`
  - デフォルトは `block`
- expected_version- string
  - オプション
  - 転送フィルターの期待するバージョンを指定します
- desired_version- string
  - オプション
  - 転送フィルターの更新成功後のバージョンを指定します
- metadata- JSONValue
  - オプション
  - 転送フィルターのメタデータを指定します
- name- string (最大 255 バイト)
  - オプション
  - 転送フィルターの名前を指定します
- priority- integer (0-32767)
  - オプション
  - 転送フィルターの優先度を指定します

```
$ curl -sS \
    -X POST \
    http://127.0.0.1:3000/ \
    -H "x-sora-target: Sora_20230628.UpdateConnectionForwardingFilter" \
    --json '{"channel_id":"sora","connection_id":"T9J5FM3NTH6JH4JKFGTSHB1BA0","rules":[[{"field":"connection_id","operator":"is_in","values":["RX1GD666HD53F3M36PB7KEZMBR"]},{"field":"kind","operator":"is_in","values":["video"]}]]}' \
    | jq .
```

### DeleteConnectionForwardingFilter API

指定したチャネルの特定のコネクションの転送フィルターを削除します。

- channel_id- string
  - 必須
- connection_id- string
  - 必須
- name- string (最大 255 バイト)
  - オプション
  - 転送フィルターの名前を指定します

```
$ curl -sS \
    -X POST \
    http://127.0.0.1:3000/ \
    -H "x-sora-target: Sora_20230628.DeleteConnectionForwardingFilter" \
    --json '{"channel_id":"sora","connection_id":"T9J5FM3NTH6JH4JKFGTSHB1BA0"}' \
    | jq .
```

## セッション生成時のチャネル単位転送フィルター仕様

セッション生成時に転送フィルターを指定することができます。

> **重要**
>
> セッション生成時の払い出しで転送フィルターがエラーになった場合、接続に失敗します。

以下はセッション接続時には音声しか転送しないフィルター例です。

```javascript
{
  "forwarding_filters": [
    {
      "action": "allow",
      "rules": [
        [
        {"field": "kind", "operator": "is_in", "values": ["audio"]}
        ]
      ]
    }
  ]
}
```

- `version` や `metadata` も指定できます
- `name` や `priority` も指定できます

> **注釈**
>
> セッション生成時に転送フィルターを指定した場合、
> API 経由で変更するには UpdateChannelForwardingFilter API を利用する必要があります。

## シグナリング時のコネクション単位転送フィルター仕様

シグナリング接続時に **コネクション単位での転送フィルター** を指定することができます。

この転送フィルターは接続したコネクションにのみ影響します。

> **重要**
>
> シグナリング接続時に転送フィルターを指定する場合は `sora.conf` にて、
> [signaling_forwarding_filters](SORA_CONF.html#bf0e30) を `true` に設定する必要があります。

以下は接続時に映像を転送せずに音声だけを自分に転送するフィルター例です。

```javascript
{
  "type": "connect",
  "role": "sendrecv",
  "channel_id": "sora", 
  "forwarding_filters": [
    {
      "action": "allow",
      "rules": [
        [
         {"field": "kind", "operator": "is_in", "values": ["audio"]}
        ]
      ]
    }
  ]
}
```

> **注釈**
>
> シグナリング時に転送フィルターを指定した場合、
> API 経由で変更するには UpdateConnectionForwardingFilter API を利用する必要があります。

## 認証成功時払い出し時のコネクション単位転送フィルターの仕様

認証成功時に、コネクション単位の転送フィルターを指定することができます。

> **重要**
>
> 認証成功時の払い出しの転送フィルターがエラーになった場合、接続に失敗します。

以下は映像を転送せずに音声だけをそのコネクションに転送するフィルター例です。

```javascript
{
  "allowed": true,
  "forwarding_filters": [
    {
      "action": "allow",
      "rules": [
        [
         {"field": "kind", "operator": "is_in", "values": ["audio"]}
        ]
      ]
    }
  ]
}
```

`version` や `metadata` も指定できます。

> **注釈**
>
> 認証成功払い出し時に転送フィルターを作成した場合、
> API 経由で変更するには UpdateConnectionForwardingFilter API を利用する必要があります。

## シグナリング通知

転送フィルターを作成、更新、削除したタイミングで、
転送フィルターによって転送されていないかどうかを、シグナリング経由で通知します。

転送フィルターが影響する範囲にのみ通知されます。

通知は送信側と受信側の両方に送られます。

- destination は映像または音声の送信先です
- source は映像または音声の送信元です
- destination_connection_id は映像または音声の送信先の connection_id です
- source_connection_id は映像または音声の送信元の connection_id です

### forwarding.blocked

転送フィルターによりブロックが有効になったタイミングで送信側と受信側に通知されます。

以下の通知は、 `source_connection_id` の送信元から `destination_connection_id` の送信先へ送信した音声をブロックすることを表しています。

```javascript
{
  "type": "notify",
  "kind": "audio",
  "event_type": "forwarding.blocked",
  "destination_connection_id": "14P91M6B5526928T14WGPW9H6G",
  "source_connection_id": "GHRNJAQ40S15KCF3MZF0N7QS8R"
}
```

### forwarding.allowed

転送フィルターによりブロックが解除されたタイミングで送信側と受信側に通知されます。

以下の通知は、 `source_connection_id` の送信元から `destination_connection_id` の送信先へ送信した音声のブロックが解除されたことを表しています。

```javascript
{
  "type": "notify",
  "kind": "audio",
  "event_type": "forwarding.allowed",
  "destination_connection_id": "14P91M6B5526928T14WGPW9H6G",
  "source_connection_id": "GHRNJAQ40S15KCF3MZF0N7QS8R"
}
```

## フィルター例

### 特定のクライアントにだけ音声と映像を転送しない

`CreateConnectionForwardingFilter` API で音声と映像を転送したくないクライアントに対してフィルターを設定してください

```
$ curl -sS \
    -X POST \
    http://127.0.0.1:3000/ \
    -H "x-sora-target: Sora_20230628.CreateConnectionForwardingFilter" \
    --json '{"channel_id":"sora","connection_id":"T9J5FM3NTH6JH4JKFGTSHB1BA0","action":"block","rules":[[{"field":"kind","operator":"is_in","values":["audio","video"]}]]}' \
    | jq .
```

このフィルターは指定したコネクションに転送するパケットのフィルターを設定しています。
`kind` で `audio` と `video` が `is_in` に設定されており、
すべてのクライアントから Sora に送信されてくる audio と video を指定したクライアントに転送しなくなります。

### 特定の connection_id の送信元以外の音声や映像を転送しない

`CreateChannelForwardingFilter` API で音声と映像の転送を許可する送信元のコネクション ID を指定してください。

```
$ curl -sS \
    -X POST \
    http://127.0.0.1:3000/ \
    -H "x-sora-target: Sora_20230628.CreateChannelForwardingFilter" \
    --json '{"channel_id":"sora","action":"block","rules":[[{"field":"connection_id","operator":"is_not_in","values":["S8YEN0TSE13JDC2991NG4XZ150"]}]]}' \
    | jq .
```

このフィルターでは指定したチャネルに転送するパケットのフィルターを設定しています。
`operator` に `is_not_in` を指定することで指定したコネクション ID の送信元以外からのパケットの送信をブロックします。

### 全体をブロックしているが、一時的に特定の connection_id の送信先だけには全クライアントの音声と映像を転送する

`CreateChannelForwardingFilter` API で音声と映像の転送をブロックしてください。

```
$ curl -sS \
    -X POST \
    http://127.0.0.1:3000/ \
    -H "x-sora-target: Sora_20230628.CreateChannelForwardingFilter" \
    --json '{"channel_id":"sora","action":"block","rules":[[{"field":"kind","operator":"is_in","values":["audio","video"]}]]}' \
    | jq .
```

`CreateConnectionForwardingFilter` API で一時的にブロックしない送信先の connection_id を指定してください。
ポイントはコネクション単位で `action` に `allow` を指定します。 `allow` は `block` を上書きします。

```
$ curl -sS \
    -X POST \
    http://127.0.0.1:3000/ \
    -H "x-sora-target: Sora_20230628.CreateConnectionForwardingFilter" \
    --json '{"channel_id":"sora","connection_id":"T9J5FM3NTH6JH4JKFGTSHB1BA0","action":"allow","rules":[[{"field":"kind","operator":"is_in","values":["audio","video"]}]]}' \
    | jq .
```

これで全体をブロックした状態で、指定した connection_id の送信先にだけ音声や映像が転送されます。

## FAQ


### チャネルとコネクションの転送フィルターはどちらが優先されますか？

チャネルとコネクションで優先度は特にありません。

ただしアクションの `allow` が優先されます。
チャネルのアクションが `block` でコネクションのアクションが `allow` で、
同じコネクション ID を指定した場合は `allow` が優先されます。

### 転送フィルターでブロックされたときの挙動を教えてください

Sora は転送フィルターでブロックされた音声や映像パケットをクライアントに転送しません。
そのため受信側ではパケットが「何も送られてこない」という状態になります。

転送フィルターが更新、または削除や `allow` で転送される状態になるとパケットの転送を開始します。

### 1 チャネルや 1 コネクションに複数の転送フィルターを指定できますか？

指定できます。 [マルチ転送フィルター機能](MULTI_FORWARDING_FILTER.html) をご確認ください。

### 転送フィルターを有効にした場合は ontrack は SDK 側で発火しますか？

発火します。転送フィルターはあくまで **本来転送する音声や映像を Sora でフィルターする機能** のため、
SDK 側の ontrack 自体は発火します。

### フィルターでブロックされたりブロック解除されたタイミングをクライアント側で知ることはできますか？

Sora はシグナリング通知経由でブロック/ブロック解除されたタイミングで通知します。
これはブロックされた送信側と受信側両方に通知が飛びます。

## シーケンス図

### チャネル単位のブロック例

```mermaid
sequenceDiagram
    autonumber
    participant C1 as クライアント1
    participant C2 as クライアント2
    participant C3 as クライアント3
    participant S as Sora
    participant A as アプリケーションサーバー
    note over C1,S: クライアント1: WebRTC 確立
    note over C2,S: クライアント2: WebRTC 確立
    par
        C1-)S: SRTP
        S-)C1: SRTP (C2)
    and
        C2-)S: SRTP 
        S-)C2: SRTP (C1)
    and
        A->>+S: CreateChannelForwardingFilter<br>channel_id=sora<br>block,kind(audio,video)
        S-->>-A: 200 OK
        note right of S: 音声と映像をこのチャネル内で転送しない
    end
    note over C1,S: ブロックフィルターで転送がブロックされる
    par
        C1-)S: SRTP
    and
        C2-)S: SRTP 
    and
        note over C3,S: クライアント3: WebRTC 確立  
    end
    par
        C1-)S: SRTP 
    and
        C2-)S: SRTP 
    and
        C3-)S: SRTP 
    end
        A->>+S: DeleteChannelForwardingFilter<br>channel_id=sora
        S-->>-A: 200 OK
    note over C1,S: ブロックフィルターが削除された
    par
        C1-)S: SRTP 
        S-)C1: SRTP (C2)
        S-)C1: SRTP (C3)
    and
        C2-)S: SRTP 
        S-)C2: SRTP (C1)
        S-)C2: SRTP (C3)
    and
        C3-)S: SRTP 
        S-)C3: SRTP (C2)
        S-)C3: SRTP (C1)
    end
    note over C1,S: 音声と映像の転送がブロックされなくなった
```

### チャネルフィルターとコネクションフィルター組み合わせ例

- 音声と映像がブロックされる
- connection_id 1 にだけ映像が転送される

```mermaid
sequenceDiagram
   autonumber
   participant C1 as クライアント1<br>connection_id: 1
   participant C2 as クライアント2<br>connection_id: 2
   participant S as Sora
   participant A as アプリケーションサーバー
   note over C1,S: クライアント1: WebRTC 確立
   note over C2,S: クライアント2: WebRTC 確立
   par
     C1-)S: SRTP (音声)
     S-)C2: SRTP (音声)
   and
       C1-)S: SRTP (映像)
     S-)C2: SRTP (映像)
   and
       C2-)S: SRTP (音声)
       S-)C1: SRTP (音声)
   and
       C2-)S: SRTP (映像)
       S-)C1: SRTP (映像)
   and
       note right of S: 音声と映像をこのチャネル内で転送しない
       A->>+S: CreateChannelForwardingFilter<br>channel_id=sora<br>block,kind(audio,video)
       S-->>-A: 200 OK
       note right of S: 映像を connection_id=1 にだけ転送する
       A->>+S: CreateConnectionForwardingFilter<br>channel_id=sora<br>connection_id: 1<br>allow,kind(video)
       S-->>-A: 200 OK
   end
   note over C1,S: チャネル単位フィルターで音声と映像の転送がブロックされる
   note over C1,S: コネクション単位フィルターで映像の転送が connection_id: 1 には許可される
   par
       note right of S: ブロックされる
       C1-)S: SRTP (音声)
   and
       note right of S: ブロックされる
       C1-)S: SRTP (映像)
   and
       note right of S: ブロックされる
       C2-)S: SRTP (音声)
   and
       C2-)S: SRTP (映像)
       note right of S: 許可されているので転送する
       S-)C1: SRTP (映像)
   end
       A->>+S: DeleteConnectionForwardingFilter<br>channel_id=sora<br>connection_id: 1
       S-->>-A: 200 OK
   note over C1,S: コネクション単位のフィルターが削除された
   par
       C1-)S: SRTP (音声)
   and
       C1-)S: SRTP (映像)
   and
       C2-)S: SRTP (音声)
   and
       C2-)S: SRTP (映像)
   end
   note over C1,S: 全員が音声と映像の転送がブロックされている
```

### version を利用した変更保証

並列に転送フィルター更新 API が叩かれてもバージョンチェックをすることで更新結果を保証する。

```mermaid
sequenceDiagram
    participant S as Sora
    participant A as アプリケーションサーバー
    par
        A->>+S: UpdateChannelForwardingFilters API<br>{"expect_version": "spam", "desire_version": "ham", ...}
        S-->>-A: 200 OK
        note over A: 更新成功
    and
        A->>+S: UpdateChannelForwardingFilters API<br>{"expect_version": "spam", "desire_version": "beacon", ...}
        S-->>-A: 400 Bad Request<br>{"message": "INVALID-VERSION", "version": "ham"}
        note over A: 更新失敗
    end
```
