# リアルタイムメッセージング機能

## 概要

リアルタイムメッセージング機能は DataChannel の互換性を維持しつつ、 超低遅延で同じチャネル参加者へメッセージを送る仕組みです。

## 注意

- リアルタイムメッセージング機能を利用するためには、 `data_channel_signaling` が有効になっている必要があります
- リアルタイムメッセージング機能は DataChannel プロトコル互換性を維持しつつ Sora 独自の仕組みを追加しています

## 制限

### メッセージサイズ制限

> **注意**
>
> 1 回のメッセージで送れる値には制限がありますのでご注意ください。

詳しくは DataChannel シグナリングの [推奨メッセージサイズ](DATA_CHANNEL_SIGNALING.html#2b27d3) をご確認ください

## SDK 対応状況

- 最新版の JavaScript SDK- 対応済みです
- 最新版の iOS SDK- 対応済みです
- 最新版の Android SDK- 対応済みです
- 最新版の Unity SDK- 対応済みです
- 最新版の C++ SDK- 対応済みです
- 最新版の Python SDK- 対応済みです

## DataChannel を利用したリアルタイムメッセージング機能を有効にする

DataChannel を利用したリアルタイムメッセージングを利用する場合、 DataChannel シグナリングが有効になっている必要があります。

その上で `sora.conf` にて [data_channel_messaging](SORA_CONF.html#1d5746) を `true` に指定してください。

利用する場合は `"type": "connect"` 時に `data_channels` を指定してください。

## リアルタイムメッセージング用 DataChannel の作成

> **重要**
>
> DataChannel を利用したリアルタイムメッセージングを利用する場合は、DataChannel シグナリングが有効になっている必要があります

Sora では、Sora がシグナリングで使用する DataChannel 以外にも、リアルタイムメッセージング用の DataChannel を作成できます。

利用する場合は `"type": "connect"` 時に定義するか、認証成功時の払い出しで定義する必要があります。

Sora のリアルタイムメッセージング用 DataChannel は、DataChannel の属性である `label` を定義する際に `#` から始める必要があります。


## data_channels 仕様

> **重要**
>
> メッセージは **送信者以外** の同一 `label` 、かつ、 `direction` が `sendrecv`
> または `recvonly` のクライアントに送信されます。


### label

メッセージのラベルを指定します。先頭に `#` が付いている必要があります。

- `label` は `#` を含めて 32 文字まで指定できます
- `label` には小文字大文字のアルファベットと `-` (ハイフン) しか利用できません- `#` の次の文字に `-` は指定できません
  - `^#[a-zA-Z0-9][a-zA-Z0-9-]{1,30}$`
- 1 接続においてラベルは最大で 1024 まで指定できます


### compress

メッセージを zlib にて圧縮するかどうかを指定します。

- `compress` が `true` の場合、圧縮/展開に `zlib.deflate` を利用します- 圧縮方式を変更することはできません


### direction

メッセージの方向を指定します。

- `direction` には `sendrecv` / `sendonly` / `recvonly` が設定できます- `sendrecv` 時に **自分が送ったメッセージ** は自分には送られてきません

クライアントからみた方向になります。

- `sendrecv` が設定されたラベルは送受信で利用できます
- `sendonly` が設定されたラベルは送信のみが利用できます
- `recvonly` が設定されたラベルは受信のみが利用できます


### ordered

順序保証を行うかどうか指定します。デフォルトでは `true` に設定され、順序保証を行います。


### max_retransmits

> **注意**
>
> max_retransmits と max_packet_life_time はどちらかしか指定できません。

最大再送回数を指定します。デフォルトでは未指定で、無制限に再送します。


### max_packet_life_time

> **注意**
>
> max_retransmits と max_packet_life_time はどちらかしか指定できません。

最大再送時間をミリ秒で指定します。デフォルトでは未指定で、無制限に再送します。


### header

メッセージングにヘッダーを追加します。ヘッダーは Sora 側で付与します。

- `header` は `direction` が `sendrecv` または `recvonly` の場合に指定できます
- `header` を指定したメッセージの受信者にヘッダーが付与されるようになります
- `header` はオプションです
- `header` のデフォルトは `[]` です
- `header` には `{"type": "sender_connection_id"}` を指定できます- `sender_connection_id` はメッセージングの送信元の `connection_id` です
  - 先頭 26 バイトが `sender_connection_id` になります
- クライアントから Sora が受信するメッセージ- `[message (variable length)]`
- Sora から `header` を指定したクライアントへ送信するメッセージ- `[sender_connection_id (26 bytes)][message (variable length)]`

```javascript
"data_channels": [
  {
    "label": "#spam",
    "max_packet_life_time": 5000,
    "ordered": true,
    "protocol": "efg",
    "compress": false,
    "direction": "recvonly",
    "header": [{"type": "sender_connection_id"}]
  },
  {
    "label": "#egg",
    "max_retransmits": 0,
    "ordered": false,
    "protocol": "abc",
    "compress": false,
    "direction": "recvonly"
  }
]
```

### JavaScript SDK 利用時の注意

- `max_retransmits` は `maxRetransmits` に変更してください
- `max_packet_life_time` は `maxPacketLifeTime` に変更してください

## "type": "connect" 時の "data_channels"

> **注釈**
>
> protocol は特に指定する必要はありません。

* - 項目名
  - 型
  - 必須 / オプション
  - デフォルト
  - 備考
* - label
  - string
  - 必須
  -
  - ^#[a-zA-Z0-9][a-zA-Z0-9-]{1,30}$
* - direction
  - string
  - 必須
  -
  - "sendrecv" / "sendonly" / "recvonly"
* - ordered
  - boolean
  - オプション
  - true
  -
* - max_packet_life_time
  - integer
  - オプション
  - 未指定
  -
* - max_retransmits
  - integer
  - オプション
  - 未指定
  -
* - protocol
  - string
  - オプション
  - ""
  -
* - compress
  - boolean
  - オプション
  - false
  -
* - header
  - array[object]
  - オプション
  - []
  - "sender_connection_id"

> **注意**
>
> Sora JS SDK や Sora DevTools で `max_packet_life_time` と `max_retransmits` を指定する場合は
> `maxPacketLifeTime` と `maxRetransmits` となります。

```javascript
{
  "type": "connect",
  "data_channels": [
    {
      "label": "#spam",
      "max_packet_life_time": 5000,
      "ordered": true,
      "protocol": "efg",
      "compress": false,
      "direction": "recvonly",
      "header": [{"type": "sender_connection_id"}]
    },
    {
      "label": "#egg",
      "max_retransmits": 0,
      "ordered": false,
      "protocol": "abc",
      "compress": false,
      "direction": "recvonly"
    }
  ]
}
```

## 認証成功時の戻り値

認証ウェブフックの認証成功時に `data_channels` を指定できます。

```javascript
{
  "allowed": true,
  "data_channels": [
    {
      "label": "#spam",
      "max_packet_life_time": 5000,
      "ordered": true,
      "protocol": "efg",
      "compress": false,
      "direction": "recvonly",
      "header": [{"type": "sender_connection_id"}]
    },
    {
      "label": "#egg",
      "max_retransmits": 0,
      "ordered": false,
      "protocol": "abc",
      "compress": false,
      "direction": "recvonly"
    }
  ]
}
```

## "type": "offer" 時の "data_channels"

> **注釈**
>
> Sora SDK を利用する場合はこれを意識する必要はありません。

接続時か認証成功時に指定された `data_channels` は `{"type": "offer"}` に含まれます。

```javascript
{
  "type": "offer",
  "data_channels": [
    {
      "label": "signaling",
      "ordered": true,
      "protocol": "signaling",
      "compress": true,
      "direction": "sendrecv"
    },
    {
      "label": "notify",
      "ordered": true,
      "protocol": "notify",
      "compress": true,
      "direction": "recvonly"
    },
    {
      "label": "push",
      "ordered": true,
      "protocol": "push",
      "compress": true,
      "direction": "recvonly"
    },
    {
      "label": "stats",
      "ordered": true,
      "max_retransmits": 1,
      "protocol": "stats",
      "compress": true,
      "direction": "sendrecv"
    },
    {
      "label": "rpc",
      "ordered": true,
      "protocol": "rpc",
      "compress": true,
      "direction": "sendrecv"
    },
    {
      "label": "#spam",
      "max_packet_life_time": 5000,
      "ordered": true,
      "protocol": "efg",
      "compress": false,
      "direction": "recvonly",
      // header の長さが type: offer 時の data_channels には含まれるようになります
      "header": [{"type": "sender_connection_id", "length": 26}]
    },
    {
      "label": "#egg",
      "max_retransmits": 0,
      "ordered": false,
      "protocol": "abc",
      "compress": false,
      "direction": "recvonly"
    }
  ]
}
```

## DataChannel を利用したメッセージングのみで接続する

DataChannel を利用したメッセージングのみを有効にするには以下を満たす必要があります。

> **注釈**
>
> role は sendrecv / sendonly / recvonly のどれでも問題ありませんが、 sendrecv / recvonly の場合、相手から送られてきた音声や映像を受信しますので、sendonly で接続することをお勧めします。

- `sora.conf` の [default_data_channel_signaling](SORA_CONF.html#adceef) を `true` にする
- `sora.conf` の [data_channel_messaging_only](SORA_CONF.html#93c61c) を `true` にする
- `sora.conf` の [data_channel_messaging](SORA_CONF.html#1d5746) を `true` にする
- `"type": "connect"` 時に `audio` を `false` にする- 認証成功時の払い出しでも可
- `"type": "connect"` 時に `video` を `false` にする- 認証成功時の払い出しでも可
- `"type": "connect"` 時に `data_channels` を指定する- 認証成功時の払い出しでも可
- `"type": "connect"` 時に `data_channel_signaling` を `true` にする- 認証成功時の払い出しでも可

これで **音声や映像を送らず** DataChannel を利用したメッセージングのみを利用できるようになります。

## シーケンス図

### シンプル

1. クライアント 1 が `label`: `spam`, `direction`: `sendrecv` と、`label`: `#egg`, `direction`: `sendonly` でメッセージング利用開始```javascript
   {
     "type": "connect",
     "data_channels": [
       {"label": "#spam", "direction": "sendrecv"},
       {"label": "#egg": "direction": "sendonly"}
     ]
   }
   ```
2. クライアント 2 が `label`: `#spam`, `direction`: `recvonly` でメッセージング利用開始```javascript
   {
     "type": "connect",
     "data_channels": [
       {"label": "#spam", "direction": "recvonly"}
     ]
   }
   ```
3. クライアント 1 が `label`: `#spam` へメッセージ `"abc"` を送信
4. クライアント 2 が Sora から `label`: `#spam` へのメッセージ `"abc"` を受信
5. クライアント 1 が `label`: `#egg` へメッセージ `"xyz"` を送信- 誰も受け取る人がいない
6. クライアント 3 が `label`: `#spam`, `direction`: `sendrecv` でメッセージング利用開始```javascript
   {
     "type": "connect",
     "data_channels": [
       {"label": "#spam", "direction": "sendrecv"}
     ]
   }
   ```
7. クライアント 1 が Sora へ `label`: `#spam` のメッセージ `"123"` を送信
8. クライアント 2 が Sora から `label`: `#spam` のメッセージ `"123"` を受信
9. クライアント 3 が Sora から `label`: `#spam` のメッセージ `"123"` を受信

```mermaid
sequenceDiagram
    autonumber

    participant C1 as クライアント1
    participant C2 as クライアント2
    participant C3 as クライアント3
    participant S as Sora

    C1->>S: "type": "connect"
    note over C1,S: クライアント1 WebRTC 確立
    C2->>S: "type": "connect"
    note over C2,S: クライアント2 WebRTC 確立
    C1-)S: label: #35;spam "abc" send
    S-)C2: label: #35;spam "abc" send
    C3->>S: "type": "connect"
    note over C3,S: クライアント3 WebRTC 確立
    C1-)S: label: #35;spam "xyz" send
    S-)C2: label: #35;spam "xyz" send
    S-)C3: label: #35;spam "xyz" send
```
