# 転送フィルター機能

> **注意**
>
> この機能を利用する場合は事前にサポートまでご連絡ください

> **警告**
>
> この機能は [実験的機能](EXPERIMENTAL.html) のため、正式版では仕様が変更される可能性があります

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

## 概要

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

## 目的

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

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

## 注意

### 利用可能なロール

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

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

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

## 機能

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

- 転送フィルターのルール指定は、チャネル単位、コネクション単位で指定できます
- 転送フィルターのルールにはコネクション ID とクライアント ID と種類 (音声、映像) が指定できます
- **転送フィルタールール** に指定するコネクション ID は 音声や映像の **送信元の** コネクション ID です。
- **転送フィルタールール** に指定するクライアント ID は 音声や映像の **送信元の** クライアント ID です。
- シグナリング指定時や認証成功時に **そのコネクションに対するのフィルター** を指定可能です

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

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

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

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

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

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

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

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

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

### 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` に設定した場合、その接続にだけは映像の転送が許可されます。

### 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
  - オプション
  - ブロック状況を表示するかどうかを指定します

```
$ http POST 127.0.0.1:3000/ \
    x-sora-target:Sora_20230628.ListForwardingFilters \
    channel_id=sora \
    blocked:=true \
    -vvv

{
  "channel_forwarding_filter": {
    "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`

```
$ http POST 127.0.0.1:3000/ \
    x-sora-target:Sora_20230628.CreateChannelForwardingFilter \
    channel_id=sora \
    rules:='[
      [
        {"field": "client_id", "operator": "is_in", "values": ["screen-share"]},
        {"field": "kind", "operator": "is_in", "values": ["video"]}
      ]
    ]' \
    -vvv
```

### UpdateChannelForwardingFilter API

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

- channel_id- string
  - 必須
- rules- `[[object, ...], [object, ...]]`
  - 必須
  - 転送フィルターのルールを指定します
- action - string
  - オプション
  - `block` または `allow`
  - デフォルトは `block`

```
$ http POST 127.0.0.1:3000/ \
    x-sora-target:Sora_20230628.UpdateChannelForwardingFilter \
    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"]}
      ]
    ]' \
    -vvv
```

### DeleteChannelForwardingFilter API

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

- channel_id- string
  - 必須

```
$ http POST 127.0.0.1:3000/ \
    x-sora-target:Sora_20230628.DeleteChannelForwardingFilter \
    channel_id=sora \
    -vvv
```

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

### CreateConnectionForwardingFilter API

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

- channel_id- string
  - 必須
- connection_id- string
  - 必須
- rules- `[[object, ...], [object, ...]]`
  - 必須
  - 転送フィルターのルールを指定します
- action - string
  - オプション
  - `block` または `allow`
  - デフォルトは `block`

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

### UpdateConnectionForwardingFilter API

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

- channel_id- string
  - 必須
- connection_id- string
  - 必須
- rules- `[[object, ...], [object, ...]]`
  - 必須
  - 転送フィルターのルールを指定します
- action - string
  - オプション
  - `block` または `allow`
  - デフォルトは `block`

```
$ http POST 127.0.0.1:3000/ \
    x-sora-target:Sora_20230628.UpdateConnectionForwardingFilter \
    channel_id=sora \
    connection_id=T9J5FM3NTH6JH4JKFGTSHB1BA0 \
    rules:='[
      [
        {"field": "connection_id", "operator": "is_in", "values": ["RX1GD666HD53F3M36PB7KEZMBR"]},
        {"field": "kind", "operator": "is_in", "values": ["video"]}
      ]
    ]' \
    -vvv
```

### DeleteConnectionForwardingFilter API

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

- channel_id- string
  - 必須
- connection_id- string
  - 必須

```
$ http POST 127.0.0.1:3000/ \
    x-sora-target:Sora_20230628.DeleteConnectionForwardingFilter \
    channel_id=sora \
    connection_id=T9J5FM3NTH6JH4JKFGTSHB1BA0 \
    -vvv
```

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

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

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

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

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

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

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

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

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

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

```javascript
{
  "type": "connect",
  "role": "sendrecv",
  "channel_id": "sora", 
  "forwarding_filter": {
    "action": "block",
    "rules": [
      [
       {"field": "kind", "operator": "is_in", "values": ["video"]}
      ]
    ]
  }
}
```

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

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

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

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

```javascript
{
  "allowed": true,
  "forwarding_filter": {
    "action": "block",
    "rules": [
      [
       {"field": "kind", "operator": "is_in", "values": ["video"]}
      ]
    ]
  }
}
```

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

## シグナリング通知

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

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

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

- destination は映像または音声の送信先です
- source は映像または音声の送信元です
- destination_connection_id は映像または音声の送信先の connection_id です
- souce_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 で音声と映像を転送したくないクライアントに対してフィルターを設定してください

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

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

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

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

```
$ http POST 127.0.0.1:3000/ \
    x-sora-target:Sora_20230628.CreateChannelForwardingFilter \
    channel_id=sora \
    action=block \
    rules:='[
      [
        {"field": "connection_id", "operator": "is_not_in", "values": ["S8YEN0TSE13JDC2991NG4XZ150"]}
      ]
    ]' \
    -vvv
```

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

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

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

```
$ http POST 127.0.0.1:3000/ \
    x-sora-target:Sora_20230628.CreateChannelForwardingFilter \
    channel_id=sora \
    action=block \
    rules:='[
      [
        {"field": "kind", "operator": "is_in", "values": ["audio", "video"]}
      ]
    ]' \
    -vvv
```

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

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

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

## FAQ


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

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

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

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

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

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

### 転送フィルターを有効にした場合は 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 App
    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: 音声と映像の転送がブロックされなくなった
```

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

```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 App
    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
        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_id1 にだけ転送する
        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: コネクション単位フィルターで映像の転送が 1 許可される
    par
        C1-)S: SRTP
        S-)C2: SRTP (C2)
    and
        C2-)S: SRTP
    end
    par
        C1-)S: SRTP 
        S-)C2: SRTP (C2)
    and
        C2-)S: 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
        C2-)S: SRTP 
    end
    note over C1,S: 全員が音声と映像の転送がブロックされている
```
