# WebRTC SFU Sora ドキュメント 製品のお問い合わせなどは sora at shiguredo.jp までお願いいたします。 (このメールアドレスへの特定電子メールの送信を拒否いたします) # LLM 向け LLM が読み込みやすい形式でドキュメントを提供しています。 - 目次は [llms.txt](/llms.txt) にあります - 全文は [llms-full.txt](/llms-full.txt) にあります # 重要なお知らせ - Sora のクラウド版 [Sora Cloud](https://sora-cloud.shiguredo.jp/) を正式リリースしました - Ubuntu 22.04 版の提供を開始しました- 移行する場合はサポートまでご連絡ください - RHEL 9 版の提供を開始しました- 移行する場合はサポートまでご連絡ください - Ubuntu 18.04 版は 2023 年 4 月でパッケージ、サポートの提供を終了します- 移行先の OS をサポートまでご連絡下さい - 詳細は [Ubuntu 18.04 サポートの終了](DEPRECATED.html#afde12) をご確認下さい Contents: - [2022.1.x から 2022.2.x への移行](2022_1_TO_2022_2.html) - [リリースノート](RELEASE_NOTE.html) - [既知の問題](KNOWN_ISSUES.html) - [実験的機能](EXPERIMENTAL.html) - [非推奨機能](DEPRECATED.html) - [廃止機能](OBSOLETE.html) - [FAQ](FAQ.html) - [トラブルシューティング](TROUBLESHOOTING.html) - [Sora が期待どおりに動かない場合、または、動作に問題がある場合](SUPPORT.html) - [Sora の仕様や使い方に関して質問がある場合](INQUIRY.html) - [チュートリアル](TUTORIAL.html) - [本番稼働に向けて](PRODUCTION.html) - [ライセンス](LICENSE.html) - [ログファイル](LOG.html) - [sora.conf リファレンス](SORA_CONF.html) - [systemd](SYSTEMD.html) - [Linux カーネルチューニング](LINUX_KERNEL_TUNING.html) - [IPv6 での動作について](IPV6.html) - [メタデータ](METADATA.html) - [センシティブデータ](SENSITIVE_DATA.html) - [ウェブフックの audio と video 項目の JSON 構造のフラット化](WEBHOOK_AUDIO_VIDEO_FLATTEN_JSON.html) - [WebSocket 経由のシグナリング](SIGNALING.html) - [DataChannel 経由のシグナリング](DATA_CHANNEL_SIGNALING.html) - [シグナリングの型定義](SIGNALING_TYPE.html) - [シグナリング通知](SIGNALING_NOTIFY.html) - [シグナリング通知メタデータ](SIGNALING_NOTIFY_METADATA.html) - [シグナリング通知メタデータ拡張機能](SIGNALING_NOTIFY_METADATA_EXT.html) - [Sora クライアント要求仕様](SORA_CLIENT.html) - [認証ウェブフック](AUTH_WEBHOOK.html) - [認証ウェブフック成功時の払い出し](AUTH_WEBHOOK_RETURN.html) - [セッションウェブフック](SESSION_WEBHOOK.html) - [イベントウェブフック](EVENT_WEBHOOK.html) - [ウェブフックの型定義](WEBHOOK_TYPE.html) - [API](API.html) - [実験的 API](EXPERIMENTAL_API.html) - [非推奨 API](DEPRECATED_API.html) - [廃止 API](OBSOLETE_API.html) - [開発者ツール](DEVTOOLS.html) - [クラスター機能](CLUSTER.html) - [マルチストリーム機能](MULTISTREAM.html) - [サイマルキャスト機能](SIMULCAST.html) - [スポットライト機能](SPOTLIGHT.html) - [TURN 機能](TURN.html) - [録画機能](RECORDING.html) - [メッセージング機能](MESSAGING.html) - [ICE コネクションステート機能](ICE_CONNECTION_STATE.html) - [モード機能](MODE.html) - [音声ストリーミング機能](AUDIO_STREAMING.html) - [統計エクスポーター機能](STATS_EXPORTER.html) - [E2EE 機能](E2EE.html) - [Lyra コーデック機能](LYRA.html) - [Sora JavaScript (TypeScript) SDK](JS_SDK.html) - [Sora iOS (Swift) SDK](IOS_SDK.html) - [Sora Android (Kotlin) SDK](ANDROID_SDK.html) - [Sora Unity (C++) SDK](UNITY_SDK.html) - [Sora C++ SDK](CPP_SDK.html) - [Sora Flutter (C++) SDK](FLUTTER_SDK.html) - [WebRTC 負荷試験ツール Zakuro](ZAKURO.html) - [WebRTC 録画合成ツール Hisui](HISUI.html) - [WebRTC 統計コレクター Kohaku](KOHAKU.html) - [音声ストリーミングゲートウェイ Suzu](SUZU.html) - [Sora exporter](SORA_EXPORTER.html) - [Media Processors](MEDIA_PROCESSORS.html) - [libwebrtc 音声処理](LIBWEBRTC_AUDIO.html) - [libwebrtc リップシンク](LIBWEBRTC_LIP_SYNC.html) - [libwebrtc ペーサー](LIBWEBRTC_PACER.html) - [libwebrtc ミキサーのストリーム数上限](LIBWEBRTC_AUDIO_MIXER_MAX_STREAMS.html) - [Microsoft Edge の WebRTC について](EDGE.html) - [Apple Safari の WebRTC について](SAFARI.html) - [nginx](NGINX.html) - [HLS 配信](HLS.html) - [お勧めのカメラとスピーカーフォン](CAMERA_SPEAKERPHONE.html) - [オープンソースライセンス](OSS_LICENSE.html) - [古いリリースノート](OLD_RELEASE_NOTE.html) - [古いドキュメント](OLD_DOCUMENT.html) # 開発ログ **WebRTC SFU Sora の開発ログを公開しています** [時雨堂 WebRTC SFU Sora 開発ログ](https://gist.github.com/voluntas/e914aa245fc26f3133c2) # 2022.1.x から 2022.2.x への移行 ## 概要 2022.1.x から 2022.2.x への移行について注意点をまとめています。 ## クラスターの再構築 2022.2 で Sora のクラスターの仕組みを変更しました。 クラスター機能を利用している場合は、いちど全ノードを停止して、ゼロからのクラスターの再構築をお願いします。 手順は以下のとおりです。 1. クラスターのすべてのノードを停止する 2. すべてのノードの `data/` ディレクトリを削除する- `sora.conf` で [data_dir](SORA_CONF.html#4445c6) を指定している場合にはそのディレクトリを削除する 3. [クラスター構築](CLUSTER.html#c65d5a) に従いクラスターを構築する ## セッションウェブフックのログ出力の変更 セッションログのフォーマット形式を変更しました。 今まではセッションウェブフックのリクエストのみが含まれていましたが、 今回のリリースからはセッションウェブフックのレスポンスも書き込まれるようになりました。 ## JSONL 形式でのログ出力 `sora.log` と `internal.log` のログ出力形式を JSONL 方式とする変更を行いました。 デフォルトでは今まで形式で出力しますが、 `sora.conf` の [legacy_log_format](SORA_CONF.html#3e05c7) を `false` にすることで、 JSONL 形式でログを出力するようになります。 この [legacy_log_format](SORA_CONF.html#3e05c7) の設定は 2023 年 6 月リリースの Sora にてデフォルトで `false` となり、 2023 年 12 月リリースの Sora にて [legacy_log_format](SORA_CONF.html#3e05c7) の設定が廃止されます。 ## 拡張子が JSONL 形式に変更 すべてのログファイルの拡張子を `jsonl` にする変更を行いました。 デフォルトでは今までの拡張子 `.log` で出力しますが、 `sora.conf` の [legacy_log_extension](SORA_CONF.html#847a26) を `false` にすることで、 `.jsonl` 拡張子でログを出力するようになります。 この [legacy_log_extension](SORA_CONF.html#847a26) の設定は 2023 年 6 月リリースの Sora にてデフォルトで `false` となり、 2023 年 12 月リリースの Sora にて [legacy_log_extension](SORA_CONF.html#847a26) の設定が廃止されます。 ## センシティブデータの取り扱い センシティブなデータの編集処理をログファイルに限定するように変更しました。 録画メタデータや API でのセンシティブなデータはそのまま出力されるようになりました。 また、センシティブなデータの編集処理をスキップできるよう、 `sora.conf` に [skip_redact_sensitive_data](SORA_CONF.html#00d209) を追加しました。 この値を `true` にすることでログファイルに書き出されるセンシティブデータがそのまま出力されます。 ### 書き換え対象ファイルと項目 - `auth_webhook.jsonl` の `event_metadata` を **"REDACTED"** に書き換えて出力します。 - `session_webhook.jsonl` の `session_metadata` と `event_metadata` を **"REDACTED"** に書き換えて出力します。 - `event_webhook.jsonl` の `event_metadata` を **"REDACTED"** に書き換えて出力します。 # リリースノート **CHANGE** : 後方互換性のない変更 **UPDATE** : 後方互換性がある変更 **ADD** : 後方互換性がある追加 **FIX** : バグ修正 ## 2022.2.3 **リリース**: 2023-02-08 ### 変更履歴 - [FIX] 依存している OpenSSL を 3.0.8 にアップデートしました - [FIX] 2023 年 4 月 4 日リリース予定の Chrome M112 でシグナリング時に接続が必ず失敗してしまう問題を修正しました - [FIX] ディスク障害が発生してログの書き込みに失敗した際に、障害が復旧した後でもログが書き込めなくなることがある問題を修正しました ## 2022.1.4 **リリース**: 2023-02-08 ### 変更履歴 - [FIX] 2023 年 4 月 4 日リリース予定の Chrome M112 でシグナリング時に接続が必ず失敗してしまう問題を修正しました ## 2022.2.2 **リリース**: 2023-01-05 ### 変更履歴 - [FIX] 音声ストリーミング機能で `sora.conf` の [default_audio_streaming_result_push](SORA_CONF.html#0b4a07) が `true` の際、プッシュ通知が行われない問題を修正しました - [FIX] 音声ストリーミング機能でロールが `reconly` の場合にプッシュ通知が受信できない問題を修正しました - [FIX] 音声ストリーミング機能で API を利用して音声ストリーミングを開始した際、通知が正常に行われない問題を修正しました ## 2022.2.1 **リリース**: 2022-12-21 ### 変更履歴 - [FIX] 開発ツールが Safari / Mobile Safari / Firefox で動作しない問題を修正しました ## 2022.2.0 **リリース**: 2022-12-21 ### ハイライト - sora ログと internal ログを JSONL 形式で出力するようになりました - Google が公開した超低ビットレートコーデック Lyra に対応しました - 音声パケットを HTTP/2 経由で出力する音声ストリーミング機能を追加しました - 録画開始ととアーカイブ開始のウェブフックを追加しました - ウェブフックが mTLS と CA 証明書の指定に対応しました ### 互換なしの変更情報 - 実験的機能であるセッションウェブフックのログ出力を req/res 形式に変更しました - 実験的機能であるセンシティブデータ向け設定 `redact_archive_metadata_sensitive_data` と `redact_api_sensitive_data` を廃止しました- 録画メタデータファイルと API はセンシティブなデータがあっても編集を行わないようにしました - クラスター機能の仕組みを変更したため互換性がなくなりました、クラスターの再構築をお願いします ### 変更履歴 - [FIX] DTLS 処理終了時に起きていた問題を修正しました - [FIX] 録画ウェブフックの `expired_at` が秒単位の UNIX Time ではなくマイクロ秒になっていたのを修正しました - [FIX] 録画ウェブフックの `split-archive.available` と `split-archive-*.json` に offset が含まれていなかったのを修正しました - [FIX] ULPFEC が有効でな状態でパケロス発生時に録画に失敗することがある問題を修正しました - [FIX] 録画機能のウェブフックやファイルに含まれる統計値の名前 total_audio_discarded が間違っていたのを修正しました ### JSONL 形式でのログ出力 - [ADD] `sora.conf` にログフォーマットのレガシー形式を維持する `legacy_log_format` を追加しました- デフォルトは `true` です - これは移行用設定です - [ADD] `sora.conf` に JSONL 形式で出力しているログのレガシー拡張子を `.log` に維持する `legacy_log_extension` を追加しました- デフォルトは `true` です - これは移行用設定です - [ADD] `sora.conf` の `legacy_log_format` を `false` にすることで以下のログは JSONL 形式で出力されます- sora ログ - internal ログ - signaling ログ - api ログ - auth_webhook ログ - session_webhook ログ - session_webhook_error ログ - event_webhook ログ - event_webhook_error ログ - connection ログ - [ADD] `sora.conf` の `legacy_log_extension` を `false` にすることでJSONL 形式で出力されているログファイルの拡張子が `.log` から `.jsonl` に変更されます- `sora.log` が `sora.jsonl` に変更されます - `internal.log` が `internal.jsonl` に変更されます - `signaling.log` が `signlaing.jsonl` に変更されます - `api.log` が `api.jsonl` に変更されます - `auth_webhook.log` が `auth_webhook.jsonl` に変更されます - `session_webhook.log` が `session_webhook.jsonl` に変更されます - `session_webhook_error.log` が `session_webhook_error.jsonl` に変更されます - `event_webhook.log` が `event_webhook.jsonl` に変更されます - `event_webhook_error.log` が `event_webhook_error.jsonl` に変更されます - `connection.log` が `connection.jsonl` に変更されます - [CHANGE] サポート用ログファイルである `connection_created_wait_timeout_error/_.json`の拡張子を `.json` から `.jsonl` に変更しました ### クラスター機能 - [CHANGE] クラスターの仕組みを変更したため、2022.1 系までのクラスターの仕組みとは互換性がありません- クラスターの初期化が必要になります - [ADD] クラスター初期化に利用する [InitCluster](EXPERIMENTAL_API.html#621990) API を追加しました - [CHANGE] クラスター機能の [ListClusterNodes](EXPERIMENTAL_API.html#a70901) API の `member_since` を廃止しました - [CHANGE] クラスター機能の [ListClusterChannels](EXPERIMENTAL_API.html#0a4459) API の戻り値を変更しました- `owners` を追加し、その下にリストで `node_name` `epoch` `epoch_latest` `connected` を持つようにしました - `node_in_charge` を `node_name` に変更しました - `node_in_charge_epoch` を `epoch` に変更しました - `node_in_charge_epoch_stale` を `epoch_latest` に変更しました - `node_in_charge_connected` を `connected` に変更しました ### Lyra コーデックへの対応 **これは実験的機能です** - [ADD] `sora.conf` に Google が公開した音声圧縮用超低ビットレートコーデック[Lyra](https://github.com/google/lyra) を有効にする設定 [lyra](SORA_CONF.html#dd7dbd) を追加しました- デフォルトは `false` です - `lyra = true` のように設定してください - [ADD] シグナリング接続時の音声コーデックタイプに Lyra を指定できるようになりました- 指定する際は大文字の `LYRA` で指定する必要があります - Lyra を利用する際は lyra_params を指定する必要があります- `lyra_params` には lyra のバージョンを指定する `version` とビットレートを指定する `bit_rate` が指定できます - `{"audio": "codec_type": "LYRA", "lyra_params": {"version": "1.3.0", "bit_rate": 9200}}` - [ADD] 認証成功時に `{"audio": true, "audio_codec_type": "LYRA", "audio_lyra_params": {"version": "1.3.0", "bitrate": 9200}` のように指定できるようになりました- この指定を利用する場合は [legacy_webhook_audio_video_json_structure](SORA_CONF.html#3be597) を `false` にする必要があります ### 音声ストリーミング機能 **これは実験的機能です** - [ADD] `sora.conf` に音声ストリーミングのリクエスト先の URL を指定する [audio_streaming_url](SORA_CONF.html#6b5dd6) を追加しました - [ADD] `sora.conf` に音声ストリーミングで利用するデフォルトのランゲージコードを指定する [default_audio_streaming_language_code](SORA_CONF.html#856531) を追加しました - [ADD] `sora.conf` に音声ストリーミングでデフォルトで結果をプッシュ通知で行うかどうかを指定する [default_audio_streaming_result_push](SORA_CONF.html#0b4a07) を追加しました - [ADD] `sora.conf` に音声ストリーミングで mTLS を利用する秘密鍵を指定する [audio_streaming_tls_privkey_file](SORA_CONF.html#5f8e61) を追加しました - [ADD] `sora.conf` に音声ストリーミングで mTLS を利用する証明書を指定する [audio_streaming_tls_fullchain_file](SORA_CONF.html#e5459b) を追加しました - [ADD] `sora.conf` に音声ストリーミングで利用する CA ルート証明書を指定する [audio_streaming_tls_verify_cacert_file](SORA_CONF.html#feef99) を追加しました - [ADD] 音声ストリーミングを開始する [StartAudioStreaming](EXPERIMENTAL_API.html#0f1087) API を追加しました - [ADD] 音声ストリーミングを終了する [StopAudioStreaming](EXPERIMENTAL_API.html#bad1bb) API を追加しました - [ADD] 音声ストリーミングの解析結果を購読する [SubscribeAudioStreamingResultPush](EXPERIMENTAL_API.html#d26262) API を追加しました - [ADD] 音声ストリーミングの解析結果を購読解除する [UnsubscribeAudioStreamingResultPush](EXPERIMENTAL_API.html#b63656) API を追加しました 詳細は [音声ストリーミング機能](AUDIO_STREAMING.html) をご確認ください。 ### 音声冗長化機能 - [CHANGE] `sora.conf` の `audio_red` のデフォルト値を `false` に変更しました ### センシティブデータ - [ADD] `sora.conf` にセンシティブなデータが含まれる可能性がある項目を `"REDACTED"` という文字列への書き換えをスキップする [skip_redact_sensitive_data](SORA_CONF.html#00d209) を追加しました- デフォルトでは `false` です - [CHANGE] `sora.conf` の `redact_archive_metadata_sensitive_data` を廃止しました- 録画メタデータファイルの `event_metadata` はセンシティブなデータの書き換え対象外としました - [CHANGE] `sora.conf` の `redact_api_sensitive_data` を廃止しました- API の `event_metadata` はセンシティブなデータの書き換え対象外としました 詳細は [センシティブデータ](SENSITIVE_DATA.html) をご確認ください。 ### ウェブフックの audio と video 項目の JSON 構造のフラット化 - [ADD] `sora.conf` にウェブフックの audio と video 項目のレガシーな JSON 構造する [legacy_webhook_audio_video_json_structure](SORA_CONF.html#3be597) を追加しました- デフォルトでは `true` です - これは移行用設定です 詳細は [ウェブフックの audio と video 項目の JSON 構造のフラット化](WEBHOOK_AUDIO_VIDEO_FLATTEN_JSON.html) をご確認ください ### セッションウェブフックログを req/res 形式に変更 - [CHANGE] `session_webhook.jsonl` の出力形式を req/res 形式に変更しました - [CHANGE] `session_webhook_error.jsonl` の出力形式を req 形式に変更しました ### 録画とアーカイブ開始ウェブフックを追加 - [ADD] 録画開始ウェブフック [recording.started](EVENT_WEBHOOK.html#9b5c58) を追加しました - [ADD] アーカイブ開始ウェブフック [archive.started](EVENT_WEBHOOK.html#462c97) を追加しました - [ADD] `sora.conf` に [ignore_recording_started_webhook](SORA_CONF.html#d9e570) を追加しました- デフォルトでは `false` です - [ADD] `sora.conf` に [ignore_archive_started_webhook](SORA_CONF.html#3fddc0) を追加しました- デフォルトでは `false` です ### ウェブフック mTLS / CA 証明書指定対応 - [ADD] `sora.conf` にウェブフックのリクエスト先との通信で mTLS を利用する際の証明書を指定する [webhook_tls_fullchain_file](SORA_CONF.html#93f2b9) を追加しました - [ADD] `sora.conf` にウェブフックのリクエスト先との通信で mTLS を理世する際の秘密鍵を指定する [webhook_tls_privkey_file](SORA_CONF.html#7065d6) を追加しました - [ADD] `sora.conf` にウェブフックのリクエスト先の証明書をベリファイするルート CA を指定する [webhook_tls_verify_cacert_file](SORA_CONF.html#7036dc) を追加しました ### ウェブフック統計情報 - [ADD] ウェブフック関連の統計情報を GetStatsReport API に追加しました- `total_auth_webhook_allowed`- 認証ウェブフックで許可された数 - `total_auth_webhook_denied`- 認証ウェブフックで拒否された数 - `total_successful_auth_webhook`- 認証ウェブフックが成功した数 - `total_failed_auth_webhook`- 認証ウェブフックが失敗した数 - `total_successful_session_webhook`- セッションウェブフックが成功した数 - `total_failed_session_webhook`- セッションウェブフックが失敗した数 - `total_successful_event_webhook`- イベントウェブフックが成功した数 - `total_failed_event_webhook`- イベントウェブフックが失敗した数 ### クラッシュログ出力 API **これは実験的機能です** - [ADD] 意図的に crash.log を出力させる [GenerateCrashLog](EXPERIMENTAL_API.html#26eea6) API を追加しました- **この API はログ出力の動作確認にのみ利用してください** - この API はかならずステータスコード 500 を返します ## 2022.1.3 **リリース**: 2022-11-02 ### 変更履歴 - [FIX] 依存している OpenSSL を 3.0.7 にアップデートしました - [FIX] データチャネルの性能ボトルネックを修正しました - [FIX] データチャネル利用時に高負荷になった状態が継続する問題を修正しました - [FIX] データチャネル利用時に意図しないメッセージを受信した際の問題を修正しました - [FIX] データチャネル利用時に意図しないエラーが発生する問題を修正しました - [FIX] データチャネル利用時に `compress` が `true` になっている Label のメッセージが壊れている場合の問題を修正しました ## 2022.1.1 **リリース**: 2022-07-12 ### 変更履歴 - [FIX] 依存している OpenSSL を 3.0.5 にアップデートしました - [FIX] 録画機能の `{"type": "split-archive-end"}` ウェブフックには解像度を含めないように修正しました - [FIX] 録画機能の `split-archive-end-.json` ファイルには解像度を含めないように修正しました - [FIX] `sora.log` にでるべきログの一部が `internal.log` に出力されていた問題を修正しました - [FIX] クラスターのノードが異常な状態になったタイミングで `emergency` ログを出力して終了するように修正しました - [FIX] sora.conf の `default_multistream` が true の時に、 `"type": "connect"` メッセージの `role` に `sendrecv` を指定し、かつ `multistream` を `指定しない` 場合に、エラーとなり接続できない問題を修正しました ## 2022.1.0 **リリース**: 2022-06-29 ### ハイライト - Ubuntu 22.04 に対応しました - RHEL 9 に対応しました - サイマルキャスト機能が正式版になりました - スポットライト機能が正式版になりました - スポットライト機能がサイマルキャスト無効でも利用できるようになりました - サイマルキャスト機能やスポットライト機能利用時に、視聴されていないストリームは復号処理を行わない仕組みを追加しました - 録画機能で、録画ファイル分割出力機能を有効にした場合にも recording.report ウェブフック通知とレポートファイルが作成されるようになりました - クラスター利用時に、同一ライセンスを利用できる「最大ノード数ライセンス」の提供を開始しました - クラスター機能で録画状態を共有する機能を追加しました - クラスター機能でクラスター参加を自動で行う仕組みを追加しました - クラスター機能でネットワーク障害発生時に自動で復旧を試みる仕組みを追加しました - 特定の接続からのストリームを受信しないようにできる `bundle_id` を追加しました - センシティブなデータが含まれる可能性がある `session_metadata` や `event_metadata` の値を `"REDACTED"` という文字列に書き換える仕組みを追加しました ### 廃止情報 - `sora.conf` の `demo` を廃止しました - `sora.conf` の `remote_stats` を廃止しました - `sora.conf` の `unuse_metadata_list` を廃止しました - `sora.conf` の `use_re_offer` を廃止しました - [GetAllRemoteStats](OBSOLETE_API.html#3a6504) API を廃止しました - [GetChannelRemoteStats](OBSOLETE_API.html#bbd252) API を廃止しました - [GetConnectionRemoteStats](OBSOLETE_API.html#2f926d) API を廃止しました - [StopRecording](API.html#fd0de5) API の `redirect` を廃止しました ### 互換なしの変更情報 - マルチストリームをデフォルトで有効にしました- `sora.conf` の `default_multistream` を `false` にすることでマルチストリームがデフォルトではなくなります - この設定は 2023 年 6 月リリースの Sora にて廃止されます - 詳細は [sora.conf の default_multistream の廃止](DEPRECATED.html#615559) をご確認ください - `type: archive.end` を `type: split-archive.end` に変更しました- `sora.conf` の `split_archive_legacy_prefix` を `true` にすることで `type: archive.end` がそのまま利用できます - この設定は 2023 年 6 月リリースの Sora にて廃止されます - 詳細は [sora.conf の split_archive_legacy_prefix の廃止](DEPRECATED.html#050276) をご確認ください - `type: archive.split` を `type: split-archive.available` に変更しました- `sora.conf` の `split_archive_legacy_prefix` を `true` にすることで `type: archive.split` がそのまま利用できます - この設定は 2023 年 6 月リリースの Sora にて廃止されます - 詳細は [sora.conf の split_archive_legacy_prefix の廃止](DEPRECATED.html#050276) をご確認ください - `archive-_.webm` を `split-archive-_.webm` に変更しました- `sora.conf` の `split_archive_legacy_prefix` を `true` にすることで `archive-_.webm` がそのまま利用できます - この設定は 2023 年 6 月リリースの Sora にて廃止されます - 詳細は [sora.conf の split_archive_legacy_prefix の廃止](DEPRECATED.html#050276) をご確認ください - `archive-_.json` を `split-archive-_.json` に変更しました- `sora.conf` の `split_archive_legacy_prefix` を `true` にすることで `archive-_.json` がそのまま利用できます - この設定は 2023 年 6 月リリースの Sora にて廃止されます - 詳細は [sora.conf の split_archive_legacy_prefix の廃止](DEPRECATED.html#050276) をご確認ください - セッションウェブフックでセッションの接続数が 0 のタイミングで `multistream` と `spotlight` がセッションと異なる新規接続が来た場合は既存のセッションを破棄し `session.destroyed` ウェブフックリクエストを送信した後に、新規でセッションを作成し `session.created` を送信するように変更しました - セッションウェブフックでセッションの接続数が 0 ではないタイミングで `multistream` と `spotlight` がセッションと異なる新規接続が来た場合は `INVALID-SIGNALING-PARAMS` エラーを返し切断するように変更しました - セッションウェブフック `session.created` と `session.destroyed` の `created_time` と `destroyed_time` を UNIX 時間に変更しました - `sora.log` と `internal.log` の時刻を RFC3339 準拠に変更しました - `cluster` 関連設定名を変更しました- `cluster_node_name` を `node_name` へ変更しました - `cluster_api_url` を `external_api_url` へ変更しました - `cluster_signaling_url` を `external_signaling_url` へ変更しました - `sora_version` を `version` に変更しました - `cluster` 関連 API の引数や戻り値を変更しました - クラスター機能を有効にしたときのモードを `initial` へ変更しました - クラスターに参加したときに自動でモードが `initial` から `normal` へ切り替わるよう変更しました ### 変更履歴 - [CHANGE] セッションウェブフック `session.created` の `created_time` を UNIX 時間に変更しました - [CHANGE] セッションウェブフック `session.destroyed` の `created_time` を UNIX 時間に変更しました - [CHANGE] セッションウェブフック `session.destroyed` の `destroyed_time` を UNIX 時間に変更しました - [UPDATE] 組み込みの開発ツールを `2022.1.0` にアップデートしました - [ADD] RHEL 9 x86_64 に対応しました - [ADD] Ubuntu 22.04 x86_64 に対応しました - [ADD] イベントウェブフック `connection.created` に RFC3339 形式で出力する `created_timestamp` を追加しました - [ADD] イベントウェブフック `connection.updated` に RFC3339 形式で出力する `created_timestamp` を追加しました - [ADD] イベントウェブフック `connection.destroyed` に RFC3339 形式で出力する `created_timestamp` を追加しました - [ADD] イベントウェブフック `connection.destroyed` に RFC3339 形式で出力する `destroyed_timestamp` を追加しました - [ADD] イベントウェブフック `connection.destroyed` に UNIX 時間で出力する `destroyed_time` を追加しました - [ADD] [GetStatsReport](EXPERIMENTAL_API.html#bbbfca) API に Sora のバージョンを取得できる `version` を追加しました - [ADD] 認証成功時の H.265 の払い出しを追加しました - [ADD] 認証ウェブフックに `simulcast_rid` を追加しました - [ADD] Sora 内部で利用するファイルを書き出す `data` ディレクトリを追加しました - [ADD] `sora.conf` に Sora 内部で利用するファイルを書き出す `data` ディレクトリを指定する `data_dir` を追加しました - [FIX] Opus の RED の仕様変更ともない動作しなくなっていた問題を修正しました - [FIX] 0 番ポートでパケットが送られてきた場合の問題を修正しました - [FIX] DTLS で異常なパケットが送られてきた場合でも可能な限り丁寧に終了処理を行うように修正しました - [FIX] 異常な STUN パケットが送られてきた場合の問題を修正しました - [FIX] 録画した WebM ファイルの `Cluster Timecode` が負の値になると発生する問題を修正しました #### マルチストリームをデフォルトで有効化 マルチストリームをデフォルトで有効にしました。 いままでマルチストリームを利用する場合は、シグナリング接続時に `"multistream": true` を指定して有効にする必要がありました。これをデフォルトで有効に変更しました。 今後は、マルチストリームを利用しない場合は明示的に `"multistream": false` を指定する必要があります。 - [CHANGE] マルチストリームをデフォルトで有効に変更しました - [ADD] `sora.conf` にマルチストリームのデフォルト値を指定する `default_multistream` を追加しました- デフォルトでは `true` が設定されています - この設定は 2023 年 6 月リリース予定の Sora にて廃止します - 詳細は [sora.conf の default_multistream の廃止](DEPRECATED.html#615559) をご確認ください 例外的にスポットライト機能を利用するときは `"multistream": true` を明示する必要があります。 #### bundle_id の追加 複数のコネクションを同じ端末から接続する際、それぞれのコネクションで同一の `bundle_id` を指定すると、 同一の `bundle_id` を指定した接続からの音声や映像、メッセージングを受信しなくなります。 画面共有の映像を受信したくない場合などにお使いください。 - [ADD] `sora.conf` に `"type": "connect"` 時に `bundle_id` を指定できるかどうかを設定する [signaling_bundle_id](SORA_CONF.html#279311) を追加しました- デフォルトでは `false` が設定されています - [ADD] `sora.conf` に [signaling_notify_bundle_id](SORA_CONF.html#f2a58f) を追加しました- デフォルトでは `true` が設定されています - [ADD] `"type": "connect"` で `bundle_id` が指定可能になりました- 詳細は [bundle_id の指定](SIGNALING.html#196326) をご確認ください - [ADD] 認証成功時の払い出しで `bundle_id` を指定可能になりました- 詳細は [bundle_id の払い出し](AUTH_WEBHOOK_RETURN.html#d2b87b) をご確認ください #### sora.log と internal.log の出力 - [CHANGE] タイムスタンプの出力を RFC3339 準拠に変更しました- Sora 2021.2.7 まで- `2022-03-07 02:54:26.847 UTC [info] [-/-/-] <0.1218.0> SORA | node_name=sora@192.0.2.1, version=2021.2.7` - Sora 2022.1.0 から- `2022-03-07T02:54:26.847130Z [info] [-/-/-] <0.1218.0> SORA | node_name=sora@192.0.2.1, version=2022.1.0` #### 録画機能 - [CHANGE] 分割録画ファイルとメタデータファイルの出力名を `archive-_.(json|webm)` から `split-archive-_.(json|webm)` に変更しました- `sora.conf` の `split_archive_legacy_prefix` を `true` にすることで `archive-_.(json|webm)` を維持できます - [CHANGE] 録画分割時のウェブフックのタイプ `"type": "archive.split"` を `"type": "split-archive.available"` に変更しました - [CHANGE] 録画分割時のウェブフックのタイプ `"type": "split.end"` を `"type": "split-archive.end"` に変更しました - [CHANGE] 録画一時ファイルディレクトリ `archive_tmp_dir` に保存される録画一時ファイルは、録画が失敗した場合には削除されなくなりました - [ADD] `report-.json` に `node_name` と `label` 項目を追加しました - [ADD] `sora.conf` に分割録画ファイル名を `archive-_.(json|webm)` にする `split_archive_legacy_prefix` を追加しました- デフォルトは `false` です - この設定は 2023 年 6 月リリース予定の Sora にて廃止します - 詳細は [sora.conf の split_archive_legacy_prefix の廃止](DEPRECATED.html#050276) をご確認ください - [ADD] 録画の状態をクラスターで共有する仕組みを追加しました - [ADD] `split_only` に `true` を指定した場合に、 `archive.end` ウェブフックと対になる `split-archive-end-.json` ファイルを作成するようになりました - [ADD] `split_only` に `true` を指定した場合でも `recording.report` ウェブフックリクエストを飛ばすようになりました - [ADD] `split_only` に `true` を指定した場合でも `report-.json` ファイルを作成するようになりました - [ADD] 録画メタデータファイルとレポートファイルに `label` と `node_name` を追加するようにしました - [UPDATE] 録画で生成された WebM ファイルが Windows の `Windows標準アプリケーションの"映画&テレビ"` で正常に再生できない問題へ対応しました- Sora 側の問題ではなく `Windows標準アプリケーションの"映画&テレビ"` が WebM の仕様を守っていないことによる問題です #### サイマルキャストやスポットライト機能利用時の負荷削減 - [ADD] サイマルキャストやスポットライト利用時に誰も視聴していない音声や映像ストリームの復号を行わない処理を追加しました - [ADD] 統計 API の rtp 項目に `tocal_decrypt_skipped_audio_srtp` を追加しました - [ADD] 統計 API の rtp 項目に `tocal_decrypt_skipped_video_srtp` を追加しました - [ADD] 統計 API の simulcast.rtp.(r0|r1|r2) 項目に `total_decrypt_skipped_srtp` を追加しました #### サイマルキャスト無効でのスポットライト機能利用 - [ADD] スポットライト機能を `"simulcast": false` でも利用可能になりました #### クラスター機能 - [CHANGE] クラスター有効時に起動した際のモードを `initial` モードに変更しました - [CHANGE] クラスターに参加したタイミングで自動で `initial` モードから `normal` モードに切り替わるように変更しました - [CHANGE] `sora.conf` の `cluster_node_name` を `node_name` に変更しました - [CHANGE] `sora.conf` の `cluster_signaling_url` を `external_signaling_url` に変更しました - [CHANGE] `sora.conf` の `cluster_api_url` を `external_api_url` に変更しました - [CHANGE] クラスター有効時に sora.log / internal.log にクラスターノード名を出力するように変更しました - [CHANGE] [JoinCluster](EXPERIMENTAL_API.html#17f3f5) API の `cluster_node_name` を `contact_node_name` に変更しました - [CHANGE] [ListClusterNodes](EXPERIMENTAL_API.html#a70901) API の `cluster_node_name` を `node_name` に変更しました - [ADD] クラスターから特定のノードの情報を完全消去する [PurgeClusterNode](EXPERIMENTAL_API.html#13b35a) API を追加しました - [ADD] `sora.conf` に Sora 起動時に自動でクラスター参加を試みる `contact_node_name_list` を追加しました- 詳細は [contact_node_name_list](CLUSTER.html#a3d0fd) をご確認ください - [ADD] `sora.conf` にネットワーク障害等発生時に自動で再接続を試みる `cluster_auto_reconnect` を追加しました- デフォルトは有効です - 詳細は [cluster_auto_reconnect](CLUSTER.html#42cbc5) をご確認ください - [ADD] ネットワーク障害等発生時に自動で復旧を試みる仕組みを追加しました- 詳細は以下をご確認ください - [通信できるノードが過半数未満となった場合の挙動](CLUSTER.html#2ccf66) - [通信できるノードが過半数以上となった場合の挙動](CLUSTER.html#1d8f01) - [全ノードが過半数未満に所属した場合の挙動](CLUSTER.html#f87161) #### 最大ノード数対応ライセンス クラスター利用時に複数のノードに同一ライセンスを利用可能にする最大ノードライセンスの提供を開始しました。 詳細は [最大ノード数ライセンス](LICENSE.html#aee259) をご確認ください。 - [CHANGE] 最大ノード数ライセンスに対応していない同一ライセンスを複数のノードに適用し、クラスターを構築しようとすると `DUPLICATE-LICENSE` が出力されるように変更されました- 無制限ライセンスをご利用のお客様でクラスターを利用されている場合はサポートまでご連絡ください - [ADD] クラスター利用時に同一ライセンスを利用可能な最大ノード数ライセンスに対応しました- **新規でライセンスを発行し直す必要がありますのでサポートまでご連絡ください** - 新しくライセンスに `max_nodes` という項目を追加し、この最大ノード数までは複数の Sora で同一ライセンスを利用可能になります #### 統計機能 - [ADD] 統計 API の rtp 項目に `total_received_srtp_invalid` を追加しました - [ADD] 統計 API の turn 項目に `total_received_unknown_packet` を追加しました - [ADD] 統計 API の turn 項目に `total_received_stun_unknown` を追加しました - [ADD] 統計 API の turn 項目に `total_received_stun_invalid` を追加しました - [ADD] 統計 API の turn 項目に `total_received_turn_invalid_stun` を追加しました - [ADD] データチャネルの破棄やリトライの回数をラベルごとに取得できるようになりました- データチャネルの破棄メッセージ数 `total_data_channel_abandon_message` を追加しました - データチャネルの再送メッセージ数 `total_data_channel_retransmit_message` を追加しました - データチャネルの `DATA_CHANNEL_OPEN` メッセージ数 `total_data_channel_ack_message` を追加しました - データチャネルの `DATA_CHANNEL_ACK` メッセージ数 `total_data_channel_open_message` を追加しました - [UPDATE] `total_sent_data_channel_message` から `DATA_CHANNEL_OPEN` メッセージを除外しました - [UPDATE] `total_received_data_channel_message` から `DATA_CHANNEL_ACK` メッセージを除外しました #### センシティブデータ編集済出力機能 詳細は [センシティブデータ](SENSITIVE_DATA.html) をご確認ください。 - [CHANGE] `auth_webhook.log` に含まれる `event_metadata` の中身を編集済みを表す `"REDACTED"` という文字列に書き換える変更を行いました - [CHANGE] `session_webhook.log` に含まれる `session_metadata` と `event_metadata` の中身を編集済みを表す `"REDACTED"` という文字列にに書き換える変更を行いました - [CHANGE] `event_webhook.log` に含まれる `event_metadata` の中身を編集済みを表す `"REDACTED"` という文字列にに書き換える変更を行いました- `event_webhook_error.log` の `event_metadata` は書き換えを行いません - [ADD] `sora.conf` にAPI 戻り値に含まれるセンシティブな可能性があるデータを編集済みを表す `"REDACTED"` という文字列に書き換える `redact_api_sensitive_data` を追加しました- デフォルトでは `true` - `event_metadata` の中身を `"REDACTED"` という文字列に書き換えます - [ADD] `sora.conf` に録画メタデータファイルに含まれるセンシティブな可能性があるデータを `"REDACTED"` という文字列に書き換える `redact_archive_metadata_sensitive_data` を追加しました- デフォルトでは `true` - `event_metadata` の中身を `"REDACTED"` という文字列に書き換えます # 既知の問題 **既知の問題の詳細についてはサポートまでお問い合わせください** ## サイマルキャスト録画 - Windows 版 Chrome で H.264 のサイマルキャストを録画した場合に画質が悪くなります ## マルチストリーム - `"type": "sendrecv"` 利用時に音声のみや映像のみを指定した場合でも、音声と映像の両方が送られてきます- 今後改善予定です ## 仕様としての制限 ### マルチトラック - 1 つのストリームに 1 オーディオトラック、1 ビデオトラックしか設定できません- マルチトラックへの対応は検討していますが未定です # 実験的機能 > **重要** > > 実験的機能を本番で利用する場合は **必ず** サポートまでご連絡ください。 ## 概要 実験的機能とは、バージョンを上げるごとに積極的に改善を行い、 お客さまのフィードバックをもとに本番採用するかどうかを決めるための機能です。 そのため、後方互換性を無視した仕様の変更が積極的に行われます。 ## 実験的機能一覧 最新版のリリース時点で実験的機能として提供している機能一覧です。 - [音声ストリーミング機能](AUDIO_STREAMING.html) - [DataChannel 経由のシグナリング](DATA_CHANNEL_SIGNALING.html) - [メッセージング機能](MESSAGING.html) - [セッションウェブフック](SESSION_WEBHOOK.html) - [モード機能](MODE.html) - [クラスター機能](CLUSTER.html) - [統計エクスポーター機能](STATS_EXPORTER.html) - [E2EE 機能](E2EE.html) - [センシティブデータ](SENSITIVE_DATA.html) - 映像コーデックのビットレートを 15Mbps より大きく指定した場合 - 片方向配信時の視聴側帯域推定を利用した配信ビットレートの自動変更機能 - クラッシュログ出力 API - Opus パラメータ指定機能- [opus_param_channels](SORA_CONF.html#f049c1) - [opus_param_maxplaybackrate](SORA_CONF.html#f707c2) - [opus_param_stereo](SORA_CONF.html#d5e189) - [opus_param_sprop_stereo](SORA_CONF.html#1824af) - [opus_param_minptime](SORA_CONF.html#043cf2) - [opus_param_useinbandfec](SORA_CONF.html#1606be) - [opus_param_usedtx](SORA_CONF.html#579143) - Lyra コーデック - H.265 対応 ## 実験的機能一覧 API 詳細は [実験的 API](EXPERIMENTAL_API.html) をご確認ください # 非推奨機能 ここでは今後廃止される非推奨の機能について説明していきます。 不明点はサポートまでお問い合わせください。 ## Ubuntu 18.04 サポートの終了 **サポート提供終了**: 2023 年 4 月末 [Ubuntu release cycle | Ubuntu](https://ubuntu.com/about/release-cycle) Ubuntu 18.04 は 2023 年 6 月末で通常サポートが終了します。 Ubuntu 側から 4 月末での通常サポート終了が 6 月末まで延長されましたが、 Sora は当初の予定のまま 2023 年 4 月末をもって Ubuntu 18.04 版のサポートとパッケージの提供を終了します。 Ubuntu 20.04 または Ubuntu 22.04 版への移行をお願いいたします。 Ubuntu 18.04 を利用しているお客様は、サポートまで切り替え先の OS をご連絡ください。 ## sora.conf の split_archive_legacy_prefix の廃止 > **重要** > > **2023 年 6 月リリース予定の Sora にて廃止** `sora.conf` の `split_archive_legacy_prefix` 設定を廃止します。 - 分割録画ファイル名 `archive-_.(json|webm)` が利用できなくなります- `split-archive-_.(json|webm)` を利用するように変更してください - 分割録画時のイベントウェブフックタイプ `"type": "archive.split"` が利用できなくなります- `"type": "split-archive.available"` を利用するように変更してください - 分割録画時のイベントウェブフックタイプ `"type": "archive.end"` が利用できなくなります- `"type": "split-archive.end"` を利用するように変更してください ## sora.conf の default_multistream の廃止 > **重要** > > **2023 年 6 月リリース予定の Sora にて廃止** `sora.conf` の `default_multistream` 設定を廃止します。 今後は接続時に `multistream` を指定せずに接続した場合は常にマルチストリームが有効になります。 マルチストリームを無効したい場合は明示的に `"multistream": false` を指定してください。 ## sora.conf の legacy_log_format の廃止 > **重要** > > **2023 年 12 月リリース予定の Sora にて廃止** sora ログや internal ログをレガシーフォーマットで出力する `sora.conf` の `legacy_log_format` 設定を廃止します。 > **注意** > > 2023 年 6 月リリース予定の Sora にてデフォルトを `false` に変更します。 ## sora.conf の legacy_log_extension の廃止 > **重要** > > **2023 年 12 月リリース予定の Sora にて廃止** JSONL 形式で出力するログの拡張子を `.log` でファイル出力する `sora.conf` の `legacy_log_extension` 設定を廃止します。 > **注意** > > 2023 年 6 月リリース予定の Sora にてデフォルトを `false` に変更します。 ## sora.conf の legacy_webhook_audio_video_json_structure の廃止 > **重要** > > **2023 年 12 月リリース予定の Sora にて廃止** ウェブフックで利用する audio と video の JSON 構造を `{"audio": {"codec_type": "OPUS"}}` といった入れ子構造にする `sora.conf` の `legacy_webhook_audio_video_json_structure` 設定を廃止します。 > **注意** > > 2023 年 6 月リリース予定の Sora にてデフォルトを `false` に変更します。 ## API [非推奨 API](DEPRECATED_API.html) をご確認ください # 廃止機能 ## 概要 廃止機能とはすでに廃止された機能です。 API の廃止については [廃止 API](OBSOLETE_API.html) をご確認ください。 ## redact_archive_metadata_sensitive_data と redact_api_sensitive_data の廃止 **2022 年 12 月リリースの Sora にて廃止** 録画メタデータと API のセンシティブデータを **"REDACTED"** という文字列に書き換えを廃止しました。 今後はこれらのデータは書き換えを行いません。 ## recording.report の metadata_filename と metadata_file_path の廃止 **2022 年 12 月リリースの Sora にて廃止** 録画イベントウェブフックの `recording.report` に含まれる `metadata_filename` と `metadata_file_path` が `filename` と `file_path` に変更されます。 2021 年 12 月リリースの Sora にて `filename` と `file_path` が追加されていますので、そちらを利用するように変更してください。 ## シグナリング通知メタデータ metadata_list の廃止 **2022 年 6 月リリースの Sora にて廃止** `metadata_list` が `data` に変更されました。 ## `"type": "update"` の廃止 **2022 年 6 月リリースの Sora にて廃止** マルチストリーム機能利用時のシグナリングで利用する `"type": "update"` を廃止し、 `"type": "re-offer"` と `"type": "re-answer"` に変更しました。 ## sora.conf の demo の廃止 **2022 年 6 月リリースの Sora にて廃止** `sora.conf` の `demo` を廃止しました。今後は `devtools` を利用してください。 これは `デモ機能` が `開発者ツール` へと名前を変更したことによる影響です。 ## sora.conf の remote_stats の廃止 **2022 年 6 月リリースの Sora にて廃止** `sora.conf` の `remote_stats` を廃止しました。今後は `user_agent_stats` を利用してください。 これは `リモート統計情報` が `ユーザーエージェント統計情報` へと名前を変更したことによる影響です。 ## StopRecording API の redirect の配信 **2022 年 6 月リリースの Sora にて廃止** 録画機能がクラスターで共有できるようになったことにより、 `redirect` 指定が不要になったため廃止しました。 ## CentOS 8 対応 **サポート提供終了**: 2021 年 12 月 - [CentOS Project shifts focus to CentOS Stream – Blog.CentOS.org](https://blog.centos.org/2020/12/future-is-centos-stream/?utm_source=rss&utm_medium=rss&utm_campaign=future-is-centos-stream) - [FAQ - CentOS Project shifts focus to CentOS Stream](https://centos.org/distro-faq/) - [FAQ: CentOS Stream Updates](https://www.redhat.com/ja/blog/faq-centos-stream-updates) CentOS 8 は 2021 年 12 月をもってサポートが終了しました。 それに伴い Sora は 2021 年 12 月末をもって CentOS 8 版のサポートとパッケージの提供を終了しました。 ## extmap_allow_mixed 設定のデフォルト有効化と廃止 **2021 年 12 月リリースの Sora にて廃止** Chrome M89 にて `a=extmap-allow-mixed` がデフォルトで設定されるようになり、 また Firefox 側でも動作に問題がなくなったことからこちらの設定が不要となりました。 2021 年 6 月リリースの Sora でデフォルト有効とし、2021 年 12 月リリースの Sora にて設定を廃止しました。 ## スポットライトレガシー機能の廃止 **2021 年 12 月リリースの Sora にて廃止** スポットライトレガシー機能は 2021 年 12 月リリースの Sora で廃止しました。 今後は [スポットライト機能](SPOTLIGHT.html) を利用してください。 ## `rtp` にある RTCP 関連統計情報を廃止 **2021 年 12 月リリースの Sora にて廃止** 統計 API の `rtp` 項目に入っている RTCP 関連統計情報を `rtcp` 項目として独立させました。 これに伴い `rtp` にある RTCP 関連統計情報を廃止しました。 ## `sora.conf` の `opus_param_clock_rate` を廃止 **2021 年 12 月リリースの Sora にて廃止** 実験的機能として提供していた `opus_param_clock_rate` を廃止しました。 ## `sora.conf` の `dcsctp_association_max_retrans` を廃止 **2021 年 12 月リリースの Sora にて廃止** 実験的機能として提供していた `dcsctp_association_max_retrans` を廃止しました。 今後は [ICE コネクションステート機能](ICE_CONNECTION_STATE.html) を利用してください。 ## role の upstream と downstream を廃止 **2021 年 6 月リリースの Sora にて廃止** `upstream` と `downstream` は 2021 年の 6 月リリースの Sora で廃止しました。 - マルチストリームの `upstream` は `sendrecv` をお使い下さい - マルチストリームの `downstream` は `recvonly` をお使い下さい - スポットライトの `upstream` は `sendrecv` をお使い下さい - スポットライトの `downstream` は `recvonly` をお使い下さい - 片方配信の `upstream` は `sendonly` をお使い下さい - 片方配信の `downstream` は `recvonly` をお使い下さい ### シグナリング接続 - シグナリング接続時に指定する `role` の `upstream` と `downstream` を廃止しました ### 認証ウェブフック - 認証ウェブフックの `channel_upstream_connections` を廃止しました- 今後は `channel_sendrecv_connections` または `channel_sendonly_connections` をご利用ください - 認証ウェブフックの `channel_downstream_connections` を廃止しました- 今後は `channel_recvonly_connections` をご利用ください ### イベントウェブフック - イベントウェブフック `*.connection` の `channel_upstream_connections` を廃止しました- 今後は `channel_sendrecv_connections` または `channel_sendonly_connections` をご利用ください - イベントウェブフック `*.connection` の `channel_downstream_connections` を廃止しました- 今後は `channel_recvonly_connections` をご利用ください ### シグナリング通知 - シグナリング通知 `*.connection` の `channel_upstream_connections` を廃止しました- 今後は `channel_sendrecv_connections` または `channel_sendonly_connections` をご利用ください - シグナリング通知 `*.connection` の `channel_downstream_connections` を廃止しました- 今後は `channel_recvonly_connections` をご利用ください ### API - `Sora_20151104.DisconnectChannelUpstream` API を廃止しました- 今後は [DisconnectChannelByRole](API.html#39de6a) API をご利用ください - `Sora_20151104.DisconnectChannelDownstream` API を廃止しました- 今後は [DisconnectChannelByRole](API.html#39de6a) API をご利用ください - `Sora_20160711.PushUpstream` API を廃止しました- 今後は [PushChannelByRole](API.html#bc57a2) API をご利用ください - `Sora_20160711.PushDownStream` API を廃止しました- 今後は [PushChannelByRole](API.html#bc57a2) API をご利用ください ## client_id を指定する設定の廃止 **2021 年 6 月リリースの Sora にて廃止** `sora.conf` の `allow_client_id_assignment` 設定を廃止し `client_id` はクライアント側で指定できるようにします。 ### sora.conf - `sora.conf` の `allow_client_id_assignment` を廃止しました ### API - `Sora_20170529.GetStats` API を廃止しました- `allow_client_id_assignment` 廃止に伴う廃止のため代替はありません - `Sora_20170814.StartForwardingRtp` API の `client_id` 指定を廃止しました- `allow_client_id_assignment` 廃止に伴う廃止のため代替はありません - `Sora_20170814.StopForwardingRtp` API の `client_id` 指定を廃止しました- `allow_client_id_assignment` 廃止に伴う廃止のため代替はありません - `Sora_20151104.ListConnections` API を廃止しました- 今後は [ListChannelConnections](API.html#d388f3) API をご利用ください - `Sora_20151104.Disconnect` API を廃止しました- 今後は [DisconnectClient](API.html#e91c0b) API をご利用ください ## 旧サイマルキャスト画質変更 API の廃止 **2021 年 6 月リリースの Sora にて廃止しました** - `Sora_20180820.ChangeSimulcastQuality`- 今後は [RequestRtpStream](API.html#6fe0b3) API をご利用ください この API の廃止に伴い、シグナリング接続時や認証成功時に指定するサイマルキャストの `quality` での `low` / `middle` / `high` 指定を廃止しました。 今後は `rid` と `r0` / `r1` / `r2` を利用してください。 ## bin/sora start の廃止 **2020 年 12 月リリースの Sora にて廃止しました** `bin/sora start` は 2020 年 12 月リリースの Sora 2020.3 で廃止しました。 今後は `bin/sora daemon` を利用してください。 systemd を利用されている方は `bin/sora foreground` を利用されていると思いますが、こちらに変更はありません。 ## Ubuntu 16.04 サポートの終了 **サポート提供終了**: 2021 年 4 月末 [Ubuntu release cycle | Ubuntu](https://ubuntu.com/about/release-cycle) Ubuntu 16.04 は 2021 年 4 月を持って通常サポートが終了しました。 それに伴い Sora は 2021 年 4 月末をもって Ubuntu 16.04 版のサポートとパッケージの提供を終了しました。 Ubuntu 18.04 または Ubuntu 20.04 版への移行をお願いいたします。 Ubuntu 16.04 を利用しているお客様は、サポートまで切り替え先の OS をご連絡ください。 # FAQ ここでは WebRTC SFU Sora に関するよくある質問についてまとめています。 ## WebRTC 全般 ### 片方向配信には対応していますか? 対応しています。 2022 年 12 月 の時点で 1 チャネルあたり最大 1000 視聴者までの配信を推奨しています。 1 チャネルで 1000 より多い視聴者に配信を行いたい場合は sora at shiguredo.jp またはサポートまでお問い合わせ下さい。 ### 双方向配信には対応していますか? 対応しています。WebRTC のマルチストリームという技術を利用して実現しています。 2022 年 12 月 の時点で 1 チャネルに参加するクライアントは 12 までを推奨としています。 1 チャネルで 12 より多いクライアントで双方向の配信を行いたい場合は [スポットライト機能](SPOTLIGHT.html) を検討するかサポートまでお問い合わせ下さい。 ### 音声検出による映像の切り替えには対応していますか? 対応しています。Sora 独自にスポットライト機能という名前で提供しています。 この機能は多人数で会議を行う場合に、クライアントやサーバーの負荷を減らせる技術です。 100 名以上が 1 チャネルに参加することが可能です。 詳細は [スポットライト機能](SPOTLIGHT.html) をご確認ください ### スクリーンキャプチャ機能には対応していますか? 2022 年 12 月 の時点でスクリーンキャプチャ機能はブラウザでは Chrome と Firefox と Safari と Edge が対応しています。 getDisplayMedia を利用することで可能になります。 [MediaDevices.getDisplayMedia() - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia) ### マルチストリームには対応していますか? 対応しています。ブラウザでは Chrome と Firefox と Safari と Edge で対応しています。 また、すべての SDK が対応しています。 ### マルチトラックには対応していますか? いいえ。 Sora は 1 メディアストリームにつき 1 音声トラック、1 映像トラックまでしか対応していません。 マルチトラックへの対応は今のところ未定です。 ### 複数の音声や映像を 1 つのコネクションを利用して送ることは可能ですか? いいえ。 1 つのコネクションから複数ストリームを配信をすることはできません。 1 接続では 1 ストリーム (1 音声/1 映像)の配信のみが可能です。 複数の配信を行いたい場合はマルチストリームの sendonly ロールを利用して複数接続してください。 ### 1 ユーザーで送受信と送信のみを利用している場合、送受信側で送信のみの音声や映像を受信しないことは可能ですか? はい、可能です。接続時、または認証成功時に [bundle_id](SIGNALING.html#b23b22) で同じ値を指定してください。 > **注釈** > > 接続時の場合は `sora.conf` の [signaling_bundle_id](SORA_CONF.html#279311) を `true` にする必要があります。 `bundle_id` が同じ接続では送信のみの音声と映像を送受信側で受信しなくなります。 ### 映像コーデックは何がお勧めですか? すべてのブラウザ、さらにほぼすべての端末で動作する VP8 がお勧めです。 ただし、端末に VP8 のハードウェアアクセラレータが搭載されていることはほとんどないため、 H.264 を採用した方が電池消費量は減ります。 一方で、H.264 は一部の Android 端末で正常に動作しないことがあります。 すべての環境が Chrome や Edge に統一できる場合は VP9 をお勧めします。 ### H.264 や VP9 での映像配信に対応していますか? ブラウザがそれぞれのコーデックに対応していれば、 Sora は問題なく配信できます。 2022 年 12 月 の時点では ... - Chrome M107 は VP8, VP9, AV1, H.264 に対応しています - Firefox 107 は VP8, VP9, H.264 に対応しています - Edge 107 は VP8, VP9, H.264 に対応しています - Safari 16.1 は VP8, VP9, H.264 に対応しています- Safari 14 から実験的機能として H.265 対応が追加されています Sora は配信者がコーデックを選択できる仕組みを採用しています。 詳細は [シグナリング](SIGNALING.html) をご確認ください ### Safari は WebRTC に対応していますか? はい。 Safari 12 で WebRTC に対応しました。 詳細は [Apple Safari の WebRTC について](SAFARI.html) をご確認ください。 ### Chrome や Edge では HTTPS が必須ですか? はい。ローカルホスト以外からのアクセスでブラウザで getUserMedia を使用する場合は HTTPS が必須になります。 もし、開発中に HTTP でアクセスしたい場合は、以下を参考にしてください。 [http でのアクセスでカメラの映像を取得する - Qiita](https://qiita.com/Hexa/items/a5e5c3e06ba2a3e6bb41) ### Safari では HTTPS が必須ですか? はい。ただし、 開発者メニューから HTTP でも getUserMedia を使用できるようにするオプションが用意されています。 ### Edge は WebRTC に対応していますか? はい。 Chrome とほぼ同等のレベルで WebRTC が利用できます。 詳細は [Microsoft Edge の WebRTC について](EDGE.html) をご確認ください。 ### サーバー側からクライアントごとにコーデックやビットレートを指定できますか? 可能です。 Sora からクライアントに送信する Offer に含める SDP を、クライアントごとに変更することが可能です。 詳細については [認証ウェブフック成功時の払い出し](AUTH_WEBHOOK_RETURN.html#e2119f) をご確認ください。 ### コーデックが異なるクライアントでも同じチャネルで双方向通信は可能ですか? 可能です。マルチストリームを利用することで接続ごとにコーデックを指定できます。 例えば、iOS の Safari は H.264 で、デスクトップの Chrome は VP8 という場合でも同じチャネルで双方向通信が可能です。 ただし、ブラウザが非対応の場合はもちろん送受信できませんのでご注意ください。 ### Firefox で複数タブで音声デバイスを利用できますか? いいえ。 Firefox 56 から複数タブで音声デバイスを利用することができなくなりました。 ### Safari で音声が有効な場合、自動で視聴を開始できますか? いいえ。 Safari の仕様で、音声が含まれている映像を自動で再生することはできません。 ### 高いビットレートで配信することは可能ですか? Sora では最大 50Mbps での配信を可能としていますが、 今のところは 15Mbps より大きなビットレートでの配信はサポート対象外とさせていただいています。 配信自体は可能ですが、クライアント、サーバーともに不安定になることがあるためです。 今後、高いビットレートでの配信を安定して実現できるようにしていく予定です。 ### 4K 30fps を実現したいのですが可能ですか? 可能です。ただしクライアント側の負荷がとても高くなります。 4K 30fps を配信するためにはソフトウェアエンコードでの配信はほぼ不可能です。 そのため 4K 30fps に対応したハードウェアエンコーダーが必要になります。 時雨堂では [WebRTC Native Client Momo](https://momo.shiguredo.jp/) という、 様々なハードウェアエンコーダーに対応したクライアントをオープンソースで公開していますので、是非試してみてください。 [shiguredo/momo: WebRTC Native Client Momo](https://github.com/shiguredo/momo) ### 映像をフレームレート 60 や 120 で配信することは可能ですか? Sora は映像のフレームレートには関与しません。 フレームレートはカメラが対応していること、また、クライアントが対応していることが必要になります。 ### カメラで指定した解像度より低い解像度で配信されるのですが? カメラ映像の解像度と WebRTC でエンコードされて配信される解像度は一致しません。 カメラから入ってくる映像を WebRTC では圧縮して配信します。WebRTC は圧縮時に CPU 使用率が高い、ネットワーク帯域不足などの状況に応じ、自動で解像度やフレームレートを落として配信できる状態にして配信します。 ### WebRTC DataChannel には対応していますか? 対応しています。 2022 年 12 月 の時点では、シグナリング機能とメッセージング機能として DataChannel を利用することが可能です。 詳細は [DataChannel 経由のシグナリング](DATA_CHANNEL_SIGNALING.html) や [メッセージング機能](MESSAGING.html) をご確認ください。 ### 音声のステレオには対応していますか? 対応しています。 ただしステレオで音声をエンコード/デコードするかどうかはクライアント側に依存します。 例えばブラウザの場合はデフォルトでステレオに対応していますが、エコーキャンセルが有効な場合はステレオは利用できません。 エコーキャンセルを無効にすることでステレオが利用できるようになります。 エコーキャンセルの設定は以下を参考にしてください。 [Media Capture and Streams](https://www.w3.org/TR/mediacapture-streams/#dom-mediatracksupportedconstraints-echocancellation) ## シグナリング ### シグナリングは独自仕様ですか? 独自仕様です。 WebRTC の規格ではシグナリング部分は定義されていないため、 WebRTC で利用されるシグナリングは独自仕様が前提になります。 Sora は `JSON over WebSocket` または `JSON over DataChannel` をシグナリングの仕様として採用しています。 Sora の SDK を利用すればシグナリングを意識する必要がありません。 Sora のシグナリングの詳細な仕様について確認したい場合は、[シグナリング](SIGNALING.html) をご確認ください。 ### シグナリングに WebSocket (WS) ではなく WebSocket over TLS (WSS) を使うことは可能ですか? getUserMedia を使用する場合、 ローカルホスト以外のアクセスは WSS を必須としています。 ただし、Sora は WS のみに対応しています。 これは、実運用を考慮して、前段にリバースプロキシサーバーを立てていることを前提としており、 リバースプロキシサーバーで TLS を終端する構成を想定しているためです。 そのため、もし WSS を使う場合は、 nginx などのリバースプロキシサーバーを使用して TLS を終端してください。 > **注意** > > nginx の設定などについてはサポート対象外となりますので、お問い合わせはご遠慮ください 弊社では、TLS を終端するリバースプロキシサーバーには nginx の使用を推奨しています。 詳細については [nginx](NGINX.html) をご確認ください。 ### クライアント単位で接続時間を知ることは可能ですか? 可能です。Sora は接続ごとにタイマーを保持しており、 接続後 1 分ごとに外部のアプリケーションサーバーに HTTP 経由で接続の状態を報告します。 この報告はクライアントごとに独立しており、報告にはクライアント ID やチャネル ID やアプリケーションサーバーが認証時に指定した event_metadata が含まれています。 これらの情報を使用して、例えば、ユーザーごとに接続から 10 分経過したら切断する等の処理が簡単に行えます。 ### シグナリングで利用している WebSocket や DataChannel を使ってクライアントにメッセージ送ることは可能ですか? 可能です。 [プッシュ API](API.html#561ac3) を利用することでシグナリングで利用している WebSocket や DataChannel 経由でクライアントにメッセージを送ることが可能です。 または [メッセージング機能](MESSAGING.html) を利用してクライアント間でメッセージがやりとり可能です。 ### クライアントがシグナリング経由で他の人の接続を通知で受け取ることは可能ですか? 同一チャネルのみに限りますが可能です。 [シグナリング通知](SIGNALING_NOTIFY.html) をご確認ください。 ### シグナリングに DataChannel を使うことは可能ですか? 可能です。ただし、WebRTC 接続確立までは必ず WebSocket を利用する必要があります。 詳細は [DataChannel 経由のシグナリング](DATA_CHANNEL_SIGNALING.html) をご確認ください。 ## 認証 ### シグナリング時の認証は可能ですか? 可能です。ただし、Sora 自体は認証機能を持っていません。 Sora のシグナリング開始時に任意の情報をクライアントに送ることができる `metadata` を指定することが可能です。 これは外部のアプリケーションサーバー側で払い出して使用することができます。 認証のフローを以下に簡単に書き出しておきます。 1. 外部のアプリケーションサーバーでアクセストークンをクライアントに払い出す 2. そのアクセストークンを `metadata` に入れて Sora に接続する 3. Sora はそのアクセストークンやコネクション ID を外部のアプリケーションサーバーに HTTP 経由で問い合わせる 4. 外部のアプリケーションサーバーはそのアクセストークンが正しいことを確認し、 `{"allowed": true}` を HTTP ステータスコード 200 番台で Sora に返す 5. Sora は Offer をクライアントに送る 外部の HTTP サーバーに対して問い合わせを行い、 `{"allowed": true}` と HTTP ステータスコード 200 番台 が返ってきたら認証を許可します。 詳細は [認証ウェブフック](AUTH_WEBHOOK.html) をご確認ください ### シグナリングの認証失敗時に失敗の理由をクライアントに返せますか? 可能です。外部のアプリケーションサーバーで Sora への認証ウェブフックの戻り値を返す場合、 `{"allowed": false, "reason": "最大 100 バイトまでの文字列"}` という値を返す必要があります。 この `reason` 部分はクライアントに通知されます。 詳細は [認証ウェブフック](AUTH_WEBHOOK.html) をご確認ください ## 通知 ### チャネルに参加中のクライアントが、別のクライアントの参加や離脱を知ることは可能ですか? 可能です。シグナリング通知機能を利用することにより、接続や切断のタイミングで、 シグナリングで利用している WebSocket または DataChannel 経由で通知されます。 詳細は [シグナリング通知](SIGNALING_NOTIFY.html) をご確認ください。 ### チャネルに参加中のクライアントが、自分の録画開始/終了を知ることは可能ですか? 可能です。シグナリング通知機能を利用することにより、録画の開始や終了のタイミングで、 シグナリングで利用している WebSocket または DataChannel 経由で通知されます。 詳細は [シグナリング通知](SIGNALING_NOTIFY.html) をご確認ください。 ### 参加者に Sora 側で変更可能なメタデータをもたせることは可能ですか? 可能です。シグナリング通知メタデータ拡張機能を利用することで、 接続や切断のタイミングで API 経由で変更したメタデータを通知できます。 さらにメタデータの変更時に参加者全員にプッシュで通知することも可能です。 詳細は [シグナリング通知メタデータ拡張](SIGNALING_NOTIFY_METADATA_EXT.html) をご確認ください。 ## API ### 指定したコネクションのみを切断することは可能ですか? 可能です。 Sora はチャネル ID とコネクション ID を指定して接続を切断することができます。 詳細は [DisconnectConnection](API.html#2ec3a0) をご確認ください。 ### 指定したコネクションを切断した際に切断理由を含めることは可能ですか? 可能です。 `reason` を指定することで、イベントウェブフック `connection.destroyed` の `disconnect_api_reason` として指定した値が入ってきます。 詳細は [DisconnectConnection](API.html#2ec3a0) をご確認ください。 ### 指定したクライアントのみを切断することは可能ですか? 可能です。 Sora はチャネル ID とクライアント ID を指定して接続を切断することができます。 詳細は [DisconnectClient](API.html#e91c0b) をご確認ください。 ### 指定したチャネルの配信者や視聴者のみを切断することは可能ですか? 可能です。 Sora はチャネル ID を指定して配信者や視聴者のみを接続を切断することができます。 詳細は [DisconnectChannelByRole](API.html#39de6a) をご確認ください。 ### 指定した配信者の映像を、指定した視聴者が受信しないことは可能ですか? 可能です。Sora は配信者、視聴者のコネクション ID を指定して映像を Sora で一時的に止めることができます。 詳細は [PauseRtpStream](EXPERIMENTAL_API.html#de7a52) をご確認ください。 ## 録画 ### Sora で録画した場合に出力されるファイルの形式は何ですか? WebM 形式です。 - [The WebM Project | Welcome to the WebM Project](https://www.webmproject.org/) - [WebM - Wikipedia](https://ja.wikipedia.org/wiki/WebM) ### Sora で録画した複数の WebM 形式のファイルを一つのファイルに出力することは可能ですか? サポートの範囲外になりますが可能です。 録画ファイル合成ツールをオープンソースとして公開しています。 [Recording Composition Tool Hisui](https://github.com/shiguredo/hisui) ### 録画した WebM 形式のファイルはブラウザで閲覧できますか? 可能です。Chrome と Firefox、Edge で閲覧することができます。 Safari では WebM 形式のファイルの閲覧に対応はしていますが VP9/Opus のファイルのみに対応しています。 > **警告** > > iOS 15.1 の Safari では WebM 形式を正常に読み込むことができません。 > これは Safari 側のバグのようで、対応待ちです。 ### 録画可能なコーデックは何ですか? VP8 と Opus 、VP9 と Opus、AV1 と Opus、または H.264 と Opus の組み合わせに対応しており、 WebM 形式で保存されます。 H.265 の録画には現時点で対応していません。 ### 音声のみを録音できますか? 可能です。Opus コーデックで音声のみの録音が可能になります。 webma ファイルではなく webm ファイルで出力されますのでご注意ください。 ### 録画した WebM のサイズの例を教えてください 基本的には指定したビットレートで決まります。 例として、VP8 と Opus の組み合わせの WebM で、 VP8 の解像度が 640x480 でビットレートが 300kbps 程度、音声ありの場合、 1 分の映像で約 2.5 M バイトです。 ### 録画が終了するタイミングを教えて下さい 録画終了するタイミングは 3 つあります。 1. [StopRecording](API.html#fd0de5) API が呼ばれた場合 2. 接続が切断した場合 3. 録画開始時に指定した期限が来た場合 ### 録画の開始と終了をクライアントへ通知することはできますか? 可能です。 シグナリング通知で `recording.started` と `recording.stopped` が送られます。 ### サイマルキャスト機能を利用した場合に録画は可能ですか? 可能です。映像の優先度が一番低い映像を録画します。 映像の優先度については [映像の優先度](SIMULCAST.html#36c708) をご確認下さい。 ### スポットライト機能を利用した場合に録画は可能ですか? 可能です。映像の優先度が一番低い映像を録画します。 映像の優先度については [映像の優先度](SIMULCAST.html#36c708) をご確認下さい。 ### 録画関連ファイルをアップロードする仕組みはありますか? サポートの範囲外になりますが可能です。 Sora が出力した録画関連ファイルを、 Amazon S3 や S3 互換オブジェクトストレージにアップロードするツールをオープンソースとしてとして公開しています。 [Sora Archive Uploader](https://github.com/shiguredo/sora-archive-uploader) ### replaceTrack(null) を使うと、再生時に音声と映像がずれてしまいます Chrome には、特定の条件で RTP タイムスタンプが正しく進まないという問題があり、 そのため Sora が生成する WebM ファイルの再生時に音声と映像がずれてしまうことがあります。 発生条件は、音声ストリームに対して RTCRtpSender.replaceTrack(null) を実行した後に RTCRtpSender.replaceTrack(audioTrack) した場合です。 この問題は Chrome/WebRTC のバグトラッカー で 管理されています。 ### 録画時のキーフレーム要求間隔は何秒ですか? 録画機能利用時の Sora からのキーフレーム要求間隔は 20 秒です。 ## TURN ### TURN サーバーを立てる必要はありますか? Sora は TURN 機能を組み込んでありますので TURN サーバーを立てる必要はありません。 また、Sora とは別に TURN サーバーを立てることは推奨していません。 ### Sora の組み込み TURN サーバーは TURN-TCP や TURN-TLS に対応していますか? 対応しています。ただし、TURN-TLS 機能を使用するためには nginx が必要となります。 - TURN-UDP- ポート変動 - TURN-TCP- ポート固定 - TURN-TLS- ポート固定 - nginx 必須 詳細は [TURN 機能](TURN.html) をご確認ください ### HTTPS で利用される 443 番のポートを TURN 機能で利用することはできますか? nginx の利用が必須ですが、可能です。 詳細は [TURN-TLS、TURN-TCP、シグナリングで 443 番ポートを使用する](PRODUCTION.html#14258d) をご確認ください。 > **注意** > > nginx の設定などについてはサポート対象外となりますので、お問い合わせはご遠慮ください ### Sora を使った場合、TURN サーバーで使用するユーザー名やクレデンシャルはどう払い出せば良いですか? いくつか方法がありますが、ここでは Sora の認証機能と合わせて使用する方法をご紹介します。 Sora は認証を外部のアプリケーションサーバーに問い合わせます。この問い合わせの戻り値の JSON に metadata を含むことができます。 その戻された JSON の metadata はそのままクライアントまで払い出されます。 これを利用して、認証に成功した場合にのみ TURN の認証に使用するユーザー名とクレデンシャルを払い出すことが可能になります。 認証時のクライアントへの metadata の払い出しについての詳細は [metadata の払い出し](AUTH_WEBHOOK_RETURN.html#57f62c) をご確認ください。 ### TURN IPv6 に対応していますか? 対応しています。 ### TURN の FQDN 設定はどのようなときに設定が必要ですか? NAT64/DNS64 ネットワーク環境に対しては TURN の FQDN を設定する必要があります。 ## ウェブフック ### ウェブフックのリクエスト送信先は複数登録することができますか? できません。 もし、送信先を複数にしたい場合は、登録した送信先のアプリケーションサーバーなどで対応をお願いします。 ### ウェブフックにベーシック認証は利用できますか? できます。 `sora.conf` にて [webhook_basic_authn](SORA_CONF.html#081a9f) の設定を有効にして下さい。 詳細については [ウェブフックリクエスト送信先のサーバーがベーシック認証を利用している場合](SESSION_WEBHOOK.html#2a13ea) をご確認ください。 ### ウェブフックのタイムアウト値を設定できますか? できます。 `sora.conf` にて [webhook_response_timeout](SORA_CONF.html#e81d13) を設定することで、ウェブフックのレスポンスのタイムアウトが変更可能です。 ### イベントウェブフックの connection.updated の戻り値を使用して切断などはできますか? できません。切断をする場合は Sora が持つ切断 API を使用してください。 ### イベントウェブフックの connection.updated を送らない設定はできますか? できます。 `sora.conf` にて [ignore_connection_updated_webhook](SORA_CONF.html#f3f12a) を `true` を設定することで、 connection.updated のイベントウェブフックリクエストが送信されなくなります。 ### イベントウェブフックのワーカー数を変更することはできますか? できます。同時接続数が増えた場合や、ウェブフックリクエスト送信先のサーバーの応答速度が遅い場合は、 `sora.conf` にて [event_webhook_worker_number](SORA_CONF.html#58523d) の値を変更してください。 イベントウェブフックのワーカー割り当てに利用している値は `channel_id` となります。 ワーカーが 10 の場合、 `channel_id` が 100 利用している場合、1 ワーカーに 10 の `channel_id` が割り当てられます。 ### イベントウェブフックの処理が遅くなった場合の挙動はどうなりますか? イベントウェブフックワーカーがキューを持っており、もしそのワーカーがリクエストを処理中の場合、キューに追加されます。 そのリクエストの処理が終わりったらキューから取り出され処理されます。 ## DataChannel ### DataChannel でメッセージを送ることはできますか? できます。 Sora のメッセージング機能は DataChannel を利用しています。 詳細については [メッセージング機能](MESSAGING.html) をご確認ください。 ### DataChannel でクライアントが `RTCPeerConnection.createDataChannel()` を利用することはできますか? できません。Sora 側で用意された DataChannel を利用してください。 ### role が recvonly で受信のみでもメッセージング機能を利用してメッセージを送ることはできますか? できます。メッセージングが送ることができるかどうかは `direction` にのみ影響を受けます。 ## クラスター機能 ### クラスターには対応していますか? 対応しています。現在 1 クラスター最大 10 ノードまで対応しています。 詳細については [クラスター機能](CLUSTER.html) をご確認ください。 ### クラスター構築時に同一のライセンスを使う方法はありますか? あります。通常はライセンスを複数のノードで利用することはできませんが [最大ノード数ライセンス](LICENSE.html#aee259) を利用することで可能になります。 ### ロードバランスには対応していますか? 対応しています。 クラスター機能の一つとして、新規チャネルの接続は接続割合が少ない Sora ノードに割り振ります。 ### クラスターへの自動参加には対応していますか? 対応しています。 `sora.conf` の `contact_node_name_list` に書かれている Sora ノードに自動で参加を試みます。 ### クラスターの自動復旧には対応していますか? 対応しています。 ネットワーク障害やノード障害により、クラスターから離脱した場合 Sora は再度クラスターへの参加を自動で試みます。 ### ノード間通信は暗号化されていますか? されていません。そのためプライベートネットワークまたは暗号化されたネットワークを利用してください。 ### 2 ノードでもクラスターを構築できますか? 可能です。Sora は 1+1 の 2 ノードでのクラスター機能を構築できます。 ただしどちらかのノードに障害が発生した場合には、クラスター全体が止まってしまうため、 可用性は 1 ノードの場合よりも低くなります。 そのため 3 ノード以上でクラスターを組むことをお勧めします。 ### クラスターからノードを離脱させたい場合はどうすれば良いですか? Sora を終了することで離脱を行います。丁寧に離脱したい場合はモード切替で [新規コネクションブロックモード](MODE.html#0b67d3) を指定し、 すべての接続を切断してから終了してください。 もしそのノードが今後もクラスターに参加しない場合、 [PurgeClusterNode](EXPERIMENTAL_API.html#13b35a) API を利用してクラスターからそのノードの情報を完全消去してください。 なおノード情報を完全消去せずに、一度に過半数以上のノードを離脱させてしまうと、 残ったノードも接続を処理できなくなってしまうので注意が必要です。 詳細については [通信できるノードが過半数未満となった場合の挙動](CLUSTER.html#2ccf66) をご確認ください。 ### クラスターのディザスタリカバリーには対応していますか? 対応していません。今後対応予定はありますが、リリース時期は未定です。 ### クラスターのインターコネクトには対応していますか? 対応していません。今後対応予定はありますが、リリース時期は未定です。 ### クラスターの最大ノード数はいくつですか? クラスターを構築するノードの最大数は 10 を想定しています。 これ以上のノード数でのクラスター構築を検討されている場合はサポートまでご連絡ください。 ## その他 ### IP アドレスは複数指定できますか? 可能ですが、運用が複雑になるため、現時点ではドキュメントには記載していません。 もし、IP アドレスの複数指定を利用したい場合は、サポートまでお問い合わせください。 基本的には、クライアントごとに IP アドレスを変更したい場合は、認証時の戻り値を使用してください。 ### 配信者は音声と映像を配信し、視聴者は音声のみを受信することは可能ですか? 可能です。視聴者は配信者からの映像や音声のどちらかだけを受け取るよう指定できます。 詳細は [視聴メディアの選択](SIGNALING.html#ca3d9c) をご確認ください。 ### 複数のユーザーの中で、発言していないユーザーは低画質な映像のみを配信し、発言しているユーザーは音声と高画質な映像を配信することは可能ですか? スポットライト機能を利用すれば可能です。 詳細は [スポットライト機能](SPOTLIGHT.html) をご確認ください ### サイマルキャストに対応していますか? 対応しています。ブラウザは Chrome と Edge と Safari の最新バージョンに対応しています。 それ以外のブラウザでは配信はできませんが、視聴は可能です。 映像コーデックは VP8 と H.264 に対応しています。 > **注釈** > > VP8 と H.264 両方のコーデックが利用できる場合、VP8 が比較的安定しています。 ### 映像や音声を WebRTC 以外で出力する仕組みはありますか? [StartForwardingRtp](EXPERIMENTAL_API.html#c734b8) API と [StopForwardingRtp](EXPERIMENTAL_API.html#729828) API を利用することで、 外部のサーバーに対して WebRTC の DTLS (暗号部分) を除いた RTP パケットを送ることが可能です。 FFmpeg などを使用することで、 RTP から HLS や MPEG-DASH などに変換することもできます。 ### 映像の配信を一時的に止める仕組みはありますか? [PauseRtpStream](EXPERIMENTAL_API.html#de7a52) API と [ResumeRtpStream](EXPERIMENTAL_API.html#43002a) API を利用することで、 指定した接続からの映像の配信を一時的に停止できます。 ### HLS 配信はできますか? Sora 単体ではできません。ただし、Sora の [RTP 転送 API](EXPERIMENTAL_API.html#726b29) を利用して FFmpeg などに転送することで、HLS での配信が可能です。 **こちらのドキュメントは古いため参考程度にお願いします** [HLS 配信](HLS.html) をご確認ください。 実際に Sora を利用した HLS での配信サービスをさくらインターネット様が提供されていますのでこちらの利用をおすすめします。 [ライブ配信サービス ImageFlux Live Streaming|さくらインターネット](https://www.sakura.ad.jp/services/imageflux/livestreaming/) ### 追いかけ再生はできますか? Sora 単体ではできません。 ただし、Sora の [RTP 転送 API](EXPERIMENTAL_API.html#726b29) を利用して FFmpeg などに転送することで、HLS での配信が可能です。 そのため、この HLS での配信を利用することで追いかけ再生を実現できます。 **こちらのドキュメントは古いため参考程度にお願いします** [HLS 配信](HLS.html) をご確認ください。 ### WebRTC 確立するまでにかかる時間は知ることができますか? [GetStatsReport](EXPERIMENTAL_API.html#bbbfca) API の `average_setup_time_msec` でシグナリング接続開始から WebRTC 接続が確立するまでにかかった平均時間が取得できます。 ## 性能 ### 負荷試験はどう行えばよいですか? サポートの範囲外になりますが、Sora 専用の負荷試験ツールをオープンソースとして公開しています。 [WebRTC Load Testing Tool Zakuro](https://github.com/shiguredo/zakuro) ### Sora は CPU をどの程度使用しますか? > **重要** > > WebRTC では全ての通信が暗号化されているため、暗号化/復号処理で最も CPU リソースを消費します 通信環境やビットレートに影響するため一概には言えませんが、参考値を紹介します。 環境は AWS の C5n.4xlarge を利用しています。 以下の CPU の % は 1 コアを 100% とした場合です。 解像度が QVGA / 20fps / 1000kbps の映像と音声の送受信で 1 チャネル 8 クライアントを 12 ルーム (96 接続) で CPU 使用率を 200 % 程度利用します。 ### Sora はメモリをどの程度使用しますか? Sora は再送のキャッシュ用途にメモリを使用します。 100 接続であれば 4 GB 以上あれば十分です。 また、録画利用時にはフレーム組み立てのため一時的にメモリを使用します。こちらはビットレートに依存します。 ### Sora はディスクをどの程度使用しますか? 主に録画したファイルとログによりディスクが使用されます。 録画する映像の容量はコーデックやビットレートに依存するため一概には言えません。 ### マルチストリームは 1 チャネルで最大何クライアントまで対応していますか? 2022.2.0 時点で最大 12 クライアントまで対応しています。それ以上を接続することもできますが、お勧めはできません。 もし、大規模での会議を行いたい場合は、現在実験的機能として提供中の [スポットライト機能](SPOTLIGHT.html) の利用を検討してください。 ## 運用 ### WebSocket が通らないプロキシ環境がある場合はどうしたらよいですか? WebSocket は TLS を利用しているため、おそらくプロキシは TLS を一度終端するタイプかと思われます。 接続に対して中身の解析を行うプロキシであれば、 WebSocket だけでなく、TURN-UDP や TURN-TCP、TURN-TLS も通らない可能性が高いです。 結果として WebSocket が通らないプロキシを利用している場合は WebRTC 自体が利用できない可能性が高いため、プロキシの設定を変更してもらう以外の方法はありません。 ### Sora は Prometheus 形式に対応した監視情報を出力しますか? Sora 自体は Prometheus 形式の監視情報は出力しません。 その代わりにオープンソースとして Sora exporter を公開しています。 [Prometheus exporter for WebRTC SFU Sora metrics.](https://github.com/shiguredo/sora_exporter) ### Sora をデーモン化せずに起動することは可能ですか? 可能です。 Sora を起動する際、 `bin/sora foreground` で起動してください。 ### Sora を systemd で利用することは可能ですか? 可能です。 詳細は [systemd](SYSTEMD.html) をご確認ください。 ### Sora クラスターを利用せず、ロードバランサーを利用することは可能ですか? できません。 Sora ではかならず同一チャネルの接続を同一 Sora に集約する必要があるためです。 もしロードバランサーを利用したい場合はクラスターを構築する必要があります。 ### Sora クラスターを利用して、ロードバランサーを利用する事は可能ですか? 可能です。 ロードバランサーは WebSocket に対応している必要があります。 さらにロードバランサー側では 30 秒以上のタイムアウトを設定する必要があります。 これは Sora は WebSocket と DataChannel をシグナリングに併用した場合 30 秒間隔で Ping を Sora から送るためです。 また、ロードバランサーを経由しないシグナリング接続もできるようにする必要があります。 これは Sora 側でシグナリングのリダイレクトを行い別の Sora に直接接続させる仕組みがあるためです。 ### Sora は Docker 上で利用できますか? Sora をコンテナで運用するのは推奨していませんが、技術的には可能です。 サポートへ問い合わせする場合はコンテナに関係する問題を切り分けをして頂く必要があります。 ### Sora の WebSocket を利用したシグナリングのキープアライブの切断条件は何ですか? Sora は WebSocket 経由で 5 秒間隔で `"type": "ping"` を送信し、 60 秒間で 1 回も `"type": "pong"` が返って来こなかった場合、 Sora はシグナリング接続を切断します。 ### Sora の DataChannel を利用したシグナリングの Sora 側からの切断条件は何ですか? Sora は定期的に接続状態を確認する仕組みを持っており、その仕組みで切断かどうかを判断しています。 詳細は [ICE コネクションステート](ICE_CONNECTION_STATE.html) をご確認ください。 ### Sora 1 台のサーバーでは最大同時接続数はいくつですか? 現状 1 台では 1000 接続までを推奨していますが、 サーバーのスペックが高ければ 1 台で 3000 同時接続なども可能です。 1000 以上の接続を 1 台で行いたい場合は sora at shiguredo.jp またはサポートまでお問い合わせ下さい。 ### Sora が対応している OS は何ですか? 2022.2.0 の時点では以下の OS に対応しています。 - Ubuntu 22.04 LTS x86_64 - Ubuntu 20.04 LTS x86_64 - Ubuntu 18.04 LTS x86_64- 新規でのお客様向けには提供は行っておらず、既存のお客様向けにのみ提供しています - 2023 年 4 月にサポートの提供を終了するため、非推奨としています - Red Hat Enterprise Linux 9 x86_64 - Red Hat Enterprise Linux 8 x86_64 - CentOS 7 x86_64- 新規でのお客様向けには提供は行っておらず、既存のお客様向けにのみ提供しています - カーネルが古く Sora の性能が引き出せないため、非推奨としています - Ubuntu 22.04 LTS arm64 - Ubuntu 20.04 LTS arm64 > **重要** > > arm64 版は 3 ヶ月以上、 200 同時接続以上のライセンスをご契約頂いているお客様にのみ提供しています。 ### Sora は Amazon Linux に対応していますか? 対応していません。 Sora が対応していると明記している OS 以外で動作させている場合は Sora はサポート対象外となります。 ### Sora のプロセス名は何になりますか? `bin/sora daemon` で起動した場合、Sora 本体は run_erl というプロセスになります。こちらの死活監視をお願いします。 ### Sora を終了しても epmd というプロセスが残りますが問題ありませんか? 問題ありません。 Sora と関係するプロセスですが独立しており、起動し続けていて構いません。 ### カーネルパラメータの設定は何をすれば良いですか? まずはファイルディスクリプタ数をご確認ください。値は 65535 に設定しておくことをお勧めします。 その他のチューニング項目については [Linux カーネルチューニング](LINUX_KERNEL_TUNING.html) をご確認ください。 ### ログローテーションはどうすれば良いですか? sora.log と connection.log はローテションされませんので必要な部分で mv コマンドなどで移動してください。 ファイルが無い場合、新しく作られます。 erlang.log については自動でログローテーションを行いますので気にする必要はありません。 ログの詳細については [ログファイル](LOG.html) をご確認ください。 ### ログのタイムゾーンを教えてください UTC です。 ### Sora が使用する UDP のポート範囲を教えてください Sora が使用する UDP ポートは Linux のエフェメラルポートを使用しています。 エフェメラルポートの範囲は sysctl などで確認してください。 実行例: ``` $ sysctl -n net.ipv4.ip_local_port_range 32768 60999 ``` ### Sora が使用する UDP のポート範囲を制限できますか? 可能です。Sora が使用する UDP ポートの範囲はエフェメラルポートの範囲です。 Linux 側でエフェメラルポートの範囲を設定してください。 sysctl にて net.ipv4.ip_local_port_range の範囲を指定してください。 ### ブラウザで WebRTC の詳細情報を取得することはできますか? はい、可能です。 - Chrome であれば URL に `chrome://webrtc-internals` を入力してみてください - Firefox であれば URL に `about:webrtc` を入力してみてください - Edge であれば URL に `edge://webrtc-internals` を入力してみてください - Safari であれば JavaScript コンソールの設定の一般から WebRTC を設定可能です ![image](https://i.gyazo.com/cbcc400253e213c4d5e311377ea5a613.png) ### SELinux を利用する際の注意点はありますか? Sora の log ディレクトリ以下にログを書き込めるようにする必要があります。 以下を参考にしてみてください。 - [logging - logrotate cron job not rotating certain logs - Stack Overflow](https://stackoverflow.com/questions/15652654/logrotate-cron-job-not-rotating-certain-logs) - [linux - Configuring SELINUX to allow logging to a file that's outside /var/log - Unix & Linux Stack Exchange](https://unix.stackexchange.com/questions/79311/configuring-selinux-to-allow-logging-to-a-file-thats-outside-var-log) ### 映像が乱れたり止まったりする場合は何を確認するのが良いですか? 映像が乱れたり止まったりする場合はネットワーク回線が不安定なことがほとんどです。 この場合は切断時に生成される connection.log を確認してみてください。 このログで映像の送信側と受信側の統計情報が確認できますので、映像が乱れたり止まったりした接続の connection_id を記録しておいて下さい。 - total_received_rtcp_rtpfb_generic_nack - total_sent_rtcp_rtpfb_generic_nack この値が多ければ多いほど「再送要求」の回数が多く、回線が不安定だったことが把握できます。 connection.log の詳細については [connection ログ](LOG.html#f2e264) をご確認ください。 ### Sora が突然終了しました Sora は何か問題があり Sora が終了した場合 `erl_crash.dump` というログを出力します。 このログが出力された場合はサポート問い合わせの手順に従ってサポートまでご連絡ください。 もし `erl_crash.dump` が出力されずに Sora が終了した場合はカーネル側から停止された可能性があります。 まずは OOM Killer で殺されていないかどうかを確認してみてください。 ## SDK Sora の SDK は基本的にシグナリング処理のための SDK です。 WebRTC 部分は webrtc.org が提供しているライブラリを利用しています。 ### Sora の SDK へのサポートはありますか? Sora の SDK サポートは提供していません。また有償のサポートも提供していません。 もしアドバイスが必要だったり、問題が起きたりした場合は Discord へお願いします。バグ対応は最優先で行います。 ### Discord サーバーの招待 URL - Sora JavaScript SDK- `#sora-js-sdk` チャンネル - Sora iOS SDK- `#sora-ios-sdk` チャンネル - Sora Android SDK- `#sora-android-sdk` チャンネル - Sora Unity SDK- `#sora-unity-sdk` チャンネル - Sora C++ SDK- `#sora-cpp-sdk` チャンネル - Sora Flutter SDK- `#sora-flutter-sdk` チャンネル ### JavaScript SDK はありますか? Sora の JavaScript SDK に関しては以下をご確認ください。 - [Sora JavaScript SDK ドキュメント — Sora JavaScript SDK](https://sora-js-sdk.shiguredo.jp/) - [WebRTC SFU Sora JavaScript SDK](https://github.com/shiguredo/sora-js-sdk) ### iOS SDK はありますか? Sora の iOS SDK に関しては以下をご確認ください。 Swift で書かれています。 - [Sora iOS SDK ドキュメント — Sora iOS SDK](https://sora-ios-sdk.shiguredo.jp/) - [WebRTC SFU Sora iOS SDK](https://github.com/shiguredo/sora-ios-sdk) - [WebRTC SFU Sora iOS SDK クイックスタート](https://github.com/shiguredo/sora-ios-sdk-quickstart) - [WebRTC SFU Sora iOS SDK サンプル集](https://github.com/shiguredo/sora-ios-sdk-samples) ### Android SDK はありますか? Sora の Android SDK に関しては以下をご確認ください。 Kotlin で書かれています。 - [Sora Android SDK ドキュメント — Sora Android SDK](https://sora-android-sdk.shiguredo.jp/) - [WebRTC SFU Sora Android SDK](https://github.com/shiguredo/sora-android-sdk) - [WebRTC SFU Sora Android SDK クイックスタート](https://github.com/shiguredo/sora-android-sdk-quickstart) - [WebRTC SFU Sora Android SDK サンプルアプリケーション](https://github.com/shiguredo/sora-android-sdk-samples) ### C++ SDK はありますか? Sora の C++ SDK に関しては以下をご確認ください。 C++ で書かれています。 - [WebRTC SFU Sora C++ SDK](https://github.com/shiguredo/sora-cpp-sdk) - [WebRTC SFU Sora C++ SDK サンプル集](https://github.com/shiguredo/sora-cpp-sdk-samples) ### Unity SDK はありますか? Sora の Unity SDK に関しては以下をご確認ください。 C++ SDK をベースにしています。 - [WebRTC SFU Sora Unity SDK](https://github.com/shiguredo/sora-unity-sdk) - [WebRTC SFU Sora Unity SDK サンプル集](https://github.com/shiguredo/sora-unity-sdk-samples) ### Flutter SDK はありますか? Sora の C++ SDK に関しては以下をご確認ください。 C++ SDK をベースにしています。 - [WebRTC SFU Sora Flutter SDK](https://github.com/shiguredo/sora-flutter-sdk) ### JavaScript SDK は認証付き HTTP Proxy に対応していますか? JavaScript SDK はブラウザで動作するため、ブラウザが WebRTC での HTTP Proxy に対応している必要があります。 主要なブラウザは HTTP Proxy に対応済みです。利用する場合はブラウザで HTTP Proxy の設定をしてください。 ### iOS / Android / Unity / C++ SDK は認証付き HTTP Proxy に対応していますか? 対応しています。ただし Basic 認証のみの対応で、 **OS の設定や PAC ファイルへの対応は未定です** 。 - iOS SDK- 最新版で対応済みです - Android SDK- 最新版で対応済みです - C++ SDK- 最新版で対応済みです - Unity SDK- 最新版で対応済みです - Flutter SDK- 最新版で対応済みです ### ブラウザレスな WebRTC クライアントアプリケーションはありますか? OSS として WebRTC Native Client Momo を公開しています。 - [WebRTC Native Client Momo](https://momo.shiguredo.jp/) - [shiguredo/momo: WebRTC Native Client Momo](https://github.com/shiguredo/momo) ## ライセンス ### 同時接続とは具体的に何を指していますか? シグナリングの同時接続数を指しています。1 シグナリング接続で 1 同時接続です。 ### ライセンスの同時接続数を超えた時はどうなりますか? もし、最大同時 100 接続のライセンスファイルを利用している場合で 101 本目の接続がきた場合、 Sora は 101 本目の接続を拒否します。 ### ライセンスの同時接続数の最小の値はいくつですか? ライセンスの同時接続数の最小は 100 となります。 10 や 50 といったライセンスは提供しておりません。 ### ライセンスの同時接続数は 100 単位ですか? はい、その通りです。100 の次は 200 となり、100 同時接続単位となります。 110 や 150 といったライセンスは提供おりません。 ### ライセンスの期限を過ぎた場合はどうなりますか? 動作上、既存の接続に対しては特に何もありませんが、新規の接続を受け付けなくなります。 ### Sora の現在の同時接続数を確認する方法はありますか? [GetStatsReport](EXPERIMENTAL_API.html#bbbfca) API の `total_ongoing_connections` で現在 Sora に接続している同時接続数が確認可能です。 ### ライセンス期限のタイムゾーンを教えてください UTC です。 ### クラスター利用時に同一のライセンスを利用する方法はありますか? あります。 `最大ノード数ライセンス` を利用することで、 1 つのクラスター構築時に同一のライセンスを利用することが可能になります。 `最大ノード数ライセンス` では、 1 クラスターで同一のライセンスを最大いくつのノードに適用できるかがあらかじめ定義されています。 そのため、クラスターを構築する際に、その最大ノード数までは同一ライセンスを利用することが可能になります。 詳細は [最大ノード数ライセンス](LICENSE.html#aee259) をご確認ください。 ### 最大ノード数ライセンスの最大ノード数はいくつですか? 最大ノード数ライセンスの最大ノード数は 10 です。 ## バージョンアップ ### バージョンアップは有償ですか? ご購入いただいたライセンスが有効な期間は、バージョンアップはすべて無償で提供させていただきます。 ### バージョンアップのタイミングは決まっていますか? 少なくとも年 2 回、 6 月と 12 月に大きめのバージョンアップを行います。 それ以外は何かしら問題があったタイミングで修正のバージョンアップを行います。 ### Sora のバージョン表記 バージョン表記: ``` YYYY.RELEASE.FIX ``` - `YYYY` はリリースした年になります - `RELEASE` はその年のリリース回数になります - `FIX` は 0 から始まり、仕様が変わらない修正のみのリリース回数になります リリース回数は社内でのリリース回数となるため、公開リリースの番号は飛ぶことがあります。 公開されるバージョンが 2020.1.0 の次が 2020.4.1 となったりすることがありますのでご了承ください ## サポート ### 古いバージョンの Sora のサポートは提供していますか? いいえ。サポートは最新版の Sora を利用している場合のみ、受け付けています。 ### Sora のサポートは電話で受け付けていますか? いいえ。サポートはサポート専用のメールでのみ、受け付けています。 ### Sora のサポートは 24 時間 365 日ですか? いいえ。サポートは弊社営業日の 10:00-17:00 のみ、対応しています。 ### SDK の有償サポートは受け付けていますか? いいえ。Sora SDK の有償サポートは行っていません。 ただし GitHub 上ですべてのコードを公開しています。 もし何か問題が起きた場合は時雨堂コミュニティの Discord にてご相談ください。 バグ対応は最優先で行います。 ### Zakuro や Hisui など関連ツールの有償サポートは受け付けていますか? いいえ。関連ツールの有償サポートは行っていません。 ただし GitHub 上ですべてのコードを公開しています。 もし何か問題が起きた場合は時雨堂コミュニティの Discord にてご相談ください。 バグ対応は最優先で行います。 # トラブルシューティング ## 突然切断された ### sora ログに `PONG-TIMEOUT-ERROR | reason=<<"WebSocket">>` が出力されている場合 Sora から 5 秒間隔で送っている `{"type": "ping"}` に対して、 クライアントが `{"type": "pong"}` を 60 秒間返してこない場合に発生します。 これは Sora がクライアントが疎通不能だと判断して切断した、正常な終了です。 まずはクライアントのネットワーク状況を確認してみてください。 WebSocket が詰まることを回避する方法としては、 [DataChannel 経由のシグナリング](DATA_CHANNEL_SIGNALING.html) の利用を検討してください。 # Sora が期待どおりに動かない場合、または、動作に問題がある場合 Sora が期待どおりに動かない場合、 または動作に問題がある場合の問い合わせ時の事前確認と注意事項をまとめています。 ## 事前確認 問い合わせの前に、まずは以下の項目について事前に確認をお願いします。 ### 利用している Sora のバージョンが最新版か確認してください **最新版でのみ、サポートの対応を行っております** もし、最新版を利用していない場合は、最新版へのアップデート後に問題が再現するかの確認をお願いします。 ### Sora の SDK サポートについては Sora サポート範囲外のため Discord サーバーの各チャンネルをご利用ください **時雨堂コミュニティサーバー**: - Sora JS SDK- `#sora-js-sdk` チャンネル - Sora iOS SDK- `#sora-ios-sdk` チャンネル - Sora Android SDK- `#sora-android-sdk` チャンネル - Sora Unity SDK- `#sora-unity-sdk` チャンネル - Sora C++ SDK- `#sora-cpp-sdk` チャンネル - Sora FlutterSDK- `#sora-flutter-sdk` チャンネル ### 利用しているブラウザが安定版の最新版か確認してください ブラウザが古い場合、うまく接続できない可能性があります。 もし、ブラウザが古い場合は、最新版で再度問題が発生するかどうか確認をお願いします。 ### 開発ツールを有効にして開発ツールで問題が再現するか確認してください クライアント側の実装の問題もあるため、必ず確認をお願いしています。 もし、クライアント側の問題の場合は、 Sora のサポートでは対応することができません。ご了承下さい。 ### クライアントのシグナリング接続が WebSocket over TLS で接続しているかどうかを確認してください WebSocket over TLS ではない場合は、まずは WebSocket over TLS で接続するようにお願いいたします。 ### Sora のサポート範囲外の質問はご遠慮ください Sora の挙動や使い方以外はサポートの範囲外です。 - Sora を利用したサービスの設計や開発 - nginx 全般 - WebRTC 全般 - Sora SDK 全般 - WebRTC Native Client Momo - WebRTC Load Testing Tool Zakuro - Recording Composition Tool Hisui - WebRTC Stats Collector Kohaku - Audio Streaming Gateway Suzu - 各種クラウドサービス 上記はすべて Sora のサポート範囲外となります。 ## 問い合わせの場合、お送り頂く情報 > **重要** > > 前述の事前の確認後、以下の情報を **必ず** お送り下さい。 情報をお送り頂くときは `テキストファイル` でお送りください。 - サーバーやクライアントのスペック- わかれば機種名 - CPU - メモリ - ディスク - Linux Kernel のバージョン- `uname -a` の出力 - OS の種類、バージョン- Ubuntu、 Red Hat Enterprise Linux、CentOS のどれを使っているか - 使っているバージョン - Sora のバージョン- 2021.1.2 など - クラスターを利用している場合はクラスターの構成 - Sora の **sora.conf 設定ファイル** - Sora の log ディレクトリ以下全てのログファイル- クラスターを利用している場合は全ノードのログ - tar.gz または zip などで圧縮し、パッケージ提供時にお送りしているログアップローダーを利用してお送りください - 評価中の場合は tar.gz または zip などで圧縮し、メールにてお送り下さい ### 詳細な問題発生状況 **何をどうすると問題が発生したのかの状況を可能な限り詳細にお教え下さい** > **重要** > > 以下の情報については **必ず** お送り下さい。 - シグナリングの情報- チャネル ID - セッション ID - コネクション ID - 音声の有無- コーデック - ビットレート - 映像の有無- コーデック - ビットレート - 解像度 - サイマルキャスト機能の有無 - マルチストリーム機能の有無 - スポットライト機能の有無 - 問題が発生したブラウザバージョン- Chrome 102.0.5005.61 や Safari 15.5 など - SDK の種類とバージョン- Sora JavaScript SDK 2020.2.5 や Sora iOS SDK 2020.4.1 など - 問題が発生したブラウザまたは SDK を利用している OS の種類とバージョン- iOS 14.4 や macOS 11.2.3 や Windows 10 1903 など - 問題の発生状況- 発生時刻 (何度か発生している場合は複数) - 発生したタイミング (接続した直後、配信が10分以上継続した後、など) - 発生頻度 - 発生時の配信者数、視聴者数 - 発生の確率 (ある手順を踏むと必ず発生する、同じ手順でも5回に1回程度のみ発生する、など) ### 再現方法 **Sora 内蔵の開発ツールでの再現方法をお送りください** - 再現の手順- 開発ツールで問題が発生する場合、その手順をお送り下さい- 接続する開発ツールの URL- 開発ツールの copy URL を押すと現在の設定を反映した URL がコピーされます - 複数クライアントを接続したときに発生する場合は、その順序と接続間隔 (ほぼ同時、数分おいて接続、など) - 開発ツールでは発生しない場合、開発ツールに準じた情報をお送り下さい- シグナリングのパラメータ - 複数クライアントの接続の場合、その順序と接続間隔 (ほぼ同時、数分おいて接続、など) - 問題を再現するための独立したアプリケーションが作成可能であれば、そちらをご用意頂くと解決までの距離が短くなります ## 録画関連の問い合わせについて **録画については以下の点をご注意ください** ### 録画ファイルの取り扱いについて もし、何か録画に問題があった場合でも、録画ファイルを送ることは **絶対** にしないでください。 録画したファイルの代わりに録画したファイルの情報を取得して送ってください。 録画ファイルの情報は mkvinfo と mediainfo コマンドを録画ファイルに対して実行した結果を、テキストファイルでお送りください。 mkvinfo は macOS で Homebrew を利用していれば `brew install mkvtoolnix` でインストール可能です。 それ以外は以下からダウンロードしてください。 [MKVToolNix news – Matroska tools for Linux/Unix and Windows](https://mkvtoolnix.download/) mediainfo は macOS で Homebrew を利用していれば `brew install media-info` でインストール可能です。 それ以外は以下からダウンロードしてください。 [MediaInfo - Download](https://mediaarea.net/en/MediaInfo/Download) mkvinfo コマンド例: ``` $ mkvinfo -t -z -v -v -v archive-K3FZ5EZJWS7HXBAJFR37ZYT4GR.webm ``` mediainfo コマンド例: ``` $ mediainfo --Details=2 archive-K3FZ5EZJWS7HXBAJFR37ZYT4GR.webm ``` ### 問題が起きた状況について - ブラウザで再生して問題が起きた場合は、ブラウザの種類とバージョン、プラットフォームをお教えください - VLC で再生して問題が起きた場合は、VLC のバージョンとプラットフォームをお教えください ### HLS や MPEG-DASH の問い合わせについて HLS や MEPG-DASH といった Sora が録画したファイルを変換した状態で発生した問題についてはサポート対象外です。 # Sora の仕様や使い方に関して質問がある場合 ドキュメントに記載されている Sora の仕様や使い方に関して不明点がある場合はドキュメントの URL を添えてお送りください。 # チュートリアル ## 概要 このチュートリアルでは、Sora に組み込まれている開発者ツールを動かして、ひととおり使ってみるところまでを説明します。 ## チュートリアルの注意点 > **注意** > > 繋がらないという問い合わせのほとんどは UDP のポート開放忘れです。必ずポートを開放してください。 - このチュートリアルでは、リバースプロキシとしての nginx や HTTPS の知識を必要とします - Sora は TCP と UDP の両方を利用します- TCP はデフォルトであれば 3000 番と 5000 番を利用します - UDP はデフォルトであればエフェメラルポートの範囲を利用します - Sora の開発者ツールは Sora に組み込まれているものを利用して下さい - Sora の開発者ツールは HTTPS 非対応のため、nginx をリバースプロキシとして利用して、TLS 終端を行ってから Sora に繋ぐ必要があります - Sora のシグナリングは WebSocket over TLS 非対応のため、nginx をリバースプロキシとして利用して、 TLS 終端を行い Sora のシグナリングへ繋ぐ必要があります ## Sora の展開 tar.gz で圧縮されていますので、展開して下さい。 ```console $ tar xfz sora--.tar.gz ``` ## 設定ファイル 設定ファイルは Sora を展開した `sora-/etc/sora.conf` にあります。まずは開発者ツールを動作させるまでの最低限の設定を行います。 `#` はコメントになっている部分ですので、設定する項目がコメントになっている場合は `#` を削除して設定項目を有効にしてください。 1. ライセンスファイルの指定- ライセンスファイルを etc/ において、cp コマンドを利用して `license.json` に変更して下さい。 2. 開発者ツールの有効化- Sora には簡単に検証してもらうための開発者ツールを組み込んでいます。 `devtools` 項目の `#` を削除して設定を有効にし、加えて、設定値に true を指定して Sora に組み込まれている開発者ツールを有効化してください。 ```ini ## ライセンスファイルを指定してください ## この設定はオプションで、デフォルトは "etc/license.json" です # license_file = etc/license.json ## 開発者ツールを有効にするかどうかを指定してください ## オプションでデフォルト false です devtools = true ``` 他の設定はここでは不要です。 ## 起動 設定が終わったらサーバーを起動します。 ``` $ sora-/bin/sora daemon ``` ### 停止 停止したい場合は以下で可能です ``` $ sora-/bin/sora stop ``` ## シグナリングへの HTTPS の適用 **HTTPS (WebSocket over TLS を含む) の適用は必ず行ってください。HTTPS への接続以外はサポート対象外となります** ブラウザで WebRTC の機能の一つである getUserMedia を利用する場合は HTTPS が必須となります。 ただし、Sora 自体は HTTPS 非対応のため、Sora の前段にリバースプロキシとして nginx を設置して TLS 終端を行ってください。 nginx の location ディレクティブの設定については [nginx](NGINX.html) を参考にして設定をお願いします。 > **注意** > > nginx の設定に関する質問については Sora のサポート範囲外となりますのでご了承下さい。 証明書については [Let's Encrypt - Free SSL/TLS Certificates](https://letsencrypt.org/) の利用をおすすめします。 > **注意** > > Let's Encrypt に関する質問については Sora のサポート範囲外となりますのでご了承下さい。 リバースプロキシとしての nginx の役割: ``` // 開発者ツールの静的ファイルの場合 クライアント -> -> nginx -> -> Sora // シグナリングの場合 クライアント -> -> nginx -> -> Sora ``` ## 開発者ツールを利用してみる Sora に組み込まれている開発者ツールの使い方を説明します。 開発者ツールでは Sora の持っている一通りの配信機能を試すことができます。 ブラウザで `https://<設定したドメイン>/` にアクセスして以下のような画面が表示されれば成功です。 ![image](https://i.gyazo.com/a2ec768a1c51493ac8a71497c3e95603.png) ### 開発者ツールが動作するブラウザ一覧 以下の最新のブラウザで動作します。 - Google Chrome - Mozilla Firefox - Apple Safari - Microsoft Edge ただし一部の機能は特定のブラウザでのみ動作します。 ### 動作確認 > **警告** > > ハウリングする可能性があります。 ビデオ会議システムなどで利用されるような双方向での配信機能です。 受信だけ、送信だけでの利用も可能です。 `マルチストリーム送受信` を開き `connect` を押して、 その後、別のブラウザやタブで同じ URL を開いて、 `connect` を押して下さい。 ![image](https://i.gyazo.com/b79590e2493ec49fed8f9dc0e0470a26.png) 追加でタブを開いて `connect` していけば参加者を増やせます。 開発ツールでは気軽にいろいろな設定を試せるようになっています。触ってみてください。 ## 次のステップ - `sora.conf` の `ipv4_address` にサーバーの IP アドレスを指定してください [本番稼働に向けて](PRODUCTION.html) をお読みください。 また、 Sora はいろいろな機能を持っていますので、一通りドキュメントをご確認下さい。 ## トラブルシューティング ### タイムアウトが起きてつながらない場合 > **重要** > > OS の設定やファイアウォールで UDP の通信ができない場合は接続に失敗します。 Sora が利用する UDP のポートの範囲は通常 32768 から 60999 です。この範囲の通信を許可にしてみてください。 ### それでもうまく繫がらない場合 サーバーの IPv4 アドレスを `ipv4_address` に指定して、 `ipv6` を `false` にしてみてください。 ```ini ## ライセンスファイルを指定してください ## この設定はオプションで、デフォルトは "etc/license.json" です # license_file = etc/license.json ## サーバーで利用する IPv4 アドレスを指定してください ## 指定が無い場合は、自動で見つけたアドレスを利用します ipv4_address = 192.0.2.10 ## 開発者ツールを有効にするかどうかを指定してください ## オプションでデフォルト false です devtools = true ``` > **注釈** > > Amazon EC2 インスタンス等のようなパブリック IP アドレスとプライベート IP アドレスが異なる環境では > ブラウザからアクセス可能な IP アドレス(パブリック IP アドレス)を ipv4_address に設定してください。 ### よくある問題 ここでは利用しているドメインを仮に `example.com` としています。 - `https://example.com/` にアクセスできない- nginx の設定が間違っている可能性があります。nginx の設定を見直して下さい - `https://example.com/` にアクセスしても 404 になる- Sora の組み込みの開発者ツールが有効になっていない可能性があります- `sora.conf` の設定で開発者ツールが有効になっているか確認して下さい - `http://example.com:5000/` にアクセスして開発者ツールが有効になっているかを確認して下さい - Sora が利用するポートを他のプロセスが利用していないかを確認してください- Sora が利用したいポートを他のプロセスが既に利用しているために、Sora が起動していない可能性があります ### それでも繋がらない場合 **お問い合わせ前に以下を確認してください** - チュートリアル以外のことはやっていないかどうかを確認して下さい - **ファイアウォールの設定を全て無効にして確認してください** - IPv6 アドレスを無効にして確認してください - Sora では基本的にロードバランサーを利用することはできませんので、ロードバランサーなしで確認してください 全てを確認しても繋がらない場合はお問い合わせください。 その際に以下の情報を **必ず** お送りください。 - どんな環境でチュートリアルを実行しているか - Sora のバージョン - Sora の設定ファイルである `sora.conf` - log ディレクトリ以下すべてを tar.gz にて圧縮してお送りください- 容量が 1 メガバイトを超える場合は事前にご連絡ください。アップローダーをご提供します - 繋がらなかった開発者ツール- たとえば `sendonly` など - 繋がらなかったブラウザを利用している OS とバージョン- たとえば `macOS Big Sur 11.4` や `Windows 10 2004` など - 繋がらなかったブラウザの種類とバージョン- たとえば `Chrome 91.0.4472.77` など それ以外にも可能な限り、こちらがサポートをするために必要そうな情報をお送りください。 # 本番稼働に向けて この資料はチュートリアルで Sora をなんとなく体験したあとに、 本番環境に向けてどのような準備が必要なのか、どの機能を使っていけばいいのかをまとめたものです。 不明点などはサポートまでお問い合わせください。 ## ログ出力形式の変更 > **重要** > > この設定を導入することを強く推奨します レガシーフォーマットやレガシー拡張を利用せず JSONL 形式や `jsonl` 拡張子での出力を有効にすることを推奨します。 JSONL 形式は `jsonl` 拡張子での出力をする場合は `sora.conf` の [legacy_log_format](SORA_CONF.html#3e05c7) と [legacy_log_extension](SORA_CONF.html#847a26) を `false` にしてください。 ## ウェブフックの audio/video のフラット化 > **重要** > > この設定を導入することを強く推奨します レガシーな構成ではなく、フラットな構成を利用することを推奨します。 フラットな構成を利用する場合は `sora.conf` の [legacy_webhook_audio_video_json_structure](SORA_CONF.html#3be597) を `false` にしてください。 ## IPv4 アドレスの固定 `sora.conf` の [ipv4_address](SORA_CONF.html#04becc) にサーバーの IP アドレスを指定してください。 ```ini ipv4_address = 192.0.2.10 ``` ## IPv6 アドレスの利用について Safari は IPv6 環境での動作が不安定なため、 Safari をターゲットデバイスに含んでいる場合は `sora.conf` の IPv6 設定を無効にする `ipv6 = false` を推奨しています。 ファイアーウォールを利用される場合は IPv6 向け設定もご確認ください。 ## sora.conf の turn_fqdn を設定する iOS の場合は TURN は FQDN を利用しないと接続ができない場合があるため、 TURN-UDP / TURN-TCP で利用するドメインを指定してください。 `sora.conf` の `ipv4_address` に指定した IP アドレスを設定してある FQDN を指定してください。 ```ini turn_fqdn = sora-turn.example.com ``` ## HTTP API のループバックアドレスからのみのアクセス > **重要** > > この設定を導入することを強く推奨します `sora.conf` の [api_loopback_address_only](SORA_CONF.html#9d6140) の値を `true` にしてください。 こうすることでループバックアドレスからのみ HTTP API が叩けるようになります。 ## シグナリングのループバックアドレスからのみのアクセス > **重要** > > この設定を導入することを強く推奨します `sora.conf` の [signaling_loopback_address_only](SORA_CONF.html#e22105) の値を `true` にしてください。 こうすることでループバックアドレスからのみシグナリングが叩けるようになります。 ## ファイルディスクリプタ数の設定 Sora は 1 接続で少なくとも 2 つのファイルディスクリプタを利用します。 また、ウェブフックやログの書き込みでも追加でファイルディスクリプタを利用します。 同時接続数が 100 の場合は Linux のデフォルト値である 1024 でも足りますが、 それを超える同時接続がある場合はファイルディスクリプタ数をデフォルトから変更してください。 ## systemd の適用 > **重要** > > この仕組みを導入することを強く推奨します Sora の起動/停止に `bin/sora daemon` を利用するのではなく systemd を適用してください。 デーモン化せずに Sora を動かすには `bin/sora foreground` を利用します。 詳細は [systemd](SYSTEMD.html) をご確認ください。 ## TURN-TLS、TURN-TCP、シグナリングで 443 番ポートを使用する > **重要** > > この仕組みを導入することを強く推奨します。 > この設定は Sora 2021.1 以降に最適化されています。 > **注意** > > nginx および systemd の設定に関する質問については Sora のサポート範囲外となります。 **この設定はある程度の nginx や証明書の知識が必要になります** nginx のバージョンは 1.11.5 以降が必須です。 TURN-TLS、TURN-TCP、シグナリング(HTTPS)を 443 番ポートのみで受信する場合は次の設定を追加してください。 > **注意** > > nginx の停止に QUIT シグナルを使用している場合は、nginx 起動時に作成された UNIX domain socket のソケットファイルは削除されないため、nginx の再起動に失敗します。 > そのため、サービス停止を QUIT シグナルではなく TERM シグナルを使用するように変更するか、または、daemon off で起動することをお勧めします。 > systemd を使用している場合も、ドロップインファイル等を作成して、nginx 停止時のシグナルを QUIT シグナルから TERM シグナルへの変更や、daemon off による管理への変更をお勧めします。 ### nginx のストリーム機能と ssl_preread 機能を利用する nginx の機能を利用して、同一ポートの待受で複数のプロトコルを扱えるようにします。 その機能を利用した nginx の参考設定です。証明書には Let's Encrypt を利用している想定です。 利用する証明書はマルチドメイン (SANs) またはワイルドカード証明書が前提となります。 - sora.example.com- シグナリングの WebSocket over TLS で利用するドメイン - sora-turn.example.com- TURN-TLS で利用するドメイン ```nginx stream { # SNI のサーバー名が取得できない場合、または、該当するサーバー名が指定されていない場合は TURN-TCP へ # 該当するサーバー名が指定されている場合は TURN-TLS または シグナリングへ map $ssl_preread_server_name $upstream { default sora-turn.example.com; "sora-turn.example.com" unix:/tmp/tls.sock; "sora.example.com" unix:/tmp/https.sock; } # Sora の TURN-TCP へ転送 upstream sora-turn.example.com { # Sora の TURN-TCP へ # ここの IP アドレスは Sora の ipv4_address に指定した値を指定してください # ここを 127.0.0.1 にすると Firefox で繋がらなくなることを確認しています server 192.0.2.1:3478; } # TURN-TCP, TURN-TLS, シグナリングを TCP で待ち受け server { listen 443; # IPv6 を利用している場合は下記を有効にしてください # listen [::]:443; proxy_pass $upstream; proxy_protocol on; ssl_preread on; } # TURN-TLS, シグナリングの TLS 終端し TURN-TCP へ転送 server { listen unix:/tmp/tls.sock ssl proxy_protocol; # SNI を見て TURN-TLS の場合は TURN-TCP へ転送 # シグナリング(HTTPS)の場合は HTTP へ転送 proxy_pass $ssl_server_name; proxy_protocol on; ssl_certificate /etc/letsencrypt/live/sora.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/sora.example.com/privkey.pem; ssl_protocols TLSv1.2; ssl_prefer_server_ciphers on; ssl_handshake_timeout 10s; ssl_session_cache off; ssl_session_tickets off; } } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; gzip on; # $proxy_protocol_addr を利用することでクライアントの IP が保持可能になる log_format proxy '$proxy_protocol_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent"'; # 定義した proxy を利用する access_log /var/log/nginx/access.log proxy; server { listen unix:/tmp/https.sock ssl proxy_protocol; root /var/www/html; index index.html index.htm; ssl_certificate /etc/letsencrypt/live/sora.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/sora.example.com/privkey.pem; ssl_protocols TLSv1.2; ssl_prefer_server_ciphers on; ssl_session_cache off; ssl_session_tickets off; real_ip_header proxy_protocol; server_name sora.example.com; # シグナリングを Sora に Proxy します location = /signaling { proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_pass http://127.0.0.1:5000/signaling; proxy_set_header X-Real-IP $proxy_protocol_addr; proxy_set_header X-Forwarded-For $proxy_protocol_addr; } # Sora の HTTP API に Proxy します # 本番環境では認証などの機能を利用してください location /api { proxy_http_version 1.1; proxy_pass http://127.0.0.1:3000/; } # Sora の開発ツールに Proxy します # 本番環境では不要です location / { proxy_http_version 1.1; proxy_pass http://127.0.0.1:5000; } } } ``` TURN-TCP、 TURN-TLS、シグナリングを 443 番で使用する場合の sora.conf の設定は以下になります。 turn_tcp_port, turn_tls_port を 443 に変更します。 ```ini ## TURN 機能を有効にするかどうかを指定してください turn = true ## TURN 機能で利用するレルムを指定してください turn_realm = sora-turn.example.com ## TURN 機能で TURN URL 払い出し機能で利用する FQDN (最後の . なし)を指定してください turn_fqdn = sora-turn.example.com ## TURN 機能で TURN-TCP を有効にするかどうかを指定してください turn_tcp = true ## TURN 機能で TURN-TCP を有効にした際に利用するポート番号を指定してください turn_tcp_listen_port = 3478 ## TURN 機能で TURN-TCP URL 払い出し時のポート番号を指定してください turn_tcp_port = 443 ## TURN 機能で TURN-TLS URL 払い出し機能を有効にするかどうかを指定してください ## オプションでデフォルトは false です turn_tls = true ## TURN 機能で TURN-TLS URL 払い出し機能で利用する FQDN (最後の . なし)を指定してください ## turn_tls_fqdn は turn_fqdn の値を上書きします turn_tls_fqdn = sora-turn.example.com ## TURN 機能で TURN-TLS URL 払い出し機能を有効にした際に利用するポート番号を指定してください turn_tls_port = 443 ``` ## カーネルパラメーターの適用 Sora は UDP を利用します。音声や映像の配信では大量の UDP を処理するため Linux のデフォルトの設定だと厳しい場合があります。 そのため、パラメータの変更を推奨しています。 詳細は [Linux カーネルチューニング](LINUX_KERNEL_TUNING.html) をご確認ください。 ## SDK の利用 Sora へ接続をする場合は弊社がオープンソースとして公開している SDK を利用してください。 これらのライブラリは弊社によって最新版の Sora で動作するようにメンテナンスされています。 導入もとても簡単になっているので、是非利用してください。 > **重要** > > SDK に関する質問・要望・バグなどの報告は Discord の利用をお願いします。 > Sora のライセンス契約の有無に関わらず、 > 応答時間と問題の解決を保証しませんのでご了承ください。 > > ただし、明らかなバグについては優先的に対応しますので、ご安心ください。 - Sora JS SDK- `#sora-js-sdk` チャンネル - Sora iOS SDK- `#sora-ios-sdk` チャンネル - Sora Android SDK- `#sora-android-sdk` チャンネル - Sora Unity SDK- `#sora-unity-sdk` チャンネル - Sora C++ SDK- `#sora-cpp-sdk` チャンネル - Sora Flutter SDK- `#sora-flutter-sdk` チャンネル ## やりたいことが 1:1 の双方向配信の場合 配信が 1:1 の双方向の場合はマルチストリーム機能を利用してください。 詳細は [マルチストリーム機能](MULTISTREAM.html) をご確認ください。 ## やりたいことが複数人での双方向配信の場合 複数人で双方向の配信を行いたい場合はスポットライト機能を検討してください。 スポットライト機能を利用することで、クライアントとサーバー側の負荷をかなり抑えられるようになります。 詳細は [スポットライト機能](SPOTLIGHT.html) をご確認ください。 ## Edge が機能要件に含まれている場合 最新の Edge であれば、ほとんど Chrome と同じ動きをしますので安心してお使いください。 ただし Edge では AV1 は動作しません。 ## 認証を外部の指定した HTTP サーバーで判断したい場合 認証ウェブフック機能を利用してください。この機能は外部の指定した HTTP サーバーで認証を判断することが可能になります。 外部の HTTP サーバーの URL 指定は `sora.conf` の [auth_webhook_url](SORA_CONF.html#36a99a) に設定してください。 そうすることで、外部に認証を移譲することができます。 詳細は [認証ウェブフック](AUTH_WEBHOOK.html) をご確認ください。 ## 接続、切断の検知を外部の指定した HTTP サーバーで利用したい場合 イベントウェブフック機能を利用してください。この機能は外部の指定した HTTP サーバーでクライアント単位での接続、切断を検知することが可能になります。 外部の HTTP サーバーの URL 指定は `sora.conf` の [event_webhook_url](SORA_CONF.html#e1a4d2) に設定してください。 そうすることで、外部にイベントをリクエスト送信することができます。 詳細は [イベントウェブフック](EVENT_WEBHOOK.html) をご確認ください。 ## 配信されている音声や映像を記録したい場合 Sora には録画機能があります。もし利用を検討されている場合はいくつか注意事項があります。 - 録画を終了させる、またはクライアントが切断するまで、録画ファイルは生成されない - 複数人数が参加する会議の録画ファイルはクライアントごとに生成される- 5 人が会議に参加していれば 5 個ファイルが生成されます これらを踏まえて録画機能の利用を検討してください。 録画機能の詳細は [録画機能](RECORDING.html) をご確認ください。 ## クライアント側で参加してきたユーザーの情報を通知したい場合 Sora では「〜さんが会議に参加しました」や「〜さんが会議から退席しました」というメッセージをクライアント側で流すことが可能です。 これにはシグナリング通知を利用します。 シグナリング通知機能はシグナリングで利用している WebSocket もしくは DataChannel を経由して、参加しているチャネルに新しく参加、または退席した状態を通知する機能です。自分が参加したときも自身に参加通知は飛びます。 ただシグナリング通知に含まれる標準の情報はあくまでコネクション ID のみになるため、そのコネクション ID が誰なのかはどこからか取得する必要があります。 そのコネクション ID が誰なのかを問い合わせる処理が毎回走ってしまうのは無駄なため、認証ウェブフックの戻り値で、 `signaling_notify_metadata` (シグナリング通知メタデータ)にそのコネクション ID の値のユーザー名を含めてください。そうすることで、Sora がその参加者のユーザー名を `signaling_notify_metadata` に含めて返すようになります。 この `signaling_notify_metadata` は新しく参加した人には `data` として、既存の参加している人の `signaling_notify_metadata` が含まれたリストが参加時に通知されるようになっています。 さらに、新しく参加者がいた場合はその参加者の `metadata` が通知されます。もちろん退席者の場合でもその退席者の `metadata` が含まれて通知されます。 `metadata` にユーザー名が含まれるため、サーバーへ問い合わせをしなくても参加者や退席者のユーザー名を取得することができます。 シグナリング通知の詳細は [シグナリング通知](SIGNALING_NOTIFY.html) をご確認ください。 シグナリング通知メタデータの詳細は [シグナリング通知メタデータ](SIGNALING_NOTIFY_METADATA.html) をご確認ください。 # ライセンス Sora はライセンスファイルを読み込ませることで起動します。 ## ライセンスファイルのパス設定と配置 ライセンスファイルのパスは `sora.conf` の [license_file](SORA_CONF.html#77d4d5) で設定できます。 Sora を起動する前に設定し、ライセンスファイルを配置してください。 デフォルト設定のまま使う場合は、ライセンスファイルを sora ディレクトリ以下の etc/license.json にコピーしてください。 ``` $ cp 123ABC-SRA-E001-202301-100.json sora/etc/license.json ``` ## ライセンスの更新 ライセンスを更新する場合は `sora.conf` の [license_file](SORA_CONF.html#77d4d5) で指定しているファイルを cp コマンドで上書きしてください。 デフォルト設定では sora ディレクトリ以下にある `etc/license.json` です。 ```console $ cp 123ABC-SRA-E002-201901-100.json sora/etc/license.json ``` その後、ライセンス更新 API である `UpdateLicense API` を実行することで更新されます。 Sora の再起動は不要です。 192.0.2.1 の部分には実際に利用している IP アドレスかドメインを指定してください ```console $ http POST 192.0.2.1:3000/ x-sora-target:Sora_20171218.UpdateLicense -vvv ``` 正常に反映されているかを `GetLicense API` を実行して `serial_code` を確認してください。 ```console $ http POST 192.0.2.1:3000/ x-sora-target:Sora_20171218.GetLicense -vvv ``` ### ライセンスの更新に失敗した場合 もし、誤って壊れているライセンスファイル等を使用して更新に失敗しても、既存のライセンス情報は上書きされません。 ### ライセンスの更新時のライセンス適用について ライセンスが更新される際に新しい接続が発生したとしても、 更新前または更新後のいずれかのライセンスが適用され、最大同時接続数の確認が行われます。 ライセンスの状態が一時的に空白になることはありません。 ## 接続数制限 Sora はライセンスファイルを組み込むことで起動するようになります。 ライセンスファイルには最大接続数が定義してあり、その最大接続数を超えて接続することはできません。 また、接続ができなかったクライアントには `EXCEED-MAX-CONNECTIONS` というエラーが通知されます。 ## ライセンス期限が過ぎている場合 既存の接続は継続されますが、新規接続ができなくなります。 `EXPIRED-LICENSE` というエラーがログに記録されます。 ### ライセンスの期限時刻 ライセンスの期限が `2022-01` の場合は UTC で 2022 年 2 月 1 日の 0 時から新規接続ができなくなります。 ## ライセンスファイルのパスの更新 ライセンスファイルのパスの更新は、一度 Sora を停止し、 `sora.conf` の [license_file](SORA_CONF.html#77d4d5) のパスを変更して Sora を起動する必要があります。 ## 最大ノード数ライセンス 2022 年 6 月から `最大ノード数ライセンス` という形式のライセンスを提供しています。 Sora のライセンスは 1 Sora 起動 1 ライセンスと固定されており、 無制限ライセンスを除き、同一ライセンスを複数の Sora で利用することはできません。 しかし `最大ノード数ライセンス` は、 クラスター構築時にライセンスの最大ノード数までは同一ライセンスを利用することができるライセンスです。 > **危険** > > 最大ノード数に対応していないライセンスで複数の Sora を起動することはできません。 最大ノード数に対応したライセンスファイルの中身の例 ```javascript { "expired_at": "2013-03", "max_connections": 100, "max_nodes": 3, "product_name": "Sora", "serial_code": "DOC123-SRA-E002-201303-N3-100", "signature": "****", "type": "Experimental" } ``` ファイルの中身に `"max_nodes": 3` と書かれているライセンスでは、クラスターを組む際に最大 3 ノードまで同一のライセンスが利用可能です。 > **注釈** > > max_nodes 1 につき 1 ライセンス分の料金が必要になります。例えば max_nodes が 3 の場合は 3 ライセンス分の料金となります。 > **危険** > > 最大ノード数に対応しているライセンスを利用した場合に構築できるクラスターは 1 つのみです。複数のクラスターを構築することはできません。 `最大ノード数ライセンス` について不明な部分がある場合はサポートにお問い合わせください。 ### 最大ノード数ライセンスの非クラスター利用について > **注意** > > 契約済みの最大ノード数ライセンスを非クラスターで利用したい場合はサポートまでご連絡ください。 最大ノード数ライセンスはクラスターを利用しない場合は通常のライセンスと同じように利用できます。 ただし、 その場合は 1 ライセンスとして扱うため、1 ノードでしか利用できません。 もし `"max_nodes": 3` と記載されていても、クラスターを利用しない場合は 1 ノードでしか利用できません。 ### 最大ノード数ライセンスへの切り替えについて 通常のライセンスから最大ノード数ライセンスへの切り替えが可能です。詳細はサポートまでご連絡ください。 # ログファイル **サポート問い合わせの場合は log/ ディレクトリ以下をすべて圧縮して送ってください** ## log/ 以下のログファイル Sora は log/ ディレクトリ以下にログファイルを出力します。 ### Sora の運用に関係するログ - sora.log または sora.jsonl- Sora の開始、終了や問題があった場合に出力されますので、まずはこの監視をお願いします - ログローテーションされませんので、ログローテーションをお願いします - 週次ログローテーションを推奨します - auth_webhook.log または auth_webhook.jsonl- auth_webhook で外部に送信する処理を全て書き込みます - ログローテーションされませんので、ログローテーションをお願いします - 週次ログローテーションを推奨します - session_webhook.log または session_webhook.jsonl- session_webhook で外部に送信する処理を全て書き込みます - ログローテーションされませんので、ログローテーションをお願いします - 週次ログローテーションを推奨します - session_webhook_error.log または session_webhook_error.jsonl- session_webhook で外部への送信が失敗した処理を書き込みます - ログローテーションされませんので、ログローテーションをお願いします - 週次ログローテーションを推奨します - event_webhook.log または event_webhook.jsonl- event_webhook で外部に送信する処理を全て書き込みます - ログローテーションされませんので、ログローテーションをお願いします - 週次ログローテーションを推奨します - event_webhook_error.log または event_webhook_error.jsonl- event_webhook で外部に送信が失敗した処理を書き込みます - ログローテーションされませんので、ログローテーションをお願いします - 週次ログローテーションを推奨します ### Sora のサポートに関係するログ - connection.log または connection.jsonl- 接続が切断した際にクライアントとサーバーの統計情報を出力するログです - ログローテーションされませんので、ログローテーションをお願いします - 週次ログローテーションを推奨します - signaling.log または signaling.jsonl- シグナリングでやりとりされている offer/answer/candidate/re-offer/re-answer と接続終了を記録したログです - ログローテーションされませんので、ログローテーションをお願いします - 週次ログローテーションを推奨します - api.log または api.jsonl- 一部の API 操作に関するログを出力します - ログローテーションされませんので、ログローテーションをお願いします - 週次ログローテーションを推奨します - internal.log または internal.jsonl- Sora が予定外の動作をしたときに出力されるログです。問題解決に必須のログです - ログローテーションされませんので、ログローテーションをお願いします - 週次ログローテーションを推奨します - crash.log- Sora が予定外の動作をしたときに出力されるログです。問題解決に必須のログです - ログローテーションされませんので、ログローテーションをお願いします - 週次ログローテーションを推奨します - erlang.log.<1-5>- サポート時に必要となるログですので、気にする必要はありません - 自動でログローテーションされますので、ログローテーションは不要です - `bin/sora foreground` コマンドで起動する場合には出力されません - sysctl.log- 起動時に取得するログで、毎回上書きされます - sysctl -a の実行結果を記録します - ログローテーションは不要です - ulimit.log- 起動時に取得するログで、毎回上書きされます - ulimit -n の実行結果を記録します - ログローテーションは不要です - run_erl.log- 起動時に出力されるログのため、ほとんどログが出力されることはありません - ログローテーションは不要です - `bin/sora foreground` コマンドで起動する場合には出力されません - connection_created_wait_timeout_error/_.jsonl- sora.log に `CONNECTION-CREATED-WAIT-TIMEOUT-ERROR` が出力された際の接続情報を出力します - クライアントと Sora との間で WebRTC が確立できなかった場合の情報です - ファイル名は時刻とコネクション ID の組み合わせです ## 特別なログ Sora が異常終了した際 `erl_crash.dump` というファイルが log/ ディレクトリに生成されます。 こちらは **必ず** 保存し、送っていただけるようお願いいたします。 ### 監視用確認目的で erl_crash.dump ログを強制的に出力させる方法 監視を行う際に実際に `erl_crash.dump` を生成したい場合には、 `bin/sora daemon` で起動した上で、 `kill -SIGUSR1` を使用して `run_erl` プロセスを落としてください。 ``` $ kill -SIGUSR1 <プロセス ID> ``` この方法で log/ ディレクトリに `erl_crash.dump` が生成されます。 ## JSONL (JSON Lines) フォーマット Sora は一部のログを除いて JSONL フォーマットでログを出力します。 JSONL の仕様は [JSON Lines](https://jsonlines.org/) に記載されているものに準拠します。 - UTF-8 エンコード - 改行は `\n` - 各行は JSON 値 - ファイル拡張子は `jsonl` ### JSONL フォーマットで出力されるログ `sora.conf` の `legacy_log_format` を `false` に設定することで以下のログが JSONL フォーマットで出力されます。 JSONL フォーマット出力ログの拡張子を `jsonl` に変更するには `sora.conf` の `legacy_log_extension` を `false` に設定します。 - sora ログ - internal ログ - api ログ - signaling ログ - connection ログ - auth_webhook ログ - session_webhook ログ - session_webhook_error ログ - event_webhook ログ - event_webhook_error ログ ## connection ログ **出力ファイル名**: connection.log または connection.jsonl Sora は接続単位で統計情報を保持しています。クライアント側の統計情報とサーバー側の統計情報の両方をログとして出力します。 クライアント側の統計情報はユーザーエージェント統計情報機能を利用しているため、 SDK 側がユーザーエージェント統計機能に対応している必要があります。 こちらのログはログローテーションしないため、ローテーションが必要となります。 ## sora ログ **出力ファイル名**: sora.log または sora.jsonl sora ログは主にサポートで利用するためのログを出力します。そのためエラーメッセージがかなり技術的な表現になっています。 - sora ログは何かあって大量のログが出たとしてもうまい具合にスキップする機能が入っています ### UTC に固定 sora ログのタイムスタンプは RFC 3339 UTC (マイクロ秒) 形式に固定されています。 ``` 2022-06-06T08:04:37.390710Z [warning] [sora/1DSH1E4S/sendrecv] [sim,multi] ``` JSONL フォーマットの場合は `timestamp` という項目でタイムスタンプが出力されます。 ```javascript { "level": "debug", "channel_id": "sora", "multistream": true, "role": "sendonly", "simulcast": false, "spotlight": false, "node_name": "sora@127.0.0.1", "connection_id": "NXHKH46FP93571ZM4PZBSFD4Z4", "timestamp": "2022-08-02T04:43:02.828358Z" } ``` ### クラスター利用時 #### レガシーフォーマット利用時 レガシーフォーマット利用時にクラスターを有効にしている場合はログレベルの後ろにノード名が出力されます。 ``` 2022-06-07T02:25:48.479789Z [warning] sora@127.0.0.1 [sora/1DSH1E4S/sendrecv] [sim,multi] ``` #### JSONL フォーマット利用時 JSONL フォーマットの場合はノード名は常に出力されます。 ```javascript { "level": "debug", "channel_id": "sora", "multistream": true, "role": "sendonly", "simulcast": false, "spotlight": false, "node_name": "sora@127.0.0.1", "connection_id": "NXHKH46FP93571ZM4PZBSFD4Z4", "timestamp": "2022-08-02T04:43:02.828358Z" } ``` ### オプション情報 #### レガシーフォーマット利用時 - [チャネル ID/コネクション ID(ショート)/role] を表示します - `multi` / `spot` / `sim` の3つを表示します **multi** : マルチストリーム **spot** : スポットライト **sim** : サイマルキャスト ``` 2022-06-07T02:25:48.479789Z [warning] [sora/1DSH1E4S/sendrecv] [sim,multi] ``` #### JSONL フォーマット利用時 JSONL フォーマットの場合は各項目はブーリアンで出力されます。 ```javascript { "level": "debug", "channel_id": "sora", "multistream": true, "role": "sendonly", "simulcast": false, "spotlight": false, "node_name": "sora@127.0.0.1", "connection_id": "NXHKH46FP93571ZM4PZBSFD4Z4", "timestamp": "2022-08-02T04:43:02.828358Z" } ``` ### 出力例 #### レガシーフォーマット利用時 シグナリング接続時の `"type"` で指定する JSON が間違っており、Sora 側から切断した際に出力される `INVALID-JSON` の出力例は次のとおりです。 ``` 2022-06-07T02:25:48.479789Z [error] [-/-/-] <0.9239.2> INVALID-JSON ``` シグナリングに WebSocket を利用している場合に、 60 秒に一度も `"type": "pong"` が返ってこない場合Sora 側から切断した際に出力される `PONG-TIMEOUT-ERROR` の出力例は次の通りです。 ``` 2022-06-07T02:25:48.479789Z [error] [sora/4G7607CP/sendrecv] [multi] <0.13016.17> PONG-TIMEOUT-ERROR | reason=<<"WebSocket">> ``` #### JSONL フォーマット利用時 シグナリング接続時に認証サーバーがステータスコード 400 を返してきた際に出力される `AUTH-WEBHOOK-RESPONSE-UNEXPECTED-STATUS-CODE` の出力例は次の通りです。 ```javascript { "channel_id": "sora", "connection_id": "J9RQEB074S2EB9SFBCN9AH7ASM", "domain": [ "sora", "signaling" ], "level": "error", "msg": "AUTH-WEBHOOK-RESPONSE-UNEXPECTED-STATUS-CODE | reason={auth_webhook_response_unexpected_status_code,#{status_code => 400}}", "multistream": true, "node": "sora@127.0.0.1", "role": "recvonly", "simulcast": false, "sora_version": "2022.2.0", "spotlight": false, "timestamp": "2022-08-03T03:43:13.588364Z" } ``` ### warning ログレベル `warning` は「接続自体は維持できる問題」の際に出力します。 このログが出力された場合でも Sora 側から切断は行いません。 - 一般- WEBSOCKET-TERMINATE- DataChannel シグナリングで ignore_disconnect_websocket: true の際に WebSocket が想定外の終了をした場合に出力します - MULTISTREAM-RE-ANSWER-NO-ICE-UFRAG- マルチストリーム利用時 `type: re-answer` を受信した際に ICE に必要な SDP が含まれていない場合に出力します - MULTISTREAM-INTERNAL-ERROR - ウェブフック- INVALID-AUTHZ-VALUE- 認証ウェブフック成功時に認証サーバーからの払い出した値がおかしい場合に出力します - TERMINATE-EVENT-WORKER- イベントウェブフックのワーカーが何らかの理由で終了した場合に出力します - MISSING-WEBHOOK-BASIC-AUTH-USER-ID- ウェブフック利用時にベーシック認証のユーザー ID が見つからない場合に出力します - MISSING-WEBHOOK-BASIC-AUTH-PASSWORD- ウェブフック利用時にベーシック認証のパスワードが見つからない場合に出力します - MISSING-WEBHOOK-PROXY-AUTH-PASSWORD- ウェブフック利用時にプロキシのパスワードが見つからない場合に出力します - 録画- ARCHIVE-FINAL-SPLIT-ERROR- 録画ファイルの分割がエラーになった場合に出力します、ただし全体出力に向けて処理は継続します - MISSING-RECORDING-WORKER-PID- 録画処理が完了したワーカーが見つからず正常終了できない場合に出力します - プロトコル- DTLS-ALERT- DTLS でレベルが WARNING のアラートメッセージがクライアントから送られてきた場合に出力します - TURN-SEND-INDICATION-BINDING-ERROR- TURN 利用時に STUN-Binding-Error over STUN-Send-Indication を受信した場合に出力します - TURN-CHANNEL-DATA-BINDING-ERROR- TURN 利用時に STUN-Binding-Error over TURN-Channel-Data を受信した場合に出力します - SIMULCAST-DUPLICATED-RID- クライアントから複数の SSRC から同一の RID が送られてきた場合に出力します - UNKNOWN-RTP- `role: reconly` にもかかわらず RTP パケットが送られてきた場合に出力します - Sora の内部エラーでも出力される場合があります - UNKNWON-RTCP- 見知らぬ RTCP を受信した場合に出力します - ULPFEC-RECOVER-ERROR- ULPFEC を利用している場合にリカバーを試みて失敗した場合に出力します - RTP-PACKET-LOSS-SIMULATOR-INCOMING-ENABLED- 受信パケロスシュミレーターを有効にしている場合に出力します - RTP-PACKET-LOSS-SIMULATOR-OUTGOING-ENABLED- 送信パケロスシュミレーターを有効にしている場合に出力します ### error ログレベル `error` は「接続自体を維持できない問題」の際に出力します。 このログが出力された場合、Sora 側から切断を行います。 - 一般- UNEXPECTED-EXIT - シグナリング- INVALID-JSON- 無効な JSON を受け取った場合に出力します - FAILURE-JSON-DECODE- JSON のデコードに失敗した場合に出力します - AUTHENTICATION-FAILURE- 認証ウェブフックで認証が失敗した場合に出力します - AUTHENTICATION-INTERNAL-ERROR- 認証ウェブフックで 200 番台以外が返ってきた場合に出力します - INTERNAL-ERROR- Sora の内部エラーです - MISSING-SDP-FINGERPRINT- SDP に DTLS の証明書検証に利用するフィンガープリントが見つからなかった場合に出力します - MISSING-ICE-SDP- SDP に ICE で利用する情報が見つからなかった場合に出力します - FAILURE-SDP-PARSE- SDP のパースに失敗した場合に出力します - INVALID-SIGNALING-TYPE- 送られてきたシグナリングメッセージの type が無効な場合に出力します - UNEXPECTED-SIGNALING-TYPE- 送られてきたシグナリングメッセージの type が見知らぬ場合に出力します - MISSING-TYPE- 送られてきたシグナリングメッセージに type が見つからない場合に出力します - INVALID-MESSAGE- E2EE が有効ではないのに E2EE メッセージが送られてきた場合に出力します - TOO-LARGE-JSON- 送られてきた JSON が巨大な場合に出力されます - TOO-MANY-CANDIDATE- あまりにも多い type: candidate を送ってきた場合に出力します - SIGNALING-INTERNAL-ERROR- シグナリングでの内部エラーが発生した場合に出力します - TRANSPORT-INTERNAL-ERROR- 通信での内部エラーが発生した場合に出力します - BAD-FINGERPRINT- DTLS の証明書の検証に失敗した場合に出力します - PONG-TIMEOUT-ERROR- 5 秒間隔で type: ping を送信し、60 秒間 1 度も type: pong が返ってこない場合に出力します - CONNECT-WAIT-TIMEOUT-ERROR- WebSocket を確立して一定時間以内に type: connect を送ってこない場合に出力します - CONNECTION-CREATED-WAIT-TIMEOUT-ERROR- 一定時間以内に WebRTC が確立しない場合に出力します - ANSWER-TIMEOUT-ERROR- 一定時間以内に type: answer を送ってこない場合に出力します - ライセンス- EXPIRED-LICENSE- ライセンスが切れている場合に出力されます - EXCEED-MAX-CONNECTIONS- ライセンスの同時接続数を超えて接続をしようとしたクライアントがいた場合に出力されます - 認証ウェブフック- AUTH-WEBHOOK-INTERNAL-ERROR- 認証ウェブフックで内部エラーが発生した場合出力します - AUTH-WEBHOOK-AUTHZ-INTERNAL-ERROR- 認証ウェブフックの戻り値で内部エラーが発生した場合出力します - イベントウェブフック- EVENT-WEBHOOK-ERROR- イベントウェブフックリクエストが正常に送信できなかった場合に出力します - DataChannel- INVALID-DATA-CHANNEL-USER-DATA- 片方向でしか利用していない DataChannel にメッセージが送られてきた場合に出力します - 録画- ARCHIVE-FAILED- 録画ファイルの生成に失敗した際に出力します - RECORDING-INTERNAL-ERROR- 録画で内部エラーが発生した際に出力します - E2EE- INVALID-E2EE-MESSAGE- E2EE メッセージがおかしい場合に出力します - NOT-ALLOWED-E2EE- E2EE を許可していない状態で E2EE 機能をクライアントが利用しようとした場合に出力します - プロトコル- TURN-UDP-INTERNAL-ERROR- TURN UDP で内部エラーが発生した場合に出力します - DTLS-ALERT- DTLS でレベルが FATAL のアラートメッセージが送られてきたとき出力します ### emergency ログレベル `emergency` は「Sora の起動を維持できない問題」の際に出力します。 このログが出力された場合、Sora を終了します。 - BOOT-FAILED> - Sora が正常に起動できない場合に出力します - 設定- SORA-CONF-ERROR- sora.conf が正常に読み込めない場合に出力します - クラスター- CLUSTER-INTERNAL-FAILURE- クラスター内部で問題が発生した際に出力します # sora.conf リファレンス Sora の設定ファイルは `key = value` 形式です。 文字列であっても `""` で囲わないでください。 ## 単位指定 `sora.conf` では一部の設定に単位の指定が必須です。 - 利用可能な単位- ミリ秒 `ms` - 秒 `s` - 分 `min` - 時 `h` - 数値と単位の間にはスペースを入れて下さい ```ini webhook_response_timeout = 30 s ``` ## license_file **デフォルト**: "etc/license.json" ライセンスファイルのパスを指定してください、可能な限り **絶対パス** を指定してください。 ```ini license_file = etc/license.json ``` ## label **デフォルト**: "WebRTC SFU Sora" 認証やイベントウェブフックリクエスト送信時に送られる、サーバー固有の値を指定することができます。 ```ini label = sora-node-001.example.com ``` ## ipv4_address **デフォルト**: 設定無し この値を有効にしなくても自動で IPv4 アドレスを収集しますが、 固定された IPv4 アドレスがサーバーに割り当てられている場合は指定することを推奨しています。 IPv4 アドレスを指定してください。 `192.0.2.10` のように指定してください。 ```ini ipv4_address = 192.0.2.10 ``` ## ipv6 **デフォルト**: false IPv6 機能を有効にするかどうか指定してください。デフォルトでは無効になっています。 この機能を有効にすると以下の機能が有効になります - ipv6_address が指定されていない場合は自動で IPv6 アドレスが収集される - ipv6_address で指定された値が使用される - IPv6 アドレスが使用可能だった場合、 TURN サーバーの URL が IPv6 でも払い出される この機能はシグナリングや API を IPv6 有効にする機能ではありません。シグナリングや API は IPv6 非対応です。 ```ini ipv6 = false ``` ## ipv6_address **デフォルト**: 設定無し この値を有効にしなくても ipv6 が true の場合は、自動で IPv6 アドレスを収集しますが、 固定された IPv6 アドレスがサーバーに割り当てられている場合は指定することを推奨しています。 IPv6 アドレスを指定してください。 `2001:0DB8::10` のように指定してください。 ```ini ipv6_address = 2001:0DB8::10 ``` ## devtools **デフォルト**: false Sora には機能をすぐに試してもらえるように開発ツールが含まれています。 開発ツールを有効にする場合は、 true を指定し、有効にしてください。 詳細は [開発者ツール](DEVTOOLS.html) をご確認ください。 ```ini devtools = true ``` ## auth_webhook_url **デフォルト**: 指定なし 認証機能を有効にしたときに、問い合わせに行く HTTP URL を指定してください。その戻り値に含まれる値によって認証の可否を判定します。 ```ini auth_webhook_url = https://example.com/sora/webhook/auth ``` ## auth_webhook_log **デフォルト**: true 認証のログをすべてファイルに出力します。詳細は [認証ウェブフックログ](AUTH_WEBHOOK.html#d4693f) をご確認ください。 ```ini auth_webhook_log = true ``` ## session_webhook_url **デフォルト**: 指定なし セッションに関連するウェブフックリクエスト送信先の HTTP URL を指定してください。 ```ini session_webhook_url = https://example.com/sora/webhook/session ``` ## session_webhook_worker_number **デフォルト**: 5 **範囲**: 5-5000 セッションウェブフックのワーカー数を指定します。 ```ini session_webhook_worker_number = 5 ``` ## session_created_timeout **デフォルト**: 5 s **範囲**: 0 - 300 s セッションの同時接続数が 0 から 1 になった場合にセッション作成にかけられる時間を指定します。 ```ini session_created_timeout = 5 s ``` ## session_destroyed_timeout **デフォルト**: 15 s **範囲**: 0 - 300 s セッションに同時接続数が 0 になった場合、セッション破棄する時間を指定します。 ```ini session_destroyed_timeout = 15 s ``` ## event_webhook_url **デフォルト**: 指定なし クライアントの接続や切断、録画ファイル生成の終了などのイベントを通知する HTTP URL を指定してください。 ```ini event_webhook_url = https://example.com/sora/webhook/event ``` ## event_webhook_worker_number **デフォルト**: 5 **範囲**: 5-5000 イベントウェブフックのワーカー数を指定します。 イベントウェブフックのワーカー割り当てに利用する値は `channel_id` です。 ```ini event_webhook_worker_number = 5 ``` ## webhook_response_timeout **デフォルト**: 5 s **範囲**: 1-600 s ウェブフックのレスポンスタイムアウト時間を指定してください。 ```ini webhook_response_timeout = 5 s ``` ## webhook_insecure > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: false ウェブフックで HTTPS を利用する際に証明書のチェックを行わない場合はこの設定を有効にして下さい。 ```ini webhook_insecure = true ``` ## webhook_basic_authn **デフォルト**: false ウェブフックで HTTP ベーシック認証を利用するかどうかを指定してください。 ```ini webhook_basic_authn = true ``` ## webhook_basic_authn_user_id **デフォルト**: 指定なし ウェブフックで HTTP ベーシック認証を利用する際のユーザー ID を指定して下さい。 `basic-authn-user-id` の用に文字列で指定して下さい。 ```ini webhook_basic_authn_user_id = basic-authn-user-id ``` ## webhook_basic_authn_password **デフォルト**: 指定なし ウェブフックで HTTP ベーシック認証を利用する際のパスワードを指定して下さい。 `basic-authn-password` の用に文字列で指定して下さい。 ```ini webhook_basic_authn_password = basic-authn-password ``` ## webhook_proxy_url **指定しない場合はコメントアウトしたままにしてください** **デフォルト**: 指定なし ウェブフックで利用する HTTP Proxy の URL を指定して下さい。 `http://proxy.example.com:8080` の用に URL を指定して下さい。 ```ini webhook_proxy_url = http://proxy.example.com:8080 ``` ## webhook_proxy_auth_user **指定しない場合はコメントアウトしたままにしてください** **デフォルト**: 指定なし ウェブフックで利用する HTTP Proxy の認証ユーザーを指定して下さい。 `proxy-auth-user` の用に文字列で指定して下さい。 ```ini webhook_proxy_auth_user = proxy-auth-user ``` ## webhook_proxy_auth_password **指定しない場合はコメントアウトしたままにしてください** **デフォルト**: 指定なし ウェブフックで利用する HTTP Proxy の認証パスワードを指定して下さい。 `proxy-auth-password` の用に文字列で指定して下さい。 ```ini webhook_proxy_auth_password = proxy-auth-password ``` ## webhook_tls_fullchain_file **指定しない場合はコメントアウトしたままにしてください** **デフォルト**: 指定なし ウェブフックリクエスト送信先との通信に HTTPS で mTLS を利用するための設定で、 中間証明書を含むクライアント証明書を PEM 形式で設定して下さい。 ```ini webhook_tls_fullchain_file = /path/to/fullchain.pem ``` ## webhook_tls_privkey_file **指定しない場合はコメントアウトしたままにしてください** **デフォルト**: 指定なし ウェブフックリクエスト送信先との通信に HTTPS で mTLS を利用するための設定で、 クライアント証明書の秘密鍵を PEM 形式で設定して下さい。 > **重要** > > 秘密鍵にはパスフレーズが設定されている場合エラーとなります ```ini webhook_tls_privkey_file = /path/to/privkey.pem ``` ## webhook_tls_verify_cacert_file **指定しない場合はコメントアウトしたままにしてください** **デフォルト**: 指定なし ウェブフックリクエスト送信先との通信に HTTPS を利用した際、サーバー証明書のチェックを行う CA ファイルを PEM 形式で設定して下さい。 ```ini webhook_tls_verify_cacert_file = /path/to/server_cacert.pem ``` > **重要** > > この設定をしないと Sora に内蔵している CA 証明書を利用してサーバー証明書をチェックします。 > Sora に内蔵している CA 証明書一覧は [こちら](https://ccadb-public.secure.force.com/mozilla/IncludedCACertificateReport) で確認可能です ## ignore_connection_updated_webhook **デフォルト**: false イベントウェブフックの接続の更新時に `event_webhook_url` に指定された URL へ `connection.updated` を送るかどうかを指定してください。 デフォルトではリクエストの送信を行います。 ```ini ignore_connection_updated_webhook = false ``` ## ignore_connection_failed_webhook **デフォルト**: true 接続が失敗時に `event_webhook_url` に指定された URL へ `connection.failed` リクエストを送るかどうかを指定してください。 デフォルトではリクエストの送信を行いません。 ```ini ignore_connection_failed_webhook = true ``` ## ignore_session_vanished_webhook **デフォルト**: true モードが `block_new_session` または `block_new_connection` の際に、 `session_webhook_url` に指定された URL に `session.vanished` リクエストを送るかどうか指定してください。 デフォルトではリクエストの送信を行いません。 ```ini ignore_session_vanished_webhook = true ``` ## ignore_spotlight_changed_webhook **デフォルト**: true スポットライト機能で発言者が切り替わった場合に、 `event_webhook_url` に登録された URL に `spotlight.focused` と `spotlight.unfocused` リクエストを送るかどうかを指定してください。 デフォルトではリクエストの送信を行いません。 ```ini ignore_spotlight_changed_webhook = true ``` ## ignore_recording_started_webhook **デフォルト**: false 録画機能で、録画を開始した場合に、 `event_webhook_url` に登録された URL に `recording.started` リクエストを送るかどうかを指定してください。 デフォルトではリクエストの送信を行います。 ```ini ignore_recording_started_webhook = true ``` ## ignore_archive_started_webhook **デフォルト**: false 録画機能で、コネクションのアーカイブを開始した場合に、 `event_webhook_url` に登録された URL に `archive.started` リクエストを送信するかどうかを指定してください。 デフォルトではリクエストの送信を行います。 ```ini ignore_archive_started_webhook = true ``` ## archive_dir **デフォルト**: archive 録画ファイルが保存されるディレクトリを指定してください。可能な限り **絶対パス** で指定してください。 ```ini archive_dir = /path/to/archive ``` > **注意** > > `archive_dir` と `archive_tmp_dir` は違うディレクトリを指定して下さい ## archive_tmp_dir **デフォルト**: tmp/archive 録画に使用する一時ファイルを保存するディレクトリを指定してください。可能な限り **絶対パス** で指定してください。 > **重要** > > 録画が失敗した場合には、このディレクトリに保存されたファイルは自動的に削除されません。 > そのため録画失敗時には一時ファイルが残り続けます。 ```ini archive_tmp_dir = /path/to/tmp/archive ``` > **注意** > > `archive_dir` と `archive_tmp_dir` は違うディレクトリを指定して下さい ## split_archive_legacy_prefix > **警告** > > この設定は 2023 年 6 月リリース予定の Sora にて廃止されます **デフォルト**: false レガシーな分割録画の設定を有効にするかどうかを指定してください。 この設定を有効にすると以下のように変更されます。 - 分割録画ファイルが利用できるようになった際のイベントウェブフックタイプが `"type": "archive.split"` に変更されます - 分割録画ファイルが終了した際のイベントウェブフックタイプが `"type": "archive.end"` に変更されます - 分割録画ファイルメタデータのファイル名が `"type": "archive-_.json"` に変更されます ```ini split_archive_legacy_prefix = false ``` ## signaling_port **デフォルト**: 5000 シグナリングに使用するポート番号を指定してください。 ```ini signaling_port = 5000 ``` ## signaling_loopback_address_only **デフォルト**: false シグナリングへのアクセスをループバックアドレスからのみに制限します。可能な限り有効にしてください。 ```ini signaling_loopback_address_only = true ``` ## signaling_notify **デフォルト**: true シグナリング経由で接続や切断、更新の通知を受け取るかどうか指定してください。この設定はすべての設定に影響します。 個別の設定の場合は認証ウェブフックのレスポンス時で指定してください。 シグナリング経由での通知機能の詳細は ["type": "notify"](SIGNALING.html#c4828f) をご確認ください 認証の戻り値に関しては [認証ウェブフックの戻り値での指定](SIGNALING_NOTIFY_METADATA.html#28d39f) を確認してください。 ```ini signaling_notify = true ``` ## signaling_notify_session_id **デフォルト**: true シグナリング通知機能が有効な際、通知にセッション ID を含むかどうかを指定してください。 ```ini signaling_notify_session_id = true ``` ## signaling_notify_client_id **デフォルト**: true シグナリング通知機能が有効な際、通知にクライアント ID を含むかどうかを指定してください。 ```ini signaling_notify_client_id = true ``` ## signaling_notify_bundle_id **デフォルト**: true シグナリング通知機能が有効な際、通知にバンドル ID を含むかどうかを指定してください。 ```ini signaling_notify_bundle_id = true ``` ## signaling_notify_connection_id **デフォルト**: true シグナリング通知機能が有効な際、通知にコネクション ID を含むかどうかを指定してください。 ```ini signaling_notify_connection_id = true ``` ## signaling_notify_media **デフォルト**: true シグナリング通知機能が有効な際、通知に音声や映像が有効かどうかを含むかどうかを指定してください。 ```ini signaling_notify_media = true ``` ## signaling_notify_metadata **デフォルト**: true シグナリング通知機能が有効な際、 `"type": "connect"` の `signaling_notify_metadata` で指定した値、 または認証ウェブフックの戻り値の `signaling_notify_metadata` で指定した値を通知するかどうかを指定してください。 ```ini signaling_notify_metadata = true ``` ## signaling_notify_metadata_ext **デフォルト**: false シグナリング通知メタデータ拡張機能を有効にするかどうかを指定して下さい。 シグナリング通知機能が無効でも通知されないだけで API は利用可能です。 詳細は [シグナリング通知メタデータ拡張機能](SIGNALING_NOTIFY_METADATA_EXT.html) をご確認下さい。 ```ini signaling_notify_metadata_ext = true ``` ## signaling_notify_authn_metadata_max_size **デフォルト**: 64512 シグナリング通知認証メタデータの最大サイズをバイト単位で指定してください。 0 ~ 1048576 の範囲で指定可能です。 ```ini signaling_notify_authn_metadata_max_size = 64512 ``` ## signaling_notify_network **デフォルト**: true シグナリング通知機能が有効な際、ネットワークの状態を通知するかどうかを指定してください。 ```ini signaling_notify_network = true ``` ## signaling_notify_rtp_stream **デフォルト**: true シグナリング通知機能が有効な際、 RTP ストリームの停止と再開の状態を通知するかどうかを指定してください。 ```ini signaling_notify_rtp_stream = true ``` ## signaling_notify_recording **デフォルト**: true シグナリング通知機能が有効な際、 録画の開始と停止の状態を通知するかどうかを指定してください。 ```ini signaling_notify_recording = true ``` ## signaling_bundle_id **デフォルト**: false シグナリングでバンドル ID を指定可能にするかどうかを指定してください。 ```ini signaling_bundle_id = true ``` ## default_data_channel_signaling > **注意** > > この機能を本番環境で利用する場合は事前にサポートまでご連絡ください **デフォルト**: false シグナリング経路を WebSocket から DataChannel に切り替えるかどうかを指定してください。 ```ini default_data_channel_signaling = false ``` ## default_ignore_disconnect_websocket > **注意** > > この機能を本番環境で利用する場合は事前にサポートまでご連絡ください **デフォルト**: false シグナリング経路を DataChannel に切り替えた際に WebSocket が切断されても接続の切断と判断しないかどうかを指定してください。 ```ini default_ignore_disconnect_websocket = false ``` ## data_channel_messaging > **注意** > > この機能を本番環境で利用する場合は事前にサポートまでご連絡ください **デフォルト**: false DataChannel を使用したメッセージング機能を利用するかどうかを指定してください。 ```ini data_channel_messaging = false ``` ## data_channel_messaging_only > **注意** > > この機能を本番環境で利用する場合は事前にサポートまでご連絡ください **デフォルト**: false DataChannel メッセージング利用時に、音声と映像を `false` にした場合でも接続可能にするかどうかを指定してください。 ```ini data_channel_messaging_only = false ``` ## data_channel_stats_timer_interval **単位指定必須** **デフォルト**: 5 s **範囲**: 5-300 秒 シグナリング経路を DataChannel に切り替えた際にクライアントへの統計情報を要求する間隔を指定してください。 ```ini data_channel_stats_timer_interval = 5 s ``` ## dcsctp_heartbeat_interval > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **単位指定必須** **デフォルト**: 30 s **範囲**: 0-120 秒 シグナリング経路を DataChannel に切り替えた際の SCTP プロトコルのハートビート間隔を指定してください。 ```ini dcsctp_heartbeat_interval = 30 s ``` ## dcsctp_slow_start_tcp_style > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: false シグナリング経路を DataChannel に切り替えた際の SCTP プロトコルの TCP スタイルスロースタートを指定してください。 ```ini dcsctp_slow_start_tcp_style = false ``` ## api_port **デフォルト**: 3000 API に使用するポート番号を指定してください。 ```ini api_port = 3000 ``` ## api_loopback_address_only **デフォルト**: false API へのアクセスをループバックアドレスからのみに制限します。可能な限り有効にしてください。 ```ini api_loopback_address_only = true ``` ## api_cors_origin **デフォルト**: 指定なし API の戻りのヘッダーに CORS (Cross-Origin Resource Sharing) を含める際のドメインを指定してください。 http から始めて、パスの / は含まないでください。 ```ini api_cors_origin = http://127.0.0.1:5000 ``` ## turn **デフォルト**: true > **注意** > > この機能を false にする場合は事前にサポートまでご連絡ください ### 使用しない場合の設定 ```ini turn = false ``` ## turn_realm **デフォルト**: "sora-turn.example.com" TURN 機能で使用するレルムを指定します。 文字列であれば何でも良いのですが、会社のドメインなどを指定することをおすすめします。 ```ini turn_realm = sora-turn.example.com ``` ## turn_fqdn **デフォルト**: なし TURN 機能の URL で使用する FQDN (最後の . なし) を指定してください。 指定した場合は TURN-UDP, TURN-TCP, TURN-TLS に共通で採用されます。 TURN-TLS の FQDN は `turn_tls_fqdn` 設定で上書きできます。 ### TURN 利用ドメイン名が sora-turn.example.com の場合 ```ini turn_fqdn = sora-turn.example.com ``` ## turn_tls_fqdn TURN 機能で TURN-TLS の URL で使用する FQDN (最後の . なし) を指定してください。 指定しない場合は `turn_fqdn` の値が採用されます。 どちらも設定されていない場合 TURN-TLS を利用することはできません。 ### ドメイン名が sora.example.com の場合 ```ini turn_tls_fqdn = sora-turn.example.com ``` ## turn_tcp **デフォルト**: true TURN 機能で TURN-TCP を使用するかどうかを指定します。使用しない場合は false を指定してください。 ### 使用しない場合の設定 ```ini turn_tcp = false ``` ## turn_tcp_allocate_success_delay_time **デフォルト**: 100 ms **範囲**: 0-1 s TURN 機能で TURN-TCP 時の Allocate-Success を返す時間を遅らせます。 ```ini turn_tcp_allocate_success_delay_time = 100 ms ``` ## turn_tcp_listen_port **デフォルト**: 3478 TURN 機能で TURN-TCP を有効にした際に使用するポート番号を指定してください。デフォルトでは 3478 番ポートが使用されます。 ```ini turn_tcp_listen_port = 3478 ``` ## turn_tcp_port **デフォルト**: turn_tcp_listen_port の値を利用 TURN 機能で TURN-TCP URL 払い出し時のポート番号を指定してください。デフォルトでは turn_tcp_listen_port の値が利用されます。 ```ini turn_tcp_port = 3478 ``` ## turn_tcp_only **デフォルト**: false > **危険** > > この機能はあくまで検証時のみ有効にしてください TURN-TCP を強制的に利用するようになります。この機能を有効にした場合 warning ログが出力されます。 ### 検証する場合 ```ini turn_tcp_only = true ``` ## turn_tls **デフォルト**: false TURN 機能で TURN-TLS の URL 払い出し機能を使用するかどうかを指定します。使用しない場合は false を指定してください。 ```ini turn_tls = true ``` ## turn_tls_port **デフォルト**: 5349 TURN 機能で TURN-TLS の URL 払い出し機能を有効にした際に使用するポート番号を指定してください。デフォルトでは 5349 番ポートが使用されます。 ```ini turn_tls_port = 443 ``` ## turn_tls_only **デフォルト**: false > **危険** > > この機能はあくまで検証時のみ有効にしてください TURN-TLS を強制的に利用するようになります。この機能を有効にした場合 warning ログが出力されます。 ### 検証する場合 ```ini turn_tls_only = true ``` ## rtx > **注意** > > この設定を無効にする場合は事前にサポートまでご連絡ください **デフォルト**: true RTX を有効にするかどうかを指定します。デフォルトでは true で有効になっています。 現時点では Chrome / Safari / Edge / Firefox が使用可能です。 iOS / Android / Unity は libwebrtc の最新版を利用している場合は対応しています。 ```ini rtx = false ``` ## ulpfec > **注意** > > この設定を有効にする場合は事前にサポートまでご連絡ください **デフォルト**: false ULPFEC を有効にするかどうかを指定します。デフォルトでは無効になっています。 現時点では Chrome と Safari が使用可能で、 Firefox は対応しておりません。 iOS/Android は libwebrtc を使用した場合は対応しています。 ```ini ulpfec = false ``` ## audio_red > **注意** > > この設定を有効にする場合は事前にサポートまでご連絡ください **デフォルト**: false 音声冗長化を有効にするかどうかを指定します。デフォルトでは無効になっています。 現時点では Chrome M95 以降で使用可能です。非対応ブラウザが混在していても利用可能です。 ```ini audio_red = true ``` ## generic_nack > **注意** > > この設定を無効にする場合は事前にサポートまでご連絡ください **デフォルト**: true Generic NACK を有効にするかどうかを指定します。一つのチャネルに対して、 視聴者がかなり多い場合などはこの設定を無効にすることで、サーバー側の負荷を抑えることができるようになります。 ```ini generic_nack = true ``` ## default_audio_bit_rate **設定しないことをおすすめします** **単位**: k(キロ)bps **範囲**: 6-510 **デフォルト**: 指定なし 音声が使用できるビットレートを指定します。デフォルトの場合はブラウザ側の判断に依存します。 ```ini default_audio_bit_rate = 32 ``` ## default_video_bit_rate **デフォルト**: 500 **単位**: k(キロ)bps **範囲**: 1-50000 映像が使用できるビットレートを指定します。デフォルトでは 500kbps です。この値を少なく指定すると解像度が不安定になります。 基本は 500 で余裕があるのであれば 800 などに設定することをお勧めします。 15000 より大きい値はまだ十分に検証ができていないため、現時点ではサポート外となります。ご了承ください。 ```ini default_video_bit_rate = 500 ``` ## default_simulcast_rid **デフォルト**: r0 サイマルキャスト利用時に視聴する rid を指定しない場合に採用される rid を指定してください。 指定可能な値は `r0` または `r1` または `r2` のどれかになります。 ```ini default_simulcast_rid = r0 ``` ## default_forwarding_pli_interval > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **単位指定必須** **デフォルト**: 10 s **範囲**: 1-90 秒 RTP 転送 API 利用時にクライアントに対して PLI を送る間隔を指定します。 ```ini default_forwarding_pli_interval = 10 s ``` ## forwarding_simulcast > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **単位指定必須** **デフォルト**: single サイマルキャスト転送時のストリームを指定します。 - `single` は最も優先度の低いストリームのみを転送します - `all` はすべてのストリームを転送します ```ini forwarding_simulcast = all ``` ## audio_streaming_url **デフォルト**: 指定なし 音声ストリーミングゲートウェイの URL を指定してください。 音声ストリーミングゲートウェイは HTTP/2 over HTTPS に対応している必要があります。 ```ini audio_streaming_url = https://example.com/speech ``` ## default_audio_streaming_result_push **デフォルト**: true 音声ストリーミングゲートウェイからのレスポンスをシグナリングプッシュ通知で送ることをデフォルトで行うかを指定してください。 ```ini default_audio_streaming_result_push = true ``` ## default_audio_streaming_language_code **デフォルト**: 指定なし 音声ストリーミングゲートウェイ接続時に HTTP ヘッダー `sora-audio-steraming-language-code` にデフォルトで含める文字列を指定してください。 この設定がない場合、接続時に `audio_streaming_language_code` で文字列が指定されていない場合、 音声ストリーミングが有効になっても Sora は接続の音声ストリーミングを開始しません。 ```ini default_audio_streaming_language_code = ja-JP ``` ## audio_streaming_tls_fullchain_file > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: 指定なし 音声ストリーミングゲートウェイとの通信に HTTPS で mTLS を利用するための設定で、 中間証明書を含むクライアント証明書を PEM 形式で設定して下さい。 ```ini audio_streaming_tls_fullchain_file = /path/to/fullchain.pem ``` ## audio_streaming_tls_privkey_file > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: 指定なし 音声ストリーミングゲートウェイとの通信に HTTPS で mTLS を利用するための設定で、 クライアント証明書の秘密鍵を PEM 形式で設定して下さい。 > **重要** > > 秘密鍵にはパスフレーズが設定されている場合エラーとなります ```ini audio_streaming_tls_privkey_file = /path/to/privkey.pem ``` ## audio_streaming_tls_verify_cacert_file > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: 指定なし 音声ストリーミングゲートウェイとの通信に HTTPS を利用した際、サーバー証明書のチェックを行う CA ファイルを PEM 形式で設定して下さい。 ```ini audio_streaming_tls_verify_cacert_file = /path/to/server_cacert.pem ``` > **重要** > > この設定をしないと Sora はサーバー証明書チェックを行いません。 ## hide_origin_username **デフォルト**: false 有効にした場合は SDP の Offer 時に送られる o= の username の部分を `shiguredo...SORA-` から `_` に変更します。 ```ini hide_origin_username = false ``` ## connection_created_wait_timeout **単位指定必須** **デフォルト**: 30 s **範囲**: 1-600 秒 WebRTC SFU と WebRTC の接続が確立するまでの許容時間を指定してください。 基本的に WebRTC SFU との接続確立は数百ミリ秒で終わります。 ただし iOS などでカメラの使用などを許可するといった設定が入る場合を考慮しデフォルトは 30 秒としています。 ```ini connection_created_wait_timeout = 30 s ``` ## default_spotlight_focus_rid **デフォルト**: r1 **指定可能 rid**: none / r0 / r1 / r2 スポットライト機能利用時に、フォーカスした際に利用する rid を指定してください。 none は映像自体を配信しません。 ```ini default_spotlight_focus_rid = r1 ``` ## default_spotlight_unfocus_rid **デフォルト**: r0 **範囲**: none, r0, r1, r2 スポットライト機能利用時に、フォーカスなしで利用する rid を指定してください。 none は映像自体を配信しません。 ```ini default_spotlight_unfocus_rid = none ``` ## default_spotlight_unfocus_audio **デフォルト**: true スポットライト機能利用時に、フォーカスなしでの音声配信を指定してください。 ```ini default_spotlight_unfocus_audio = false ``` ## default_spotlight_unfocus_audio_rate_limit **デフォルト**: 2 **範囲**: 0-5 スポットライト機能利用時に、フォーカスなしの音声転送の上限レートを指定してください。 単位は 1 音声ストリーム = 50 packets / s となります。 ```ini default_spotlight_unfocus_audio_rate_limit = 2 ``` ## default_spotlight_delayed_focus **デフォルト**: true スポットライト利用時に、遅延フォーカスの有無を指定してください。 遅延フォーカスは音声が有効になってもすぐにフォーカスせず、一定時間音声が有効な際に初めてフォーカスする仕組みです。 ```ini default_spotlight_delayed_focus = true ``` ## default_spotlight_delayed_focus_interval **デフォルト**: 2000 ms **範囲**: 1-60000 ms スポットライト利用時に、遅延フォーカスが有効な際に、どの程度遅延をさせるか指定してください。 ```ini default_spotlight_delayed_focus_interval = 2000 ms ``` ## default_spotlight_auto_unfocus **デフォルト**: true スポットライト利用時の自動アンフォーカスの有無を指定します。 ```ini default_spotlight_auto_unfocus = true ``` ## default_spotlight_auto_unfocus_interval **デフォルト**: 10 s **範囲**: 1 ms 以上 30 s 以下 スポットライト機能の自動アンフォーカスの時間間隔を指定します。 ```ini default_spotlight_auto_unfocus_interval = 10 s ``` ## default_spotlight_focus_min_interval **デフォルト**: 2000 ms **範囲**: 0 ms 以上 60 s 以下 スポットライト機能でフォーカスしてからアンフォーカスされるまでの最低時間間隔を指定します。 ```ini default_spotlight_focus_min_interval = 2000 ms ``` ## default_spotlight_number **デフォルト**: 1 **範囲**: 1-8 スポットライトで同時にフォーカスされるデフォルトの数を指定します。 ```ini default_spotlight_number = 2 ``` ## simulcast_encodings_file **デフォルト**: なし サイマルキャスで利用するエンコーディングパラメータのカスタマイズを JSON 形式のファイルにて指定します。 詳細は [映像のエンコーディングパラメータのカスタマイズ](SIMULCAST.html#03a03b) をご確認ください。 ```ini simulcast_encodings_file = etc/simulcast_encodings.json ``` ## spotlight_encodings_file **デフォルト**: なし スポットライトで利用するエンコーディングパラメータのカスタマイズを JSON 形式のファイルにて指定します。 詳細は [スポットライト利用時の映像のエンコーディングパラメータのカスタマイズ](SPOTLIGHT.html#65404b) をご確認ください。 ```ini spotlight_encodings_file = etc/spotlight_encodings.json ``` ## multistream_auto_sharing_video_bit_rate **デフォルト**: true マルチストリームで配信者が利用する映像ビットレートを自動で共有する機能です。 映像のビットレートに 1000kbps を指定した場合 4 人の配信者がいる場合はそれぞれの配信者のビットレートは 250kbps になります。 ```ini multistream_auto_sharing_video_bit_rate = true ``` ## user_agent_stats **デフォルト**: true SDK やクライアント側の統計情報を取得しサーバー側で最新の情報を保持します。 SDK やクライアント側が type: stats に対応している必要があります。 ```ini user_agent_stats = true ``` ## ice_connection_state_disconnected_timeout > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: 5 s ICE コネクションステートが `connecting` から `disconnected` の状態に移行するまでの時間を指定します。 ```ini ice_connection_state_disconnected_timeout = 5 s ``` ## ice_connection_state_failed_timeout > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: 10 s ICE コネクションステートが `disconnected` から `failed` の状態に移行するまでの時間を指定します。 ```ini ice_connection_state_failed_timeout = 10 s ``` ## skip_redact_sensitive_data **デフォルト**: false ログファイル中のセンシティブなデータを **"REDACTED"** という文字列に書き換えて出力する処理をスキップします。 ```ini skip_redact_sensitive_data = true ``` センシティブなデータを書き換える対象は以下のとおりです。 - `auth_webhook.log` の `event_metadata` を **"REDACTED"** に書き換えます - `session_webhook.log` の `session_metadata` と `event_metadata` を **"REDACTED"** に書き換えます - `event_webhook.log` の `event_metadata` を **"REDACTED"** に書き換えます ## default_h264_profile_level_id **デフォルト**: 42e01f H.264 で利用するプロファイルレベル ID を文字列で指定します。 ```ini default_h264_profile_level_id = 42e01f ``` ## e2ee > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: false クライアントによる E2EE の利用を許可します。 ```ini e2ee = true ``` ## stats_collector_url > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: 指定なし 統計コレクターの URL を指定します。 http を指定した場合は HTTP/2 (h2c) で送られます。 https の場合は HTTP/2 (h2) で送られます。 統計コレクターは HTTP/2 に対応している必要があります。 ```ini stats_exporter_url = http://192.0.2.10/collector ``` ## stats_exporter_number > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: 5 統計エクスポーターの数を指定します。同時接続数が多くなった場合増やすことを検討してください。 ```ini stats_exporter_number = 10 ``` ## stats_exporter_tls_fullchain_file > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: 指定なし 統計コレクターサーバーとの通信に HTTPS で mTLS を利用するための設定で、 中間証明書を含むクライアント証明書を PEM 形式で設定して下さい。 ```ini stats_exporter_tls_fullchain_file = /path/to/fullchain.pem ``` ## stats_exporter_tls_privkey_file > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: 指定なし 統計コレクターサーバーとの通信に HTTPS で mTLS を利用するための設定で、 クライアント証明書の秘密鍵を PEM 形式で設定して下さい。 > **重要** > > 秘密鍵にはパスフレーズが設定されている場合エラーとなります ```ini stats_exporter_tls_privkey_file = /path/to/privkey.pem ``` ## stats_exporter_tls_verify_cacert_file > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: 指定なし 統計コレクターサーバーとの通信に HTTPS を利用した際、サーバー証明書のチェックを行う CA ファイルを PEM 形式で設定して下さい。 ```ini stats_exporter_tls_verify_cacert_file = /path/to/server_cacert.pem ``` > **重要** > > この設定をしないと Sora はサーバー証明書チェックを行いません。 ## node_name **デフォルト**: 指定なし クラスター機能で利用するノード名を指定します。 ノード名の @ の前には、正規表現 `[0-9A-Za-z_\\-]+` にマッチする文字列を指定してください。 また @ の後ろには、サーバーのドメイン名(FQDN)や、IP アドレスを指定してください。 ```ini node_name = sora@192.0.2.10 ``` ## cluster **デフォルト**: true クラスター機能を利用するかどうかを指定します。 ```ini cluster = true ``` ## external_signaling_url **デフォルト**: 指定なし ノードに対するシグナリング URL を指定します。クラスター機能のリダイレクト時に用います。 ```ini external_signaling_url = ws://127.0.0.1:5000/signaling ``` ## external_api_url **デフォルト**: 指定なし ノードに対する Sora API の URL を指定します。クラスター機能のリダイレクト時に用います。 ```ini external_api_url = http://127.0.0.1:3000/ ``` ## contact_node_name_list **デフォルト**: 指定なし クラスターが有効な時、起動時に自動で JoinCluster を試行するノード名のリストを指定します。 カンマ区切りで指定してください。 > **注釈** > > 自分自身のノード名を含めても問題ありません。 ```ini node_name = sora@192.0.2.10 contact_node_name_list = sora@192.0.2.10, sora11@192.0.2.11, sora12@192.0.2.12 ``` ## cluster_auto_reconnect **デフォルト**: true クラスターが有効な際、ネットワーク障害やノード障害の発生時に自動で再接続を試みるかどうかを指定します。 ```ini cluster_auto_reconnect = true ``` ## cluster_listen_min_port > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: 49010 `sora.conf` にクラスター利用時のノード間通信に使用するポート番号範囲の最小値を指定します。 ```ini cluster_listen_min_port = 49010 ``` ## cluster_listen_max_port > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: 49020 `sora.conf` にクラスター利用時のノード間通信に使用するポート番号範囲の最大値を指定します。 ```ini cluster_listen_max_port = 49020 ``` ## data_dir > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: data Sora 内部で利用する情報を書き出すディレクトリを指定してください。可能な限り **絶対パス** で指定してください。 ```ini data_dir = /path/to/data ``` ## av1 **デフォルト**: true AV1 が利用可能になります。 ```ini av1 = true ``` ## h265 **デフォルト**: false > **危険** > > この機能はあくまで検証時のみ有効にしてください H.265 が利用可能になります。 ```ini h265 = true ``` ## lyra **デフォルト**: false 一部の SDK にて [Lyra](https://github.com/google/lyra) が利用可能になります。 ```ini lyra = true ``` ## legacy_log_format **デフォルト**: true > **危険** > > この設定は 2023 年 6 月リリースの Sora にてデフォルトが false に変更されます > **危険** > > この設定は 2023 年 12 月リリースの Sora にて廃止されます sora ログや internal ログの出力をレガシーフォーマットで出力するかどうかを指定してください。 `false` にすることで JSONL フォーマットで出力されます。 ```ini legacy_log_format = false ``` ## legacy_log_extension **デフォルト**: true > **危険** > > この設定は 2023 年 6 月リリースの Sora にてデフォルトが false に変更されます > **危険** > > この設定は 2023 年 12 月リリースの Sora にて廃止されます JSONL 形式のログの拡張子を `.log` で出力するかどうかを指定してください。 `false` にすることで `.jsonl` 拡張子で出力されます。 対象は以下のとおりです。 - sora ログ - internal ログ - session_webhook ログ - session_webhook_error ログ - event_webhook ログ - event_webhook_error ログ - connection ログ - signaling ログ - api ログ - auth_webhook ログ ```ini legacy_log_extension = false ``` ## default_multistream **デフォルト**: true > **危険** > > この設定は 2023 年 6 月リリースの Sora にて廃止されます マルチストリームをデフォルトにするかどうかを指定してください。 ```ini default_multistream = true ``` ## legacy_webhook_audio_video_json_structure **デフォルト**: true > **危険** > > この設定は 2023 年 6 月リリースの Sora にてデフォルトが false に変更されます > **危険** > > この設定は 2023 年 12 月リリースの Sora にて廃止されます ウェブフックや録画メタデータファイルの `audio` と `video` 項目にレガシーな入れ子構造を利用するかどうかを指定してください。 ```ini legacy_webhook_audio_video_json_structure = false ``` ## rtp_hdrext_video_orientation > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: false RTP ヘッダー拡張 `urn:3gpp:video-orientation` を利用するかどうかを指定します。 ## rtp_hdrext_video_content_type > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: false RTP ヘッダー拡張 `http://www.webrtc.org/experiments/rtp-hdrext/video-content-type` を利用するかどうかを指定します。 ## rtp_hdrext_video_timing > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: false RTP ヘッダー拡張 `http://www.webrtc.org/experiments/rtp-hdrext/video-timing` を利用するかどうかを指定します。 ## rtp_hdrext_playout_delay > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: false RTP ヘッダー拡張 `http://www.webrtc.org/experiments/rtp-hdrext/playout-delay` を利用するかどうかを指定します。 ## rtp_hdrext_color_space > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: false RTP ヘッダー拡張 `http://www.webrtc.org/experiments/rtp-hdrext/color-space` を利用するかどうかを指定します。 ## rtp_hdrext_sdes_mid > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: false RTP ヘッダー拡張 `urn:ietf:params:rtp-hdrext:sdes:mid` を利用するかどうかを指定します。 ## rtp_packet_loss_simulator_incoming > **危険** > > この機能はあくまで検証時のみ有効にしてください **デフォルト**: 0 **範囲**: 0-100 Sora が受信する RTP パケットを指定したパーセント分ドロップさせます。 値を 0 より大きくした場合、クライアントが接続するたびに warning が発生します。 ### Sora が受信する RTP パケットを 10 % パケロスさせる場合 ```ini rtp_packet_loss_simulator_incoming = 10 ``` ## rtp_packet_loss_simulator_outgoing > **危険** > > この機能はあくまで検証時のみ有効にしてください **デフォルト**: 0 **範囲**: 0-100 Sora が送信する RTP パケットを指定したパーセント分ドロップさせます。 値を 0 より大きくした場合、クライアントが接続するたびに warning が発生します。 ### Sora が送信する RTP パケットを 10 % パケロスさせる場合 ```ini rtp_packet_loss_simulator_outgoing = 10 ``` ## data_channel_packet_loss_simulator_incoming > **危険** > > この機能はあくまで検証時のみ有効にしてください **デフォルト**: 0 **範囲**: 0-100 Sora が受信する DataChannel パケットを指定したパーセント分ドロップさせます。 値を 0 より大きくした場合、クライアントが接続するたびに warning が発生します。 ### Sora が受信する DataChannel パケットを 10 % パケロスさせる場合 ```ini data_channel_packet_loss_simulator_incoming = 10 ``` ## data_channel_packet_loss_simulator_outgoing > **危険** > > この機能はあくまで検証時のみ有効にしてください **デフォルト**: 0 **範囲**: 0-100 Sora が送信する DataChannel パケットを指定したパーセント分ドロップさせます。 値を 0 より大きくした場合、クライアントが接続するたびに warning が発生します。 ### Sora が送信する DataChannel パケットを 10 % パケロスさせる場合 ```ini data_channel_packet_loss_simulator_outgoing = 10 ``` ## opus_param_channels > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: 2 **範囲**: 1-8 ## opus_param_maxplaybackrate > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: 48000 **範囲**: 8000-48000 ## opus_param_stereo > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: true ## opus_param_sprop_stereo > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: true ## opus_param_ptime > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: 20 **範囲**: 3-120 ## opus_param_minptime > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: 10 **範囲**: 3-120 ## opus_param_useinbandfec > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: true ## opus_param_usedtx > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: false # systemd `bin/sora foreground` はデーモン化せずに Sora を起動するコマンドです。 ## 設定 ### ユニットファイル `/etc/systemd/system/` に `sora.service` のユニットファイルを作成します。 ユニットファイルの例: ``` [Unit] Description=WebRTC SFU Sora Service After=network.target [Service] Environment="HOME=/home/shiguredo" ExecStart=/home/shiguredo/sora/bin/sora foreground Type=simple Restart=always RestartSec=60s User=shiguredo KillMode=process [Install] WantedBy=multi-user.target ``` `[Service]` セクションの `Environment`、 `User` はそれぞれ、実際に Sora サービスを開始するユーザーの `$HOME`、 `$USER` に置き換えてください。 また、 `ExecStart` は Sora のインストール先による実行コマンドのパスに置き換えてください。 ### Sora サービスの有効化と開始 sora.service の有効化: ``` $ sudo systemctl enable sora.service ``` sora.service の開始: ``` $ sudo systemctl start sora.service ``` ### Sora サービスの停止 sora.service の停止: ``` $ sudo systemctl stop sora.service ``` # Linux カーネルチューニング Sora は UDP に対して大きな負荷がかかるシステムです。そのためカーネルをチューニングする必要があります。 ## 確認方法 netstat コマンドで Errors が出ていた場合はバッファが足りない可能性が高いです。 ``` $ netstat -su ``` ## Ubuntu 22.04 または Ubuntu 20.04 ### sysctl sysctl にて、以下の値を設定することを推奨します。 このあたりの値はサーバースペックによりますので、こちらは推奨値となります。 ``` sysctl -w net.core.rmem_default=33554432 sysctl -w net.core.rmem_max=33554432 sysctl -w net.core.wmem_default=33554432 sysctl -w net.core.wmem_max=33554432 sysctl -w net.core.somaxconn=65535 sysctl -w net.core.optmem_max=25165824 sysctl -w net.core.netdev_max_backlog=65536 sysctl -w net.ipv4.tcp_mem='786432 1048576 26777216' sysctl -w net.ipv4.tcp_rmem='8192 87380 33554432' sysctl -w net.ipv4.tcp_wmem='8192 65536 33554432' sysctl -w net.ipv4.udp_mem='65536 131072 262144' sysctl -w net.ipv4.udp_rmem_min=16384 sysctl -w net.ipv4.udp_wmem_min=16384 ``` # IPv6 での動作について ## 概要 Sora は IPv6 での動作に対応しています。ただし、ブラウザ側が非対応な場合があります。 特に、IPv6 での TURN 機能にクライアントが対応していない場合は接続できないことがあります。 ## お問い合わせの際の情報について IPv6 環境は様々な組み合わせがあるため、問題を解析するには多くの情報が必要になります。 お問い合わせの際は以下の情報をお送りください。 - クライアント側の IPv6 の有無について - Sora 側の IPv6 の設定の有無について - Sora が動作しているサーバーの A または AAAA レコードの有無について - クライアントが IPv4 または IPv6 または IPv4 と IPv6 どの環境かについて 他にも何か気づいた点などがありましたらそちらも合わせてお問い合わせください。 # メタデータ ## 概要 Sora では様々なメタデータを扱っているため、それぞれのメタデータの説明をしています。 ## 認証ウェブフック成功時のメタデータ払い出し 認証ウェブフック成功時に `metadata` を払い出すことができます。 この値は Sora が `"type": "offer"` をクライアントへ送る際に `metadata` として送られます。 ```json { "allowed": true, "metadata": {"spam": "egg"} } ``` ```json { "type": "offer", "sdp": "...", "metadata": {"spam": "egg"} } ``` この値は Sora とクライアントだけで共有される値です。他のクライアントには一切共有されません。 ## 認証ウェブフック成功時のイベントメタデータ払い出し 認証ウェブフック成功時に `event_metadata` を払い出すことができます。 この値は Sora がイベントウェブフックリクエストを送信する際に `event_metadata` として含まれます。 ```json { "allowed": true, "event_metadata": {"spam": "egg"} } ``` ```json { "type": "connection.created", "event_metadata": {"spam": "egg"} } ``` この値は Sora と認証ウェブフックとイベントウェブフック先のサーバーとのみで共有されます。 クライアントには通知されません。 ## 接続時のシグナリング通知メタデータ指定 シグナリング接続時の `"type": "connect"` で `signaling_notify_metadata` が指定できます。 ここで指定した値は同じチャネルに参加しているクライアントと新しく参加するクライアントに通知されます。 ```json { "type": "connect", "signaling_notify_metadata": {"spam": "egg"} } ``` ```json { "type": "connection.created", "authn_metadata": {"spam": "egg"} "metadata": {"spam": "egg"} } ``` この通知はシグナリング通知メタデータ拡張が無効になっているときの通知です。 有効になっている場合は以下のように `authn_metadata` のみに値が含まれます。 ```json { "type": "connection.created", "authn_metadata": {"spam": "egg"} "metadata": {} } ``` ## 認証ウェブフック成功時のシグナリング通知メタデータ払い出し 認証ウェブフック成功時に `signaling_notify_metadata` を払い出すことができます。 この値は同じチャネルに参加しているクライアントと新しく参加するクライアントに通知されます。 ```json { "allowed": true, "signaling_notify_metadata": {"spam": "egg"} } ``` ```json { "type": "connection.created", "authz_metadata": {"spam": "egg"} "metadata": {"spam": "egg"} } ``` この通知はシグナリング通知メタデータ拡張が無効になっているときの通知です。 有効になっている場合は以下のように `authz_metadata` のみに値が含まれます。 ```json { "type": "connection.created", "authz_metadata": {"spam": "egg"} "metadata": {} } ``` ## シグナリング通知メタデータ拡張 [シグナリング通知メタデータ拡張](SIGNALING_NOTIFY_METADATA_EXT.html) を利用すると接続毎に状態を持つことが可能になります。 本来、シグナリング通知メタデータは接続時か認証成功払い出し時にしか指定できず一度指定したら変更できません。 シグナリング通知メタデータ拡張を利用した場合は HTTP API を利用して途中でメタデータの値を変更することができます。 この機能を有効にするとシグナリング時の通知メタデータに指定した値は `metadata` に含まれなくなります。 ## セッション生成時のセッションメタデータ払い出し セッション生成時に送信される [session.created ウェブフック](SESSION_WEBHOOK.html#3cec61) の戻り値に指定することで `session_metadata` を払い出すことができます。 この値はこのセッションが終了した時に [session.destoryed ウェブフック](SESSION_WEBHOOK.html#4e36be) に送信されます。 ```json { "session_metadata": "" } ``` ## 一括録画ファイルメタデータ archive-.json 録画機能で一括録画を指定した際に `archive//` 以下に生成されるファイルです。 かならず `archive-.webm` ファイルとペアになります。 ## 分割録画ファイルメタデータ split-archive-_.json 録画機能で分割録画を指定した際に `archive//` 以下に生成されるファイルです。 かならず `split-archive-_.webm` ファイルとペアになります。 ## StartRecodirng API で指定するメタデータ [StartRecording](API.html#c5b527) API では `metadata` を指定することができます。 この値は、録画終了時に [recording.report](EVENT_WEBHOOK.html#920a02) に送信されます。 また、 `report-.json` ファイルにも記録されます。 # センシティブデータ > **警告** > > センシティブデータは実験的機能のため、正式版では仕様が変更される可能性があります ## 概要 Sora ではログに出力されるセンシティブデータを **"REDACTED"** という文字列に書き換えます。 ## 対象ログと項目 Sora のログは以下の内容のセンシティブデータを **"REDACTED"** に書き換えて出力します。 - `auth_webhook.log` の `event_metadata` を **"REDACTED"** に書き換えて出力します。 - `session_webhook.log` の `session_metadata` と `event_metadata` を **"REDACTED"** に書き換えて出力します。 - `event_webhook.log` の `event_metadata` を **"REDACTED"** に書き換えて出力します。 ### event_webhook_error ログ > **重要** > > `event_webhook_error.log` の `event_metadata` については "REDACTED" の書き換えは行いません ### session_webhook_error ログ > **重要** > > `session_webhook_error.log` の `session_metadata` と `event_metadata` については "REDACTED" の書き換えは行いません ## 書き換えをスキップする > **重要** > > この書き換えを無効にすることは推奨していません。 センシティブなデータを利用している場合は、 **"REDACTED"** への書き換えをスキップする設定を提供しています。 `sora.conf` の [skip_redact_sensitive_data](SORA_CONF.html#00d209) を `true` にすることでセンシティブなデータの **"REDACTED"** への書き換えをスキップします。 # ウェブフックの audio と video 項目の JSON 構造のフラット化 ## 概要 WebRTC API の仕様に参考にしてきた `audio` と `video` の入れ子である JSON 構造を廃止し、フラット化した構造を採用します。 > **重要** > > この設定はウェブフックのみでシグナリング接続時の audio/video の構造は変更しません。 > 今後は変更するかもしれませんが、クライアント側を破壊的変更することになるため、 > もし変更する場合でもかなり時間をかけて変更していきます。 ## 理由 一つの項目に複数の型が存在する仕様は取り扱いがややこしくなると判断したためです。 ## 設定 `sora.conf` にて [legacy_webhook_audio_video_json_structure](SORA_CONF.html#3be597) を `false` にすることで、ウェブフックの audio と video の JSON 構造がフラット化します。 この設定は 2023 年 6 月リリース予定の Sora にてデフォルトを `false` にし、2023 年 12 月リリース予定の Sora にて廃止します。 詳細は [sora.conf の legacy_webhook_audio_video_json_structure の廃止](DEPRECATED.html#a7613b) をご確認ください。 ## ウェブフックリクエスト audio / video ### audio - `{"audio": false}` は変わりません - `{"audio": {"codec_type": "OPUS"}}` は `{"audio": true, "audio_codec_type": "OPUS"}` へフラット化します - `{"audio": {"bit_rate": 32}}` は `{"audio": true, "audio_bit_rate": 32}` へフラット化します ### video - `{"video": false}` は変わりません - `{"video": {"codec_type": "VP8"}}` は `{"video": true, "video_codec_type": "VP8"}` へフラット化します - `{"video": {"bit_rate": 500}}` は `{"video": true, "video_bit_rate": 500}` へフラット化します ## 認証ウェブフック成功時 audio / video 認証ウェブフック成功時の戻り値に指定する `audio` と `video` の指定もフラット化する必要があります。 ### audio - `{"audio": false}` は変わりません - `{"audio": {"codec_type": "OPUS"}}` は `{"audio": true, "audio_codec_type": "OPUS"}` へフラット化して指定する必要があります - `{"audio": {"bit_rate": 32}}` は `{"audio": true, "audio_bit_rate": 32}` へフラット化して指定する必要があります - `{"audio": true, "audio_codec_type": "OPUS", "audio_opus_params": {"useinbandfec": true}}` のように `audio_opus_params` が指定可能になりました - `{"audio": true, "audio_codec_type": "LYRA", "audio_lyra_params": {"version": "1.3.0"}}` のように `audio_lyra_params` が指定可能になりました ### video - `{"video": false}` は変わりません - `{"video": {"codec_type": "VP8"}}` は `{"video": true, "video_codec_type": "VP8"}` へフラット化して指定する必要があります - `{"video": {"bit_rate": 500}}` は `{"video": true, "video_bit_rate": 500}` へフラット化して指定する必要があります ## 録画メタデータファイル audio / video 録画メタデータファイルも [legacy_webhook_audio_video_json_structure](SORA_CONF.html#3be597) を `true` にすることで、フラット化します。 フラット化の内容はウェブフック audio / video と同様です。 - `{"video": {"height": 1024}}` は `{"video": true, "video_height": 1024}` へフラット化します - `{"video": {"width": 1024}}` は `{"video": true, "video_width": 1024}` へフラット化します # WebSocket 経由のシグナリング ## 概要 > **重要** > > Sora の SDK を利用する場合は、ここに書かれているシグナリングの細かい仕様を把握する必要は基本的にありません。 Sora のシグナリングにはデフォルトでは WebSocket を使用します。 ## 用語 ### channel_id 接続のグルーピングに利用する ID です。接続時に任意の文字列、最大 255 バイトまでを自由に指定可能です。 ### client_id 接続時やサーバー認証成功時に任意の文字列を最大 255 バイトまで指定できる値です。 指定しない場合はコネクション ID が入ります。自由に指定可能です。重複が可能な ID です。 ### bundle_id `bundle_id` を指定した場合、マルチストリーム利用時に `bundle_id` が等しい接続からの音声や映像、メッセージング、シグナリング通知を受信しなくなります。 接続時やサーバー認証成功時に任意の文字列を最大 255 バイトまで指定できる値です。指定しない場合はコネクション ID が入ります。 シグナリングでのバンドル ID の指定はデフォルトでは無効になっているため、有効にする場合には `sora.conf` にて `signaling_bundle_id` を `true` にする必要があります。 ### connection_id 接続ごとのユニークな値です。UUIDv4 で生成した値を Base32 でエンコードした値で、Sora が払い出します。指定はできません。 **connection_id の例** : "FW0CJSHETX0RXAGX8WWEXNBQN8" ## 仕組み Sora のシグナリングは、Sora からクライアントへ Offer (SDP) を送ります。 シグナリングの処理の流れは、[認証ウェブフックなし](SIGNALING.html#cea9ce) のシーケンス図を参照してください。 シグナリングの型の正確な仕様は [シグナリングの型定義](SIGNALING_TYPE.html) を参照してください。 ### URL デフォルトの設定では、シグナリングは `0.0.0.0:5000` でリッスンするため、 シグナリング URL は `http://<サーバーのアドレス>:5000/signaling` となります。 **パス部分は /signaling 固定で変更できません** 。 ### DataChannel 経由への切り替え > **注意** > > 実験的機能として、シグナリングを WebSocket 経由から DataChannel 経由へ変更する機能を提供中です 詳細は [DataChannel 経由のシグナリング](DATA_CHANNEL_SIGNALING.html) をご確認ください。 ## 注意 シグナリングが完了しても WebSocket の接続は切断しないでください。WebSocket の接続が切れると Sora は WebRTC 接続を終了します。 ## 設定 ### signaling_loopback_address_only `sora.conf` にて [signaling_loopback_address_only](SORA_CONF.html#e22105) を `true` にすることで、 ループバックアドレスからのみアクセスできるようにします。 nginx などを前段に利用している場合は可能な限り有効にしてください。 ## シグナリングのタイプ Sora のシグナリングは、タイプごとの JSON でクライアントとメッセージをやりとりします。 ### "type": "connect" クライアントは Sora に接続の意思を伝える JSON を送ります。以下は最小の JSON です。 ```json { "type": "connect", "role": "sendonly", "channel_id": "Spam" } ``` #### role そのクライアントの役割を指定します。この設定は必須です。 `role` には `sendrecv` / `sendonly` / `recvonly` のどれかを指定してください。 - sendrecv- マルチストリーム、スポットライトで利用できます。送信及び受信を行います - sendonly- すべてで利用できます。送信のみを行い、受信を行いません - recvonly- すべてで利用できます。受信のみを行い、送信を行いません #### channel_id `channel_id` は 1-255 バイトまでの文字列であればどのような文字列でも指定可能です。 #### 視聴メディアの選択 **この項目はオプションです** 視聴者は配信者からの映像と音声、または、映像や音声のどちらかだけを受け取る指定が可能です。 視聴者が映像を受信せずに、音声のみを受信する場合は video に false を指定します。 ```json { "type": "connect", "role": "recvonly", "channel_id": "Spam", "video": false } ``` 音声を受信せずに、映像だけを受信する場合は audio に false を指定してください。 ```json { "type": "connect", "role": "recvonly", "channel_id": "Spam", "audio": false } ``` > **重要** > > Chrome 使用時に配信者が音声だけを配信している場合、視聴者が音声と映像を選択すると正常に配信されません。 これは Chrome の仕様によるものです。 音声のみを配信する場合は、視聴者も音声のみを選択することでこの問題は回避できます。 #### オーディオコーデック指定 **この項目はオプションです** 配信者や視聴者はオーディオコーデックを指定することができます。 この設定はオプションです。 この設定が指定されない場合は、 `OPUS` がデフォルトで設定されます。 > **重要** > > Lyra は一部の Sora SDK では利用できません。 - Opus- "OPUS" - Lyra- "LYRA" ```json { "type": "connect", "role": "sendonly", "channel_id": "Spam", "audio": { "codec_type":"OPUS" } } ``` #### オーディオビットレート指定 **この項目はオプションです** > **重要** > > オーディオビットレートは指定しないことをおすすめします。指定しないことで最適なビットレートが採用されます。 配信者はオーディオビットレートの最大値を指定することができます。 このビットレート指定は Opus にのみ有効で、 Lyra には適用されません。 Lyra の場合は `lyra_params` の `bitrate` を指定してください。 - bit_rate- 6-510 ```json { "type": "connect", "role": "sendonly", "channel_id": "Spam", "audio": { "codec_type": "OPUS", "bit_rate": 64 } } ``` 指定できる値は 6 から 510 です。32 を指定した場合は、32kbps がビットレートの最大値です。 指定しない場合は `sora.conf` の `default_audio_bit_rate` に指定した値が採用されます。 `default_audio_bit_rate` も指定していない場合、ビットレートはクライアント側に依存します。 #### オーディオの Opus 設定指定 > **注意** > > この機能は実験的機能です。この機能を利用される場合は必ず事前にサポートまでご連絡ください 配信者は Opus の設定を指定することができます。 - channels- 1-8 - maxplaybackrate- 8000-48000 - stereo- boolean - sprop_stereo- boolean - minptime- integer 3-120 - useinbandfec- boolean - usedtx- boolean - **この機能を有効にした場合は録画がおかしくなります** ```json { "type": "connect", "role": "sendonly", "channel_id": "Spam", "audio": { "codec_type": "OPUS", "opus_params": { "stereo": false, "useinbandfec": false } } } ``` #### オーディオの Lyra 設定指定 > **注意** > > この機能は実験的機能です。この機能を利用される場合は必ず事前にサポートまでご連絡ください **この項目は Lyra を使う場合必須です** - version- string - 1.2.0 や 1.3.0 といった Lyra のバージョンを指定します - bitrate- integer 3200 or 6000 or 9200 ```json { "type": "connect", "role": "sendonly", "channel_id": "Spam", "audio": { "codec_type": "LYRA", "lyra_params": { "version": "1.3.0", "bitrate": 6000 } } } ``` #### ビデオコーデック指定 **この項目はオプションです** 配信者や視聴者はビデオコーデックを指定することができます。 この設定はオプションです。 この設定が指定されない場合は、VP9 がデフォルトで設定されます。 - VP8- `"VP8"` - VP9- "`VP9"` - Safari では実験的機能を有効にすることで利用可能です - AV1- `"AV1"` - Chrome M96 以降で利用可能です - H.264- `"H264"` - H.265- `"H265"` - Safari では実験的機能を有効にすることで利用可能です ```json { "type": "connect", "role": "sendonly", "channel_id": "Spam", "video": { "codec_type":"VP9" } } ``` #### ビデオビットレート指定 **この項目はオプションです** 配信者はビデオビットレートの最大値を指定することができます。単位は **kbps** です。 - bit_rate- 1-50000 ```json { "type": "connect", "role": "sendonly", "channel_id": "Spam", "video": { "codec_type": "VP9", "bit_rate": 500 } } ``` 指定できる値は 1 から 50000 です。500 を指定した場合は、500 kbps がビットレートの最大値です。 10 Mbps を最大値としたい場合は 10000 を指定してください。ただし 15 Mbps より大きい値は現時点ではサポート外となります。 指定しない場合は `sora.conf` の `default_video_bit_rate` に指定した値が採用されます。 #### 認証メタデータ **この項目はオプションです** 認証するための判断材料としてメタデータを使用することができます。 認証メタデータは必須ではありません。 ```json { "type": "connect", "role": "sendonly", "channel_id": "Spam", "metadata": "1234abcd" } ``` 認証メタデータは、そのまま認証サーバーに送られます。詳細は [認証ウェブフック](AUTH_WEBHOOK.html) をご確認ください。 #### client_id の指定 **この項目はオプションです** > **重要** > > `client_id` の値は重複することが可能です。 1-255 バイトまでの文字列であれば、どのような文字列でも指定可能です。 ```json { "type": "connect", "role": "sendonly", "channel_id": "Spam", "client_id": "egg-ham" } ``` #### bundle_id の指定 **この項目はオプションです** > **重要** > > `bundle_id` の値は重複することが可能です。 1-255 バイトまでの文字列であれば、どのような文字列でも指定可能です。 マルチストリーム利用時に `bundle_id` が同じ接続からの音声や映像、メッセージングを受信しなくなります。 ```json { "type": "connect", "role": "sendonly", "channel_id": "Spam", "bundle_id": "spam_egg" } ``` #### マルチストリーム **この項目はオプションです** 他のクライアントのストリームを複数受信することができる仕組みです。デフォルトで有効です。 もしマルチストリームを使わない場合は明示的に `"multistream": false` を指定してください。 ```json { "type": "connect", "role": "sendrecv", "channel_id": "spam", "multistream": false } ``` 詳細は [マルチストリーム機能](MULTISTREAM.html) をご確認ください。 #### サイマルキャスト **この項目はオプションです** 自分が配信する映像のストリームを複数本にすることで、 受信側にどのストリームを受信するかを選択させることが可能になります。 サイマルキャストを有効にする場合には `"multistream": true` も明示的に指定する必要があります。 ```json { "type": "connect", "role": "sendrecv", "channel_id": "spam", "multistream": true, "simulcast": true } ``` 詳細は [サイマルキャスト機能](SIMULCAST.html) をご確認ください。 #### スポットライト **この項目はオプションです** 話をした人にフォーカスを当てて、フォーカスが当たっている人は高画質な映像と音声で配信、 フォーカスが当たっていない人は低画質な映像で配信するという、クライアントの負荷を下げる仕組みです。 ```json { "type": "connect", "role": "sendrecv", "channel_id": "spam", "multistream": true, "simulcast": true, "spotlight": true } ``` 詳細は [スポットライト機能](SPOTLIGHT.html) をご確認ください。 #### sdp **この項目はオプションです** Sora SDK や Sora クライアントで生成した offer SDP を Sora のログに記録します。 この項目は、ログの記録にのみ利用します。 ```json { "type": "connect", "role": "sendrecv", "channel_id": "spam", "sdp": "..." } ``` #### sora_client **この項目はオプションです** Sora SDK や Sora クライアントの情報を文字列で送ることができます。 これはログに記録されたり、認証ウェブフックリクエストで送信されたりします。 ```json { "type": "connect", "role": "sendrecv", "channel_id": "sora", "sora_client": "Sora JavaScript SDK 2021.1.0" } ``` #### environment **この項目はオプションです** Sora SDK や Sora クライアントの利用環境を文字列で送ることができます。 これはログに記録されたり、認証ウェブフックリクエストで送信されたりします。 Sora JavaScript SDK では userAgent の情報が入ります。 ```json { "type": "connect", "role": "sendrecv", "channel_id": "sora", "environment": "Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/93.0.4522.0 Safari\/537.36" } ``` #### libwebrtc **この項目はオプションです** Sora SDK や Sora クライアントの libwebrtc のバージョンを文字列で送ることができます。 これはログに記録されたり、認証ウェブフックリクエストで送信されたりします。 ```json { "type": "connect", "role": "sendrecv", "channel_id": "sora", "libwebrtc": "Shiguredo-Build M90.4430@{#3} (90.4430.3.1 dee77cf2)" } ``` ### "type": "offer" 認証ウェブフックが認証成功を返すと、Sora は以下のような JSON をクライアントに送ります。 SDK を利用している場合は、この仕様を意識する必要はありません。 ```json { "type": "offer", "sdp": "", "connection_id": "ECF3W1RGMD02DETH30CDZTHNRW", "client_id": "ECF3W1RGMD02DETH30CDZTHNRW", "bundle_id": "ECF3W1RGMD02DETH30CDZTHNRW", "multistream": true, "simulcast": false, "spotlight": false, "version": "2021.1", "metadata": "1234abcd", "config": { "iceServers": [ { "credential": "ClDTPB4DjgFLrclpSBxjTiXg7K8kYsGf", "urls": [ "turn:192.0.2.1:443?transport=tcp" ], "username": "sYL5WdMt" } ], "iceTransportPolicy": "relay" }, "mid": { "audio": "audio_aDScYe", "video": "video_i2sNRq" }, "data_channels": [ { "compress": true, "label": "stats" }, { "compress": false, "label": "e2ee" }, { "compress": true, "label": "push" }, { "compress": true, "label": "notify" }, { "compress": true, "label": "signaling" } ] } ``` - connection_id- UUIDv4 を Base32 でエンコードしたユニークな ID が入ります - client_id- クライアントや認証サーバーが指定した値、または、Sora が生成した connection_id が入ります - bundle_id- クライアントや認証サーバーが指定した値、または、Sora が生成した connection_id が入ります - config- RTCPeerConnection に渡す設定が入ります - 主に TURN の情報です - mid- audio と video の MediaStream Id が入ります - version- Sora のバージョンが入ります - metadata- これはオプションです - 認証サーバーから払い出された metadata が入ります - data_channels- これは DataChannel 経由のシグナリングを有効にしている場合にのみ利用されます - 詳細は [DataChannel への切り替え要否の判断](DATA_CHANNEL_SIGNALING.html#1abf7f) をご確認ください ### "type": "answer" クライアントは offer を受け取りしだい、answer 用の SDP を生成します。 ```json { "type": "answer", "sdp": "" } ``` その後、必要があればクライアントは取得した candidate を送ります。 ```json { "type": "candidate", "candidate": "candidate:3179889176 1 tcp 1518214911 192.168.1.10 0 typ host tcptype active generation 0" } ``` ### "type": "disconnect" クライアントからこのメッセージを送ると、Sora は WebSocket を切断します。また、WebRTC 側も終了します。 クライアントから切断する際には、このメッセージを送るようにしてください。 ```json { "type": "disconnect" } ``` オプションとして reason を指定することも可能です。この値は `connection.destoryed` の `type_disconnect_reason` として含まれます。 ```json { "type": "disconnect", "reason": "NO-ERROR" } ``` ### "type": "ping" サーバーからクライアント側に定期的に送られる通知です。この値をクライアントが受け取った場合は、すぐに以下の JSON を Sora に送信してください。 ```json { "type": "pong" } ``` `"type": "ping"` を送ってから 60 秒の間に一度も `"type": "pong"` が返ってこない場合、 Sora は正常な通信が行えていないと判断して、Sora からシグナリングの接続を切断します。 #### stats > **注意** > > この機能は WebSocket 経由でのシグナリングの時のみ有効です `sora.conf` にて `user_agent_stats` を `true` にしている場合は、 `"type": "ping"` 時に `"stats": true` が送られてきます。 ```json { "type": "ping", "stats": true } ``` この値を受け取った場合は、WebRTC の統計情報を取得して `"type": "pong"` 送信時に `stats` をキーにして値を含んで応答してください。 ```json { "type": "pong", "stats": [{"type": "..."}, {"type": "..."}] } ``` ### "type": "notify" サーバーからクライアントに対して、参加しているチャネルの情報が通知されるようになります。 詳細は [シグナリング通知機能](SIGNALING_NOTIFY.html) をご確認ください。 ## シグナリングエラー 切断時の reason を利用してハンドリングすることが可能です。 - Sora のシグナリング失敗時には必ず WebSocket が切断されます。 - どのようなエラーでも、ステータスコードは固定で 4490 が返ってきます。 - reason にはエラーメッセージが入ります ``` "DUPLICATED-CHANNEL-ID" ``` * - reason - 解説 * - FAILURE-JSON-DECODE - 不正な JSON 形式のメッセージの場合のエラー * - DUPLICATED-CHANNEL-ID - 同一の channel_id をすでに使用中の場合のエラー * - AUTHENTICATION-FAILURE - 認証に失敗した場合のエラー * - AUTHENTICATION-INTERNAL-ERROR - 認証サーバーが意図しないレスポンスを返してきた場合のエラー * - UNKNOWN-CODEC-TYPE - 不正な codec_type を指定した場合のエラー * - UNMATCH-VIDEO-CODEC-TYPE - Plan B でのマルチストリーム、またはスポットライト機能で映像のコーデックが他の参加者と異なる値の場合のエラー * - UNMATCH-AUDIO-CODEC-TYPE - スポットライト機能で音声のコーデックが他の参加者と異なる値の場合のエラー * - INVALID-SPOTLIGHT-COUNT - スポットライト機能の配信数が 1 から 8 の範囲外、または他の参加者と異なる値の場合のエラー * - FAILURE-SDP-PARSE - 不正な SDP の場合のエラー * - UNEXPECTED-SIGNALING-TYPE - シグナリングのフローとして許されない type を受信した場合のエラー * - INVALID-SIGNALING-TYPE - type の値が不正である場合のエラー * - CONNECT-WAIT-TIMEOUT - Open したあと一定時間以内に "type": "connect" のメッセージを送信しなかった場合のエラー * - MISSING-ICE-SDP - SDP に ICE 情報が含まれていなかった場合のエラー * - FAILURE-SDP-PARSE - answer や update、 candidate の SDP のパースに失敗したエラー * - MISSING-TYPE - type: が JSON に含まれていなかった場合のエラー * - INVALID-JSON - JSON 形式が間違っていた場合のエラー * - PONG-TIMEOUT-ERROR - Ping の応答が返ってこなかった場合のエラー * - CONNECT-WAIT-TIMEOUT-ERROR - シグナリング開始後 5 秒以内に "type": "connect" を送ってこなかった場合のエラー * - CONNECTION-CREATED-WAIT-TIMEOUT-ERROR - シグナリング開始してから指定した時間シグナリングが成功しなかった場合のエラー * - NO-MEDIA - 音声も映像も有効にせずに "type": "connect" を送ってきた場合のエラー * - EXCEED-MAX-CONNECTIONS - ライセンスの接続数を超えた接続が来た場合のエラー * - CLIENT-ERROR - クライアントが想定外の動作をした場合のエラー * - BAD-FINGERPRINT - 証明書検証が失敗した場合のエラー * - ANSWER-TIMEOUT-ERROR - 30 秒以内に "type": "answer" を返さなかった場合のエラー * - TOO-MANY-CANDIDATE - 多くの "type": "candidate" が送られてきた場合のエラー * - NO-ACCEPTABLE-NODE - クラスターのどのノードも受け入れられない場合のエラー * - INVALID-SIGNALING-PARAMS - セッションが残っている状態かつ、接続数が 0 ではない際にシグナリング項目が一致しない接続がきた場合のエラー * - INITIAL - モードが ``initial`` のノードに、接続がきた場合のエラー * - BLOCK-NEW-CONNECTION - モードが ``block_new_connection`` のノードに、接続がきた場合のエラー * - BLOCK-NEW-SESSION - ノードのモードが ``block_new_session`` かつ、そのノードが担当していないセッションに対しての接続がきた場合のエラー * - SIGNALING-INTERNAL-ERROR - シグナリング内部エラー * - TRANSPORT-INTERNAL-ERROR - 通信内部エラー * - ROUTER-INTERNAL-ERROR - 通信内部エラー * - INTERNAL-ERROR - 内部エラー ### AUTHENTICATION-FAILURE このエラーはクライアントに通知されることはなく、ログにしか出力されません。 ### CONNECTION-CREATED-WAIT-TIMEOUT-ERROR シグナリングを実行してから Sora と WebRTC の接続が成功するまでの許容時間を超えた場合に出力されるエラーです。 この許容時間はデフォルトでは 30 秒に設定されており、この値は `sora.conf` の設定で変更が可能です。 ```ini // これは 10 秒待っても、シグナリングが成功しない場合は接続を切断する設定です connection_created_wait_timeout = 10 s ``` このログが sora.log に出力された場合は、 `log/connection_created_wait_timeout_error/` 以下に詳細なログが出力されます。 ## シーケンス図 ### 認証ウェブフックなし seqdiag { default_fontsize = 15; edge_length = 250; クライアント ->> Sora [label = '"type": "connect"']; クライアント <<- Sora [label = '"type": "offer"']; クライアント ->> Sora [label = '"type": "answer"', noactivate]; クライアント ->> Sora [label = '"type": "candidate"', noactivate]; === WebRTC 確立 === Sora -> アプリケーションサーバー [label = 'イベントウェブフック\n"type": "connection.created"']; Sora <-- アプリケーションサーバー [label = '200 OK']; === クライアント切断 === クライアント ->> Sora [label = '"type": "disconnect"', noactivate]; Sora -> アプリケーションサーバー [label = 'イベントウェブフック\n"type": "connection.destroyed"']; Sora <-- アプリケーションサーバー [label = '200 OK']; クライアント <<- Sora [label = 'WebSocket Close']; } ### 認証ウェブフックあり seqdiag { default_fontsize = 14; edge_length = 200; クライアント ->> Sora [label = '"type": "connect"']; Sora -> アプリケーションサーバー [label = '認証ウェブフック']; Sora <-- アプリケーションサーバー [label = '200 OK\n{"allowed": true}']; クライアント <<- Sora [label = '"type": "offer"']; クライアント ->> Sora [label = '"type": "answer"', noactivate]; クライアント ->> Sora [label = '"type": "candidate"', noactivate]; === WebRTC 確立 === Sora -> アプリケーションサーバー [label = 'イベントウェブフック\n"type": "connection.created"']; Sora <-- アプリケーションサーバー [label = '200 OK']; === クライアント切断 === クライアント ->> Sora [label = '"type": "disconnect"', noactivate]; Sora -> アプリケーションサーバー [label = 'イベントウェブフック\n"type": "connection.destroyed"']; Sora <-- アプリケーションサーバー [label = '200 OK']; クライアント <<- Sora [label = 'WebSocket Close']; } # DataChannel 経由のシグナリング > **警告** > > DataChannel 経由のシグナリングは実験的機能のため、正式版では仕様が変更される可能性があります ## 概要 DataChannel は WebRTC の機能の一つでデータの送受信を行える機能です。 Sora では WebRTC 接続確立後に、シグナリングを WebSocket 経由から DataChannel 経由に切り替えることが可能です。 ## 目的 WebSocket は TCP ベースのため Head of Line Blocking が存在し、不安定な回線などでパケットが詰まってしまうことがあります。 DataChannel は WebSocket とは異なり、パケットを並列でやりとりすることができるため、不安定な回線などでもパケットが詰まることが少なくなります。 シグナリングを WebSocket 経由から DataChannel 経由へ切り替える機能を提供することでより安定した接続が維持できます。 ## SDK 対応状況 - 最新版の JavaScript SDK- 対応済みです - 最新版の iOS SDK- 対応済みです - 最新版の Android SDK- 対応済みです - 最新版の Unity SDK- 対応済みです - 最新版の C++ SDK- 対応済みです - 最新版の Flutter SDK- 対応済みです ## 注意 DataChannel 経由のシグナリングを有効にした場合、ラベルが違うメッセージは並列に処理されます。 そのため、ラベルをまたいだメッセージ間の順序は保証されなくなります。 例えば、WebSocket 経由のシグナリングではマルチストリーム時の SDP 再交換である `"type": "re-offer"` によって上がる `ontrack` は、 参加通知 `"type": "notify", "event_type": "connection.created"` より先に発火することが多くなります。 DataChannel 経由のシグナリングでは `ontrack` と `"type": "notify", "event_type": "connection.created"` 順序は不定となります。 不明点がある場合はサポートまでお問い合わせください。 ## 制限 - Sora の DataChannel 機能では、クライアント側から DataChannel を作成することはできません。- Sora 側で用意した DataChannel の Label のみを利用できます - Sora の DataChannel 機能では、クライアント側からデータを送信する際には特定の条件を満たす必要があります。 ### 推奨メッセージサイズ DataChannel で利用している SCTP というプロトコルはもともと小さなメッセージを送るために設計されたため、大きなメッセージを送るのには向いていません。そのため 1 メッセージサイズは最大でも 64 kbyte 以内に収まるようにしてください。 64 kbyte 以上のメッセージを送る場合は、大きくても 64 kbyte 以下のメッセージなるように分割して送るようにしてください。 ### SDP メッセージサイズ制限 DataChannel は送受信できるメッセージサイズがブラウザごとに制限されているため、 マルチストリーム利用時の SDP が最大メッセージサイズを超えた場合、挙動がおかしくなる場合があります。 現時点で 1 チャネルで多くのユーザーでマルチストリームを利用する場合は DataChannel 経由でのシグナリングは利用しないようにしてください。 今後 SDP を再利用する仕組みを導入することでこの問題を解決していく予定です。 ## シグナリング切り替え DTLS が確立したタイミングで、シグナリングでのやりとりを WebSocket 経由から DataChannel 経由に切り替える仕組みです。 > **重要** > > 切り替えが完了した場合でも、Sora 側からは WebSocket を切断しません。 シグナリングの切り替えを含めた DataChannel 経由のシグナリングの処理の流れは、[DataChannel シグナリング](DATA_CHANNEL_SIGNALING.html#5626ed) のシーケンス図をご確認ください。 ### シグナリングの切り替えを有効にする シグナリングの切り替えを有効にするには、次の 3 つの方法があります。 - `"type": "connect"` 時に `data_channel_signaling` を `true` にする - 認証成功時に `data_channel_signaling` を `true` で払い出す - `sora.conf` の [default_data_channel_signaling](SORA_CONF.html#adceef) を `true` にする Sora SDK を利用している限りは、これらの設定のみで、シグナリングの WebSocket 経由から DataChannel 経由への切り替えを利用できます。 ### "type": "switched" DataChannel へ完全に切り替わるタイミングで、 Sora は `"type": "switched"` を WebSocket 経由でクライアントへ送ります。 DataChannel に切り替わる前に WebSocket が閉じた場合、Sora はその接続が無効と判断して、接続を終了します。 ### DataChannel へ切り替わった後("type": "switched" 後)の WebSocket での "type": "ping" / "type": "pong" について WebSocket から DataChannel に切り替わると、 WebSocket の `"type": "ping"` を送る間隔が 5 秒から 30 秒に引き延ばされます。 さらに Sora が `"type": "pong"` を期待しなくなります。 ## WebSocket が閉じたことを無視する Sora は、デフォルトでは接続の切断判定に WebSocket を利用しています。WebSocket が閉じると、Sora は接続が切断したと判断します。 ただし、WebSocket が閉じた場合でも、接続が切断したと判断しないようにしたい場面もあるため、`ignore_disconnect_websocket` という設定を用意しています。 この設定は `sora.conf` 、 `"type": "connect"` または認証成功時の払い出しで指定できます。 この設定を `true` にすることで、Sora は WebSocket が閉じてもその接続が切断したとは判断せずに、 WebRTC のやりとりを継続します。 > **注意** > > `"type": "disconnect"` を送らずに終了した場合、 DataChannel が切断に気付くまでには早くても 10 秒はかかります。 ### クライアント側の切断タイミング もし、 `ignore_disconnect_websocket` を `true` にして WebSocket を切断したい場合は、必ず Sora から `"type": "switched"` を受け取った後にしてください。 `ignore_disconnect_websocket` が `true` の場合でも、 `"type": "switched"` を受け取る前に WebSocket を切断すると、 Sora はその接続が無効と判断して接続を終了します。 ## DataChannel への切り替え要否の判断 `"type": "offer"` に `"data_channels"` が含まれることを確認することで、DataChannel への切り替えが必要と判断することが可能です。 切り替えが不要な場合は `"data_channels"` は送られてきません。 ```javascript { "type": "offer", "data_channels": [ { "compress": true, "label": "stats" }, { "compress": false, "label": "e2ee" }, { "compress": true, "label": "push" }, { "compress": true, "label": "notify" }, { "compress": true, "label": "signaling" } ] } ``` ## label 単位の圧縮 Sora は、DataChannel 経由のメッセージを `zlib/deflate` で圧縮した送受信を要求する場合があります。 メッセージの圧縮や展開は Label ごとに要求します。 メッセージの圧縮や展開を要求する Label の情報は、 `"type": "offer"` 時に `data_channels` で `compress` を `true` に指定してクライアントに送ります。 - Sora は圧縮時に zlib ヘッダーを付けて送ってきます - Sora は展開時に zlib ヘッダーを必要とします - Sora は圧縮レベルは `default` を利用します ### 圧縮されるデフォルト Label - signaling - notify - push - stats ### 圧縮されない Label - e2ee ## 設定 ### deafult_data_channel_signaling シグナリングを WebSocket から DataChannel 経由に切り替えるかどうかの設定です。 デフォルトは `false` です。 ### default_ignore_disconnect_websocket シグナリングを DataChannel 経由に切り替えた際に、 WebSocket が閉じても、接続が切断したとみなさない設定です。 デフォルトは `false` です。 ## label とシグナリングのタイプ 各 label とシグナリングのタイプについては、[DataChannel シグナリング](DATA_CHANNEL_SIGNALING.html#5626ed) の図も下記の説明と合わせてご確認ください。 ### "label": "signaling" **順番**: あり **信頼性**: あり **圧縮**: あり WebRTC が確立する前の type: connect/offer/answer/candiate については、DataChannel 経由のシグナリングでは利用できません。 `"type": "re-offer"` は `"label": "signaling"` に送られてきます。 `"type": "re-answer"` 、 `"type": "disconnect"` は `"label": "signaling"` に送ります。 `"type": "ping"` と `"type": "pong"` は DataChannel では利用しません。 #### "type": "re-offer" > **重要** > > "type": "update" の代わりに Sora からは "type": "re-offer" が送られてきます。 マルチストリーム利用時に SDP 再交換を行う際に、 Sora から送られてきます。 #### "type": "re-answer" > **重要** > > "type": "update" の代わりに Sora へ "type": "re-answer" を送ります。 マルチストリーム利用時に SDP 再交換を行う際に、 Sora へ送ります。 #### "type": "disconnect" 接続を切断することを通知するために Sora へ送ります。 ### "label": "notify" **順番**: あり **信頼性**: あり **圧縮**: あり `"type": "notify"` は `"label": "notify"` に送られてきます。 中身は WebSocket 経由の値と変わりません。 ### "label": "push" **順番**: あり **信頼性**: あり **圧縮**: あり `"type": "push"` は `"label": "push"` に送られてきます。 中身は WebSocket 経由の値と変わりません。 ### "label": "e2ee" **順番**: あり **信頼性**: あり **圧縮**: なし - WebSocket シグナリングのクライアントやサーバーが送るバイナリメッセージと同様です ### "label": "stats" **順番**: あり **信頼性**: あり **圧縮**: あり **DataChannel から新しく追加されたタイプです** 今まで `"type": "ping"` と `"type": "pong"` 内部でやりとりしていた `stats` は DataChannel 経由では独立しました。 Sora から `{"type": "req-stats"}` が送られてきたら、 `{"type": "stats", "reports": [{"id": "...", ...}, ...]}` で `reports` の中に、WebSocket 経由時には `"type": "pong"` で入れていた統計情報を入れて送り返してください。 #### "type": "req-stats" Sora からクライアントに stats 情報を要求します。 #### "type": "stats" クライアントから Sora に stats 情報を送ります。 ## DataChannel 関連の設定 ### data_channel_stats_timer_interval シグナリングを DataChannel 経由に切り替えた際に、 Sora からクライアントへ統計情報の要求を送る間隔の設定です。 デフォルトは `5 s` です。 ### dcsctp_heartbeat_interval シグナリングを DataChannel 経由に切り替えた際に、 SCTP プロトコルのハートビートを送る間隔の設定です。 デフォルトは `30 s` です。 ## シーケンス図 ### 認証ウェブフックなし seqdiag { default_fontsize = 15; edge_length = 300; クライアント ->> Sora [label = '"type": "connect"']; クライアント <<- Sora [label = '"type": "offer"']; クライアント ->> Sora [label = '"type": "answer"', noactivate]; クライアント ->> Sora [label = '"type": "candidate"', noactivate]; === WebRTC 確立 === Sora -> アプリケーションサーバー [label = 'イベントウェブフック\n"type": "connection.created"']; Sora <-- アプリケーションサーバー [label = '200 OK']; === DataChannel 確立 === クライアント <- Sora [label = '"type": "switched"']; === これ以降は DataChannel が利用される === } ### DataChannel シグナリング seqdiag { default_fontsize = 15; edge_length = 350; === WebRTC 確立 === === DataChannel 確立 === クライアント <<- Sora [label = '"type": "switched"']; === これ以降は DataChannel が利用される === クライアント <<- Sora [label = '"type": "re-offer"', rightnote = 'label: signaling']; クライアント ->> Sora [label = '"type": "re-answer"', leftnote = 'label: signaling']; クライアント <<- Sora [label = '"type": "notify"', rightnote = 'label: notify', noactivate]; クライアント <<- Sora [label = '"type": "push"', rightnote = 'label: push', noactivate]; クライアント <<- Sora [label = '"type": "req-stats"', rightnote = 'label: stats'] クライアント ->> Sora [label = '"type": "stats"', leftnote = 'label: stats']; } # シグナリングの型定義 この章ではシグナリングの型について説明します。 シグナリングの仕様については [シグナリング](SIGNALING.html) を参照ください。 型の表記は TypeScript で記述します。 ## 基本的なデータ型 ```typescript // JSON 値を表します。 // 仕様は RFC 8259 に従います。 type JSONValue = | null | boolean | number | string | JSONValue[] | { [key: string]: JSONValue | undefined } // ストリームの種別 type Role = 'sendrecv' | 'sendonly' | 'recvonly' // サイマルキャストで配信する映像の種類 type SimulcastRid = 'r0' | 'r1' | 'r2' // 音声の設定 type Audio = | boolean | { codec_type?: AudioCodecType bit_rate?: number lyra_params?: LyraParams opus_params?: OpusParams } type LyraParams = { version?: string bitrate?: number } type OpusParams = { channels?: number maxplaybackrate?: number minptime?: number ptime?: number stereo?: boolean sprop_stereo?: boolean useinbandfec?: boolean usedtx?: boolean } // 映像の設定 type Video = | boolean | { codec_type?: VideoCodecType bit_rate?: number } // 音声コーデックの種類 type AudioCodecType = 'OPUS' | 'LYRA' // 映像コーデックの種類 type VideoCodecType = 'VP9' | 'VP8' | 'AV1' | 'H264' | 'H265' // DataChannel の方向 type Direction = 'sendrecv' | 'sendonly' | 'recvonly' // DataChannels type DataChannel = { label: string direction: Direction ordered?: boolean max_packet_life_time?: number max_retransmits?: number protocol?: string compress?: boolean } // SoraClient type SoraClient = { environment?: string raw?: string type?: string version?: string commit_short?: string libwebrtc?: string } ``` ## シグナリング シグナリングは「クライアントからサーバー (Sora) に送信される」メッセージと「サーバー (Sora) からクライアントに送信される」メッセージに分かれます。 ### クライアントからサーバーに送信されるメッセージ - connect - answer - candidate - re-answer - pong- WebSocket 経路利用時のみ - disconnect - stats- DataChannel 経路利用時のみ ### Server からクライアントに送信されるメッセージ - offer - re-offer - ping- WebSocket 経路利用時のみ - push - notify - req-stats- DataChannel 経路利用時のみ ## 完全な型定義 ```typescript // シグナリング type Signaling = ClientToServer | ServerToClient // クライアントからサーバーに送信されるメッセージ type ClientToServer = | SignalingConnectMessage | SignalingAnswerMessage | SignalingCandidateMessage | SignalingReAnswerToServerMessage | SignalingPongMessage | SignalingDisconnectMessage // サーバーからクライアントに送信されるメッセージ type ServerToClient = | SignalingRedirectMessage | SignalingOfferMessage | SignalingReOfferToClientMessage | SignalingPingMessage | SignalingPushMessage | SignalingNotifyMessage | SignalingSwitchedMessage // type: "connect" type SignalingConnectMessage = { type: 'connect' role: Role channel_id: string client_id?: string bundle_id?: string metadata?: JSONValue signaling_notify_metadata?: JSONValue multistream?: boolean spotlight?: boolean spotlight_number?: number data_channel_signaling?: boolean ignore_disconnect_websocket?: boolean data_channels?: DataChannel[] simulcast?: boolean simulcast_rid?: SimulcastRid spotlight_focus_rid?: SimulcastRid | 'none' spotlight_unfocus_rid?: SimulcastRid | 'none' audio?: Audio video?: Video // type: redirect で戻されて再度 type: connect で接続するときに有効にする redirect?: boolean audio_streaming_language_code?: string e2ee?: boolean sdp?: string sora_client?: SoraClient environment?: string libwebrtc?: string } type Mid = { auido?: string video?: string } // type: "redirect" type SignalingRedirectMessage = { type: 'redirect' location: string } // type: "offer" type SignalingOfferMessage = { type: 'offer' sdp: string multistream: boolean simulcast: boolean spotlight: boolean client_id: string bundle_id: string connection_id: string metadata?: JSONValue config?: JSONValue encodings?: RTCRtpEncodingParameters[] mid?: Mid data_channels?: DataChannel[] } // type: "answer" type SignalingAnswerMessage = { type: 'answer' sdp: string } // type: "candidate" type SignalingCandidateMessage = { type: 'candidate' candidate: string } // type: "re-offer" // サーバーからクライアントに送信される type SignalingReOfferToClientMessage = { type: 're-offer' sdp: string } // type: "re-answer" // クライアントからサーバーに送信される type SignalingReAnswerToServerMessage = { type: 're-answer' sdp: string } // type: "ping" type SignalingPingMessage = { type: 'ping' stats?: boolean } // type: "pong" type SignalingPongMessage = { type: 'pong' stats?: RTCStatsReport[] } // type: "push" type SignalingPushMessage = { type: 'push' data: Record } // type: "notify" type SignalingNotifyMessage = | SignalingNotifyConnectionCreated | SignalingNotifyConnectionUpdated | SignalingNotifyConnectionDestroyed | SignalingNotifySpotlightFocused | SignalingNotifySpotlightUnfocused | SignalingNotifyRecordingStarted | SignalingNotifyRecordingStopped | SignalingNotifyNetworkStatus // 接続中のクライアントの情報 type SignalingNotifyMetadata = { client_id?: string bundle_id?: string connection_id?: string authn_metadata?: JSONValue authz_metadata?: JSONValue metadata?: JSONValue } // "connection.created", type SignalingNotifyConnectionCreated = { type: 'notify' event_type: 'connection.created' role: Role session_id?: string client_id?: string bundle_id?: string connection_id?: string audio?: boolean video?: boolean authn_metadata?: JSONValue authz_metadata?: JSONValue metadata?: JSONValue data?: SignalingNotifyMetadata[] minutes: number channel_connections: number channel_sendrecv_connections: number channel_sendonly_connections: number channel_recvonly_connections: number turn_transport_type: 'udp' | 'tcp' } // "connection.updated" type SignalingNotifyConnectionUpdated = { type: 'notify' event_type: 'connection.updated' role: Role session_id?: string client_id?: string bundle_id?: string connection_id?: string audio?: boolean video?: boolean authn_metadata?: JSONValue authz_metadata?: JSONValue metadata?: JSONValue minutes: number channel_connections: number channel_sendrecv_connections: number channel_sendonly_connections: number channel_recvonly_connections: number turn_transport_type: 'udp' | 'tcp' } // "connection.destroyed" type SignalingNotifyConnectionDestroyed = { type: 'notify' event_type: 'connection.destroyed' role: Role session_id?: string client_id?: string bundle_id?: string connection_id?: string audio?: boolean video?: boolean minutes: number authn_metadata?: JSONValue authz_metadata?: JSONValue metadata?: JSONValue channel_connections: number channel_sendrecv_connections: number channel_sendonly_connections: number channel_recvonly_connections: number turn_transport_type: 'udp' | 'tcp' } // "spotlight.focused" type SignalingNotifySpotlightFocused = { type: 'notify' event_type: 'spotlight.focused' client_id: string | null bundle_id: string | null connection_id: string audio: boolean video: boolean fixed: boolean } // "spotlight.unfocused" type SignalingNotifySpotlightUnfocused = { type: 'notify' event_type: 'spotlight.unfocused' client_id: string | null bundle_id: string | null connection_id: string audio: boolean video: boolean fixed: boolean } // "recording.started" type SignalingNotifyRecordingStarted = { type: 'notify' event_type: 'recording.started' client_id: string | null bundle_id: string | null connection_id: string } // "recording.stopped" type SignalingNotifyRecordingStopped = { type: 'notify' event_type: 'recording.stopped' client_id: string | null bundle_id: string | null connection_id: string } // "network.status" type SignalingNotifyNetworkStatus = { type: 'notify' event_type: 'network.status' unstable_level: 0 | 1 | 2 | 3 } // type: "disconnect" type SignalingDisconnectMessage = { type: 'disconnect' reason: string } // type: "stats" // サーバーからクライアントに送信される type DataChannelStatsToClientMessage = { type: 'stats' } // type: "stats" // クライアントからサーバーに送信される type DataChannelStatsToServerMessage = { type: 'stats' reports: RTCStatsReport[] } // type: "switched" type SignalingSwitchedMessage = { type: 'switched' ignore_disconnect_websocket: boolean } ``` # シグナリング通知 ## 概要 シグナリング通知は、Sora に接続情報をもたせることで、 クライアントの参加や離脱の情報をリアルタイムに通知する機能です。 ## シグナリング通知を利用することで実現可能なこと - 配信されているストリームに対してユーザー名を表示する - 新しくチャネルに参加したクライアントのユーザー名を通知する - 現在のネットワークの状態をクライアント画面に表示する - 離脱したユーザーの名前を表示する ## シグナリング通知の有効 / 無効について シグナリング通知はデフォルトで有効になっています。 シグナリング通知を無効にした場合はシグナリング通知が送られてこなくなります。 無効にするには、sora.conf でシグナリング通知の無効を指定するか、または、認証ウェブフックの戻り値で無効を指定する必要があります。 ### sora.conf での指定 sora.conf でシグナリング通知の有無を指定する方法です。 sora.conf で `signaling_notify = false` を指定することで、シグナリング通知が無効になります。 ただし、この値は認証ウェブフックの戻り値で上書きすることが可能です。 ### 認証ウェブフックの戻り値での指定 認証ウェブフックの戻り値を利用して、クライアントごとに signaling_notify の true / false を指定する方法です。 認証ウェブフックの戻り値に `{"signaling_notify": false}` を指定することで、そのクライアントに対して signaling_notify を無効にすることができます。 ```json { "allowed": true, "signaling_notify": false } ``` 認証ウェブフックの戻り値に signaling_notify の指定が無い場合は、sora.conf の signaling_notify の値が採用されます。 **表 1. sora.conf と認証ウェブフックの戻り値の signaling_notify の組み合わせによるクライアントの signaling_notify の採用値** * - sora.conf の signaling_notify - 認証ウェブフックの戻り値の signaling_notify - クライアントの signaling_notify の採用値 * - true - 指定なし - true * - true - false - false * - true - true - true * - false - 指定なし - false * - false - false - false * - false - true - true ## sora.conf によるシグナリング通知関連の設定 ### signaling_notify_client_id `sora.conf` で `signaling_notify_client_id = false` を指定することで、シグナリング通知時にクライアント ID を含まなくなります。 ### signaling_notify_bundle_id `sora.conf` で `signaling_notify_bundle_id = false` を指定することで、シグナリング通知時にバンドル ID を含まなくなります。 ### signaling_notify_connection_id `sora.conf` で `signaling_notify_connection_id = false` を指定することで、シグナリング通知時にコネクション ID を含まなくなります。 ### signaling_notify_media `sora.conf` で `signaling_notify_media = false` を指定することで、シグナリング通知時に音声や映像の情報を含まなくなります。 ### signaling_notify_metadata `signaling_notify_metadata` は、ユーザーが参加や離脱したときに送られるシグナリング通知に含まれるメタデータです。 シグナリング通知メタデータの詳細は [シグナリング通知メタデータ](SIGNALING_NOTIFY_METADATA.html) をご確認ください。 ### signaling_notify_metadata_ext `signaling_notify_metadata_ext` は、ユーザーが参加や離脱したときに送られるシグナリング通知に含まれるメタデータを、API 経由で自由に変更できるようにします。 シグナリング通知メタデータ拡張の詳細は [シグナリング通知メタデータ拡張機能](SIGNALING_NOTIFY_METADATA_EXT.html) をご確認ください。 ## クライアントに送信される JSON の仕様 - event_type- string - `connection.created` 、 `connection.updated` 、 `connection.destroyed` の 3 つの内のいずれかが入ります - `connection.created` と `connection.destroyed` は、全員に通知されます - `connection.updated` は、自身に通知されます - role- string - `sendrecv` / `sendonly` / `recvonly` が入ります - minutes- integer - その接続の接続経過時間 (分) が入ります - channel_connections- integer - そのチャネルの接続数が入ります - channel_sendonly_connections- integer - そのチャネルの sendonly 接続数が入ります - channel_recvonly_connections- integer - そのチャネルの recvonly 接続数が入ります - channel_sendrecv_connections- integer - そのチャネルの sendrecv 接続数が入ります - client_id- string - `connection.created` の場合は、参加してきたクライアントのクライアント ID が入ります - `connection.destroyed` の場合は、離脱したクライアントのクライアント ID が入ります - `connection.updated` の場合は、自身のクライアント ID が入ります - `sora.conf` で、 `signaling_notify_client_id` を `false` にすることで無効にすることが可能です - bundle_id- string - `connection.created` の場合は、参加してきたクライアントのバンドル ID が入ります - `connection.destroyed` の場合は、離脱したクライアントのバンドル ID が入ります - `connection.updated` の場合は、自身のバンドル ID が入ります - `sora.conf` で、 `signaling_notify_bundle_id` を `false` にすることで無効にすることが可能です - connection_id- string - `connection.created` の場合は、参加してきたクライアントのコネクション ID が入ります - `connection.destroyed` の場合は、離脱したクライアントのコネクション ID が入ります - `connection.updated` の場合は、自身のコネクション ID が入ります - `sora.conf` で、 `signaling_notify_connection_id` を `false` にすることで無効にすることが可能です - audio- boolean - `connection.created` の場合は、参加してきたクライアントの audio が有効かどうかが入ります - `connection.destroyed` の場合は、離脱したクライアントの audio が有効かどうかが入ります - `connection.updated` の場合は、自身の audio が有効かどうかが入ります - `sora.conf` で、 `signaling_notify_media` を `false` にすることで無効にすることが可能です - video- boolean - `connection.created` の場合は、参加してきたクライアントの video が有効かどうかが入ります - `connection.destroyed` の場合は、離脱したクライアントの video が有効かどうかが入ります - `connection.updated` の場合は、自身の video が有効かどうかが入ります - `sora.conf` で、 `signaling_notify_media` を `false` にすることで無効にすることが可能です - metadata- json - `sora.conf` で、 `signaling_notify_metadata` を `false` にすることで無効にすることが可能です - data- json 型のリスト- json 型の中身は、 `signaling_notify_client_id` や `signaling_notify_bundle_id` 、 `signaling_notify_connection_id` の設定により変化します - 設定値による json 型の中身は、下記の `表 2` をご確認ください - 新規でチャネルに接続した際に、すでにチャネルに参加している接続一覧の情報がはいります - `connection.created` の場合のみこの値が入ります - `sora.conf` で、 `signaling_notify_metadata` を `false` にすることで無効にすることが可能です **表 2. signaling_notify_client_id、 signaling_notify_bundle_id および signaling_notify_connection_id の設定値による json 型の中身** * - signaling_notify_client_id - signaling_notify_bundle_id - signaling_notify_connection_id - json 型の中身 * - true - true - true - ``{"client_id": string, "bundle_id": string, "connection_id": string, "metadata": json}`` * - false - true - true - ``{"bundle_id": string, "connection_id": string, "metadata": json}`` * - true - false - true - ``{"client_id": string, "connection_id": string, "metadata": json}`` * - true - true - false - ``{"client_id": string, "bundle_id": string, "metadata": json}`` * - true - false - false - ``{"client_id": string, "metadata": json}`` * - false - true - false - ``{"bundle_id": string, "metadata": json}`` * - false - false - true - ``{"connection_id": string, "metadata": json}`` * - false - false - false - ``{"metadata": json}`` ```json { "type": "notify", "event_type": "connection.created", "role": "recvonly", "minutes": 0, "channel_connections": 2, "channel_recvonly_connections": 1, "channel_sendonly_connections": 1, "channel_sendrecv_connections": 0, "client_id": "4DFFDF56RX3E3DPBCDSWPTCAV0", "bundle_id": "4DFFDF56RX3E3DPBCDSWPTCAV0", "connection_id": "4DFFDF56RX3E3DPBCDSWPTCAV0", "audio": true, "video": true, "metadata": { "diaplay_name": "小夜" }, "data": [ { "authz_metadata": { "diaplay_name": "時雨" }, "client_id": "4SW2CB0E1D01S23W3G6JFCEN98", "bundle_id": "4SW2CB0E1D01S23W3G6JFCEN98", "connection_id": "4SW2CB0E1D01S23W3G6JFCEN98", "metadata": { "diaplay_name": "時雨" } } ], "authz_metadata": { "diaplay_name": "小夜" }, "turn_transport_type": "udp" } ``` ### "event_type": "connection.created" この event_type は、参加しているチャネルに接続があった場合に、 `signaling_notify` を有効にしている自分を含む全員に通知されます。 この通知を利用することで、他のクライアントが接続してきたことをクライアント側で把握することができます。 新規接続クライアントと bundle_id が等しいクライアントに対しては、このイベントは通知されません。 また通知 JSON の data の中身からも bundle_id が等しいクライアントは除外されます。 ### "event_type": "connection.updated" この event_type は、クライアントごとに異なり、 1 分間隔で通知されます。 この通知を利用することで、現在クライアントの累計接続時間をクライアント側で把握することができます。 ### "event_type": "connection.destroyed" この event_type は、参加しているチャネルに切断があった場合に、 `signaling_notify` を有効にしている自分以外の全員に通知されます。 この通知を利用することで、他のクライアントが切断したことをクライアント側で把握することができます。 切断クライアントと bundle_id が等しいクライアントに対しては、このイベントは通知されません。 ## スポットライト機能のシグナリング通知 スポットライト機能を利用した場合のシグナリング通知は上記の `connection.*` とは別に `spotlight.*` が通知されます。 ### "event_type": "spotlight.focused" この event_type は、参加しているチャネルの配信がフォーカスされた場合に、 `signaling_notify` を有効にしている全員に通知されます。 この通知を利用することで、配信が切り替わったことをクライアントが気付くことができるようになります。 フォーカスされたクライアントと bundle_id が等しいクライアントに対しては、このイベントは通知されません。 ### "event_type": "spotlight.unfocused" この event_type は、参加しているチャネルの配信からフォーカスが外れた場合に、 `signaling_notify` を有効にしている全員に通知されます。 この通知を利用することで、配信が切り替わったことをクライアントが気付くことができるようになります。 フォーカスが外れたクライアントと bundle_id が等しいクライアントに対しては、このイベントは通知されません。 ### クライアントに送信される JSON の仕様 - event_type- string - `spotlight.focused` または `spotlight.unfocused` が入ります - channel_id- string - 現在利用しているチャネル ID が入ります - client_id- string - どのクライアントに配信が切り替わったかが入ります - bundle_id- string - 切り替わった配信のバンドル ID が入ります - connection_id- string - どの接続に配信が切り替わったかが入ります - spotlight_number- integer - 現在のスポットライト数が入ります - audio- boolean - 切り替わった配信の audio が有効かどうかが入ります - video- boolean - 切り替わった配信の video が有効かどうかが入ります - fixed- boolean - 切り替わった配信が固定されているかどうかが入ります ```json { "type": "notify", "event_type": "spotlight.focused", "client_id": "4D40YWH56N5S99QHJV6GAPNHB0", "bundle_id": "4D40YWH56N5S99QHJV6GAPNHB0", "connection_id": "4D40YWH56N5S99QHJV6GAPNHB0", "spotlight_number": 3, "audio": true, "video": true, "fixed": false } ``` ```json { "type": "notify", "event_type": "spotlight.unfocused", "client_id": "4D40YWH56N5S99QHJV6GAPNHB0", "bundle_id": "4D40YWH56N5S99QHJV6GAPNHB0", "connection_id": "4D40YWH56N5S99QHJV6GAPNHB0", "spotlight_number": 3, "audio": true, "video": true, "fixed": false } ``` ## 録画のシグナリング通知 録画のシグナリング通知は録画開始時には `recording.started` 、録画終了時には `recording.stopped` が通知されます。 > **ヒント** > > `role` が `recvonly` のクライアントには通知されません。 ### sora.conf の設定 `sora.conf` の `signaling_notify_recording` で通知するかどうかを指定可能です。デフォルトは `true` で通知します。 ```ini signaling_notify_recording = false ``` ### "event_type": "recording.started" 録画開始時に通知されます。接続前にすでに StartRecording API が実行されていた場合は、 `connection.created` の後に通知されます。 ```json { "type": "notify", "event_type": "recording.started", "client_id": "4D40YWH56N5S99QHJV6GAPNHB0", "bundle_id": "4D40YWH56N5S99QHJV6GAPNHB0", "connection_id": "4D40YWH56N5S99QHJV6GAPNHB0" } ``` ### "event_type": "recording.stopped" 録画終了時に通知されます。StopRecording API が実行されたタイミング、または期限が切れたタイミングで通知されます。 ```json { "type": "notify", "event_type": "recording.stopped", "client_id": "4D40YWH56N5S99QHJV6GAPNHB0", "bundle_id": "4D40YWH56N5S99QHJV6GAPNHB0", "connection_id": "4D40YWH56N5S99QHJV6GAPNHB0" } ``` ## ネットワークのシグナリング通知 **これは実験的機能です** ネットワークのシグナリング通知は、上記の `connection.*` とは別に `network.*` が通知されます。 ### "event_type": "network.status" この event_type は、 `signaling_notify` を有効にしている全員に通知されます。 この通知を利用することで、ネットワークの状態をクライアントが把握することが可能になります。 ### 送られる条件 現時点では映像を Sora に対して配信していることが通知の条件になります。 以下は通知されません - 受信のみ - 音声だけの配信 ### 現在の判定材料 - クライアント、またはサーバーからの再送要求の頻度 ### クライアントに送信される JSON の仕様 - event_type- string - `network.status` が入ります - unstable_level- integer - ネットワークの不安定レベルが入ります- 0- とても安定したネットワークです - 1- 安定したネットワークです - 2- 不安定なネットワークです - 3- とても不安定なネットワークです ```json { "type": "notify", "event_type": "network.status", "unstable_level": 0, } ``` ## RTP ストリーム停止と再開のシグナリング通知 **これは実験的機能です** RTP ストリーム停止と再開のシグナリング通知はストリーム停止時には `rtp_stream.pause` 、ストリーム再開時には `rtp_stream.resume` が通知されます。 ### sora.conf の設定 `sora.conf` の `signaling_notify_rtp_stream` で通知するかどうかを指定可能です。デフォルトは `true` で通知します。 ```ini signaling_notify_rtp_stream = false ``` ### "event_type": "rtp_stream.pause" RTP ストリーム停止時に通知されます。RTP ストリームが停止される送信側および受信側の接続に通知されます。 ```json { "type": "notify", "event_type": "rtp_stream.pause", "recv_connection_id": "4D40YWH56N5S99QHJV6GAPNHB0", "send_connection_id": "4SW2CB0E1D01S23W3G6JFCEN98" } ``` ### "event_type": "rtp_stream.resume" RTP ストリーム再開時に通知されます。RTP ストリームが再開される送信側および受信側の接続に通知されます。 ```json { "type": "notify", "event_type": "rtp_stream.resume", "stream_id": "4D40YWH56N5S99QHJV6GAPNHB0" } ``` ## シーケンス図 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']; クライアント <<- Sora [label = 'シグナリング通知\n"type": "connection.craeted"']; ... 接続から 1 分経過 ... Sora -> アプリケーションサーバー [label = 'イベントウェブフック\n"type": "connection.updated"']; Sora <-- アプリケーションサーバー [label = '200 OK']; クライアント <<- Sora [label = 'シグナリング通知\n"type": "connection.updated"']; } # シグナリング通知メタデータ ## 概要 `signaling_notify_metadata` はユーザーが参加や離脱したときに送られるシグナリング通知に含まれるメタデータです。 シグナリング接続時、または認証ウェブフック成功の戻り値に `signaling_notify_metadata` で JSON を指定することで利用できるようになります。 新しく参加したときにはすでに参加しているクライアントの `signaling_notify_metadata` の値がリストで送られます。 ## 注意 [シグナリング通知メタデータ拡張機能](SIGNALING_NOTIFY_METADATA_EXT.html) を有効にしている場合、 `metadata` ではなく `authz_metadata` のみに値が入るよう挙動が変わります。 ## sora.conf の指定 `sora.conf` で `signaling_notify_metadata = false` を指定することで、 シグナリング通知時に `metadata` や `data` を含まなくなります。 `data` の内容は `signaling_notify_client_id` や `signaling_notify_bundle_id` 、 `signaling_notify_connection_id` の設定により変化します。 > - 設定による data の出力内容の違いは [table-signaling-notify-client-id-bundle-id-connection-id](SIGNALING_NOTIFY.html#table-signaling-notify-client-id-bundle-id-connection-id) をご確認ください > - 設定を行ったときの出力例は [sora.conf の設定内容とシグナリング通知メタデータ出力の例](SIGNALING_NOTIFY_METADATA.html#a608ef) をご確認ください ## シグナリング接続時での指定 `"type": "connect"` 接続時に `signaling_notify_metadata` で JSON 型の好きな値を指定できます。 ```json { "type": "connect", "role": "sendonly", "channel_id": "bacon", "signaling_notify_metadata": {"spam": "egg"} } ``` シグナリング接続時に指定した値は、通知時に `metadata` として通知されます。 ```json { "type": "notify", "event_type": "connection.created", "authn_metadata": {"spam": "egg"}, "metadata": {"spam": "egg"}, "data": [ { "client_id": "KKBFZTQXDD6H7FD2NYCQX8S474", "bundle_id": "KKBFZTQXDD6H7FD2NYCQX8S474", "connection_id": "KKBFZTQXDD6H7FD2NYCQX8S474", "authn_metadata": {"spam": "egg"}, "metadata": {"spam": "egg"} }, { "client_id": "4D40YWH56N5S99QHJV6GAPNHB0", "bundle_id": "4D40YWH56N5S99QHJV6GAPNHB0", "connection_id": "4D40YWH56N5S99QHJV6GAPNHB0", "authn_metadata": 10, "metadata": 10 } ] } ``` また `auth_metadata` としても通知されます。 ### シグナリング接続時に指定できるシグナリング通知メタデータのサイズ制限 > **重要** > > シグナリング接続時に指定できるシグナリング通知メタデータのサイズは最大 64 KiB (65536 バイト) です。 メタデータのサイズはメタデータ拡張機能をエンコード済みの JSON 、つまり文字列としてサイズを計算します。 例えば `{"a":"b"}` の場合は 9 バイトで、 `{"a":"b","c":1200}` は 18 バイトです。 ## 認証ウェブフックの戻り値での指定 ```json { "allowed": true, "signaling_notify_metadata": 10 } ``` 認証ウェブフックの戻り値で指定した値は、通知時に `authz_metadata` としても通知されます。 ```json { "type": "notify", "event_type": "connection.created", "authn_metadata": {"spam": "egg"}, "authz_metadata": "bacon", "metadata": "bacon", "data": [ { "authz_metadata": {"spam": "egg"}, "client_id": "🐗🐗🐗🐗", "bundle_id": "KKBFZTQXDD6H7FD2NYCQX8S474", "connection_id": "KKBFZTQXDD6H7FD2NYCQX8S474", "metadata": {"spam": "egg"} }, { "authz_metadata": 10, "client_id": "🐹🐹🐹🐹", "bundle_id": "4D40YWH56N5S99QHJV6GAPNHB0", "connection_id": "4D40YWH56N5S99QHJV6GAPNHB0", "metadata": 10 } ] } ``` すでに参加しており、他のクライアントが参加してきた場合や離脱した場合は以下の通りになります。 ```json { "type": "notify", "metadata": 10 } ``` ### 認証成功時払い出しのシグナリング通知メタデータのサイズ制限 制限はありません。 ## sora.conf の設定内容とシグナリング通知メタデータ出力の例 sora.conf - `signaling_notify_client_id = true` - `signaling_notify_bundle_id = true` - `signaling_notify_connection_id = true` ```json { "type": "notify", "event_type": "connection.created", "authn_metadata": {"spam": "egg"}, "authz_metadata": "bacon", "metadata": "bacon", "data": [ { "authz_metadata": {"spam": "egg"}, "client_id": "🐗🐗🐗🐗", "bundle_id": "KKBFZTQXDD6H7FD2NYCQX8S474", "connection_id": "KKBFZTQXDD6H7FD2NYCQX8S474", "metadata": {"spam": "egg"} }, { "authz_metadata": 10, "client_id": "🐹🐹🐹🐹", "bundle_id": "4D40YWH56N5S99QHJV6GAPNHB0", "connection_id": "4D40YWH56N5S99QHJV6GAPNHB0", "metadata": 10 } ] } ``` - `signaling_notify_client_id = false` - `signaling_notify_bundle_id = true` - `signaling_notify_connection_id = true` ```json { "type": "notify", "event_type": "connection.created", "authn_metadata": {"spam": "egg"}, "authz_metadata": "bacon", "metadata": "bacon", "data": [ { "authz_metadata": {"spam": "egg"}, "bundle_id": "KKBFZTQXDD6H7FD2NYCQX8S474", "connection_id": "KKBFZTQXDD6H7FD2NYCQX8S474", "metadata": {"spam": "egg"} }, { "authz_metadata": 10, "bundle_id": "4D40YWH56N5S99QHJV6GAPNHB0", "connection_id": "4D40YWH56N5S99QHJV6GAPNHB0", "metadata": 10 } ] } ``` - `signaling_notify_client_id = true` - `signaling_notify_bundle_id = false` - `signaling_notify_connection_id = true` ```json { "type": "notify", "event_type": "connection.created", "authn_metadata": {"spam": "egg"}, "authz_metadata": "bacon", "metadata": "bacon", "data": [ { "authz_metadata": {"spam": "egg"}, "client_id": "🐗🐗🐗🐗", "connection_id": "KKBFZTQXDD6H7FD2NYCQX8S474", "metadata": {"spam": "egg"} }, { "authz_metadata": 10, "client_id": "🐹🐹🐹🐹", "connection_id": "4D40YWH56N5S99QHJV6GAPNHB0", "metadata": 10 } ] } ``` - `signaling_notify_client_id = true` - `signaling_notify_bundle_id = true` - `signaling_notify_connection_id = false` ```json { "type": "notify", "event_type": "connection.created", "authn_metadata": {"spam": "egg"}, "authz_metadata": "bacon", "metadata": "bacon", "data": [ { "authz_metadata": {"spam": "egg"}, "client_id": "🐗🐗🐗🐗", "bundle_id": "KKBFZTQXDD6H7FD2NYCQX8S474", "metadata": {"spam": "egg"} }, { "authz_metadata": 10, "client_id": "🐹🐹🐹🐹", "bundle_id": "4D40YWH56N5S99QHJV6GAPNHB0", "metadata": 10 } ] } ``` - `signaling_notify_client_id = false` - `signaling_notify_bundle_id = false` - `signaling_notify_connection_id = false` ```json { "type": "notify", "event_type": "connection.created", "authn_metadata": {"spam": "egg"}, "authz_metadata": "bacon", "metadata": "bacon", "data": [ { "authz_metadata": {"spam": "egg"}, "metadata": {"spam": "egg"} }, { "authz_metadata": 10, "metadata": 10 } ] } ``` # シグナリング通知メタデータ拡張機能 > **警告** > > シグナリング通知メタデータ拡張機能は実験的機能のため正式版では仕様が変更される可能性があります ## 概要 シグナリング通知メタデータ拡張機能(以降メタデータ拡張機能)は、 Sora に API 経由で変更可能なメタデータを接続ごとに保持する機能です。 - メタデータは新規参加者にシグナリング通知経由で共有されます - メタデータを API 経由で変更した際に変更をプッシュで通知することも可能になります ## 目的 接続ごとに持たせたメタデータを API 経由で変更し、 既存参加者にはプッシュで通知、新規参加者には参加時に通知するような仕組みを提供することです。 ## シグナリング通知メタデータの課題 今までのシグナリング通知メタデータは、接続時の指定した値を認証成功時の払い出しで上書きするといったものでした。 そのため **接続ごとの状態変更** を管理するために別の仕組みを用意する必要がありました。 メタデータ拡張を利用することで、接続ごとの状態、 例えば「忙しい」といったプレゼンス情報を Sora で管理し、他の接続に通知することが可能になります。 ## メタデータ拡張機能を利用することで実現可能なこと - 参加者のプレゼンス状態を変更した際に既存参加者にはプッシュで共有し、新規参加者にはシグナリング通知で共有できるようになる - マイクミュート状態を既存参加者にはプッシュで共有し、新規参加者にはシグナリング通知で共有できるようになる - 画面共有中の配信者を既存参加者にはプッシュで共有し、新規参加者にはシグナリング通知で共有できるようになる 今まで別の場所で保持していた変更可能な状態を Sora 側で持つことが可能になります。 ## メタデータ拡張機能の有効 / 無効について メタデータ拡張機能はデフォルトで無効になっています。 ### sora.conf の指定 メタデータ拡張機能を有効にするには設定を有効にする必要があります。 ```ini signaling_notify_metadata_ext = true ``` ### 有効にした際の変更点 - API 経由で connection.created 時に共有される `metadata` が key / value 形式で指定できるようになります - シグナリング通知時に送られる `metadata` は API でのみ反映され、接続時や認証時の `signaling_notify_metadata` は反映されません - シグナリング通知時に送られる `metadata` の初期値は `{}` で空オブジェクトです - 接続時に指定していた `signaling_notify_metadata` は `authn_metadata` を利用してください- 指定しない場合は `authn_metadata` はシグナリング通知時に含まれません - 認証成功時に払い出していた `signaling_notify_metadata` は `authz_metadata` を利用してください- 指定しない場合は `authz_metadata` はシグナリング通知時に含まれません ## メタデータ拡張機能の特徴 - API 実行時に `"push": true` を指定することで、メタデータの変更と通知を同時に行えます- 通知は `"type": "push"` で行われます - API 経由で以外では変更できません ## メタデータ拡張機能の制限 > **重要** > > 1 接続が保持できるメタデータ拡張のサイズは最大 32 KiB (32768 バイト) です。 メタデータのサイズはメタデータ拡張機能をエンコード済みの JSON 、つまり文字列としてサイズを計算します。 例えば `{"a":"b"}` の場合は 9 バイトで、 `{"a":"b","c":1200}` は 18 バイトです。 ## 利用方法 **開発ツールを利用します** > **注意** > > シグナリング通知メタデータ拡張 API が有効になるのはイベントウェブフックの `connection.created` が通知されてからです。 1. シグナリング通知メタデータ拡張機能を有効にしましょう- `sora.conf` の `signaling_notify_metadata_ext = true` を設定します 2. まず1つ目の接続をしてみましょう- 開発ツールの `マルチストリーム送受信` を開いて、右上の debug にチェックを入れて connect を押してください - `channel_id` はデフォルトの `sora` のままで問題ありません - `connection_id` を `PPD3R008XH0S11CG535JFKQFH0` とします 3. この時点で、まだ `PPD3R008XH0S11CG535JFKQFH0` の `metadata` は `{}` です 4. `PPD3R008XH0S11CG535JFKQFH0` のメタデータに新しいアイテムを追加してみましょう - HTTP API の `PutSignalingNotifyMetadataItem` を利用します - key を "abc" とし value を 10 としてアイテムを追加します - ついでにプッシュ通知も行うように push を true にします ``` http POST 127.0.0.1:3000/ x-sora-target:Sora_20201124.PutSignalingNotifyMetadataItem \ channel_id=sora connection_id=PPD3R008XH0S11CG535JFKQFH0 \ key=abc value:=10 push:=true HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 10 content-type: application/json date: Wed, 25 Nov 2020 08:16:44 GMT server: Cowboy { "abc": 10 } ``` - Push タブにプッシュ通知が来ていたら成功です 5. 項目に値が入っているか確認してみましょう ``` http POST 127.0.0.1:3000/ x-sora-target:Sora_20201124.GetSignalingNotifyMetadata \ channel_id=sora connection_id=PPD3R008XH0S11CG535JFKQFH0 -vvv HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 10 content-type: application/json date: Wed, 25 Nov 2020 08:14:34 GMT server: Cowboy { "abc": 10 } ``` 6. 新しい接続に追加したアイテムが反映されているメタデータが通知されるか確認してみましょう- 別のタブで `マルチストリーム送受信` を開いて、debug にチェックを入れて connect して Notify タブを見てみて下さい - `data` の中に `connection_id: PPD3R008XH0S11CG535JFKQFH0` があり、その `metadata` が先程作成した値であれば成功です # Sora クライアント要求仕様 ## 概要 Sora SDK や Sora クライアントの開発者に向けた資料です。 ## クライアント側の終了処理条件 ### RTCPeerConnectionState が failed になる 全ての接続において [RTCPeerConnectionState](https://www.w3.org/TR/webrtc/#dom-rtcpeerconnectionstate) が [failed](https://www.w3.org/TR/webrtc/#dom-rtcpeerconnectionstate-failed) になったタイミングで `"type": "disconnect"` は送らず、 クライアント側で終了処理をしてください。 ### WebSocket のみ - RTCPeerConnectionState が failed になった- 終了処理に入る - WebSocket onclose が上がった - 終了処理に入る - WebSocket onerror が上がった- 終了処理に入る ### WebSocket と DataChannel - RTCPeerConnectionState が failed になった- 終了処理に入る - WebSocket onclose が上がった - `"type": "switched"` が送られてきていない- 終了処理に入る - `"type": "switched", "ignore_disconnect_websocket": true` が送られてきていた- 何もしない - `"type": "switched", "ignore_disconnect_websocket": false` が送られてきていて、 RTCPeerConnectionState が failed になっている- 終了処理に入る - `"type": "switched", "ignore_disconnect_websocket": false` が送られてきていて、 RTCPeerConnectionState が failed になっていない- DataChanel で `"type": "disconnect", reason: "WEBSOCKET-ONCLOSE"` を送ることを試みる - 終了処理に入る - WebSocket onerror が上がった- `"type": "switched"` が送られてきていない- 終了処理に入る - `"type": "switched", "ignore_disconnect_websocket": true` が送られてきていた- 何もしない - `"type": "switched", "ignore_disconnect_websocket": false` が送られてきていて、 RTCPeerConnectionState が failed になっている- 終了処理に入る - `"type": "switched", "ignore_disconnect_websocket": false` が送られてきていて、 RTCPeerConnectionState が failed になっていない- DataChanel で `"type": "disconnect", reason: "WEBSOCKET-ONERROR"` を送ることを試みる - 終了処理に入る ### DataChannel のみ - RTCPeerConnectionState が failed になった- 終了処理に入る ### DataChannel の終了 Sora SDK の切断タイムアウトのデフォルト値は 3000 ミリ秒です。 - RTCDataChannel [onclose](https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onclose) が上がった- RTCDataChannel [onerror](https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onerror) にコールバックをセットしている場合- 終了処理に入る、または切断タイマーを開始し、全ての RTCDataChannel の [readyState](https://www.w3.org/TR/webrtc/#dom-datachannel-readystate) がすべて [closed](https://www.w3.org/TR/webrtc/#dom-rtcdatachannelstate-closed) にならずタイムアウトした場合は終了処理にはいる - RTCDataChannel onerror にコールバックをセットしていない場合- 終了処理に入る - RTCDataChannel onerror が上がった- 終了処理に入る ## アプリケーション経由の "type": "disconnect" 送信後の終了処理 Sora SDK の切断タイムアウトのデフォルト値は 3000 ミリ秒です。 ### WebSocket のみ `data_channel_signaling: false` の場合。 - WebSocket 経由で `"type": "disconnect", reason: "NO-ERROR"` を送る- 終了処理に入る、または切断タイマーを開始し、WebSocket onclose が上がらずタイムアウトした場合は終了処理に入る ### WebSocket と DataChannel `data_channel_signaling: true` で `ignore_disconnect_websocket: false` の場合。 - `"type": "switched"` が送られて来ていない- WebSocket 経由で `"type": "disconnect", reason: "NO-ERROR"` を送る - 終了処理にはいる、または切断タイマーを開始し、WebSocket onclose が上がらずタイムアウトした場合は終了処理にはいる - `"type": "switched", "ignore_disconnect_websocket": false` が送られてきていて、 WebSocket は切断していない- DataChannel 経由で `"type": "disconnect", reason: "NO-ERROR"` を送る - [RTCDataChannel](https://www.w3.org/TR/webrtc/#dom-rtcdatachannel) [onerror](https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onerror) にコールバックをセットしている場合- 終了処理に入る、または切断タイマーを開始し、WebSocket の onclose かつ、全ての RTCDataChannel の [readyState](https://www.w3.org/TR/webrtc/#dom-datachannel-readystate) がすべて [closed](https://www.w3.org/TR/webrtc/#dom-rtcdatachannelstate-closed) にならずタイムアウトした場合は終了処理にはいる - [RTCDataChannel](https://www.w3.org/TR/webrtc/#dom-rtcdatachannel) [onerror](https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onerror) にコールバックをセットしていない場合- 終了処理に入る ### DataChannel のみ `data_channel_signaling: true` で `ignore_disconnect_websocket: true` の場合。 - `"type": "switched"` が送られて来ていない- WebSocket 経由で `"type": "disconnect", reason: "NO-ERROR"` を送る - 切断タイマーを開始する - WebSocket onclose が上がらずタイムアウトした場合は終了処理に入る - `"type": "switched", "ignore_disconnect_websocket": true` が送られてきていて、 WebSocket も切断している- DataChannel 経由で `"type": "disconnect", reason: "NO-ERROR"` を送る - RTCDataChannel [onerror](https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onerror) にコールバックをセットしている場合- 終了処理に入る、または切断タイマーを開始し、全ての RTCDataChannel の [readyState](https://www.w3.org/TR/webrtc/#dom-datachannel-readystate) がすべて [closed](https://www.w3.org/TR/webrtc/#dom-rtcdatachannelstate-closed) にならずタイムアウトした場合は終了処理にはいる - RTCDataChannel onerror にコールバックをセットしていない場合- 終了処理に入る ## 異常発生による終了 ### シグナリングの異常 終了処理に入ってください。 ### シグナリング以外の異常 `"type": "disconnect", reason: "INTERNAL-ERROR"` を送り、終了処理に入って下さい。 ## RTCPeerConnectionState が定義されていない場合 > **注釈** > > ブラウザでは Firefox が RTCPeerConnectionState が定義されていません [RTCDtlsTransprot](https://www.w3.org/TR/webrtc/#dom-rtcdtlstransport) が実装されていない場合 RTCPeerConnectionState が正常に動作しないため、 [RTCIceConnectionState](https://www.w3.org/TR/webrtc/#dom-rtciceconnectionstate) を利用してください。 RTCIceConnectionState が [disconnect](https://www.w3.org/TR/webrtc/#dom-rtciceconnectionstate-disconnected) になった場合、切断タイマーを開始し、 タイムアウトした場合 disconnect から変化がなければ切断してください。 Sora SDK の RTCIceConnectionState 用の切断タイマーはデフォルトで 10 秒です。 # 認証ウェブフック ## 概要 Sora 自体はクライアントの接続を認証する機能を持っていません。認証する場合は外部に認証サーバーを用意する必要があります。 Sora はシグナリング経由で送られてきた情報や、 そのチャネルに接続している情報を POST リクエストで `sora.conf` の [auth_webhook_url](SORA_CONF.html#36a99a) に指定された URL へ送信します。 このとき送信する情報は JSON 形式です。 ## 注意 シグナリング `"type": "connect"` 経由で送られてきた情報がそのまま認証ウェブフックのリクエストとして送信されるわけではありません。 ## ウェブフックリクエスト送信先のサーバーがベーシック認証を利用している場合 もしウェブフックリクエスト送信先のサーバーがベーシック認証を利用している場合は、 `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_tls_verify_cacert_file](SORA_CONF.html#7036dc) を指定することで、 指定されたルート CA を利用してサーバーの証明書検証を行います。 もしくは推奨はできませんが `sora.conf` にて、 [webhook_insecure](SORA_CONF.html#676769) を `true` に設定することで証明書のチェックを行わなくなります。 ## ウェブフックリクエスト送信先のサーバーが mTLS を利用している場合 mTLS を利用する場合は `sora.conf` にて [webhook_tls_fullchain_file](SORA_CONF.html#93f2b9) にクライアント証明書、 [webhook_tls_privkey_file](SORA_CONF.html#7065d6) にクライアント秘密鍵を指定することで mTLS を利用します。 ## auth_webhook_url **デフォルト**: 未設定 クライアントの認証可否を判断するための URL を指定します。認証ウェブフック機能を使用する場合は指定してください。 この URL には HTTPS の URL を指定することも可能です。 HTTPS の URL を指定する場合、リクエスト送信先のアプリケーションについて基本的には正規の認証局から発行された証明書を利用してください。 独自の証明書を利用する場合は [ウェブフックリクエスト送信先のサーバーが自己署名証明書などを利用している場合](AUTH_WEBHOOK.html#467c4b) をご確認ください。 Sora は戻り値の JSON で認証可否を判断します。 HTTP のレスポンスは 200 OK 等の 200 番台のステータスコードの必要があります。 ### 設定 認証可否の判断に使用する HTTP リクエストの送信先を `sora.conf` の [auth_webhook_url](SORA_CONF.html#36a99a) に設定します。 ```ini auth_webhook_url = http://127.0.0.1:8080/sora/auth/webhook ``` ### 認証処理時に送信する JSON Sora は、 `sora.conf` の [auth_webhook_url](SORA_CONF.html#36a99a) に設定した URL に対して **POST リクエスト** で次のような JSON を送ります。 ```json { "audio": { "codec_type": "OPUS" }, "channel_connections": 0, "channel_id": "sora", "channel_recvonly_connections": 0, "channel_sendonly_connections": 0, "channel_sendrecv_connections": 0, "connection_id": "VSMDDJG3ZH1RHB93W260APVEQW", "data_channel_signaling": true, "data_channels": [ { "compress": false, "direction": "sendrecv", "label": "#abc", "ordered": true } ], "e2ee": false, "ignore_disconnect_websocket": false, "label": "WebRTC SFU Sora", "multistream": true, "node_name": "node1@192.0.2.10", "role": "sendrecv", "simulcast": false, "sora_client": { "environment": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36", "raw": "Sora JavaScript SDK 2021.1.0", "type": "Sora JavaScript SDK", "version": "2021.1.0" }, "spotlight": false, "timestamp": "2021-06-08T07:51:32.593704Z", "version": "2021.1", "video": { "bit_rate": 1000, "codec_type": "VP9" } } ``` `sora.conf` で [legacy_webhook_audio_video_json_structure](SORA_CONF.html#3be597) を false にしている場合は以下のようになります。 ```json { "audio": true, "audio_codec_type": "OPUS", "channel_connections": 0, "channel_id": "sora", "channel_recvonly_connections": 0, "channel_sendonly_connections": 0, "channel_sendrecv_connections": 0, "connection_id": "VSMDDJG3ZH1RHB93W260APVEQW", "data_channel_signaling": true, "data_channels": [ { "compress": false, "direction": "sendrecv", "label": "#abc", "ordered": true } ], "e2ee": false, "ignore_disconnect_websocket": false, "label": "WebRTC SFU Sora", "multistream": true, "node_name": "node1@192.0.2.10", "role": "sendrecv", "simulcast": false, "sora_client": { "environment": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36", "raw": "Sora JavaScript SDK 2021.1.0", "type": "Sora JavaScript SDK", "version": "2021.1.0" }, "spotlight": false, "timestamp": "2021-06-08T07:51:32.593704Z", "version": "2021.1", "video": true, "video_bit_rate": 1000, "video_codec_type": "VP9" } ``` - version- Sora のバージョンが `文字列` で入ってきます - label- `sora.conf` の [label](SORA_CONF.html#815983) で指定した値が入ってきます - node_name- Sora のノード名が入ってきます - timestamp- ウェブフックリクエスト送信時のタイムスタンプが RFC3339 フォーマットで入ってきます - マイクロ秒まで含まれています - e2ee- クライアントが E2EE を有効にしているかどうかが入ってきます - true の場合は E2EE を利用する接続です - multistream- マルチストリームでの接続要求を出しているかどうかの値が入ってきます - true の場合はマルチストリームを希望している接続です - simulcast- サイマルキャストでの接続要求を出しているかどうかの値が入ってきます - true の場合はサイマルキャストを希望している接続です - simulcast_rid- サイマルキャストでの受け取る rid を指定します - spotlight- スポットライトでの接続要求を出しているかどうかの値が入ってきます - spotlight_number- **この項目はオプションです** - `spotlight_number` をシグナリングの connect 時に送ってきた場合に値が入ります - role- 以下が入ってきます - `sendrecv` (送受信) - `sendonly` (送信) - `recvonly` (受信) - channel_id- 認証対象のクライアントが接続要求を出しているチャネル ID です - client_id- 認証対象のクライアントが利用要求を出しているクライアント ID です - `"type": "connect"` で `client_id` が送られてこない場合、アプリケーション側にも送られません - bundle_id- 認証対象のコネクションが利用要求を出しているバンドル ID です - `sora.conf` の [signaling_bundle_id](SORA_CONF.html#279311) が `true` で `"type": "connect"` で `bundle_id` が送られてこない場合、アプリケーション側にも送られません - connection_id- Base32-UUIDv4 です - 認証対象のコネクションに割り当てられたユニークな ID です - channel_connections- 現在そのチャネルの接続数です - 自分は含まれません - channel_sendrecv_connections- 現在そのチャネルで送受信をしている配信者の接続数です - 自分は含まれません - channel_sendonly_connections- 現在そのチャネルで送信のみをしている配信者の接続数です - 自分は含まれません - channel_recvonly_connections- 現在そのチャネルの配信を受信のみしている視聴者の接続数です - 自分は含まれません - audio- `false` の場合は `audio` を使用しません - コーデックやビットレートが入ってくる場合は `{"codec_type": "OPUS", "bit_rate": 32}` が入ってきます - コーデックの種類は `OPUS` です - **ビットレートの項目はオプションです**- もし `default_audio_bit_rate` に値を指定していた場合はその値が利用されます - 最小が 6 で、最大が 510 です - `sora.conf` の [legacy_webhook_audio_video_json_structure](SORA_CONF.html#3be597) を `false` にした場合以下のようにフラット化します- `audio: true` - `audio_codec_type: "OPUS"` - `audio_bit_rate: 32` - 詳細は [ウェブフックの audio と video 項目の JSON 構造のフラット化](WEBHOOK_AUDIO_VIDEO_FLATTEN_JSON.html) をご確認ください - video- `false` の場合は `video` を使用しません - コーデックやビットレートが入ってくる場合は `{"codec_type": "VP9", "bit_rate": 500}` が入ってきます - コーデックの種類は VP8、VP9、AV1、H264、H265 の 5 種類です - コーデックはクライアントが送ってこない場合はデフォルトで `VP9` が使用されます - ビットレートはクライアントが送ってこない場合は `sora.conf` の [default_video_bit_rate](SORA_CONF.html#620132) が使用されます- デフォルトは 500 です - 最小が 1 で、最大が 30000 です - 15000 より大きい値は現時点でサポート範囲外です - 単位は `kbps` です - `sora.conf` の [legacy_webhook_audio_video_json_structure](SORA_CONF.html#3be597) を `false` にした場合以下のようにフラット化します- `"video": true` - `"video_codec_type": "VP9"` - `"video_bit_rate": 500` - 詳細は [ウェブフックの audio と video 項目の JSON 構造のフラット化](WEBHOOK_AUDIO_VIDEO_FLATTEN_JSON.html) をご確認ください - metadata- **この項目はオプションです** - ユーザーが定義を自由にできる値です - JSON で使用できる形式ならどんな値でも指定可能です - `"type": "connect"` で `metadata` が送られてこない場合、アプリケーション側にも送られません - authn_metadata- **この項目はオプションです** - この項目は metadata と同じです - metadata の別名です - `"type": "connect"` で `metadata` が送られてこない場合、アプリケーション側にも送られません - data_channel_signaling- シグナリングの DataChannel 切り替えをするかどうか - ignore_disconnect_websocket- シグナリングの DataChannel 切り替え時に WebSocket の切断を無視するかどうか - data_channels- **この項目はオプションです** - DataChannel を利用したメッセージングの定義が入ってきます - クライアントが指定しない場合は入ってきません - sora_client- **この項目はオプションです** - クライアントから送られてきた情報が入ってきます ### sora_client 認証ウェブフックの `sora_client` にはクライアントから送られてきた情報が入ってきます。 クライアントから情報が送られてこなければ含まれません。 Sora SDK を利用している場合は必ず入ってきます。 ```json "sora_client": { "environment": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36", "raw": "Sora JavaScript SDK 2021.1.0", "type": "Sora JavaScript SDK", "version": "2021.1.0" }, ``` - type- オプションです - クライアントから送られてきた Sora SDK またはクライアントのタイプが入ってきます - raw- オプションです - クライアントから送られてきた sora_client の値がそのまま入ってきます - version- オプションです - クライアントから送られてきた Sora SDK またはクライアントのバージョンが入ってきます - commit_short- オプションです - クライアントから送られてきた Sora SDK のコミットハッシュが入ってきます - environment- オプションです - クライアントから送られてきた端末情報が入ってきます - libwebrtc- オプションです - クライアントから送られてきた libwebrtc のバージョン情報が入ってきます ### 認証成功時のレスポンス JSON 認証に成功した場合は、以下の JSON を返してください。 ```json { "allowed": true } ``` Sora は "allowed" が true の場合は認証を成功と判断して処理をします。 ### 認証失敗時のレスポンス JSON 認証に失敗した場合は、以下の JSON を返してください。 ```json { "allowed": false, "reason": "" } ``` > **注釈** > > 認証失敗の場合も HTTP レスポンスのステータスコードは 200 番台である必要があります Sora は "allowed" が false で、 "reason" が含まれている場合に認証失敗と判断して処理します。 "reason" は必須です、何かしらエラー理由を **100 バイト以内** の文字列にて追加してください。 認証に失敗した場合、認証サーバーから送られてきた "reason" の内容は文字列としてクライアントに送られます。 ``` "<認証サーバーから送られてきた reason>" ``` ## 認証ウェブフック成功時の払い出し 認証サーバーは認証成功時に様々な値を出すことができます。 ```json { "allowed": true, "event_metadata": { "pk": 1 } } ``` 詳細は [認証ウェブフック成功時の払い出し](AUTH_WEBHOOK_RETURN.html) をご確認ください。 ## 認証ウェブフックログ `sora.conf` の [auth_webhook_log](SORA_CONF.html#116686) を `true` にしている場合は `log/auth_webhook.log` が出力されます。 > **重要** > > `auth_webhook_log` はデフォルトで `true` です。 このログには認証ウェブフックのリクエストとレスポンス、ウェブフック URL、タイムスタンプが含まれます。 - req- 認証ウェブフックの送信リクエストがそのまま入ります - res- 認証ウェブフックの戻り値がそのまま入ります - url- auth_webhook_url を指定していない場合はログに含まれません - timestamp- RFC3339 フォーマットのタイムスタンプが入ります - UTC です ### auth_webhook_url あり / レスポンスあり ```json { "req": { "audio": { "codec_type": "OPUS" }, "channel_connections": 0, "channel_id": "sora", "channel_recvonly_connections": 0, "channel_sendonly_connections": 0, "channel_sendrecv_connections": 0, "connection_id": "F2SMT1W59S5ADDZ84CMQ8CDBX4", "e2ee": false, "label": "WebRTC SFU Sora", "multistream": true, "node_name": "node1@192.0.2.10", "role": "sendrecv", "simulcast": false, "sora_client": { "environment": "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_0_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36", "raw": "Sora JavaScript SDK 2020.5.0", "type": "Sora JavaScript SDK", "version": "2020.5.0" }, "spotlight": false, "timestamp": "2020-12-07T09:16:54.079650Z", "version": "2020.3", "video": { "bit_rate": 1000, "codec_type": "VP9" } }, "res": { "allowed": true, "event_metadata": { "abc": "efg" }, "metadata": "abc", "signaling_notify_metadata": { "a": "b" } }, "timestamp": "2020-12-07T09:16:54.089962Z", "url": "http://127.0.0.1:3001/sora/auth/webhook" } ``` ### auth_webhook_url あり / レスポンスなし - res がありません ```json { "req": { "audio": { "codec_type": "OPUS" }, "channel_connections": 0, "channel_id": "sora", "channel_recvonly_connections": 0, "channel_sendonly_connections": 0, "channel_sendrecv_connections": 0, "connection_id": "0FBC8HF84544ZDHYYN9BCRNZG8", "e2ee": false, "label": "WebRTC SFU Sora", "multistream": true, "node_name": "node1@192.0.2.10", "role": "sendrecv", "simulcast": false, "sora_client": { "environment": "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_0_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36", "raw": "Sora JavaScript SDK 2020.5.0", "type": "Sora JavaScript SDK", "version": "2020.5.0" }, "spotlight": false, "timestamp": "2020-12-07T06:30:56.240917Z", "version": "2020.3", "video": { "bit_rate": 1000, "codec_type": "VP9" } }, "timestamp": "2020-12-07T06:30:56.252785Z", "url": "http://127.0.0.1:3001/sora/authn/webhook" } ``` ### auth_webhook_url なし - url がありません ```json { "req": { "audio": { "codec_type": "OPUS" }, "channel_connections": 0, "channel_id": "sora", "channel_recvonly_connections": 0, "channel_sendonly_connections": 0, "channel_sendrecv_connections": 0, "client_id": "K8PCW533MN1WK24YNZ83HDP74C", "connection_id": "K8PCW533MN1WK24YNZ83HDP74C", "e2ee": false, "label": "WebRTC SFU Sora", "multistream": true, "node_name": "node1@192.0.2.10", "role": "sendrecv", "simulcast": false, "sora_client": { "environment": "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_0_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36", "raw": "Sora JavaScript SDK 2020.5.0", "type": "Sora JavaScript SDK", "version": "2020.5.0" }, "spotlight": false, "timestamp": "2020-12-07T06:26:58.916204Z", "version": "2020.3", "video": { "bit_rate": 1000, "codec_type": "VP9" } }, "res": { "allowed": true }, "timestamp": "2020-12-07T06:26:58.916242Z" } ``` ## エラーメッセージ これらエラーメッセージは sora.log に出力されます。 ### AUTH_WEBHOOK_RESPONSE_UNEXPECTED_STATUS_CODE 認証サーバーが返すステータスコードが 200 系ではなかった場合に出力されます。 例えばステータスコードが 400 だと出力されます。 ### INVALID_AUTH_WEBHOOK_RESPONSE_JSON 認証サーバーが返す JSON に必須で項目が含まれていない場合に出力されます。 例えば `allowed` が含まれていない場合に出力されます。 ### AUTH-WEBHOOK-RESPONSE-BAD-JSON 認証サーバーが返す JSON のデコードに失敗した場合に出力されます。 例えば `{"a: b"}` といったような JSON と判断できない場合に出力されます。 ## シーケンス図 ### 認証成功 seqdiag { default_fontsize = 15; edge_length = 250; クライアント ->> Sora [label = '"type": "connect"']; Sora -> アプリケーションサーバー [label = '認証ウェブフック']; Sora <-- アプリケーションサーバー [label = '200 OK\n{"allowed": true}']; クライアント <<- Sora [label = '"type": "offer"']; クライアント ->> Sora [label = '"type": "answer"', noactivate]; === WebRTC 確立 === } ### 認証拒否 seqdiag { default_fontsize = 15; edge_length = 250; クライアント ->> Sora [label = '"type": "connect"']; Sora -> アプリケーションサーバー [label = '認証ウェブフック']; Sora <-- アプリケーションサーバー [label = '200 OK\n{"allowed": false, \n"reason": "reject"}']; クライアント <<- Sora [label = 'WebSocket Close']; } # 認証ウェブフック成功時の払い出し ## 概要 Sora では認証ウェブフック成功時に様々な値を外部の認証サーバーから払い出すことができます。 Sora は払い出された値を反映した状態でクライアントへの接続要求 `("type": "offer")` を送ります。 ## audio の払い出し クライアントが指定してきた音声のコーデックやビットレートなどのパラメータに対して、 認証サーバー側で新たに値を払い出すことで、上書きを行えます。 クライアントが指定してきた値を上書きすることができるため、 サーバー側でそれぞれのクライアントに対して、音声のコーデックやビットレートをコントロールすることができます。 ### レガシーな払い出し例 > **重要** > > これは `sora.conf` にて [legacy_webhook_audio_video_json_structure](SORA_CONF.html#3be597) が `true` の場合の設定方法です。 > この設定は 2023 年 12 月リリース予定の Sora にて利用できなくなります。 この機能を使用する場合は、認証成功時のレスポンス JSON に `audio` を指定してください。 ここで使用できるのはシグナリングの `"type": "connect"` 時に指定可能な `audio` の値です。 ただしレガシーな払い出しの場合は `opus_params` や `lyra_params` は指定できません。 ```json { "allowed": true, "audio": { "codec_type": "OPUS", "bit_rate": 64 } } ``` #### 指定可能な値 - audio- `true` または `false` または object が指定可能です - codec_type- "OPUS" - codec_type を指定しないことも可能です - bit_rate- 6 ~ 510 - 単位は kbps です - デフォルトで最適なビットレートが選択されるようになっているため指定する必要はありません ### フラットな払い出し例 これは `sora.conf` にて [legacy_webhook_audio_video_json_structure](SORA_CONF.html#3be597) が `false` の場合の設定方法です。 この機能を使用する場合は、認証成功時のレスポンス JSON に `audio` や `audio_codec_type` や `audio_bit_rate` を指定してください。 ここで使用できるのはシグナリングの `"type": "connect"` 時に指定可能な `audio` の値です。 ```json { "allowed": true, "audio": true, "audio_codec_type": "OPUS", "audio_bit_rate": 64 } ``` #### 指定可能な値 - audio- `true` または `false` または object が指定可能です - audio_codec_type- "OPUS" - codec_type を指定しないことも可能です - audio_bit_rate- 6 ~ 510 - 単位は kbps です - **デフォルトで最適なビットレートが選択されるようになっているため指定する必要はありません** - audio_opus_params- **この機能はフラット構造でのみ利用可能です** - [オーディオの Opus 設定指定](SIGNALING.html#c82100) をオブジェクトとして指定可能です - audio_lyra_params- **この機能はフラット構造でのみ利用可能です** - [オーディオの Lyra 設定指定](SIGNALING.html#ba1209) をオブジェクトとして指定可能です ## video の払い出し クライアントが指定してきた映像のコーデックやビットレートなどのパラメータに対して、 認証サーバー側で新たに値を払い出すことで、上書きを行えます。 クライアントが指定してきた値を上書きすることができるため、 サーバー側でそれぞれのクライアントに対して、映像のコーデックやビットレートを指定することができます。 ### レガシーな払い出し例 > **重要** > > これは `sora.conf` にて [legacy_webhook_audio_video_json_structure](SORA_CONF.html#3be597) が `true` の場合の設定方法です。 > この設定は 2023 年 12 月リリース予定の Sora にて利用できなくなります。 この機能を使用する場合は、認証成功時のレスポンス JSON に `video` を指定してください。 ここで使用できるのはシグナリングの `"type": "connect"` 時に指定可能な `video` の値です。 ```json { "allowed": true, "video": { "codec_type": "VP9", "bit_rate": 1000 } } ``` #### 指定可能な値 - "video"- true または false または object が指定可能です - "codec_type"- 文字列で指定可能です - "VP8" - "VP9" - "AV1" - "H264" - "H265"- `sora.conf` にて [h265](SORA_CONF.html#2e0d28) を `true` にしている必要があります - codec_type を指定しないことも可能です - "bit_rate"- 1 ~ 30000- サポートされている値は 1 ~ 15000 までです - 単位は kbps です - bit_rate を指定しないことも可能です ### フラットな払い出し例 これは `sora.conf` にて [legacy_webhook_audio_video_json_structure](SORA_CONF.html#3be597) が `false` の場合の設定方法です。 この機能を使用する場合は、認証成功時のレスポンス JSON に `video` や `video_codec_type` や `video_bit_rate` を指定してください。 ここで使用できるのはシグナリングの `"type": "connect"` 時に指定可能な `video` の値です。 ```json { "allowed": true, "video": true, "video_codec_type": "VP9", "video_bit_rate": 1000 } ``` #### 指定可能な値 - "video"- true または false または object が指定可能です - "video_codec_type"- 文字列で指定可能です - "VP8" - "VP9" - "AV1" - "H264" - "H265"- `sora.conf` にて [h265](SORA_CONF.html#2e0d28) を `true` にしている必要があります - codec_type を指定しないことも可能です - "video_bit_rate"- 1 ~ 30000- サポートされている値は 1 ~ 15000 までです - 単位は kbps です - bit_rate を指定しないことも可能です ## client_id の払い出し Sora は認証成功時の戻り値に `client_id` を認証サーバーから返すことができます。 シグナリング接続時にも、 認証成功時の戻り値にも `client_id` を指定しない場合は `connection_id` と同じ値が `client_id` に割りあてられます。 ```json { "allowed": true, "client_id": "spam" } ``` - client_id- 1 から 255 の長さの文字列 ## bundle_id の払い出し Sora は認証成功時の戻り値に `bundle_id` を認証サーバーから返すことができます。 `bundle_id` を指定した場合、マルチストリーム利用時に `bundle_id` の値が同じ接続からの音声や映像、メッセージング、シグナリング通知を受信しなくなります。 シグナリング接続時にも、 認証成功時の戻り値にも `bundle_id` を指定しない場合は `connection_id` と同じ値が `bundle_id` に割りあてられます。 ```json { "allowed": true, "bundle_id": "spam" } ``` - bundle_id- 1 から 255 バイトの文字列 ## data_channel_signaling の払い出し Sora は、認証成功時のタイミングで接続単位での `data_channel_signaling` の値を認証サーバーから払い出すことが可能です。 ```json { "allowed": true, "data_channel_signaling": true } ``` この値は `"type": "connect"` の `data_channel_signaling` や `sora.conf` の [default_data_channel_signaling](SORA_CONF.html#adceef) の値を上書きします。 ### 認証成功時にクライアントが受け取る JSON ```json { "type": "offer", "sdp": "", "data_channel_signaling": true, "ignore_disconnect_websocket": false } ``` ## ignore_disconnect_websocket の払い出し Sora は、認証成功時のタイミングで接続単位での `ignore_disconnect_websocket` の値を認証サーバーから払い出すことが可能です。 ```json { "allowed": true, "ignore_disconnect_websocket": true } ``` この値は `"type": "connect"` の `ignore_disconnect_websocket` や `sora.conf` の [default_ignore_disconnect_websocket](SORA_CONF.html#58fe04) の値を上書きします。 ただし `data_channel_signaling` が `true` の時のみ、この値は有効になります。 ### 認証成功時にクライアントが受け取る JSON data_channel_signaling が有効な場合、 `"type": "switched"` が送られる際に `ignore_disconnect_websocket` も送られます。 ```json { "type": "switched", "ignore_disconnect_websocket": "", } ``` ## data_channels の払い出し Sora は、認証成功時のタイミングで接続単位での `data_channels` の値を認証サーバーから払い出すことができます。 ```json { "allowed": true, "data_channels": [ { "label": "#spam", "max_packet_life_time": 5000, "ordered": true, "protocol": "efg", "compress": false, "direction": "sendonly" }, { "label": "#egg", "max_retransmits": 0, "ordered": false, "protocol": "abc", "compress": false, "direction": "recvonly" } ] } ``` `data_channels` の詳細仕様は [data_channels 仕様](MESSAGING.html#ad1989) をご確認ください。 ## metadata の払い出し Sora は、認証成功時のタイミングで `metadata` という値を認証サーバーから払い出すことができます。 ```json { "allowed": true, "metadata": {"spam": "egg"} } ``` 認証サーバーが認証成功時に `metadata` を含めた場合、クライアントへ送る `"type": "offer"` に `metadata` をそのまま送ります。 この機能を使うことで、認証成功のタイミングでユーザー毎に任意の値を送ることができます。 ### 認証成功時にクライアントが受け取る JSON 認証成功の場合は Offer 送信時の JSON に `metadata` が含められます。 ```json { "type": "offer", "sdp": "", "metadata": {"spam": "egg"} } ``` ## event_metadata の払い出し **event_metadata はクライアントには送られません** Sora は、認証成功時のタイミングで `event_metadata` という値を認証サーバーから払い出すことができます。 認証サーバーが認証成功時に `event_metadata` を含めた場合、 イベントウェブフックリクエスト送信時に `event_metadata` という項目が追加されます。 ```json { "allowed": true, "event_metadata": {"pk": 1} } ``` `event_metadata` はクライアントに知られることのない値です。 Sora イベントウェブフックリクエスト送信先のサーバーのみが知り得る値となります。 ### 使用例 この `event_metadata` の値は、クライアントに知られることはありません。そのためユーザー ID を直接入れておくという仕組みも使用できます。 こうすることで通知の際、サーバー側がユーザーの判定をしやすくなります。 ## シグナリング経由での通知機能の払い出し Sora は、認証成功時のタイミングで `signaling_notify` という値を認証サーバーから払い出すことができます。 ```json { "allowed": true, "signaling_notify": true } ``` `signaling_notify` の値を返すことで、クライアント毎にシグナリング通知を受け取るかどうかを指定可能になります。 シグナリング経由での通知機能の詳細は ["type": "notify"](SIGNALING.html#c4828f) をご確認ください ### シグナリング経由での通知機能を利用したメタデータの払い出し Sora は、認証成功時のタイミングで `signaling_notify_metadata` という値を認証サーバーから払い出すことができます。 ここに値を指定することで、参加時や離脱時に外の参加者に情報を通知することができます。 ```json { "allowed": true, "signaling_notify_metadata": { "username": "spam" } } ``` 詳細は [signaling_notify_metadata](SORA_CONF.html#2d9340) をご確認ください。 ## ipv4_address と ipv6_address の払い出し Sora は、認証成功時のタイミングで `ipv4_address` または `ipv6_address` を認証サーバーから払い出すことができます。 `ipv4_address` と `ipv6_address` は片方だけでも、両方返しても問題ありません。 ```json { "allowed": true, "ipv4_address": "192.0.2.10", "ipv6_address": "2001:0DB8::10" } ``` この値は SDP の offer 時の a=candidate と TURN-UDP と TURN-TCP の URL の払い出しに使用されます。 `sora.conf` の値はこの戻り値で上書きされます。指定する IP アドレスを間違えると繋がらなくなるため、使用には注意してください。 この機能を使用することでクライアント毎に経路を指定することができます。 ## turn_fqdn 払い出し Sora は、認証成功時のタイミングで接続単位での `turn_fqdn` の値を認証サーバーから払い出すことができます。 ```json { "allowed": true, "turn_fqdn": "sora-turn.example.com" } ``` この値は `sora.conf` の [turn_fqdn](SORA_CONF.html#6513e4) の値を上書きします。 指定する FQDN を間違えると繋がらなくなるため、使用には注意してください。 ## turn_tls_fqdn の 払い出し Sora は、認証成功時のタイミングで接続単位での `turn_tls_fqdn` の値を認証サーバーから払い出すことができます。 ```json { "allowed": true, "turn_tls_fqdn": "sora-turn.example.com" } ``` この値は sora.conf の `turn_tls_fqdn` の値を上書きします。指定する FQDN を間違えると繋がらなくなるため、使用には注意してください。 この機能は `sora.conf` の [turn_tls_fqdn](SORA_CONF.html#3bfd30) の値を上書きします。 ## turn_tcp_only / turn_tls_only の払い出し Sora は、認証成功時のタイミングで接続単位での `turn_tcp_only` または `turn_tls_only` の値を認証サーバーから払い出すことができます。 ```json { "allowed": true, "turn_tcp_only": true } ``` ```json { "allowed": true, "turn_tls_only": true } ``` この値は `sora.conf` の [turn_tcp_only](SORA_CONF.html#479c51) や [turn_tls_only](SORA_CONF.html#58d702) の値を上書きします。 ## simulcast / simulcast_rid の払い出し Sora は、認証成功時のタイミングで接続単位での `simulcast` と `simulcast_rid` の値を認証サーバーから払い出すことが可能です。 ```json { "allowed": true, "simulcast": true } ``` ```json { "allowed": true, "simulcast": true, "simulcast_rid": "r0" } ``` この値は `sora.conf` の `default_simulcast_rid` の値を上書きします。 ## simulcast_encodings の払い出し Sora は、認証成功時のタイミングで接続単位での `simulcast_encodings` の値を認証サーバーから払い出すことが可能です。 ```json { "allowed": true, "simulcast_encodings": [ {"rid": "r0", "active": true, "scaleResolutionDownBy": 2.0, "maxFramerate": 1.0}, {"rid": "r1", "active": true, "scaleResolutionDownBy": 2.0, "maxFramerate": 10.0}, {"rid": "r2", "active": true, "scaleResolutionDownBy": 1.0, "maxFramerate": 30.0} ] } ``` 詳細については [サイマルキャスト](SIMULCAST.html) の [映像のエンコーディングパラメータのカスタマイズ](SIMULCAST.html#03a03b) をご確認ください。 ## spotlight_encodings の払い出し Sora は、認証成功時のタイミングで接続単位での `spotlight_encodings` の値を認証サーバーから払い出すことが可能です。 ```json { "allowed": true, "spotlight_encodings": [ {"rid": "r0", "active": true, "scaleResolutionDownBy": 4.0, "maxFramerate": 1.0}, {"rid": "r1", "active": true, "scaleResolutionDownBy": 1.0, "maxFramerate": 10.0}, {"rid": "r2", "active": false} ] } ``` 詳細については [サイマルキャスト](SIMULCAST.html) の [映像のエンコーディングパラメータのカスタマイズ](SIMULCAST.html#03a03b) をご確認ください。 ## spotlight / spotlight_number の払い出し Sora は、認証成功時のタイミングで接続単位での `spotlight` と `spotlight_number` の値を認証サーバーから払い出すことが可能です。 ```json { "allowed": true, "spotlight": true } ``` ```json { "allowed": true, "spotlight": true, "spotlight_number": 3 } ``` ## user_agent_stats の払い出し Sora は、認証成功時のタイミングで接続単位での `user_agent_stats` の値を認証サーバーから払い出すことが可能です。 ```json { "allowed": true, "user_agent_stats": true } ``` この値は `sora.conf` の [user_agent_stats](SORA_CONF.html#b8b6ef) の値を上書きします。 ## h264_profile_level_id の払い出し Sora は、認証成功時のタイミングで接続単位での `h264_profile_level_id` の値を認証サーバーから払い出すことが可能です。 ```json { "allowed": true, "h264_profile_level_id": "42e01f" } ``` この値は `sora.conf` の [default_h264_profile_level_id](SORA_CONF.html#8a25f5) の値を上書きします。 ## audio_streaming_language_code の払い出し Sora は、認証成功時のタイミングで音声ストリーミングのランゲージコードの値を認証サーバーから払い出すことが可能です。 ```json { "allowed": true, "audio_streaming_language_code": "ja-JP" } ``` この値は接続時の `audio_streaming_language_code` と `sora.conf` の [default_audio_streaming_language_code](SORA_CONF.html#856531) の値を上書きします。 # セッションウェブフック > **注意** > > セッションウェブフックは実験的機能のため、正式版では仕様が変更される可能性があります ## 概要 セッションウェブフックは、チャネルに誰も接続していない状態で新しく接続されたタイミングと、 誰も接続しない状態が一定時間続いたタイミングで、ウェブフックを利用してセッションの状態を HTTP リクエストで送信する機能です。 ## 目的 セッションは特定の期間にチャネルに接続していたクライアントを時間でグルーピングする仕組みです。 もともと Sora ではチャネルを作るという概念がありません。 誰もそのチャネルに接続していない状態で新しく接続があれば、新規チャネルが自動的に作られます。 そのため、チャネルが利用されているかされていないかの判断は HTTP API を利用したり、 イベントウェブフックリクエストの送信を利用したりして、アプリケーション側で判断する必要がありました。 このセッションウェブフックは新しくチャネルに状態を持たせ、 その状態をウェブフックリクエストで送信することで開発や運用のコストを減らすことができるようになります。 ## セッション ID 特定の期間チャネルに接続していたクライアントをグルーピングするために、 Sora はセッション ID という値を払い出します。 セッション ID は Sora が指定するため、書き換えることはできません。 セッション ID は UUIDv4 を Base32 でエンコードした 26 バイトの文字列です。 ### HTTP ヘッダー > **注釈** > > JSON のパース時の判断などに利用してください。 イベントウェブフックの HTTP ヘッダー に `x-sora-session-webhook-type` というヘッダー名でイベントウェブフックのタイプが入ってきます。 `type` が `session.created` の場合は `x-sora-session-webhook-type: session.created` のように値が入ってきます。 ## 設定 ### ウェブフックリクエスト送信先のサーバーがベーシック認証を利用している場合 もしウェブフックリクエスト送信先のサーバーがベーシック認証を利用している場合は `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` を設定することで証明書のチェックを行わないようになります。 ### session_webhook_url セッションウェブフックリクエストの送信先を指定してください。 ```ini session_webhook_url = https://example.com/sora/session/webhook ``` ### session_created_timeout セッションが存在しない状態で、新しくセッションを生成する際の制限時間です。 これはセッションウェブフック処理も含めた時間で、この時間を超えるとタイムアウトとなり、切断されます。 デフォルトでは 5 秒です。 ```ini session_created_timeout = 5 s ``` ### session_destroyed_timeout そのチャネルの接続数が 0 になってから、何秒間新しい接続が無い場合に `session.destoryed` のイベントウェブフックリクエストを送信するかどうかを指定します。 デフォルトでは 15 秒です。 ```ini session_destroyed_timeout = 15 s ``` ## ログ セッションウェブフックのログは `log/session_webhook.log` に出力されます。 これは `session_webhook_url` を指定していなくても出力されます。 ## `multistream` と `spotlight` が既存セッションと異なる場合の挙動 セッションが存在するタイミングでシグナリングのパラメータが異なる接続が来た場合、接続数によって挙動が変わります。 ### 既存セッションの接続数が 0 の場合 セッションの接続数が 0 のタイミングで `multistream` と `spotlight` がセッションと異なる新規接続が来た場合は既存のセッションを破棄し `session.destroyed` ウェブフックリクエストを送信します。その後に、新規でセッションを作成し `session.created` ウェブフックリクエストを送信します。 ### 既存セッションの接続数が 0 ではない場合 セッションの接続数が 0 ではないタイミングで `multistream` と `spotlight` がセッションと異なる新規接続が来た場合は `INVALID-SIGNALING-PARAMS` エラーを返し切断します。 ## session.created ウェブフック **セッション生成** 同時接続数が 0 のチャネル ID に新しい接続の認証が成功したタイミングで `session.created` ウェブフックリクエストを送信します。 チャネルの同時接続数が 0 の場合でも `multistream` および `spotlight` の値が一致するセッションが過去に生成されており、 まだ破棄されていない場合には、それが使用されるため `session.created` ウェブフックは送信されません。 * - キー - 型 - 内容 * - type - string - "session.created" * - id - string - ウェブフック ID (ユニーク) * - label - string - sora.conf の label にて指定した値 * - node_name - string - Sora ノード名 * - version - string - Sora のバージョン * - channel_id - string - チャネル ID * - session_id - string - セッション ID * - timestamp - string (RFC3339 UTC マイクロ秒) - ウェブフック作成時間 * - created_time - integer (UNIX 時間) - セッション作成時間 * - created_timestamp - integer (RFC3339 UTC マイクロ秒) - セッション作成時間 * - multistream - boolean - マルチストリームが有効かどうか * - spotlight - boolean - スポットライトが有効かどうか ```javascript { "channel_id": "sora", "created_time": 1638337454, "created_timestamp": "2021-12-01T05:44:14.523736Z", "id": "2YN2DQE5KD3GSFSVPAYZ7VTAV4", "label": "WebRTC SFU Sora", "multistream": true, "spotlight": false, "node_name": "sora@127.0.0.1", "session_id": "NPR769YPQ914K10FW42PGH4TKW", "timestamp": "2021-12-01T05:44:14.523912Z", "type": "session.created", "version": "2022.1.0" } ``` ### 戻り値 通常のイベントウェブフックとは異なり、セッションウェブフックは `"type": "session.created"` の戻り値を指定することができます。 #### session_metadata `session_metadata` を指定した場合、セッション終了時の `"type": "session.destroyed"` に `session_metadata` が含まれます。 ```javascript { "session_metadata": "" } ``` ## session.destoryed ウェブフック **セッション破棄** 同時接続数が 0 になったチャネル ID が一定時間経過したタイミングで `session.destroyed` ウェブフックリクエストを送信します。 * - キー - 型 - 内容 * - type - string - "session.destoryed" * - id - string - ウェブフック ID (ユニーク) * - label - string - sora.conf の label にて指定した値 * - node_name - string - Sora ノード名 * - version - string - Sora のバージョン * - channel_id - string - チャネル ID * - session_id - string - セッション ID * - timestamp - string (RFC3339 UTC マイクロ秒) - ウェブフック作成時間 * - created_time - integer (UNIX 時間) - セッション作成時間 * - created_timestamp - integer (RFC3339 UTC マイクロ秒) - セッション作成時間 * - destroyed_time - integer (UNIX 時間) - セッション破棄時間 * - destroyed_timestamp - integer (RFC3339 UTC マイクロ秒) - セッション破棄時間 * - multistream - boolean - マルチストリームが有効かどうか * - spotlight - boolean - スポットライトが有効かどうか * - total_connections - integer - 延べ接続数 * - max_connections - integer - 最大同時接続数 * - connections - array (object) - セッションに参加した接続情報 ```javascript { "channel_id": "sora", "connections": [ { "audio": { "codec_type": "OPUS" }, "client_id": "W9QE86Z0BS1QFFPZ2QB5DRZ2HC", "bundle_id": "W9QE86Z0BS1QFFPZ2QB5DRZ2HC", "connection_id": "W9QE86Z0BS1QFFPZ2QB5DRZ2HC", "created_timestamp": "2021-12-01T05:44:23.051704Z", "destroyed_timestamp": "2021-12-01T05:44:57.083215Z", "role": "sendrecv", "simulcast": false, "video": { "bit_rate": 1000, "codec_type": "VP9" } }, { "audio": { "codec_type": "OPUS" }, "client_id": "JXMYW6GPX54EH0HGA5X4130FBM", "bundle_id": "JXMYW6GPX54EH0HGA5X4130FBM", "connection_id": "JXMYW6GPX54EH0HGA5X4130FBM", "created_timestamp": "2021-12-01T05:44:21.500272Z", "destroyed_timestamp": "2021-12-01T05:44:56.878019Z", "role": "sendrecv", "simulcast": false, "video": { "bit_rate": 1000, "codec_type": "VP9" } }, { "audio": { "codec_type": "OPUS" }, "client_id": "F8VK9R71BN5S5EDE737C8XAA3C", "bundle_id": "F8VK9R71BN5S5EDE737C8XAA3C", "connection_id": "F8VK9R71BN5S5EDE737C8XAA3C", "created_timestamp": "2021-12-01T05:44:19.811385Z", "destroyed_timestamp": "2021-12-01T05:44:55.897819Z", "role": "sendrecv", "simulcast": false, "video": { "bit_rate": 1000, "codec_type": "VP9" } }, { "audio": { "codec_type": "OPUS" }, "client_id": "VBYS5TV5S510F98GS2VK015AKG", "bundle_id": "VBYS5TV5S510F98GS2VK015AKG", "connection_id": "VBYS5TV5S510F98GS2VK015AKG", "created_timestamp": "2021-12-01T05:44:14.716974Z", "destroyed_timestamp": "2021-12-01T05:44:57.197372Z", "role": "sendrecv", "simulcast": false, "video": { "bit_rate": 1000, "codec_type": "VP9" } } ], "created_time": 1638337454, "created_timestamp": "2021-12-01T05:44:14.523736Z", "destroyed_time": 1638337502, "destroyed_timestamp": "2021-12-01T05:45:02.199179Z", "id": "M7K1AVS9KS34V9XFJJH04TB400", "label": "WebRTC SFU Sora", "max_connections": 4, "multistream": true, "node_name": "sora@127.0.0.1", "session_id": "NPR769YPQ914K10FW42PGH4TKW", "spotlight": false, "timestamp": "2021-12-01T05:45:02.199419Z", "total_connections": 4, "type": "session.destroyed", "version": "2022.1.0" } ``` ## session.vanished ウェブフック Sora のモードが `block_new_session` または `block_new_connection` の時に、 全てのセッションがなくなったタイミングでウェブフックリクエストを送信します。 このウェブフックリクエストを受信するには `sora.conf` にて [ignore_session_vanished_webhook](SORA_CONF.html#85718d) を `false` に設定してください。 ```javascript { "id": "047MK20PWD14QBPBA2JAK585JM", "label": "WebRTC SFU Sora", "node_name": "sora@127.0.0.1", "timestamp": "2021-10-05T01:51:57.977800Z", "type": "session.vanished", "version": "2022.1.0" } ``` ## シーケンス図 seqdiag { default_fontsize = 12; edge_length = 200; クライアント1; クライアント2; Sora; アプリケーションサーバー クライアント1 ->> Sora [label = '"type": "type"']; Sora -> アプリケーションサーバー [label = 'セッションウェブフック\n"type": "session.created"']; Sora <-- アプリケーションサーバー [label = '200 OK']; クライアント1 <<- Sora [label = '"type": "offer"']; クライアント1 ->> Sora [label = '"type": "answer"', noactivate]; === クライアント1 WebRTC 確立 === Sora -> アプリケーションサーバー [label = 'イベントウェブフック\n"type": "connection.created"']; Sora <-- アプリケーションサーバー [label = '200 OK']; クライアント2 ->> Sora [label = '"type": "type"']; クライアント2 <<- Sora [label = '"type": "offer"']; クライアント2 ->> Sora [label = '"type": "answer"', noactivate]; === クライアント2 WebRTC 確立 === Sora -> アプリケーションサーバー [label = 'イベントウェブフック\n"type": "connection.created"']; Sora <-- アプリケーションサーバー [label = '200 OK']; クライアント1 ->> Sora [label = '"type": "disconnect"', noactivate]; Sora -> アプリケーションサーバー [label = 'イベントウェブフック\n"type": "connection.destroyed"']; Sora <-- アプリケーションサーバー [label = '200 OK']; クライアント1 <<- Sora [label = 'WebSocket Close']; === クライアント2 WebRTC 切断 === クライアント2 ->> Sora [label = '"type": "disconnect"', noactivate]; Sora -> アプリケーションサーバー [label = 'イベントウェブフック\n"type": "connection.destroyed"']; Sora <-- アプリケーションサーバー [label = '200 OK']; クライアント2 <<- Sora [label = 'WebSocket Close']; === クライアント2 WebRTC 切断 === ... 接続数 0 から 15 秒経過 ... Sora -> アプリケーションサーバー [label = 'セッションウェブフック\n"type": "session.destoryed"']; Sora <-- アプリケーションサーバー [label = '200 OK']; ... セッションがすべて破棄された ... Sora -> アプリケーションサーバー [label = 'セッションウェブフック\n"type": "session.vanished"']; Sora <-- アプリケーションサーバー [label = '200 OK']; } # イベントウェブフック ## 概要 Sora は、予め設定しておいた URL に、シグナリングの接続や切断、 録画の終了といった様々なイベントを HTTP リクエストとして送信するウェブフックの機能を持っています。 この機能を使うことで、Sora のイベントをアプリケーション側と簡単に連携することが可能です。 ## 注意 `sora.conf` の [event_webhook_url](SORA_CONF.html#e1a4d2) を有効にしない場合でも `log/event_webhook.log` または `log/event_webhook.jsonl` は生成されます。 ## 設定 ### ウェブフックリクエスト送信先のサーバーがベーシック認証を利用している場合 もしウェブフックリクエスト送信先のサーバーがベーシック認証を利用している場合は `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 を指定する場合、リクエスト送信先のアプリケーションについて基本的には正規の認証局から発行された証明書を利用してください。 独自の証明書を利用する場合は [ウェブフックリクエスト送信先のサーバーが自己署名証明書などを利用している場合](EVENT_WEBHOOK.html#467c4b) をご確認ください。 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 です - `sora.conf` の [legacy_webhook_audio_video_json_structure](SORA_CONF.html#3be597) を `false` にした場合以下のようにフラット化します- `audio: true` - `audio_codec_type: "OPUS"` - `audio_bit_rate: 32` - 詳細は [ウェブフックの audio と video 項目の JSON 構造のフラット化](WEBHOOK_AUDIO_VIDEO_FLATTEN_JSON.html) をご確認ください - video- false の場合は video を使用しません - コーデックやビットレートが入ってくる場合は {"codec_type": "VP9", "bit_rate": 100} が入ってきます- コーデックの種類は VP8、VP9、AV1、H264、H265 の 5 種類です - ビットレートはクライアントが送ってこない場合は `sora.conf` の [default_video_bit_rate](SORA_CONF.html#620132) が使用されます- デフォルトは 500 です - 最小が 1 で、最大が 30000 です - 15000 より大きい値は現時点でサポート外です - `sora.conf` の [legacy_webhook_audio_video_json_structure](SORA_CONF.html#3be597) を `false` にした場合以下のようにフラット化します- `video: true` - `video_codec_type: "VP8"` - `video_bit_rate: 500` - 詳細は [ウェブフックの audio と video 項目の JSON 構造のフラット化](WEBHOOK_AUDIO_VIDEO_FLATTEN_JSON.html) をご確認ください - 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": "", "session_id": "", "client_id": "", "bundle_id": "", "connection_id": "", "timestamp": "", "event_metadata": "", "data": { "created_time": "", "created_timestamp": "", "audio": { "codec_type": "" }, "channel_connections": "", "channel_recvonly_connections": "", "channel_sendonly_connections": "", "channel_sendrecv_connections": "", "minutes": "", "total_received_bytes": "", "total_sent_bytes": "", "turn_transport_type": "", "video": { "bit_rate": "", "codec_type": "" } }, "id": "", "label": "", "multistream": "", "node_name": "", "role": "", "simulcast": "", "spotlight": "", "version": "" } ``` ### 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": "", "session_id": "", "client_id": "", "bundle_id": "", "connection_id": "", "timestamp": "", "event_metadata": "", "data": { "created_time": "", "created_timestamp": "", "destroyed_time": "", "destroyed_timestamp": "", "audio": { "codec_type": "" }, "channel_connections": "", "channel_recvonly_connections": "", "channel_sendonly_connections": "", "channel_sendrecv_connections": "", "minutes": "", "reason": "", "type_disconnect_reason": "", "total_received_bytes": "", "total_sent_bytes": "", "turn_transport_type": "", "video": { "bit_rate": "", "codec_type": "VP9" } }, "id": "", "label": "", "multistream": "", "node_name": "", "role": "", "simulcast": "", "spotlight": "", "version": "" } ``` ### 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": "", "session_id": "", "client_id": "", "bundle_id": "", "connection_id": "", "timestamp": "", "event_metadata": "", "data": { "audio": { "codec_type": "" }, "channel_connections": , "channel_recvonly_connections": "", "channel_sendonly_connections": "", "channel_sendrecv_connections": "", "created_time": "", "created_timestamp": "", "minutes": "", "total_received_bytes": "", "total_sent_bytes": "", "turn_transport_type": "", "video": { "bit_rate": "", "codec_type": "" } }, "id": "", "label": "", "multistream": "", "node_name": "", "role": "", "simulcast": "", "spotlight": "", "version": "" } ``` ### connection.failed **接続失敗** > **重要** > > このイベントを受信する場合は、 `sora.conf` にて [ignore_connection_failed_webhook](SORA_CONF.html#45096a) を無効にする必要があります。 シグナリングが失敗したり、異常が起きたりした場合に送信されます。 ```json { "type": "connection.failed", "id": "", "role": "", "channel_id": "", "client_id": "", "bundle_id": "", "connection_id": "", "timestamp": "", "data": { "message": "", "channel_connections": "", "channel_sendrecv_connections": "", "channel_sendonly_connections": "", "channel_recvonly_connections": "", "total_received_bytes": "", "total_sent_bytes": "" }, "label": "", "multistream": "", "node_name": "", "simulcast": "", "spotlight": "", "version": "" } ``` ## 録画・録音イベント ### recording.started > **重要** > > このイベントには `event_metadata` は含まれません **録画開始** - data.metadata- StartRecording API で指定した metadata が入ります - 指定していない場合は `metadata` の項目が入ってきません ```json { "type": "recording.started", "id": "", "version": "", "label": "", "node_name": "", "channel_id": "", "timestamp": "", "data": { "channel_id": "", "recording_id": "", "metadata": "", "split_only": "", "created_at": "", "expire_time": "", "expired_at": "" } } ``` ### recording.report > **重要** > > このイベントには `event_metadata` は含まれません **録画結果報告** - data.archives[].start_time_offset- StartRecording API を叩いてから何秒経過した後にこの録画が開始したかを表しています - data.archives[].stop_time_offset- StartRecording API を叩いてから何秒経過した後にこの録画が終了したかを表しています - data.metadata- StartRecording API で指定した metadata が入ります - 指定していない場合は `metadata` の項目が入ってきません - data.expired_at- 期限が切れた日時を UNIX Time で返します #### 一括録画時 recording.report ```json { "type": "recording.report", "id": "", "version": "", "label": "", "node_name": "", "channel_id": "", "timestamp": "", "data": { "channel_id": "", "recording_id": "", "metadata": "", "split_only": "", "created_at": "", "expire_time": "", "expired_at": "", "file_path": "", "filename": "", "start_timestamp": "", "stop_timestamp": "", "archives": [ { "label": "", "node_name": "", "client_id": "", "bundle_id": "", "connection_id": "", "file_path": "", "filename": "", "metadata_file_path": "", "metadata_filename": "", "start_time_offset": "", "start_timestamp": "", "stop_time_offset": "", "stop_timestamp": "", "size": "" }, { "label": "", "node_name": "", "client_id": "", "bundle_id": "", "connection_id": "", "file_path": "", "filename": "", "metadata_file_path": "", "metadata_filename": "", "start_time_offset": "", "start_timestamp": "", "stop_time_offset": "", "stop_timestamp": "", "size": "" } ] } } ``` #### 分割録画時 recording.report ```json { "type": "recording.report", "id": "", "version": "", "label": "", "node_name": "", "channel_id": "", "timestamp": "", "data": { "channel_id": "", "recording_id": "", "metadata": "", "split_only": "", "split_duration": "", "created_at": "", "expire_time": "", "expired_at": "", "file_path": "", "filename": "", "start_timestamp": "", "stop_timestamp": "", "archives": [ { "label": "", "node_name": "", "client_id": "", "bundle_id": "", "connection_id": "", "start_time_offset": "", "start_timestamp": "", "stop_time_offset": "", "stop_timestamp": "", "split_last_index": "" }, { "label": "", "node_name": "", "client_id": "", "bundle_id": "", "connection_id": "", "start_time_offset": "", "start_timestamp": "", "stop_time_offset": "", "stop_timestamp": "", "split_last_index": "" } ] } } ``` ## 録画・録音保存イベント ### archive.started **録画ファイル保存開始** ```json { "type": "archive.started", "id": "", "version": "", "label": "", "node_name": "", "channel_id": "", "session_id": "", "client_id": "", "bundle_id": "", "connection_id": "", "timestamp": "", "event_metadata": "", "data": { "channel_id": "", "recording_id": "", "session_id": "", "client_id": "", "bundle_id": "", "connection_id": "", "created_at": "", "audio": { "codec_type": "" }, "video": { "codec_type": "", "bit_rate": "", "height": "", "width": "" }, "start_time": "", "start_time_offset": "", "start_timestamp": "" } } ``` ### 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": "", "version": "", "label": "", "node_name": "", "channel_id": "", "session_id": "", "client_id": "", "bundle_id": "", "connection_id": "", "timestamp": "", "event_metadata": "", "data": { "channel_id": "", "recording_id": "", "session_id": "", "client_id": "", "bundle_id": "", "connection_id": "", "created_at": "", "file_path": "", "filename": "", "metadata_file_path": "", "metadata_filename": "", "size": "", "audio": { "codec_type": "" }, "video": { "codec_type": "", "bit_rate": "", "height": "", "width": "" }, "stats": {}, "start_time": "", "start_time_offset": "", "start_timestamp": "", "stop_time": "", "stop_time_offset": "", "stop_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.start_time_offset- この分割して出力された録画が、StartRecording API を叩いてから何秒経過した後に開始したかを表しています - data.stop_time_offset- この分割して出力された録画が、StartRecording API を叩いてから何秒経過した後に終了したかを表しています - data.stats- サポート向けに、録画に使用したパケット情報の統計を格納しています - 内部向け情報のため、予告なく変更されることがあります ```json { "type": "split-archive.available", "id": "", "version": "", "label": "", "node_name": "", "channel_id": "", "session_id": "", "client_id": "", "bundle_id": "", "connection_id": "", "timestamp": "", "event_metadata": "", "data": { "channel_id": "", "recording_id": "", "split_index": "", "session_id": "", "client_id": "", "bundle_id": "", "connection_id": "", "created_at": "", "file_path": "", "filename": "", "metadata_file_path": "", "metadata_filename": "", "size": "", "video": { "codec_type": "", "bit_rate": "", "height": "", "width": "" }, "audio": { "codec_type": "" }, "stats": { }, "start_time": "", "start_time_offset": "", "start_timestamp": "", "stop_time": "", "stop_time_offset": "", "stop_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": "", "version": "", "label": "", "node_name": "", "channel_id": "", "session_id": "", "client_id": "", "bundle_id": "", "connection_id": "", "timestamp": "", "event_metadata": "", "data": { "split_last_index": "", "recording_id": "", "channel_id": "", "session_id": "", "client_id": "", "bundle_id": "", "connection_id": "", "video": { "codec_type": "", "bit_rate": "" }, "audio": { "codec_type": "", "bit_rate": "" }, "file_path": "", "filename": "", "stats": {}, "start_time": "", "start_time_offset": "", "start_timestamp": "", "stop_time": "", "stop_time_offset": "", "stop_timestamp": "", } } ``` ### archive.failed **録画ファイル保存失敗** ```json { "type": "archive.failed", "id": "", "version": "", "label": "", "node_name": "", "timestamp": "", "channel_id": "", "session_id": "", "client_id": "", "bundle_id": "", "connection_id": "", "event_metadata": "", "data": { "recording_id": "", "session_id": "", "file_path": "", "filename": "", "video": { "codec_type": "", "bit_rate": "", "height": "", "width": "" }, "audio": { "codec_type": "" }, "stats": {}, "start_time": "", "start_timestamp": "", "stop_time": "", "stop_timestamp": "", } } ``` ## スポットライト機能 ### spotlight.focused **フォーカス設定** フォーカスされた際にウェブフックが飛びます。 ```json { "type": "spotlight.focused", "channel_id": "", "client_id": "", "bundle_id": "", "connection_id": "", "timestamp": "", "spotlight_number:": "", "fixed": "", "id": "", "label": "", "version": "", "audio": "", "video": "" } ``` ### spotlight.unfocused **フォーカス解除** フォーカスが外れた際にウェブフックが飛びます。 ```json { "type": "spotlight.unfocused", "channel_id": "", "client_id": "", "bundle_id": "", "connection_id": "", "timestamp": "", "spotlight_number:": "", "audio": "", "id": "", "label": "", "version": "", "audio": "", "video": "" } ``` ## シーケンス図 ### 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']; } # ウェブフックの型定義 ここではウェブフックの型について説明します。 型の表記は TypeScript で記述します。 ## 基本的なデータ型 ```typescript // JSON 値を表します。 // 仕様は RFC 8259 に従います。 type JSONValue = | null | boolean | number | string | JSONValue[] | { [key: string]: JSONValue | undefined } // ストリームの種別 type Role = 'sendrecv' | 'sendonly' | 'recvonly' // サイマルキャストで配信する映像の種類 type SimulcastRid = 'r0' | 'r1' | 'r2' // 音声の設定 type Audio = | boolean | { codec_type?: AudioCodecType bit_rate?: number lyra_params?: LyraParams opus_params?: OpusParams } type LyraParams = { version?: string bitrate?: number } type OpusParams = { channels?: number maxplaybackrate?: number minptime?: number ptime?: number stereo?: boolean sprop_stereo?: boolean useinbandfec?: boolean usedtx?: boolean } // 映像の設定 type Video = | boolean | { codec_type?: VideoCodecType bit_rate?: number } // 音声コーデックの種類 type AudioCodecType = 'OPUS' | 'LYRA' // 映像コーデックの種類 type VideoCodecType = 'VP9' | 'VP8' | 'AV1' | 'H264' | 'H265' // DataChannel の方向 type Direction = 'sendrecv' | 'sendonly' | 'recvonly' // DataChannels type DataChannel = { label: string direction: Direction ordered?: boolean max_packet_life_time?: number max_retransmits?: number protocol?: string compress?: boolean } // SoraClient type SoraClient = { environment?: string raw?: string type?: string version?: string commit_short?: string libwebrtc?: string } ``` ## ウェブフック共通のデータ型 ```typescript // ウェブフックで通知される音声の設定 type WebhookAudio = | boolean | { codec_type?: AudioCodecType bit_rate?: number } ``` ## 完全な型定義 ### 認証ウェブフック ```typescript // 認証ウェブフックリクエスト type AuthWebhookRequest = { timestamp: string version: string label: string node_name: string role: Role channel_id: string client_id?: string bundle_id?: string connection_id: string multistream: boolean simulcast: boolean // Sora 2023.1 で simulcast が false の場合は入ってこなくなります simulcast_rid: SimulcastRid spotlight: boolean audio: WebhookAudio audio_codec_type?: string audio_bit_rate?: number video: Video video_codec_type?: string video_bit_rate?: number data_channel_signaling: boolean ignore_disconnect_websocket: boolean data_channels?: [DataChannel] channel_connections: number channel_sendrecv_connections: number channel_sendonly_connections: number channel_recvonly_connections: number e2ee: boolean sora_client?: SoraClient auth_metadata?: JSONValue metadata?: JSONValue } // 認証ウェブフック成功レスポンス // 200 OK で返してください type AuthWebhookAcceptResponse = { allowed: true audio?: Audio audio_codec_type?: string audio_bit_rate?: number audio_lyra_params?: LyraParams audio_opus_params?: OpusParams video?: Video video_codec_type?: string video_bit_rate?: number bundle_id?: string client_id?: string data_channel_signaling?: boolean ignore_disconnect_websocket?: boolean data_channels?: [DataChannel] simulcast?: boolean simulcast_rid?: SimulcastRid simulcast_encodings?: [SimulcastEncoding] spotlight?: boolean spotlight_number?: number spotlight_focus_rid?: 'none' | SimulcastRid spotlight_unfocus_rid?: 'none' | SimulcastRid spotlight_encodings?: [SimulcastEncoding] turn_fqdn?: string turn_tls_fqdn?: string signaling_notify?: boolean signaling_notify_metadata?: JSONValue h264_profile_level_id?: string user_agent_stats?: boolean metadata?: JSONValue event_metadata?: JSONValue ipv4_address?: string ipv6_address?: string audio_streaming_language_code?: string turn_tcp_only?: boolean turn_tls_only?: boolean rtp_packet_loss_simulator_incoming?: number rtp_packet_loss_simulator_outgoing?: number } type SimulcastEncoding = { rid: SimulcastRid active?: boolean scaleResolutionDownBy?: number maxBitrate?: number maxFramerate?: number adaptivePtime?: boolean } // 認証ウェブフック失敗レスポンス // 200 OK で返してください type AuthWebhookRejectResponse = { allowed: false reason: string } ``` ### セッションウェブフック ```typescript // セッションウェブフック生成リクエスト type SessionWebhookCreatedRequest = { type: 'session.created' timestamp: string id: string version: string label: string node_name: string channel_id: string session_id: string multistream: boolean spotlight: boolean created_time: number created_timestamp: string } // 200 OK で返していください type SessionWebhookCreatedResponse = { session_metadata?: JSONValue audio_streaming?: boolean } // セッションウェブフック破棄リクエスト type SessionWebhookDestroyedRequest = { type: 'session.destroyed' timestamp: string id: string version: string label: string node_name: string channel_id: string session_id: string multistream: boolean spotlight: boolean created_time: number created_timestamp: string destroyed_time: number destroyed_timestamp: string max_connections: number total_connections: number session_metadata?: JSONValue connections?: [SessionConnection] } type SessionConnection = { role: Role client_id: string bundle_id: string connection_id: string simulcast: boolean audio: WebhookAudio audio_codec_type?: string audio_bit_rate?: number video: Video video_codec_type?: string video_bit_rate?: number connection_created_timestamp: string connection_destroyed_timestamp: string event_metadata?: JSONValue } // セッションウェブフック全破棄リクエスト type SessionWebhookVanishedRequest = { type: 'session.vanished' timestamp: string id: string version: string label: string node_name: string } ``` ### イベントウェブフック ```typescript // イベントコネクション生成ウェブフックリクエスト type EventWebhookConnectionCreatedRequest = { type: 'connection.created' timestamp: string id: string version: string label: string node_name: string role: Role channel_id: string session_id: string client_id: string bundle_id: string connection_id: string multistream: boolean simulcast: boolean spotlight: boolean event_metadata?: JSONValue data: EventWebhookConnectionCreatedData } // イベントコネクション生成ウェブフックデータ type EventWebhookConnectionCreatedData = { minutes: number audio: WebhookAudio audio_codec_type?: AudioCodecType audio_bit_rate?: number video: Video video_codec_type?: VideoCodecType video_bit_rate?: number channel_connections: number channel_sendrecv_connections: number channel_sendonly_connections: number channel_recvonly_connections: number turn_transport_type: 'udp' | 'tcp' created_time: number created_timestamp: string total_received_bytes: number total_sent_bytes: number } // イベントコネクション更新ウェブフックリクエスト type EventWebhookConnectionUpdatedRequest = { type: 'connection.updated' timestamp: string id: string version: string label: string node_name: string role: Role channel_id: string session_id: string client_id: string bundle_id: string connection_id: string multistream: boolean simulcast: boolean spotlight: boolean event_metadata?: JSONValue data: EventWebhookConnectionUpdatedData } // イベントコネクション更新ウェブフックデータ type EventWebhookConnectionUpdatedData = { minutes: number audio: WebhookAudio audio_codec_type?: AudioCodecType audio_bit_rate?: number video: Video video_codec_type?: VideoCodecType video_bit_rate?: number channel_connections: number channel_sendrecv_connections: number channel_sendonly_connections: number channel_recvonly_connections: number turn_transport_type: 'udp' | 'tcp' created_time: number created_timestamp: string total_received_bytes: number total_sent_bytes: number } // イベントコネクション破棄ウェブフックリクエスト type EventWebhookConnectionDestroyedRequest = { type: 'connection.destroyed' timestamp: string id: string version: string label: string node_name: string role: Role channel_id: string session_id: string client_id: string bundle_id: string connection_id: string multistream: boolean simulcast: boolean spotlight: boolean event_metadata?: JSONValue data: EventWebhookConnectionDestroyedData } // イベントコネクション破棄ウェブフックデータ type EventWebhookConnectionDestroyedData = { minutes: number audio: WebhookAudio audio_codec_type?: AudioCodecType audio_bit_rate?: number video: Video video_codec_type?: VideoCodecType video_bit_rate?: number channel_connections: number channel_sendrecv_connections: number channel_sendonly_connections: number channel_recvonly_connections: number turn_transport_type: 'udp' | 'tcp' created_time: number created_timestamp: string destroyed_time: number destroyed_timestamp: string total_received_bytes: number total_sent_bytes: number reason?: string disconnect_api_reason?: string type_disconnect_reason?: string } type EventWebhookConnectionFailedRequest = { type: 'connection.failed' timestamp: string id: string version: string label: string node_name: string role?: Role channel_id?: string client_id?: string bundle_id?: string connection_id: string multistream: boolean simulcast: boolean spotlight: boolean data: EventWebhookConnectionFailedData } type EventWebhookConnectionFailedData = { message: string channel_connections: number channel_sendrecv_connections: number channel_sendonly_connections: number channel_recvonly_connections: number total_received_bytes: number total_sent_bytes: number } ``` ### イベントウェブフック (録画) ```typescript type EventWebhookRecordingStartedRequest = { type: 'recording.started' timestamp: string id: string version: string label: string node_name: string channel_id: string data: EventWebhookRecordingStartedData } type EventWebhookRecordingStartedData = { channel_id: string recording_id: string metadata?: JSONValue split_only: boolean created_at: number expire_time: number expired_at: number } type EventWebhookRecordingReportRequest = { type: 'recording.report' timestamp: string id: string version: string label: string node_name: string channel_id: string data: EventWebhookRecordingReportData } type EventWebhookRecordingReportData = { channel_id: string recording_id: string metadata?: JSONValue split_only: boolean split_duration?: number created_at: number expire_time: number expired_at: number file_path: string filename: string start_timestamp: string stop_timestamp: string archives: [EventWebhookRecordingReportArchive] } type EventWebhookRecordingReportArchive = { label: string node_name: string client_id: string bundle_id: string connection_id: string file_path?: string filename?: string metadata_file_path?: string metadata_filename?: string start_time_offset: number start_timestamp: string stop_time_offset: number stop_timestamp: string size?: number split_last_index?: string } type EventWebhookArchiveStartedRequest = { type: 'archive.started' timestamp: string id: string version: string label: string node_name: string channel_id: string session_id: string client_id: string bundle_id: string connection_id: string event_metadata?: JSONValue data: EventWebhookArchiveStartedData } type ArchiveVideo = | boolean | { codec_type?: VideoCodecType bit_rate?: number height?: number width?: number } type EventWebhookArchiveStartedData = { recording_id: string channel_id: string session_id: string client_id: string bundle_id: string connection_id: string created_at: number audio: WebhookAudio audio_codec_type?: string audio_bit_rate?: number video: Video video_codec_type?: string video_bit_rate?: number start_time: number start_time_offset: number start_timestamp: string } type EventWebhookArchiveAvailableRequest = { type: 'archive.available' timestamp: string id: string version: string label: string node_name: string channel_id: string session_id: string client_id: string bundle_id: string connection_id: string event_metadata?: JSONValue data: EventWebhookArchiveAvailableData } type EventWebhookArchiveAvailableData = { recording_id: string channel_id: string session_id: string client_id: string bundle_id: string connection_id: string file_path: string filename: string metadata_file_path: string metadata_filename: string size: number created_at: number audio: WebhookAudio audio_codec_type?: string audio_bit_rate?: number video: ArchiveVideo video_codec_type?: string video_bit_rate?: number video_height?: number video_width?: number start_time: number start_time_offset: number start_timestamp: string stop_time: number stop_time_offset: number stop_timestamp: string stats: JSONValue } type EventWebhookSplitArchiveAvailableRequest = { type: 'split-archive.available' id: string timestamp: string version: string label: string node_name: string channel_id: string session_id: string client_id: string bundle_id: string connection_id: string event_metadata?: JSONValue data: EventWebhookSplitArchiveAvailableData } type EventWebhookSplitArchiveAvailableData = { recording_id: string channel_id: string session_id: string client_id: string bundle_id: string connection_id: string split_index: string file_path: string filename: string metadata_file_path: string metadata_filename: string size: number created_at: number audio: WebhookAudio audio_codec_type?: string audio_bit_rate?: number video: ArchiveVideo video_codec_type?: string video_bit_rate?: number video_height?: number video_width?: number start_time: number start_time_offset: number start_timestamp: string stop_time: number stop_time_offset: number stop_timestamp: string stats: JSONValue } type EventWebhookSplitArchiveEndRequest = { type: 'split-archive.end' id: string timestamp: string version: string label: string node_name: string channel_id: string session_id: string client_id: string bundle_id: string connection_id: string event_metadata?: JSONValue data: EventWebhookSplitArchiveEndData } type EventWebhookSplitArchiveEndData = { split_last_index: string recording_id: string channel_id: string session_id: string client_id: string bundle_id: string connection_id: string file_path: string filename: string audio: WebhookAudio audio_codec_type?: string audio_bit_rate?: number video: Video video_codec_type?: string video_bit_rate?: number start_time: number start_time_offset: number start_timestamp: string stop_time: number stop_time_offset: number stop_timestamp: string stats: JSONValue } type EventWebhookArchiveFailedRequest = { type: 'archive.failed' timestamp: string id: string version: string label: string node_name: string channel_id: string session_id: string client_id: string bundle_id: string connection_id: string event_metadata?: JSONValue data: EventWebhookSplitArchiveFailedData } type EventWebhookSplitArchiveFailedData = { recording_id: string session_id: string file_path: string filename: string audio: WebhookAudio audio_codec_type?: string audio_bit_rate?: number video: ArchiveVideo video_codec_type?: string video_bit_rate?: number video_height?: number video_width?: number start_time: number start_timestamp: string stop_time: number stop_timestamp: string stats: JSONValue } ``` ### イベントウェブフック (スポットライト) ```typescript type EventWebhookSpotlightFocusedRequest = { type: 'spotlight.focused' timestamp: string id: string version: string label: string node_name: string channel_id: string client_id: string bundle_id: string connection_id: string spotlight_number: number fixed: boolean audio: boolean video: boolean } type EventWebhookSpotlightUnfocusedRequest = { type: 'spotlight.unfocused' timestamp: string id: string version: string label: string node_name: string channel_id: string client_id: string bundle_id: string connection_id: string spotlight_number: number audio: boolean video: boolean } ``` # API ## 概要 API は Sora に対して HTTP 経由で実行できます。 ## 用語 - object- `JSON Object` です - [HTTPie](https://httpie.io/) では `key:='{"spam": "egg"}'` のように指定してください ## API の種類 ### API 正式リリースされている API ### 実験的 API 仕様が確定していない API 詳細は [実験的 API](EXPERIMENTAL_API.html) をご確認ください。 ### 非推奨 API 期限が来たら廃止される API 詳細は [非推奨 API](DEPRECATED_API.html) をご確認ください。 ### 廃止 API 廃止された API 詳細は [廃止 API](OBSOLETE_API.html) をご確認ください。 ## x-sora-target ヘッダー API は [DynamoDB や Route53 などの AWS API が独特な仕様なので紹介](https://gist.github.com/voluntas/811240c5b6a169ae1c6ac401e0197417) を参考にしており、 `x-sora-target` というヘッダーを使って実行します。 - 全ての API は POST を使用します - すべての API の PATH は `/` です - リクエストの Body には JSON を使用します - レスポンスの Body には JSON を使用します ## 設定 ### api_port API のポート番号を変更したい場合は `sora.conf` の [api_port](SORA_CONF.html#4adab7) にて、 API のポート番号を設定してください。 デフォルトでは 3000 番を利用します。 ```ini api_port = 3000 ``` ### api_loopback_address_only API へのアクセスをループバックアドレスからのみに制限します。 本番環境では可能な限り有効にしてください。 ```ini api_loopback_address_only = true ``` ### api_cors_origin > **警告** > > 本番環境ではこの設定は有効にしないでください。 API をクロスドメインで使用したい場合に設定します。 ```ini api_cors_origin = http://127.0.0.1:5000 ``` こうすることで、ブラウザで `http://127.0.0.1:5000` から API を叩くことができるようになります。 ## HTTPie ここでの例では HTTPie という Python のライブラリを使用しています。 [As easy as /aitch-tee-tee-pie/ 🥧 Modern, user-friendly command-line HTTP client for the API era. JSON support, colors, sessions, downloads, plugins & more.](https://github.com/httpie/httpie) > **注釈** > > 時雨堂は HTTPie 作者のスポンサーです ### インストール - Ubuntu は `apt install httpie` で入ります - CentOS は `yum install httpie` で入ります - macOS は `brew install httpie` または `port install httpie` で入ります 詳細は をご確認下さい。 ## シグナリング API ### DisconnectChannel **x-sora-target**: Sora_20151104.DisconnectChannel 指定したチャネルの接続をすべて切断します。 **リクエスト JSON** * - キー - 型 * - channel_id - string * - reason (オプション) - object `reason` に値を指定した場合、イベントウェブフック `connection.destroyed` の `disconnect_api_reason` および `reason` に指定した値が入ってきます。 ```console $ http POST 127.0.0.1:3000 \ x-sora-target:Sora_20151104.DisconnectChannel \ channel_id=sora \ -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 22 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.4.0 x-sora-target: Sora_20151104.DisconnectChannel { "channel_id": "sora" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 21 content-type: application/json date: Wed, 07 Jul 2021 05:44:01 GMT server: Cowboy { "channel_id": "sora" } ``` ### DisconnectClient **x-sora-target**: Sora_20151104.DisconnectClient 指定したクライアント ID の接続をすべて切断します。 **リクエスト JSON** * - キー - 型 * - channel_id - string * - client_id - string * - reason (オプション) - object `reason` に値を指定した場合、イベントウェブフック `connection.destroyed` の `disconnect_api_reason` および `reason` に指定した値が入ってきます。 ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20151104.DisconnectClient \ channel_id=sora \ client_id=E2APPNQ9P97Q32V2ABW546SWW8 \ -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 65 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.4.0 x-sora-target: Sora_20151104.DisconnectClient { "channel_id": "sora", "client_id": "E2APPNQ9P97Q32V2ABW546SWW8" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 62 content-type: application/json date: Wed, 07 Jul 2021 05:45:09 GMT server: Cowboy { "channel_id": "sora", "client_id": "E2APPNQ9P97Q32V2ABW546SWW8" } ``` ### DisconnectConnection **x-sora-target**: Sora_20151104.DisconnectConnection 指定したコネクション ID の接続を切断します。 **リクエスト JSON** * - キー - 型 * - channel_id - string * - connection_id - string * - reason (オプション) - object `reason` に値を指定した場合、イベントウェブフック `connection.destroyed` の `disconnect_api_reason` および `reason` に指定した値が入ってきます。 ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20151104.DisconnectConnection \ channel_id=sora \ connection_id=T34CDBMRJS1B5BVPF17RTBQA3C \ -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 69 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.4.0 x-sora-target: Sora_20151104.DisconnectConnection { "channel_id": "sora", "connection_id": "T34CDBMRJS1B5BVPF17RTBQA3C" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 66 content-type: application/json date: Wed, 07 Jul 2021 05:59:41 GMT server: Cowboy { "channel_id": "sora", "connection_id": "T34CDBMRJS1B5BVPF17RTBQA3C" } ``` ### DisconnectChannelByRole **x-sora-target**: Sora_20201120.DisconnectChannelByRole 指定したチャネルの指定したロールの接続を切断します。 * - キー - 型 * - channel_id - string * - role - string (sendrecv | sendonly | recvonly) ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20201120.DisconnectChannelByRole \ channel_id=sora \ role=sendrecv \ -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 42 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.2.0 x-sora-target: Sora_20201120.DisconnectChannelByRole { "channel_id": "sora", "role": "sendrecv" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 39 content-type: application/json date: Thu, 03 Dec 2020 06:15:25 GMT server: Cowboy { "channel_id": "sora", "role": "sendrecv" } ``` ### ListConnections **x-sora-target**: Sora_20201013.ListConnections すべての接続一覧を取得します。 ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20201013.ListConnections \ -vvv POST / HTTP/1.1 Accept: */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 0 Host: 127.0.0.1:3000 User-Agent: HTTPie/2.2.0 x-sora-target: Sora_20201013.ListConnections HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 908 content-type: application/json date: Wed, 25 Nov 2020 09:25:07 GMT server: Cowboy [ { "audio": { "codec_type": "OPUS" }, "channel_id": "akane", "client_id": "DV2Z3MSXC50M78Y11ETN3VZ360", "created_time": 1642469139980509, "bundle_id": "DV2Z3MSXC50M78Y11ETN3VZ360", "connection_id": "DV2Z3MSXC50M78Y11ETN3VZ360", "multistream": true, "role": "sendrecv", "simulcast": false, "spotlight": false, "video": { "bit_rate": 1000, "codec_type": "VP9" } }, { "audio": { "codec_type": "OPUS" }, "channel_id": "sora", "client_id": "DKF93NH82X3BDB0CVKEH32JMVR", "created_time": 1642469139980509, "bundle_id": "DKF93NH82X3BDB0CVKEH32JMVR", "connection_id": "DKF93NH82X3BDB0CVKEH32JMVR", "multistream": true, "role": "sendrecv", "simulcast": false, "spotlight": false, "video": { "bit_rate": 1000, "codec_type": "VP9" } }, { "audio": { "codec_type": "OPUS" }, "channel_id": "sora", "client_id": "W6725M370N2W301378Y5SFG01C", "created_time": 1642469139980509, "bundle_id": "W6725M370N2W301378Y5SFG01C", "connection_id": "W6725M370N2W301378Y5SFG01C", "multistream": true, "role": "sendrecv", "simulcast": false, "spotlight": false, "video": { "bit_rate": 1000, "codec_type": "VP9" } } ] ``` ### ListChannelConnections **x-sora-target**: Sora_20201013.ListChannelConnections 指定したチャネルの接続一覧を取得します。 * - キー - 型 * - channel_id - string ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20201013.ListChannelConnections \ channel_id=sora \ -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 22 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.2.0 x-sora-target: Sora_20201013.ListChannelConnections { "channel_id": "sora" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 605 content-type: application/json date: Wed, 25 Nov 2020 09:26:00 GMT server: Cowboy [ { "audio": { "codec_type": "OPUS" }, "channel_id": "sora", "client_id": "DKF93NH82X3BDB0CVKEH32JMVR", "created_time": 1642469139980509, "bundle_id": "DKF93NH82X3BDB0CVKEH32JMVR", "connection_id": "DKF93NH82X3BDB0CVKEH32JMVR", "multistream": true, "role": "sendrecv", "simulcast": false, "spotlight": false, "video": { "bit_rate": 1000, "codec_type": "VP9" } }, { "audio": { "codec_type": "OPUS" }, "channel_id": "sora", "client_id": "W6725M370N2W301378Y5SFG01C", "created_time": 1642469139980509, "bundle_id": "W6725M370N2W301378Y5SFG01C", "connection_id": "W6725M370N2W301378Y5SFG01C", "multistream": true, "role": "sendrecv", "simulcast": false, "spotlight": false, "video": { "bit_rate": 1000, "codec_type": "VP9" } } ] ``` ## サイマルキャスト API ### RequestRtpStream **x-sora-target**: Sora_20201005.RequestRtpStream 指定した視聴者の受信する RTP ストリームの rid をリクエストします。 * - キー - 型 * - channel_id - string * - recv_connection_id - string * - send_connection_id (オプション) - string * - rid - string (r0 | r1 | r2) r1 までしか配信されていない場合に、r2 をリクエストした場合は r1 を受信し始めます。 ``` $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20201005.RequestRtpStream \ channel_id=sora \ recv_connection_id=4EVK3MN5Z17GB62RE5TGD045ZM \ send_connection_id=EKNQ103WRD4ZZ74B6TKRM9YK78 \ rid=r1 \ -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 139 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.2.0 x-sora-target: Sora_20201005.RequestRtpStream { "channel_id": "sora", "recv_connection_id": "4EVK3MN5Z17GB62RE5TGD045ZM", "rid": "r1", "send_connection_id": "EKNQ103WRD4ZZ74B6TKRM9YK78" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 132 content-type: application/json date: Wed, 25 Nov 2020 09:31:11 GMT server: Cowboy { "channel_id": "sora", "recv_connection_id": "4EVK3MN5Z17GB62RE5TGD045ZM", "rid": "r1", "send_connection_id": "EKNQ103WRD4ZZ74B6TKRM9YK78" } ``` ### ResetRtpStream **x-sora-target**: Sora_20201005.ResetRtpStream 指定した視聴者の受信する RTP ストリームの rid をリセットします。 * - キー - 型 * - channel_id - string * - recv_connection_id - string * - send_connection_id (オプション) - string ``` $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20201005.ResetRtpStream \ channel_id=sora \ recv_connection_id=4EVK3MN5Z17GB62RE5TGD045ZM \ send_connection_id=EKNQ103WRD4ZZ74B6TKRM9YK78 \ -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 126 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.2.0 x-sora-target: Sora_20201005.ResetRtpStream { "channel_id": "sora", "recv_connection_id": "4EVK3MN5Z17GB62RE5TGD045ZM", "send_connection_id": "EKNQ103WRD4ZZ74B6TKRM9YK78" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 121 content-type: application/json date: Wed, 25 Nov 2020 09:31:57 GMT server: Cowboy { "channel_id": "sora", "recv_connection_id": "4EVK3MN5Z17GB62RE5TGD045ZM", "send_connection_id": "EKNQ103WRD4ZZ74B6TKRM9YK78" } ``` ## スポットライト API ### FocusSpotlightFixed **x-sora-target**: Sora_20200807.FocusSpotlightFixed 指定した Connection ID のクライアントに常にフォーカスが当たるようにします。 これは UnfocusSpotlight API が呼ばれるまで当たり続けます。 * - キー - 型 * - channel_id - string * - connection_id - string ``` $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20200807.FocusSpotlightFixed \ channel_id=sora connection_id=7QSNT842FS0J9E6BZDBC2DRYY8 -vvv POST / HTTP/1.1 Accept: application/json, */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 69 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.0.0 x-sora-target: Sora_20200807.FocusSpotlightFixed { "channel_id": "sora", "connection_id": "7QSNT842FS0J9E6BZDBC2DRYY8" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 66 content-type: application/json date: Wed, 09 Sep 2020 08:27:57 GMT server: Cowboy { "channel_id": "sora", "connection_id": "7QSNT842FS0J9E6BZDBC2DRYY8" } ``` ### FocusSpotlight **x-sora-target**: Sora_20200807.FocusSpotlight 指定した Connection ID のクライアントを強制的にフォーカスが当たった状態にします。 * - キー - 型 * - channel_id - string * - connection_id - string ``` $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20200807.FocusSpotlight \ channel_id=sora connection_id=74Z2G1JS7S67DE226T8R1H3YGW -vvv POST / HTTP/1.1 Accept: application/json, */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 69 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.0.0 x-sora-target: Sora_20200807.FocusSpotlight { "channel_id": "sora", "connection_id": "74Z2G1JS7S67DE226T8R1H3YGW" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 66 content-type: application/json date: Wed, 09 Sep 2020 08:33:54 GMT server: Cowboy { "channel_id": "sora", "connection_id": "74Z2G1JS7S67DE226T8R1H3YGW" } ``` ### UnfocusSpotlight **x-sora-target**: Sora_20200807.UnfocusSpotlight 指定した Connection ID のフォーカスを外します。 この API は FocusSpotlightFixed でフォーカスを当て続けてているのを解除する場合にも利用します。 * - キー - 型 * - channel_id - string * - connection_id - string ``` $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20200807.UnfocusSpotlight \ channel_id=sora connection_id=74Z2G1JS7S67DE226T8R1H3YGW -vvv POST / HTTP/1.1 Accept: application/json, */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 69 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.0.0 x-sora-target: Sora_20200807.UnfocusSpotlight { "channel_id": "sora", "connection_id": "74Z2G1JS7S67DE226T8R1H3YGW" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 66 content-type: application/json date: Wed, 09 Sep 2020 08:34:56 GMT server: Cowboy { "channel_id": "sora", "connection_id": "74Z2G1JS7S67DE226T8R1H3YGW" } ``` ### ChangeSpotlightNumber **x-sora-target**: Sora_20200807.ChangeSpotlightNumber フォーカスする最大数を変更します。最小は 1 で最大は 8 です この API でフォーカス最大数を変更した後に、`type:connect` で `spotlight_number` を指定するクライアントは、 **変更後の値** を指定する必要があります。 * - キー - 型 * - channel_id - string * - spotlight_number - integer (1 ~ 8) ``` $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20200807.ChangeSpotlightNumber \ channel_id=sora spotlight_number:=1 -vvv POST / HTTP/1.1 Accept: application/json, */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 45 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.0.0 x-sora-target: Sora_20200807.ChangeSpotlightNumber { "channel_id": "sora", "spotlight_number": 1 } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 42 content-type: application/json date: Wed, 09 Sep 2020 08:35:36 GMT server: Cowboy { "channel_id": "sora", "spotlight_number": 1 } ``` ### RequestSpotlightRid **x-sora-target**: Sora_20211215.RequestSpotlightRid スポットライトのフォーカス時とアンフォーカス時の rid を指定します。 これにより接続時に指定した `spotlight_focurs_rid` と `spotlight_unfocus_rid` の値を変更することができます。 * - キー - 型 * - channel_id - string * - recv_connection_id - string * - send_connection_id (オプション) - string * - spotlight_focus_rid - string (none | r0 | r1 | r2) * - spotlight_unfocus_rid - string (none | r0 | r1 | r2) ``` $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20211215.RequestSpotlightRid \ channel_id=sora \ recv_connection_id=AD0ZWY8W492XV9RQGB40GX5C94 \ spotlight_focus_rid=none \ spotlight_unfocus_rid=none \ -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 138 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.4.0 x-sora-target: Sora_20211215.RequestSpotlightRid { "channel_id": "sora", "recv_connection_id": "AD0ZWY8W492XV9RQGB40GX5C94", "spotlight_focus_rid": "none", "spotlight_unfocus_rid": "none" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 131 content-type: application/json date: Tue, 30 Nov 2021 02:20:44 GMT server: Cowboy { "channel_id": "sora", "recv_connection_id": "AD0ZWY8W492XV9RQGB40GX5C94", "spotlight_focus_rid": "none", "spotlight_unfocus_rid": "none" } ``` ### ResetSpotlightRid **x-sora-target**: Sora_20211215.ResetSpotlightRid スポットライトのフォーカス時とアンフォーカス時の rid を接続時に指定した値に戻します。 * - キー - 型 * - channel_id - string * - recv_connection_id - string * - send_connection_id (オプション) - string ``` $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20211215.ResetSpotlightRid \ channel_id=sora \ recv_connection_id=AD0ZWY8W492XV9RQGB40GX5C94 \ -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 74 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.4.0 x-sora-target: Sora_20211215.ResetSpotlightRid { "channel_id": "sora", "recv_connection_id": "AD0ZWY8W492XV9RQGB40GX5C94" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 71 content-type: application/json date: Tue, 30 Nov 2021 02:22:17 GMT server: Cowboy { "channel_id": "sora", "recv_connection_id": "AD0ZWY8W492XV9RQGB40GX5C94" } ``` ### BatchRequestSpotlightRid **x-sora-target**: Sora_20211215.BatchRequestSpotlightRid スポットライトのフォーカス時とアンフォーカス時の rid を一括で変更します。 * - キー - 型 * - channel_id - string * - item_list - array item_list には以下が含まれます。 * - キー - 型 * - recv_connection_id - string * - send_connection_id - string * - spotlight_focus_rid - string (none | r0 | r1 | r2) * - spotlight_unfocus_rid - string (none | r0 | r1 | r2) ``` $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20211215.BatchRequestSpotlightRid \ channel_id=sora \ item_list:='[{"recv_connection_id": "AD0ZWY8W492XV9RQGB40GX5C94", "send_connection_id": "RGEFFZM95S2XN0PC03XNMCRTB0", \ "spotlight_focus_rid": "none", "spotlight_unfocus_rid": "none"}, \ {"recv_connection_id": "AD0ZWY8W492XV9RQGB40GX5C94", "send_connection_id": "P9AFYE2BQN7JB93Q6GK0VYWGHM", \ "spotlight_focus_rid": "none", "spotlight_unfocus_rid": "none"}]' \ -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 377 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.4.0 x-sora-target: Sora_20211215.BatchRequestSpotlightRid { "channel_id": "sora", "item_list": [ { "recv_connection_id": "AD0ZWY8W492XV9RQGB40GX5C94", "send_connection_id": "RGEFFZM95S2XN0PC03XNMCRTB0", "spotlight_focus_rid": "none", "spotlight_unfocus_rid": "none" }, { "recv_connection_id": "AD0ZWY8W492XV9RQGB40GX5C94", "send_connection_id": "P9AFYE2BQN7JB93Q6GK0VYWGHM", "spotlight_focus_rid": "none", "spotlight_unfocus_rid": "none" } ] } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 387 content-type: application/json date: Tue, 30 Nov 2021 02:29:51 GMT server: Cowboy { "channel_id": "sora", "item_list": [ { "recv_connection_id": "AD0ZWY8W492XV9RQGB40GX5C94", "result": "ok", "send_connection_id": "RGEFFZM95S2XN0PC03XNMCRTB0", "spotlight_focus_rid": "none", "spotlight_unfocus_rid": "none" }, { "recv_connection_id": "AD0ZWY8W492XV9RQGB40GX5C94", "result": "ok", "send_connection_id": "P9AFYE2BQN7JB93Q6GK0VYWGHM", "spotlight_focus_rid": "none", "spotlight_unfocus_rid": "none" } ] } ``` ## プッシュ API シグナリングで使用している WebSocket や DataChannel を活用できる API です。 この機能を使うことでアプリケーション側でプッシュの仕組みを用意する必要がなくなります。 ### PushChannel **x-sora-target**: Sora_20160711.PushChannel 指定したチャネル全員にプッシュ通知を送る。 * - キー - 型 * - channel_id - string * - data - object data には全員に通知する JSON (object) を指定してください。 クライアントには data に指定した JSON (object) が送られます。 ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20160711.PushChannel \ channel_id=sora \ data:="{\"spam\": \"egg\"}" \ -vvv POST / HTTP/1.1 Accept: application/json Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 47 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/0.9.4 x-sora-target: Sora_20160711.PushChannel { "channel_id": "sora", "data": { "spam": "egg" } } HTTP/1.1 200 OK content-length: 37 content-type: application/json date: Sun, 24 Jul 2016 06:26:21 GMT server: Cowboy { "data": { "spam": "egg" }, "type": "push" } ``` ### PushClient **x-sora-target**: Sora_20160711.PushClient 指定したチャネルのクライアントにプッシュ通知を送ります。 * - キー - 型 * - channel_id - string * - client_id - string * - data - object 複数の接続に同一の `client_id` が指定されていた場合、複数の接続にプッシュ通知が送られます。 ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20160711.PushClient \ channel_id=sora \ client_id=C0YTCRZM715BKATBXWFPKTYGRM \ data:="{\"spam\": \"egg\"}" \ -vvv POST / HTTP/1.1 Accept: application/json Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 100 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/0.9.4 x-sora-target: Sora_20160711.PushClient { "channel_id": "sora", "client_id": "C0YTCRZM715BKATBXWFPKTYGRM", "data": { "spam": "egg" } } HTTP/1.1 200 OK content-length: 37 content-type: application/json date: Sun, 24 Jul 2016 07:46:31 GMT server: Cowboy { "data": { "spam": "egg" }, "type": "push" } ``` ### PushConnection **x-sora-target**: Sora_20160711.PushConnection 指定したチャネルの接続にプッシュ通知を送ります。 * - キー - 型 * - channel_id - string * - connection_id - string * - data - object ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20160711.PushConnection \ channel_id=sora \ connection_id=C0YTCRZM715BKATBXWFPKTYGRM \ data:="{\"spam\": \"egg\"}" \ -vvv POST / HTTP/1.1 Accept: application/json Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 100 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/0.9.4 x-sora-target: Sora_20160711.PushConnection { "channel_id": "sora", "connection_id": "C0YTCRZM715BKATBXWFPKTYGRM", "data": { "spam": "egg" } } HTTP/1.1 200 OK content-length: 37 content-type: application/json date: Sun, 24 Jul 2016 07:46:31 GMT server: Cowboy { "data": { "spam": "egg" }, "type": "push" } ``` ### PushChannelByRole **x-sora-target**: Sora_20201120.PushChannelByRole 指定したチャネルの指定したロールにプッシュ通知を送ります。 * - キー - 型 * - channel_id - string * - role - string (sendrecv | sendonly | recvonly) * - data - object ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20201120.PushChannelByRole \ channel_id=sora \ role=sendrecv \ data:="{\"spam\": \"egg\"}" \ -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 67 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.2.0 x-sora-target: Sora_20201120.PushChannelByRole { "channel_id": "sora", "data": { "spam": "egg" }, "role": "sendrecv" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 37 content-type: application/json date: Thu, 03 Dec 2020 06:16:16 GMT server: Cowboy { "data": { "spam": "egg" }, "type": "push" } ``` ## 録画 API 録画されたファイルは `sora.conf` の `archive_dir` に指定したディレクトリに置かれます。 音声と映像のコーデック指定はシグナリング開始時に指定してください。 ### StartRecording **x-sora-target**: Sora_20161101.StartRecording 指定したチャネルの録画を開始します。 クラスター機能利用時には、クラスター内のどのノードで実行しても開始された録画情報はすべてのノードで共有されます。 * - キー - 型 * - channel_id - string * - expire_time - integer * - split_duration (オプション) - integer * - split_only (オプション) - boolean * - metadata (オプション) - object - `expire_time` の範囲は `0` から `86400` までで、秒数を指定してください- expire_time を 0 に指定した場合、録画の期限が無くなります - `split_only` は `true` か `false` を指定して下さい。指定しない場合は `false` が指定されます - `split_only` を `true` に指定する場合は `expire_time` は `0` を指定する必要があります - `split_only` を `true` に指定する場合は `split_duration` を指定する必要があります- `split_duration` は 1 から 86400 までで、秒数を指定して下さい - `metadata` は JSON オブジェクトを指定してください- この `metadata` は `recording.report` ウェブフックやレポートファイルに含まれるようになります。 #### expire_time が 0 ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20161101.StartRecording \ channel_id=sora \ expire_time:=0 \ -vvv POST / HTTP/1.1 Accept: application/json, */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 41 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/0.9.9 x-sora-target: Sora_20161101.StartRecording { "channel_id": "sora", "expire_time": 0 } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 82 content-type: application/json date: Wed, 19 Apr 2017 06:35:38 GMT server: Cowboy { "channel_id": "sora", "expire_time": 0, "recording_id": "C0YTCRZM715BKATBXWFPKTYGRM" } ``` #### expire_time が 3600 ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20161101.StartRecording \ channel_id=sora \ expire_time:=3600 \ -vvv POST / HTTP/1.1 Accept: application/json, */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 43 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/0.9.9 x-sora-target: Sora_20161101.StartRecording { "channel_id": "sora", "expire_time": 3600 } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 84 content-type: application/json date: Wed, 19 Apr 2017 06:37:08 GMT server: Cowboy { "channel_id": "sora", "expire_time": 3600, "recording_id": "C0YTCRZM715BKATBXWFPKTYGRM" } ``` #### split_only が true ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20161101.StartRecording \ channel_id=sora \ expire_time:=0 \ split_duration:=3600 \ split_only:=true \ -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 84 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.2.0 x-sora-target: Sora_20161101.StartRecording { "channel_id": "sora", "expire_time": 0, "split_duration": 3600, "split_only": true } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 121 content-type: application/json date: Fri, 04 Dec 2020 03:04:17 GMT server: Cowboy { "channel_id": "sora", "expire_time": 0, "recording_id": "MK4J54QBGS4ES0MCSZMF6C9M9M", "split_duration": 3600, "split_only": true } ``` #### エラー - "STARTED-RECORDING"- 指定したチャネル ID で、すでに録画が開始している ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20161101.StartRecording \ channel_id=sora \ expire_time:=3600 \ -vvv POST / HTTP/1.1 Accept: application/json, */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 43 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/0.9.9 x-sora-target: Sora_20161101.StartRecording { "channel_id": "sora", "expire_time": 3600 } HTTP/1.1 400 Bad Request access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 34 content-type: application/json date: Wed, 19 Apr 2017 06:44:58 GMT server: Cowboy { "error_type": "STARTED-RECORDING" } ``` - "NOT-CLUSTER-MAJORITY"- クラスターで過半数以下のグループに所属している ### StopRecording **x-sora-target**: Sora_20161101.StopRecording 指定したチャネルの録画を停止します。 この API は非同期です。200 が返ってきた場合でも録画ファイルや録画メタデータファイルが生成されていることを保証しません。 イベントウェブフックの [archive.available](EVENT_WEBHOOK.html#de9132) または [recording.report](EVENT_WEBHOOK.html#920a02) の通知を利用してください。 クラスター機能利用時には、クラスター内のどのノードで実行しても録画を停止します。 例えば、StartRecodirng API を実行したノードと StopRecording を実行するノードが異なっていても動作します。 * - キー - 型 * - channel_id - string ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20161101.StopRecording \ channel_id=sora \ -vvv POST / HTTP/1.1 Accept: application/json Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 22 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/0.9.4 x-sora-target: Sora_20161101.StopRecording { "channel_id": "sora" } HTTP/1.1 200 OK content-length: 21 content-type: application/json date: Fri, 11 Nov 2016 14:29:14 GMT server: Cowboy { "channel_id": "sora" } ``` #### エラー - NOT-STARTED-RECORDING- 指定したチャネルの録画が開始されていない - "NOT-CLUSTER-MAJORITY"- クラスターで過半数以下のグループに所属している ### GetStartedRecording **x-sora-target**: Sora_20161101.GetStartedRecording 録画が有効かどうかを確認します。 クラスター機能利用時には、クラスター内のどのノードで実行することができます。 例えば、StartRecodirng API を実行したノードと GetStartedRecording を実行するノードが異なっていても動作します。 * - キー - 型 * - channel_id - string ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20161101.GetStartedRecording \ channel_id=sora \ -vvv POST / HTTP/1.1 Accept: application/json Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 22 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/0.9.4 x-sora-target: Sora_20161101.GetStartedRecording { "channel_id": "sora" } HTTP/1.1 200 OK content-length: 88 content-type: application/json date: Sat, 19 Nov 2016 13:03:24 GMT server: Cowboy { "channel_id": "sora", "expire_time": 3600, "expired_at": 1479563964, "start_time": 1479560364 } ``` #### エラー - NOT-STARTED-RECORDING- 指定したチャネルの録画が開始されていない ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20161101.GetStartedRecording \ channel_id=sora \ -vvv POST / HTTP/1.1 Accept: application/json Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 22 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/0.9.4 x-sora-target: Sora_20161101.GetStartedRecording { "channel_id": "sora" } HTTP/1.1 400 Bad Request content-length: 38 content-type: application/json date: Sat, 19 Nov 2016 13:03:53 GMT server: Cowboy { "error_type": "NOT-STARTED-RECORDING" } ``` - "NOT-CLUSTER-MAJORITY"- クラスターで過半数以下のグループに所属している ### ListStartedRecording **x-sora-target**: Sora_20161101.ListStartedRecording 録画が行われているチャネル一覧を取得します。 クラスター機能利用時には、クラスター内のどのノードで実行しても、クラスター内で有効な録画の一覧を取得できます。 ```console $ http POST 127.0.0.1:3000/ \ "x-sora-target:Sora_20161101.ListStartedRecording" \ -vvv POST / HTTP/1.1 Accept: */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 0 Host: 127.0.0.1:3000 User-Agent: HTTPie/2.4.0 x-sora-target: Sora_20161101.ListStartedRecording HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 307 content-type: application/json date: Tue, 30 Nov 2021 01:13:10 GMT server: Cowboy [ { "channel_id": "sora", "created_at": 1638234656, "expire_time": 3600, "expired_at": 1638238256, "recording_id": "WWZ61PT4GS03F80F39MCPVSEQR", "split_only": false }, { "channel_id": "zakuro", "created_at": 1638234654, "expire_time": 3600, "expired_at": 1638238254, "recording_id": "Z60BJP5YDN4PD0D7RGM4TFEE48", "split_only": false } ] ``` #### エラー - "NOT-CLUSTER-MAJORITY"- クラスターで過半数以下のグループに所属している ### ListArchiving **x-sora-target**: Sora_20161101.ListArchiving 現在録画中の状態を取得します。 > **注釈** > > クラスター機能利用時であっても、API を実行したノードで録画中の状態のみを取得します。 > クラスター内で録画中のすべてを取得したい場合はすべてのノードに ListArchiving API を実行する必要があります。 ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20161101.ListArchiving \ -vvv POST / HTTP/1.1 Accept: */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 0 Host: 127.0.0.1:3000 User-Agent: HTTPie/1.0.2 x-sora-target: Sora_20161101.ListArchiving HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 218 content-type: application/json date: Mon, 15 Apr 2019 08:39:20 GMT server: Cowboy [ { "audio": { "codec_type": "OPUS" }, "channel_id": "sora", "client_id": "C0YTCRZM715BKATBXWFPKTYGRM", "bundle_id": "C0YTCRZM715BKATBXWFPKTYGRM", "connection_id": "C0YTCRZM715BKATBXWFPKTYGRM", "seconds": 146, "video": { "bit_rate": 1000, "codec_type": "VP9" } } ] ``` - seconds は録画を開始してからの経過時間(秒)です - video が設定されていない場合は `"video": false` という値が入ってきます - audio が設定されていない場合は `"audio": false` という値が入ってきます ## 統計 API ### 統計項目一覧 **説明が書いていないものは項目名そのままの内容になります** - timestamp- API を取得した時点の UTC 時間 RFC3339 形式 - channel_id - client_id - bundle_id - connection_id - simulcast- r0- rtp- total_decrypt_skipped_srtp - tocal_decrypt_skipped_audio_srtp - tocal_decrypt_skipped_video_srtp - total_received_rtp - total_received_rtp_byte_size - total_received_rtp_padding - total_received_rtp_padding_size - total_received_rtp_red - total_received_rtp_red_rtx - total_received_rtp_red_ulpfec - total_received_rtp_rtx - rtp_hdr_ext- total_received_rtp_hdr_ext_abs_send_time - total_received_rtp_hdr_ext_audio_level - total_received_rtp_hdr_ext_av1_rtp_sepc - total_received_rtp_hdr_ext_color_space - total_received_rtp_hdr_ext_inband_cn - total_received_rtp_hdr_ext_playout_delay - total_received_rtp_hdr_ext_sdes_mid - total_received_rtp_hdr_ext_sdes_repaired_rtp_stream_id - total_received_rtp_hdr_ext_sdes_rtp_stream_id - total_received_rtp_hdr_ext_toffset - total_received_rtp_hdr_ext_transport_wide_cc - total_received_rtp_hdr_ext_unknown - total_received_rtp_hdr_ext_video_content_type - total_received_rtp_hdr_ext_video_orientation - total_received_rtp_hdr_ext_video_timeing - r1- r0 と同様 - r2- r0 と同様 - spotlight- total_spotlight_focus_failed - total_spotlight_unfocus_audio_no_room - total_spotlight_unfocus_audio_out_packet - total_spotlight_unfocus_audio_publish - dtls- total_received_dtls- 受信した DTLS パケットの総数 - total_sent_dtls- 送信した DTLS パケットの総数 - network_status- unstable_level- API を取得した時点の不安定レベル - signaling- total_received_signaling_pong - total_sent_signaling_ping - packet_loss_simulator- total_dropped_received_rtp- 受信したがパケロスシミュレータが落とした RTP パケットの総数 - total_dropped_sent_rtp- 送信したがパケロスシミュレータが落とした RTP パケットの総数 - total_dropped_received_data_channel- 受信したがパケロスシミュレータが落とした DataChannel パケットの総数 - total_dropped_sent_data_channel- 送信したがパケロスシミュレータが落とした DataChannel パケットの総数 - rtp- total_generic_nack_cache_hit- 再送要求に答えた総数 - total_generic_nack_cache_miss- 再送要求に答えられなかった総数 - total_pli_trigger- 再送要求が限界に来たため全画面要求(PLI) を送信した総数 - total_received - total_received_byte_size - total_received_rtp - total_received_rtp_byte_size - total_received_rtp_red - total_received_rtp_red_rtx - total_received_rtp_red_ulpfec - total_received_rtp_rtx - total_sent - total_sent_byte_size - total_sent_rtp - total_sent_rtp_byte_size - total_decrypt_skipped_srtp- 復号をスキップした SRTP 総数 - total_decrypt_skipped_video_srtp- 復号をスキップした映像 SRTP 総数 - total_decrypt_skipped_audio_srtp- 復号をスキップした音声 SRTP 総数 - total_received_srtp_invalid - total_received_rtp_padding - total_received_rtp_padding_size - total_received_intra_frame- I フレームを受信した総数 - total_ulpfec_recovered- ULPFEC を利用して損失パケットを回復した総数 - rtp_hdr_ext- total_received_rtp_hdr_ext_abs_send_time - total_received_rtp_hdr_ext_audio_level - total_received_rtp_hdr_ext_av1_rtp_sepc - total_received_rtp_hdr_ext_color_space - total_received_rtp_hdr_ext_inband_cn - total_received_rtp_hdr_ext_playout_delay - total_received_rtp_hdr_ext_sdes_mid - total_received_rtp_hdr_ext_sdes_repaired_rtp_stream_id - total_received_rtp_hdr_ext_sdes_rtp_stream_id - total_received_rtp_hdr_ext_toffset - total_received_rtp_hdr_ext_transport_wide_cc - total_received_rtp_hdr_ext_unknown - total_received_rtp_hdr_ext_video_content_type - total_received_rtp_hdr_ext_video_orientation - total_received_rtp_hdr_ext_video_timeing - total_sent_rtp_hdr_ext_abs_send_time - total_sent_rtp_hdr_ext_audio_level - total_sent_rtp_hdr_ext_av1_rtp_sepc - total_sent_rtp_hdr_ext_color_space - total_sent_rtp_hdr_ext_inband_cn - total_sent_rtp_hdr_ext_playout_delay - total_sent_rtp_hdr_ext_sdes_mid - total_sent_rtp_hdr_ext_sdes_repaired_rtp_stream_id - total_sent_rtp_hdr_ext_sdes_rtp_stream_id - total_sent_rtp_hdr_ext_toffset - total_sent_rtp_hdr_ext_transport_wide_cc - total_sent_rtp_hdr_ext_unknown - total_sent_rtp_hdr_ext_video_content_type - total_sent_rtp_hdr_ext_video_orientation - total_sent_rtp_hdr_ext_video_timeing - rtcp- total_received_rtcp - total_received_rtcp_bye - total_received_rtcp_byte_size - total_received_rtcp_psfb_afb - total_received_rtcp_psfb_fir - total_received_rtcp_psfb_pli - total_received_rtcp_rr - total_received_rtcp_rtpfb_generic_nack - total_received_rtcp_rtpfb_tmmbn - total_received_rtcp_rtpfb_tmmbr - total_received_rtcp_rtpfb_transport_wide - total_received_rtcp_sdes - total_received_rtcp_sr - total_received_rtcp_unknown - total_received_rtcp_xr - total_sent_rtcp - total_sent_rtcp_bye - total_sent_rtcp_byte_size - total_sent_rtcp_psfb_afb - total_sent_rtcp_psfb_fir - total_sent_rtcp_psfb_pli - total_sent_rtcp_rr - total_sent_rtcp_rtpfb_generic_nack - total_sent_rtcp_rtpfb_tmmbn - total_sent_rtcp_rtpfb_tmmbr - total_sent_rtcp_rtpfb_transport_wide - total_sent_rtcp_sdes - total_sent_rtcp_sr - total_sent_rtcp_unknown - total_sent_rtcp_xr - turn- total_received_turn_unknown_stun - total_received_turn_invalid_stun - total_received_unknown_channel_number - total_received_expired_channel_number - total_received_allocate_request - total_received_binding_request - total_received_channel_bind_request - total_received_channel_data - total_received_create_permission_request - total_received_refresh_request - total_received_send_indication - total_received_turn_binding_error - total_received_turn_binding_request - total_received_turn_binding_success - total_received_turn_unknown - total_sent_allocate_error - total_sent_allocate_success - total_sent_binding_error - total_sent_binding_success - total_sent_channel_bind_error - total_sent_channel_bind_success - total_sent_channel_data - total_sent_create_permission_error - total_sent_create_permission_success - total_sent_data_indication - total_sent_refresh_error - total_sent_refresh_success - total_sent_turn_binding_error - total_sent_turn_binding_request - total_sent_turn_binding_success - total_sent_turn_unknown - data_channel- signaling- ordered - max_packet_life_time - max_retransmits - protocol - direction - compress - total_data_channel_abandon_message - total_data_channel_retransmit_message - total_data_channel_open_message - total_data_channel_ack_message - total_received_data_channel_message - total_received_data_channel_message_byte_size - total_sent_data_channel_message - total_sent_data_channel_message_byte_size - notify- signaling と同様 - push- signaling と同様 - stats- signaling と同様 - e2ee- signaling と同様 - # から始まるメッセージング用ラベル- signaling と同様 - sctp- total_received_invalid_sctp - total_received_sctp - total_received_sctp_byte_size - total_received_sctp_chunk_abort - total_received_sctp_chunk_asconf - total_received_sctp_chunk_asconf_ack - total_received_sctp_chunk_auth - total_received_sctp_chunk_cookie_ack - total_received_sctp_chunk_cookie_echo - total_received_sctp_chunk_cwr - total_received_sctp_chunk_data - total_received_sctp_chunk_ecne - total_received_sctp_chunk_error - total_received_sctp_chunk_forward_tsn - total_received_sctp_chunk_heartbeat - total_received_sctp_chunk_heartbeat_ack - total_received_sctp_chunk_i_data - total_received_sctp_chunk_i_forward_tsn - total_received_sctp_chunk_init - total_received_sctp_chunk_init_ack - total_received_sctp_chunk_pad - total_received_sctp_chunk_reconfig - total_received_sctp_chunk_sack - total_received_sctp_chunk_shutdown - total_received_sctp_chunk_shutdown_ack - total_received_sctp_chunk_shutdown_complete - total_received_sctp_chunk_unknown - total_received_unknown_sctp - total_sent_sctp - total_sent_sctp_byte_size - total_sent_sctp_chunk_abort - total_sent_sctp_chunk_asconf - total_sent_sctp_chunk_asconf_ack - total_sent_sctp_chunk_auth - total_sent_sctp_chunk_cookie_ack - total_sent_sctp_chunk_cookie_echo - total_sent_sctp_chunk_cwr - total_sent_sctp_chunk_data - total_sent_sctp_chunk_ecne - total_sent_sctp_chunk_error - total_sent_sctp_chunk_forward_tsn - total_sent_sctp_chunk_heartbeat - total_sent_sctp_chunk_heartbeat_ack - total_sent_sctp_chunk_i_data - total_sent_sctp_chunk_i_forward_tsn - total_sent_sctp_chunk_init - total_sent_sctp_chunk_init_ack - total_sent_sctp_chunk_pad - total_sent_sctp_chunk_reconfig - total_sent_sctp_chunk_sack - total_sent_sctp_chunk_shutdown - total_sent_sctp_chunk_shutdown_ack - total_sent_sctp_chunk_shutdown_complete - total_sent_sctp_chunk_unknown ### GetStatsConnection **x-sora-target**: Sora_20170529.GetStatsConnection 指定した接続の統計情報を取得します。 * - キー - 型 * - channel_id - string * - connection_id - string ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20170529.GetStatsConnection \ channel_id=sora \ connection_id=KDBN2YD1A919V5BA2JX6TG2RP8 -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 69 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.4.0 x-sora-target: Sora_20170529.GetStatsConnection { "channel_id": "sora", "connection_id": "KP8VZZ321D0A90RSVJC4RMGJ08" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 10954 content-type: application/json date: Tue, 30 Nov 2021 01:59:51 GMT server: Cowboy { "channel_id": "sora", "client_id": "KP8VZZ321D0A90RSVJC4RMGJ08", "bundle_id": "KP8VZZ321D0A90RSVJC4RMGJ08", "connection_id": "KP8VZZ321D0A90RSVJC4RMGJ08", "data_channel": { "#test": { "compress": false, "direction": "sendrecv", "ordered": true, "protocol": "", "total_received_data_channel_message": 1, "total_received_data_channel_message_byte_size": 1, "total_sent_data_channel_message": 1, "total_sent_data_channel_message_byte_size": 17 }, "e2ee": { "compress": false, "direction": "sendrecv", "ordered": true, "protocol": "", "total_received_data_channel_message": 1, "total_received_data_channel_message_byte_size": 1, "total_sent_data_channel_message": 1, "total_sent_data_channel_message_byte_size": 16 }, "notify": { "compress": true, "direction": "recvonly", "ordered": true, "protocol": "", "total_received_data_channel_message": 1, "total_received_data_channel_message_byte_size": 1, "total_sent_data_channel_message": 8, "total_sent_data_channel_message_byte_size": 627 }, "push": { "compress": true, "direction": "recvonly", "ordered": true, "protocol": "", "total_received_data_channel_message": 1, "total_received_data_channel_message_byte_size": 1, "total_sent_data_channel_message": 1, "total_sent_data_channel_message_byte_size": 16 }, "signaling": { "compress": true, "direction": "sendrecv", "ordered": true, "protocol": "", "total_received_data_channel_message": 1, "total_received_data_channel_message_byte_size": 1, "total_sent_data_channel_message": 1, "total_sent_data_channel_message_byte_size": 21 }, "stats": { "compress": true, "direction": "sendrecv", "ordered": true, "protocol": "", "total_received_data_channel_message": 3, "total_received_data_channel_message_byte_size": 30078, "total_sent_data_channel_message": 3, "total_sent_data_channel_message_byte_size": 73 } }, "dtls": { "total_received_dtls": 36, "total_sent_dtls": 37 }, "network_status": { "unstable_level": 0 }, "packet_loss_simulator": { "total_dropped_received_data_channel": 2, "total_dropped_received_rtp": 0, "total_dropped_sent_data_channel": 2, "total_dropped_sent_rtp": 0 }, "rtcp": { "total_generic_nack_cache_hit": 4, "total_generic_nack_cache_miss": 0, "total_pli_trigger": 0, "total_received_rtcp": 375, "total_received_rtcp_bye": 0, "total_received_rtcp_byte_size": 33260, "total_received_rtcp_psfb_afb": 278, "total_received_rtcp_psfb_fir": 0, "total_received_rtcp_psfb_pli": 0, "total_received_rtcp_rr": 73, "total_received_rtcp_rtpfb_generic_nack": 4, "total_received_rtcp_rtpfb_tmmbn": 0, "total_received_rtcp_rtpfb_tmmbr": 0, "total_received_rtcp_rtpfb_transport_wide": 0, "total_received_rtcp_sdes": 298, "total_received_rtcp_sr": 298, "total_received_rtcp_unknown": 0, "total_received_rtcp_xr": 0, "total_sent_rtcp": 184, "total_sent_rtcp_bye": 0, "total_sent_rtcp_byte_size": 14812, "total_sent_rtcp_psfb_afb": 79, "total_sent_rtcp_psfb_fir": 0, "total_sent_rtcp_psfb_pli": 0, "total_sent_rtcp_rr": 91, "total_sent_rtcp_rtpfb_generic_nack": 0, "total_sent_rtcp_rtpfb_tmmbn": 0, "total_sent_rtcp_rtpfb_tmmbr": 0, "total_sent_rtcp_rtpfb_transport_wide": 0, "total_sent_rtcp_sdes": 93, "total_sent_rtcp_sr": 93, "total_sent_rtcp_unknown": 0, "total_sent_rtcp_xr": 0 }, "rtp": { "total_received": 5706, "total_received_byte_size": 1879672, "total_received_rtp": 5331, "total_received_rtp_byte_size": 1846412, "total_received_rtp_padding": 0, "total_received_rtp_padding_size": 0, "total_received_rtp_red": 0, "total_received_rtp_red_rtx": 0, "total_received_rtp_red_ulpfec": 0, "total_received_rtp_rtx": 79, "total_sent": 5548, "total_sent_byte_size": 2015913, "total_sent_rtp": 5364, "total_sent_rtp_byte_size": 2001101 }, "rtp_hdr_ext": { "total_received_rtp_hdr_ext_abs_send_time": 5331, "total_received_rtp_hdr_ext_audio_level": 3187, "total_received_rtp_hdr_ext_av1_rtp_sepc": 2144, "total_received_rtp_hdr_ext_color_space": 0, "total_received_rtp_hdr_ext_inband_cn": 0, "total_received_rtp_hdr_ext_playout_delay": 0, "total_received_rtp_hdr_ext_sdes_mid": 0, "total_received_rtp_hdr_ext_sdes_repaired_rtp_stream_id": 0, "total_received_rtp_hdr_ext_sdes_rtp_stream_id": 0, "total_received_rtp_hdr_ext_toffset": 0, "total_received_rtp_hdr_ext_transport_wide_cc": 0, "total_received_rtp_hdr_ext_unknown": 0, "total_received_rtp_hdr_ext_video_content_type": 0, "total_received_rtp_hdr_ext_video_orientation": 0, "total_received_rtp_hdr_ext_video_timeing": 0, "total_sent_rtp_hdr_ext_abs_send_time": 0, "total_sent_rtp_hdr_ext_audio_level": 3188, "total_sent_rtp_hdr_ext_av1_rtp_sepc": 2176, "total_sent_rtp_hdr_ext_color_space": 0, "total_sent_rtp_hdr_ext_inband_cn": 0, "total_sent_rtp_hdr_ext_playout_delay": 0, "total_sent_rtp_hdr_ext_sdes_mid": 0, "total_sent_rtp_hdr_ext_sdes_repaired_rtp_stream_id": 0, "total_sent_rtp_hdr_ext_sdes_rtp_stream_id": 0, "total_sent_rtp_hdr_ext_toffset": 0, "total_sent_rtp_hdr_ext_transport_wide_cc": 0, "total_sent_rtp_hdr_ext_unknown": 0, "total_sent_rtp_hdr_ext_video_content_type": 0, "total_sent_rtp_hdr_ext_video_orientation": 0, "total_sent_rtp_hdr_ext_video_timeing": 0 }, "sctp": { "total_pruned_sctp_data_chunk": 0, "total_received_invalid_sctp": 0, "total_received_sctp": 32, "total_received_sctp_byte_size": 8244, "total_received_sctp_chunk_abort": 0, "total_received_sctp_chunk_asconf": 0, "total_received_sctp_chunk_asconf_ack": 0, "total_received_sctp_chunk_auth": 0, "total_received_sctp_chunk_cookie_ack": 0, "total_received_sctp_chunk_cookie_echo": 1, "total_received_sctp_chunk_cwr": 0, "total_received_sctp_chunk_data": 14, "total_received_sctp_chunk_ecne": 0, "total_received_sctp_chunk_error": 0, "total_received_sctp_chunk_forward_tsn": 0, "total_received_sctp_chunk_heartbeat": 0, "total_received_sctp_chunk_heartbeat_ack": 2, "total_received_sctp_chunk_i_data": 0, "total_received_sctp_chunk_i_forward_tsn": 0, "total_received_sctp_chunk_init": 1, "total_received_sctp_chunk_init_ack": 0, "total_received_sctp_chunk_pad": 19, "total_received_sctp_chunk_reconfig": 0, "total_received_sctp_chunk_sack": 15, "total_received_sctp_chunk_shutdown": 0, "total_received_sctp_chunk_shutdown_ack": 0, "total_received_sctp_chunk_shutdown_complete": 0, "total_received_sctp_chunk_unknown": 0, "total_received_unknown_sctp": 0, "total_sent_sctp": 37, "total_sent_sctp_byte_size": 2060, "total_sent_sctp_chunk_abort": 0, "total_sent_sctp_chunk_asconf": 0, "total_sent_sctp_chunk_asconf_ack": 0, "total_sent_sctp_chunk_auth": 0, "total_sent_sctp_chunk_cookie_ack": 1, "total_sent_sctp_chunk_cookie_echo": 0, "total_sent_sctp_chunk_cwr": 0, "total_sent_sctp_chunk_data": 19, "total_sent_sctp_chunk_ecne": 0, "total_sent_sctp_chunk_error": 0, "total_sent_sctp_chunk_forward_tsn": 0, "total_sent_sctp_chunk_heartbeat": 2, "total_sent_sctp_chunk_heartbeat_ack": 0, "total_sent_sctp_chunk_i_data": 0, "total_sent_sctp_chunk_i_forward_tsn": 0, "total_sent_sctp_chunk_init": 0, "total_sent_sctp_chunk_init_ack": 1, "total_sent_sctp_chunk_pad": 0, "total_sent_sctp_chunk_reconfig": 0, "total_sent_sctp_chunk_sack": 14, "total_sent_sctp_chunk_shutdown": 0, "total_sent_sctp_chunk_shutdown_ack": 0, "total_sent_sctp_chunk_shutdown_complete": 0, "total_sent_sctp_chunk_unknown": 0 }, "signaling": { "total_received_signaling_pong": 0, "total_sent_signaling_ping": 0 }, "simulcast": { "r0": { "rtp": { "total_received_rtp": 0, "total_received_rtp_byte_size": 0, "total_received_rtp_padding": 0, "total_received_rtp_padding_size": 0, "total_received_rtp_red": 0, "total_received_rtp_red_rtx": 0, "total_received_rtp_red_ulpfec": 0, "total_received_rtp_rtx": 0 }, "rtp_hdr_ext": { "total_received_rtp_hdr_ext_abs_send_time": 0, "total_received_rtp_hdr_ext_audio_level": 0, "total_received_rtp_hdr_ext_av1_rtp_sepc": 0, "total_received_rtp_hdr_ext_color_space": 0, "total_received_rtp_hdr_ext_inband_cn": 0, "total_received_rtp_hdr_ext_playout_delay": 0, "total_received_rtp_hdr_ext_sdes_mid": 0, "total_received_rtp_hdr_ext_sdes_repaired_rtp_stream_id": 0, "total_received_rtp_hdr_ext_sdes_rtp_stream_id": 0, "total_received_rtp_hdr_ext_toffset": 0, "total_received_rtp_hdr_ext_transport_wide_cc": 0, "total_received_rtp_hdr_ext_unknown": 0, "total_received_rtp_hdr_ext_video_content_type": 0, "total_received_rtp_hdr_ext_video_orientation": 0, "total_received_rtp_hdr_ext_video_timeing": 0 } }, "r1": { "rtp": { "total_received_rtp": 0, "total_received_rtp_byte_size": 0, "total_received_rtp_padding": 0, "total_received_rtp_padding_size": 0, "total_received_rtp_red": 0, "total_received_rtp_red_rtx": 0, "total_received_rtp_red_ulpfec": 0, "total_received_rtp_rtx": 0 }, "rtp_hdr_ext": { "total_received_rtp_hdr_ext_abs_send_time": 0, "total_received_rtp_hdr_ext_audio_level": 0, "total_received_rtp_hdr_ext_av1_rtp_sepc": 0, "total_received_rtp_hdr_ext_color_space": 0, "total_received_rtp_hdr_ext_inband_cn": 0, "total_received_rtp_hdr_ext_playout_delay": 0, "total_received_rtp_hdr_ext_sdes_mid": 0, "total_received_rtp_hdr_ext_sdes_repaired_rtp_stream_id": 0, "total_received_rtp_hdr_ext_sdes_rtp_stream_id": 0, "total_received_rtp_hdr_ext_toffset": 0, "total_received_rtp_hdr_ext_transport_wide_cc": 0, "total_received_rtp_hdr_ext_unknown": 0, "total_received_rtp_hdr_ext_video_content_type": 0, "total_received_rtp_hdr_ext_video_orientation": 0, "total_received_rtp_hdr_ext_video_timeing": 0 } }, "r2": { "rtp": { "total_received_rtp": 0, "total_received_rtp_byte_size": 0, "total_received_rtp_padding": 0, "total_received_rtp_padding_size": 0, "total_received_rtp_red": 0, "total_received_rtp_red_rtx": 0, "total_received_rtp_red_ulpfec": 0, "total_received_rtp_rtx": 0 }, "rtp_hdr_ext": { "total_received_rtp_hdr_ext_abs_send_time": 0, "total_received_rtp_hdr_ext_audio_level": 0, "total_received_rtp_hdr_ext_av1_rtp_sepc": 0, "total_received_rtp_hdr_ext_color_space": 0, "total_received_rtp_hdr_ext_inband_cn": 0, "total_received_rtp_hdr_ext_playout_delay": 0, "total_received_rtp_hdr_ext_sdes_mid": 0, "total_received_rtp_hdr_ext_sdes_repaired_rtp_stream_id": 0, "total_received_rtp_hdr_ext_sdes_rtp_stream_id": 0, "total_received_rtp_hdr_ext_toffset": 0, "total_received_rtp_hdr_ext_transport_wide_cc": 0, "total_received_rtp_hdr_ext_unknown": 0, "total_received_rtp_hdr_ext_video_content_type": 0, "total_received_rtp_hdr_ext_video_orientation": 0, "total_received_rtp_hdr_ext_video_timeing": 0 } } }, "spotlight": { "total_spotlight_focus_failed": 0, "total_spotlight_unfocus_audio_no_room": 0, "total_spotlight_unfocus_audio_out_packet": 0, "total_spotlight_unfocus_audio_publish": 0 }, "timestamp": "2021-11-30T01:59:51.372062Z", "turn": { "total_received_allocate_request": 7, "total_received_binding_request": 0, "total_received_channel_bind_request": 1, "total_received_channel_data": 5802, "total_received_create_permission_request": 1, "total_received_expired_channel_number": 0, "total_received_refresh_request": 4, "total_received_send_indication": 3, "total_received_turn_binding_error": 0, "total_received_turn_binding_request": 29, "total_received_turn_binding_success": 28, "total_received_turn_invalid_stun": 0, "total_received_turn_unknown": 0, "total_received_turn_unknown_stun": 0, "total_received_unknown_channel_number": 0, "total_sent_allocate_error": 2, "total_sent_allocate_success": 2, "total_sent_binding_error": 0, "total_sent_binding_success": 0, "total_sent_channel_bind_error": 0, "total_sent_channel_bind_success": 1, "total_sent_channel_data": 5644, "total_sent_create_permission_error": 0, "total_sent_create_permission_success": 1, "total_sent_data_indication": 2, "total_sent_refresh_error": 0, "total_sent_refresh_success": 3, "total_sent_turn_binding_error": 0, "total_sent_turn_binding_request": 28, "total_sent_turn_binding_success": 1, "total_sent_turn_unknown": 0 } } ``` ### GetStatsClient **x-sora-target**: Sora_20170529.GetStatsClient 指定したクライアントの統計情報を取得します。 * - キー - 型 * - channel_id - string * - client_id - string ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20170529.GetStatsClient \ channel_id=sora \ client_id=82TKXKK1M15C76KTF192WVDSVC \ -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 65 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.4.0 x-sora-target: Sora_20170529.GetStatsClient { "channel_id": "sora", "client_id": "spam" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 10656 content-type: application/json date: Tue, 30 Nov 2021 02:02:33 GMT server: Cowboy [ { "channel_id": "sora", "client_id": "spam", "bundle_id": "DDG3V4NZPH04V02NKDMY97993W", "connection_id": "DDG3V4NZPH04V02NKDMY97993W", ... }, { "channel_id": "sora", "client_id": "spam", "bundle_id": "1RKMMEA10923N96N88S1GEKGYR", "connection_id": "1RKMMEA10923N96N88S1GEKGYR", ... } ] ``` ### GetStatsAllConnections **x-sora-target**: Sora_20171101.GetStatsAllConnections すべての接続の統計情報を取得します。 ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20171101.GetStatsAllConnections -vvv POST / HTTP/1.1 Accept: */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 0 Host: 127.0.0.1:3000 User-Agent: HTTPie/2.4.0 x-sora-target: Sora_20171101.GetStatsAllConnections HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 32059 content-type: application/json date: Tue, 30 Nov 2021 02:06:00 GMT server: Cowboy [ { "channel_id": "sora", "client_id": "spam", "bundle_id": "DDG3V4NZPH04V02NKDMY97993W", "connection_id": "DDG3V4NZPH04V02NKDMY97993W", ... }, { "channel_id": "sora", "client_id": "spam", "bundle_id: "1RKMMEA10923N96N88S1GEKGYR", "connection_id": "1RKMMEA10923N96N88S1GEKGYR", ... }, { "channel_id": "zakuro", "client_id": "EYYX5FGZN17VB647HGYZ27K8MM", "bundle_id": "EYYX5FGZN17VB647HGYZ27K8MM", "connection_id": "EYYX5FGZN17VB647HGYZ27K8MM", ... } ] ``` ## ライセンス API ### GetLicense **x-sora-target**: Sora_20171218.GetLicense 現在利用しているライセンス情報を取得します。 > **重要** > > `signature` は表示されません ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20171218.GetLicense -vvv POST / HTTP/1.1 Accept: */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 0 Host: 127.0.0.1:3000 User-Agent: HTTPie/0.9.9 x-sora-target: Sora_20171218.GetLicense HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 174 content-type: application/json date: Fri, 05 Jan 2018 06:41:35 GMT server: Cowboy { "expired_at": "2023-03", "max_connections": 100, "product_name": "Sora", "serial_code": "123ABC-SRA-E001-202303-100", "type": "Experimental" } ``` ### UpdateLicense **x-sora-target**: Sora_20171218.UpdateLicense ライセンスを更新します。 `sora.conf` の `license_file` に設定したファイルを新規のライセンスとして読み込みます。 ライセンスが壊れていたり、見つからない場合はエラーになります。 いずれの場合も接続中のクライアントへの影響はありません。 > **重要** > > `signature` は表示されません ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20171218.UpdateLicense -vvv POST / HTTP/1.1 Accept: */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 0 Host: 127.0.0.1:3000 User-Agent: HTTPie/0.9.9 x-sora-target: Sora_20171218.UpdateLicense HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 379 content-type: application/json date: Fri, 05 Jan 2018 06:44:47 GMT server: Cowboy { "new_license": { "expired_at": "2023-03", "max_connections": 100, "product_name": "Sora", "serial_code": "123ABC-SRA-E001-202303-100", "type": "Experimental" }, "old_license": { "expired_at": "2024-03", "max_connections": 100, "product_name": "Sora", "serial_code": "123ABC-SRA-E002-202403-100", "type": "Experimental" } } ``` # 実験的 API ## 概要 実験的 API とは、今後のアップデートで互換性を保証しない API です。 将来的には正式版としてリリースするか、または非推奨となり廃止するかのどちらかです。 ## シグナリング API > **注意** > > この API は実験的機能のため、正式版では仕様が変更される可能性があります ### ListChannels **x-sora-target**: Sora_20201013.ListChannels 全てのチャネル一覧を取得します。 ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20201013.ListChannels \ -vvv POST / HTTP/1.1 Accept: */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 0 Host: 127.0.0.1:3000 User-Agent: HTTPie/2.2.0 x-sora-target: Sora_20201013.ListChannels HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 120 content-type: application/json date: Thu, 26 Nov 2020 04:16:17 GMT server: Cowboy [ { "channel_id": "sora", "multistream": true, "spotlight": false }, { "channel_id": "akane", "multistream": true, "spotlight": false } ] ``` ## クラスター API > **注意** > > この API は実験的機能のため、正式版では仕様が変更される可能性があります ### InitCluster **x-sora-target**: Sora_20221221.InitCluster クラスターを初期化する際に必ず実行する必要がある API です。 クラスター初期化時に参加させるどれかのノードに対して行ってください。 `node_name_list` には初期化されたクラスターに参加するノードのリストを指定してください。 API が成功すると、そのノードリストで構成されるクラスターが構築されます。 > **ヒント** > > InitCluster API の実行はひとつのクラスターにつき一度だけ必要です。 > InitCluster API が成功した場合、その後のノード追加には [JoinCluster](EXPERIMENTAL_API.html#17f3f5) API を使います。 > > InitCluster API が次に必要になるのはクラスターが破綻した場合です。 > 詳細は [クラスター運用](CLUSTER.html#0233aa) を参照ください。 * - キー - 型 * - node_name_list - array of string ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20221221.InitCluster \ node_name_list:='["node-02@192.0.2.7", "node-03@10.99.0.8", "node-01@192.0.2.5"]' \ -vvv ``` ### JoinCluster **x-sora-target**: Sora_20211215.JoinCluster 指定したクラスターノードに参加します。 参加したいクラスターに属するノードのいずれかを `contact_node_name` で指定してください。 クラスターに属していれば、どのノードでもかまいません。 - 参加したいクラスターがすでに初期化されている必要があります。 - 正常に完了するためには、参加したいクラスターの過半数のノードが正常に稼働している必要があります- 参加したいクラスターが 1 ノードのときは例外で、そのノードが稼働していれば正常に処理可能です > **注釈** > > 新規にクラスターを作成する場合には、まず [InitCluster](EXPERIMENTAL_API.html#621990) API を使用してください。 事前にクラスターの参加ノードが判明している場合には `sora.conf` の `contact_node_name_list` に指定しておくと、 それらのノードに対して、起動時に自動で JoinCluster を試行するようになります。 * - キー - 型 * - contact_node_name - string ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20211215.JoinCluster \ contact_node_name=node-03@10.99.0.8 \ -vvv POST / HTTP/1.1 Accept: application/json, */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 42 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/1.0.3 x-sora-target: Sora_20211215.JoinCluster { "contact_node_name": "node-03@192.0.2.8" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 116 content-type: application/json date: Tue, 16 Nov 2021 09:28:11 GMT server: Cowboy { "node_name_list": [ "node-01@192.0.2.5" "node-02@192.0.2.7", "node-03@192.0.2.8", "node-04@192.0.2.9", "node-05@192.0.2.10", ] } ``` ### ListClusterNodes **x-sora-target**: Sora_20211215.ListClusterNodes クラスターのノード一覧を表示します。 * - キー - 型 * - include_all_known_nodes (オプション) - boolean `include_all_known_nodes` を `true` に指定することで、接続していないノードも含め、そのノードが知っているすべてのノード一覧を返します。 接続していないノードについては `node_name` と `connected` のみが結果に含まれます。 **レスポンス JSON** * - キー - 型 - 内容 * - external_api_url - string - ``sora.conf`` の ``external_api_url`` * - epoch - integer - 再起動回数 * - license_max_nodes - integer - ライセンスの最大ノード数 * - license_max_connections - integer - ライセンスの最大同時接続数 * - license_serial_code - string - ライセンスのシリアルコード * - license_type - string - ライセンスのタイプ * - node_name - string - ``sora.conf`` の ``node_name`` * - connected - boolean - API 実行ノードと正常に接続できているかどうか * - external_signaling_url - string - ``sora.conf`` の ``external_signaling_url`` * - version - string - Sora のバージョン * - mode - string - モード (normal / block_new_session / block_new_connection / initial) ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20211215.ListClusterNodes \ -vvv POST / HTTP/1.1 Accept: */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 0 Host: 127.0.0.1:3000 User-Agent: HTTPie/1.0.3 x-sora-target: Sora_20211215.ListClusterNodes HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 1753 content-type: application/json date: Tue, 16 Nov 2021 09:22:16 GMT server: Cowboy [ { "external_api_url": "http://192.0.2.5:3000/", "epoch": 1, "license_max_connections": 500, "license_serial_code": "ABCDEF-SRA-E001-203801-500", "license_type": "Experimental", "node_name": "node-01@192.0.2.5", "mode": "normal", "connected": true, "external_signaling_url": "wss://node-01.example.com/signaling", "version": "2021.2" }, { "api_url": "http://192.0.2.7:3000/", "epoch": 2, "license_max_connections": 500, "license_serial_code": "ABCDEF-SRA-E002-203801-500", "license_type": "Experimental", "node_name": "node-02@192.0.2.7", "mode": "normal", "connected": true, "external_signaling_url": "wss://node-02.example.com/signaling", "version": "2021.2" }, { "external_api_url": "http://192.0.2.8:3000/", "epoch": 2, "license_max_connections": 500, "license_serial_code": "ABCDEF-SRA-E003-203801-500", "license_type": "Experimental", "node_name": "node-03@192.0.2.8", "mode": "normal", "connected": true, "external_signaling_url": "wss://node-03.example.com/signaling", "version": "2021.2" }, { "external_api_url": "http://192.0.2.9:3000/", "epoch": 1, "license_max_connections": 500, "license_serial_code": "ABCDEF-SRA-E004-203801-500", "license_type": "Experimental", "node_name": "node-04@192.0.2.9", "mode": "normal", "connected": true, "external_signaling_url": "wss://node-04.example.com/signaling", "version": "2021.2" }, { "external_api_url": "http://192.0.2.10:3000/", "epoch": 2, "license_max_connections": 500, "license_serial_code": "ABCDEF-SRA-E005-203801-500", "license_type": "Experimental", "node_name": "node-05@192.0.2.10", "mode": "normal", "connected": true, "external_signaling_url": "wss://node-05.example.com/signaling", "version": "2021.2" } ] ``` ### ListClusterChannels **x-sora-target**: Sora_20211215.ListClusterChannels クラスターチャネル割り当て一覧を表示します。 * - キー - 型 - 内容 * - channel_id - string - チャネル ID * - owners - string - 担当ノード owners には以下が含まれます。 * - キー - 型 - 内容 * - node_name - string - ノード名 * - epoch - integer - 担当ノードへ割り当てられた際のクラスターへの参加回数 * - epoch_latest - boolean - 担当ノードが無効かどうか * - connected - boolean - 担当ノードが API 実行ノードと正常に接続できているかどうか ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20211215.ListClusterChannels \ -vvv POST / HTTP/1.1 Accept: */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 0 Host: 127.0.0.1:3000 User-Agent: HTTPie/1.0.3 x-sora-target: Sora_20211215.ListClusterChannels HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 646 content-type: application/json date: Tue, 16 Nov 2021 08:42:25 GMT server: Cowboy [ { "channel_id": "sora", "owners": [ { "node_name": "node-01@192.0.2.5", "epoch": 1, "epoch_latest": true, "connected": true } ] }, { "channel_id": "lemon", "owners": [ { "node_name": "node-01@192.0.2.5", "epoch": 1, "epoch_latest": true, "connected": true } ] }, { "channel_id": "hisui", "owners": [ { "node_name": "node-03@192.0.2.5", "epoch": 2, "epoch_latest": true, "connected": true } ] }, { "channel_id": "zakuro", "owners": [ { "node_name": "node-03@192.0.2.5", "epoch": 2, "epoch_latest": true, "connected": true } ] } ] ``` ### PurgeClusterNode **x-sora-target**: Sora_20220629.PurgeClusterNode 復旧がすぐには難しい障害が発生したノードや、縮退し再参加する予定が無いノードの情報をクラスターから完全消去します。 この API は 1 クラスターにつき 1 回実行すればすべての参加ノードから指定したノード情報が完全消去されます。 - この API の実行時には、消去対象のノードは停止している必要があります - この API が正常に完了するためには、過半数のノードが正常に稼働している必要があります - API を実行するノードは、クラスターに参加していて、正常に稼働しているノードであればどのノードでもかまいません > **警告** > > PurgeClusterNode API はクラスターからノードを完全に消去するための API です。 > 再参加するノードに対しては基本的に使用しないでください。 > この API を含めた運用の手順は [クラスター運用](CLUSTER.html#0233aa) をご確認ください。 * - キー - 型 * - target_node_name - string ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20220629.PurgeClusterNode \ target_node_name=node-03@192.0.2.5 \ -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate, br Connection: keep-alive Content-Length: 39 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/3.2.1 x-sora-target: Sora_20220629.PurgeClusterNode { "target_node_name": "node-03@192.0.2.5" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:3000 access-control-max-age: 1000 content-length: 38 content-type: application/json date: Sun, 12 Jun 2022 03:13:42 GMT server: Cowboy { "target_node_name": "node-03@192.0.2.5" } ``` ```console $ http POST 127.0.0.1:3001/ x-sora-target:Sora_20220629.PurgeClusterNode \ target_node_name=node-03@192.0.2.5 \ -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate, br Connection: keep-alive Content-Length: 39 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/3.2.1 x-sora-target: Sora_20220629.PurgeClusterNode { "target_node_name": "node-03@192.0.2.5" } HTTP/1.1 400 Bad Request access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:3000 access-control-max-age: 1000 content-length: 79 content-type: application/json date: Sun, 12 Jun 2022 03:13:29 GMT server: Cowboy { "error_reason": { "target_node": "node-03@192.0.2.5" }, "error_type": "NODE-IS-ALIVE" } ``` ## モード API > **注意** > > この API は実験的機能のため、正式版では仕様が変更される可能性があります ### ChangeMode **x-sora-target**: Sora_20211215.ChangeMode Sora のモードを変更します。 * - キー - 型 * - mode - string `mode` はすべての新規コネクションを受け入れる `normal` 、新規セッションの受け入れを停止する `block_new_session` と新規コネクションの受け入れを停止する `block_new_connection` が指定可能です。 ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20211215.ChangeMode \ mode=block_new_connection \ -vvv POST / HTTP/1.1 Accept: application/json, */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 32 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/1.0.3 x-sora-target: Sora_20211215.ChangeMode { "mode": "block_new_connection" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 31 content-type: application/json date: Tue, 16 Nov 2021 09:36:35 GMT server: Cowboy { "mode": "block_new_connection" } ``` ### GetMode **x-sora-target**: Sora_20211215.GetMode Sora のモードを取得します。 ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20211215.GetMode \ -vvv POST / HTTP/1.1 Accept: */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 0 Host: 127.0.0.1:3000 User-Agent: HTTPie/1.0.3 x-sora-target: Sora_20211215.GetMode HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 17 content-type: application/json date: Tue, 16 Nov 2021 09:35:26 GMT server: Cowboy { "mode": "normal" } ``` ## RTP 転送 API > **注意** > > この API は実験的機能のため、正式版では仕様が変更される可能性があります 指定したチャネル ID の配信している映像または音声の RTP を指定した IP アドレスとポートに送信します。 ### StartForwardingRtp **x-sora-target**: Sora_20170814.StartForwardingRtp 指定したチャネルの RTP の転送を開始します。 * - キー - 型 * - channel_id - string * - connection_id (オプション) - string * - ip_address - string * - audio_port - integer * - video_port - integer マルチストリームの音声や映像を転送する場合は `connection_id` を指定してください。 ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20170814.StartForwardingRtp \ channel_id=sora \ ip_address=127.0.0.1 \ audio_port:=60001 \ video_port:=60003 \ -vvv POST / HTTP/1.1 Accept: application/json Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 93 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/0.9.2 x-sora-target: Sora_20170814.StartForwardingRtp { "audio_port": 60001, "channel_id": "sora", "ip_address": "127.0.0.1", "video_port": 60003 } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 262 content-type: application/json date: Wed, 30 Aug 2017 02:08:50 GMT server: Cowboy { "sdp": "v=0\r\no=- 0 0 IN IP4 0.0.0.0\r\ns=-\r\nt=0 0\r\nm=audio 60001 RTP/SAVPF 109\r\nc=IN IP4 127.0.0.1\r\na=rtpmap:109 opus/48000/2\r\nm=video 60003 RTP/SAVPF 120\r\nc=IN IP4 127.0.0.1\r\na=rtpmap:120 VP9/90000\r\na=fmtp:120 max-fs=12288;max-fr=60\r\n" } ``` ### StopForwardingRtp **x-sora-target**: Sora_20170814.StopForwardingRtp 指定したチャネルの RTP の転送を停止します。 * - キー - 型 * - channel_id - string * - connection_id (オプション) - string マルチストリームの音声や映像の転送を停止する場合は `connection_id` を指定してください。 ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20170814.StopForwardingRtp \ channel_id=sora \ -vvv POST / HTTP/1.1 Accept: application/json, */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 22 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/0.9.9 x-sora-target: Sora_20170814.StopForwardingRtp { "channel_id": "sora" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 21 content-type: application/json date: Fri, 25 Aug 2017 13:32:48 GMT server: Cowboy { "channel_id": "sora" } ``` ## シグナリング通知メタデータ拡張 API > **注意** > > この API は実験的機能のため、正式版では仕様が変更される可能性があります。 ### ListSignalingNotifyMetadata **x-sora-target**: Sora_20201124.ListSignalingNotifyMetadata 指定したチャネルの全ての接続のメタデータをリストで返します。リストの中には `connection_id` と `bundle_id` と `client_id` と `metadata` をキーとしたオブジェクトがリストで入ってきます。順番保証はしません。 * - キー - 型 * - channel_id - string ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20201124.ListSignalingNotifyMetadata \ channel_id=sora \ -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 22 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.2.0 x-sora-target: Sora_20201124.ListSignalingNotifyMetadata { "channel_id": "sora" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 111 content-type: application/json date: Thu, 26 Nov 2020 03:45:25 GMT server: Cowboy [ { "client_id": "V3Q452QQBD5TQ6ZQDMTEDKA07C", "bundle_id": "V3Q452QQBD5TQ6ZQDMTEDKA07C", "connection_id": "V3Q452QQBD5TQ6ZQDMTEDKA07C", "metadata": { "abc": 10 } } ] ``` ### GetSignalingNotifyMetadata **x-sora-target**: Sora_20201124.GetSignalingNotifyMetadata 指定した接続のメタデータを取得します。 * - キー - 型 * - channel_id - string * - connection_id - string ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20201124.GetSignalingNotifyMetadata \ channel_id=sora \ connection_id=0FQE5EA5YN3FS13P01QZ1JG8R0 \ -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 69 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.2.0 x-sora-target: Sora_20201124.GetSignalingNotifyMetadata { "channel_id": "sora", "connection_id": "0FQE5EA5YN3FS13P01QZ1JG8R0" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 13 content-type: application/json date: Thu, 26 Nov 2020 03:48:44 GMT server: Cowboy { "abc": "efg" } ``` ### PutSignalingNotifyMetadata **x-sora-target**: Sora_20201124.PutSignalingNotifyMetadata 指定した接続のメタデータを作成します。 * - キー - 型 * - channel_id - string * - connection_id - string * - metadata - object * - push (オプション) - boolean 指定した接続のメタデータを作成します。メタデータがすでにあった場合は更新します。 追加したあとのメタデータが値として返ってきます。 ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20201124.PutSignalingNotifyMetadata \ channel_id=sora \ connection_id=0FQE5EA5YN3FS13P01QZ1JG8R0 \ metadata:='{"abc": "efg"}' \ -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 97 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.2.0 x-sora-target: Sora_20201124.PutSignalingNotifyMetadata { "channel_id": "sora", "connection_id": "0FQE5EA5YN3FS13P01QZ1JG8R0", "metadata": { "abc": "efg" } } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 13 content-type: application/json date: Thu, 26 Nov 2020 03:47:52 GMT server: Cowboy { "abc": "efg" } ``` ### DeleteSignalingNotifyMetadata **x-sora-target**: Sora_20201124.DeleteSignalingNotifyMetadata 指定した接続のメタデータを削除します。 * - キー - 型 * - channel_id - string * - connection_id - string * - push (オプション) - boolean 指定した接続のメタデータを削除します。メタデータが空だったとしてもエラーにはなりません。 削除されるまえのメタデータが値として返ってきます。 ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20201124.DeleteSignalingNotifyMetadata \ channel_id=sora \ connection_id=0FQE5EA5YN3FS13P01QZ1JG8R0 \ -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 69 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.2.0 x-sora-target: Sora_20201124.DeleteSignalingNotifyMetadata { "channel_id": "sora", "connection_id": "0FQE5EA5YN3FS13P01QZ1JG8R0" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 13 content-type: application/json date: Thu, 26 Nov 2020 03:51:48 GMT server: Cowboy { "abc": "efg" } ``` ### PutSignalingNotifyMetadataItem **x-sora-target**: Sora_20201124.PutSignalingNotifyMetadataItem 指定した接続のメタデータ項目を作成または更新します。 * - キー - 型 * - channel_id - string * - connection_id - string * - key - string * - value - json * - push (オプション) - boolean key/value で指定したメタデータ項目を追加します。その項目が既にあった場合は更新します。 追加したあとのメタデータが値として返ってきます。 ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20201124.PutSignalingNotifyMetadataItem \ channel_id=sora \ connection_id=0FQE5EA5YN3FS13P01QZ1JG8R0 \ key=abc \ value=efg \ -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 99 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.2.0 x-sora-target: Sora_20201124.PutSignalingNotifyMetadataItem { "channel_id": "sora", "connection_id": "0FQE5EA5YN3FS13P01QZ1JG8R0", "key": "abc", "value": "efg" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 13 content-type: application/json date: Thu, 26 Nov 2020 03:51:48 GMT server: Cowboy { "abc": "efg" } ``` push を有効にした場合は、そのチャネルの全てのクライアントに以下のようなプッシュ通知が送られます。 ```javascript { "type": "push", "data": { "action": "PutMetadataItem", "connection_id": "0FQE5EA5YN3FS13P01QZ1JG8R0", "key": "abc", "type": "signaling_notify_metadata_ext", "value": "efg" } } ``` - action- 呼ばれた API 名 - connection_id- シグナリング通知メタデータの項目が変更された接続の ID - key- シグナリング通知メタデータの項目が変更されたキー - value- シグナリング通知メタデータの項目が変更されたバリュー ### DeleteSignalingNotifyMetadataItem **x-sora-target**: Sora_20201124.DeleteSignalingNotifyMetadataItem 指定した接続のメタデータ項目を削除します。 * - キー - 型 * - channel_id - string * - connection_id - string * - key - string * - push (オプション) - boolean key で指定したメタデータ項目を削除します。その項目がなかったとしてもエラーにはなりません。 削除されたあとのメタデータが値として返ってきます。 ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20201124.DeleteSignalingNotifyMetadataItem \ channel_id=sora \ connection_id=0FQE5EA5YN3FS13P01QZ1JG8R0 \ key=abc \ push:=true \ -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 97 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.2.0 x-sora-target: Sora_20201124.DeleteSignalingNotifyMetadataItem { "channel_id": "sora", "connection_id": "0FQE5EA5YN3FS13P01QZ1JG8R0", "key": "abc", "push": true } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 2 content-type: application/json date: Thu, 26 Nov 2020 03:54:50 GMT server: Cowboy {} ``` ## RTP ストリーム停止/再開 API > **注意** > > この API は実験的機能のため、正式版では仕様が変更される可能性があります。 ### PauseRtpStream **現時点では映像のみを停止します** **x-sora-target**: Sora_20200401.PauseRtpStream 指定した接続からのストリームを停止します。 この API はマルチストリーム、サイマルキャスト、スポットライトで利用できます。 * - キー - 型 * - channel_id - string * - recv_connection_id - string * - send_connection_id - string - recv_connection_id- RTP ストリームの受信を停止する接続の `connection_id` を指定します - send_connection_id- 受信を停止する RTP ストリームを配信している接続の `connection_id` を指定します 映像自体は Sora までは届いていますが、実際の配信が一時停止されるという仕組みになっています。 ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20200401.PauseRtpStream \ channel_id=sora \ recv_connection_id=VTGYC92AZX6M72K860BPREFTMC \ send_connection_id=3X0W1C23KS1TQAAYMKA9TXJS4G \ -vvv POST / HTTP/1.1 Accept: application/json, */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 121 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.0.0 x-sora-target: Sora_20200401.PauseRtpStream { "channel_id": "sora", "recv_connection_id": "VTGYC92AZX6M72K860BPREFTMC", "send_connection_id": "3X0W1C23KS1TQAAYMKA9TXJS4G" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 121 content-type: application/json date: Thu, 16 Apr 2020 02:06:39 GMT server: Cowboy { "channel_id": "sora", "recv_connection_id": "VTGYC92AZX6M72K860BPREFTMC", "send_connection_id": "3X0W1C23KS1TQAAYMKA9TXJS4G" } ``` ### ResumeRtpStream **x-sora-target**: Sora_20200401.ResumeRtpStream 指定した接続からのストリームを再開します。 この API はマルチストリーム、サイマルキャスト、スポットライトで利用できます。 * - キー - 型 * - channel_id - string * - recv_connection_id - string * - send_connection_id - string - recv_connection_id- RTP ストリームの受信を再開する接続の `connection_id` を指定します - send_connection_id- 受信を停止している RTP ストリームを配信している接続の `connection_id` を指定します ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20200401.ResumeRtpStream \ channel_id=sora \ recv_connection_id=VTGYC92AZX6M72K860BPREFTMC \ send_connection_id=3X0W1C23KS1TQAAYMKA9TXJS4G \ -vvv POST / HTTP/1.1 Accept: application/json, */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 121 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.0.0 x-sora-target: Sora_20200401.ResumeRtpStream { "channel_id": "sora", "recv_connection_id": "VTGYC92AZX6M72K860BPREFTMC", "send_connection_id": "3X0W1C23KS1TQAAYMKA9TXJS4G" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 121 content-type: application/json date: Thu, 16 Apr 2020 02:07:27 GMT server: Cowboy { "channel_id": "sora", "recv_connection_id": "VTGYC92AZX6M72K860BPREFTMC", "send_connection_id": "3X0W1C23KS1TQAAYMKA9TXJS4G" } ``` ### ListPauseRtpStreams **x-sora-target**: Sora_20200401.ListPauseRtpStreams 指定したチャネルの停止しているストリーム一覧を返します。 * - キー - 型 * - channel_id - string ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20200401.ListPauseRtpStreams \ channel_id=sora \ -vvv POST / HTTP/1.1 Accept: application/json, */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 22 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.0.0 x-sora-target: Sora_20200401.ListPauseRtpStreams { "channel_id": "sora" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 111 content-type: application/json date: Thu, 09 Apr 2020 07:10:18 GMT server: Cowboy [ { "channel_id": "sora", "recv_connection_id": "G8AN156DSD3DBBN4P15VJ74QRW", "role": "sendrecv", "send_connection_id": "47YZ3NYNRN2CS5MW2W8V28W6QW" } ] ``` ## 統計 API > **注意** > > この API は実験的機能のため、正式版では仕様が変更される可能性があります。 ### GetStatsReport **x-sora-target**: Sora_20171010.GetStatsReport Sora が起動している間の Sora 全体の統計情報を取得することができます。この統計情報は Sora を止めたり再起動したりすることでクリアされますので注意してください。 #### レスポンス項目 - version- sora のバージョン - total_connection_created- 現在までの接続が作成された数 - total_connection_updated- 現在までの接続が更新された数 - total_connection_destroyed- 現在までの接続が破棄された数 - total_session_created- 現在までのセッションが作成された数 - total_session_destroyed- 現在までのセッションが破棄された数 - total_successful_connections- 現在までの接続が成功した数 - total_ongoing_connections- 現在接続している数 - total_failed_connections- 現在までの接続が失敗した数 - total_duration_sec- 現在までの合計接続時間 (秒) - total_turn_udp_connections- 現在までの TURN-UDP での接続数 - total_turn_tcp_connections- 現在までの TURN-TCP または TURN-TLS での接続数 - total_received_invalid_turn_tcp_packet- 現在までの TURN-TCP でパースできないパケットが送られてきた数 - total_auth_webhook_allowed- 認証ウェブフックで許可された数 - total_auth_webhook_denied- 認証ウェブフックで拒否された数 - total_successful_auth_webhook- 認証ウェブフックが成功した数 - total_failed_auth_webhook- 認証ウェブフックが失敗した数 - total_successful_session_webhook- セッションウェブフックが成功した数 - total_failed_session_webhook- セッションウェブフックが失敗した数 - total_successful_event_webhook- イベントウェブフックが成功した数 - total_failed_event_webhook- イベントウェブフックが失敗した数 - average_duration_sec- 平均接続時間 (秒) - average_setup_time_msec- 平均セットアップ時間 (ミリ秒) - セットアップ時間とはシグナリング接続開始から WebRTC が確立するまでにかかった時間です - cluster- 現時点ではクラスター機能で採用している [Raft Consensus Algorithm](https://raft.github.io/) の情報です - raft_commit_index- Raft ノードが最後にコミットしたログのインデックス番号 - raft_state- Raft ノードの現在の状態 - raft_term- Raft ノードの現在の term ウェブフックの成功は 2xx 系が戻ってきておりかつ、JSON がある場合は JSON のパースに失敗しない場合です。 それ以外は失敗としています。 ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20171010.GetStatsReport \ -vvv POST / HTTP/1.1 Accept: */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 0 Host: 127.0.0.1:3000 User-Agent: HTTPie/0.9.9 x-sora-target: Sora_20171010.GetStatsReport HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 172 content-type: application/json date: Tue, 10 Oct 2017 10:23:22 GMT server: Cowboy { "average_duration_sec": 1450, "average_setup_time_msec": 879, "cluster": { "raft_commit_index": 28, "raft_state": "follower", "raft_term": 1 }, "total_auth_webhook_allowed": 3, "total_auth_webhook_denied": 0, "total_connection_created": 3, "total_connection_destroyed": 2, "total_connection_updated": 48, "total_duration_sec": 2901, "total_failed_auth_webhook": 0, "total_failed_connections": 0, "total_failed_event_webhook": 0, "total_failed_session_webhook": 0, "total_ongoing_connections": 1, "total_received_invalid_turn_tcp_packet": 38, "total_session_created": 3, "total_session_destroyed": 2, "total_successful_auth_webhook": 3, "total_successful_connections": 3, "total_successful_event_webhook": 60, "total_successful_session_webhook": 5, "total_turn_tcp_connections": 0, "total_turn_udp_connections": 3, } ``` ## ユーザーエージェント統計情報 API > **注意** > > この API は実験的機能のため、正式版では仕様が変更される可能性があります。 ### 統計情報更新のタイミングについて この統計情報は、クライアントからシグナリングで送信されてくる統計情報の最新の値を返します。 WebSocket 経由の場合は 5 秒間隔で更新され、DataChannel 経由の場合は 30 秒間隔で更新されます。 ### ListUserAgentStats **x-sora-target**: Sora_20211215.ListUserAgentStats すべてのユーザーエージェント統計情報の一覧を取得します。 ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20211215.ListUserAgentStats -vvv POST / HTTP/1.1 Accept: */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 0 Host: 127.0.0.1:3000 User-Agent: HTTPie/2.4.0 x-sora-target: Sora_20211215.ListUserAgentStats HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 30262 content-type: application/json date: Sat, 13 Nov 2021 13:05:51 GMT server: Cowboy [ { "channel_id": "sora", "connection_id": "FNRGZ8VFSN3R98DK7NBA38MFNR", "timestamp": "2021-11-13T13:05:33.264Z", "user_agent_stats": [ { "audioLevel": 0, "id": "RTCAudioSource_1", "kind": "audio", "timestamp": 1636808733258.573, "totalAudioEnergy": 0, "totalSamplesDuration": 90.08000000000918, "trackIdentifier": "222a181f-d0fe-4434-b7a1-a8e05e3abbb4", "type": "media-source" }, ... ] }, { "channel_id": "zakuro", "connection_id": "X019KW3ZT95WZ6T15S6HHTM59C", "timestamp": "2021-11-13T13:05:44.044Z", "user_agent_stats": [ { "audioLevel": 0, "id": "RTCAudioSource_1", "kind": "audio", "timestamp": 1636808744029.488, "totalAudioEnergy": 0, "totalSamplesDuration": 31.070000000002057, "trackIdentifier": "9a84b996-d3ab-4cea-8131-04f96232dde5", "type": "media-source" }, ... ] } ] ``` ### ListChannelUserAgentStats **x-sora-target**: Sora_20211215.ListChannelUserAgentStats 指定したチャネルのユーザーエージェント統計情報の一覧を取得します。 * - キー - 型 * - channel_id - string ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20211215.ListChannelUserAgentStats \ channel_id=sora \ -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 22 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.4.0 x-sora-target: Sora_20211215.ListChannelUserAgentStats { "channel_id": "sora" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 30368 content-type: application/json date: Sat, 13 Nov 2021 13:10:35 GMT server: Cowboy [ { "channel_id": "sora", "connection_id": "1BW6V4P6A14MZ0W2HHXV3M8MCW", "timestamp": "2021-11-13T13:10:25.736Z", "user_agent_stats": [ { "audioLevel": 0, "id": "RTCAudioSource_1", "kind": "audio", "timestamp": 1636809025720.942, "totalAudioEnergy": 0, "totalSamplesDuration": 90.08000000000918, "trackIdentifier": "58c7f808-5b7f-4283-8816-0ac1f7d75387", "type": "media-source" }, ... ] }, { "channel_id": "sora", "connection_id": "VDH8HN6X6S4MZF2FCQJF3Z4M8G", "timestamp": "2021-11-13T13:10:30.643Z", "user_agent_stats": [ { "audioLevel": 0, "id": "RTCAudioSource_1", "kind": "audio", "timestamp": 1636809030622.809, "totalAudioEnergy": 0, "totalSamplesDuration": 91.08000000000968, "trackIdentifier": "e6d3182d-706c-445f-9a91-c5951d55e000", "type": "media-source" }, ... ] } ] ``` ### GetUserAgentStats **x-sora-target**: Sora_20211215.GetUserAgentStats 指定した接続のユーザーエージェント統計情報を取得します。 * - キー - 型 * - channel_id - string * - connection_id - string ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20211215.GetUserAgentStats \ channel_id=sora \ connection_id=VDH8HN6X6S4MZF2FCQJF3Z4M8G \ -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 69 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.4.0 x-sora-target: Sora_20211215.GetUserAgentStats { "channel_id": "sora", "connection_id": "VDH8HN6X6S4MZF2FCQJF3Z4M8G" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 15181 content-type: application/json date: Sat, 13 Nov 2021 13:11:46 GMT server: Cowboy { "channel_id": "sora", "connection_id": "VDH8HN6X6S4MZF2FCQJF3Z4M8G", "stats": [ { "audioLevel": 0, "id": "RTCAudioSource_1", "kind": "audio", "timestamp": 1636809090624.392, "totalAudioEnergy": 0, "totalSamplesDuration": 151.08000000000757, "trackIdentifier": "e6d3182d-706c-445f-9a91-c5951d55e000", "type": "media-source" }, ... ], "timestamp": "2021-11-13T13:11:30.647Z" } ``` ## 音声ストリーミング API > **注意** > > この API は実験的機能のため、正式版では仕様が変更される可能性があります。 ### StartAudioStreaming **x-sora-target**: Sora_20221221.StartAudioStreaming セッションが存在し、音声ストリーミングが開始していないチャネルに対して音声ストリーミングを開始します。 * - キー - 型 * - channel_id - string ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20221221.StartAudioStreaming \ channel_id=sora \ -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 22 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.6.0 x-sora-target: Sora_20221221.StartAudioStreaming { "channel_id": "sora" } HTTP/1.1 200 OK content-length: 43 content-type: application/json date: Thu, 15 Dec 2022 06:21:40 GMT server: Cowboy { "session_id": "MPXNY180M175Z69YY9FZFJ0QWR" } ``` ### StopAudioStreaming **x-sora-target**: Sora_20221221.StopAudioStreaming セッションが存在し、音声ストリーミングが開始しているチャネルに対して音声ストリーミングを停止します。 * - キー - 型 * - channel_id - string ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20221221.StopAudioStreaming \ channel_id=sora \ -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 22 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.6.0 x-sora-target: Sora_20221221.StopAudioStreaming { "channel_id": "sora" } HTTP/1.1 200 OK content-length: 43 content-type: application/json date: Thu, 15 Dec 2022 06:21:58 GMT server: Cowboy { "session_id": "MPXNY180M175Z69YY9FZFJ0QWR" } ``` ### SubscribeAudioStreamingResultPush **x-sora-target**: Sora_20221221.SubscribeAudioStreamingResultPush 音声ストリーミングサーバーからの戻り値のプッシュ通知を指定した接続が購読するよう設定します。 * - キー - 型 * - channel_id - string * - connection_id - string ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20221221.SubscribeAudioStreamingResultPush \ channel_id=sora \ connection_id=AT10T0WHH94PHEM3M5F45QFGRW \ -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 69 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.6.0 x-sora-target: Sora_20221221.SubscribeAudioStreamingResultPush { "channel_id": "sora", "connection_id": "AT10T0WHH94PHEM3M5F45QFGRW" } HTTP/1.1 200 OK content-length: 66 content-type: application/json date: Thu, 15 Dec 2022 06:26:32 GMT server: Cowboy { "channel_id": "sora", "connection_id": "AT10T0WHH94PHEM3M5F45QFGRW" } ``` ### UnsubscribeAudioStreamingResultPush **x-sora-target**: Sora_20221221.UnsubscribeAudioStreamingResultPush 音声ストリーミングサーバーからの戻り値のプッシュ通知を指定した接続が購読しないよう設定します。 * - キー - 型 * - channel_id - string * - connection_id - string ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20221221.UnsubscribeAudioStreamingResultPush \ channel_id=sora \ connection_id=4D83B8APHS4JX03C8SZ3176SBM \ -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 69 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.6.0 x-sora-target: Sora_20221221.UnsubscribeAudioStreamingResultPush { "channel_id": "sora", "connection_id": "4D83B8APHS4JX03C8SZ3176SBM" } HTTP/1.1 200 OK content-length: 66 content-type: application/json date: Thu, 15 Dec 2022 06:28:22 GMT server: Cowboy { "channel_id": "sora", "connection_id": "4D83B8APHS4JX03C8SZ3176SBM" } ``` ## その他の API > **注意** > > この API は実験的機能のため、正式版では仕様が変更される可能性があります。 ### ChangeUpstreamVideoBitRate **x-sora-target**: Sora_20190327.ChangeUpstreamVideoBitRate 指定した接続のビットレートを動的に変更します。 この API は片方向とマルチストリームでのみ利用できます。 主に `role` が `sendonly` の **配信ビットレート** を動的に変更し固定することを目的としている API です。 * - キー - 型 * - channel_id - string * - connection_id - string * - bit_rate - integer (1 - 30000) ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20190327.ChangeUpstreamVideoBitRate \ channel_id=sora \ connection_id=HMRVPQEXJX03D3B3WE778SJGRC \ bit_rate:=300 \ -vvv POST / HTTP/1.1 Accept: application/json, */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 96 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/1.0.2 x-sora-target: Sora_20190327.ChangeUpstreamVideoBitRate { "bit_rate": 300, "channel_id": "sora", "connection_id": "HMRVPQEXJX03D3B3WE778SJGRC" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 91 content-type: application/json date: Wed, 27 Mar 2020 08:38:03 GMT server: Cowboy { "bit_rate": 300, "channel_id": "sora", "connection_id": "HMRVPQEXJX03D3B3WE778SJGRC" } ``` ## 検証 API > **注意** > > この API は実験的機能のため、正式版では仕様が変更される可能性があります。 ### GenerateCrashLog **この API は検証目的のためだけに利用してください** **x-sora-target**: Sora_20221221.GenerateCrashLog ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20221221.GenerateCrashLog \ info:='{"spam": "egg"}' \ -vvv ``` # 非推奨 API ## 概要 非推奨 API は廃止日が設定されている API です。 基本的には以下のルールで廃止をしますが、例外はあります。不明点がある場合はサポートまでご連絡下さい。 - API が非推奨 API になった場合、代替 API がない場合は廃止までにすくなくとも 1 年以上の期間を設けます - API が非推奨 API になった場合、代替 API がある場合は廃止までにすくなくとも 6 ヶ月以上の期間を設けます # 廃止 API ## 概要 廃止 API とはすでに廃止された API です。 ## 廃止 シグナリング API ### ListAllConnections > **危険** > > この API 廃止されました。 **廃止**: 2021 年 12 月リリースの Sora にて廃止 **代替 API**: Sora_20201013.ListConnections **x-sora-target**: Sora_20151104.ListAllConnections すべての接続一覧を取得します。 #### レスポンス項目 **リスト** - role - channel_id - client_id - connection_id - multistream - simulcast - spotlight ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20151104.ListAllConnections \ -vvv POST / HTTP/1.1 Accept: */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 0 Host: 127.0.0.1:3000 User-Agent: HTTPie/2.0.0 x-sora-target: Sora_20151104.ListAllConnections HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 542 content-type: application/json date: Fri, 12 Jun 2020 06:38:55 GMT server: Cowboy [ { "channel_id": "sora", "client_id": "6DXMKHX8Q106K9YKN693C2D69C", "connection_id": "6DXMKHX8Q106K9YKN693C2D69C", "multistream": true, "role": "sendrecv", "simulcast": true, "spotlight": false }, { "channel_id": "sora", "client_id": "QR3H6TYEA907B2HRDF6KCBGWYG", "connection_id": "QR3H6TYEA907B2HRDF6KCBGWYG", "multistream": true, "role": "sendrecv", "simulcast": true, "spotlight": false }, { "channel_id": "sora1", "client_id": "K3VJGRFG614SV4RRF74QDEYHVC", "connection_id": "K3VJGRFG614SV4RRF74QDEYHVC", "multistream": true, "role": "sendrecv", "simulcast": true, "spotlight": false } ] ``` ### ListChannelClients > **危険** > > この API 廃止されました。 **廃止**: 2021 年 12 月リリースの Sora にて廃止 **代替 API**: Sora_20201013.ListChannelConnections **x-sora-target**: Sora_20170814.ListChannelClients 指定したチャネルのクライアント情報を取得します。 * - キー - 型 * - channel_id - string #### レスポンス項目 **リスト** - role - multistream - channel_id - client_id - connection_id - audio - video - minutes- 分単位での接続経過時間 - event_metadata- 認証時に認証サーバーから指定した event_metadata ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20170814.ListChannelClients \ channel_id=sora \ -vvv POST / HTTP/1.1 Accept: application/json, */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 22 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.0.0 x-sora-target: Sora_20170814.ListChannelClients { "channel_id": "sora" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 465 content-type: application/json date: Fri, 12 Jun 2020 06:39:57 GMT server: Cowboy [ { "audio": { "codec_type": "OPUS" }, "channel_id": "sora", "client_id": "6DXMKHX8Q106K9YKN693C2D69C", "connection_id": "6DXMKHX8Q106K9YKN693C2D69C", "minutes": 2, "multistream": true, "role": "sendrecv", "video": { "bit_rate": 3000, "codec_type": "VP8" } }, { "audio": { "codec_type": "OPUS" }, "channel_id": "sora", "client_id": "QR3H6TYEA907B2HRDF6KCBGWYG", "connection_id": "QR3H6TYEA907B2HRDF6KCBGWYG", "minutes": 2, "multistream": true, "role": "sendrecv", "video": { "bit_rate": 3000, "codec_type": "VP8" } } ] ``` ### DisconnectChannelUpstream > **危険** > > この API 廃止されました。 **廃止**: 2021 年 6 月リリースの Sora にて廃止 **代替 API**: 20201013.DisconnectChannelByRole **x-sora-target**: Sora_20151104.DisconnectChannelUpstream 指定したチャネルすべての配信者の接続を切断します。 * - キー - 型 * - channel_id - string * - reason (オプション) - object `reason` に値を指定した場合、イベントウェブフック `connection.destroyed` の `reason` に指定した値が入ってきます。 ```console $ http POST 127.0.0.1:3000 \ x-sora-target:Sora_20151104.DisconnectChannelUpstream \ channel_id=sora \ -vvv POST / HTTP/1.1 Accept: application/json Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 22 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/0.9.3 x-sora-target: Sora_20151104.DisconnectChannelUpstream { "channel_id": "sora" } HTTP/1.1 200 OK content-length: 0 content-type: application/json date: Sun, 24 Jul 2016 06:04:53 GMT server: Cowboy ``` ### DisconnectChannelDownstream > **危険** > > この API 廃止されました。 **廃止**: 2021 年 6 月リリースの Sora にて廃止 **代替 API**: 20201013.DisconnectChannelByRole **x-sora-target**: Sora_20151104.DisconnectChannelDownstream 指定したチャネルすべての視聴者の接続を切断します。 * - キー - 型 * - channel_id - string * - reason (オプション) - object reason に値を指定した場合、イベントウェブフック connection.destroyed の reason に指定した値が入ってきます。 ```console $ http POST 127.0.0.1:3000 \ x-sora-target:Sora_20151104.DisconnectChannelDownstream \ channel_id=sora \ -vvv POST / HTTP/1.1 Accept: application/json Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 22 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/0.9.3 x-sora-target: Sora_20151104.DisconnectChannelDownstream { "channel_id": "sora" } HTTP/1.1 200 OK content-length: 0 content-type: application/json date: Sun, 24 Jul 2016 06:04:53 GMT server: Cowboy ``` ### Disconnect > **危険** > > この API 廃止されました。 > **警告** > > sora.conf にて allow_client_id_assignment を true にしていた場合はこの API は利用できません **廃止**: 2021 年 6 月リリースの Sora にて廃止 **代替 API**: Sora_20151104.DisconnectClient **x-sora-target**: Sora_20151104.Disconnect 指定したクライアント ID の接続を切断する * - キー - 型 * - channel_id - string * - client_id - string * - reason (オプション) - object reason に値を指定した場合、イベントウェブフック connection.destroyed の reason に指定した値が入ってきます。 ``` $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20151104.Disconnect \ channel_id=sora \ client_id=HMRVPQEXJX03D3B3WE778SJGRC \ -vvv POST / HTTP/1.1 Accept: application/json Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 75 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/0.9.3 x-sora-target: Sora_20151104.Disconnect { "channel_id": "sora", "client_id": "HMRVPQEXJX03D3B3WE778SJGRC" } HTTP/1.1 200 OK content-length: 0 content-type: application/json date: Sun, 29 May 2020 05:13:20 GMT server: Cowboy ``` ### ListConnections > **危険** > > この API 廃止されました。 **廃止**: 2021 年 6 月リリースの Sora にて廃止 **代替 API**: Sora_20201013.ListChannelConnections **x-sora-target**: Sora_20151104.ListConnections 指定したチャネルの接続一覧を取得します。 * - キー - 型 * - channel_id - string ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20151104.ListConnections \ channel_id=sora \ -vvv POST / HTTP/1.1 Accept: application/json, */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 22 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.0.0 x-sora-target: Sora_20151104.ListConnections { "channel_id": "sora" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 361 content-type: application/json date: Fri, 12 Jun 2020 06:37:58 GMT server: Cowboy [ { "channel_id": "sora", "client_id": "6DXMKHX8Q106K9YKN693C2D69C", "connection_id": "6DXMKHX8Q106K9YKN693C2D69C", "multistream": true, "role": "sendrecv", "simulcast": true, "spotlight": false }, { "channel_id": "sora", "client_id": "QR3H6TYEA907B2HRDF6KCBGWYG", "connection_id": "QR3H6TYEA907B2HRDF6KCBGWYG", "multistream": true, "role": "sendrecv", "simulcast": true, "spotlight": false } ] ``` ## 廃止 サイマルキャスト API ### ChangeSimulcastQuality > **危険** > > この API 廃止されました。 **廃止**: 2021 年 6 月リリースの Sora にて廃止 **代替 API**: Sora_20201005.RequestRtpStream **x-sora-target**: Sora_20180820.ChangeSimulcastQuality 指定した参加者の視聴する映像の画質を変更する * - キー - 型 * - channel_id - string * - connection_id - string * - stream_id (オプション) - string * - quality - string (high | middle | low) ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20180820.ChangeSimulcastQuality \ channel_id=sora \ connection_id=KD9N57E2RN5T1BDEA7S7SH038M \ quality=high \ -vvv POST / HTTP/1.1 Accept: application/json, */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 98 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/1.0.2 x-sora-target: Sora_20180820.ChangeSimulcastQuality { "channel_id": "sora", "connection_id": "KD9N57E2RN5T1BDEA7S7SH038M", "quality": "high" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 93 content-type: application/json date: Thu, 04 Apr 2019 05:36:44 GMT server: Cowboy { "channel_id": "sora", "connection_id": "KD9N57E2RN5T1BDEA7S7SH038M", "quality": "high" } ``` ## 廃止 統計 API ### GetStats > **危険** > > この API 廃止されました。 > **警告** > > sora.conf にて allow_client_id_assignment を true にしていた場合はこの API は利用できません **廃止**: 2021 年 6 月リリースの Sora にて廃止 **x-sora-target**: Sora_20170529.GetStats 指定したクライアントの統計情報を取得します。 * - キー - 型 * - channel_id - string * - client_id - string ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20170529.GetStats \ channel_id=sora \ client_id=WZXPMM6K8113K83VB8G9XZDTFW -vvv POST / HTTP/1.1 Accept: application/json, */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 65 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.0.0 x-sora-target: Sora_20170529.GetStats { "channel_id": "sora", "client_id": "WZXPMM6K8113K83VB8G9XZDTFW" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 2770 content-type: application/json date: Tue, 09 Jun 2020 05:42:39 GMT server: Cowboy { "channel_id": "sora", "client_id": "WZXPMM6K8113K83VB8G9XZDTFW", "connection_id": "WZXPMM6K8113K83VB8G9XZDTFW", "dtls": { "total_received_dtls": 2, "total_sent_dtls": 2 }, "network_status": { "unstable_level": 0 }, "packet_loss_simulator": { "total_dropped_received_rtp": 0, "total_dropped_sent_rtp": 0 }, "rtp": { "total_generic_nack_cache_hit": 0, "total_generic_nack_cache_miss": 0, "total_pli_trigger": 0, "total_received": 1105, "total_received_byte_size": 845972, "total_received_rtcp": 20, "total_received_rtcp_bye": 0, "total_received_rtcp_byte_size": 1304, "total_received_rtcp_psfb_afb": 0, "total_received_rtcp_psfb_fir": 0, "total_received_rtcp_psfb_pli": 0, "total_received_rtcp_rr": 2, "total_received_rtcp_rtpfb_generic_nack": 0, "total_received_rtcp_rtpfb_tmmbn": 0, "total_received_rtcp_rtpfb_tmmbr": 0, "total_received_rtcp_rtpfb_transport_wide": 0, "total_received_rtcp_sdes": 18, "total_received_rtcp_sr": 18, "total_received_rtcp_unknown": 0, "total_received_rtcp_xr": 0, "total_received_rtp": 1085, "total_received_rtp_byte_size": 844668, "total_received_rtp_red": 0, "total_received_rtp_red_rtx": 0, "total_received_rtp_red_ulpfec": 0, "total_received_rtp_rtx": 0, "total_sent": 9, "total_sent_byte_size": 606, "total_sent_rtcp": 9, "total_sent_rtcp_bye": 0, "total_sent_rtcp_byte_size": 606, "total_sent_rtcp_psfb_afb": 8, "total_sent_rtcp_psfb_fir": 0, "total_sent_rtcp_psfb_pli": 0, "total_sent_rtcp_rr": 9, "total_sent_rtcp_rtpfb_generic_nack": 0, "total_sent_rtcp_rtpfb_tmmbn": 0, "total_sent_rtcp_rtpfb_tmmbr": 0, "total_sent_rtcp_rtpfb_transport_wide": 0, "total_sent_rtcp_sdes": 0, "total_sent_rtcp_sr": 0, "total_sent_rtcp_unknown": 0, "total_sent_rtcp_xr": 0, "total_sent_rtp": 0, "total_sent_rtp_byte_size": 0 }, "timestamp": "2020-06-09T05:42:40Z", "turn": { "total_received_allocate_request": 11, "total_received_binding_request": 0, "total_received_channel_bind_request": 1, "total_received_channel_data": 1113, "total_received_create_permission_request": 2, "total_received_expired_channel_number": 0, "total_received_refresh_request": 0, "total_received_send_indication": 7, "total_received_turn_binding_error": 0, "total_received_turn_binding_request": 7, "total_received_turn_binding_success": 6, "total_received_turn_invalid_stun": 0, "total_received_turn_unknown": 0, "total_received_turn_unknown_stun": 0, "total_received_unknown_channel_number": 0, "total_sent_allocate_error": 7, "total_sent_allocate_success": 2, "total_sent_binding_error": 0, "total_sent_binding_success": 0, "total_sent_channel_bind_error": 0, "total_sent_channel_bind_success": 1, "total_sent_channel_data": 19, "total_sent_create_permission_error": 0, "total_sent_create_permission_success": 2, "total_sent_data_indication": 5, "total_sent_refresh_error": 0, "total_sent_refresh_success": 0, "total_sent_turn_binding_error": 0, "total_sent_turn_binding_request": 6, "total_sent_turn_binding_success": 2, "total_sent_turn_unknown": 0 } } ``` ## 廃止 プッシュ API ### PushUpstream > **危険** > > この API 廃止されました。 **廃止**: 2021 年 6 月リリースの Sora にて廃止 **代替 API**: Sora_20201120.PushChannelByRole **x-sora-target**: Sora_20160711.PushUpstream 指定したチャネルの配信クライアントにプッシュ通知を送ります。 * - キー - 型 * - channel_id - string * - data - object ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20160711.PushUpstream \ channel_id=sora \ data:="{\"spam\": \"egg\"}" \ -vvv POST / HTTP/1.1 Accept: application/json Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 47 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/0.9.4 x-sora-target: Sora_20160711.PushUpstream { "channel_id": "sora", "data": { "spam": "egg" } } HTTP/1.1 200 OK t-length: 37 content-type: application/json date: Sun, 24 Jul 2016 06:29:08 GMT server: Cowboy { "data": { "spam": "egg" }, "type": "push" } ``` ### PushDownstream > **危険** > > この API 廃止されました。 **廃止**: 2021 年 6 月リリースの Sora にて廃止 **代替 API**: Sora_20201120.PushChannelByRole **x-sora-target**: Sora_20160711.PushDownstream 指定したチャネルの視聴クライアントにプッシュ通知を送ります。 * - キー - 型 * - channel_id - string * - data - object ``` $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20160711.PushDownstream \ channel_id=sora \ data:="{\"spam\": \"egg\"}" \ -vvv POST / HTTP/1.1 Accept: application/json Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 47 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/0.9.4 x-sora-target: Sora_20160711.PushDownstream { "channel_id": "sora", "data": { "spam": "egg" } } HTTP/1.1 200 OK content-length: 37 content-type: application/json date: Sun, 24 Jul 2016 06:29:20 GMT server: Cowboy { "data": { "spam": "egg" }, "type": "push" } ``` ## 廃止 リモート統計情報 API ### 統計情報更新のタイミングについて この統計情報は、シグナリングで死活監視用の Pong メッセージに含まれてくるクライアント統計情報の最新の値を返します。 Ping メッセージは 5 秒間隔で Sora から送られるため、ネットワークが正常であれば Pong メッセージが返ってくるのは 5 秒間隔となります。 そのため、統計情報は 5 秒間隔で更新されます。 ### GetAllRemoteStats > **危険** > > この API 廃止されました。 **廃止**: 2022 年 6 月リリースの Sora にて廃止 **代替 API**: Sora_20211215.ListUserAgentStats **x-sora-target**: Sora_20200225.GetAllRemoteStats 全てのリモート統計情報を取得する。 ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20200225.GetAllRemoteStats -vvv POST / HTTP/1.1 Accept: */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 0 Host: 127.0.0.1:3000 User-Agent: HTTPie/2.0.0 x-sora-target: Sora_20200225.GetAllRemoteStats HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 9444 content-type: application/json date: Thu, 09 Apr 2020 07:31:33 GMT server: Cowboy [ { "channel_id": "sora", "connection_id": "HMRVPQEXJX03D3B3WE778SJGRC", "remote_stats": [ { "audioLevel": 0, "id": "RTCAudioSource_1", "kind": "audio", "timestamp": 1586417492054.487, "totalAudioEnergy": 0, "totalSamplesDuration": 24.930000000001098, "trackIdentifier": "8de161d9-c93f-4c8a-ab0e-c4cb1ed45543", "type": "media-source" }, ... ], "timestamp": "2020-04-09T07:31:32.056Z" } ] ``` ### GetChannelRemoteStats > **危険** > > この API 廃止されました。 **廃止**: 2022 年 6 月リリースの Sora にて廃止 **代替 API**: Sora_20211215.ListChannelUserAgentStats **x-sora-target**: Sora_20200225.GetChannelRemoteStats 指定したチャネルのリモート統計情報を取得する。 * - キー - 型 * - channel_id - string ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20200225.GetChannelRemoteStats \ channel_id=sora \ -vvv POST / HTTP/1.1 Accept: application/json, */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 22 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.0.0 x-sora-target: Sora_20200225.GetChannelRemoteStats { "channel_id": "sora" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 9479 content-type: application/json date: Thu, 09 Apr 2020 07:32:36 GMT server: Cowboy [ { "channel_id": "sora", "connection_id": "HMRVPQEXJX03D3B3WE778SJGRC", "remote_stats": [ { "audioLevel": 0, "id": "RTCAudioSource_1", "kind": "audio", "timestamp": 1586417557067.526, "totalAudioEnergy": 0, "totalSamplesDuration": 89.95000000000911, "trackIdentifier": "8de161d9-c93f-4c8a-ab0e-c4cb1ed45543", "type": "media-source" }, ... ], "timestamp": "2020-04-09T07:32:37.069Z" } ] ``` ### GetConnectionRemoteStats > **危険** > > この API 廃止されました。 **廃止**: 2022 年 6 月リリースの Sora にて廃止 **代替 API**: Sora_20211215.GetUserAgentStats **x-sora-target**: Sora_20200225.GetConnectionRemoteStats 指定した接続のリモート統計情報を取得する。 * - キー - 型 * - channel_id - string * - connection_id - string ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20200225.GetConnectionRemoteStats \ channel_id=sora \ connection_id=HMRVPQEXJX03D3B3WE778SJGRC \ -vvv POST / HTTP/1.1 Accept: application/json, */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 69 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.0.0 x-sora-target: Sora_20200225.GetConnectionRemoteStats { "channel_id": "sora", "connection_id": "HMRVPQEXJX03D3B3WE778SJGRC" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 9473 content-type: application/json date: Thu, 09 Apr 2020 07:33:41 GMT server: Cowboy { "channel_id": "sora", "connection_id": "HMRVPQEXJX03D3B3WE778SJGRC", "stats": [ { "audioLevel": 0, "id": "RTCAudioSource_1", "kind": "audio", "timestamp": 1586417622080.464, "totalAudioEnergy": 0, "totalSamplesDuration": 154.96000000000404, "trackIdentifier": "8de161d9-c93f-4c8a-ab0e-c4cb1ed45543", "type": "media-source" }, ... ], "timestamp": "2020-04-09T07:33:42.081Z" } ``` ## 廃止 スポットライト API ### CastSpotlight > **危険** > > この API 廃止されました。 **廃止**: 2021 年 12 月リリースの Sora にて廃止 **x-sora-target**: Sora_20180404.CastSpotlight 指定した参加者を強制的に画面に表示する。 * - キー - 型 * - channel_id - string * - connection_id - string ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20180404.CastSpotlight \ channel_id=sora \ connection_id=KD9N57E2RN5T1BDEA7S7SH038M \ -vvv POST / HTTP/1.1 Accept: application/json, */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 75 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/0.9.9 x-sora-target: Sora_20180404.CastSpotlight { "channel_id": "sora", "connection_id": "KD9N57E2RN5T1BDEA7S7SH038M" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 72 content-type: application/json date: Fri, 27 Apr 2018 02:01:35 GMT server: Cowboy { "channel_id": "sora", "connection_id": "KD9N57E2RN5T1BDEA7S7SH038M" } ``` ### CastAlwaysSpotlight > **危険** > > この API 廃止されました。 **廃止**: 2021 年 12 月リリースの Sora にて廃止 **x-sora-target**: Sora_20180404.CastAlwaysSpotlight 指定した参加者を常に画面に表示します。 * - キー - 型 * - channel_id - string * - connection_id - string * - spotlight_id (オプション) - string spotlight_id を指定しない場合はどこかのスポットライトに入ります。 ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20180404.CastAlwaysSpotlight \ channel_id=sora \ connection_id=KD9N57E2RN5T1BDEA7S7SH038M \ spotlight_id=spotlight-1 \ -vvv POST / HTTP/1.1 Accept: application/json, */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 106 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/0.9.9 x-sora-target: Sora_20180404.CastAlwaysSpotlight { "channel_id": "sora", "connection_id": "af9103b1-2412-4a3c-88b2-cc4d84114d98", "spotlight_id": "spotlight-1" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 101 content-type: application/json date: Wed, 25 Apr 2018 07:11:30 GMT server: Cowboy { "channel_id": "sora", "connection_id": "KD9N57E2RN5T1BDEA7S7SH038M", "spotlight_id": "spotlight-1" } ``` ### CancelSpotlight > **危険** > > この API 廃止されました。 **廃止**: 2021 年 12 月リリースの Sora にて廃止 **x-sora-target**: Sora_20180404.CancelSpotlight 指定した参加者を常に画面に表示する状態を解除します。 * - キー - 型 * - channel_id - string * - connection_id - string ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20180404.CancelSpotlight \ channel_id=sora \ connection_id=KD9N57E2RN5T1BDEA7S7SH038M \ -vvv POST / HTTP/1.1 Accept: application/json, */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 75 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/0.9.9 x-sora-target: Sora_20180404.CancelSpotlight { "channel_id": "sora", "connection_id": "KD9N57E2RN5T1BDEA7S7SH038M" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 72 content-type: application/json date: Wed, 25 Apr 2018 07:12:01 GMT server: Cowboy { "channel_id": "sora", "connection_id": "KD9N57E2RN5T1BDEA7S7SH038M" } ``` ### DowngradeSpotlightBitRate > **危険** > > この API 廃止されました。 **廃止**: 2021 年 12 月リリースの Sora にて廃止 **x-sora-target**: Sora_20181023.DowngradeSpotlightBitRate 指定したスポットライトチャネルのビットレートを下げる。 * - キー - 型 * - channel_id - string 現時点ではどの程度下げるかどうかは指定することはできません。 ``` $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20181023.DowngradeSpotlightBitRate \ channel_id=sora \ -vvv ``` ### ResetSpotlightBitRate > **危険** > > この API 廃止されました。 **廃止**: 2021 年 12 月リリースの Sora にて廃止 **x-sora-target**: Sora_20181023.ResetSpotlightBitRate 指定したスポットライトチャネルのビットレートを戻します。 * - キー - 型 * - channel_id - string ``` $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20181023.ResetSpotlightBitRate \ channel_id=sora \ -vvv ``` ### RequestSpotlightQuality > **危険** > > この API 廃止されました。 **廃止**: 2020 年 12 月リリースの Sora にて廃止 **代替 API**: Sora_20201005.RequestRtpStream **x-sora-target**: Sora_20200807.RequestSpotlightQuality 指定した参加者の受信している映像ストリームのクオリティを変更します。 スポットライトのフォーカスとは別に、画質を受信ストリームすべて、またはストリームごと変更可能です。 現時点では low か middle のみ指定可能です。 * - キー - 型 * - channel_id - string * - connection_id - string * - stream_id (オプション) - string * - quality - string (low / middle / high) ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20200807.RequestSpotlightQuality \ channel_id=sora connection_id=DRPBMP6FEH49S5CSB04EDSTQ38 quality=low -vvv POST / HTTP/1.1 Accept: application/json, */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 87 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.0.0 x-sora-target: Sora_20200807.RequestSpotlightQuality { "channel_id": "sora", "connection_id": "DRPBMP6FEH49S5CSB04EDSTQ38", "quality": "low" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 82 content-type: application/json date: Wed, 09 Sep 2020 08:47:49 GMT server: Cowboy { "channel_id": "sora", "connection_id": "DRPBMP6FEH49S5CSB04EDSTQ38", "quality": "low" } ``` ### ResetSpotlightQuality > **危険** > > この API 廃止されました。 **廃止**: 2020 年 12 月リリースの Sora にて廃止 **代替 API**: Sora_20201005.ResetRtpStream **x-sora-target**: Sora_20200807.ResetSpotlightQuality 指定した参加者の受信している映像ストリームのクオリティをリセットします。 RequestSpotlightQuality で変更された画質をリセットします。 * - キー - 型 * - channel_id - string * - connection_id - string * - stream_id (オプション) - string ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20200807.ResetSpotlightQuality \ channel_id=sora connection_id=DRPBMP6FEH49S5CSB04EDSTQ38 -vvv POST / HTTP/1.1 Accept: application/json, */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 69 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.0.0 x-sora-target: Sora_20200807.ResetSpotlightQuality { "channel_id": "sora", "connection_id": "DRPBMP6FEH49S5CSB04EDSTQ38" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 66 content-type: application/json date: Wed, 09 Sep 2020 08:48:35 GMT server: Cowboy { "channel_id": "sora", "connection_id": "DRPBMP6FEH49S5CSB04EDSTQ38" } ``` # 開発者ツール ## 概要 時雨堂がオープンソースとして開発している [Sora DevTools](https://github.com/shiguredo/sora-devtools) を Sora に組み込んでいる機能です。 ## 目的 - Sora の機能を試してもらう - Sora を利用したアプリケーションの開発中に機能を確認する - Sora で何か問題が発生した場合に再現を行ってもらう ## 設定 > **警告** > > 商用環境ではこの設定は利用せず、開発環境でのみ有効にしてください。 `sora.conf` にて `devtools` を `true` にすることで利用可能になります。 ```ini devtools = true ``` ## オープンソース版 > **重要** > > オープンソース版 Sora DevTools はサポート対象外です。 > サポートを受ける場合は必ず Sora に組み込まれている開発ツール機能を利用して下さい。 Sora に組み込まれている開発者ツールはオープンソースとして GitHub にて [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0) で公開されています。 [shiguredo/sora-devtools: Sora DevTools](https://github.com/shiguredo/sora-devtools) ### サポートについて オープンソースの Sora DevTools は Sora のサポートには含まれません。 ### Discord Discord にてコミュニティを運営しています。 なにか質問したい場合は Discord サーバーへ参加してください。 開発者ツールのチャネルは `#sora-devtools` です。 # クラスター機能 > **警告** > > クラスター機能は実験的機能のため、正式版では仕様が変更される可能性があります ## 概要 これは Sora でクラスターを構成し、冗長化、負荷分散を行うための仕組みです。 クラスター内では、ひとつのチャネル ID への接続は、担当するひとつの Sora ノードにすべて割り当てられます。 クライアントがクラスターを構成しているいずれかの Sora に接続した際には、 そのチャネル ID で、接続すべき Sora の `Signaling URL` を提示する仕組みです。 ## 目的 可用性を高めるため Sora 複数台でクラスターを組み、冗長化やロードバランシングを実現します。 ## 仕組み Sora のクラスター機能の仕組みは、ひとつのチャネル ID への接続は、 担当するひとつの Sora ノードにすべて割り当てるものです。 これを実現するために、Sora のクラスターに参加しているそれぞれの Sora ノードは、 どのノードがどのチャネルを担当するべきかを把握しています。 そして、自分が担当でなかったら担当者にリダイレクトすることにより、 クライアントは担当ノードを意識することなく、任意のノードにアクセスするだけで担当ノードに接続できます。 ## 特徴 > **注釈** > > これらの仕組みは `sora.conf` にてクラスター機能を有効にした場合に使用できます ### クライアントへの複数シグナリング設定 Sora SDK にシグナリング URL を複数指定することで、いずれかの Sora ノードが正常に動作していれば Sora に繋がります。 ### Sora ノード選択 / ロードバランス機能 クラスターを構築している Sora ノードの中で `現在の同時接続数` を `ライセンスの最大同時接続数` で割った値が一番小さい Sora ノードに新規チャネル ID の担当を割り当てます。 値が全て同じ場合は接続しに行ったノードが担当します。 すでにそのチャネル ID がクラスター内部で利用されている場合は、 そのチャネル ID を担当している Sora ノードへ割り当てられます。 ### シグナリングのリダイレクト機能 > **重要** > > Sora の SDK を利用している場合は、基本的にここに書かれているリダイレクトの > 細かい仕様を把握する必要はありません。 `"type": "connect"` を送った際、認証に入る前に `{"type": "redirect", "location": "wss://sora1.example.com/signaling"}` が戻ってくる場合があります。 この場合は送られてきたシグナリング URL に切り替えて再度 `type: connect` を行ってください。 その際は `{type: connect, redirect: true}` のように `redirect: true` を追加情報として入れてください。 ### HTTP API のリダイレクト機能 チャネル ID を指定する HTTP API を利用する場合、リダイレクトが発生することがあります。 指定されたチャネル ID を他ノードが担当している場合に、ステータスコード 307 (Temporary Redirect)の HTTP 応答により、クライアントにそのノードへのリダイレクトを要求します。 ステータス 307 の処理は HTTP のクライアントとするツールやライブラリにより異なります。 必要に応じて、リダイレクト応答の Location ヘッダーへアクセスを継続するようにしてください。 たとえば、`curl` コマンドの場合は、 `-L` オプションを指定することでリダイレクト先への再要求を行います。 ### クラスター自動参加機能 クラスターにノードが自動で参加する機能です。 Sora はクラスターが有効な際、起動時に `sora.conf` の [contact_node_name_list](CLUSTER.html#a3d0fd) に存在する ノード名に対してクラスターの参加を自動で試みます。 そのノードが一度でもクラスターに参加したことがある場合は、そのクラスターに参加していた時の ノード一覧を利用して、クラスターへの参加を自動で試みます。 新規にクラスターを作成する場合には事前に [InitCluster](EXPERIMENTAL_API.html#621990) API を実行して、 クラスターを初期化しておく必要があります。 ### クラスター手動参加機能 > **重要** > > `sora.conf` の [contact_node_name_list](CLUSTER.html#a3d0fd) を利用した自動参加の利用を推奨しています。 複数の Sora でクラスターを手動で組む機能です。クラスターに参加する際に [JoinCluster](EXPERIMENTAL_API.html#17f3f5) API を叩きます。 すでにクラスターが存在している場合には、そこに参加しているノードのいずれかを引数の `contact_node_name` で 指定してください。クラスターに参加していて、初期化済みであれば、どのノードでもかまいません。 新規にクラスターを作成する場合には事前に [InitCluster](EXPERIMENTAL_API.html#621990) API を実行して、 クラスターを初期化しておく必要があります。 ### クラスター自動復旧 クラスターで利用しているネットワークに障害が発生した際、個々のノードはクラスターを構成する他のノードへの接続を試み、 復旧処理を行います。 ### ネットワーク分断時の接続受付の停止 ネットワーク分断時には Sora のノード間で通信ができず、クラスター内の情報の整合性が取れなくなる可能性があります。 不整合を回避するために、Sora は自分が過半数未満のグループに属した場合に、既存の接続を切断した上で、 新規接続の受付を停止します。 ### 特定ノードへの新規チャネル ID の割り当て停止 [モード機能](MODE.html) の [イニシャルモード](MODE.html#74fada) 、 [新規コネクションブロックモード](MODE.html#0b67d3) または [新規セッションブロックモード](MODE.html#041e1c) になっている場合は、 そのノードに対して新規チャネル ID の割り当てを行いません。 ### 録画情報の共有 録画の情報はクラスター内部で共有されます。 たとえば [StartRecording](API.html#c5b527) API をあるノードに対して実行した後にそのノードが停止しても 録画情報は他のノードに残り続けます。 ## ポート番号の開放 以下のポート番号を開放して下さい - epmd(Erlang Port Mapper Daemon)で利用する TCP/IP ポート番号- 4369 - ノード間通信に利用する TCP/IP ポート番号- 49010 - 49020 - `sora.conf` の `cluster_listen_(min|max)_port` にて指定可能です ## 注意 ### ライセンス クラスターの 1 Sora ノードにつき 1 ライセンスが必要になります。 3 台の Sora ノードでクラスターを組む場合は 3 ライセンス必要になります。 > **注釈** > > [最大ノード数ライセンス](LICENSE.html#aee259) を利用することで、同一ライセンスを複数 Sora ノードで利用することが可能になります。 ### クラスターのノード数 クラスター機能を有効にしている場合は 1 ノードだけでは利用できず、必ず 2 ノード以上である必要があります。 > **注釈** > > 1 ノードの場合は接続を受け付けません 3 ノード以上での運用を強く推奨します。 > **注釈** > > 2 ノードのクラスターでは片方のノードが停止すると、生きているノードは過半数未満となるため接続を受け付けません。 > そのため 1 ノードの場合よりも可用性が落ちます。 ### クラスターの最大ノード数 クラスターを構築するノードの最大数は 10 ノードを想定しています。 これ以上を検討されている場合はサポートまでご連絡ください。 ### クラスター構成情報ファイル > **危険** > > このファイルは Sora が内部で利用するためのファイルなので触らないでください。 Sora でクラスターを利用する場合、クラスター参加後のノード情報を永続化する `data/` ディレクトリ以下にファイルを生成します。 Sora のバージョンアップ時にこのファイルをコピーする必要はありません。 ファイルが無い場合、クラスターに参加した際に生成されます。 バージョンアップ以外の場合は `data/` ディレクトリを消さないでください。 ### クラスターからのノードの完全消去について クラスターからノードを完全に消去させる場合は `bin/sora stop` で停止させた後に、 クラスターを構成してる実行中のノードのいずれかに対し、 [PurgeClusterNode](EXPERIMENTAL_API.html#13b35a) API を実行します。 > **警告** > > [PurgeClusterNode](EXPERIMENTAL_API.html#13b35a) API はクラスターからノードを完全に消去するための API です。 > 再参加するノードに対しては基本的に使用しないでください。 ### PurgeClusterNode API で完全消去したノードの再参加 > **警告** > > [PurgeClusterNode](EXPERIMENTAL_API.html#13b35a) API はクラスターからノードを完全に消去するための API です。 > 通常は、再参加するノードに対しては使用しないでください。 > ここの説明は、長期間に渡ってクラスターに参加できないため、苦肉の策として > [PurgeClusterNode](EXPERIMENTAL_API.html#13b35a) API を使った場合の説明です。 > **警告** > > [PurgeClusterNode](EXPERIMENTAL_API.html#13b35a) APIでクラスターから消去したノードは、 > 以下に示す手順を経ずに再起動してはいけません。 クラスターからノードを完全消去した場合、そのまま再度参加をすることはできません。 再度クラスターに参加をする場合は `data/` ディレクトリを削除する必要があります。 PurgeClusterNode API を実行して、さらにそのノードの `data/` ディレクトリを削除した場合、そのノードは 完全に新規のノードとして取り扱われます。 この状態になったノードは新規ノードですので、 [JoinCluster](EXPERIMENTAL_API.html#17f3f5) API をつかうか、 `sora.conf` の [contact_node_name_list](CLUSTER.html#a3d0fd) を利用してクラスターに参加できます。 ### クラスターから消去されたノードを別クラスターに参加させたい場合 あるクラスター A に参加していたノードを、A から削除して別のクラスター B に参加させたい状況を考えます。 > **警告** > > PurgeClusterNode API はクラスターからノードを完全に消去するための API です。 > 通常は、再利用するノードに対しては使用しないでください。 > Sora が稼働するサーバーを再利用して、別のクラスター B に参加する新規ノードが欲しい場合には、 > Sora リリースの tar.gz を展開して、まっさらな状態からの新規ノード構築を推奨します。 > ここの説明は、どうしても既存の tar.gz 展開ディレクトリを再利用したい場合の説明です。 PurgeClusterNode API で消去されたノードは以下の 2 点で以前参加していたクラスター A のノード群を覚えています。 - sora.conf の [contact_node_name_list](CLUSTER.html#a3d0fd) - sora 起動ディレクトリ以下の `data/` ディレクトリ内のデータ よって、再利用する場合にはこれらの情報を無くす必要があります。 - [contact_node_name_list](CLUSTER.html#a3d0fd) は新しい別クラスター B のノードのリストにするか空にする必要があります - `data/` ディレクトリは削除する必要があります > **警告** > > 以上の手順を踏まずに別クラスター B に参加させようとすると、最悪の場合には A と B がひとつになった > クラスターになってしまう場合があります。 ## クラスター機能有効時のモード クラスター機能を有効にした場合、 Sora は [イニシャルモード](MODE.html#74fada) という クラスター機能だけで利用される特殊なモードで起動します。 - [イニシャルモード](MODE.html#74fada) はすべての接続を受け入れません - [イニシャルモード](MODE.html#74fada) はクラスターに参加後、過半数以上のグループになったタイミングで[ノーマルモード](MODE.html#920e82) へ自動で切り替わります - [イニシャルモード](MODE.html#74fada) はモード変更 API では指定できません ## ネットワーク障害やノード障害 Sora のクラスター機能はネットワーク障害やノード障害が発生した際に、 自動で新規接続の受付の停止とそこからの復旧を試みます。 ### 発生しうる問題と新規接続の受付停止 ネットワーク障害等が発生した場合には、 Sora のノード間で通信ができず、クラスター内の情報の整合性が取れなくなる可能性があります。 たとえば、5 ノードのクラスターが 3 ノードからなるグループ A と 残りの 2 ノードからなるグループ B の 2 グループに分断されるということが起こりえます。 それぞれのグループ内では通信ができるものの、他グループへの通信ができないという状態です。 この状態ですべてのノードが接続を受け付けると、同じチャネル ID を指定していても、 あるクライアントはグループ A に繋がり、別のクライアントは グルーブ B につながる可能性があります。 その場合はクライアント間で音声と映像が届かなくなります。 このような状況を防止するため、Sora は自分が過半数未満のグループに属した場合に、新規接続の受付を停止します。 特に、自分が孤立した場合もこれに含まれます。 その後、クラスター自動復旧により、通信できるノードが過半数以上となった場合には、自動で新規接続の受付を再開します。 #### 新規接続の受付がまったくできなくなる場合 障害の状況によっては新規接続の受付がまったくできなくなる場合もあります。 例えばネットワークの分断によって、5 ノードのクラスターが 2 ノード、2 ノード、1 ノードという 3 つのグループに分断された状況を考えます。 この場合にはどのノードも過半数未満となるため、新規接続の受付はまったくできなくなります。 ネットワーク障害ではなくても、5 ノードクラスターで、3 ノードが停止してしまった場合には、残った 2 ノードは 過半数未満となるため、新規接続の受付はできません。 ### 通信できるノードが過半数未満となった場合の挙動 ノード数が過半数未満のクラスターに参加しているノードは、接続中のすべての接続を切断し、その後は接続を受け入れません。 また、その時のモードによってモードが変わることがあります。 - [ノーマルモード](MODE.html#920e82) の場合には [イニシャルモード](MODE.html#74fada) に状態を移行します - [ノーマルモード](MODE.html#920e82) 以外のモードであった場合はモードは変わりません その後はクラスター自動復旧を試みます。 ### 通信できるノードが過半数以上となった場合の挙動 通信できるノードが過半数未満から過半数以上に変わったタイミングで、そのときのモードによってモードが変わることがあります。 - [イニシャルモード](MODE.html#74fada) の場合には [ノーマルモード](MODE.html#920e82) に状態を移行します - [イニシャルモード](MODE.html#74fada) 以外のモードであった場合はモードは変わりません 遷移後のモードに従って、新規接続を受け付けます。 ### 全ノードが過半数未満に所属した場合の挙動 ネットワーク障害等が発生したことで、いずれのノードも通信できるノードが過半数未満になった場合、 新規接続はまったく受け付けられない状態になります。 この場合でも、永続化しておいたノード一覧を利用し自動でクラスターの復旧を試みます。 復旧して過半数以上のグループができた場合は新規接続が可能になります。 ## クラスター環境での録画 ### 録画情報の共有 録画の情報はクラスター内部で共有されます。 たとえば [StartRecording](API.html#c5b527) API をあるノードに対して実行した後にそのノードが停止しても 録画情報は他のノードに残り続けます。 また [StopRecording](API.html#fd0de5) API はどのノードに対しても実行することができます。 たとえば、あるチャネルで [StartRecording](API.html#c5b527) API が実行された後に、 ノード A に接続がきて録画が開始したとします。 このノード A がノード障害等で終了した後に、同じチャネルで別の接続がノード B に来た場合には ノード B で録画が進行します。 ### 録画ファイルの出力ノード `archive-.json`, `archive-.webm` の録画ファイルは、接続を担当するノードで 出力されます。 次のような場合には同一の `recording_id` に属する録画ファイルが、 複数ノードにまたがって出力されることがありますのでご注意ください。 1. 録画開始 2. ノード A に接続が来てしばらくして終了、録画ファイルがノード A に作られる 3. ノード A が停止 4. ノード B に接続が来てしばらくして終了、録画ファイルがノード B に作られる ### `report-.json` ファイルの出力ノード あるチャネルに対して、 [StopRecording](API.html#fd0de5) API を実行した場合には録画が終了し、 `report-.json` ファイルが出力されます。 このファイルの出力ノードは次のとおりです。 - そのチャネルに接続したクライアントがひとつもなかった場合はどのノードで出力されるかは未定です- ただし、クラスター内のいずれかのノードで出力されます - そのチャネルに接続中のクライアントがいる場合は、チャネルの担当ノードで出力されます - そのチャネルに接続したクライアントが過去にいた場合は 2 パターンがありえます- クライアントが接続したノードが生存し続けている場合はそのノードで出力されます - ノードが落ちている、または停止した後に再起動した場合にはどのノードで出力されるかは未定です- ただし、クラスター内のいずれかのノードで出力されます ### `report-.json` ファイルが一時的に出力されない場合 全ノードが過半数未満に所属した場合には `report-.json` ファイルが出力されません。 5 ノードのクラスターがあるとして、いくつか例を示します。 - ネットワーク障害が発生し、2 + 2 + 1 に分断された場合 - ノード障害(運用での停止も含む)が発生し、3 ノードが停止した場合 - ノード障害で 1 ノードが停止した状態でネットワーク障害が発生し、 2 + 2 に分断された場合 このあとに分断が解消し、過半数以上のグループができたあとに [StopRecording](API.html#fd0de5) API を 実行すると `report-.json` ファイルが出力されます。 ## 設定 ### cluster クラスター機能を利用する場合、 `sora.conf` にて [cluster](SORA_CONF.html#b2cd99) を `true` を設定する必要があります。 デフォルトでは `cluster` は有効になっていません。 > **重要** > > cluster = true にして Sora を起動した場合、 > Sora はすべての接続を受け付けない [イニシャルモード](MODE.html#74fada) モードで起動します。 > > 自動または手動でクラスターに参加した後、過半数以上のグループになった時点で > [ノーマルモード](MODE.html#920e82) へ自動で切り替わります。 ```ini cluster = true ``` ### node_name クラスター機能を利用する際のノード名を指定して下さい。 この名前はクラスター内のノードの識別に使われます。 具体的には、クラスターノード間の通信相手の特定や、 `sora.conf` の [contact_node_name_list](CLUSTER.html#a3d0fd) 、 [JoinCluster](EXPERIMENTAL_API.html#17f3f5) API、 [PurgeClusterNode](EXPERIMENTAL_API.html#13b35a) API で指定する名前として利用します。 > **重要** > > `node_name` はクラスター内のすべてのノードでユニークである必要があります ノード名の @ の前には、正規表現 `[0-9A-Za-z_\\-]+` にマッチする文字列を指定してください。 また @ の後ろには、サーバーのドメイン名(FQDN)や、IP アドレスを指定してください。 > **重要** > > クラスターどうしの通信は暗号化されていないため、プライベートネットワークを利用するか > 暗号化されたネットワークを利用してください。 > **重要** > > @ の後ろにホスト名("." を含まない文字列)を指定すると、ノード間で通信が行えなくなってしまいます。 > **重要** > > クラスター参加後にノード名を変更する場合には、古い方の名前は > [PurgeClusterNode](EXPERIMENTAL_API.html#13b35a) API を用いて削除してください。 > また `data/` のディレクトリ削除も必ずおこなってください。 > > 詳しくは [ノード名変更手順](CLUSTER.html#1ab2c5) を参照してください。 ```ini # ドメイン名を指定する例 node_name = node01@node01.example.com ``` ```ini # IP アドレスを指定する例 node_name = node02@192.0.2.1 ``` ### contact_node_name_list クラスター機能が有効な場合で、 `sora.conf` の [contact_node_name_list](CLUSTER.html#a3d0fd) が指定されていた場合、 起動時に自分以外のノード名に対して自動でクラスターの参加を試みます。 > **注釈** > > 自分自身のノード名が `concact_node_name_list` に含まれていても無視します。 ```ini node_name_list = sora1@192.0.2.1, sora2@192.0.2.2, sora3@192.0.2.3 ``` ### cluster_auto_reconnect クラスター機能が有効な場合で、 `sora.conf` の `cluster_auto_reconnect` が `true` の場合、 ネットワーク障害やノード障害の発生時に自動で再接続を試みます。 この設定はデフォルトで有効です。 ```ini cluster_auto_reconnect = true ``` ### external_signaling_url `sora.conf` にてシグナリングの URL を指定して下さい。 この URL はクラスター機能を利用した際に `"type": "redirect"` の `"location"` の値として払い出されます。 ```ini external_signaling_url = wss://node1.example.com/signaling ``` 上記の設定をした場合は `{"type": "redirect", "location": "wss://node1.example.com/signaling"}` として払い出されます。 ### external_api_url `sora.conf` にて API の URL を指定して下さい。 この URL はクラスター機能を利用した際に API を適切なノードに HTTP 307 でリダイレクトする際、 HTTP ヘッダー `"location"` の値として払い出されます。 ```ini external_api_url = https://node1.example.com/ ``` ### cluster_listen_(min|max)_port `sora.conf` にてクラスター情報の同期に利用する TCP/IP の受信ポートの範囲を指定してください。 デフォルトでは 49010 - 49020 が指定されています。 ```ini cluster_listen_min_port = 49010 cluster_listen_max_port = 49020 ``` ## API ### クラスター初期化 API クラスターを構築するときは、まずクラスターの初期化を行います。 > **重要** > > クラスターの初期化はクラスターを初めて構築する際と、クラスターが破綻した際に行う必要があります。 クラスターの初期化を実行する場合は `Sora_20221221.InitCluster` API をクラスター構築するノードで実行します。 `node_name_list` にはクラスターを構成するノードを、 API を実行するノードを含め指定してください。 1 ノードだけを指定した場合には、そのノードは initial モードに留まります。 その後に [JoinCluster](EXPERIMENTAL_API.html#17f3f5) API を実行すると normal モードに遷移します。 API の詳細は [InitCluster](EXPERIMENTAL_API.html#621990) API をご確認ください。 ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20221221.InitCluster \ node_name_list:='["node-02@192.0.2.7", "node-03@10.99.0.8", "node-01@192.0.2.5"]' \ -vvv HTTP/1.1 200 OK content-length: 646 content-type: application/json date: Tue, 16 Nov 2021 08:42:25 GMT server: Cowboy { "node_name_list": [ "node-02@192.0.2.7", "node-03@192.0.2.8", "node-01@192.0.2.5" ] } ``` > **重要** > > クラスターのノードが恒久的に破損し、過半数以下になった場合には、 > 再度クラスターの初期化を行う必要があります。 > > 詳しくは [クラスター破綻からの再構築手順](CLUSTER.html#7c3099) を参照してください。 ### クラスター参加 API > **ヒント** > > `sora.conf` の [contact_node_name_list](CLUSTER.html#a3d0fd) を利用したクラスターへの自動参加の利用を推奨しています。 参加するノードに対して、すでにクラスターに参加しているノードを指定してクラスターへ参加します。 API の詳細は [JoinCluster](EXPERIMENTAL_API.html#17f3f5) API をご確認ください。 ```console http POST 127.0.0.1:3000/ x-sora-target:Sora_20211215.JoinCluster \ contact_node_name=sora1@192.0.2.5 HTTP/1.1 200 OK content-length: 646 content-type: application/json date: Tue, 16 Nov 2021 08:42:25 GMT server: Cowboy { "node_name_list": [ "node-01@192.0.2.5", "node-02@192.0.2.7", "node-03@192.0.2.8" ] } ``` ### クラスターノード完全消去 API ある Sora ノードが障害で再参加が難しい、またはスケールインのためにノード破棄する場合は [PurgeClusterNode](EXPERIMENTAL_API.html#13b35a) API を利用して、そのノード情報を完全消去してください。 これはクラスターのどのノードでもかまわないので 1 回だけ実行すれば、完全消去した結果はクラスター内部で共有されます。 > **警告** > > PurgeClusterNode API はクラスターからノードを完全に消去するための API です。 > 再参加するノードに対しては基本的に使用しないでください。 > この API を含めた運用の手順は [クラスター運用](CLUSTER.html#0233aa) をご確認ください。 ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20220629.PurgeClusterNode \ target_node_name=sora1@192.0.2.5 ``` 詳細は [PurgeClusterNode](EXPERIMENTAL_API.html#13b35a) API をご確認ください。 ### クラスターノード一覧 API 詳細は [ListClusterNodes](EXPERIMENTAL_API.html#a70901) API をご確認ください。 ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20211215.ListClusterNodes HTTP/1.1 200 OK content-length: 1051 content-type: application/json date: Tue, 16 Nov 2021 08:36:25 GMT server: Cowboy [ { "external_api_url": "http://192.0.2.5:3000/", "epoch": 1, "license_max_connections": 600, "license_max_nodes": 10, "license_serial_code": "ABCDEF-SRA-E001-203801-400", "license_type": "Experimental", "node_name": "node-01@192.0.2.5", "connected": true, "mode": "normal", "external_signaling_url": "wss://node-01.example.com/signaling", "version": "2022.1.0" }, { "external_api_url": "http://192.0.2.7:3000/", "epoch": 1, "license_max_connections": 600, "license_max_nodes": 10, "license_serial_code": "ABCDEF-SRA-E002-203801-400", "license_type": "Experimental", "node_name": "node-02@192.0.2.7", "connected": true, "mode": "normal", "external_signaling_url": "wss://node-02.example.com/signaling", "version": "2022.1.0" }, { "external_api_url": "http://192.0.2.8:3000/", "epoch": 1, "license_max_connections": 600, "license_max_nodes": 10, "license_serial_code": "ABCDEF-SRA-E003-203801-500", "license_type": "Experimental", "node_name": "node-03@192.0.2.8", "connected": true, "mode": "normal", "external_signaling_url": "wss://node-03.example.com/signaling", "version": "2022.1.0" } ] ``` ### クラスターチャネル割り当て一覧 API 詳細は [ListClusterChannels](EXPERIMENTAL_API.html#0a4459) API をご確認ください。 ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20211215.ListClusterChannels HTTP/1.1 200 OK content-length: 646 content-type: application/json date: Tue, 16 Nov 2021 08:42:25 GMT server: Cowboy [ { "channel_id": "sora", "owners": [ { "node_name": "node-01@192.0.2.5", "epoch": 1, "epoch_latest": true, "connected": true } ] }, { "channel_id": "lemon", "owners": [ { "node_name": "node-01@192.0.2.5", "epoch": 1, "epoch_latest": true, "connected": true } ] }, { "channel_id": "hisui", "owners": [ { "node_name": "node-03@192.0.2.5", "epoch": 2, "epoch_latest": true, "connected": true } ] }, { "channel_id": "zakuro", "owners": [ { "node_name": "node-03@192.0.2.5", "epoch": 2, "epoch_latest": true, "connected": true } ] } ] ``` ## クラスター構築 > **重要** > > `node_name` はクラスター内のすべてのノードでユニークである必要があります ### ライセンス Sora ノード数分のライセンスが必要になります。 Sora 3 台でクラスターを組む場合は通常のライセンスが 3 つ、もしくは 3 ノード以上に対応した 最大ノード数ライセンスが 1 つ必要です。 ### ノードの未初期化、初期化済み状態 クラスターの場合、各ノードは「未初期化」または「初期化済み」の状態を持ちます。 `bin/sora daemon` や `bin/sora foreground` コマンドで最初に起動したとき、そのノードは「未初期化」の 状態で起動します。 この状態のノードが「初期化済み」の状態に遷移するのは以下のどれかのイベントが発生した場合です。 - [InitCluster](EXPERIMENTAL_API.html#621990) の `node_name_list` に指定され、クラスターの初期化が成功した場合- このとき、 `node_name_list` に指定された他のノードも同時に「初期化済み」に遷移します - sora.conf の [contact_node_name_list](CLUSTER.html#a3d0fd) を利用した自動参加が成功した場合 - そのノードに [JoinCluster](EXPERIMENTAL_API.html#17f3f5) API が発行され、成功した場合 sora.conf の [contact_node_name_list](CLUSTER.html#a3d0fd) での参加も、[JoinCluster](EXPERIMENTAL_API.html#17f3f5) API での参加も、 相手が「初期化済み」である必要があります。 そのため、その前に一度だけ、 [InitCluster](EXPERIMENTAL_API.html#621990) API を実行し、「初期化済み」ノードを 作る必要があります。 一度「初期化済み」に遷移したノードは、その後も「初期化済み」の状態にとどまります。 「初期化済み」から「未初期化」に遷移する手順は通常の運用では発生しませんが、 `bin/sora stop` で停止して、 `data/` ディレクトリを削除した場合には「未初期化」状態になります。 > **注釈** > > Sora の新しいリリースバージョンに更新する場合、 tar.gz を展開した場合にも `data/` ディレクトリを > 古いバージョンからコピーしない場合は「未初期化」状態から始まります。 ### 3 台での構築 ここでは、3 ノードの Sora クラスターを構築する手順を示します。 クラスター特有ではない Sora の設定や起動方法については [チュートリアル](TUTORIAL.html#e103da) を参照してください。 > **注釈** > > クラスターを構築する際、クラスター間の通信に使うネットワークは、 > 可能な限りプライベートネットワークを利用してください。 > > クラスタ間の通信に使う IP アドレスは `node_name` の @ 以下の IP アドレスまたはドメイン名で指定します。 以下の手順の前提として、3 台のサーバーがそれぞれ TCP/IP で通信できる状態になっていること、 そして Sora の tar.gz が展開されて `bin/sora` が実行可能になっていることが必要です。 1. クラスター間の通信に必要な TCP/IP のポートをすべて開放する- TCP/IP 4369- ポート番号の変更はできません、必ずこのポートを開放してください - TCP/IP 49010-49020- `sora.conf` にて変更可能ですがデフォルトをお勧めします 2. 最初のノード(sora1)の `sora.conf` の設定をクラスター対応にする```ini node_name = sora1@192.0.2.101 cluster = true external_signaling_url = wss://sora-node1.example.com/signlaing external_api_url = https://sora-node1.example.com/api contact_node_name_list = sora1@192.0.2.101, sora2@192.168.0.102, sora3@192.168.0.103 ``` 3. 最初のノード(sora1)の Sora を起動する 4. 次のノード(sora2)の `sora.conf` の設定をクラスター対応にする```ini node_name = sora2@192.168.0.102 cluster = true external_signaling_url = wss://sora-node2.example.com/signlaing external_api_url = https://sora-node2.example.com/api contact_node_name_list = sora1@192.0.2.101, sora2@192.168.0.102, sora3@192.168.0.103 ``` 5. 次のノード(sora2)の Sora を起動する 6. 最後のノード(sora3)の `sora.conf` の設定をクラスター対応にする```ini node_name = sora3@192.168.0.103 cluster = true external_signaling_url = wss://sora-node3.example.com/signlaing external_api_url = https://sora-node3.example.com/api contact_node_name_list = sora1@192.0.2.101, sora2@192.168.0.102, sora3@192.168.0.103 ``` 7. 最後のノード(sora3)の Sora を起動する 8. 最初のノード(sora1)の Sora に [InitCluster](EXPERIMENTAL_API.html#621990) APIを実行し、3 ノードのクラスターとして初期化する```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20221221.InitCluster \ node_name_list:='["sora1@192.0.2.101", "sora2@192.168.0.102", "sora3@192.168.0.103"]' ``` 9. 最初のノード(sora1)の Sora に [ListClusterNodes](EXPERIMENTAL_API.html#a70901) APIを実行し、ノード一覧を取得する```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20211215.ListClusterNodes ``` - 結果として、sora1 から sora3 の 3 ノードの一覧が取得できれば、クラスターの構築は完了です ## クラスター運用 ### ノード数 Sora は 2 ノードからクラスターを構築できますが、 2 ノードの場合は可用性が 1 ノードの場合より低下するため、 3 ノード以上でのクラスター構築をお勧めしています。 ### クラスターからの一時的な離脱 モード切り替え API を利用し、 [新規コネクションブロックモード](MODE.html#0b67d3) または [新規セッションブロックモード](MODE.html#041e1c) に 切り替えます。 その後、すべての接続がいなくなったタイミングで Sora ノードを終了してください。 一時的に離脱したノードは、再起動するとそのままクラスターに参加して動作します。 ### 一時的に離脱したノードを含めるクラスターノード一覧 [ListClusterNodes](EXPERIMENTAL_API.html#a70901) API では現在クラスターに参加しているノード一覧が返ります。 結果に一時的に離脱したノードを含めるには、 `include_all_known_nodes` を `true` に指定し API を実行すると、そのノードが知っているすべてのノードを返します。 ### クラスターからノード情報の完全消去 > **重要** > > 恒久的にノードを破棄する場合には、必ず、この作業を行ってください。 特定のクラスターノードが障害が起きた後、復旧が難しい場合は [PurgeClusterNode](EXPERIMENTAL_API.html#13b35a) API を利用して、 クラスターに参加しているノードから、障害が起きたノードの情報を完全消去してください。 また、スケールインのためにノードを破棄する場合も同様に [PurgeClusterNode](EXPERIMENTAL_API.html#13b35a) API を 利用して、破棄したノードの情報を完全消去してください。 この作業はクラスターの新鮮さを保つために必要な作業となります。 この作業を行わないと存在していないノードが残り続けることで過半数かどうかの判断を誤る場合があります。 > **警告** > > PurgeClusterNode API はクラスターからノードを完全に消去するための API です。 > 近い将来に再び参加するノードに対しては基本的に使用しないでください。 ### クラスターのアップデート > **注釈** > > ローリングアップデートを推奨しています。 1. アップデート対象の Sora ノードを [ChangeMode](MODE.html#3af05f) API で [新規コネクションブロックモード](MODE.html#0b67d3)または [新規セッションブロックモード](MODE.html#041e1c) に切り替えます- 必要があれば [ListChannels](EXPERIMENTAL_API.html#b27c42) API と [DisconnectChannel](API.html#a87366) API を利用して既存接続を切断します 2. すべての接続がなくなったら Sora を停止させます 3. 新しいバージョンの Sora へ入れ替えます 4. 新しいバージョンの Sora を起動します 5. [JoinCluster](EXPERIMENTAL_API.html#17f3f5) API を叩いて起動ノードをクラスターに参加させます( `sora.conf` で[contact_node_name_list](CLUSTER.html#a3d0fd) が指定されている場合にはこの手順は不要です) 6. [ListClusterNodes](EXPERIMENTAL_API.html#a70901) API で新しいバージョンの Sora がクラスターに参加できているかを確認します > **警告** > > 自動でクラスターに参加する処理がエラーになる可能性もあるため、 > [ListClusterNodes](EXPERIMENTAL_API.html#a70901) API で新しいバージョンの Sora がクラスターに参加できているかを必ず確認してください。 > 確認せずに他ノードのローリングアップデートを行った場合、クラスターに参加できていないままのノードが出てしまう > 可能性があります。 > さらに、複数のノードが参加できずに過半数を割ってしまうと、クラスターがまったく稼働しなくなる可能性もあります。 上の手順を 1 ノードごとに繰り返してください。 ### クラスター破綻からの再構築手順 クラスターのうち、過半数のノードが停止した場合、クラスターのすべての Sora ノードは接続を受け付けなくなります。 この状態からでも、停止したノードを再開させ、過半数のノードが正常に戻ったタイミングで、接続を受け付け始めます。 その場合は、ここで書かれている手順は必要ありません。 ただし、停止したノードがディスク障害などで `data/` ディレクトリを失ってしまったときや、使っていた IP アドレスが使えなくなってしまうなどの理由で、再開できないこともあります。 ここでは、3 ノードクラスターを組んでいたものの、うち 2 つのサーバーがディスク障害で `data/` ディレクトリを失った状態からの再構築手順を示します。 > **注釈** > > `data/` ディレクトリを失ってしまうと、「未初期化」状態になるため、再度クラスターへの参加手順が必要です。 > **注釈** > > `node_name` に IP アドレスを使う場合、IP アドレスが変わると `node_name` も変える必要があります。 > その際は `data/` ディレクトリを削除する必要があります。 - まずすべての Sora プロセスを停止状態にします - ディスク障害がおきたサーバーでは- Sora をインストールしなおします - 必要に応じて sora.conf 設定を行います - ディスク障害がおきなかったサーバーでは- `data/` ディレクトリを削除します - これを忘れると正しい再構築ができません、必ず削除してください - ここまでで、完全にまっさらの Sora クラスターを組む準備ができたことになります - すべての Sora ノードを起動します - [InitCluster](EXPERIMENTAL_API.html#621990) API を発行し、クラスターを初期化します 以上の手順で、あたらしい 3 ノードのクラスターが動き始めます。 ### ノード名変更手順 sora.conf の `node_name` を変更する際の手順を示します。 この手順は、例えば Sora が動作するサーバーの IP アドレスが変わり、 `node_name` の IP アドレス部分を 変更する場合に必要になります。 - 対象の Sora ノードを停止します - `data/` ディレクトリを削除します- これを忘れるとノード名変更が正しく実行できません、必ず削除してください - クラスターの起動しているノードのいずれかに対し、 [PurgeClusterNode](EXPERIMENTAL_API.html#13b35a) API を発行し、対象のノードをクラスターから削除します - sora.conf の `node_name` を変更します - 対象の Sora ノードを起動します - [JoinCluster](EXPERIMENTAL_API.html#17f3f5) API でクラスターにあらたに参加します- [contact_node_name_list](CLUSTER.html#a3d0fd) を利用している場合にはこの手順は必要ありません > **警告** > > この手順では、 `data/` ディレクトリの削除を含むため、対象のノードは「未初期化」状態になります。 > 複数のノードの名前変更が必要な場合には、1 ノードずつこの手順を実行することを推奨します。 > 1 ノードの変更のたびに、 [ListClusterNodes](EXPERIMENTAL_API.html#a70901) を使ってクラスターに正しく > 参加したことを確認して次のノードの手順に取り掛かってください。 #### ノード名変更をする場合の [contact_node_name_list](CLUSTER.html#a3d0fd) の扱い ノード名変更をするときに、クラスター自動参加を利用する方法を示します。 クラスター自動参加を使わずに [JoinCluster](EXPERIMENTAL_API.html#17f3f5) API を使う場合は この説明は関係しません。 関連する sora.conf の設定は [contact_node_name_list](CLUSTER.html#a3d0fd) です。 この設定は sora 起動時のときのみ利用されます。 また、一度クラスターに参加して初期化済みとなった場合には、正しいノードリストを知っているため、 この設定は無視されます。 以下、具体的に、3 ノードクラスターがあり、全ノードの IP アドレスが変わる状況を考えます。 状況: - 現状のノード名: `sora1@192.0.2.101`, `sora2@192.168.0.102`, `sora3@192.168.0.103`- 既にクラスターを組んでいる - それぞれを新規のノード名 `sora1@10.0.0.1`, `sora2@10.0.0.2`, `sora3@10.0.0.3` に変更する- まず sora1 を入れ替える - それが成功した後に sora2 を入れ替える - それが成功した後に sora3 を入れ替えと進める 現状のノードでは、既にクラスターを組んでいるため `concact_node_name_list` は利用されません。 そのため、sora.conf の設定を変更する必要はありません。 新しいノードでは、起動時に [contact_node_name_list](CLUSTER.html#a3d0fd) が利用されます。 入れ替えは順番に実行する必要があるため、現状のノードのみが起動中である状態や 新規ノードのみの状態、または混在している状態がありえます。 - 最初に sora1 を入れ替える際には、残り2ノードは現状のノード `sora2@192.168.0.102`, `sora3@192.168.0.103` である - 途中で sora2 を入れ替える際には、残り2ノードは現状のノード `sora3@192.168.0.103` と新規`sora1@10.0.0.1` が混在している - 最後に sora3 を入れ替える際には、残り2ノードは新規のノード `sora1@10.0.0.1`, `sora2@10.0.0.2` である このパターンに対して、ノード個別に [contact_node_name_list](CLUSTER.html#a3d0fd) を設定するのは複雑になってしまいます。 しかし、 [contact_node_name_list](CLUSTER.html#a3d0fd) に指定したノードのうち、起動していないノードは無視されますので、 既存ノードと新規ノードをすべて `sora1@192.0.2.101`, `sora2@192.168.0.102`, `sora3@192.168.0.103` `sora1@10.0.0.1`, `sora2@10.0.0.2`, `sora3@10.0.0.3` 指定することで、全ノードの入れ替えに対応できます。 > **注釈** > > 既存と新規の対応するノードが同時に起動することがないようにしてください。 > たとえば、 `sora1@10.0.0.1` を起動する前には、かならず `sora2@192.168.0.102` を停止した上で、 > `sora2@192.168.0.102` 再び起動することがないようにしてください。 ## シーケンス図 ### type: redirect seqdiag { default_fontsize = 14; edge_length = 200; クライアント ->> Sora1 [label = '"type": "connect"']; クライアント <<- Sora1 [label = '"type": "redirect"', rightnote='sora2 のシグナリング URL を返す']; クライアント ->> Sora2 [label = '"type": "connect"']; Sora2 -> アプリケーションサーバー [label = '認証ウェブフック']; Sora2 <-- アプリケーションサーバー [label = '200 OK\n{"allowed": true}']; クライアント <<- Sora2 [label = '"type": "offer"']; クライアント ->> Sora2 [label = '"type": "answer"', noactivate]; クライアント ->> Sora2 [label = '"type": "candidate"', noactivate]; === WebRTC 確立 === Sora2 -> アプリケーションサーバー [label = 'イベントウェブフック\n"type": "connection.created"']; Sora2 <-- アプリケーションサーバー [label = '200 OK']; } # マルチストリーム機能 ## 概要 マルチストリームとは一つの PeerConnection の中で複数の映像や音声を動的に追加したり削除したりする仕組みです。 この機能を利用することで、複数の PeerConnection を管理せずに複数の映像や音声を使用できるようになります。 ## 制限 - 配信側は音声 1 トラック、映像 1 トラック固定です - 動的に配信側のトラックを追加したりするマルチトラックには対応していません ## ブラウザ Chrome、Firefox、Safari、Edge と主要ブラウザすべてでマルチストリームを利用できます。 ## シグナリング仕様 マルチストリームを利用する場合は、ユーザーが参加や離脱をするたびに SDP を交換する必要があります。 ### "type": "connect" マルチストリームはデフォルトで有効になっています。 ```json { "type": "connect", "role": "sendrecv", "channel_id": "sora" } ``` マルチストリームを無効にする場合は `"type": "connect"` 時に `"multistream": false` を追加します。 ```json { "type": "connect", "role": "sendrecv", "channel_id": "sora", "multistream": false } ``` ### "type": "re-offer" ```json { "type": "re-offer", "sdp": ".." } ``` ### "type": "re-answer" `"type": "re-offer"` が送られてきた場合、 クライアントから Sora へ送るメッセージは `"type": "re-answer"` を送る必要があります。 ```json { "type": "re-answer", "sdp": ".." } ``` ## role マルチストリームでは role に `sendrecv` と `sendonly` と `recvonly` を指定することができます。 - `sendrecv` は配信と視聴を行います - `sendonly` は配信のみを行います - `recvonly` は視聴のみを行います ## マルチストリームにおける映像ビットレート自動シェアリング機能 > **重要** > > マルチストリームではビットレート自動シェアリング機能がデフォルトで有効になっています。 **音声のビットレートには影響しません** マルチストリームでは複数の映像を大量に受信するため、 配信側の映像ビットレートを、参加している配信者全員でシェアする機能がデフォルトで有効になっています。 そのため、マルチストリームにおける video の `bit_rate` は、 非マルチストリームの `bit_rate` とは扱いが異なります。 例えば、 `bit_rate` を 1200 と指定した場合、 2 人で配信している場合はそれぞれ配信に 600 kbps ずつ使用します。 ここに 1 人が加わり 3 人になると、 1 人 400 kbps ずつ使用して配信するようになります。 また、ここに 5 人が加わり、合計で 8 人になると、 1 人 150 kbps ずつ使用して配信するようになります。 配信の合計のビットレートを指定するのが video の `bit_rate` です。 ### 同じチャネルに参加している人が異なる `bit_rate` を指定した場合 2 人が同じチャネルに参加している状態で、1 人は映像のビットレートを 500 、もう 1 人は 1000 を指定して接続しているとします。 その場合、Sora では 500 を指定した人は配信に 250 kbps を使用し、 1000 を指定した人は配信に 500 kbps を使用します。 ### ビットレート自動シェアリング機能が適用されない条件 マルチストリームにおいても、以下の条件ではシェアされず、 `bit_rate` で指定した値を使います。 - スポットライトの場合 - サイマルキャストの場合 ### 無効にする場合 `sora.conf` の [multistream_auto_sharing_video_bit_rate](SORA_CONF.html#93f542) を `false` に指定することで無効にできます。 > **注釈** > > 設定を無効にした状態で、高いビットレートの配信者が増えていく場合、 > クライアント側の転送量が増え、さらにデコードの負荷も高くなってしまいます。 > そのため配信が安定的にできなくなり、結果的にクライアント側で配信ビットレートを下げるといった挙動が発生します。 > > 参加者が増えた場合でも高いビットレートを維持したいという状況ではない限りは設定を無効にすることは推奨しません。 ## シーケンス図 seqdiag { default_fontsize = 15; edge_length = 250; activation = none; === クライアント1 認証成功 === クライアント1 <<- Sora [label = '"type": "offer"']; クライアント1 ->> Sora [label = '"type": "answer"', noactivate]; === クライアント1 WebRTC 確立 === クライアント1 <<- Sora [label = 'シグナリング通知\nクライアント1\n"type": "connection.craeted"']; === クライアント2 認証成功 === クライアント2 <<- Sora [label = '"type": "offer"']; クライアント2 ->> Sora [label = '"type": "answer"', noactivate]; クライアント1 <<- Sora [label = '"type": "re-offer"']; クライアント1 ->> Sora [label = '"type": "re-answer"', noactivate]; === クライアント2 WebRTC 確立 === クライアント2 <<- Sora [label = 'シグナリング通知\nクライアント2\n"type": "connection.craeted"']; クライアント1 <<- Sora [label = 'シグナリング通知\nクライアント2\n"type": "connection.craeted"']; クライアント2 ->> Sora [label = '"type": "disconnect"', noactivate]; クライアント2 <<- Sora [label = 'WebSocket Close']; クライアント1 <<- Sora [label = 'シグナリング通知\nクライアント2\n"type": "connection.destroyed"']; } # サイマルキャスト機能 ## 概要 サイマルキャスト (Simulcast) は、配信時に 1 つの RTCPeerConnection から複数種類のエンコードした映像を配信する技術です。 映像を配信する際、 Sora に対して、 1 つの RTCPeerConnection で複数種類のエンコードした映像を送信することにより、 受信者がどの映像を受信するかを選択できるようになります。 ## 注意 ### 現時点でのサイマルキャストの仕様 2022 年 12 月 時点でサイマルキャストで出力されるストリームの本数は解像度とビットレートに依存しています。 **解像度とビットレートとストリーム数の関係** * - 解像度 - ビットレート - ストリーム数 * - 1920x1080 - 5000 kbps - 3 * - 1280x720 - 2500 kbps - 3 * - 960x540 - 1200 kbps - 3 * - 640x360 - 700 kbps - 2 * - 480x270 - 450 kbps - 2 * - 320x180 - 200 kbps - 1 この値は libwebrtc にハードコードされています。 ```cpp // These tables describe from which resolution we can use how many // simulcast layers at what bitrates (maximum, target, and minimum). // Important!! Keep this table from high resolution to low resolution. constexpr const SimulcastFormat kSimulcastFormats[] = { {1920, 1080, 3, webrtc::DataRate::KilobitsPerSec(5000), webrtc::DataRate::KilobitsPerSec(4000), webrtc::DataRate::KilobitsPerSec(800)}, {1280, 720, 3, webrtc::DataRate::KilobitsPerSec(2500), webrtc::DataRate::KilobitsPerSec(2500), webrtc::DataRate::KilobitsPerSec(600)}, {960, 540, 3, webrtc::DataRate::KilobitsPerSec(1200), webrtc::DataRate::KilobitsPerSec(1200), webrtc::DataRate::KilobitsPerSec(350)}, {640, 360, 2, webrtc::DataRate::KilobitsPerSec(700), webrtc::DataRate::KilobitsPerSec(500), webrtc::DataRate::KilobitsPerSec(150)}, {480, 270, 2, webrtc::DataRate::KilobitsPerSec(450), webrtc::DataRate::KilobitsPerSec(350), webrtc::DataRate::KilobitsPerSec(150)}, {320, 180, 1, webrtc::DataRate::KilobitsPerSec(200), webrtc::DataRate::KilobitsPerSec(150), webrtc::DataRate::KilobitsPerSec(30)}, // As the resolution goes down, interpolate the target and max bitrates down // towards zero. The min bitrate is still limited at 30 kbps and the target // and the max will be capped from below accordingly. {0, 0, 1, webrtc::DataRate::KilobitsPerSec(0), webrtc::DataRate::KilobitsPerSec(0), webrtc::DataRate::KilobitsPerSec(30)}}; ``` ### SDK 対応状況 最新版の JavaScript SDK, iOS SDK, Android SDK, Unity SDK, C++ SDK では、 配信と視聴ともに VP8 と H.264 に対応済みです。 ### 配信ブラウザの対応状況 **Firefox は配信に対応していません** 配信側は Chrome と Edge と Safari の最新バージョンに対応しています。 ### 視聴ブラウザの対応状況 視聴側は Chrome と Safari と Firefox と Edge の最新バージョンに対応しています。 ### 映像コーデック 配信時に利用できる映像コーデックは VP8 と H.264 です。 > **注釈** > > VP8 と H.264 両方のコーデックが利用できる場合、VP8 が比較的安定しています。 ### 非対応機能 **以下はすべて今後対応予定です** - ULPFEC 機能には対応していません ## 映像の優先度 サイマルキャストでは 1 つのクライアントからの同じ映像を複数のエンコードで配信することが可能です。 Sora では 1 つのクライアントから最大 3 種類のエンコードで映像を受信する仕組みが入っています。 この 3 種類の映像のそれぞれに r0 / r1 / r2 の 3 つの値を定義しています。 この値は rid と呼ばれています。 配信継続の優先度は r0 > r1 > r2 です。 例えば、回線が不安定だったりマシンの負荷が高かった場合、rid が r2 の映像の配信が最初に停止します。 さらに配信状況が悪化した場合は rid が r1 の映像の配信が停止します。 r0 の映像は必ず配信されます。 ## 映像の種類のデフォルト Sora ではサイマルキャストで配信する映像の種類にデフォルト値を設定しています。 ```json [ {"rid": "r0", "active": true, "scaleResolutionDownBy": 4.0}, {"rid": "r1", "active": true, "scaleResolutionDownBy": 2.0}, {"rid": "r2", "active": true, "scaleResolutionDownBy": 1.0} ] ``` ### r0 rid が r0 の場合は通常の解像度から解像度 (一辺) が 1/4 の映像になるように設定されています。 ### r1 rid が r1 の場合は通常の解像度から解像度 (一辺) が 1/2 の映像になるように設定されています。 ### r2 rid が r2 の場合は通常の解像度のままの映像に設定されています。 ## 映像のエンコーディングパラメータのカスタマイズ Sora ではサイマルキャストでの映像のエンコーディングパラメータを自由に設定することができます。 - sora.conf のファイルで指定することで全体のサイマルキャストのエンコーディングパラメータが指定できます - 認証成功時に simulcast_encodings で払い出すことで個別にサイマルキャストのエンコーディングパラメータが指定できます ### sora.conf でファイル指定 sora.conf にて `simulcast_encodings_file` で JSON を指定してください。 ```ini simulcast_encodings_file = etc/simulcast_encodings.json ``` ### sora.conf で指定する JSON ファイルの記述方法 ```json [ {"rid": "r0", "active": true, "scaleResolutionDownBy": 2.0, "maxFramerate": 5.0}, {"rid": "r1", "active": true, "scaleResolutionDownBy": 2.0, "maxFramerate": 20.0}, {"rid": "r2", "active": true, "scaleResolutionDownBy": 1.0, "maxFramerate": 30.0} ] ``` ### 認証成功時に simulcast_encodings で払い出す記述方法 ```json { "allowed": true, "simulcast_encodings": [ {"rid": "r0", "active": true, "scaleResolutionDownBy": 2.0, "maxFramerate": 5.0}, {"rid": "r1", "active": true, "scaleResolutionDownBy": 2.0, "maxFramerate": 20.0}, {"rid": "r2", "active": true, "scaleResolutionDownBy": 1.0, "maxFramerate": 30.0} ] } ``` ### カスタマイズの設定 - rid- 必須 - string (r0 / r1 / r2) - active- このエンコーディングパラメータを有効にします - オプション - boolean - scaleResolutionDownBy- オプション - 1 以上の number (float または integer) - maxBitrate- オプション - 最大ビットレートを指定する - 0 以上の integer - maxFramerate- オプション - 最大フレームレートを指定する - 0 以上の number (float または integer) - adaptivePtime- **この設定は Chrome でしか利用できません** - オプション - boolean ### active: false の挙動 r1 の active を false にカスタマイズしている配信で r1 を受信をリクエストした場合、r0 が配信されます。 ```json [ {"rid": "r0", "active": true}, {"rid": "r1", "active": false}, {"rid": "r2", "active": true} ] ``` r0 の active を false にカスタマイズしている配信で r0 を受信をリクエストした場合、r1 が配信されます。 ```json [ {"rid": "r0", "active": false}, {"rid": "r1", "active": true}, {"rid": "r2", "active": true} ] ``` r0 と r1 の active を false にカスタマイズしている配信で r0 を受信をリクエストした場合、r2 が配信されます。 ```json [ {"rid": "r0", "active": false}, {"rid": "r1", "active": false}, {"rid": "r2", "active": true} ] ``` ## 配信側の利用方法 シグナリング開始時に指定できます。 ### シグナリング開始時 シグナリングの `"type": "connect"` 時に `"simulcast": true` を指定することで、有効になります。 映像コーデックは `VP8` または `H264` を選択してください。 ```json { "type": "connect":, "role": "sendonly", "channel_id": "sora", "video": {"codec_type": "VP8"}, "multistream": false, "simulcast": true } ``` マルチストリーム利用時にも利用可能です。 ```json { "type": "connect":, "role": "sendonly", "channel_id": "sora", "video": {"codec_type": "VP8"}, "multistream": true, "simulcast": true } ``` ## 視聴側の利用方法 シグナリング開始時に指定できます。 ### シグナリング開始時 - シグナリング `"type": "connect"` 時に `"simulcast": true` を指定することで、有効になります - `simulcast_rid` には `r0` / `r1` / `r2` が指定可能です- `simulcast_rid` を指定しない場合は `r0` が指定されます - この値は **サイマルキャストで配信されている映像を受信する際のデフォルト値** です - この値は `sora.conf` の `default_simulcast_rid` で変更可能です - 映像コーデックは `VP8` または `H264` を選択してください ```json { "type": "connect":, "role": "recvonly", "channel_id": "sora", "video": {"codec_type": "VP8"}, "multistream": false, "simulcast": true, "simulcast_rid": "r2" } ``` マルチストリーム利用時にも指定できます。 ```json { "type": "connect":, "role": "recvonly", "channel_id": "sora", "video": {"codec_type": "VP8"}, "multistream": true, "simulcast": true, "simulcast_rid": "r2" } ``` ## 視聴側のストリームの変更 API 詳細は [サイマルキャスト API](API.html#adcbc8) をご確認ください ## シーケンス図 seqdiag { default_fontsize = 15; edge_length = 250; activation = none; クライアント1 ->> Sora [label = '{"type": "connect",\n"role": "sendonly",\n"simulcast": true}']; === クライアント1 WebRTC 確立 === Sora <<- クライアント2 [label = '{"type": "connect",\n"role": "recvonly",\n"simulcast": true\n"simulcast_rid": "r1"}']; === クライアント2 WebRTC 確立 === クライアント1 ->> Sora [label = '映像\nrid: r0', noactivate]; クライアント1 ->> Sora [label = '映像\nrid: r1', noactivate]; Sora ->> クライアント2 [label = '映像\nrid: r1', noactivate]; クライアント1 ->> Sora [label = '映像\nrid: r2', noactivate]; } # スポットライト機能 > **重要** > > この機能は VP8 または H.264 でのみ利用できます ## 概要 WebRTC SFU サーバーを利用して 20 名で会議を行う場合、各参加者は自分以外の 19 名分の音声と映像を常に受信し続ける必要があります。 また、WebRTC SFU サーバーも、常に 20 名分の音声や映像を受信し、配信し続ける必要があります。 ところが実際は 20 名の会議であっても、ひとつのトピックに対して発言している人はせいぜい 2 名から 3 名です。 また、映像も常に参加者全員のものを高画質で配信しなくとも、その時点でアクティブに発言している人の映像がクリアであれば十分というケースも多いです。 この **スポットライト機能** を利用すると、発言していない大多数の参加者の音声は配信せず、低画質の映像のみを配信できます。ある参加者が発言し始めると、自動でその参加者の音声の配信を開始し、さらにあらかじめ設定した秒数が経過すると、映像の画質も自動で高画質に切り替えることができます。 この仕組を使うことで、クライアントやサーバーの負荷を抑えながら大人数で会議を行うことが可能になります。 この機能は、発言している参加者のみの音声と高画質の映像が配信されることから、スポットライトが当たるイメージに見立てて、スポットライト機能と名付けています。 ## 仕組み 開始前に、フォーカスする人数を決めます。 フォーカスする人数とは、会議の参加者のうち、最大何人分の映像を高画質で配信するかの数です。 ここではフォーカスする人数を 1 人とします。 この機能を利用した場合は、発言していない参加者の映像は低画質で配信され、音声は配信されません。 最初に A さんが発言し始めると、 A さんの映像が高画質になって配信されます。 次に B さんが発言すると、 B さんの映像が高画質になって配信されます。 このタイミングで A さんの映像は低画質になります。 その後は同じように、直近で発言した 1 人分の映像が高画質で配信され、音声も配信されます。 それ以外の参加者の映像は低画質で配信され、音声は配信されません。 このように、高画質で配信する人数を限定することで、クライアントやサーバーの負荷を抑えながら大人数での会議が実現できます。 ただし、上記のような自動切り替えでは、参加者の映像が頻繁に入れ替わると逆に負荷が高くなってしまいます。 それを抑えるため、Sora では、参加者が発言し始めるとまずは音声だけを配信し始め、映像の切り替えはしばらく時間が経ってから行うことが可能です。 この時、映像が切り替わる前に、先に音声を配信することをフォーカスなし音声配信と呼びます。 これにより、映像の切り替わりの有無に関わらず、短い発言、あいづちなども配信し、スムーズな会話を成立させられます。 また、音声よりも遅れて映像を切り替えることを遅延フォーカスと呼びます。 映像の切り替えを遅延させることにより、ちょっとした雑音や短い発言のたびに映像が切り替わることを抑制することが可能です。 これらのフォーカスなし音声配信や遅延フォーカス機能を利用すれば、スポットライト機能でフォーカスする人数は 1 〜 2 人で十分です。多くても 3 人です。 ## 注意 ### スポットライト機能はサイマルキャスト機能を活用した機能です デフォルトであれば解像度が VGA 以上のサイズであれば 2 つの画質の映像を配信します。 - 高画質- 解像度の縮小比が 1 で 30 fps - 低画質- 解像度の縮小比が 4 で 5 fps ### Chrome 、 Edge 、 Safari で動作します 現時点では Chrome と Edge と Safari の最新版に対応しています。 > **注釈** > > Firefox ではサイマルキャスト機能ができないため、 Firefox を利用する場合はサイマルキャスト機能を無効にして接続する必要があります。 > 詳細は [サイマルキャスト機能を無効にして接続する](SPOTLIGHT.html#ae2845) をご確認ください。 ## マルチストリームのサイマルキャストとの違い マルチストリームのサイマルキャストを利用する場合、 受信する映像の種類を切り替えるには [RequestRtpStream](API.html#6fe0b3) API を利用する必要があります。 スポットライトはこの API の切り替え部分を Sora が自動で判断します。判断には参加者の音量を利用します。 例えば、音量が閾値を下回った場合は rid は r0 、閾値を超えた場合は rid は r1 のように、他の参加者が受信する映像の rid を切り替えます。 マルチストリームの詳細は [マルチストリーム機能](MULTISTREAM.html) をご確認ください サイマルキャストの詳細は [サイマルキャスト機能](SIMULCAST.html) をご確認ください ## SDK 対応状況 - 最新版の JavaScript SDK- 対応済みです - 最新版の iOS SDK- 対応済みです - 最新版の Android SDK- 対応済みです - 最新版の Unity SDK- 対応済みです - 最新版の C++ SDK- 対応済みです ## スポットライト利用時の映像の種類のデフォルト Sora ではスポットライトで配信する映像の種類にデフォルト値を設定しています。 ```json [ {"rid": "r0", "active": true, "maxFramerate": 5.0, "scaleResolutionDownBy": 4.0}, {"rid": "r1", "active": true, "maxFramerate": 30.0, "scaleResolutionDownBy": 1.0}, {"rid": "r2", "active": false} ] ``` ### r0 rid が r0 の場合は通常の解像度から解像度(一辺) が 1/4 で、 フレームレートが 5 になるようなエンコードがされるように設定されています。 ### r1 rid が r1 の場合は通常の解像度のままで、 フレームレートが 30 でエンコードがされるように設定されています。 ### r2 rid が r2 の場合はエンコードがされないように設定されています。 ## スポットライト利用時の映像のエンコーディングパラメータのカスタマイズ Sora ではスポットライトでの映像のエンコーディングパラメータを自由に設定することができます。 - `sora.conf` のファイルで指定することで全体のスポットライトのエンコーディングパラメータが指定できます - 認証成功時に `spotlight_encodings` で払い出すことで個別にスポットライトのエンコーディングパラメータが指定できます ### sora.conf でファイル指定 `sora.conf` にて スポットライトの場合は [spotlight_encodings_file](SORA_CONF.html#6115fb) で JSON ファイルを指定してください。 ```ini spotlight_encodings_file = etc/spotlight_encodings.json ``` ### sora.conf で指定する JSON ファイルの記述方法 ```json [ {"rid": "r0", "active": true, "scaleResolutionDownBy": 4.0, "maxFramerate": 5.0}, {"rid": "r1", "active": true, "scaleResolutionDownBy": 1.0, "maxFramerate": 10.0}, {"rid": "r2", "active": true, "scaleResolutionDownBy": 1.0, "maxFramerate": 30.0} ] ``` ### 認証成功時に spotlight_encodings で払い出す記述方法 ```json { "allowed": true, "spotlight_encodings": [ {"rid": "r0", "active": true, "scaleResolutionDownBy": 2.0, "maxFramerate": 5.0}, {"rid": "r1", "active": true, "scaleResolutionDownBy": 2.0, "maxFramerate": 20.0}, {"rid": "r2", "active": true, "scaleResolutionDownBy": 1.0, "maxFramerate": 30.0} ] } ``` ### カスタマイズの設定 - rid- 必須 - string (r0 / r1 / r2) - active- このエンコーディングパラメータを有効にします - オプション - boolean - scaleResolutionDownBy- オプション - 1 以上の number (float または integer) - maxBitrate- オプション - 最大ビットレートを指定する - 0 以上の integer - maxFramerate- オプション - 最大フレームレートを指定する - 0 以上の number (float または integer) - adaptivePtime- **この設定は Chrome でしか利用できません** - オプション - boolean ## フォーカスする配信数 フォーカスする配信数はチャネル ID ごとに 1 から 8 までのいずれかを選択できます。 デフォルトのフォーカス数は 1 です。 遅延フォーカスやフォーカスなしでの音声配信を有効にしていればフォーカス数は 1 で十分です。 ## 遅延フォーカス ちょっとした物音でフォーカスをしないようにするため、フォーカスを遅延させる機能です。 この機能を有効にした場合、フォーカスされる場合に一定時間以上、音が出続けている必要があります。 ### [default_spotlight_delayed_focus](SPOTLIGHT.html#8b9a4e) `sora.conf` で遅延フォーカスを有効にするかどうかを指定してください。デフォルトで `true` です。 ### [default_spotlight_delayed_focus_interval](SPOTLIGHT.html#794eec) `sora.conf` でフォーカスを遅延させる時間を指定してください。デフォルトは `2000 ms` です。 ## 遅延アンフォーカス スポットライトの数が少ないときに、フォーカスの奪い合いが発生しないように、フォーカスが発生してからアンフォーカスするまで遅延させる機能です。 ### [default_spotlight_focus_min_interval](SPOTLIGHT.html#966f51) `sora.conf` でフォーカスしてからアンフォーカスされるまでの最低時間間隔を指定します。デフォルトは `2000 ms` です。 ## フォーカスなし音声配信 フォーカスがない状態でも音声を配信するかを指定する機能です。 この機能を有効にすると、フォーカスが他の配信者にとられても音声を配信し続けます。 配信するレートの上限も指定できます。 ### [default_spotlight_unfocus_audio](SPOTLIGHT.html#27f670) `sora.conf` でフォーカスなし音声を有効にするかどうかを指定してください。デフォルトで `true` です。 ### [default_spotlight_unfocus_audio_rate_limit](SPOTLIGHT.html#91cb49) `sora.conf` でフォーカスなし音声を配信する上限レートを指定してください。デフォルトは `2` です。 レートの単位は `1 音声ストリーム = 50 packets / s` です。 ## 自動アンフォーカス 無音状態が一定時間続くとフォーカスを自動で外す機能です。この機能を利用するとフォーカス数が 0 になることもあります。 クライアントが受信するパケット、Sora が配信するパケットを減らすことができます。 ### [default_spotlight_auto_unfocus](SPOTLIGHT.html#9db9f6) `sora.conf` で音がない場合に自動でアンフォーカスするかどうかを指定してください。デフォルトは `true` です。 ### [default_spotlight_auto_unfocus_interval](SPOTLIGHT.html#4636fe) `sora.conf` で自動でアンフォーカスする無音時間を指定してください。デフォルトは `10 s` です。 ## サイマルキャスト機能を無効にして接続する > **注釈** > > サイマルキャストを無効にして接続すると常にフォーカスされ続けます。 スポットライト機能でサイマルキャスト機能を無効にして利用することも可能です。 無効にする場合はシグナリング接続時または認証成功時に `"simulcsat": "false"` を指定する必要があります。 サイマルキャスト機能を無効にしてスポットライトを利用した場合、 そのクライアントは常にフォーカスされている状態となります。 そのため `spotlight_focus_rid` や `spotlight_unfocus_rid` の影響も受けません。 サイマルキャスト機能を無効にした利用は、 画面共有やサイマルキャストが利用できないクライアントでの利用を想定しています。 ## シグナリング - シグナリングの `"type": "connect"` で `multistream` と `spotlight` を `true` に設定してください- これは必須です - シグナリングの `"type": "connect"` で `simulcast` を設定してください- これはオプションです - サイマルキャストを無効にする場合は [サイマルキャスト機能を無効にして接続する](SPOTLIGHT.html#ae2845) をご確認ください - シグナリングの `"type": "connect"` で `spotlight_number` で 1 ~ 8 の値を指定してください- 1 から 3 の間がお勧めです - これはオプションです その他の項目は [シグナリング](SIGNALING.html) を参照ください。以下に シグナリング `"type": "connect"` の例を示します。 ### "type": "connect" #### simulcast: false サイマルキャスト無効。 ```json { "type": "connect", "channel_id": "sora", "role": "sendrecv", "spotlight": true, "simulcast": false, "multistream": true, "video": { "codec_type": "VP8", "bit_rate": 800 } } ``` #### spotlight_number フォーカス数はデフォルトの 1 ```json { "type": "connect", "channel_id": "sora", "role": "sendrecv", "spotlight": true, "simulcast": true, "multistream": true, "video": { "codec_type": "VP8", "bit_rate": 800 } } ``` フォーカス数は指定した値の 5 ```json { "type": "connect", "channel_id": "sora", "role": "sendrecv", "spotlight": true, "spotlight_number": 5, "simulcast": true, "multistream": true, "video": { "codec_type": "VP8", "bit_rate": 800 } } ``` #### spotlight_focus_rid / spotlight_unfocus_rid シグナリング接続時、認証成功時にフォーカスした場合とフォーカスしていない場合に受信する映像の rid を接続ごとに指定できます。 例えば、映像は特に受け取らなくていい場合は、両方の設定で none を指定することで参加者全員の映像を受信しなくなります。 また、話している人は rid は r1 で受信し、それ以外は受信しない (rid に none を指定) といった設定も可能です。 ```json { "type": "connect", "channel_id": "sora", "role": "sendrecv", "spotlight": true, "spotlight_focus_rid": "r0", "spotlight_unfocus_rid": "none", "simulcast": true, "multistream": true, "video": { "codec_type": "VP8", "bit_rate": 800 } } ``` `sora.conf` で [default_spotlight_focus_rid](SORA_CONF.html#c71c97) と [default_spotlight_unfocus_rid](SORA_CONF.html#a7cd9b) を指定することで、個別ではなくサーバー全体の設定も可能です。 ## シグナリング通知 シグナリング通知の詳細は [スポットライト機能のシグナリング通知](SIGNALING_NOTIFY.html#dcfbb9) をご確認ください。 フォーカスされたタイミングとフォーカスが外れたタイミングでシグナリング通知をクライアントに送ります。 クライアントはこの通知を利用することで、配信が切り替わったことを知ることが可能になります。 ## イベントウェブフック フォーカスされたタイミングとフォーカスが外れたタイミングでウェブフックリクエストが送信されます。 `sora.conf` の [ignore_spotlight_changed_webhook](SORA_CONF.html#7f5ed5) で指定できます。 デフォルトではイベントウェブフックのリクエスト送信は無効になっています。 - [spotlight.focused](EVENT_WEBHOOK.html#d79712) イベントウェブフック - [spotlight.unfocused](EVENT_WEBHOOK.html#41715c) イベントウェブフック ## API API の詳細は [スポットライト API](API.html#cb7b53) をご確認ください。 - [FocusSpotlightFixed](API.html#beaf88) API- 特定のクライアントにフォーカスし続ける API - [FocusSpotlight](API.html#90a256) API- 特定のクライアントにフォーカスする API - [UnfocusSpotlight](API.html#1390bc) API- 特定のクライアントからアンフォーカスする API - [ChangeSpotlightNumber](API.html#17e930) API- フォーカスする数を変更する API - [RequestSpotlightRid](API.html#5c2650) API- 特定のクライアントのフォーカス/アンフォーカス時の rid を変更する API - [ResetSpotlightRid](API.html#680344) API- 特定のクライアントのフォーカス/アンフォーカス時の rid をリセットする API - [BatchRequestSpotlightRid](API.html#a2e06c) API- フォーカス/アンフォーカス時の rid を一括で変更する API ## シーケンス図 seqdiag { default_fontsize = 15; edge_length = 250; activation = none; クライアント1 ->> Sora [label = '{"type": "connect",\n"role": "sendonly",\n"multistream": true,\n"spotlight": true}']; === クライアント1 WebRTC 確立 === クライアント1 ->> Sora [label = '映像\nrid: r0', noactivate]; クライアント1 ->> Sora [label = '映像\nrid: r1', noactivate]; Sora <<- クライアント2 [label = '{"type": "connect",\n"role": "recvonly",\n"multistream": true,\n"spotlight": true}']; === クライアント2 WebRTC 確立 === クライアント2 ->> Sora [label = '映像\nrid: r0', noactivate]; クライアント2 ->> Sora [label = '映像\nrid: r1', noactivate]; Sora ->> クライアント2 [label = 'クライアント1映像\nrid: r0', noactivate]; Sora ->> クライアント1 [label = 'クライアント2映像\nrid: r0', noactivate]; ... クライアント1 が喋り始める ... Sora ->> クライアント2 [label = 'クライアント1音声', noactivate]; ... しゃべり初めて 2 秒経過 ... Sora ->> クライアント2 [label = 'クライアント1映像\nrid: r1', leftnote='r0 の代わりに r1 映像を配信' , noactivate]; } # TURN 機能 Sora は TURN 機能を内蔵しています。そのため TURN サーバーを別途立てる必要はありません。 ## 推奨設定 一番接続率が高くなる設定は以下の通りです。 - TURN-TCP を 443 番ポートで待ち受け - TURN-TLS を 443 番ポートで待ち受け 上記設定をしたい場合は [TURN-TLS、TURN-TCP、シグナリングで 443 番ポートを使用する](PRODUCTION.html#14258d) をご確認ください。 ## TURN はすべて同時に試される TURN 利用時には TURN-UDP と TURN-TCP と TURN-TLS をすべて同時に試みて、 確立が早かった経路を利用する仕組みになっています。 ## ブラウザの TURN 対応状況 Chrome、Firefox、Edge、Safari は TURN-UDP / TURN-TCP / TURN-TLS に対応しています。 ## 注意 Firefox では TURN の urls を 5 個より多く送るとエラーがコンソールに表示されます。 ## 設定 **Sora はデフォルトで TURN 機能が有効になっています** ```ini ## TURN 機能を有効にするかどうかを指定してください # turn = false ## TURN 機能で利用するレルムを指定してください # turn_realm = sora-turn.example.com ## TURN 機能で TURN URL 払い出し機能で利用する FQDN (最後の . なし)を指定してください # turn_fqdn = sora-turn.example.com ## TURN 機能で TURN-TCP を有効にするかどうかを指定してください # turn_tcp = false ## TURN 機能で TURN-TCP を有効にした際に利用するポート番号を指定してください # turn_tcp_listen_port = 3478 ## TURN 機能で TURN-TCP URL 払い出し時のポート番号を指定してください # turn_tcp_port = 3478 ## TURN 機能で TURN-TLS URL 払い出し機能を有効にするかどうかを指定してください ## オプションでデフォルトは false です # turn_tls = true ## TURN 機能で TURN-TLS URL 払い出し機能で利用する FQDN (最後の . なし)を指定してください ## turn_tls_fqdn は turn_fqdn の値を上書きします # turn_tls_fqdn = sora-turn.example.com ## TURN 機能で TURN-TLS URL 払い出し機能を有効にした際に利用するポート番号を指定してください # turn_tls_port = 5349 ``` ### 設定の優先順位 TURN が有効な場合 Sora が TURN 用の URL を生成する優先順位が存在します。 1. 認証時に外部サーバーから払い出される `ipv4_address` が採用されます- `sora.conf` で `ipv6` が `true` の場合は払い出された `ipv6_address` も採用されます 2. 外部サーバーから `ipv4_address` が払い出されなかった場合は `sora.conf` の `ipv4_address` が採用されます- `sora.conf` で `ipv6` が `true` の場合は `sora.conf` の `ipv6_address` も採用されます 3. TURN-TLS を有効にしている場合、外部サーバーから払い出される `turn_tls_fqdn` が払い出されなかった場合は `sora.conf` の `turn_tls_fqdn` が採用されます。さらに `turn_tls_fqdn` が指定されてない場合は `turn_fqdn` が採用されます。 #### 設定例 1 ```ini ipv4_address = 192.0.2.10 ipv6 = false turn = true turn_realm = sora-turn.example.com turn_fqdn = sora-turn.example.com turn_tcp = true turn_tcp_listen_port = 3478 turn_tcp_port = 3478 turn_tls = true turn_tls_fqdn = sora-turn.example.com turn_tls_port = 5349 ``` 外部サーバーから払い出しは `turn_tls_fqdn` が `"sora-turn.example.com"` の場合、払い出される TURN の urls は 3 つです。 UDP のポートは動的に決まるためここでは 54321 としています。 - turn:sora-turn.example.com:54321?transport=udp - turn:sora-turn.example.com:3478?transport=tcp - turns:sora-turn.example.com:5349?transport=tcp #### 設定例 2 - sora.conf- 全てデフォルト - 収集された IP アドレスは 192.0.2.10 と 192.0.2.20 - 外部サーバーから払い出し- なし - auth_webhook_url コメントアウト この場合、払い出される TURN の urls は 4 つです。 UDP のポートは動的に決まるためここでは 54321 としています。 - turn:192.0.2.10:54321?transport=udp - turn:192.0.2.10:3478?transport=tcp - turn:192.0.2.20:54321?transport=udp - turn:192.0.2.20:3478?transport=tcp ## 内蔵 TURN 機能のメリット - Sora との通信経路を強制的に TURN 経由に固定することで、効率よく接続の確立が行えます- `"type": "candidate"` を待つ必要がなく、 Answer さえ受け取ってしまえば接続の確立まで進めます - 接続ごとに TURN に使用する Username や Credential を意識する必要がなくなります - TURN-TCP や TURN-TLS 機能を使用することで UDP が使用できない環境でも WebRTC を利用できるようになります ## Sora の TURN 機能 - TURN-UDP での TURN 機能- 動的なポートでの TURN-UDP にのみ対応しています - TURN-TCP での TURN 機能 - TURN-TLS での TURN URL 払い出し機能- nginx の利用を前提とした機能です - ワンタイムな Username や Credential、TURN の URL の自動払い出し- Sora がすべて自動で行ってくれます - Sora は TURN 機能に必要な Username や Credential をクライアントごとにワンタイムで生成します - TURN-UDP / TURN-TCP の IPv6 対応- TURN で払い出す urls も IPv6 に対応します - TURN-TLS での IPv6 対応については nginx 依存となります - TURN-TCP の Proxy Protocol 対応- nginx などを利用したリバースプロキシが前段にいて Proxy Protocol を利用する場合でも対応が可能です ## Sora の TURN-TCP 機能 - デフォルトでは有効になっていますので、無効にしたい場合は `sora.conf` にて `turn_tcp = false` を指定してください - TURN-TCP で受信するポート番号を指定したい場合は `sora.conf` にて `turn_tcp_listen_port = 3478` のように指定してください - TURN-TCP の設定で払い出すポート番号を指定したい場合は `sora.conf` にて `turn_tcp_port = 443` のように指定してください ## Sora の TURN-TLS URL 払い出し機能 Sora では TURN-TLS 機能は直接提供していません。 TLS の終端には nginx を利用します。 つまり nginx 側で TURN-TLS の TLS を終端して、 TURN-TCP として Sora に投げてもらいます。 > **重要** > > 必ず turn_tcp の設定を有効にしてください デフォルトでは無効になっていますので、有効にしたい場合は `sora.conf` で `turn_tls = true` を指定してください。 TURN-TLS で使用するポート番号を指定したい場合は `sora.conf` で `turn_tls_port = 5349` のように指定してください。デフォルトでは 5349 をお勧めします。 さらに TURN-TLS では使用する場合はかならず証明書の FQDN を指定する必要があります。 sora-turn.example.com の証明書を使用する場合は `sora.conf` で `turn_tls_fqdn = sora-turn.example.com` のように指定してください。 詳細は [TURN-TLS、TURN-TCP、シグナリングで 443 番ポートを使用する](PRODUCTION.html#14258d) をご確認ください。 ## Sora の TURN IPv6 対応 IPv6 のアドレスが使用できる場合、クライアントに送られる TURN UDP/TCP サーバー機能も IPv6 で提供します。 ## TURN-TCP / TURN-TLS の検証 `sora.conf` に `turn_tcp_only = true` や `turn_tls_only = true` の設定を有効にすることで強制的に TURN-TCP や TURN-TLS を利用することが可能になります。 こちらは、あくまで検証のみで利用していただくことを想定している機能です。そのため有効にしている場合は `sora.log` に警告メッセージが出力されます。 ## Sora TURN 機能の制限 Sora の TURN 機能には一部制限があります。 - TURN で使用される UDP のポート番号の固定ができない- TURN のポート番号は個々のクライアントに対して動的に生成されるため、固定できません。 この課題を解決したい場合は、 Sora の TURN 機能を無効にして、別途 TURN サーバーを立てる必要があります。 ただし、別途 TURN サーバーを立てることは推奨していません。 ## 外部の TURN サーバーを使用する場合 > **警告** > > Sora の内蔵 TURN サーバーを無効にして外部の TURN サーバーを利用するのは非推奨です、もし利用したい場合はサポートまでご連絡ください ## TURN 機能を使う場合の注意点 > **重要** > > 弊社が提供している Sora の SDK を利用する場合は、 SDK 側で TURN 機能に対応しているため、対応は不要です TURN 機能を使用する場合、 Sora はシグナリングの `"type": "offer"` 時に、 WebSocket 経由で送られてくる JSON 形式のメッセージの config: に、 TURN 接続に必要な情報を含めてクライアントに送信します。 この config を、 PeerConnection を new する際の引数に指定してください。 ```javascript // ws_url は Sora のシグナリング API の URL を指定する ws = new WebSocket(ws_url); // WebSocket 経由で送られてきたメッセージのコールバックを指定する ws.onmessage = onMessage; function onMessage(event) { var message = JSON.parse(event.data); if (message.type == 'offer') { // TURN 機能を有効に為た場合は offer メッセージの config に TURN で使用する情報が入っています var config = message.config; // 途中から省略しています RTCPeerConnection.generateCertificate({ name: "ECDSA", namedCurve: "P-256" }) .then(function(certificate) { config.certificates = [certificate]; // ここで RTCPeerConnection を生成する際の config に送られてきた config を指定してください peerConnection = new RTCPeerConnection(config); ``` この Sora から Offer として送られてくる config には、常に接続を TURN 経由で行う仕組みが入っています。 - urls に記載される URL の IP アドレスは sora.conf の ip_address に設定した値になります - urls に記載される URL のポート番号は Sora が動的に生成したポートの値になります - username と credential は Sora の TURN 機能が動的に生成したワンタイムな値が使用されます ```javascript // offer メッセージの config のサンプルです config = { "iceTransportPolicy": "relay", // urls は Sora が動的に生成したポートを使用した URL が入ります "iceServers": [{"urls": ["turn:sora-turn.example.com:3478?transport=udp", "turn:sora-turn.example.com:3478?transport=tcp", "turns:sora-turn.example.com:5349?transport=tcp"], "username": "one-time-username", "credential": "one-time-credential"}] }; ``` ## シーケンス図 ### TURN への接続は同時に試す TURN-UDP のポートは動的に決まります。 seqdiag { default_fontsize = 15; edge_length = 300; activation = none; クライアント; nginx; Sora; クライアント -> nginx [label = 'シグナリング (443 番)']; nginx -> Sora [label = 'シグナリング (5000 番)']; nginx <- Sora [label = '"type": "offer"']; クライアント <- nginx [label = '"type": "offer"']; クライアント -> nginx [label = '"type": "answer"']; nginx ->> Sora [label = '"type": "answer"']; クライアント ->> Sora [label = "TURN-UDP Allocate-Request (52520 番)"]; クライアント ->> nginx [label = 'TURN-TCP Allocate-Request (443 番)']; nginx -> Sora [label = 'TURN-TCP Allocate-Request (3478 番)']; クライアント ->> nginx [label = 'TURN-TLS Allocate-Request (443 番)']; nginx -> Sora [label = 'TURN-TCP Allocate-Request (3478 番)']; クライアント <- Sora [label = 'TURN-UDP Allocate-Success']; クライアント -> Sora [label = 'TURN-UDP Permission-Request']; クライアント <- Sora [label = 'TURN-UDP Permission-Success']; クライアント -> Sora [label = 'TURN-UDP Channel-Reuqest']; クライアント <- Sora [label = 'TURN-UDP Channel-Success']; クライアント ->> Sora [label = 'DTLS Client Hello over TURN (443 番)']; } # 録画機能 ## 概要 Sora では、配信している映像や音声を録画、録音して保存することが可能です。 配信されている映像をできるかぎりそのまま保存するため、CPU リソースを最小限に抑えることができます。 出力される録画ファイルは WebM 形式です。映像のみの録画、音声のみの録音にも対応しています。 録画時には一切トランスコードを行っていません。配信された映像や音声をそのままに記録します。 ## 用語 **単一録画ファイル** : 切断または [StopRecording](API.html#fd0de5) API の実行、または録画期限が切れた場合に一つのファイルとして出力される動画ファイル **分割録画ファイル** : `split_duration` で指定した時間ごとに区切られ分割されて出力される動画ファイル ## 録画ファイルの出力 録画ファイルの出力には 3 パターンあります。 ### 単一録画ファイルのみ出力 - `split_duration` を指定していない 上記を満たした場合、1 接続で 1 つ録画ファイルが出力されます。 ### 分割録画ファイルのみ出力 - `split_duration` が指定されている - `expire_time` が `0` に指定されている - `split_only` が `true` に指定されている 上記を満たした場合、分割された録画ファイルのみが出力されます。 ### 単一録画ファイルと分割録画ファイルの両方が出力 - `split_duration` が指定されている 上記を満たした場合、 1 接続で 1 つの録画ファイルと分割された録画ファイルの両方が出力されます。 イベントウェブフックも単一録画、分割録画、両方のイベントウェブフックリクエストが送信されます。 ## 制限 ### コーデック 録画 (録音) は、映像コーデックに VP8 と VP9 と H.264 と AV1 、また音声コーデックに Opus を選択した場合のみ可能です。 > **警告** > > H.265 の録画には非対応です。 ### 解像度 WebRTC では配信側の CPU リソースが不足した場合や、 回線の品質が悪化した場合に解像度を動的に変更します。 そのため録画したデータの途中で解像度が低くなる可能性があります。 ### 音声や映像のクライアント側でのトラック削除 クライアント側でシグナリング接続時に音声や映像を有効にした状態で、 クライアント側で音声トラック、または映像トラックのどちらかを削除した場合でも録画は行われます。 さらに追加して戻した形であれば録画側も戻ります。 ただし、音声と映像両方のトラックを削除した場合は正常に録画が行われません。 ### マルチストリーム機能での録画 対応しています。 ### サイマルキャスト機能での録画 対応しています。 サイマルキャストを利用している際の録画は **一番優先度が低い** ストリーム、すなわちデフォルトでは最も高い画質の映像を録画します。 詳細はサイマルキャストの [映像の優先度](SIMULCAST.html#36c708) をご確認下さい。 ### スポットライト機能での録画 対応しています。 サイマルキャストを利用している際の録画は **一番優先度が低い** ストリーム、すなわちデフォルトでは最も高い画質の映像を録画します。 詳細はサイマルキャストの [映像の優先度](SIMULCAST.html#36c708) をご確認下さい。 ### キーフレーム要求間隔 録画機能利用時の Sora からのキーフレーム要求間隔は 20 秒に固定されています。 そのため、分割録画の最小時間は 20 秒 + `split_duration` に指定した秒数となります。 もし録画時のキーフレーム要求間隔を変更したい場合は、サポートまでご連絡ください。 ## 無変換録画 WebRTC 経由で流れてきている映像や音声を変換せず、 そのまま録画するファイルの形式に組み立て直してファイルを保存します。 そのため、CPU リソースを最小限に抑えられます。 ブラウザでの録画など、通常の録画は変換が入るため CPU に多くの負荷がかかります。 変換を行わないため、録画を終了した数秒後には録画したファイルを取得することができます。 解像度は送られてきた映像の最大値を録画ファイルの解像度として使用します。 ## 録画の開始と終了について Sora の録画機能は **明示的にチャネルの録画を停止するか、 チャネルの録画開始から指定した期限が過ぎるまでは、 そのチャネルでの配信を自動で録画する** といった機能になります。 ## 録画関連イベントのウェブフックについて ### recording.started イベントウェブフック 録画開始 API が実行されたタイミングで `recording.started` リクエストを送信します。 詳しくは [recording.started](EVENT_WEBHOOK.html#9b5c58) をご確認ください。 ### recording.report イベントウェブフック 録画終了 API が実行されたか、 録画の期限が切れたタイミングで `recording.report` リクエストを送信します。 詳しくは [recording.report](EVENT_WEBHOOK.html#920a02) をご確認ください。 ### archive.started ウェブフック 録画ファイルを保存しはじめたタイミングで `archive.started` リクエストを送信します。 詳しくは [archive.started](EVENT_WEBHOOK.html#462c97) をご確認ください。 ### archive.available イベントウェブフック 単一録画ファイルが出力されたタイミングで `archive.available` リクエストを送信します。 詳しくは [archive.available](EVENT_WEBHOOK.html#de9132) をご確認ください。 ### split-archive.available イベントウェブフック 録画ファイル分割出力機能を有効にした場合、 分割された録画ファイルが出力されたタイミングで `split-archive.available` リクエストを送信します。 詳しくは [split-archive.available](EVENT_WEBHOOK.html#555071) をご確認ください。 ### split-archive.end イベントウェブフック 録画ファイル分割出力機能を有効にした場合、 分割された録画が終了したタイミングで `split-archive.end` リクエストを送信します。 詳しくは [split-archive.end](EVENT_WEBHOOK.html#31be7a) をご確認ください。 ### archive.failed イベントウェブフック 録画ファイルの保存に失敗した場合、 `archive.failed` リクエストを送信します。 詳しくは [archive.failed](EVENT_WEBHOOK.html#5006f8) をご確認ください。 ## 単一録画ファイル出力のみ 単一録画ファイル出力のみの場合は `sora.conf` の [archive_dir](SORA_CONF.html#ad2156) に指定したディレクトリに `recording_id` 名のディレクトリ以下にファイルが出力されます。 `recording_id` は録画開始 API を実行したときに戻ってくる値で、 Base32 でエンコードされた UUIDv4 となります。 ディレクトリ構造: ``` ├── archive │ ├── 1CS9QJ0XPN4C76HBGBN6MGMK5M │ │ ├── archive-A4756MXP914ZB265E92JE3ZMWC.json │ │ ├── archive-A4756MXP914ZB265E92JE3ZMWC.webm │ │ ├── archive-H2NDA2YCGH7S1E9CVMFMXMA34R.json │ │ ├── archive-H2NDA2YCGH7S1E9CVMFMXMA34R.webm │ │ ├── archive-PBVZQQN3JS3MQF8XHVFXDMCEEC.json │ │ ├── archive-PBVZQQN3JS3MQF8XHVFXDMCEEC.webm │ │ └── report-1CS9QJ0XPN4C76HBGBN6MGMK5M.json │ └── CZZ8A8KZB16A1DF5PKERBHGFNR │ ├── archive-3B7AFF8ZRX6VNEYV40B35Z9S2C.json │ ├── archive-3B7AFF8ZRX6VNEYV40B35Z9S2C.webm │ ├── archive-DGSN3TC0E91RSCZT5KVPRWCDHR.json │ ├── archive-DGSN3TC0E91RSCZT5KVPRWCDHR.webm │ └── report-CZZ8A8KZB16A1DF5PKERBHGFNR.json ``` > **注意** > > `archive_dir` と `archive_tmp_dir` は違うディレクトリを指定して下さい ### archive- #### 単一録画ファイル 単一録画ファイルは `/archvie-.webm` に WebM 形式で出力されます。 #### 単一録画メタデータファイル 単一録画メタデータファイルは `/archive-.json` に JSON 形式で出力されます。 メタデータファイルには WebM ファイルがいつ出力され、どんな形式なのか、開始時刻や終了時刻などの情報が含まれています。 - start_timestamp- この録画が開始された時刻を RFC 3339 (UTC) で表しています - stop_timestamp- この録画が終了した時刻を RFC 3339 (UTC) で表しています - start_time- この録画が開始された時刻を UNIX 時間で表しています - stop_time- この録画が終了した時刻を UNIX 時間で表しています **stats は省略しています** ```json { "audio": { "codec_type": "OPUS" }, "channel_id": "sora", "session_id": "JA8FB89ZJS1H9CV5GN3NCT5RA0", "client_id": "GK2R6PSDYX68VDQPRX4FVVFN8W", "bundle_id": "GK2R6PSDYX68VDQPRX4FVVFN8W", "connection_id": "GK2R6PSDYX68VDQPRX4FVVFN8W", "created_at": 1615524156, "file_path": "/path/to/sora/archive/WHEJ888HQ55KDCFE3TZ4VPFQHR/archive-GK2R6PSDYX68VDQPRX4FVVFN8W.webm", "filename": "WHEJ888HQ55KDCFE3TZ4VPFQHR/archive-GK2R6PSDYX68VDQPRX4FVVFN8W.webm", "metadata_file_path": "/path/to/sora/archive/WHEJ888HQ55KDCFE3TZ4VPFQHR/archive-GK2R6PSDYX68VDQPRX4FVVFN8W.json", "metadata_filename": "WHEJ888HQ55KDCFE3TZ4VPFQHR/archive-GK2R6PSDYX68VDQPRX4FVVFN8W.json", "recording_id": "WHEJ888HQ55KDCFE3TZ4VPFQHR", "size": 0, "start_time": 1615524137, "start_time_offset": 7, "start_timestamp": "2021-03-12T04:42:17.455668Z", "stats": {}, "stop_time": 1615524154, "stop_time_offset": 24, "stop_timestamp": "2021-03-12T04:42:34.094375Z", "label": "WebRTC SFU Sora", "node_name": "node1@192.0.2.10", "event_metadata": {"spam": "egg"}, "video": { "bit_rate": 1000, "codec_type": "VP9", "height": 480, "width": 640 } } ``` > **注釈** > > `sora.conf` の [legacy_webhook_audio_video_json_structure](SORA_CONF.html#3be597) を `false` にしている場合は > audio/video はフラット化します。詳細は > [ウェブフックの audio と video 項目の JSON 構造のフラット化](WEBHOOK_AUDIO_VIDEO_FLATTEN_JSON.html) > をご確認ください 色々省略していますが audio / video は以下のようになります。 ```javascript { "audio": true, "audio_codec_type": "OPUS" "video": true, "video_bit_rate": 1000, "video_codec_type": "VP9", "video_height": 480, "video_width": 640 } ``` ### report- 録画終了時に、それまでにそのチャネルで録画したファイル一覧が記載されているレポートファイルが JSON 形式で出力されます。 録画終了は [StopRecording](API.html#fd0de5) API を使用して指定したチャネルに対する録画を停止するか、 録画の期限が切れた場合のふたつのパターンがあります。 このファイルは主にマルチストリームや途中で切れてしまった場合などを考慮しており、 録画ファイルのグルーピングを目的としたファイルです。 ファイルは `/report-.json` に出力されます。 - トップレベルの start_timestamp- [StartRecording](API.html#c5b527) API を受け付た時刻を RFC 3339 (UTC) で表しています - トップレベルの stop_timestamp- [StopRecording](API.html#fd0de5) API を受け付た時刻か、 [StartRecording](API.html#c5b527) API で設定された期限の時刻を RFC 3339 (UTC) で表しています - archives 内の start_time_offset- [StartRecording](API.html#c5b527) API を叩いてから何秒経過した後にこの録画が開始したかを表しています - archives 内の stop_time_offset- [StartRecording](API.html#c5b527) API を叩いてから何秒経過した後にこの録画が終了したかを表しています ```json { "archives": [ { "client_id": "GK2R6PSDYX68VDQPRX4FVVFN8W", "bundle_id": "GK2R6PSDYX68VDQPRX4FVVFN8W", "connection_id": "GK2R6PSDYX68VDQPRX4FVVFN8W", "file_path": "/path/to/sora/archive/WHEJ888HQ55KDCFE3TZ4VPFQHR/archive-GK2R6PSDYX68VDQPRX4FVVFN8W.webm", "filename": "WHEJ888HQ55KDCFE3TZ4VPFQHR/archive-GK2R6PSDYX68VDQPRX4FVVFN8W.webm", "metadata_file_path": "/path/to/sora/archive/WHEJ888HQ55KDCFE3TZ4VPFQHR/archive-GK2R6PSDYX68VDQPRX4FVVFN8W.json", "metadata_filename": "WHEJ888HQ55KDCFE3TZ4VPFQHR/archive-GK2R6PSDYX68VDQPRX4FVVFN8W.json", "size": 0, "start_time_offset": 0, "start_timestamp": "2021-03-12T04:42:17.455668Z", "stop_time_offset": 17, "stop_timestamp": "2021-03-12T04:42:34.094375Z", "label": "WebRTC SFU Sora", "node_name": "node1@192.0.2.10" } ], "channel_id": "sora", "created_at": 1615524137, "expire_time": 3600, "expired_at": 1615527737, "file_path": "/path/to/sora/archive/WHEJ888HQ55KDCFE3TZ4VPFQHR/report-WHEJ888HQ55KDCFE3TZ4VPFQHR.json", "filename": "WHEJ888HQ55KDCFE3TZ4VPFQHR/report-WHEJ888HQ55KDCFE3TZ4VPFQHR.json", "metadata": {"spam": "egg"}, "recording_id": "WHEJ888HQ55KDCFE3TZ4VPFQHR", "split_only": false, "start_timestamp": "2021-03-12T04:42:17.455668Z", "stop_timestamp": "2021-03-12T04:42:34.094375Z" } ``` ## 分割録画ファイル出力のみ Sora では [StartRecording](API.html#c5b527) API 実行時に `split_duration` と `split_only: true` と `expire_time: 0` の 3 つを指定することで、 録画ファイルを指定した間隔で出力する機能を提供しています。 > **重要** > > 分割の最小単位はキーフレームから次のキーフレームまでです。例えば `split_duration` を 1 秒に設定した場合は、1 秒経過後に次のキーフレームが来たタイミングで分割出力されます。 録画が完了したファイルは `sora.conf` の [archive_dir](SORA_CONF.html#ad2156) に指定したディレクトリに `recording_id` 名のディレクトリ以下にファイルが出力されます。 `recording_id` は [StartRecording](API.html#c5b527) API を実行したときに戻ってくる値です。 ### 録画ファイル分割出力のみを行う 録画開始 API 実行時に `split_duration` と `split_only: true` と `expire_time: 0` の 3 つを指定することで、 録画ファイル分割出力 **のみ** を行うことが可能になります。 ディレクトリ構造: ``` ├── archive │ ├── 1CS9QJ0XPN4C76HBGBN6MGMK5M │ │ ├── split-archive-end-A4756MXP914ZB265E92JE3ZMWC.json │ │ ├── split-archive-A4756MXP914ZB265E92JE3ZMWC_0001.json │ │ ├── split-archive-A4756MXP914ZB265E92JE3ZMWC_0001.webm │ │ ├── split-archive-A4756MXP914ZB265E92JE3ZMWC_0002.json │ │ ├── split-archive-A4756MXP914ZB265E92JE3ZMWC_0002.webm │ │ ├── split-archive-A4756MXP914ZB265E92JE3ZMWC_0003.json │ │ ├── split-archive-A4756MXP914ZB265E92JE3ZMWC_0003.webm │ │ ├── split-archive-A4756MXP914ZB265E92JE3ZMWC_0003.json │ │ ├── split-archive-A4756MXP914ZB265E92JE3ZMWC_0003.webm │ │ └── report-1CS9QJ0XPN4C76HBGBN6MGMK5M.json │ └── CZZ8A8KZB16A1DF5PKERBHGFNR │ ├── split-archive-end-3B7AFF8ZRX6VNEYV40B35Z9S2C.json │ ├── split-archive-end-DGSN3TC0E91RSCZT5KVPRWCDHR.json │ ├── split-archive-3B7AFF8ZRX6VNEYV40B35Z9S2C_0001.json │ ├── split-archive-3B7AFF8ZRX6VNEYV40B35Z9S2C_0001.webm │ ├── split-archive-DGSN3TC0E91RSCZT5KVPRWCDHR_0001.json │ ├── split-archive-DGSN3TC0E91RSCZT5KVPRWCDHR_0001.webm │ ├── split-archive-DGSN3TC0E91RSCZT5KVPRWCDHR_0002.json │ ├── split-archive-DGSN3TC0E91RSCZT5KVPRWCDHR_0002.webm │ └── report-CZZ8A8KZB16A1DF5PKERBHGFNR.json ``` ### split-archive-_ #### 分割録画ファイル 分割録画ファイルは `/split-archvie-_.webm` に WebM 形式で出力されます。 #### 分割録画メタデータファイル 分割録画メタデータファイルは `/split-archive-_.json` に JSON 形式で出力されます。 - split_index- ファイル名につくインデックスです - 0001 から始まり 9999 の後は 10000 となります **stats は省略しています** ```json { "audio": { "codec_type": "OPUS" }, "recording_id": "CZZ8A8KZB16A1DF5PKERBHGFNR", "file_path": "/path/to/sora/archive/CZZ8A8KZB16A1DF5PKERBHGFNR/split-archive-3B7AFF8ZRX6VNEYV40B35Z9S2C_001.webm", "filename": "CZZ8A8KZB16A1DF5PKERBHGFNR/split-archive-3B7AFF8ZRX6VNEYV40B35Z9S2C_001.webm", "metadata_file_path": "/path/to/sora/split-archive/CZZ8A8KZB16A1DF5PKERBHGFNR/archive-3B7AFF8ZRX6VNEYV40B35Z9S2C_001.json", "metadata_filename": "CZZ8A8KZB16A1DF5PKERBHGFNR/split-archive-3B7AFF8ZRX6VNEYV40B35Z9S2C_001.json", "channel_id": "sora", "session_id": "JA8FB89ZJS1H9CV5GN3NCT5RA0", "client_id": "3B7AFF8ZRX6VNEYV40B35Z9S2C", "bundle_id": "3B7AFF8ZRX6VNEYV40B35Z9S2C", "connection_id": "3B7AFF8ZRX6VNEYV40B35Z9S2C", "split_index": "0001", "created_at": 1604656364, "size": 823263, "start_time": 1604656354, "start_time_offset": 4, "start_timestamp": "2020-11-06T09:52:34.696758Z", "stats": {}, "stop_time": 1604656364, "stop_time_offset": 14, "stop_timestamp": "2020-11-06T09:52:44.493179Z", "label": "WebRTC SFU Sora", "node_name": "node1@192.0.2.10", "event_metadata": {"spam": "egg"}, "video": { "bit_rate": 1000, "codec_type": "VP9", "height": 480, "width": 640 } } ``` > **注釈** > > `sora.conf` の [legacy_webhook_audio_video_json_structure](SORA_CONF.html#3be597) を `false` にしている場合は > audio/video はフラット化します。詳細は > [ウェブフックの audio と video 項目の JSON 構造のフラット化](WEBHOOK_AUDIO_VIDEO_FLATTEN_JSON.html) > をご確認ください ### split-archive-end- #### 分割録画終了メタデータファイル 分割録画終了メタデータファイルは `/split-archive-end-.json` に JSON 形式で出力されます。 **stats は省略しています** ```json { "audio": { "codec_type": "OPUS" }, "split_last_index": "0042", "recording_id": "CZZ8A8KZB16A1DF5PKERBHGFNR", "file_path": "/path/to/sora/archive/CZZ8A8KZB16A1DF5PKERBHGFNR/split-archive-end-3B7AFF8ZRX6VNEYV40B35Z9S2C.json", "filename": "CZZ8A8KZB16A1DF5PKERBHGFNR/split-archive-end-3B7AFF8ZRX6VNEYV40B35Z9S2C.json", "channel_id": "sora", "session_id": "JA8FB89ZJS1H9CV5GN3NCT5RA0", "client_id": "3B7AFF8ZRX6VNEYV40B35Z9S2C", "bundle_id": "3B7AFF8ZRX6VNEYV40B35Z9S2C", "connection_id": "3B7AFF8ZRX6VNEYV40B35Z9S2C", "start_time": 1604656354, "start_time_offset": 4, "start_timestamp": "2020-11-06T09:52:34.696758Z", "stats": {}, "stop_time": 1604656364, "stop_time_offset": 14, "stop_timestamp": "2020-11-06T09:52:44.493179Z", "label": "WebRTC SFU Sora", "node_name": "node1@192.0.2.10", "event_metadata": {"spam": "egg"}, "video": { "bit_rate": 1000, "codec_type": "VP9" } } ``` > **注釈** > > `sora.conf` の [legacy_webhook_audio_video_json_structure](SORA_CONF.html#3be597) を `false` にしている場合は > audio/video はフラット化します。詳細は > [ウェブフックの audio と video 項目の JSON 構造のフラット化](WEBHOOK_AUDIO_VIDEO_FLATTEN_JSON.html) > をご確認ください #### 録画ファイル分割出力終了時 接続単位での録画が終了したタイミングでイベントウェブフックリクエスト `split-archive.end` がリクエスト送信されます。 詳細は [split-archive.end](EVENT_WEBHOOK.html#31be7a) をご確認ください。 ### report- 録画終了時に、それまでにそのチャネルで録画したファイル一覧が記載されているレポートファイルが JSON 形式で出力されます。 録画終了は [StopRecording](API.html#fd0de5) API を使用して指定したチャネルに対する録画を停止するか、 録画の期限が切れた場合のふたつのパターンがあります。 このファイルは主にマルチストリームや途中で切れてしまった場合などを考慮しており、 録画ファイルのグルーピングを目的としたファイルです。 ファイルは `/report-.json` に出力されます。 分割録画ファイル出力のみの場合は archives には `connection_id` や `client_id` といった接続情報と、 分割録画ファイルの最後のインデックス番号のみが含まれます。 - トップレベルの start_timestamp- [StartRecording](API.html#c5b527) API を受け付た時刻を RFC 3339 (UTC) で表しています - トップレベルの stop_timestamp- [StopRecording](API.html#fd0de5) API を受け付た時刻か、 [StartRecording](API.html#c5b527) API で設定された期限の時刻を RFC 3339 (UTC) で表しています - archives 内の start_time_offset- [StartRecording](API.html#c5b527) API を叩いてから何秒経過した後にこの録画が開始したかを表しています - archives 内の stop_time_offset- [StartRecording](API.html#c5b527) API を叩いてから何秒経過した後にこの録画が終了したかを表しています ```json { "archives": [ { "client_id": "GK2R6PSDYX68VDQPRX4FVVFN8W", "bundle_id": "GK2R6PSDYX68VDQPRX4FVVFN8W", "connection_id": "GK2R6PSDYX68VDQPRX4FVVFN8W", "split_last_index": "0042" "start_time_offset": 4, "start_timestamp": "2020-11-06T09:52:34.696758Z", "stop_time_offset": 14, "stop_timestamp": "2020-11-06T09:52:44.493179Z", "label": "WebRTC SFU Sora", "node_name": "node1@192.0.2.10" } ], "channel_id": "sora", "created_at": 1615524137, "expire_time": 3600, "expired_at": 1615527737, "file_path": "/path/to/sora/archive/WHEJ888HQ55KDCFE3TZ4VPFQHR/report-GK2R6PSDYX68VDQPRX4FVVFN8W.json", "filename": "WHEJ888HQ55KDCFE3TZ4VPFQHR/report-GK2R6PSDYX68VDQPRX4FVVFN8W.json", "recording_id": "WHEJ888HQ55KDCFE3TZ4VPFQHR", "split_duration": 3600, "split_only": false, "metadata": {"spam": "egg"}, "start_timestamp": "2020-11-06T09:52:34.696758Z", "stop_timestamp": "2020-11-06T09:52:44.493179Z" } ``` ## 単一録画ファイルと分割録画ファイル [StartRecording](API.html#c5b527) API 実行時に `split_only` を有効にしない限り、 単一ファイルと分割ファイルの二つが出力されます。 単一録画ファイルと分割録画ファイルのいいところ取りですが、その分ストレージの容量も 2 倍消費します。 出力されるファイルは単一と分割のファイルが混ざった形式になります。 ディレクトリ構造: ``` ├── archive │ ├── 1CS9QJ0XPN4C76HBGBN6MGMK5M │ │ ├── split-archive-end-A4756MXP914ZB265E92JE3ZMWC.json │ │ ├── split-archive-A4756MXP914ZB265E92JE3ZMWC_0001.json │ │ ├── split-archive-A4756MXP914ZB265E92JE3ZMWC_0001.webm │ │ ├── split-archive-A4756MXP914ZB265E92JE3ZMWC_0002.json │ │ ├── split-archive-A4756MXP914ZB265E92JE3ZMWC_0002.webm │ │ ├── split-archive-A4756MXP914ZB265E92JE3ZMWC_0003.json │ │ ├── split-archive-A4756MXP914ZB265E92JE3ZMWC_0003.webm │ │ ├── split-archive-A4756MXP914ZB265E92JE3ZMWC_0003.json │ │ ├── split-archive-A4756MXP914ZB265E92JE3ZMWC_0003.webm │ │ ├── archive-A4756MXP914ZB265E92JE3ZMWC.json │ │ ├── archive-A4756MXP914ZB265E92JE3ZMWC.webm │ │ └── report-1CS9QJ0XPN4C76HBGBN6MGMK5M.json │ └── CZZ8A8KZB16A1DF5PKERBHGFNR │ ├── split-archive-end-3B7AFF8ZRX6VNEYV40B35Z9S2C.json │ ├── split-archive-3B7AFF8ZRX6VNEYV40B35Z9S2C_0001.json │ ├── split-archive-3B7AFF8ZRX6VNEYV40B35Z9S2C_0001.webm │ ├── split-archive-end-DGSN3TC0E91RSCZT5KVPRWCDHR.json │ ├── split-archive-DGSN3TC0E91RSCZT5KVPRWCDHR_0001.json │ ├── split-archive-DGSN3TC0E91RSCZT5KVPRWCDHR_0001.webm │ ├── split-archive-DGSN3TC0E91RSCZT5KVPRWCDHR_0002.json │ ├── split-archive-DGSN3TC0E91RSCZT5KVPRWCDHR_0002.webm │ ├── archive-3B7AFF8ZRX6VNEYV40B35Z9S2C.json │ ├── archive-3B7AFF8ZRX6VNEYV40B35Z9S2C.webm │ ├── archive-DGSN3TC0E91RSCZT5KVPRWCDHR.json │ ├── archive-DGSN3TC0E91RSCZT5KVPRWCDHR.webm │ └── report-CZZ8A8KZB16A1DF5PKERBHGFNR.json ``` ### report- 出力される report ファイルは単一と分割が混ざった形式になります。 - トップレベルの start_timestamp- [StartRecording](API.html#c5b527) API を受け付た時刻を RFC 3339 (UTC) で表しています - トップレベルの stop_timestamp- [StopRecording](API.html#fd0de5) API を受け付た時刻か、 [StartRecording](API.html#c5b527) API で設定された期限の時刻を RFC 3339 (UTC) で表しています - archives 内の start_time_offset- [StartRecording](API.html#c5b527) API を叩いてから何秒経過した後にこの録画が開始したかを表しています - archives 内の stop_time_offset- [StartRecording](API.html#c5b527) API を叩いてから何秒経過した後にこの録画が終了したかを表しています ```json { "archives": [ { "client_id": "GK2R6PSDYX68VDQPRX4FVVFN8W", "bundle_id": "GK2R6PSDYX68VDQPRX4FVVFN8W", "connection_id": "GK2R6PSDYX68VDQPRX4FVVFN8W", "file_path": "/path/to/sora/archive/WHEJ888HQ55KDCFE3TZ4VPFQHR/archive-GK2R6PSDYX68VDQPRX4FVVFN8W.webm", "filename": "WHEJ888HQ55KDCFE3TZ4VPFQHR/archive-GK2R6PSDYX68VDQPRX4FVVFN8W.webm", "metadata_file_path": "/path/to/sora/archive/WHEJ888HQ55KDCFE3TZ4VPFQHR/archive-GK2R6PSDYX68VDQPRX4FVVFN8W.json", "metadata_filename": "WHEJ888HQ55KDCFE3TZ4VPFQHR/archive-GK2R6PSDYX68VDQPRX4FVVFN8W.json", "size": 0, "start_time_offset": 0, "start_timestamp": "2021-03-12T04:42:17.455668Z", "stop_time_offset": 17, "stop_timestamp": "2021-03-12T04:42:34.094375Z", "split_last_index": "0042", "label": "WebRTC SFU Sora", "node_name": "node1@192.0.2.10" } ], "channel_id": "sora", "created_at": 1615524137, "expire_time": 3600, "expired_at": 1615527737, "file_path": "/path/to/sora/archive/WHEJ888HQ55KDCFE3TZ4VPFQHR/report-WHEJ888HQ55KDCFE3TZ4VPFQHR.json", "filename": "WHEJ888HQ55KDCFE3TZ4VPFQHR/report-WHEJ888HQ55KDCFE3TZ4VPFQHR.json", "recording_id": "WHEJ888HQ55KDCFE3TZ4VPFQHR", "label": "WebRTC SFU Sora", "node_name": "node1@192.0.2.10", "split_duration": 3600, "split_only": false, "metadata": {"spam": "egg"}, "start_timestamp": "2021-03-12T04:42:17.455668Z", "stop_timestamp": "2021-03-12T04:42:34.094375Z" } ``` ## 録画ファイル出力失敗時の録画一時ファイル 何らかの理由で録画ファイル出力が失敗した場合、 `archive_tmp_dir` で指定したディレクトリに録画一時ファイルが削除されずに残ります。そのため、定期的な削除が必要です。 この録画一時ファイルは WebM 形式のためそのまま再生することが可能です。 ## シグナリング通知 シグナリング通知で録画開始と終了を通知することが可能です。 詳細は [録画のシグナリング通知](SIGNALING_NOTIFY.html#7ce275) をご確認ください。 ## 録画ファイル合成ツール マルチストリームを録画した場合はそれぞれの接続に対して録画ファイルが出力されます。このそれぞれ分かれた録画ファイルを合成して一つにするツールをオープンソースとして公開しています。 詳細は [WebRTC 録画合成ツール Hisui](HISUI.html) をご確認ください。 ## 試してみる Sora では録画機能を試すための開発ツールを提供しています。 [開発ツール](DEVTOOLS.html) を参照の上、開発ツールを有効にしてください。 ここでは Sora が立っているサーバーは example.com としています。 ### チャネルの録画開始 API を叩いて録画を開始してください。 httpie: ``` $ http POST example.com:3000/ \ x-sora-target:Sora_20161101.StartRecording \ channel_id=sora \ expire_time:=3600 -vvv ``` curl: ``` $ curl -X POST example.com:3000/ \ -H "x-sora-target: Sora_20161101.StartRecording" \ -d '{"channel_id": "sora", "expire_time": 3600}' -vvv ``` その後 `https://example.com/sendonly.html` を開き、 connect ボタンを押して配信を開始します。 切断またはチャネルの録画終了、もしくはチャネルの録画期限が来たタイミングでクライアントの録画は終了します。 ### チャネルの録画終了 チャネルの録画を終了するには API を叩く必要があります。 httpie: ``` $ http POST example.com:3000/ \ x-sora-target:Sora_20161101.StopRecording \ channel_id=sora -vvv ``` curl: ``` $ curl -X POST example.com:3000/ \ -H "x-sora-target: Sora_20161101.StopRecording" \ -d '{"channel_id": "sora"}' -vvv ``` その後 archive/ ディレクトリに webm 形式のファイルが出力されます。 Chrome または Firefox にドラッグアンドドロップして、動作を確認してください。 ## 録画関連ファイルアップローダー > **重要** > > このツールはサポート対象外です 時雨堂では、録画関連ファイルを [Amazon S3](https://aws.amazon.com/jp/s3/) 、または S3 互換オブジェクトストレージにアップロードするツールを OSS として Apache License 2.0 で公開しています。 これは、Sora のクラウド版である [Sora Cloud](https://sora-cloud.shiguredo.jp) で利用している仕組みを 切り出したものです。 [shiguredo/sora-archive-uploader: Sora Archive Uploader](https://github.com/shiguredo/sora-archive-uploader) ## シーケンス図 ### StopRecording API seqdiag { default_fontsize = 15; edge_length = 250; === 認証成功 === クライアント <<- Sora [label = '"type": "offer"']; クライアント ->> Sora [label = '"type": "answer"', noactivate]; === WebRTC 確立 === アプリケーションサーバー ->> Sora [label = 'HTTP API\nStartRecording']; アプリケーションサーバー <-- Sora [label = '200 OK']; ... 録画中 ... アプリケーションサーバー ->> Sora [label = 'HTTP API\nStopRecording']; アプリケーションサーバー <-- Sora [label = '200 OK']; ... 録画終了 ... Sora -> アプリケーションサーバー [label = 'イベントウェブフック\n"type": "archive.available"']; Sora <-- アプリケーションサーバー [label = '200 OK']; Sora -> アプリケーションサーバー [label = 'イベントウェブフック\n"type": "recording.report"']; Sora <-- アプリケーションサーバー [label = '200 OK']; } ### 録画期限切れ seqdiag { default_fontsize = 15; edge_length = 250; === 認証成功 === クライアント <<- Sora [label = '"type": "offer"']; クライアント ->> Sora [label = '"type": "answer"', noactivate]; === WebRTC 確立 === アプリケーションサーバー ->> Sora [label = 'HTTP API\nStartRecording']; アプリケーションサーバー <-- Sora [label = '200 OK']; ... 録画中 ... ... 期限切れにより録画終了 ... Sora -> アプリケーションサーバー [label = 'イベントウェブフック\n"type": "archive.available"']; Sora <-- アプリケーションサーバー [label = '200 OK']; Sora -> アプリケーションサーバー [label = 'イベントウェブフック\n"type": "recording.report"']; Sora <-- アプリケーションサーバー [label = '200 OK']; } ### クライアント切断 seqdiag { default_fontsize = 15; edge_length = 250; === 認証成功 === クライアント <<- Sora [label = '"type": "offer"']; クライアント ->> Sora [label = '"type": "answer"', noactivate]; === WebRTC 確立 === アプリケーションサーバー ->> Sora [label = 'HTTP API\nStartRecording']; アプリケーションサーバー <-- Sora [label = '200 OK']; ... 録画中 ... クライアント ->> Sora [label = '"type": "disconnect"', noactivate]; Sora -> アプリケーションサーバー [label = 'イベントウェブフック\n"type": "connection.destroyed"']; Sora <-- アプリケーションサーバー [label = '200 OK']; クライアント <<- Sora [label = 'WebSocket Close']; ... クライアント切断により録画終了 ... Sora -> アプリケーションサーバー [label = 'イベントウェブフック\n"type": "archive.available"']; Sora <-- アプリケーションサーバー [label = '200 OK']; } # メッセージング機能 > **注意** > > メッセージング機能は実験的機能のため、正式版では仕様が変更される可能性があります ## 概要 ここでは DataChannel を利用したメッセージング機能について説明します。 DataChannel は、WebRTC の機能の一つでデータの送受信を行える機能です。 ## 注意 - メッセージング機能を利用するためには、 `data_channel_siganling` が有効になっている必要があります - メッセージング機能は DataChannel プロトコル互換性を維持しつつ Sora 独自の仕組みを追加しています ## 制限 ### メッセージサイズ制限 > **注意** > > 1 回のメッセージで送れる値には制限がありますのでご注意ください。 詳しくは DataChannel シグナリングの [推奨メッセージサイズ](DATA_CHANNEL_SIGNALING.html#2b27d3) をご確認ください ## SDK 対応状況 - 最新版の JavaScript SDK- 対応済みです - 最新版の iOS SDK- 対応済みです - 最新版の Android SDK- 対応済みです - 最新版の Unity SDK- 対応済みです - 最新版の C++ 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 はどちらかしか指定できません。 最大再送時間を指定します。デフォルトでは未指定で、無制限に再送します。 ### 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 - > **注意** > > 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": "sendonly" }, { "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": "sendonly" }, { "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": "#spam", "max_packet_life_time": 5000, "ordered": true, "protocol": "efg", "compress": false, "direction": "sendrecv" }, { "label": "#egg", "max_retransmits": 0, "ordered": false, "protocol": "abc", "compress": false "direction": "recvonly" } ] } ``` ## DataChannel を利用したメッセージングのみで接続する DataChannel を利用したメッセージングのみを有効にするには以下を満たす必要があります。 - `sora.conf` の `default_data_channel_signaling` を `true` にする - `sora.conf` の `data_channel_messaging_only` を `true` にする - `sora.conf` の `data_channel_messaging` を `true` にする - `{"type": "connect"}` 時に `role` を `sendrecv` にする - `{"type": "connect"}` 時に `multistream` を `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"` を受信 seqdiag { default_fontsize = 18; edge_length = 200; activation = none; クライアント1; クライアント2; クライアント3; Sora; クライアント1 ->> Sora [label = '1. type: connect']; === クライアント1 WebRTC 確立 === クライアント2 ->> Sora [label = '2. type: connect']; === クライアント2 WebRTC 確立 === クライアント1 ->> Sora [label = '3. label: #spam']; クライアント2 <<- Sora [label = '4. label: #spam']; クライアント1 ->> Sora [label = '5. label: #egg']; クライアント3 ->> Sora [label = '6. type: connect']; === クライアント3 WebRTC 確立 === クライアント1 ->> Sora [label = '7. label: #spam']; クライアント3 <<- Sora [label = '8. label: #spam']; クライアント2 <<- Sora [label = '9. label: #spam']; } # ICE コネクションステート機能 ## 概要 ICE コネクションステート機能は Sora に ICE コネクションによる状態管理を持たせた機能です。 ## 前提 この機能はクライアント側が意識する必要はありません。 ## 挙動 Sora は WebRTC が確立した後に TURN 上で ICE コネクションステートを更新し続けます。 ステートの更新には `STUN Binding-Request` と `STUN Binding-Sucess` を利用します。 - Sora は 2.5 秒間隔で `STUN Binding-Request` をクライアントへ送ります- `STUN Binding-Success` が 2.5 秒以内に一度も返ってこない場合、状態を `connected` から `connecting` へ遷移します - 状態が `connecting` へ遷移した場合、 Sora は 1 秒間隔で `STUN Binding-Request` をクライアントへ送ります- `STUN Binding-Success` が 5 秒以内に一度も返ってこない場合、状態を connecting から disocnnected へ遷移します - この 5 秒は `sora.conf` にて `ice_connection_state_disconnected_timeout` で変更可能です - 状態が `disocnnected` に遷移した場合、 Sora は 50 ミリ秒間隔で `STUN Binding-Request` をクライアントへ送ります- `STUN Binding-Success` が 10 秒以内に一度も返ってこない場合、状態を `disconnected` から `failed` へ遷移します - この 10 秒は `sora.conf` にて `ice_connection_state_failed_timeout` で変更可能です - このタイミングで `sora.log` に `warning` として `ICE-CONNECTION-STATE-DISCONNECTED` が出力されます - 状態が `failed` に遷移した場合、Sora はクライアントの接続を切断します- このタイミングで `sora.log` に `error` として `ICE-CONNECTION-STATE-FAILED` が出力されます ## 設定 ICE コネクションステート機能は無効にすることはできません。 ただし、切断や失敗までの判定時間を `sora.conf` にてデフォルト値から変更することが可能です。 ### ice_connection_state_disconnected_timeout この値は Sora が ICE コネクションステートを disconnected へと遷移する際にクライアントからの応答を待つ時間です。 デフォルトでは `5 s` が設定されています。 ### ice_connection_state_failed_timeout この値は Sora が ICE コネクションステートを failed へと遷移する際にクライアントからの応答を待つ時間です。 デフォルトでは `10 s` が設定されています。 ## シーケンス図 > **重要** > > 図のタイムアウト値はデフォルト値を採用しています。 ### connected 正常な接続状態である connected を継続しているシーケンス図です。 seqdiag { default_fontsize = 15; edge_length = 300; === WebRTC 確立 === Sora ->> クライアント [label = 'STUN Binding-Request']; Sora <<- クライアント [label = 'STUN Binding-Sucess']; ... 2.5 秒 ... Sora ->> クライアント [label = 'STUN Binding-Request']; Sora <<- クライアント [label = 'STUN Binding-Sucess']; ... 2.5 秒 ... Sora ->> クライアント [label = 'STUN Binding-Request']; Sora <<- クライアント [label = 'STUN Binding-Sucess']; } ### connected -> connecting 正常な接続状態である connected から一時的に反応が無く connecting 状態へ切り替わるシーケンス図です。 seqdiag { default_fontsize = 15; edge_length = 300; === WebRTC 確立 === Sora ->> クライアント [label = 'STUN Binding-Request', noactivate]; ... 2.5 秒経過したが反応が無い ... === connecting === Sora ->> クライアント [label = 'STUN Binding-Request', noactivate]; ... 1.0 秒 ... Sora ->> クライアント [label = 'STUN Binding-Request', noactivate]; ... 1.0 秒 ... Sora ->> クライアント [label = 'STUN Binding-Request', noactivate]; } ### connecting -> disconnected 一時的に反応が無い connecting の状態が続いたため、 切断判断をするために短い間隔で疎通パケットを送信する disconnected 状態へ切り替わるシーケンス図です。 seqdiag { default_fontsize = 15; edge_length = 300; === WebRTC 確立 === === connecting === Sora ->> クライアント [label = 'STUN Binding-Request', noactivate]; ... 1.0 秒間隔で 5 秒間送り続けるが反応が無い ... Sora ->> クライアント [label = 'STUN Binding-Request', noactivate]; ... 50 ミリ秒 ... Sora ->> クライアント [label = 'STUN Binding-Request', noactivate]; } ### disconnected -> failed 切断判断をするため短い間隔で疎通パケットを送り続けたが、反応が無かったため failed へと切り替わるシーケンス図です。 seqdiag { default_fontsize = 15; edge_length = 300; === WebRTC 確立 === === connecting === === disconnected === Sora ->> クライアント [label = 'STUN Binding-Request', noactivate]; ... 50 ミリ秒間隔で 10 秒間送り続けるが反応が無い ... === 10 秒経過 (failed) === ... Sora はクライアントを切断する ... } ### disconnected -> connecting -> connected 一定時間、不通になっていたため状態が disconnected になっていましたが、 connecting を経て connected まで状態が戻るシーケンス図です。 seqdiag { default_fontsize = 15; edge_length = 300; === WebRTC 確立 === === connecting === === disconnected === Sora ->> クライアント [label = 'STUN Binding-Request', noactivate]; ... 50 ミリ秒間隔で 10 秒間送り続ける ... Sora <<- クライアント [label = 'STUN Binding-SUCCESS', noactivate]; === connecting === Sora ->> クライアント [label = 'STUN Binding-Request', noactivate]; ... 1.0 秒間隔で 5 秒間送り続ける ... Sora <<- クライアント [label = 'STUN Binding-SUCCESS', noactivate]; === connected === Sora ->> クライアント [label = 'STUN Binding-Request', noactivate]; ... 2.5 秒間隔で送り続ける ... Sora <<- クライアント [label = 'STUN Binding-SUCCESS', noactivate]; } # モード機能 > **注意** > > モード機能は実験的機能のため、正式版では仕様が変更される可能性があります ## 概要 モード (mode) 機能 は、指定されているモードごとに Sora の挙動を変更する機能です。 ## 目的 現在の Sora 自体には認証の機能を持っていないため、一時的に接続をブロックするといった仕組みがありません。もしやるとしても認証サーバー側で処理をすることになり不便でした。 そこで、Sora 側にモード機能を持たせることで、モードを切り替えることで接続を気軽にブロックする機能を追加します。 また、クラスター機能が有効な場合には、起動直後のノードやネットワーク障害などで孤立したノードに特別なモードを割り当てることで、 「同じチャネルが複数のノードで処理されている」などといった不整合が発生することを防いでいます。 ## モード ### ノーマルモード このモードは何もせず、すべての新規接続を受け入れます。 ### 新規コネクションブロックモード このモードは新規の接続をブロックします。すでに接続しているコネクションはそのままです。 ### 新規セッションブロックモード このモードは新規セッションの作成をブロックします。すでに接続しているセッションやコネクションはそのままです。 そのためセッション(チャネルに 1 人以上接続しているアクティブな状態)が存在する場合は接続できますが、セッションが存在しない場合は新規の接続をブロックします。 ### イニシャルモード > **注意** > > このモードはクラスター機能が有効の際に起動時や孤立した際に割り当てられる特殊なモードです。 このモードはすべての接続をブロックします。 - クラスターへ参加したタイミングでノーマルモードで自動で切り替わります - クラスターから孤立したタイミングでノーマルモードからイニシャルモードへ自動で切り替わります- ノーマルモード以外の場合には、切り替わらずに、その時のモードが維持されます このモードを指定して変更することはできません。 ## ウェブフック ### session.vanished このウェブフックは、新規コネクションブロック、または新規セッションブロックモード時に全てのセッションが破棄されたタイミングで送信されます。 ```javascript { "type": "session.vanished", } ``` ## API ### ChangeMode - mode- normal - block_new_session - block_new_connection ```console $ http POST 127.0.0.1:3000 x-sora-target:Sora_20211215.ChangeMode mode=block_new_session -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 29 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.3.0 x-sora-target: Sora_20211215.ChangeMode { "mode": "block_new_session" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 28 content-type: application/json date: Wed, 06 Oct 2021 10:42:35 GMT server: Cowboy { "mode": "block_new_session" } ``` ```console $ http POST 127.0.0.1:3000 x-sora-target:Sora_20211215.ChangeMode mode=block_new_connection -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 32 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.3.0 x-sora-target: Sora_20211215.ChangeMode { "mode": "block_new_connection" } HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 31 content-type: application/json date: Wed, 06 Oct 2021 10:44:05 GMT server: Cowboy { "mode": "block_new_connection" } ``` ### GetMode ```console $ http POST 127.0.0.1:3000 x-sora-target:Sora_20211215.GetMode -vvv POST / HTTP/1.1 Accept: */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 0 Host: 127.0.0.1:3000 User-Agent: HTTPie/2.3.0 x-sora-target: Sora_20211215.GetMode HTTP/1.1 200 OK access-control-allow-headers: Origin, X-Requested-With, Content-Type, Accept, x-sora-target access-control-allow-methods: POST, OPTIONS access-control-allow-origin: http://127.0.0.1:5000 access-control-max-age: 1000 content-length: 17 content-type: application/json date: Wed, 06 Oct 2021 10:42:19 GMT server: Cowboy { "mode": "normal" } ``` ## クラスター機能 ### クラスター機能有効での Sora 起動時の mode クラスター機能を利用した場合、 Sora 起動時の `mode` が [イニシャルモード](MODE.html#74fada) になります。 クラスターへの参加に成功したタイミングで [イニシャルモード](MODE.html#74fada) から [ノーマルモード](MODE.html#920e82) へ変更されます。 ### チャネル ID のノード割り当て クラスター機能を利用した場合、 `mode` が [新規セッションブロックモード](MODE.html#041e1c) または [新規コネクションブロックモード](MODE.html#0b67d3) または [イニシャルモード](MODE.html#74fada) のノードに対して、 新規のチャネル ID を割り当てません。 ## シーケンス図 ### block_new_connection seqdiag { default_fontsize = 15; edge_length = 220; activation = none; クライアント1; クライアント2; Sora; HTTPクライアント; === Sora 起動 === === モード: normal === クライアント1 ->> Sora [label = '"type": "connect"', noactivate]; HTTPクライアント -> Sora [label = 'ChangeMode API\n mode=block_new_connection']; HTTPクライアント <- Sora; === モード: block_new_connection === クライアント2 ->> Sora [label = '"type": "connect" 失敗\n\n', failed]; HTTPクライアント -> Sora [label = 'ChangeMode API\n mode=normal']; HTTPクライアント <- Sora; === モード: normal === クライアント2 ->> Sora [label = '"type": "connect"']; } ### block_new_session seqdiag { default_fontsize = 12; edge_length = 170; activation = none; クライアント1; クライアント2; クライアント3; Sora; HTTPクライアント; === Sora 起動 === === モード: normal === クライアント1 ->> Sora [label = 'type: connect\nchannel_id: spam', noactivate]; クライアント1 <<- Sora [label = 'type: offer', noactivate]; HTTPクライアント -> Sora [label = 'ChangeMode API\n mode=block_new_session']; HTTPクライアント <- Sora; === モード: block_new_session === クライアント2 ->> Sora [label = 'type: connect\nchannel_id: egg\n失敗\n\n', failed]; クライアント3 -> Sora [label = 'type: connect\nchannel_id: spam', noactivate]; クライアント3 <- Sora [label = 'type: offer', noactivate]; } # 音声ストリーミング機能 > **注意** > > この機能を利用する場合は事前にサポートまでご連絡ください > **警告** > > 音声ストリーミング機能は実験的機能のため、正式版では仕様が変更される可能性があります ## 概要 Sora に WebRTC で送られてきた音声を接続ごとに HTTP/2 で外部へ出力し、解析結果をクライアントへプッシュで通知する機能です。 ## 仕様 ### マルチストリームでのみ利用可能 音声ストリーミング機能はマルチストリームを有効にした状態でのみ利用可能です。 ### 言語コードの指定 音声ストリーミングを利用する場合、 言語コードを指定する必要があります。 シグナリング接続時、または認証成功時の払い出しで `{"audio_streaming_language_code": "ja-JP"}` のように指定してください。 指定するのは **文字列であればなんでもかまいません** 。Sora 自体は言語コードには関与しません。あくまでただの文字列として扱います。 > **注意** > > 言語コードが指定されていない接続は、音声ストリーミングが開始している場合でも音声ストリーミングを行いません。 > 言語コードは音声を解析するにあたり必要になるためこのような仕様になっています。 ### セッションウェブフック経由での開始 音声ストリーミングはセッション単位で開始、終了します。 セッション開始時から音声ストリーミングを開始したい場合、 セッションウェブフックの戻り値に `{"audio_streaming": true}` を指定することで音声ストリーミングが開始します。 そのセッションに参加してきた言語コードが指定されているクライアントはすべて音声ストリーミングが行われます。 ### セッション終了時の音声ストリーミング終了 チャネルのセッションが終了したタイミングで音声ストリーミングは終了します。 ### API 経由での開始 セッションの途中で音声ストリーミングを開始する場合は [StartAudioStreaming](EXPERIMENTAL_API.html#0f1087) API を利用する必要があります。 ### API 経由での終了 セッションの途中で音声ストリーミングを終了する場合は [StopAudioStreaming](EXPERIMENTAL_API.html#bad1bb) API を利用する必要があります。 ### 1 コネクション 1 HTTP/2 コネクション 音声ストリーミングが開始している状態でそのチャネルに新規クライアントが参加すると、 `audio_streaming_url` 宛てに新しく HTTP/2 コネクションが張られ、 クライアントから送られてきた Opus のバイナリデータがそのまま送られます。 HTTP/2 コネクションを張る際のヘッダーには以下の値が入ります。 - sora-channel-id- クライアントのチャネル ID - sora-connection-id- クライアントのコネクション ID - sora-audio-streaming-language-code- クライアントの言語コード ### プッシュ通知経由での戻り値の通知 シグナリングのプッシュ通知経由で外部サーバーからの戻り値を通知します。 ```javascript { "type": "push", "data": { "type": "audio_streaming_result", "connection_id": "", "result": "レスポンスがそのまま含まれる" } } ``` ## 設定 ### audio_streaming_url **デフォルト**: 指定なし 音声ストリーミングゲートウェイの URL を指定してください。 音声ストリーミングゲートウェイは HTTP/2 に対応している必要があります。 詳細は [audio_streaming_url](SORA_CONF.html#6b5dd6) をご確認ください。 ### default_audio_streaming_result_push **デフォルト**: true 音声ストリーミングゲートウェイからのレスポンスをシグナリングプッシュ通知で送ることをデフォルトで行うかを指定してください。 詳細は [default_audio_streaming_result_push](SORA_CONF.html#0b4a07) をご確認ください。 ### default_audio_streaming_language_code **デフォルト**: 指定なし 音声ストリーミングゲートウェイ接続時に HTTP ヘッダー `sora-audio-steraming-language-code` にデフォルトで含める文字列を指定してください。 詳細は [default_audio_streaming_language_code](SORA_CONF.html#856531) をご確認ください。 ### audio_streaming_tls_fullchain_file **デフォルト**: 指定なし 音声ストリーミングゲートウェイとの通信に HTTPS で mTLS を利用するための設定で、 中間証明書を含む PEM 形式 のクライアント証明書のパスを設定して下さい。 詳細は [audio_streaming_tls_fullchain_file](SORA_CONF.html#e5459b) をご確認ください。 ### audio_streaming_tls_privkey_file **デフォルト**: 指定なし 音声ストリーミングゲートウェイとの通信に HTTPS で mTLS を利用するための設定で、 PEM 形式のクライアント証明書秘密鍵のパスを設定して下さい。 詳細は [audio_streaming_tls_privkey_file](SORA_CONF.html#5f8e61) をご確認ください。 ### audio_streaming_tls_verify_cacert_file **デフォルト**: 指定なし 音声ストリーミングゲートウェイとの通信に HTTPS を利用した際、 サーバー証明書のチェックを行う PEM 形式の CA ファイルのパスを設定して下さい。 詳細は [audio_streaming_tls_verify_cacert_file](SORA_CONF.html#feef99) をご確認ください。 ## API ### StartAudioStreaming API セッションが存在し、音声ストリーミングが開始していないチャネルに対して音声ストリーミングを開始します。 詳細は [StartAudioStreaming](EXPERIMENTAL_API.html#0f1087) をご確認ください。 ### StopAudioStreaming API セッションが存在し、音声ストリーミングが開始しているチャネルに対して音声ストリーミングを停止します。 > **注釈** > > 音声ストリーミングを終了すると、すべて接続の購読状態は初期化され、デフォルトの値に戻ります。 詳細は [StopAudioStreaming](EXPERIMENTAL_API.html#bad1bb) をご確認ください。 ### SubscribeAudioStreamingResultPush API 指定した接続が音声ストリーミングサーバーからの戻り値のプッシュ通知を購読するよう設定します。 詳細は [SubscribeAudioStreamingResultPush](EXPERIMENTAL_API.html#d26262) をご確認ください。 > **注釈** > > デフォルトの値は `sora.conf` の [default_audio_streaming_result_push](SORA_CONF.html#0b4a07) が適用されます。 ### UnsubscribeAudioStreamingResultPush API 指定した接続が音声ストリーミングサーバーからの戻り値のプッシュ通知を購読しないよう設定します。 > **注釈** > > デフォルトの値は `sora.conf` の [default_audio_streaming_result_push](SORA_CONF.html#0b4a07) が適用されます。 詳細は [UnsubscribeAudioStreamingResultPush](EXPERIMENTAL_API.html#b63656) をご確認ください。 ## Audio Streaming Gateway Suzu > **重要** > > Audio Streaming Gateway Suzu は Sora サポートの対象外です [shiguredo/suzu: Audio Streaming Gateway Suzu](https://github.com/shiguredo/suzu) Sora から HTTP/2 経由で送られてくるヘッダーや Opus 音声データを、 音声からテキストに変換するサービスへを Ogg 形式にして送信し、 サービスから受信した変換結果を Sora に返すゲートウェイです。 ### 対応サービス - [Amazon Transcribe](https://aws.amazon.com/jp/transcribe/) - [Google Cloud Speech-to-Text](https://cloud.google.com/speech-to-text) ## シーケンス図 ### Suzu + AWS Transcribe seqdiag { default_fontsize = 15; edge_length = 220; activation = none; クライアント -> Sora [label = 'SRTP']; クライアント -> Sora [label = 'SRTP']; クライアント -> Sora [label = 'SRTP']; === StartAudioStreaming API 実行 === クライアント -> Sora [label = 'SRTP']; Sora -> Suzu [label = 'Opus over HTTP/2']; Suzu -> 'AWS Transcribe' [label = 'Ogg over HTTP/2']; クライアント -> Sora [label = 'SRTP']; Sora -> Suzu [label = 'Opus over HTTP/2']; Suzu -> 'AWS Transcribe' [label = 'Ogg over HTTP/2']; クライアント -> Sora [label = 'SRTP']; Sora -> Suzu [label = 'Opus over HTTP/2']; Suzu -> 'AWS Transcribe' [label = 'Ogg over HTTP/2']; Suzu <- 'AWS Transcribe' [label = 'JSON over HTTP/2']; Sora <- Suzu [label = 'Json over HTTP/2']; クライアント <- Sora[label = 'DataChannel']; } # 統計エクスポーター機能 > **注意** > > 統計エクスポーター機能は実験的機能のため、正式版では仕様が変更される可能性があります ## 概要 Sora 経由で統計情報コレクターに向けて統計情報をエクスポートする機能です。 ## HTTP/2 - 統計コレクターサーバーは HTTP/2 に対応している必要があります - h2c と h2 の両方に対応しています - `http://` から始めると h2c を利用します - `https://` から始めると h2 を利用します ## WebRTC Stats Collector Kohaku **URL**: Kohaku は統計エクスポーター対応の統計コレクターです。 ## 設定 ### stats_collector_url 統計情報を収集するコレクターの URL を指定します。 HTTP または HTTPS の URL が指定可能です。 ```ini stats_collector_url = http://192.0.2.10:5890/collector ``` ### stats_exporter_number 統計情報を出力するエクスポーターの数を指定できます。 基本的にはデフォルトの 5 で足りますが、同時接続数が多い場合は変更をお勧めします。 ```ini stats_exporter_number = 5 ``` ### stats_exporter_tls_fullchain_file mTLS を利用するための設定で、中間証明書を含むクライアント証明書を PEM 形式で設定して下さい。 ```ini stats_exporter_tls_fullchain_file = /path/to/fullchain.pem ``` ### stats_exporter_tls_privkey_file 統計コレクターサーバーと mTLS を利用するための設定で、クライアント証明書の秘密鍵を PEM 形式で設定して下さい。 > **重要** > > 秘密鍵にパスフレーズが設定されている場合はエラーとなります ```ini stats_exporter_tls_privkey_file = /path/to/privkey.pem ``` ### stats_exporter_tls_verify_cacert_file 統計コレクターサーバーとの通信に HTTPS を利用した際、サーバー証明書のチェックを行う CA ファイルを PEM 形式で設定して下さい。 ```ini stats_exporter_tls_verify_cacert_file = /path/to/server_cacert.pem ``` ### stats_exporter_erlang_vm_interval > **注意** > > この設定は無理に設定する必要はありません 統計コレクターサーバーに Sora が利用している Erlang VM の統計情報を送る間隔を指定できます。 間隔を指定しないと統計情報自体を送りません。 ```ini stats_exporter_erlang_vm_interval = 60 s ``` ## エクスポーター 統計情報をコレクターに対して送ります。 ### 共通 - type- 統計情報の種類情報が入ります - node_name- Sora のノード名が入ります - クラスター機能を利用していない場合は `sora@127.0.0.1` です - version- Sora のバージョンが入ります - label- sora.conf に設定された label が入ります - timestamp- Sora が stats を送る直前の時間 RFC3339 形式の (UTC) が入ります ### HTTP ヘッダー > **注釈** > > JSON のパース時の判断などに利用してください。 統計エクスポーターの HTTP ヘッダー に `x-sora-stats-exporter-type` というヘッダー名で統計エクスポーターのタイプが入ってきます。 `type` が `connection.user-agent` の場合は `x-sora-stats-exporter-type: connection.user-agent` のように値が入ってきます。 ### type: connection.user-agent クライアントから送られてくるユーザーエージェント統計情報です。 ユーザーエージェント統計情報は W3C の [Identifiers for WebRTC's Statistics API](https://www.w3.org/TR/webrtc-stats/) に準拠している必要があります。 - type- `connection.user-agent` - channel_id- チャネル ID が入ります - session_id- セッション ID が入ります - client_id - connection_id - multistream - simulcast - spotlight - stats ```javascript { "channel_id": "sora", "client_id": "NCD5EF3ME900ZDJ3SE27Y6AB6R", "connection_id": "NCD5EF3ME900ZDJ3SE27Y6AB6R", "id": "N6W0DBF6A957B01BKNJJR1HC04", "label": "WebRTC SFU Sora", "stats": [ { "id": "RTCAudioSource_5", "kind": "audio", "timestamp": 1629449091306.655, "type": "media-source", "audioLevel": 0.02237006744590594, "totalAudioEnergy": 0.15581033797981153, "totalSamplesDuration": 5.089999999999936, "trackIdentifier": "922dd031-8a4f-4122-9687-ce094fa11ee2" }, ... ], "timestamp": "2021-08-20T08:44:51.308778Z", "type": "connection.user-agent", "version": "2021.2" } ``` ### type: connection.sora **現時点ではまだ対応していません** Sora にため込んでいる統計情報です。 ## type の頻度指定 変化が無かったり変化の少ない stats を送る頻度を減らしています。 デフォルト 600 秒間隔にしています。 ### type: connection.user-agent 送信頻度を抑えている Stats Type。 - codec- Sora の場合、初期値から変更される項目が無いため - local-candidate- Sora の場合、初期値から変更される項目が無いため - remote-candidate- Sora の場合、初期値から変更される項目が無いため - certificate- Sora の場合、初期値から変更される項目が無いため - peer-connection- Sora の場合、初期値から変更される項目が無いため - track- DEPRECATED 項目のため - stream- DEPRECATED 項目のため ## シーケンス図 ### DataChannel シグナリング利用時 seqdiag { default_fontsize = 15; edge_length = 220; === WebRTC 確立 === クライアント -> Sora [label = 'Stats over DataChannel', noactivate]; Sora -> "Stats Collector" [label = 'Stats over HTTP/2']; "Stats Collector" -> TSDB [noactivate]; "Stats Collector" <-- TSDB; Sora <<-- "Stats Collector" [label = '200 OK']; } # E2EE 機能 > **警告** > > E2EE 機能は実験的機能のため、正式版では仕様が変更される可能性があります ## 概要 E2EE とは End-to-End Encryption の略で、音声や映像を、 WebRTC SFU が保持しない暗号鍵を利用して暗号化した状態で WebRTC SFU に送る仕組みです。 そのため WebRTC SFU 側では音声や映像を解析することが不可能になります。 ## 既知の問題 **この問題は次の Sora E2EE ライブラリのリリースで解決予定です** - 同一ページで同一チャネルに複数接続できない - 同一ページで複数チャネルに接続できない ## SDK 対応状況 現時点では Sora JavaScript SDK が E2EE に対応しています。 iOS / Android / Unity SDK は非対応です。 ## 対応済みブラウザ - Chrome 89 以降 - Edge 89 以降 ## Sora E2EE の詳細 別途ドキュメントにまとめています。 [Sora E2EE ドキュメント](https://sora-e2ee.shiguredo.jp/) ## E2EE を有効にする ### e2ee 設定の有効化 **E2EE 機能はデフォルトで無効です** sora.conf にて `e2ee = true` を設定してください。 ```ini e2ee = true ``` 有効にすることで Sora が E2EE メッセージルーティングを行うようになります。 この設定が `false` の状態でクライアントが E2EE 接続を行っても、メッセージのルーティングを行わず切断されます。 ### signaling_notify の有効化 **シグナリング通知機能はデフォルトで有効です** E2EE 機能はシグナリング通知機能を利用します。 ```ini signaling_notify = true ``` ### signaling_notify_connection_id の有効化 **シグナリング通知コネクション ID 機能はデフォルトで有効です** E2EE 機能はシグナリング通知機能のコネクション ID を利用します。 ```ini signaling_notify_connection_id = true ``` ### signaling_notify_metadata の有効化 **シグナリング通知メタデータ機能はデフォルトで有効です** E2EE 機能はシグナリング通知機能のメタデータを利用します。 ```ini signaling_notify_metadata = true ``` ## E2EE を利用する ### wasm ファイルの用意 ブラウザで Sora の E2EE を利用するには wasm ファイルが必要です。 wasm ファイルは自前でビルドすることをおすすめします。ビルドをご確認下さい。 ### ビルド済み WebAssembly バイナリ 弊社では、開発ツールでの利用のため、ビルド済み WebAssembly バイナリを CDN で提供しています。 - - 2020.2 バージョン > **重要** > > 本番環境では、これらの URL は利用しないでください。 > 代わりに、自前でビルドしたバイナリを配置してご利用下さい。 ### Sora JavaScript SDK の用意 Sora JS SDK の最新版を利用してください。 ```javascript // E2EE 用 Wasm 読み込み // Sora.initE2EE("wasm.wasm"); でも良い Sora.initE2EE("https://example.com/wasm.wasm"); let sora = Sora.connection('wss://example.com/signaling'); let channelId = 'sora-e2ee'; let sendrecv = sora.sendrecv(channelId, undefined, {e2ee: true}); navigator.mediaDevices.getUserMedia({audio: true, video: true}) .then(mediaStream => { // connect sendrecv.connect(mediaStream) .then(stream => { // stream を video.src に追加する等の処理 }); }) .catch(e => { console.error(e); }); // disconnect sendrecv.disconnect() .then(() => { // video を止める等の処理 }); // event sendrecv.on('disconnect', function(e) { console.error(e); }); ``` ## サポート E2EE ではクライアントを含めたサポートが必要になる場合がありますが、 ご質問などがあればまずサポートまでお問い合わせください。 ## E2EE が有効かどうか E2EE の状態で録画を行うと、生成されるファイルが全て暗号化された状態になり、 一切見られなくなりますので **E2EE の動作確認** として利用してみて下さい。 ## Discord Discord にてコミュニティを運営しています。 なにか質問したい場合は Discord サーバーへ参加してください。 # Lyra コーデック機能 > **注意** > > Lyra コーデック機能は実験的機能のため、正式版では仕様が変更される可能性があります ## 概要 Google が公開している超低ビットレートで利用可能な音声コーデック [Lyra](https://github.com/google/lyra) を利用可能にする機能です。 Lyra についての詳細は Google の記事をご確認ください。 [Lyra V2 - a better, faster, and more versatile speech codec | Google Open Source Blog](https://opensource.googleblog.com/2022/09/lyra-v2-a-better-faster-and-more-versatile-speech-codec.html) ## 機能 - 音声コーデックに Opus とは別に Lyra を指定することが可能になります - ビットレートも 3200 / 6000 / 9200 bps の 3 種類が指定可能です ### 対応ブラウザ [WebAssembly 化した Lyra](https://github.com/shiguredo/lyra-wasm) と [WebRTC Encoded Transform API](https://www.w3.org/TR/webrtc-encoded-transform/) を利用する事で、 Chrome / Edge / Safari で利用可能です。Firefox には対応していません。 ### 対応 SDK - JavaScript SDK - C++ SDK ## 独自対応 Lyra 用の SDP は独自機能です。 ``` a=rtpmap:109 lyra/16000/1 a=fmtp:109 version=1.3.0;bitrate=6000;usedtx=1 ``` - version- Lyra のバージョンが入ってきます- SDK が対応している Lyra と受信した sdp の Lyra のバージョンが異なる場合 SDK 側でエラーを出力する場合があります - bitrate- 3200 / 6000 / 9200 のどれかが入ってきます - usedtx- DTX を利用するかどうかです- 利用する場合は 1 、利用しない場合は 0 が入ってきます- Lyra はデフォルトで DTX を利用します # Sora JavaScript (TypeScript) SDK ## 概要 **URL**: Sora JavaScript SDK は Sora を JavaScript から使用するための仕組みです。 ## ドキュメント ドキュメントは にて提供しています。 ## ライセンス Sora JavaScript SDK は [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) で公開しています。 ## サポートについて Sora JavaScript SDK に関する質問・要望・バグなどの報告は Discord の利用をお願いします。 Sora のライセンス契約の有無に関わらず、応答時間と問題の解決を保証しませんのでご了承ください。 ただし、明らかなバグに関しては優先的に対応させていただきます。 Sora JavaScript SDK に対する有償のサポートについては提供しておりません。 ## Discord **URL**: Discord にてコミュニティを運営しています。 なにか質問したい場合は Discord サーバーへ参加してください。 Sora JavaScript SDK のチャンネルは `#sora-js-sdk` です。 ## E2EE について Sora JavaScript SDK では E2EE が利用できます。 E2EE ライブラリはオープンソースとして Apache License 2.0 で GitHub にて公開しています。 [shiguredo/sora-e2ee: WebRTC SFU Sora 向け JavaScript E2EE ライブラリ](https://github.com/shiguredo/sora-e2ee) 詳細については [E2EE 機能](E2EE.html) をご確認ください。 # Sora iOS (Swift) SDK ## 概要 **URL**: Sora iOS SDK は Sora を iOS から使用するための仕組みです。 ## ドキュメント ドキュメントは にて提供しています。 ## サンプル - [WebRTC SFU Sora iOS SDK クイックスタート](https://github.com/shiguredo/sora-ios-sdk-quickstart) - [WebRTC SFU Sora iOS SDK サンプル集](https://github.com/shiguredo/sora-ios-sdk-samples) ## ライセンス Sora iOS SDK は [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) で公開しています。 ## サポートについて Sora iOS SDK に関する質問・要望・バグなどの報告は Discord の利用をお願いします。 Sora のライセンス契約の有無に関わらず、応答時間と問題の解決を保証しませんのでご了承ください。 ただし、明らかなバグに関しては優先的に対応させていただきます。 Sora iOS SDK に対する有償のサポートについては提供しておりません。 ## Discord **URL**: Discord にてコミュニティを運営しています。 なにか質問したい場合は Discord サーバーへ参加してください。 Sora iOS SDK のチャンネルは `#sora-ios-sdk` です。 ## NAT64/DNS64 対応 ### 前提 [Supporting IPv6 DNS64/NAT64 Networks](https://developer.apple.com/library/archive/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/UnderstandingandPreparingfortheIPv6Transition/UnderstandingandPreparingfortheIPv6Transition.html) Apple IPv6 審査対応として NAT64/DNS64 への対応が必要になります。 iOS SDK は NAT64/DNS64 へ対応しています。ただ WebRTF SFU Sora 側を NAT64/DNS64 へ対応するためには設定を追加する必要があります。 ### WebRTC SFU Sora の設定 `sora.conf` の `turn` を `true` にして、 `turn_fqdn` に FQDN を設定してください。それだけで対応は完了です。 ```ini turn_fqdn = sora.example.com ``` # Sora Android (Kotlin) SDK ## 概要 **URL**: Sora Android SDK は Sora を Android から使用するための仕組みです。 ## ドキュメント ドキュメントは にて提供しています。 ## サンプル - [WebRTC SFU Sora Android SDK クイックスタート](https://github.com/shiguredo/sora-android-sdk-quickstart) - [WebRTC SFU Sora Android SDK サンプル集](https://github.com/shiguredo/sora-android-sdk-samples) ## ライセンス Sora Android SDK は [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) で公開しています。 ## サポートについて Sora Android SDK に関する質問・要望・バグなどの報告は Discord の利用をお願いします。 Sora のライセンス契約の有無に関わらず、応答時間と問題の解決を保証しませんのでご了承ください。 ただし、明らかなバグに関しては優先的に対応させていただきます。 Sora Android SDK に対する有償のサポートについては提供しておりません。 ## Discord **URL**: Discord にてコミュニティを運営しています。 なにか質問したい場合は Discord サーバーへ参加してください。 Sora Android SDK のチャンネルは `#sora-android-sdk` です。 # Sora Unity (C++) SDK ## 概要 **URL**: Sora Unity SDK は Sora を Unity から使用するための仕組みです。 ## ドキュメント ドキュメントは にて提供しています。 ## ライセンス Sora Unity SDK は [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) で公開しています。 ## サンプル [shiguredo/sora-unity-sdk-samples: WebRTC SFU Sora Unity SDK サンプル集](https://github.com/shiguredo/sora-unity-sdk-samples) ## サポートについて Sora Unity SDK に関する質問・要望・バグなどの報告は Discord の利用をお願いします。 Sora のライセンス契約の有無に関わらず、応答時間と問題の解決を保証しませんのでご了承ください。 ただし、明らかなバグに関しては優先的に対応させていただきます。 Sora Unity SDK に対する有償のサポートについては提供しておりません。 ## Discord **URL**: Discord にてコミュニティを運営しています。 なにか質問したい場合は Discord サーバーへ参加してください。 Sora Unity SDK のチャンネルは `#sora-unity-sdk` です。 # Sora C++ SDK ## 概要 **URL**: Sora C++ SDK は Sora を C++ から使用するための仕組みです。 ## 特徴 - Windows / macOS / Linux / iOS / Android といったプラットフォームに対応しています - それぞれのプラットフォーム向けのハードウェアエンコーダー / デコーダーに対応しています 詳細は [Sora C++ SDK](https://github.com/shiguredo/sora-cpp-sdk) をご確認ください。 ## サンプル - [WebRTC SFU Sora C++ SDK サンプル集](https://github.com/shiguredo/sora-cpp-sdk-samples) [Simple DirectMedia Layer (SDL)](https://github.com/libsdl-org/SDL) を利用した送受信のサンプルなどを提供しています。 ## ライセンス Sora C++ SDK は [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) で公開しています。 ## サポートについて Sora C++ SDK に関する質問・要望・バグなどの報告は Discord の利用をお願いします。 Sora のライセンス契約の有無に関わらず、応答時間と問題の解決を保証しませんのでご了承ください。 ただし、明らかなバグに関しては優先的に対応させていただきます。 Sora C++ SDK に対する有償のサポートについては提供しておりません。 ## Discord **URL**: Discord にてコミュニティを運営しています。 なにか質問したい場合は Discord サーバーへ参加してください。 Sora C++ SDK のチャンネルは `#sora-cpp-sdk` です。 # Sora Flutter (C++) SDK ## 概要 **URL**: Sora Flutter SDK は Sora を Flutter から使用するための仕組みです。 ## ドキュメント ドキュメントは にて提供しています。 ## ライセンス Sora Flutter SDK は [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) で公開しています。 ## サポートについて Sora Flutter SDK に関する質問・要望・バグなどの報告は Discord の利用をお願いします。 Sora のライセンス契約の有無に関わらず、応答時間と問題の解決を保証しませんのでご了承ください。 ただし、明らかなバグに関しては優先的に対応させていただきます。 Sora Flutter SDK に対する有償のサポートについては提供しておりません。 ## Discord **URL**: Discord にてコミュニティを運営しています。 なにか質問したい場合は Discord サーバーへ参加してください。 Sora iOS SDK のチャンネルは `#sora-flutter-sdk` です。 # WebRTC 負荷試験ツール Zakuro ## 概要 [shiguredo/zakuro: WebRTC Load Testing Tool Zakuro](https://github.com/shiguredo/zakuro) WebRTC は、要求するビットレートや利用するネットワーク、送信者の数、受信者の数によって負荷が変わります。 弊社では、 Sora のサーバーサイジング向けに Sora 専用の WebRTC 負荷試験ツールを公開しています。 ## ライセンス Zakuro は [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) で公開しています。 ## サポートについて Zakuro のサポートやアドバイスは提供していません。 ## Discord **URL**: Discord にてコミュニティを運営しています。 なにか質問したい場合は Discord サーバーへ参加してください。 Zakuro のチャンネルは `#zakuro` です。 # WebRTC 録画合成ツール Hisui ## 概要 [shiguredo/hisui: Recording Composition Tool Hisui](https://github.com/shiguredo/hisui) Sora が生成する録画ファイルを合成するツールを公開しています。 ## ライセンス Hisui は [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) で公開しています。 ## サポートについて Hisui のサポートやアドバイスは提供していません。 ## Discord **URL**: Discord にてコミュニティを運営しています。 なにか質問したい場合は Discord サーバーへ参加してください。 Hisui のチャンネルは `#hisui` です。 # WebRTC 統計コレクター Kohaku ## 概要 [shiguredo/kohaku: WebRTC Stats Collector Kohaku](https://github.com/shiguredo/kohaku) WebRTC クライアントの統計情報を収集することで様々な問題を解決しやすくなります。 弊社では、 Sora 経由でクライアントの統計情報を取得可能にする WebRTC 統計コレクターを公開しています。 ## ライセンス Kohaku は [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) で公開しています。 ## サポートについて Kohaku のサポートやアドバイスは提供していません。 ## Discord Discord にてコミュニティを運営しています。 なにか質問したい場合は Discord サーバーへ参加してください。 Kohaku のチャンネルは `#kohaku` です。 # 音声ストリーミングゲートウェイ Suzu ## 概要 [shiguredo/suzu: Audio Streaming Gateway Suzu](https://github.com/shiguredo/suzu) Sora が出力音声ストリーミングを音声解析サービスに転送するツールを公開しています。 ## ライセンス Suzu は [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) で公開しています。 ## サポートについて Suzu のサポートやアドバイスは提供していません。 ## Discord Discord にてコミュニティを運営しています。 なにか質問したい場合は Discord サーバーへ参加してください。 Suzu のチャンネルは `#suzu` です。 # Sora exporter ## 概要 [shiguredo/sora_exporter: Prometheus exporter for WebRTC SFU Sora metrics.](https://github.com/shiguredo/sora_exporter) Sora exporter は Sora の GetStatsReport API を Prometheus 形式に変換してくれる prometheus エージェントです。 ## ライセンス Sora exporter は [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) で公開しています。 ## サポートについて Sora exporter のサポートやアドバイスは提供していません。 ## Discord **URL**: Discord にてコミュニティを運営しています。 なにか質問したい場合は Discord サーバーへ参加してください。 Sora exporter のチャンネルは `#sora_exporter` です。 # Media Processors ## 概要 [shiguredo/media-processors: Media Processors](https://github.com/shiguredo/media-processors) 仮想背景やノイズ抑制といったメディア処理をブラウザで簡単に行えるようにするためのライブラリです。 ## ライセンス Media Processors は [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) で公開しています。 ## サポートについて Media Processors のサポートやアドバイスは提供していません。 ## Discord **URL**: Discord にてコミュニティを運営しています。 なにか質問したい場合は Discord サーバーへ参加してください。 Media Processors のチャンネルは `#media-processors` です。 # libwebrtc 音声処理 > **注意** > > この資料の正確性を保証しません。 > **重要** > > この資料についての問い合わせは Sora のサポート範囲には含まれません。 この資料は [libwebrtc M99 (4844)](https://webrtc.googlesource.com/src.git/+log/refs/branch-heads/4844) 時点の資料です。 ## libwebrtcでの音声処理全般(前提知識) ### ソースコード - 音声処理関連は [webrtc/modules/audio_processing/](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing) 以下にまとまっている ### 音声フレーム - 音声フレームは [AudioBuffer](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/audio_buffer.h) クラスに格納されて渡ってくる - サンプリングレートは 16khz or 32kHz or 48kHz のいずれか - 1 フレームには 10ms 分のサンプルが格納されている:- 16kHz なら 160 個 - 32kHz なら 320 個 - 48kHz なら 480 個 - 基本的には、 [AudioBuffer::SplitIntoFrequencyBands()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/audio_buffer.h;l=123) を使ってフレームを周波数帯域毎のバンドに分割した上で、各バンドに対して音声処理が適用される- 何分割されるかは、サンプリングレートによって変わり、ひとつのバンド内のサンプル数は 160 になるようになっている - つまり、- 16kHz なら一分割 (分割なし) - 32kHz なら二分割 (low, high) - 48kHz なら三分割 (low, middle, high) - 処理適用後は、 [AudioBuffer::MergeFrequencyBands()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/audio_buffer.h;l=126;bpv=0;bpt=1g) で全てのバンドが結合され、通常の音声フレームの形式に戻される ### 音声フレームの処理タイミング - 音声処理の対象となる音声フレームは [audio_processing_impl.cc](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/audio_processing_impl.cc) の中で処理されることになる - 各音声フレームの処理タイミングには、音声ストリームの「入口」と「出口」の 2 つがある- 前者の場合には [AudioProcessingImpl::ProcessCaptureStreamLocked()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/audio_processing_impl.cc;l=1051;bpv=0;bpt=0) 内で処理が適用される- 大半の音声処理はここで実行される - 後者の場合には [AudioProcessingImpl::ProcessRenderStreamLocked()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/audio_processing_impl.cc;l=1483;bpv=0;bpt=0) 内で処理が適用される- ほとんどの音声処理は、こちら側では何も行わない - エコーキャンセルでは「実際に出力される音声フレームのバッファリング」といった軽い処理が実施される - なお、これはローカルストリームについての話であり、 WebRTC のようにネットワークを跨いだストリームの「入口(送信側)」と「出口(受信側)」の話とは独立している> - libwebrtc の音声処理の API としては送信側ストリームと受信側ストリームのどちらにも適用可能 > - ただし、このドキュメントで扱うような処理は、一般に、送信側ストリームに適用されることが多い ### 各音声処理の適用順序 音声処理な主な適用箇所となる [AudioProcessingImpl::ProcessCaptureStreamLocked()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/audio_processing_impl.cc;l=1051;bpv=0;bpt=0) メソッド内での、各音声処理の適用順序を記載する。 なお、実際に音声データの更新まで行われる場合には `[処理]` 、(原則として)データ収集のみの場合には `[分析]` と記載としている。 また、それぞれの音声処理は、設定や構成によってスキップされることがある。 適用順序: 1. **[処理]** ハイパスフィルタ(設定次第で後ろの箇所に移動) 2. **[処理]** 前回の AGC の結果を受けての、入力音声データの音量レベル調整 3. [分析] エコーキャンセル 4. [分析] AGC マネージャ 5. **[処理]** バンド分割 6. **[処理]** ハイパスフィルタ 7. [分析] AGC 8. **[処理]** エコーキャンセル 9. [分析] ノイズ抑制 10. **[処理]** ノイズ抑制 11. **[処理]** モバイル版エコーキャンセル 12. **[処理]** AGC マネージャ 13. **[処理]** AGC 14. **[処理]** バンド統合 15. **[処理]** トランジェント抑制 ※ コメントで「AGC の前後のどちらが良いのかは要調査」との記載がある 16. **[処理]** AGC2 以下では、具体的な例として Chromium での Android および iOS の場合に適用される処理と、その順序を記載する。 ソースコードとしては [media/webrtc/helpers.cc](https://source.chromium.org/chromium/chromium/src/+/main:media/webrtc/helpers.cc) の `CreateWebRtcAudioProcessingModule()` および `ConfigAutomaticGainControl()` 関数でこれらの構成が決定されている。 なお、ハイパスフィルタやノイズ抑制、エコーキャンセル、AGC の有効・無効はユーザが利用時に指定できるが、それらは全て有効になっているものとする。 また、実験的なフィールドトライアルの機能は全て無効になっているものとする。 #### Android の場合の適用順序 1. **[処理]** ハイパスフィルタ 2. **[処理]** バンド分割 3. [分析] AGC 4. [分析] ノイズ抑制 5. **[処理]** ノイズ抑制 6. **[処理]** モバイル版エコーキャンセル 7. **[処理]** AGC 8. **[処理]** バンド統合 なお AGC のモードは kFixedDigital となっている(モードの意味については AGC の節を参照)。 #### iOS の場合の適用順序 1. **[処理]** ハイパスフィルタ 2. [分析] エコーキャンセル 3. **[処理]** バンド分割 4. [分析] AGC 5. **[処理]** エコーキャンセル 6. [分析] ノイズ抑制- 入力音声データ( `capture_buffer` )ではなく、 エコーキャンセル処理の結果得られた `liear_aec_buffer` を分析対象とする 7. **[処理]** ノイズ抑制 8. **[処理]** AGC 9. **[処理]** バンド統合 なお AGC のモードは kAdaptiveAnalog となっている。 ## ハイパスフィルタ 音声の低周波成分をカットする処理 ### 概要 - [HighPassFiler::Process()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/high_pass_filter.h;l=31;bpv=0;bpt=1) によって行われる - アルゴリズムは [BiQuadFilter](https://en.wikipedia.org/wiki/Digital_biquad_filter) (双2次フィルタ) の "Direct form 1" - 計算量としては「各音声フレーム内の各サンプルを走査して、数回の算術演算(加算と乗算)を適用する」という極めて軽いもの ### 補足 - 音声フレームの各チャネルは独立して処理される - [HighPassFiler::Process()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/high_pass_filter.h;l=31;bpv=0;bpt=1) に渡すフラグによって「音声フレーム全体」ないし「一番下のバンドだけ」に処理が適用されるかどうかが切り替わる- デフォルトはおそらく前者 - 後者の場合には、周波数成分の高いバンドへの処理はスキップされて、オリジナルのデータがそのまま使われる(ハイパスなのでこれでも問題はない) - フィルタの実装は [CascadedBiQuadFilter](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/utility/cascaded_biquad_filter.h;bpv=0;bpt=1) クラス- "Cascaded"とあるようにフィルタを複数回適用できるようなインタフェースになっているけれど、今回の用途では、各音声フレームの各チャネルに対して、常に 1 回だけ適用される - フィルタの係数は [high_pass_filter.cc#21](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/high_pass_filter.cc;bpv=0;bpt=1) で定義されている - フィルタのイメージとしては [双2次フィルタ (Biquad Filter) の周波数特性(振幅・位相)の一覧](https://www.wizard-notes.com/entry/music-analysis/biquad-filter-frequency-responses) の記事も参考になる ## ノイズ抑制 音声フレーム内の雑音を抑制するための処理 主に定常的な雑音に対して効果を発揮する ### 概要 - [NoiseSuppressor::Analyze()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/ns/noise_suppressor.h;l=39;bpv=0;bpt=0) および [NoiseSuppressor::Process()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/ns/noise_suppressor.h;l=42;bpv=0;bpt=0) によってノイズ抑制が行われる - `Analyze` と `Process` が分かれているのは、他の音声処理(e.g., エコーキャンセル)の影響を受けずに、ノイズ抑制用に必要な情報の収集を行えるようにするため #### [NoiseSuppressor::Analyze()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/ns/noise_suppressor.h;l=39;bpv=0;bpt=0) での処理: - ここでは **音声フレーム中に含まれるノイズ(スペクトル)の分析** が行われる - ノイズスペクトルの判定には [NoiseEstimator](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/ns/noise_estimator.h;bpv=0;bpt=0) クラスが使用される- アルゴリズムは "quantile noise estimation"- ざっくりと言えば「ある時間範囲内の音声フレームのスペクトルを、各周波数成分単位でソートして、そのquantile (e.g, 50%タイル)以下のものをノイズと判定する」というもの - 対象とするノイズが「定常的なもの」であるという仮定があるので、突発的に発生したような雑音は苦手 - libwebrtcでの実装と完全に一致している訳ではないが ["Quantile based noise estimation for spectral subtraction and Wiener filtering"](https://ieeexplore.ieee.org/abstract/document/862122/) の論文が参考になる - また、 [NoiseEstimator](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/ns/noise_estimator.h;bpv=0;bpt=0) の結果のノイズスペクトルは「スペクトルの各周波数成分のスピーチ確率」によって調整される- ざっくりと言えば「ある周波数成分にスピーチ(人の声)が含まれている確率が高い場合には、前回音声フレームのノイズ推定結果を重視し、そうではない場合は今回のものを重視する」といった重み付けが行われる- [NoiseEstimator::PostUpdate()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/ns/noise_estimator.cc;l=149;bpv=0;bpt=0) - スピーチ確率の推定は [SpeechProbabilityEstimator](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/ns/speech_probability_estimator.h;bpv=0;bpt=0) クラスによって行われる- その際には、まず音声フレームのスペクトルやS/N比を入力としてシグナルモデル ( [SignalModel](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/ns/signal_model.h;bpv=0;bpt=0) ) を構築する - その後、そのモデルに含まれる各特徴量 (e.g., `spectral_flatness`, `lrt` (likelihood ratio test)) を使って、スペクトル内の角周波数成分のスピーチ確率が算出される - 用語としては ["Features for voice activity detection: a comparative analysis"](https://link.springer.com/article/10.1186/s13634-015-0277-z) の記事などが参考となる #### [NoiseSuppressor::Process()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/ns/noise_suppressor.h;l=42;bpv=0;bpt=0) での処理: - ここでは `Analyze` で得られたノイズスペクトルを使って **ノイズを除去するためのフィルタの構築およびその適用** が実施される - フィルタには [Wiener filter (Wikipedia)](https://en.wikipedia.org/wiki/Wiener_filter) が使用される ([WienerFilter](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/ns/wiener_filter.h;bpv=0;bpt=0) クラス) - その他細々とした色々な処理が行われているけれど、それらについては後続の「補足」を参照のこと #### 計算量 - FFT(およびその逆変換)が 2 回適用されている- `O(N log N)`- `N` は 256 - ノイズ抑制の際には「現在の音声フレーム(バンド単位で160サンプル)」の前方に「前回の音声フレームの末尾部分(96サンプル)」を結合した上で処理が行われるため、 `N` の値はその合算となる - `Analyze` と `Process` のそれぞれで音声フレームはスペクトルに変換して処理されるので、その前後で FFT (とその逆変換)が走る - また、音声フレーム全体を走査するような O(N) の処理が十数回程度実施されている(回数はあくまでも感覚値) #### ノイズ抑制によって発生する(理論上の)遅延 - 6ms - [NoiseSuppressor::Process()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/ns/noise_suppressor.h;l=42;bpv=0;bpt=0) では、入力音声フレーム内の 4/10 のデータだけが出力フレームに反映されて、残りは次回の処理時まで遅らせられる- 上述の通り音声フレームの長さは 10 ms で、その内の 6/10 の出力が次回まで遅らせられるので 6 ms と遅延となる - 一部データの出力を遅らせているのは、おそらくフレームの繋ぎ目部分の音声をスムーズにするため- `Analyze` の際にも「前回の入力フレームの末尾(遅延)部分」と「今回の入力フレーム」を結合した上で分析が行われる ### 補足 #### マルチチャネルの扱い - [NoiseSuppressor::Analyze()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/ns/noise_suppressor.h;l=39;bpv=0;bpt=0) では、各チャネルが独立に処理される - [NoiseSuppressor::Process()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/ns/noise_suppressor.h;l=42;bpv=0;bpt=0) では、各チャネルのフィルタの値(ゲイン)が集約される- [NoiseSuppressor::AggregateWienerFilters()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/ns/noise_suppressor.cc;l=272;bpv=0;bpt=0) - やっていることとしては、各周波数成分について、チャネル間で一番小さなフィルタの値を採用しているだけ #### マルチバンドの扱い - [音声フレーム](LIBWEBRTC_AUDIO.html#de9618) で触れたように、入力音声フレームのサンプリングレートが 32 kHz 以上の場合は、フレームが周波数帯域(バンド)によって分割されて、バンド単位で処理されることになる - [NoiseSuppressor::Analyze()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/ns/noise_suppressor.h;l=39;bpv=0;bpt=0) では、一番低帯域のバンドのみを使って分析が行われる - [NoiseSuppressor::Process()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/ns/noise_suppressor.h;l=42;bpv=0;bpt=0) では、一番低帯域のバンドのみにノイズ抑制処理が適用される- それよりも大きなバンドについては、ノイズ抑制は行わずに、ローバンドの抑制結果に応じた、全体の音量調整のみを実施する - コード的には `upper_band_gain` というスカラ値 ( `float` )を、音声フレームに対してひとつ算出し、それをフレーム内の各サンプルに乗算している- [noise_suppressor.cc#519](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/ns/noise_suppressor.cc;l=519;bpv=0;bpt=0) #### FFT用の窓関数 - ハニングとフラットのハイブリッドが使用される- [ApplyFilterBankWindow()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/ns/noise_suppressor.cc;l=72;bpv=0;bpt=0) #### 処理のスキップ - 音声フレームのローバンドが、値が `0` のサンプルしか含んでいない場合には [NoiseSuppressor::Analyze()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/ns/noise_suppressor.h;l=39;bpv=0;bpt=0) でのノイズスペクトルの分析および更新はスキップされる- このケース(無音)で各種統計値を更新してしまうと、無音ではなくなった後のしばらくは、音声データの全てが「スピーチ(ノイズ無し)」と判定されてしまうため - 音声フレームが実際に使われることがない場合( `capture_output_used_ == false` )は、 [NoiseSuppressor::Process()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/ns/noise_suppressor.h;l=42;bpv=0;bpt=0) はフィルタの更新はするが、適用は行わない- フィルタの情報は、 [NoiseSuppressor::Analyze()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/ns/noise_suppressor.h;l=39;bpv=0;bpt=0) 呼び出しでも参照されているので、フィルタ更新までは必要 #### 各種オプション - libwebrtcには `noise_suppression.level` というオプションがあり、それによってノイズ抑制時の各処理で使用されるパラメータが変化する - 値は `kLow` or `kModerate` or `kHigh` or `kVeryHigh` - 詳細は、以下のメソッドを参照のこと- [AudioProcessingImpl::InitializeNoiseSuppressor()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/audio_processing_impl.cc;l=1942;bpv=0;bpt=0) - [SuppressionParams::SuppressionParams()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/ns/suppression_params.cc;l=19;bpv=0;bpt=0) ## モバイル版エコーキャンセル モバイル端末向けの軽量なエコーキャンセル処理 コード中では "AECM (acoustic echo control for mobile)" と呼称されている ### 概要 - AECM では、音声データの **入力時(capture)** と **出力時(render)** のそれぞれで処理が実行される- 用語としては「入力側(の音声フレーム)は **nearend** 」、「出力側(の音声フレーム)は **farend** 」と呼ばれる - 全体の流れとしては、以下のようになる:1. [出力時] 実際に出力される音声フレームをバッファ(履歴)に保持しておく 2. [入力時] 入力音声フレーム内のエコー部分に対応する出力済み音声フレームを特定する(遅延推定) 3. [入力時] 上の遅延情報を用いて、エコー除去フィルタを適用する(ざっくりと言えば、入力音声から、対応する過去の出力音声成分を引く) - AECM 向けのAPIを提供しているのは [EchoControlMobileImpl](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/echo_control_mobile_impl.h;bpv=0;bpt=0) クラス- 内部的には [echo_control_mobile.h](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/aecm/echo_control_mobile.h;bpv=0;bpt=0) および [aecm_core.h](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/aecm/aecm_core.h;bpv=0;bpt=0) に存在する `WebRtcAecm_*` 関数群によって、実際の処理が実装されている #### 音声出力時の処理 ([AudioProcessingImpl::ProcessRenderStreamLocked()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/audio_processing_impl.cc;l=1483;bpv=0;bpt=0)) 基本的には「実際に出力される音声フレームのコピーを、後続の入力時処理の際に参照できるようにバッファに保存」しているだけとなる 主な登場人物は、以下の 2 つ: - [EchoControlMobileImpl::PackRenderAudioBuffer()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/echo_control_mobile_impl.h;l=62;bpv=0;bpt=0) 関数- 出力音声フレームを [AudioProcessingImpl](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/audio_processing_impl.h;bpv=0;bpt=0) クラスが管理している一時バッファに書き込む - **モノラルチャネル** かつ **サンプリングレートが 16 kHz** の場合には、単純なデータコピーとなる - **マルチチャネル** あるいは **マルチバンド (サンプリングレートが 16 kHz 以上)** の場合には、プラスアルファの処理が加わるので [補足](LIBWEBRTC_AUDIO.html#934b1d) の節を参照のこと - [EchoControlMobileImpl::ProcessRenderAudio()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/echo_control_mobile_impl.h;l=55;bpv=0;bpt=0) メソッド- [EchoControlMobileImpl](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/echo_control_mobile_impl.h;bpv=0;bpt=0) が管理するリングバッファに [EchoControlMobileImpl::PackRenderAudioBuffer()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/echo_control_mobile_impl.h;l=62;bpv=0;bpt=0) の結果を書き込むだけ #### 音声入力時の処理 ([AudioProcessingImpl::ProcessCaptureStreamLocked()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/audio_processing_impl.cc;l=1051;bpv=0;bpt=0)) 関数の呼び出し階層としては、以下のようになっている: ``` - EchoControlMobileImpl::ProcessCaptureAudio() # AudioProcessingImpl::ProcessCaptureStreamLocked()から呼び出されるメソッド - WebRtcAecm_Process() - WebRtcAecm_EstBufDelay() # ここで推定した遅延情報はデバッグ用途でしか使用されていない - WebRtcAecm_ProcessFrame() - WebRtcAecm_BufferFarFrame() - WebRtcAecm_FetchFarFrame() - WebRtcAecm_ProcessBlock() # 主要な処理はこの関数内で実施される - WebRtcAecm_UpdateFarHistory() - WebRtc_AddFarSpectrumFix() - WebRtc_DelayEstimatorProcessFix() - WebRtcAecm_AlignedFarend() - WebRtcAecm_CalcEnergies() - WebRtcAecm_CalcStepSize() - WebRtcAecm_UpdateChannel() - WebRtcAecm_CalcSuppressionGain() - ComfortNoise() ``` 重要なのは [WebRtcAecm_ProcessBlock()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/aecm/aecm_core_c.cc;l=372;bpv=0;bpt=0) で、それより上の関数群は、基本的にはバッファ管理しか行っていないので、今回はあまり気にする必要はない。 [WebRtcAecm_ProcessBlock()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/aecm/aecm_core_c.cc;l=372;bpv=0;bpt=0) 関数のシグネチャは次の通り: ```c int WebRtcAecm_ProcessBlock(AecmCore* aecm, // farend の音声フレーム (64 サンプル) const int16_t* farend, // nearend の音声フレーム (64 サンプル) const int16_t* nearendNoisy, // nearendNoisy から雑音を除いたもの // 今回の用途では常に NULL になるので無視して良い const int16_t* nearendClean, // nearendNoisy に対してエコーキャンセルを適用した結果の格納先 // 今回の用途では nearendNoisy と同じポインタが使用される int16_t* output) ``` [WebRtcAecm_ProcessBlock()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/aecm/aecm_core_c.cc;l=372;bpv=0;bpt=0) 関数の処理の大まかな流れは以下の通り: 1. `farend` 引数および `nearendNoisy` 引数に FFT を適用して周波数スペクトルに変換する ( [TimeTofrequencyDomain()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/aecm/aecm_core_c.cc;l=264;bpv=0;bpt=0) ) 2. `farend` 引数の周波数スペクトルを `aecm` 引数が管理している履歴 (リングバッファ) に追記する ( [WebRtcAecm_UpdateFarHistory()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/aecm/aecm_core.cc;l=135;bpv=0;bpt=0) ) 3. 上の履歴と `nearendNoisy` 引数の周波数スペクトルを照会して、出力音声(エコー)が入力音声に含まれるまでの遅延を推定する- [WebRtc_AddFarSpectrumFix()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/utility/delay_estimator_wrapper.cc;l=203) および [WebRtc_DelayEstimatorProcessFix()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/utility/delay_estimator_wrapper.cc;l=417) - この部分の詳細は [遅延推定](LIBWEBRTC_AUDIO.html#81eb3a) を参照 4. 推定遅延に対応する出力音声フレーム(スペクトル)を取得する ( [WebRtc_AlignedFarend()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/aecm/aecm_core.cc;l=167;bpv=0;bpt=0) )- これによって、**現在の入力音声フレーム** と **そのエコー成分に対応する出力音声フレーム** が得られたので、以後の処理ではこの 2 つのフレーム(のスペクトル)が使用される 5. エコーキャンセル用のフィルタ構築の前段として `aecm` が管理しているエコー音声チャネルを更新する- チャネル更新には NLMS というアルゴリズムを使用 ( Wikipedia: [Normalizecd least squares filter (NLMS)](https://en.wikipedia.org/wiki/Least_mean_squares_filter#Normalized_least_mean_squares_filter_(NLMS)) ) - 関連する関数は [WebRtcAecm_CalcEnergies()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/aecm/aecm_core.cc;l=654;bpv=0;bpt=0) と [WebRtcAecm_CalcStepSize()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/aecm/aecm_core.cc;l=777;bpv=0;bpt=0) 、 [WebRtcAecm_UpdateChannel()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/aecm/aecm_core.cc;l=820;bpv=0;bpt=0) - この部分の詳細は [チャネル更新](LIBWEBRTC_AUDIO.html#10dc7b) を参照 6. 入力音声フレーム(スペクトル)にフィルタを適用して、エコー部分を除去する> - フィルタには [Wiener filter (Wikipedia)](https://en.wikipedia.org/wiki/Wiener_filter) を使用 > - 基本的には「入力フレームから、ひとつ上で求めたエコーチャネル成分を除去する」イメージ > - フィルタの強弱を調整するために [WebRtcAecm_CalcSuppressionGain()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/aecm/aecm_core.cc;l=1011;bpv=0;bpt=0) でゲイン値(重み)が計算される- 入力とエコーのエナジーの差分をもとに、無音、ダブルトーク、等の簡易的な状況判定を行い、それに応じてゲイン値を決定 > - NLP (non-linear processor) でフィルタの値がさらに調整される- 外れ値の処理(大き過ぎる or 小さ過ぎるフィルタの値を 1 or 0 に丸める)等がここで行われる 7. コンフォートノイズを生成( [ComfortNoise()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/aecm/aecm_core_c.cc;l=61;bpv=0;bpt=0) )> - オプショナルで、入力音声フレームにコンフォートノイズ(背景ノイズ)を生成する > - デフォルトは無効 > - ノイズキャンセルの他の箇所の処理とはほぼ独立している 8. 処理適用後の入力音声フレーム(スペクトル)に逆FFTを適用して、時間波形に戻す #### 遅延推定 出力音声が入力音声に含まれるまでの遅延の推定は [WebRtc_AddFarSpectrumFix()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/utility/delay_estimator_wrapper.cc;l=203) および [WebRtc_DelayEstimatorProcessFix()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/utility/delay_estimator_wrapper.cc;l=417) で行われている: - [WebRtc_AddFarSpectrumFix()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/utility/delay_estimator_wrapper.cc;l=203): 出力音声フレーム (farend) の形式変換と履歴への追加1. `uint16_t[64]` の形式で保持されている現在の出力音声フレーム(スペクトル)の中央部分を取り出して `uint32_t` (32 要素のビット配列)に変換する- 各周波数成分のこれまでの平均値を別途保持しており、それに比べて大きいなら 1 、小さいなら 0 となる 2. 上のビット配列を、履歴配列の先頭に挿入する- 配列の要素数は 100 で、各要素は時系列順に並んでいる - 履歴配列の位置(インデックス)が遅延値に対応する(i.e., 先頭なら遅延なしで、末尾なら 400 ms 程度) - [WebRtc_DelayEstimatorProcessFix()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/utility/delay_estimator_wrapper.cc;l=417): 遅延推定1. 現在の入力音声フレーム(スペクトル)を、上と同様の方法で `uint32_t` に変換する 2. **nearendの変換後のビット配列** と **farendの履歴の各要素** の一致度を計測する- イメージ的には `bitcount(nearend xor history[i])` といった処理で、値が小さいほど、より一致度が高いことを示す 3. 別途管理している **履歴の各位置(= 遅延)での一致度の平均** を更新する 4. 一致度の平均が最も高い位置を遅延のベスト候補とする 5. その候補を採用可能な条件が揃っている場合には、その遅延値を採用し、そうではない場合には前回の遅延値を使用する- e.g., ベスト候補とワースト候補の差が小さい場合には、不安定な状況だと判断して見送る - 条件の詳細については [WebRtc_ProcessBinarySpectrum()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/utility/delay_estimator.cc;l=525) のコードを参照のこと #### チャネル更新 チャネル更新は [WebRtcAecm_UpdateChannel()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/aecm/aecm_core.cc;l=820;bpv=0;bpt=0) および、その前段の [WebRtcAecm_CalcEnergies()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/aecm/aecm_core.cc;l=654;bpv=0;bpt=0) と [WebRtcAecm_CalcStepSize()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/aecm/aecm_core.cc;l=777;bpv=0;bpt=0) によって実施される これらの関数によって `AecmCore` 構造体が管理しているエコー音声用のチャネル情報が更新される 1. まずは、出力音声フレームのVADレベル(フラグ)を推定し、もしこれが 0 (エナジーが低く無音に近い) なら後続の処理はスキップする ( [WebRtcAecm_CalcEnergies()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/aecm/aecm_core.cc;l=654;bpv=0;bpt=0) ) 2. 次に [WebRtcAecm_CalcStepSize()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/aecm/aecm_core.cc;l=777;bpv=0;bpt=0) で、 NLMS のステップサイズパラメータである `mu` を計算する 3. 最後は [WebRtcAecm_UpdateChannel()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/aecm/aecm_core.cc;l=820;bpv=0;bpt=0) で、 NLMS を使ってエコーチャネルを更新する > - `AecmCore` は、毎フレームで更新される `channelAdapt` と、それよりは安定した `channelStored` をフィールドとして保持している- これらは出力音声フレーム(スペクトル)からエコー音声フレーム(スペクトル)を算出するための重み配列のようなもの (イメージとしては `nearend_echo[i] = farend[i] * channelXXX[i]`) > - 入出力フレーム(スペクトル) の情報を使って、 `channelAdapt` を更新 > - 十分なエナジーのフレームが一定数 (20個) 続いたら、 `channelAdapt` で `channelStored` の置換を試みる- `channelAdapt` と `channelStored` のそれぞれを用いて計算した「エコー音声フレームのエナジー」と「対応する入力音声フレームのエナジー」の差分(絶対値)を求める > - その差分の20フレーム分の合計値が `channelAdapt` を使った場合の方が小さければ、より適切なものだと判断して `channelStored` を置換する (逆の場合には `channelAdapt` が置換される) > - 後続の処理では `channelStored` の値が使用される #### バッファリングによる遅延 - 呼び出し階層の上と下で対象とする音声フレームのサンプル数は異なっている- 上の方( [EchoControlMobileImpl::ProcessCaptureAudio()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/echo_control_mobile_impl.h;l=56;bpv=0;bpt=0) )では 160 サンプル(10ms分) - 下の方( [WebRtcAecm_ProcessBlock()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/aecm/aecm_core_c.cc;l=372;bpv=0;bpt=0) )では 64 サンプル - そのため入力音声フレームは、まずリングバッファに追記され、 [WebRtcAecm_ProcessBlock()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/aecm/aecm_core_c.cc;l=372;bpv=0;bpt=0) 呼び出しの際には、そこから 64 サンプルずつ取り出されて処理されることになる - その際にキリが悪かったサンプル群は次回の入力音声処理時に持ち越されることになるので、 32 サンプル分(2ms分)の遅延が発生する #### 計算量特性 典型的には、一つの音声フレームを処理する際には、以下の関数群が1回ずつ呼び出されることになる: - [EchoControlMobileImpl::PackRenderAudioBuffer()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/echo_control_mobile_impl.h;l=62;bpv=0;bpt=0) - [EchoControlMobileImpl::ProcessRenderAudio()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/echo_control_mobile_impl.h;l=55;bpv=0;bpt=0) - [EchoControlMobileImpl::ProcessCaptureAudio()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/echo_control_mobile_impl.h;l=56;bpv=0;bpt=0) それぞれに対して、以下の処理が、チャネル数の二乗分だけ繰り返されることになる( [マルチチャネルの扱い](LIBWEBRTC_AUDIO.html#af2d71) ): - [EchoControlMobileImpl::PackRenderAudioBuffer()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/echo_control_mobile_impl.h;l=62;bpv=0;bpt=0) および [EchoControlMobileImpl::ProcessRenderAudio()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/echo_control_mobile_impl.h;l=55;bpv=0;bpt=0)- 一フレーム分のメモリコピー - [EchoControlMobileImpl::ProcessCaptureAudio()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/echo_control_mobile_impl.h;l=56;bpv=0;bpt=0)- 一フレーム分の FFT と 逆FFT - フレーム単位のメモリコピーやループを十数回~数十回 注意: 一フレームに含まれる具体的なサンプル数は、関数によって 160 あるいは 64 と変動するが、ここでは簡単のためにそれらの違いは考慮しないものとする ### 補足 #### マルチチャネルの扱い - 各チャネルは、一番下のレイヤー( [WebRtcAecm_ProcessBlock()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/aecm/aecm_core_c.cc;l=372;bpv=0;bpt=0) )では独立して処理される - 上のレイヤー( [EchoControlMobileImpl::ProcessCaptureAudio()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/echo_control_mobile_impl.h;l=56;bpv=0;bpt=0) )では、以下のような処理される- **入力音声フレームのチャネル数** の他に、 **出力音声フレームのチャネル数** の概念がある- 後者はソースコード中では `reverse_channel` と呼称されている - `EchoControlMobileImpl` クラスの初期化時には、 [WebRtcAecm_ProcessBlock()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/aecm/aecm_core_c.cc;l=372;bpv=0;bpt=0) に渡される `Aecm` 構造値インスタンスは `入力音声フレームチャネル数 * 出力音声フレームチャネル数` 個だけ生成される(おそらく典型的にはチャネル数の二乗となる) - 入力音声フレームの各チャネルの処理は、イメージとしては次のようになる( [EchoControlMobileImpl::ProcessCaptureAudio()#L173](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/echo_control_mobile_impl.cc;l=173;bpv=0;bpt=0) )1. 入力音声フレームから該当チャネル部分のデータを取得する (nearend) 2. 出力音声フレームの各チャネルデータ(farend)に対して for ループを回す( [EchoControlMobileImpl::ProcessCaptureAudio()#L198](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/echo_control_mobile_impl.cc;l=198;bpv=0;bpt=0) )- nearend と farend を引数として `WebRtcAecm_Process()` 経由で [WebRtcAecm_ProcessBlock()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/aecm/aecm_core_c.cc;l=372;bpv=0;bpt=0) を呼び出す - 次のイテレーションに進む前に nearend のデータは、ノイズキャンセル結果で置換される - つまりざっくりと言えば、チャネル数に対する二重ループを回して、各入力チャネルから各出力チャネルのエコー成分を順々に取り除いている感じとなる #### マルチバンドの扱い - マルチバンド自体については [音声フレーム](LIBWEBRTC_AUDIO.html#de9618) を参照 - 音声フレームがマルチバンドに分割された際には、一番下のバンドのみが処理され、残りのバンドについては 0 で埋められる(ローパス)- [EchoControlMobileImpl::ProcessCaptureAudio()#L216](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/echo_control_mobile_impl.cc;l=216;bpv=0;bpt=0) #### 各種オプション - ルーティングモードの指定 ( [RoutingMode](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/echo_control_mobile_impl.h;l=37;bpv=0;bpt=0) )- `kQuietEarpieceOrHeadset`, `kEarpiece`, `kLoudEarpiece`, `kSpeakerphone`, `kLoudSpeakerphone` の中から選べる - この値によって、エコーキャンセル処理時の各種パラメータが変化する - デフォルト値は `kSpeakerphone` - NLP の ON/OFF ( [AecmCore::nlpFlag](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/aecm/aecm_core.h;l=66;bpv=0;bpt=0) 、デフォルトは有効) - コンフォートノイズの ON/OFF ( [EchoControlMobileImpl::comfort_noise_enabled_](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/echo_control_mobile_impl.h;l=77;bpv=0;bpt=0) 、デフォルトは無効) ## オートゲインコントロール(AGC) 出力音量レベルを適切な範囲内で一定に保つための処理 libwebrtc には「無印の AGC (ないし AGC1)」と「AGC2」が存在するが、ここでは前者を扱っている(後者については補足節を参照のこと) ### 概要 - libwebrtc で、入力音声フレームに AGC を適用する際の論理的な流れは、以下のようになっている:1. 適切な入力音量レベルを推定(e.g., 入力音声フレームでクリッピングが発生しているならレベルを下げる) 2. 上で求めた適切な音量レベルに基づいて、音声フレームの全体音量レベルを変更 3. 音声フレーム内での音量の均一化 - また、一番上の階層での構成要素としては、以下の 3 つのクラスが存在する:- [GainControlImpl](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/gain_control_impl.h): 上述の三つの処理の全てを担当可能なクラス(後述のモードに応じて、一部処理を他のクラスに委譲する) - [AgcManagerDirect](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/agc_manager_direct.h): 「適切な音量レベルの推定」に特化した処理を担当するクラス(オプショナル) - [CaptureLevelAdjuster](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/capture_levels_adjuster/capture_levels_adjuster.h): 「全体音量レベルの変更」に特化した処理を担当するクラス(オプショナル) - これらのクラスの使い分けは [GainControlImpl](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/gain_control_impl.h) に指定される三つのモードによって説明できる:- モードは [AudioProcessing::GainController1::Mode](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/include/audio_processing.h;l=246) 列挙型によって定義され、 `kAdaptiveAnalog` 、 `kAdaptiveDigital` 、 `kFixedDigital` のいずれかとなる - `kAdaptiveAnalog` の場合:- このモードでは「アナログ(マイク)音量が制御可能」という想定のもとでゲインコントールが行われる- "Adaptive" は「適切な音量レベル推定」と、それに応じた「全体音量レベルの変更」が行われることを示す - この場合は [GainControlImpl](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/gain_control_impl.h) が「適切な音量レベルの推定」と「フレーム内での音量均一化」の両方を実施する - [CaptureLevelAdjuster](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/capture_levels_adjuster/capture_levels_adjuster.h) が有効な場合には、 このクラスが「全体音量レベルの変更」(適切な音量レベルの反映)を行う- [CaptureLevelAdjuster](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/capture_levels_adjuster/capture_levels_adjuster.h) は、入力マイクの音量調整の挙動をエミューレートするためのクラス - [CaptureLevelAdjuster](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/capture_levels_adjuster/capture_levels_adjuster.h) が無効な場合には、入力音量レベルの調整は libwebrtc の音声処理機能の利用側の責任となる- [AudioProcessing::recommended_stream_analog_level()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/include/audio_processing.h;l=598) メソッドで、期待される音量レベルは取得可能 - `kAdaptiveDigital` の場合:- このモードでは「アナログ(マイク)音量は制御不可能」という想定のもとでゲインコントールが行われる - [GainControlImpl](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/gain_control_impl.h) の役割は、基本的には `kAdaptiveAnalog` の場合と同様だが、「全体音量レベルの変更」まで一緒に行ってしまう点が異なる- アナログ音量調整を利用側に任せることができないので、自分で入力音声フレームに手を入れて、音量調整をしてしまう - そのため [GainControlImpl](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/gain_control_impl.h) が一番多くのことを行うモードとなる - `kFixedDigital` の場合:- このモードでは [GainControlImpl](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/gain_control_impl.h) は「適切な音量レベルの推定」と「全体音量レベルの変更」に関する処理を行わなくなる- 「フレーム内での音量均一化」のみを担当 - 「適切な音量レベルの推定」に関しては、 [AgcManagerDirect](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/agc_manager_direct.h) が代わりに担当する(有効になっている場合)- [AgcManagerDirect](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/agc_manager_direct.h) と [GainControlImpl](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/gain_control_impl.h) を併用する場合は、常にこのモードとなる - 「全体音量レベルの変更」に関しては、 `kAdaptiveAnalog` の場合と同様( [CaptureLevelAdjuster](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/capture_levels_adjuster/capture_levels_adjuster.h) が有効ならそれが使用され、無効なら利用者責任) - なお列挙的のコメントを意訳すると「組み込みデバイスなどで、入力音量レベルが予測可能な(i.e., 事前に適切なゲインが判明している)場合には、全体音量レベル推定および変更処理そのものを省略可能」とのこと - 今回は簡単のために、基本的には、以下の構成を想定して説明を行うこととする:- [GainControlImpl](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/gain_control_impl.h) に指定されるモードは `kFixedDigital` - [AgcManagerDirect](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/agc_manager_direct.h) は有効 - [CaptureLevelAdjuster](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/capture_levels_adjuster/capture_levels_adjuster.h) は無効(このクラスの役割は「物理マイク音量のエミューレート」で、厳密には AGC とは独立した処理であるため) - [GainControlImpl](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/gain_control_impl.h) と [AgcManagerDirect](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/agc_manager_direct.h) は、それぞれ Analyze と Process フェーズが存在する- 前者は、他の音声処理が適用される前に実施されて、(極力)生の入力音声フレームから、各種情報が収集される - 音声フレーム処理の入り口となる [AudioProcessingImpl::ProcessCaptureStreamLocked()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/audio_processing_impl.cc;l=1051;bpv=0;bpt=0) メソッドの中では、以下の順番で適用されている:1. [AgcManagerDirect](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/agc_manager_direct.h) の Analyze ( [AgcManagerDirect::AnalyzePreProcess()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/agc_manager_direct.h;l=35) メソッド) 2. [GainControlImpl](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/gain_control_impl.h) の Analyze ( [GainControlImpl::AnalyzeCaptureAudio()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/gain_control_impl.cc;l=149) メソッド) 3. [AgcManagerDirect](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/agc_manager_direct.h) の Process ( [AgcManagerDirect::Process()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/agc_manager_direct.cc;l=653) メソッド) 4. [GainControlImpl](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/gain_control_impl.h) の Process ( [GainControlImpl::ProcessCaptureAudio()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/gain_control_impl.cc;l=196) メソッド) - 以降のサブセクションでは、上記のメソッドそれぞれの詳細について記載する #### [AgcManagerDirect](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/agc_manager_direct.h) の Analyze ( [AgcManagerDirect::AnalyzePreProcess()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/agc_manager_direct.h;l=35) メソッド) このメソッドが行なっていることは、主に以下の 2 つ: 1. 入力音声フレームのクリッピング判定- クリッピング判定 = 大音量領域での音声の欠損が発生するかどうか (c.f. [Audio Clipping (Wikipedia)](https://en.wikipedia.org/wiki/Clipping_(audio))) - クリッピングが発生する場合には、入力音量レベルを下げる必要がある- 上述の通り、実際に音量レベルを変更するのは、このクラスの呼び出し側の責務( [AgcManagerDirect](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/agc_manager_direct.h) は適切なレベルを推定するのみ) 2. 「代表チャネル」を更新する- 「代表チャネル」は、ゲインコントロールの際の基準となるチャネル - 「適切な音量レベルの推定」はチャネル毎に独立して行われるが、実際に音量調整をする際には、代表チャネルの値が使用される - 代表チャネルは [AgcManagerDirect::AnalyzePreProcess()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/agc_manager_direct.h;l=35) メソッドによって選択される- 実装的には、単純に「適切な音量レベル」が一番小さなチャネルを選択しているだけ このメソッドの大半はクリッピング関連処理に費やされている。 また、オプショナルな構成要素として [ClippingPredictor](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/clipping_predictor.h;bpv=1;bpt=1) クラスが存在する。 これが有効となっている場合には「現在のフレームにクリッピングが存在するかどうか」の判定だけでなく、 「近い将来に発生しそうかどうか」の予測まで行われるようになる。 ただし、今回は簡単のために、このクラスの詳細は割愛し、無効となっているものと想定する。 クリッピング判定処理の流れは次の通り: 1. 入力音声フレームで、値が上端ないし下端に達しているサンプルの割合を計算( [AgcManagerDirect::ComputeClippedRatio()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/agc_manager_direct.cc;l=118) )- これが規定値(デフォルトでは一割)を超えている場合には「クリッピング有り」と判定される 2. 「クリッピング有り」判定、かつ、前回の判定から一定時間(デフォルトでは 3 秒)経過している場合には、以下を実施する:> - 各チャネルに対して [MonoAgc::HandleClipping()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/agc_manager_direct.cc;l=225;bpv=1;bpt=1) を呼び出す > - [MonoAgc](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/agc_manager_direct.h;l=156;bpv=1;bpt=1) は、各チャネルに対して独立に「適切な音量レベルの推定」処理を適用するためのクラス > - [MonoAgc::HandleClipping()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/agc_manager_direct.cc;l=225;bpv=1;bpt=1) の中では(ざっくり言えば)推定適切音量レベルの定数分の減少が行われる #### [GainControlImpl](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/gain_control_impl.h) の Analyze ( [GainControlImpl::AnalyzeCaptureAudio()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/gain_control_impl.cc;l=149) メソッド) このメソッドの中では主に、以下が実施される: - 入力音声フレームのエナジーなどの統計情報の取得(モードが `kFixedDigital` 以外の場合)- 取得した値は Process フェーズで利用される - 入力音声フレームの「全体音量レベルの変更」(モードが `kAdaptiveDigital` の場合) モード毎に適用される処理の概要は以下の通り: - `kAdaptiveAnalog` の場合:- 以下の処理を行う [WebRtcAgc_AddMic()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/legacy/gain_control.h;l=82) 関数をチャネル毎に適用:1. 入力音量レベルが小さすぎる場合には、入力フレームの各サンプルに一律のゲイン値を適用して調整(増幅)- 一フレームで適用されるゲイン値には上限がり、複数フレームを跨いで徐々に大きくすることで、ターゲット音量に近づけていく 2. 入力フレームのバンド 0 部分を数 ms 間隔に区切って、それぞれのエナジーとエンベロープ( [Envelope (Wikipedia)](https://en.wikipedia.org/wiki/Envelope_(music)) )を計算 3. 最後に [WebRtcAgc_ProcessVad()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/legacy/digital_agc.cc;l=572) 関数を使って、入力音声フレームにスピーチが含まれているかどうかの情報を取得- VAD 判定自体は簡易的なもの - ざっくりと言えば「現在のフレームのエナジー」と「長期的なエナジーの統計(平均と標準偏差)」を比較して、前者が十分に高ければ「ボイスが含まれている」と判定 - `kAdaptiveDigital` の場合:- 以下の処理を行う [WebRtcAgc_VirtualMic()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/legacy/gain_control.h;l=82) 関数をチャネル毎に適用:> 1. 入力音声フレームのバンド 0 を対象として、エナジーを計算して `lowLevelSignal` かどうかを判定 > 2. 入力音量フレームの音量レベルが「適切な音量レベル」に合うように、一律のゲイン値を適用する(全体音量を上げる or 下げる)- 「全体音量レベルの変更」を行なっている箇所 > - 調整結果に応じて「現在の入力音声レベル」の値も修正する > - 「適切な音量レベル」を求めること自体は Process フェーズで行われる > 3. 最後に [WebRtcAgc_AddMic()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/legacy/gain_control.h;l=82) 関数を呼び出す- つまり前処理を除けば `kAdaptiveAnalog` と同じとなる - `kFixedDigital` の場合:- 特に何も行わない #### [AgcManagerDirect](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/agc_manager_direct.h) の Process ( [AgcManagerDirect::Process()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/agc_manager_direct.cc;l=653) メソッド) このメソッドでは、主に以下が行われる: - 「適切な全体音量レベル」の推定 - 「 後続の [GainControlImpl](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/gain_control_impl.h) クラスの Process フェーズで使用されるゲイン値("compression gain")」の算出 大まかな処理の流れは次の通り: 1. 入力音声フレームのバンド 0 に対して [Agc::Process()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/agc.cc;l=40) メソッドを呼び出す- 内部ではまず [VoiceActivityDetector::ProcessChunk()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/vad/voice_activity_detector.cc;l=37) を使って、細かいチャンク単位(数ms単位)でのボイス確率と RMS を求めている- RMS は "Root Mean Square" の略で、音圧に近い指標 - その後、その二つの値を [LoudnessHistogram::Update()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/loudness_histogram.cc;l=90) を使って、ヒストグラムに格納している(RMS に対応するボイス確立を保持) 2. 上の結果を使って [MonoAgc::UpdateGain()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/agc_manager_direct.cc;l=348) メソッドで「適切な音量レベル」を更新する- RMS のヒストグラムから、現在の loudness を求め、それをターゲットとする loudness と比較する - 現在とターゲットの loudness の差から、デジタルゲインコントールのゲイン値(対象となる調整量)を求める - デジタルゲインコントールで調整可能な範囲を超えている場合には、その超過分を(物理マイク or エミューレートマイクでの)アナログ調整でカバーするために「適切な音量レベル」の値を更新する 3. 次に [MonoAgc::UpdateCompressor()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/agc_manager_direct.cc;l=401) で「デジタルゲインコントロールで使用されるゲイン値」を更新する- 一つ上で求めたデジタルゲインコントロールのゲイン値をそのまま適用すると、音量が急変してしまう可能性があるので、徐々にターゲットに近づくように、ゲイン値を調整する - 調整後のゲイン値は `GainControlImpl::set_compression_gain_db()` 経由でデジタルゲインコントロールに渡される- ただし現在の実装では `WebRTC-UseLegacyDigitalGainApplier` フラグが有効になっていないと、この値は使用されない(のであまり気にしなくても良い) 4. 最後は、Analyze フェーズと同様に [AgcManagerDirect::AggregateChannelLevels()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/agc_manager_direct.cc;l=702) メソッドを用いた代表チャネルが選出される #### [GainControlImpl](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/gain_control_impl.h) の Process ( [GainControlImpl::ProcessCaptureAudio()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/gain_control_impl.cc;l=196) メソッド) このメソッドでは、主に以下が行われる: - 「入力音声フレーム内の音量の均一化」- 参考までに `analog_processing.h` ファイル内のコメントでは、この処理は次のように説明されている> It applies a fixed gain through most of the input level range, and compresses > (gradually reduces gain with increasing level) the input signal at higher levels. - 「適切な入力音声レベル」の推定(モードが `kFixedDigital` 以外の場合) 大まかな処理の流れは次の通り: 1. [WebRtcAgc_Analyze()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/legacy/analog_agc.cc;l=935;bpv=1;bpt=1) 関数を呼び出して「適用するゲイン配列」と「適切な入力音声レベル」を計算- 内部的には [WebRtcAgc_ComputeDigitalGains()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/legacy/digital_agc.cc;l=272;bpv=1;bpt=1) 関数と [WebRtcAgc_ProcessAnalog()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/legacy/analog_agc.cc;l=575) 関数を使用している - [WebRtcAgc_ComputeDigitalGains()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/legacy/digital_agc.cc;l=272;bpv=1;bpt=1) 関数は「適用するゲイン配列」を求める- ゲイン配列は 11 要素: 音声フレームの 1ms 毎のゲイン値(10個) + 次のフレームの冒頭部分のゲイン値(1個) - この関数は、入力音声フレームの VAD や各区間(1ms単位)のエナジーの情報を使って、それぞれの区間に適用するゲイン値を求める - [WebRtcAgc_ProcessAnalog()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/legacy/analog_agc.cc;l=575) では「適切な入力音声レベル」を求めている(音声フレームの更新は、ここでは行わない)- かなり色々なヒューリスティックを用いて、期待されるアナログ音量レベルを決定しているので、詳細は実装を参照のこと- 入力音声フレームの saturation や VAD を判定したり、 etc - なお、この関数は以下のいずれかの条件に該当する場合には呼び出されない:- モードが `kFixedDigital`- [GainControlImpl](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/gain_control_impl.h) が感知する範囲では「入力音声レベルの変更」が行われないため、「適切な入力音声レベル」を求めることが不要なため - モードが `kAdaptiveDigital` かつ Analyze フェーズで求めた `lowLevelSignal` フラグが真- `lowLevelSignal` の判定箇所には "digital AGC will not adapt to low-level signals" という記載があるので、それをチェックしているものと思われる 2. ゲイン配列の適用- [ApplyDigitalGain()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/gain_control_impl.cc;l=48) 関数を用いて、上で求めたゲイン配列を入力音声フレームに適用する - 基本的には、入力音声フレームの各サンプルにゲイン値を掛けているだけの単純な関数 - 1ms 区間の区切りで不自然にならないように、ゲイン値を徐々に調整していく、などの補助的な処理がいくつか入っている 3. 「適切な入力音声レベル」の更新(モードが `kAdaptiveAnalog` の場合のみ)- アナログマイク(ないしエミューレートされたマイク)による音量変更用に、チャネル毎に求めた「適切な入力音声レベル」から代表値を選択する - 行なっていることとしては、上述の [AgcManagerDirect::AggregateChannelLevels()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/agc_manager_direct.cc;l=702) と同様(最小値を選択しているだけ) ### 補足 #### マルチチャネルの扱い - 基本的には各チャネルは独立して扱われる(特に分析系の処理では) - ただし、最終的に音量調整を行う際には、一番音量レベルが小さいチャネルを代表チャネルとして、それを基準として処理が適用される #### マルチバンドの扱い - 以下の処理は、入力音声フレームがマルチバンドに分割される前に適用される:- [CaptureLevelAdjuster](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/capture_levels_adjuster/capture_levels_adjuster.h) による入力音声フレームの音量調整 - [AgcManagerDirect](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/agc_manager_direct.h) の Analyze ( [AgcManagerDirect::AnalyzePreProcess()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/agc/agc_manager_direct.h;l=35) メソッド) - 入力音声フレームの分析・情報収集の際には、バンド 0 が対象となることが多い #### バッファリングによる遅延 バッファリングを行なっていないので、それに伴う遅延も特になし #### 計算量特性 他の音声処理の多くと同様の傾向: - 入力音声フレームの走査やコピーが十数回から数十回程度行われる - 他の音声処理の多くとは異なり FFT を行なっていないのは特徴的 #### AGC2 について ここで取り上げているのは AGC1 (ないし無印の AGC )と呼ばれるもので、 libwebrtc にはそれとは別に AGC2 も存在する ( [GainController2](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/gain_controller2.h) クラス)。 AGC1 と AGC2 は排他的なものではなく、両方を併用することも可能な模様。 例えば、 `audio_processing.h` ファイルに掲載されている example コードには、以下のような記載があり、両方が有効化されている: ```c AudioProcessing::Config config; // ..省略.. // AGC1 を有効化 config.gain_controller1.enabled = true; config.gain_controller1.mode = AudioProcessing::Config::GainController1::kAdaptiveAnalog; config.gain_controller1.analog_level_minimum = 0; config.gain_controller1.analog_level_maximum = 255; // AGC2 を有効化 config.gain_controller2.enabled = true; ``` また Chromium (利用側)の `media/webrtc/helpers.cc` ファイルにある [ConfigureAutomaticGainControl()](https://source.chromium.org/chromium/chromium/src/+/main:media/webrtc/helpers.cc;l=133) 関数で ゲインコントロールを設定している箇所を見ても AGC1 と AGC2 が併用されるようなコードとなっている。 ただし AGC2 については `features::kWebRtcAnalogAgcClippingControl` というフラグが有効になっている場合にのみ利用され、 AGC1 と異なり単体で使われることはない。 #### 各種オプション - 一番挙動に大きな影響を与えるのは、おそらく [AudioProcessing::GainController1::Mode](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/include/audio_processing.h;l=246) の値 - それ以外にもパラメータはたくさんあるがここでは割愛- 設定可能な項目については [AudioProcessing::GainController1](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_processing/include/audio_processing.h;l=239) 構造体にまとまっている # libwebrtc リップシンク > **注意** > > この資料の正確性を保証しません。 > **重要** > > この資料についての問い合わせは Sora のサポート範囲には含まれません。 この資料は [libwebrtc M99 (4844)](https://webrtc.googlesource.com/src.git/+log/refs/branch-heads/4844) 時点の資料です。 ここでは libwebrtc でのリップシンク処理(映像および音声ストリームのタイムスタンプ同期処理)について記載しています。 ## 概要 - 同期処理は、主に以下の 3 つのパートで構成される:1. 映像・音声ストリームから同期用の情報(主にパケットのタイムスタンプ)を取得部分 2. 映像・音声ストリームを同期するために必要な遅延時間の計算部分- 片方が遅れている場合には、進んでいる方のストリームに対して遅延を課してタイミングを合わせるイメージ 3. 上で求めた同期用の遅延時間のストリームへの反映部分 - [RtpStreamsSynchronizer](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/video/rtp_streams_synchronizer2.h) がこのような同期処理のハブとなるクラス- 上述の 1 と 3 については、映像・音声ストリームと情報のやり取りが必要になるが、それは [Syncable](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/call/syncable.h) という抽象クラスを通して行われる- 映像では [VideoReceiveStream2](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/video/video_receive_stream2.h) が、音声では [AudioReceiveStream](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/audio/audio_receive_stream.h) が、 [Syncable](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/call/syncable.h) の実装クラスとなる - [RtpStreamsSynchronizer](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/video/rtp_streams_synchronizer2.h) はこれらのインスタンスをメンバ変数として保持しており、必要に応じてストリームの情報を取得したり、同期結果(必要な遅延)を伝えたりする - また [RtpStreamsSynchronizer](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/video/rtp_streams_synchronizer2.h) は [StreamSynchronization](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/video/stream_synchronization.h) というクラスのインスタンスも保持している- こちらは実際のストリームとは切り離された、同期処理用の計算部分を担っているクラス(上述の 2 を担当) - [RtpStreamsSynchronizer](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/video/rtp_streams_synchronizer2.h) は [RtpStreamsSynchronizer::UpdateDelay()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/video/rtp_streams_synchronizer2.cc;l=80) メソッドを定期的(一秒毎)に呼び出し、その中で上の 1 ~ 3 の処理を実施している 以降では、上の三つのパートのそれぞれについて記載していく。 ## 詳細 ### 同期用の情報取得 [RtpStreamsSynchronizer](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/video/rtp_streams_synchronizer2.h) クラスは [Syncable::GetInfo()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/call/syncable.h;l=37) メソッドを経由して、同期に必要な各種情報を取得する。 [Syncable::GetInfo()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/call/syncable.h;l=37) メソッドは、以下の定義の [Syncable::Info](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/call/syncable.h;l=25) 構造体を返す: ```c struct Info { // 最後に RTP パケットを受信した時のシステム時刻 int64_t latest_receive_time_ms = 0; // 最後に受信した RTP パケットのタイムスタンプ uint32_t latest_received_capture_timestamp = 0; // RTCP Sender Report パケットから取得した情報 uint32_t capture_time_ntp_secs = 0; // NTP 時刻の秒部分 uint32_t capture_time_ntp_frac = 0; // NTP 時刻の秒未満部分 uint32_t capture_time_source_clock = 0; // RTP タイムスタンプ // ストリームの現在の遅延時間 // // 正確ではないが、イメージとしては「`RtpStreamsSynchronizer`が前回に求めた遅延時間(を反映した値)」が近い int current_delay_ms = 0; }; ``` 概要部分に記載の通り、映像と音声では [Syncable](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/call/syncable.h) の実装クラスは別々だが、どちらも似たような方法で RTP / RTCP パケット受信時の情報をほぼそのまま使って、この構造体に必要な情報を埋めている。 `current_delay_ms` だけは若干特殊だが、ここではこの値の求め方の詳細は割愛する。 ### 同期に必要な遅延の計算 映像ストリームと音声ストリームのタイムスタンプの同期は「片方がもう片方に対して、どの程度遅延しているか」ということを求めることで行われる。 この遅延計算を担当しているのは [RtpStreamsSynchronizer::UpdateDelay()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/video/rtp_streams_synchronizer2.cc;l=80) メソッドで、流れは以下のようになっている: 1. 前節に記載の [Syncable::GetInfo()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/call/syncable.h;l=37) を使って、映像と音声のそれぞれで [Syncable::Info](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/call/syncable.h;l=25) 構造体を取得する 2. [Syncable::Info](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/call/syncable.h;l=25) を使って、映像および音声用の [StreamSynchronization::Measurements](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/video/stream_synchronization.h;l=22) メンバ変数を更新する- [StreamSynchronization::Measurements](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/video/stream_synchronization.h;l=22) は「RTP タイムスタンプの NTP ドメインへの変換」を行うためのクラス - このクラスは [RtpToNtpEstimator](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/system_wrappers/include/rtp_to_ntp_estimator.h) というクラスのインスタンスを保持している- [RtpToNtpEstimator::UpdateMeasurements()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/system_wrappers/include/rtp_to_ntp_estimator.h;l=39) は [Syncable::Info](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/call/syncable.h;l=25) の RTCP Sender Report (SR) 関連の情報を受け取り、それらを 20 個分保持している - [RtpToNtpEstimator::Estimate()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/system_wrappers/include/rtp_to_ntp_estimator.h;l=39) では、その履歴情報を使って(線形回帰で)求めたパラメータを用いて、 RTP タイムスタンプから NTP タイムスタンプへの変換を行う 3. 更新された映像および音声用の [StreamSynchronization::Measurements](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/video/stream_synchronization.h;l=22) を引数にして [StreamSynchronization::ComputeRelativeDelay()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/video/stream_synchronization.h;l=39) メソッドを呼び出す- このメソッドは「音声ストリームが映像ストリームに対して、どの程度遅れているか(or 進んでいるか)」を結果として返す 4. 次に [StreamSynchronization::ComputeDelays()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/video/stream_synchronization.h;l=31) を呼び出して「ストリームを同期するために映像と音声のそれぞれをどの程度遅延させるべきか」を計算する 5. 最後は [Syncable::SetMinimumPlayoutDelay()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/call/syncable.h;l=40) を用いて、計算した同期用の遅延値を映像と音声ストリームのそれぞれに反映する- このメソッドの詳細については、次の節を参照 #### `ComputeRelativeDelay()` と `ComputeDelays()` の詳細 [StreamSynchronization::ComputeRelativeDelay()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/video/stream_synchronization.h;l=39) のシグネチャは以下のようになっている: ```c bool StreamSynchronization::ComputeRelativeDelay( const Measurements& audio_measurement, // 音声用の StreamSynchronization::Measurements const Measurements& video_measurement, // 映像用の StreamSynchronization::Measurements int* relative_delay_ms) // 音声を基準にした、映像の遅延時間(音声の方が遅れている場合には負の値になる) ``` メソッド内で行われていることは単純で次の通り: - [RtpToNtpEstimator::Estimate()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/system_wrappers/include/rtp_to_ntp_estimator.h;l=39) メソッドを使って、最後に受信した RTP パケットのタイムスタンプを NTP ドメインに変換する(映像と音声のそれぞれ) - 次の式で `relative_delay_ms` の値を計算する:- `(映像パケット受信システム時刻 - 音声パケット受信システム時刻) - (映像パケット NTP 時刻 - 音声パケット NTP 時刻)` [StreamSynchronization::ComputeDelays()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/video/stream_synchronization.h;l=31) の方はもう少し複雑で、シグネチャは以下のようになっている: ```c bool StreamSynchronization::ComputeDelays( int relative_delay_ms, // 上で求めた`relative_delay_ms`の値(i.e., 音声に対する映像の遅延時間) int current_audio_delay_ms, // 音声の現在の遅延時間 (`Info.current_delay_ms`) int* total_audio_delay_target_ms, // 音声用の同期用遅延時間(初期値は 0) int* total_video_delay_target_ms) // 映像用の同期用遅延時間(初期値は映像の現在の遅延時間=`Info.current_delay_ms`) ``` この関数は、大まかには以下のようなことを行なっている: 1. `映像の現在の遅延 - 音声の現在の遅延 + relative_delay_ms` という式で映像と音声の遅延のズレを算出- この結果は、過去四回分が保持されており、以降ではその平均値が使用される 2. 上の結果が 30 ms 未満なら、許容範囲ということで、ここで処理は終了- 次節に記載の同期用遅延の反映処理もスキップされる 3. 急激な遅延調整を防ぐために、上で求めた「ズレの平均値」の値を調整する- 二で割った後に、±80 ms の範囲に収まるようにmin/max を取る - 結果は `diff_ms` という変数に格納する 4. `diff_ms` が正の場合:- 映像の方が遅れている(遅延時間が長い)ので **映像の遅延を減らす** か **音声の遅延を増やす** 必要がある - 別途設定された「基準となるターゲット遅延時間」よりも映像の遅延時間が長い場合には、映像の遅延時間を `diff_ms` 分だけ減らす- かつ、音声の遅延時間を「基準となるターゲット遅延時間」にリセットする - 注釈:> - 「基準となるターゲット遅延時間」は [StreamSynchronization::SetTargetBufferingDelay()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/video/stream_synchronization.h;l=45) メソッドによって設定される > - ただし通常はデフォルト値である 0 が使用されるように見える - 「基準となるターゲット遅延時間」よりも映像の遅延時間が短い場合には、音声の遅延時間を `diff_ms` 分だけ増やす- かつ、映像の遅延時間を「基準となるターゲット遅延時間」にリセットする 5. `diff_ms` が負の場合:- 音声の方が遅れている(遅延時間が長い)ので **音声の遅延を減らす** か **映像の遅延を増やす** 必要がある - 映像と音声が逆転している以外はひとつ前のステップで行なっていることと同じなので、詳細は割愛する 6. ここまでで計算した映像の遅延時間が「基準となるターゲット遅延時間」を超えている場合には、その値を結果に採用する- そうではない場合には、前回の映像遅延時間をそのまま採用する - なお、遅延時間は 10 秒を超えないように min を取る - この値が `total_video_delay_target_ms` に格納されて呼び出し元に伝えられる 7. 映像で前回の遅延時間が採用されなかった場合には、音声の方の遅延時間を更新する- 一度のメソッド呼び出しで更新されるの映像か音声のどちらか一つの遅延時間のみ - それ以外は映像の場合の処理と同様 - この値が `total_audio_delay_target_ms` に格納されて呼び出し元に伝えられる ### 同期用遅延の反映 前節で計算された「映像と音声を同期させるために必要なそれぞれの遅延時間」は [Syncable::SetMinimumPlayoutDelay()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/call/syncable.h;l=40) メソッドを通して、 それぞれのストリームに伝達され処理されることになる。 以降では、映像と音声のそれぞれについて、サブセクションに分けて概要を記載していく。 なお、メソッド名に含まれる "PlayoutDelay" という用語については、以下のドキュメントも参考になる: #### 映像の場合 - 映像の [Syncable](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/call/syncable.h) 実装は [VideoReceiveStream2](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/video/video_receive_stream2.h) クラスで行われているので [VideoReceiveStream2::SetMinimumPlayoutDelay()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/video/video_receive_stream2.h;l=180) メソッドがエントリポイントとなる- このメソッドの内部では(細々とした調整処理を経て) [VCMTiming::set_min_playout_delay()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/video_coding/timing.h;l=50) にターゲット遅延値が渡される - 映像の遅延関連処理はこの [VCMTiming](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/video_coding/timing.h) クラスに集約されている- 同期用の遅延以外にも jitter, render, composition, etc の遅延がこのクラスで管理されている - 上述の [VCMTiming](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/video_coding/timing.h) インスタンスへの参照は、 [VideoReceiveStream2](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/video/video_receive_stream2.h) 以外にも複数箇所で共有されている- その内の一つが [FrameBufferProxy](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/video/frame_buffer_proxy.h) であり、同期遅延の反映処理は、このクラスで行われている - [FrameBufferProxy](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/video/frame_buffer_proxy.h) は設定によっていくつか別のクラスに処理を委譲することになる- 例えば [FrameBuffer2Proxy](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/video/frame_buffer_proxy.cc;l=37) が使われる場合には、 [VCMTiming](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/video_coding/timing.h) への参照は、さらに [FrameBuffer](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/video_coding/frame_buffer2.h) クラスに渡されて、処理されることになる - 以降では、この [FrameBuffer](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/video_coding/frame_buffer2.h) での挙動を見ていく - [VCMTiming](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/video_coding/timing.h) に保持された同期用の遅延時間は、以下のメソッドの中で参照されている:- [VCMTiming::TargetVideoDelay()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/video_coding/timing.h;l=92):「同期用遅延時間」と「jitter, decode, render 遅延の合計時間」を比較し、大きい方を返すメソッド - [VCMTiming::RenderTime()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/video_coding/timing.h;l=77): 「フレームのタイムスタンプ」を入力として受け取り、それを描画すべきタイムスタンプを返すメソッド- その際に「現在の遅延時間」を加味するが、その現在値が同期用の遅延時間の範囲内に収まるように min/max を取っている - [VCMTiming::MaxWaitingTime()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/video_coding/timing.h;l=86): 「デコーダに次のフレームを渡すまでの待機時間」を計算するメソッド- 同期用の遅延時間が 0 の場合(かつ、その他の条件が整った場合)には、特別な計算が実施される - この中の最初の二つのメソッドは [FrameBuffer::GetNextFrame()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/video_coding/frame_buffer2.h;l=124) メソッド、最後の一つは [FrameBuffer::FindNextFrame()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/video_coding/frame_buffer2.h;l=123) の中で使用されている - [FrameBuffer::FindNextFrame()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/video_coding/frame_buffer2.h;l=123) は「次にデコードするフレーム」と「デコードまでの待機時間」を決定するためのメソッド- この中で [VCMTiming::RenderTime()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/video_coding/timing.h;l=77) を使ってフレームの描画時刻が決定される(まだ未定だった場合) - その次に [VCMTiming::MaxWaitingTime()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/video_coding/timing.h;l=86) を呼び出して、そのフレームをデコーダに渡すまでの待機時間が決定される- もしその待機時間が負数(正確には -5ms 未満)だった場合には、そのフレームはドロップされる - [FrameBuffer::GetNextFrame()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/video_coding/frame_buffer2.h;l=124) は上で準備したフレームを、デコード時間になったら、実際に取得するメソッド- 対象フレームの描画時刻は [FrameHasBadRenderTiming()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/video_coding/frame_helpers.cc;l=19) 関数を使ってチェックされる- このメソッドに [VCMTiming::TargetVideoDelay()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/video_coding/timing.h;l=92) の値も渡される - ざっくり言えば、タイムスタンプの値が負数だったり、遅延時間が 10 秒を超えている場合に "Bad" と判定される - その場合には [VCMTiming::reset()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/video_coding/timing.h;l=40) を呼び出して状態をリセットした上で、再度 [VCMTiming::RenderTime()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/video_coding/timing.h;l=77) を使って描画時刻が計算される #### 音声の場合 - 音声の [Syncable](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/call/syncable.h) 実装は [AudioReceiveStream](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/audio/audio_receive_stream.h) クラスで行われているので [AudioReceiveStream::SetMinimumPlayoutDelay()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/audio/audio_receive_stream.h;l=120) メソッドがエントリポイントとなる- その後、以下のメソッド群の呼び出し通じて値が(ほぼそのまま)伝播する:1. [ChannelReceiveInterface::SetMinimumPlayoutDelay()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/audio/channel_receive.h;l=121) 2. [AcmReceiver::SetMinimumDelay()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_coding/acm2/acm_receiver.h;l=97) 3. [NetEq::SetMinimumDelay()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/api/neteq/neteq.h;l=236) 4. [NetEqController::SetMinimumDelay()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/api/neteq/neteq_controller.h;l=138) 5. [DelayManager::SetMinimumDelay()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_coding/neteq/delay_manager.h;l=77) - [DelayManager::SetMinimumDelay()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_coding/neteq/delay_manager.h;l=77) に渡された遅延時間は [DelayManager::Update()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_coding/neteq/delay_manager.h;l=62) メソッドの中で参照される- これは「RTP パケットのタイムスタンプ」を入力に受け取り、内部の統計情報等を更新した上で、パケットの遅延時間を返すメソッド - このメソッド呼び出し時には、他のクラスから参照される「ターゲット遅延時間」の値も更新される- このターゲット遅延時間の値は [DelayManager::TargetDelayMs()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_coding/neteq/delay_manager.h;l=70) 経由で取得可能 - [DelayManager::TargetDelayMs()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_coding/neteq/delay_manager.h;l=70) の返り値と [DelayManager::SetMinimumDelay()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_coding/neteq/delay_manager.h;l=77) に渡された値は、必ずしも一致する訳ではない- ただし、大枠を理解する上では「おおむね同じもの」と考えてしまってもそこまで問題はない - [DelayManager::TargetDelayMs()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_coding/neteq/delay_manager.h;l=70) は [DecisionLogic](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_coding/neteq/decision_logic.h) クラスの色々な箇所で呼び出されている- その中でも [DecisionLogic::GetDecision()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_coding/neteq/decision_logic.h;l=61) がおそらく一番重要 - [DecisionLogic::GetDecision()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_coding/neteq/decision_logic.h;l=61) は最後に受け取ったパケットやジッタバッファの情報を使って、次に行うべき操作を指示する [NetEq::Operation](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/api/neteq/neteq.h;l=143) 列挙型を返す - 操作決定の際には [DelayManager::TargetDelayMs()](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/audio_coding/neteq/delay_manager.h;l=70) の値も考慮し、それに応じて `Operation::kAccelerate` (再生時間を早める) や `Operation::kExpand` (再生時間を遅らせる)を指示してペース調整が行われる - なお [NetEq](https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/api/neteq/neteq.h) クラスについては以下のリンクも参考になる: # libwebrtc ペーサー > **注意** > > この資料の正確性を保証しません。 > **重要** > > この資料についての問い合わせは Sora のサポート範囲には含まれません。 この資料は [libwebrtc M104 (5112)](https://webrtc.googlesource.com/src.git/+log/refs/branch-heads/5112) 時点の資料です。 このドキュメントでは libwebrtc でのペーサーの処理について記載しています。 ペーサーは「RTP パケットの送信ペースを調整し、指定されたビットレート要求を満たすようにする」役目を担っているコンポーネントです。 なおペーサー関連の話の大枠については、libwebrtc のリポジトリで提供されている [Paced Sending](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/g3doc/index.md) というドキュメントによくまとまっているので、 理解を深めるためには、そちらに先に目を通しておくことをお勧めします。 > **注釈** > > 今回取り上げているクラスは、2022 年 7 月現在でも継続的に修正が行われています。 > そのため、今後の libwebrtc のバージョン更新に伴い、処理内容が変わる可能性は十分にあり得ます。 ## 概要 - ペーサー関連のコードは [webrtc/src/modules/pacing/](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/) ディレクトリ以下にまとまっている - その中でペース調整ロジックを提供している中心的なクラスは [PacingController](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h):- 新規に送信される RTP パケットは [PacingController::EnqueuePacket()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#133) に渡され、一度キューイングされる - その後、 [PacingController::ProcessPackets()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#197) 呼び出しタイミングで、指定されたターゲットビットレート要求を満たすペースで実際のパケット送信が行われる - ターゲットビットレートは [PacingController::SetPacingRates()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#165) によって、このクラスの外から指定される - [PacingController](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h) のペース制御アルゴリズムは [リーキーバケット](https://ja.wikipedia.org/wiki/%E3%83%AA%E3%83%BC%E3%82%AD%E3%83%BC%E3%83%90%E3%82%B1%E3%83%83%E3%83%88) に基づいている- リーキーバケットとは「穴の空いたバケツ」のこと - このアルゴリズムでは、水の流量(= パケットの送信ペース)は、バケツ内の水の容量(= キュー内のパケットの合計サイズ)には左右されず、その穴の大きさ(= 指定ビットレート)によって制御されることになる - [PacingController](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h) は「送信済みパケットサイズ」および「経過時間」、「ターゲットビットレート」をもとに「バジェット(現在の送信可能サイズ)」を計算し、その範囲内でパケットの送信を行う - デフォルトでは、音声パケットはペース調整の対象外となっており、常に即座に送信される - RTP パケットには、その種類に応じた優先度が設定されている:- バジェットに余裕ができた際には、優先度が高いパケットから先にキューから取り出されて送信される- 優先度が同じパケットを含む複数のストリームがある場合にはラウンドロビン - パケットの種類に応じた優先度は以下の通り:1. 音声パケット 2. 再送パケット 3. 映像ないし FEC パケット 4. パディングパケット(キープアライブや後述のプローブ用途で使用される) - この優先順位(と音声の特別扱い)に照らし合わせて、ペーサーの役割を端的に表現するなら「映像の送信によって、音声の送信が阻害されないようにすること」とも言える - [PacingController](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h) と関係がある主要なクラスとしては以下のものがある:- [PacingController](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h) が利用するクラス:- [BitrateProber](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h):- 帯域推定などを補佐するためのクラス - 送信パケットが少な過ぎると帯域推定の信頼度が下がるので、プローブ用のパディングパケットを、ペース調整の範囲内で挿入する役目を持つ - [RoundRobinPacketQueue](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/round_robin_packet_queue.h):- 送信パケットを一時的に格納するためのキュー - このドキュメントの範囲内では、単なる優先順位付きキュー、とみなしてしまって問題ない - [PacingController::PacketQueue](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#60) インタフェースの実装クラス - [PacketRouter](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/packet_router.h):- [PacingController](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h) が実際にパケット送信を行う際のインタフェースを規定する [PacingController::PacketSender](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#45) の実装クラス - このインタフェースは、パケット送信に加えて、FEC パケットやパディングパケットの生成メソッドも定義している - [PacingController](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h) を利用するクラス:- [TaskQueuePacedSender](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/task_queue_paced_sender.h):> - [PacingController](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h) の API ラップして `pacing` モジュール外から呼び出すためのインタフェースを提供する > - [PacingController::ProcessPackets()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#197) の呼び出しタイミングを決定するのもこのクラス - [RtpTransportControllerSend](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/call/rtp_transport_controller_send.h):> - 帯域推定や輻輳制御を行うクラスが検知したネットワーク状態の変更を [PacingController](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h) に伝えるためのハブとなるクラス > - [PacingController::SetPacingRates()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#165) などを( [TaskQueuePacedSender](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/task_queue_paced_sender.h) を経由して) 呼び出す - [PacingController](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h) がやらないこと:- ネットワークの状態(帯域や輻輳)の推定- 送信ペース調整の際には、これらの状態を考慮はするが、推定自体は外部に任せている- [PacingController](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h) はあくまでも、指定されたペースは正しいものとして、それを遵守するのが役割 - この辺りは帯域推定や輻輳制御を専門に行うクラスの責務であり、本ドキュメントの対象外となる - 送信キューが詰まった場合のパケットドロップ- 指定されたターゲット送信ビットレートが、実際に送信されるパケット群に対して小さ過ぎる場合(帯域推定が誤っている場合など)には、キューの消化ペースが追いつかなくなる - そのような場合でも [PacingController](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h) はパケットドロップは行わず、(時間は掛かっても)全てのパケットの送信を試みる - ただし、キューが詰まっている場合には、指定されたターゲット送信ビットレートを超過したペースでのパケット送信が許容されるようになる 以降では [PacingController](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h) および関連するクラスの実装やアルゴリズムの詳細を取り上げていく。 なお、フィールドトライアルやオプションによって挙動が変わる機能については、簡単のためにデフォルトの構成に準拠して記述を行なっている (末尾の「構成オプション」節も参照)。 ## 詳細 ### [PacingController](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h) クラスの詳細 ペース調整ロジックの中心を担う [PacingController](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h) の主要なメソッドについて説明していく。 #### [PacingController::SetPacingRates()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#165) [PacingController](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h) に「パケットの送信ペース(ターゲットビットレート)」を第一引数で指示するためのメソッド。 また第二引数で「パディングパケットの送信レート」を指定することも可能で、これが 0 より大きい場合には、 送信ペースに余裕がある場合は、パディングパケットが常に送信されることになる。 [PacingController](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h) の各処理では、ここで指示された送信ペースが厳守されることになる。 ペース調整は、イメージとしては `経過時間 * 送信ペース - これまでの送信量 = バジェット` として、そのバジェットに収まる分だけのパケット送信を許可する形となっている。 この式を見て分かる通り、基本的には「時間経過分だけバジェットが増えて、パケット送信分だけ減る(かつ、プラスの場合にだけ送信可能)」という単純なもの。 なお、実際のコードでは「バジェット(= 余裕分)」ではなく「 `dept` (= 不足分)」として実装されているが、符号の向きが異なるだけで、意味するところはどちらもほぼ同じ。 ただし、いくつか例外もある: - (デフォルトでは)音声パケットは、送信ペース管理の対象外(常にすぐ送信可能、また、送信分もバジェットから引かれない) - キューが詰まっている場合には、要素が延々と増えていくことを防止するために、送信ペースを(指示されたものよりも)増加させる- 詳細は [PacingController::MaybeUpdateMediaRateDueToLongQueue()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#246) を参照 - [PacingController::SetSendBurstInterval()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#161) によってバースト送信が許可されている場合には、一時的に送信ペースを超過することがある- ただし、これによって消費されるバジェットの合計が増える訳ではない なお、本メソッドの呼び出し側に関しては「 [PacingController](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h) の利用側クラスや呼び出しタイミング」節を参照。 #### [PacingController::EnqueuePacket()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#133) 送信対象の RTP パケット( [RtpPacketToSend](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/rtp_rtcp/source/rtp_packet_to_send.h) )を受け取り、それをキューに追加するメソッド。 キューイングされたパケットは [PacingController::ProcessPackets()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#197) の呼び出し時に、 (ペース調整を満たしたタイミングで)実際に送信される。 メソッドの処理の流れは以下の通り: 1. BitRateProber::OnIncomingPacket() を呼び出して、プローバに送信対象パケットのサイズを教える- プローブ関連処理の詳細は「 [BitrateProber](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h) クラスの詳細」の節を参照 2. キューが空だった場合には、現在時刻を基点にして、バジェットを再計算する:- 処理としては `UpdateBudgetWithElapsedTime(UpdateTimeAndGetElapsed(現在時刻));` が呼ばれるイメージ:- `UpdateTimeAndGetElapsed()` で、最終処理時刻を現在時刻に設定(返り値が前回の処理時刻からの経過時間) - `UpdateBudgetWithElapsedTime()` で、経過時間を元に送信バジェットを更新する - この二つのメソッドの組み合わせは [PacingController](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h) 内の色々なところで登場する頻出パターン - それぞれのメソッドの詳細については、後続のサブセクションを参照 3. キュー( [PacingController::PacketQueue](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#60) の実装クラス)に RTP パケットを追加 4. キューの要素が増えたので [PacingController::MaybeUpdateMediaRateDueToLongQueue()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#246) を呼び出して、必要なら送信ペースを増加する(キュー詰まり解消用) なおユーザが直接生成した RTP パケットだけではなく、 [PacingController::ProcessPackets()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#197) 呼び出し時に生成される 以下のパケットも、一度キューを経由して送信され、ペース調整の対象となる: - FEC 用のパケット - プローブ用のパディングパケット #### [PacingController::ProcessPackets()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#197) キューに格納されているパケット群を [PacingController::SetPacingRates()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#165) で指定されたペース制約を満たす範囲で送信するメソッド。 その他に、キープアライブやプローブ用のパディングパケットの送信を行なったりもする。 処理の流れ: 1. [PacingController::ShouldSendKeepalive()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#203) を呼び出して、キープアライブ用のパディングパケットの送信が必要かどうかを判定する- [PacingController::ShouldSendKeepalive()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#203) は大まかには「500ms 以上パケットが送信されていない場合」に、キープアライブが必要と判定する - 必要と判定されたら、ペイロードサイズが 1 のパディングパケットが送信される(この場合は [PacingController::EnqueuePacket()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#133) は経由しない) 2. [PacingController::Pause()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#140) 呼び出しによって、送信処理が一時停止中になっている場合には、ここで終了 3. [PacingController::NextSendTime()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#193) で、パケットの次回送信時刻を取得する- もし現在時刻が送信時刻に到達していない場合(i.e., 送信バジェット枯渇中)には、ここで終了 4. `UpdateTimeAndGetElapsed(次回送信時刻)` を呼び出して、「前回の処理実施時刻」から「次回送信時刻」までの経過時間を取得する- NOTE: バジェットに余裕がある場合には、次回送信時刻は、現在時刻よりも前になることがある - 経過時刻が 0 秒以上なら [PacingController::UpdateBudgetWithElapsedTime()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#219) を呼び出して、バジェットを更新する(経過時間分だけ送れる量が増える) 5. プローブ中の場合には [BitrateProber::RecommendedMinProbeSize()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h#70) を呼び出して「プローブに必要な送信データサイズ」を取得する 6. 以降で、キュー内のパケットの送信ループ処理に入る- 各イテレーションの冒頭では [PacingController::GetPendingPacket()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#213) によって、次に送信するパケットがキューから取り出される - ただし、送信バジェットが枯渇している場合などは、キューに要素が存在しても `null` が返されることがある(詳細は後述) - 「次に送信するパケットがあるかどうか」で処理が分岐する 7. **[送信パケットがない場合]** 必要に応じて、プローブ用のパディングパケットをキューに追加する1. [PacingController::PaddingToAdd()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#245) でパディングパケットのサイズを計算する- パディングパケットの送信が不要な場合には 0 が返され、ここで送信ループを抜ける 2. [PacingController::PacketSender::GeneratePadding()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#86) で上記のサイズのパディングパケットを生成する 3. [PacingController::EnqueuePacket()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#133) を呼び出して、パディングパケットをキューに追加する 4. 送信ループの次のイテレーションに進む 8. **[送信パケットがある場合]** RTP パケットを実際に送信する1. [PacingController::PacketSender::SendPacket()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#48) を呼び出して、パケットを送信する 2. FEC パケットがある場合には [PacingController::PacketSender::FetchFec()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#51) で取得して、キューに追加する 3. [PacingController::OnPacketSent()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#217) メソッドを呼び出して、(主に)以下を行う- 最終送信時刻の更新 - [PacingController::UpdateBudgetWithSentData()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#207) を呼び出してバジェットを更新(送信分だけバジェットを減らす) 4. ループ内で送信したパケットのサイズ合計を更新する 5. プローブ中の場合には、その合計サイズが「プローブに必要な送信データサイズ」を超過しているかどうかをチェックする- 超過している場合には、ここでループを抜ける - プローブ中の場合は、一度に送信するデータサイズが、少な過ぎても多過ぎても良くない 6. [PacingController::NextSendTime()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#193) を呼び出して、パケットの次回送信時刻を取得する- 次回送信時刻が「現在時刻を超えている(バジェットが枯渇した)」かつ「プローブ中ではない」場合には、ここでループを抜ける 7. `UpdateBudgetWithElapsedTime(UpdateTimeAndGetElapsed(次回送信時刻))` を呼び出して、次のイテレーションに備えてバジェットを更新する 9. 送信ループを抜けた後は、プローブ中なら BitRateProber::ProbeSent() を呼び出して、今回送信したデータサイズ合計を [BitrateProber](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h) に伝える 10. 最後に [PacingController::MaybeUpdateMediaRateDueToLongQueue()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#246) を呼び出して、以降の送信ペースの調整を行う #### [PacingController::NextSendTime()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#193) パケットの次の送信時刻を決定するためのメソッド。 バジェットが枯渇している場合には、それが回復する予定時刻を返す。 反対にバジェットに余裕がある場合には、現在より前の時刻が返されることがある。 決定の際の流れは以下の通り: 1. [PacingController::Pause()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#140) が呼ばれており、一時停止中なら「次のキープアライブ時刻」を返す- 「次のキープアライブ時刻」は `最後の送信時刻 + 500ms` 2. プローブ中の場合には [BitrateProber::NextProbeTime()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h#63) に次回時刻の決定を委譲する 3. 送信キューの先頭が音声パケットの場合には、そのパケットをキューに追加した時刻(つまり過去)を返す- 音声パケットは、デフォルトではペース調整の対象外なので、即座に送信される - 音声パケットがペース調整の対象に含まれる構成の場合には、この部分の処理はスキップされる 4. 「輻輳発生中」ないし「まだ [PacingController::EnqueuePacket()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#133) が一度も呼び出されていない」場合には「次のキープアライブ時刻」を返す- 「輻輳発生中」かどうかは [PacingController::SetCongested()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#178) によって、外部から [PacingController](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h) に伝えられる - 輻輳時には、音声パケットやキープアライブ用パディングパケットを除いて、パケット送信は抑制される 5. キューに要素がある場合には、1. `負債 / 送信ペース` で負債が解消するまで(= 次にパケットが送信可能になるまで)に掛かる時間を求める> - 「負債」は、バジェットを超過して送信したパケットの合計サイズ(超過しておらずバジェットに余裕がある場合には負数になる) 2. その時間分を「最後の送信時刻」に加算し、それを次回の送信時刻とする 6. キューが空の場合には、- 「 [PacingController::SetPacingRates()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#165) でパディングパケットの送信レートが指定されている」場合は、そのレートに合わせて次回の送信時刻を決定する - それ以外の場合には、「次のキープアライブ時刻」を次回送信時刻とする #### [PacingController::PaddingToAdd()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#245) プローブやその他の目的で使用するパディングパケットのサイズを決定するメソッド。 決定方法: - 送信キューが空ではないなら、パディングサイズは 0 (パディングではなく実際のパケットを送るべきなので) - 輻輳中ならパディングサイズは 0 (ネットワークに負荷をかけたくない) - [PacingController::EnqueuePacket()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#133) が一度も呼び出されていないなら、パディングサイズは 0 (パディングパケットを生成しても、適切なタイムスタンプを振ることができない) - プローブ中の場合には `プローブに必要なバイト数 - これまでに送信したバイト数` をパディングサイズとする - [PacingController::SetPacingRates()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#165) で「パディングパケットの送信レート」が指定されている場合には `レート * 5ms` を返す -ただし、パディング用のバジェットに余裕がある場合のみ #### [PacingController::MaybeUpdateMediaRateDueToLongQueue()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#246) 送信キューへの操作(要素追加や削除)があった場合に呼び出されるメソッド。 [SetPacingRates()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#165) で指定された送信ペース(ターゲットビットレート)に対して、 [EnqueuePacket()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#133) で追加されるペースが多過ぎると、キューが詰まって延々と要素数が増えてしまう。 それに対処するために、送信ペースの調整(増加)を行うのがこのメソッドの役割。 処理の流れ: 1. 最初に送信ペースを [PacingController::SetPacingRates()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#165) で指定された値にリセットする 2. キューにあるパケットの「サイズ合計」を求める- もし 0 ならここで終了(指定された送信ペースをそのまま使う) 3. キュー内の各要素の平均滞在時間(エンキューされてから、実際に送信されるまでの平均時間)を求める 4. 「キューが空になるまでの期待時間」を `2 秒 - 平均滞在時間` で求める(0 以下になる場合には 1ms にする)- 「2 秒」の部分は [PacingController::SetQueueTimeLimit()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#220) で変更可能 - 「キューが空になるまでの期待時間」は、「キュー内の最後のパケットの遅延を 2 秒以下にするために使える残り時間」とも言える 5. `サイズ合計 / キューが空になるまでの期待時間` で、その期待時間を達成するために必要な送信ペースを求める- 求めた送信ペースが [PacingController::SetPacingRates()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#165) よりも大きい場合には、(指定のペースではなく)そちらを採用する #### [PacingController::UpdateTimeAndGetElapsed()](LIBWEBRTC_PACER.html#ff3435) 基本的には「現在時刻」を引数にとって、それと「最終処理時刻」との差分(経過時間)を計算して返すメソッド。 処理の流れ: 1. 「最終処理時刻」よりも前の時刻が「現在時刻」として指定された場合には、このメソッドは 0 秒を経過時間として返す- 「現在時刻」には [PacingController::NextSendTime()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#193) が返した時刻が渡ってくることがあるため、過去の時刻になることもある 2. `現在時刻 - 最終処理時刻` で経過時間を求める 3. もし経過時刻が 2 秒を超えている場合には、2 秒に丸める 4. 「最終処理時刻」を「現在時刻」の値で更新して、経過時間を呼び出し元に返す #### [PacingController::UpdateBudgetWithElapsedTime()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#219) および [PacingController::UpdateBudgetWithSentData()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#207) バジェットの増減を行うための単純なメソッド群: - [PacingController::UpdateBudgetWithElapsedTime()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#219) は経過時間を引数に取り `経過時間 * 送信ペース` の分だけバジェットを増やす - [PacingController::UpdateBudgetWithSentData()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#207) は送信したパケットサイズを引数に取り、その分だけバジェットを減らす ### [BitrateProber](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h) クラスの詳細 - [BitrateProber](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h) は「送信帯域の推定(プローブ)用に追加で送信するパディングパケット」のサイズや送信タイミングを決定するためのクラス - プローブ処理は [BitrateProber::CreateProbeCluster()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h#58) 呼び出しにより開始され、プローブに必要な期間やパケット送信回数を超えたら終了する- この一回のプローブ処理のまとまりは「クラスター」と呼ばれる - クラスターは [BitrateProber::CreateProbeCluster()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h#58) 呼び出し毎に新しく生成され、FIFO キューの末尾に追加される - 一度に処理されるのはキューの先頭のクラスターのみ - [BitrateProber](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h) には [ProbingState](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h#78) で表現される以下のような状態遷移がある:- [ProbingState::kDisabled](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h#80):- プローブ処理が無効な構成の場合には、常にこの状態となる - [ProbingState::kInactive](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h#82):- この状態になるのは、- [BitrateProber](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h) のインスタンス生成直後、ないし、 - [BitrateProber::CreateProbeCluster()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h#58) によってクラスターが生成されたが、まだプローブ処理が開始されていない場合 - 基本的には、新しいパケットが [PacingController](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h) のキューに積まれた段階で [ProbingState::kActive](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h#85) に遷移する - [ProbingState::kActive](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h#85):- プローブ処理の実施中を示す状態( [PacingController](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h) と協調して、適宜パディングパケットが送信される) - 全てのクラスターでのプローブ処理が完了した時点で [ProbingState::kSuspended](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h#88) に遷移する - [ProbingState::kSuspended](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h#88):- 全てのクラスターでのプローブ処理が完了して待機中の状態 - 次の [BitrateProber::CreateProbeCluster()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h#58) 呼び出しによって [ProbingState::kInactive](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h#82) に遷移する - プローブ処理は常時実行されるものではなく、通信相手との接続直後やネットワーク状況の変更に応じて実施される 以降では [BitrateProber](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h) の主要メソッドについて説明していく。 #### [BitrateProber::CreateProbeCluster()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h#58) 新しいクラスターを生成するためのメソッド。 処理の流れは以下の通り: - 古いクラスターがキューに残っている場合には削除- 作成から五秒以上経過しているクラスターは、古いと判定される - 引数で指定された以下の情報をもとに、新しいクラスターを生成する:- ターゲット送信ビットレート - プローブ用のパケット送信回数 - プローブ用に送信するパケットサイズの合計- この値は `ターゲット送信ビットレート * プローブ期間(デフォルトでは 15ms)` によって算出される - 生成したクラスターをキューの末尾に追加 - [BitrateProber](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h) の状態を `kInactive` にする- 次の [BitrateProber::OnIncomingPacket()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h#55) 呼び出しによってプローブが開始される - 既に `kActive` の場合には何もしない) #### [BitrateProber::OnIncomingPacket()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h#55) - [PacingController::EnqueuePacket()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#133) の中で、追加対象パケットのサイズを引数として、呼び出されるメソッド - 「現在が `kInactive` 」かつ「クラスターキューが空ではない」かつ「パケットサイズが十分に大きい場合」に `kActive` 状態に遷移する- 「パケットサイズが十分に大きい場合」== 「パケットサイズが `min(200, RecommendedMinProbeSize())` 以上」 #### [BitrateProber::RecommendedMinProbeSize()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h#70) - 一度に送信するプローブ用のデータサイズの推奨(最低)値を返すメソッド- 送信量がこれより少ないとプローブの結果の信頼度が下がるので、不足分は( [PacingController](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h) によって)パディングパケットで補填される - 計算式: `2 * ターゲット送信ビットレート * 1ms` #### [BitrateProber::NextProbeTime()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h#63) - プローブ用のパケット送信を次に行うべき時刻を返すメソッド - 状態が `kActive` ではない場合には `Timestamp::PlusInfinity()` が返される - `kActive` (かつクラスターキューが空ではない)場合には [BitrateProber::CalculateNextProbeTime()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h#103) によって事前に計算されていた、次回プローブ時刻、を返す private なメソッドである [BitrateProber::CalculateNextProbeTime()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h#103) は [BitrateProber::ProbeSent()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h#75) の中で呼び出され、 以下のようにして次回プローブ時刻を決定する: - 計算式: `クラスターでの送信開始時刻 + (クラスターで送信済みのサイズ合計 / ターゲットビットレート)`- 「送信開始時刻」はクラスターの生成時刻とは異なり、初めて実際にパケットが送信された時刻 - クラスター生成時に指定されたターゲットビットレート通りの送信ペースになるように設定された単純な式 - ターゲットビットレートに対して「送信量が多い場合には未来の時刻」になり、逆に「送信量が少ない場合には過去の時刻」になる #### [BitrateProber::ProbeSent()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h#75) [PacingController::ProcessPackets()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#197) の中で「実際に送信された合計パケットサイズ」を引数に取り呼び出されるメソッド。 処理の流れは以下の通り(キュー内の先頭のクラスターに対して適用される): - このクラスターでのパケット送信が初の場合には「送信開始時刻」を現在時刻に設定する - 「送信済みバイト数合計」に、今回の送信分を加算する - 「プローブ(用のデータ送信)回数」をインクリメントする - [BitrateProber::CalculateNextProbeTime()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h#103) を呼び出して、次のプローブ時刻を決定する - 以下の両方の条件を満たす場合には、プローブ処理を終えたものと判断し、クラスターをキューから除去する:- 「送信済みバイト数合計」が [BitrateProber::CreateProbeCluster()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h#58) で指定された規定値を超過した - 「プローブ回数」が [BitrateProber::CreateProbeCluster()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h#58) で指定された規定値を超過した - クラスターキューが空になった場合には、 [BitrateProber](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h) の状態を `kSuspended` に遷移する #### [BitrateProber::CurrentCluster()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h#66) 現在のプローブ処理を行なっているクラスターを返すメソッド。 基本的にはキューの先頭要素を返すだけだが、細々とした条件や処理がある。 - [BitrateProber](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h) の状態が `kActive` ではない場合には `null` を返す(クラスター生成直後は `kInactive` である可能性がある) - 「次のプローブ時刻(cf. [BitrateProber::CalculateNextProbeTime()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/bitrate_prober.h#103) )」が現在時刻に対して 10ms よりも前の場合には「そのクラスターには深刻な遅延が発生している」と判断する:- そのクラスターはキューから除去して、次のクラスターを返す - キューが空の場合には、状態を `kSuspended` に遷移した上で `null` を返す ### [PacingController](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h) の利用側クラスや呼び出しタイミング - [PacingController](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h) の各メソッドは直接外部から触られる訳ではなく [TaskQueuePacedSender](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/task_queue_paced_sender.h) が(ほぼ)同名のメソッドをラップして提供している- `EnqueuePackets()`, `SetPacingRates()`, `SetCongested()`, `Pause()`, `Resume()`, `CreateProbeClusters()`, etc - ただし [PacingController::ProcessPackets()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#197) に対応する [TaskQueuePacedSender::MaybeProcessPackets()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/task_queue_paced_sender.h#128) は外部に公開されていない- [TaskQueuePacedSender::MaybeProcessPackets()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/task_queue_paced_sender.h#128) は上述の各ラッパー関数の最後で呼び出される形となっている - このメソッドは [PacingController::NextSendTime()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#193) の結果などを考慮し、適宜 [PacingController::ProcessPackets()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#197) を呼び出す役目を担っている - [TaskQueuePacedSender](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/task_queue_paced_sender.h) が(ラップして)公開しているメソッド群を呼び出すのは、- `EnqueuePackets()` は、映像/音声を処理しているモジュールによって使用される - `SetPacingRates()`, `SetCongested()`, `createProbeClusters()`, `Pause()`, `Resume()` といったネットワークの帯域や状態に関連するメソッドは [RtpTransportControllerSend](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/call/rtp_transport_controller_send.h) クラスから呼び出される: - さらにこれらのメソッドは [RtpTransportControllerSend](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/call/rtp_transport_controller_send.h) クラスから呼び出される:- [RtpTransportControllerSend::PostUpdates()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/call/rtp_transport_controller_send.h#154)- [NetworkControlInterface](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/api/transport/network_control.h#59) の実装クラスの各メソッド呼び出し後に、その結果( [NetworkControlUpdate](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/api/transport/network_types.h#232) 構造体)を引数として呼び出されるメソッド - [NetworkControlUpdate](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/api/transport/network_types.h#232) 構造体には [PacerConfig](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/api/transport/network_types.h#201) や [PacerClusterConfig](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/api/transport/network_types.h#212), [TargetTransferRate](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/api/transport/network_types.h#220) といったペーサーに関係するフィールドが含まれている- これらのフィールドに変更があった場合には [TaskQueuePacedSender](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/task_queue_paced_sender.h) の `SetCongested()`, `SetPacingRates()`, `createProbeClusters()` などのメソッドが呼び出される - これによって [NetworkControlInterface](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/api/transport/network_control.h#59) を実装している輻輳制御や帯域推定を行なっているクラスが得たフィードバックが [PacingController](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h) に伝わることになる - [RtpTransportControllerSend::OnNetworkAvailability()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/call/rtp_transport_controller_send.h#100):- ネットワークの利用可能性が変わった時に呼び出されるコールバックメソッド - [TaskQueuePacedSender](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/task_queue_paced_sender.h) の `Pause()` および `Resume()` が必要に応じて呼び出される(ネットワークが利用不可になったなら前者、利用可能になったなら後者) ### ペーサーによって発生し得る遅延 おそらく以下のようなケースが考えられる: - [PacingController::SetPacingRates()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#165) で指定されたターゲットビットレートが小さ過ぎる場合:- [PacingController](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h) は一度キューに入ったパケットを破棄しない - そのため [PacingController::EnqueuePacket()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#133) で追加されるパケットのサイズ(ペース)が、そもそもそのターゲットビットレート内で送信可能な量を超えている場合には、キューが詰まり、遅延も増加していく - ただし、キュー内に存在するパケットの待機時間の平均値が 2 秒を超えそうな場合には、一時的に送信ビットレートを上げて、キューに無限に要素が増えないようにしようとする - 2 秒はデフォルト値で [PacingController::SetQueueTimeLimit()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#220) を使うことで変更が可能 - 映像パケットのサイズの振れ幅が大きい場合:- [PacingController](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h) が採用しているリーキーバケットアルゴリズムでは、一度に送信可能なサイズに上限がある - そのため「極端にサイズが大きい映像の I フレームを定期的に送信」といった場合には、全体としては余裕があって、その I フレームパケットの送信がペース調整されて一度に行えず、遅延が発生する可能性がある - これが問題となる場合には [PacingController::SetSendBurstInterval()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#161) といったメソッドで、ある程度のバースト送信を許容可能にすることができるので、これで緩和できる可能性がある ### 構成オプション フィールドトライアルやメソッド呼び出しなどによって挙動を以下のように変更することが可能(注意: 網羅的ではない): - プローブ処理の無効化 - 音声パケットをペース調整処理に含める(e.g. バジェットが不足している場合には即座に送信しない、バジェット計算の際に送信済み音声パケットサイズを考慮する) - 送信済みサイズの決定の際に、RTP / TCP / IP のヘッダー部分を考慮するかどうか(デフォルトでは RTP のペイロードサイズのみが使われる) - ある程度のバースト送信を許容する ( [PacingController::SetSendBurstInterval()](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/pacing_controller.h#161) )- 利用可能な送信帯域の総容量が増える訳ではないが、一時的に大きなパケット(e.g., 映像の I フレーム)が来た場合に、それを一気に送信することができるようになる - 送信キューの実装として [RoundRobinPacketQueue](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/round_robin_packet_queue.h) の代わりに [PrioritizedPacketQueue](https://webrtc.googlesource.com/src/+/06aea31d10f860ae4236e3422252557762d39188/modules/pacing/prioritized_packet_queue.h) を使用する # libwebrtc ミキサーのストリーム数上限 > **注意** > > この資料の正確性を保証しません。 > **重要** > > この資料についての問い合わせは Sora のサポート範囲には含まれません。 この資料は [libwebrtc M105 (5195)](https://webrtc.googlesource.com/src.git/+log/refs/branch-heads/5195) 時点の資料です。 このドキュメントでは libwebrtc での音声ミキサーの処理ストリームの上限について記載しています。 音声ミキサーは、複数の入力音声ストリームがある場合に、それらをまとめて一本のストリームとして出力する機能です。 ## 処理対象となる入力ストリーム数の上限値 ミキサーの処理対象となる入力ストリーム数の上限は [kDefaultNumberOfMixedAudioSources](https://webrtc.googlesource.com/src.git/+/42be4ae879ed6870dfc5ca554d11062b536da717/modules/audio_mixer/audio_mixer_impl.h#38) 定数によって定義されており、 値は 3 となっています。 この上限は [AudioMixerImpl::Create()](https://webrtc.googlesource.com/src.git/+/42be4ae879ed6870dfc5ca554d11062b536da717/modules/audio_mixer/audio_mixer_impl.h#40) メソッドの引数に別の値を指定することで変更できます。 ## 処理対象入力ストリームの選択方法 ミキサーの処理対象となる入力ストリームの選択は [AudioMixerImpl::GetAudioFromSources()](https://webrtc.googlesource.com/src.git/+/42be4ae879ed6870dfc5ca554d11062b536da717/modules/audio_mixer/audio_mixer_impl.cc#198) メソッドで行われます。 選択手順の概要は以下の通りです: 1. 全ての入力音声ストリームを集める 2. それらを [ShouldMixBefore()](https://webrtc.googlesource.com/src.git/+/42be4ae879ed6870dfc5ca554d11062b536da717/modules/audio_mixer/audio_mixer_impl.cc#74) 関数を使ってソートする- この関数は音声ストリーム同士の音量を比較し、音の大きい方が前に配置されるようにする 3. ソート結果の先頭から上限値に達するまでストリームを選択する- ただし、ミュート状態のストリームは常に対象外となる ## 処理対象入力ストリームが入れ替わった場合の挙動 処理対象となる入力ストリーム一覧は、各ストリームの音量やミュート状態の変化、 あるいはストリーム自体の増減によって変化します。 その際に、処理対象に新しく追加されたストリームの最初の音声フレームは、ゲイン(各サンプルに乗算される重み) を調整することで、徐々に音が大きくなっていくように処理されています。 具体的には libwebrtc での音声フレームは 10ms 区切りとなっていますが、 そのフレーム内の先頭サンプルでは 0.0 (無音)から初めて、末尾サンプルでは 1.0 となるように、 段階的にゲインを増やすという処理が適用されます。 これらの処理は [RampAndUpdateGain()](https://webrtc.googlesource.com/src.git/+/42be4ae879ed6870dfc5ca554d11062b536da717/modules/audio_mixer/audio_mixer_impl.cc#89) メソッドや [Ramp()](https://webrtc.googlesource.com/src.git/+/42be4ae879ed6870dfc5ca554d11062b536da717/modules/audio_mixer/audio_frame_manipulator.cc#35) 関数によって実装されています。 なお [RampAndUpdateGain()](https://webrtc.googlesource.com/src.git/+/42be4ae879ed6870dfc5ca554d11062b536da717/modules/audio_mixer/audio_mixer_impl.cc#89) メソッド自体は、ストリームが対象から外れた場合(この場合はゲインが 1.0 から 0.0 に減少していく)も考慮された実装となっています。 ただし、このメソッドの呼び出しもとの実装的に、初回追加時にのみゲイン調整が行われます (一度対象から外れた後に再度追加された場合もゲイン処理の適用外となります)。 # Microsoft Edge の WebRTC について ## 概要 2022 年 12 月 時点で Microsoft Edge 108 を使用して確認しています。 [Download New Microsoft Edge Browser | Microsoft](https://www.microsoft.com/en-us/edge) ## 現状 Chrome とほぼ同様の仕様で、特に問題なく動作します。 ## 注意点 - Edge では AV1 が動作しません # Apple Safari の WebRTC について ## 概要 2022 年 12 月時点で Safari 16.2 を使用して確認しています。 ## 注意点 - 音声が含まれているまたは音声のみの配信の場合 iOS の Safari では自動再生されません- これは iOS の Safari の仕様のため、今のところ回避の方法はありません - macOS の Safari の場合も設定を有効にしないと同様です - Certificate Management API に非対応です- ECDSA P256 使えません - onaddstream ではなく ontrack を利用してください - 映像コーデック VP9 は対応していますが、古い iPhone では動作しなかったりします - getUserMedia を利用するには HTTPS が必須です- 開発モードで HTTPS 必須を無効にすることが可能です ## iOS の Chrome や Firefox について iOS の Chrome や Firefox は WKWebView を利用しています。 WKWebView は iOS 14.3 にて getUserMedia に対応しました。 ## iOS Safari で画面共有について iOS Safari には画面共有用の getDisplayMedia API が実装されていません。 そのため、画面共有を利用するにはネイティブアプリケーションを利用する必要があります。 2022 年 6 月時点ですべてのモバイルブラウザが getDisplayMedia API には対応していません。 [MediaDevices.getDisplayMedia() - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia#browser_compatibility) ## WebRTC Encoded Transform API が利用可能 Safari では [WebRTC Encoded Transform](https://www.w3.org/TR/webrtc-encoded-transform/) API が利用可能です。 > **重要** > > Chrome に実装されているのは WebRTC Encoded Transform API の古いバージョンである Insertable Streams API です。 > そのため WebRTC Encoded Transform に関しては Safari が最先端となります。 ## Safari Technology Preview ### H.265 が利用可能 Safari Technology Preview (Safari TP) で開発メニューで有効にすることで H.265 が利用可能です。 ![image](https://i.gyazo.com/74f321ba4fc25a90b004965046469b25.png) 現在 H.265 を WebRTC で利用できるのは唯一 Safari TP のみのため、 Safari TP 同士でしか検証できません。 ### WebRTC AV1 が利用可能 Safari Technology Preview (Safari TP) 最新版では開発メニューで有効にすることで WebRTC AV1 が利用可能です。 ![image](https://i.gyazo.com/03c913191a36e8f06640561527dd0936.png) # nginx > **注意** > > nginx の設定に関する質問については Sora のサポート範囲外となります。 **この設定はある程度の nginx や証明書の知識が必要になります** ## 概要 Sora のシグナリングを暗号化する場合に何かしらのサーバーを立てる必要があります。 ここでは nginx での設定例を紹介しています。 ## 設定例 nginx.conf の http ディレクティブに include を使用した場合の設定例です。 `ssl_*` 関連の設定は済んでいる前提とします。 ```nginx server { listen 443 ssl default_server; index index.html; server_name sora.example.com; # Sora のシグナリング に Proxy します location = /signaling { proxy_pass http://127.0.0.1:5000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } # Sora の HTTP API に Proxy します # 本番環境では認証などの機能を利用してください location /api { proxy_pass http://127.0.0.1:3000/; } # Sora の開発ツールに Proxy します # 本番環境では不要です location / { proxy_pass http://127.0.0.1:5000; } } ``` ## TURN を含んだ設定 TURN 関連は [本番稼働に向けて](PRODUCTION.html) にある資料を確認してください。 [TURN-TLS、TURN-TCP、シグナリングで 443 番ポートを使用する](PRODUCTION.html#14258d) # HLS 配信 > **重要** > > このドキュメントに書かれている FFmpeg に関する事柄についてはサポート対象外ですのでご注意ください > **警告** > > このドキュメントはとても古いため参考程度にしてください ## 概要 Sora の RTP 転送 API と FFmpeg を利用することで、HTTP Live Streaming(以下 HLS)で配信することが可能です。 ### おすすめ WebRTC to HLS は大変なので、是非サービスをご検討ください。 [ライブ配信サービス ImageFlux Live Streaming|さくらインターネット](https://www.sakura.ad.jp/services/imageflux/livestreaming/) ## 検証したバージョン > **警告** > > このドキュメントで確認している FFmpeg のバージョンはかなり古いため参考程度にしてください **FFmpeg のバージョン**: 3.3.3 ## 配信例 下記の例では、RTP 転送 API の応答で送られてきた SDP を FFmpeg に読み込ませることで、 Sora から送られてきた RTP パケットを受信して H.264/MP3 の TS ファイルで出力しています。 配信時は、この時同時に作成/更新されているプレイリスト(m3u8 ファイル)を TS ファイルと一緒に Web サーバーで公開します。 変換例: ``` #!/bin/bash CHANNEL_ID=sora VIDEO_PORT=60001 # VIDEO_PORT + 1 は RTCP の待ち受けで使用されるため空けておく # また、AUDIO_PORT + 1 も RTCP の待ち受けで使用される AUDIO_PORT=$(( $VIDEO_PORT + 2 )) VIDEO_CODEC=libx264 AUDIO_CODEC=libmp3lame QUEUE_SIZE=4000 start_forwarding_rtp() { data=$( jq -n -c --arg channel_id $CHANNEL_ID --argjson video_port $VIDEO_PORT \ --argjson audio_port $AUDIO_PORT \ '{"channel_id":$channel_id, "ip_address":"127.0.0.1", "video_port":$video_port, "audio_port":$audio_port}' ) curl -Ssf -X POST \ -H "x-sora-target:Sora_20170814.StartForwardingRtp" \ -d $data \ 127.0.0.1:3000 } json=$( start_forwarding_rtp ) sdp=$( echo $json | jq -r .sdp ) echo "$sdp" | ffmpeg \ -loglevel fatal \ -protocol_whitelist file,rtp,udp,pipe \ -i pipe:0 \ -c:v $VIDEO_CODEC \ -c:a $AUDIO_CODEC \ -map 0 \ -flags -global_header \ -max_muxing_queue_size $QUEUE_SIZE \ -f hls \ -hls_segment_type mpegts \ -hls_flags append_list \ -hls_list_size 0 \ -hls_segment_filename index%d.ts \ index.m3u8 ``` ブラウザにアクセスさせる HTML の video タグにはプレイリストを指定します。 例: ``` HLS
``` # お勧めのカメラとスピーカーフォン ## カメラ ロジクールが安定して、画質も良いです。 ### Logicool 色々種類が出ていますが、予算があれば StreamCam をおすすめします。 - [ロジクールStreamCam - フルHDストリーミング ウェブカメラ](https://www.logicool.co.jp/ja-jp/products/webcams/streamcam.html) 予算がそこまで無い場合は C922n をおすすめします。 - [C922n PRO HDストリーム ウェブカメラ](https://www.logicool.co.jp/ja-jp/products/webcams/c922n-pro-stream-webcam.960-001262.html) ## スピーカーフォン 予算に余裕があれば YAMAHA をおすすめします。 ### YAMAHA 会議室に置くなら YVC-330 で、自宅で利用するなら YVC-200 が良いです。 - [YVC-200 特長](https://sound-solution.yamaha.com/products/uc/yvc-200/index)- 1-4 人向け - [YVC-330 特長](https://sound-solution.yamaha.com/products/uc/yvc-330/index)- 4-6 人向け - [YVC-1000 特長](https://sound-solution.yamaha.com/products/uc/yvc-1000/index)- 8-40 人向け # オープンソースライセンス **WebRTC SFU Sora で利用しているオープンソースのライセンス一覧** [erlang/otp: Erlang/OTP](https://github.com/erlang/otp): ``` http://www.apache.org/licenses/LICENSE-2.0 ``` [openssl/openssl: TLS/SSL and crypto library](https://github.com/openssl/openssl): ``` http://www.apache.org/licenses/LICENSE-2.0 ``` [uwiger/parse_trans: Parse transform utilities for Erlang](https://github.com/uwiger/parse_trans): ``` http://www.apache.org/licenses/LICENSE-2.0 ``` [uwiger/gproc: Extended process registry for Erlang](https://github.com/uwiger/gproc): ``` http://www.apache.org/licenses/LICENSE-2.0 ``` [ninenines/cowboy: Small, fast, modern HTTP server for Erlang/OTP.](https://github.com/ninenines/cowboy): ``` Copyright (c) 2011-2017, Loïc Hoguin Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ``` [ninenines/cowlib: Support library for manipulating Web protocols.](https://github.com/ninenines/cowlib): ``` Copyright (c) 2013-2020, Loïc Hoguin Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ``` [ninenines/ranch: Socket acceptor pool for TCP protocols.](https://github.com/ninenines/ranch): ``` Copyright (c) 2011-2020, Loïc Hoguin Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ``` [ninenines/gun: HTTP/1.1, HTTP/2 and Websocket client for Erlang/OTP.](https://github.com/ninenines/gun): ``` Copyright (c) 2013-2020, Loïc Hoguin Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ``` [sile/jsone: Erlang JSON library](https://github.com/sile/jsone): ``` The MIT License Copyright (c) 2013-2016 Takeru Ohta Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ``` [benoitc/hackney: simple HTTP client in Erlang](https://github.com/benoitc/hackney): ``` http://www.apache.org/licenses/LICENSE-2.0 ``` [benoitc/unicode_util_compat: unicode_util compatibility library for Erlang < 20](https://github.com/benoitc/unicode_util_compat): ``` http://www.apache.org/licenses/LICENSE-2.0 ``` [benoitc/erlang-idna: Erlang IDNA lib](https://github.com/benoitc/erlang-idna): ``` Copyright the authors and contributors. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ``` [deadtrickster/ssl_verify_fun.erl: Collection of ssl verification functions for Erlang](https://github.com/deadtrickster/ssl_verify_fun.erl): ``` The MIT License (MIT) Copyright (c) 2014 Ilya Khaprov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ``` [certifi/erlang-certifi: SSL Certificates for Erlang](https://github.com/certifi/erlang-certifi): ``` Copyright (c) 2015, Benoit Chesneau . All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * The names of its contributors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ``` [benoitc/mimerl: library to handle mimetypes](https://github.com/benoitc/mimerl): ``` 2015 (c) Benoit Chesneau 2013-2015 (c) Loïc Hoguin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ``` [benoitc/erlang-metrics: A generic interface to different metrics systems in Erlang.](https://github.com/benoitc/erlang-metrics): ``` Copyright (c) 2016, benoitc . All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * The names of its contributors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ``` [ferd/recon: Collection of functions and scripts to debug Erlang in production.](https://github.com/ferd/recon): ``` Copyright (c) 2012-2017, Frédéric Trottier-Hébert All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. The names of its contributors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ``` [for-GET/jesse: jesse (JSon Schema Erlang) is an implementation of a JSON Schema validator for Erlang.](https://github.com/for-GET/jesse): ``` http://www.apache.org/licenses/LICENSE-2.0 ``` [talentdeficit/rfc3339: an erlang/elixir rfc3339 lib](https://github.com/talentdeficit/rfc3339): ``` http://www.apache.org/licenses/LICENSE-2.0 ``` [talentdeficit/jsx: an erlang application for consuming, producing and manipulating json. inspired by yajl](https://github.com/talentdeficit/jsx): ``` The MIT License Copyright (c) 2010-2013 alisdair sullivan Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ``` [rabbitmq/ra: A Raft implementation for Erlang and Elixir](https://github.com/rabbitmq/ra): ``` http://www.apache.org/licenses/LICENSE-2.0 ``` [rabbitmq/gen-batch-server: A generic batching server for Erlang and Elixir](https://github.com/rabbitmq/gen-batch-server): ``` http://www.apache.org/licenses/LICENSE-2.0 ``` [rabbitmq/aten: An adaptive accrual node failure detection library for Elixir and Erlang](https://github.com/rabbitmq/aten): ``` http://www.apache.org/licenses/LICENSE-2.0 ``` [rabbitmq/seshat](https://github.com/rabbitmq/seshat): ``` http://www.apache.org/licenses/LICENSE-2.0 ``` [shiguredo/swidden: ヘッダーベース HTTP API フレームワーク](https://github.com/shiguredo/swidden): ``` http://www.apache.org/licenses/LICENSE-2.0 ``` [shiguredo/kvconf](https://github.com/shiguredo/kvconf): ``` http://www.apache.org/licenses/LICENSE-2.0 ``` [shiguredo/base32_clockwork: Base32 (RFC 4648, Crockford)](https://github.com/shiguredo/base32_clockwork): ``` http://www.apache.org/licenses/LICENSE-2.0 ``` [shiguredo/crdt: Conflict-free Replicated Data Types in Erlang/OTP.](https://github.com/shiguredo/crdt): ``` http://www.apache.org/licenses/LICENSE-2.0 ``` [shiguredo/sora-devtools: Sora DevTools](https://github.com/shiguredo/sora-devtools): ``` http://www.apache.org/licenses/LICENSE-2.0 ``` [shiguredo/redbug: erlang tracing debugger](https://github.com/shiguredo/redbug): ``` MIT License Copyright (c) 2016 mats cronqvist Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ``` # 古いリリースノート **UPDATE** : 後方互換性がある変更 **ADD** : 後方互換性がある追加 **CHANGE** : 後方互換性のない変更 **FIX** : バグ修正 ## 2021.2.8 **リリース**: 2022-04-11 **対応 Chrome**: M98 以降 **対応 Firefox**: 97 以降 **対応 Safari**: 15.3 以降 **対応 Edge**: 98 以降 ### 変更履歴 - [FIX] 依存ライブラリ OpenSSL を 1.1.1n にアップデートしました ## 2021.2.7 **リリース**: 2022-02-24 **対応 Chrome**: M98 以降 **対応 Firefox**: 97 以降 **対応 Safari**: 15.3 以降 **対応 Edge**: 98 以降 ### 変更履歴 - [CHANGE] 録画失敗時でも一時ファイルを削除しないようにしました - [FIX] PauseRtpStream API がイベントウェブフック connection.created を受け取ったタイミングで実行しても正常に動作しない問題を修正しました - [FIX] 録画ファイル分割出力のみの場合でも、一時ファイルが録画終了時まで削除されずに残っていた問題を修正しました ## 2021.2.1 **リリース**: 2021-12-20 **対応 Chrome**: M97 以降 **対応 Firefox**: 95 以降 **対応 Safari**: 15.1 以降 **対応 Edge**: 97 以降 - [FIX] 録画機能利用時に `sora.conf` の [archive_tmp_dir](SORA_CONF.html#4d75ea) と [archive_dir](SORA_CONF.html#ad2156) で指定される 2 つのディレクトリが異なるファイルシステムにある場合に、録画ファイルの生成に失敗する問題を修正しました ## 2021.2.0 **リリース**: 2021-12-15 **対応 Chrome**: M97 以降 **対応 Firefox**: 95 以降 **対応 Safari**: 15.1 以降 **対応 Edge**: 97 以降 ### ハイライト - クラスター機能を追加しました - DataChannel を利用したメッセージング機能を追加しました - 統計エクスポーター機能を追加しました - スポットライト機能のフォーカス/アンフォーカスを変更する API を追加しました - ICE コネクションステート機能を追加しました - シグナリング通知に録画開始/終了の通知を追加しました - セッションウェブフックを追加しました - 音声冗長化機能に対応しました - AV1 コーデック利用時の録画に対応しました ### 廃止情報 - CentOS 8 への対応を終了しました- 詳細は [CentOS 8 対応](OBSOLETE.html#14536f) をご確認ください - スポットライトレガシー機能を廃止しました- 詳細は [スポットライトレガシー機能の廃止](OBSOLETE.html#9bb8f9) をご確認ください - 統計機能の `rtp` にある `rtcp` を廃止しました- 詳細は [rtp にある RTCP 関連統計情報を廃止](OBSOLETE.html#4d430c) をご確認ください - `sora.conf` の `extmap_allow_mixed` 設定を廃止しました- 詳細は [extmap_allow_mixed 設定のデフォルト有効化と廃止](OBSOLETE.html#6099d7) をご確認ください - `sora.conf` の `dcsctp_association_max_retrans` 設定を廃止しました- 詳細は [sora.conf の dcsctp_association_max_retrans を廃止](OBSOLETE.html#63d7f7) をご確認ください - 実験的機能である `sora.conf` の `opus_param_clock_rate` 設定を廃止しました - [ListAllConnections](OBSOLETE_API.html#7a9c4e) API を廃止しました- 今後は [ListConnections](API.html#d3da2a) API をご利用ください。 - [ListChannelClients](OBSOLETE_API.html#a65eee) API を廃止しました- 今後は [ListChannelConnections](API.html#d388f3) API をご利用ください ### 互換性なしの変更情報 **変更点の不明点についてはサポートまでお問い合わせください** **猶予期間を儲けない変更となっておりますのでご注意ください** - [ListConnections](API.html#d3da2a) API の戻り値に含まれる `connection_created_timestamp_sec` の項目名を `created_time` に変更、単位を秒からマイクロ秒に変更しております - [ListChannelConnections](API.html#d388f3) API の戻り値に含まれる `connection_created_timestamp_sec` の項目名を `created_time` に変更しており、単位を秒からマイクロ秒に変更しております ### 変更履歴 - [CHANGE] `connection.log` のタイムスタンプを秒からマイクロ秒に変更しました - [CHANGE] Chrome 側の破壊的変更により Chrome M95 以前の AV1 への対応を廃止しました- AV1 を利用する場合は Chrome M96 以降をご利用ください - [ADD] `sora.conf` に TURN-TCP で Allocate-Success を遅延させる [turn_tcp_allocate_success_delay_time](SORA_CONF.html#60d922) を追加しました- デフォルトは `100 ms` です - 0-1000 ms の範囲で指定可能です - [ADD] Sora 起動時に Sora のバージョンが INFO レベルで `sora.log` に出力されるようになりました- `2021-12-15 12:34:56.789 UTC [info] [-/-/-] <0.235.0> SORA | node_name=sora@127.0.0.1, version=2021.2.0` #### 移行 - [CHANGE] `sora.conf` の `use_re_offer` が `true` の場合 `type: update` を Sora に送るとエラーになるよう変更しました - [CHANGE] `sora.conf` の `use_re_offer` のデフォルト値を `true` に変更しました- この設定は 2022 年 6 月リリース予定の Sora にて廃止します - [CHANGE] `sora.conf` の `unuse_metadata_list` のデフォルト値を `true` に変更しました- この設定は 2022 年 6 月リリース予定の Sora にて廃止します #### 開発ツール - [CHANGE] デモ機能を **開発ツール** と名前を変更しました - [CHANGE] `sora.conf` の `demo` を `true` にした場合 [devtools](SORA_CONF.html#086a45) が有効になるように変更しました- `sora.conf` の `demo` は 2022 年 6 月のリリースにて廃止します - 詳細は [sora.conf の demo の廃止](OBSOLETE.html#12e7c9) をご確認ください - [ADD] `sora.conf` に [devtools](SORA_CONF.html#086a45) を追加しました- デフォルトは `false` です #### ウェブフック - [ADD] 認証ウェブフックに `node_name` を追加しました - [ADD] イベントウェブフックに `node_name` を追加しました - [ADD] イベントウェブフックの `recording.report` に `filename` と `file_path` を追加しました- `metadata_filename` と `metadata_file_path` は 2022 年 12 月リリース予定の Sora で廃止します - 廃止対象は JSON 内の `"data"` 直下のフィールドのみで、 `"archives"` 以下にある`metadata_filename` と `metadata_file_path` は変更ありません #### セッションウェブフック 詳細は [セッションウェブフック](SESSION_WEBHOOK.html) をご確認ください。 - [ADD] `sora.conf` にセッションウェブフックの URL を指定する [session_webhook_url](SORA_CONF.html#76fa79) を追加しました - [ADD] `sora.conf` にセッション作成時のタイムアウトを指定する [session_created_timeout](SORA_CONF.html#20c8c6) を追加しました- デフォルトは `5 s` です - [ADD] `sora.conf` に セッション破棄時のタイムアウトを指定する [session_destroyed_timeout](SORA_CONF.html#642cc4) を追加しました- デフォルトは `15 s` です - [ADD] `session.created` セッションウェブフックを追加しました- セッションが作成されたタイミングで送信します - [ADD] `session.destroyed` セッションウェブフックを追加しました- セッションが破棄されたタイミングで送信します - [ADD] `session.vanished` セッションウェブフックを追加しました- `block_new_connection` または `block_new_session` モード時に全てのセッションが破棄されたタイミングで送信します - [ADD] `sora.conf` に `session.vanished` をウェブフックリクエストとして送信しない [ignore_session_vanished_webhook](SORA_CONF.html#85718d) を追加しました- デフォルトは `true` です - [ADD] セッションウェブフックリクエスト送信時の HTTP ヘッダーに `x-sora-session-webhook-type` を追加しました- ヘッダーの値は `type` の値が入ります - [ADD] セッションウェブフックのログを出力する `log/session_webhook.log` を追加しました - [ADD] セッションウェブフックの失敗ログを出力する `log/session_webhook_failed.log` を追加しました - [ADD] [GetStatsReport](EXPERIMENTAL_API.html#bbbfca) API に合計セッション作成回数 `total_session_created` を追加しました - [ADD] [GetStatsReport](EXPERIMENTAL_API.html#bbbfca) API に合計セッション破棄回数 `total_session_destroyed` を追加しました #### モード機能 詳細は [モード機能](MODE.html) をご確認ください。 - [ADD] 新規セッションやコネクションを受け付けなくするモードの仕組みを追加しました- 初期値は `normal` です - `sora.conf` にて `cluster` を有効にしたときの初期値は `block_new_connection` です - [ADD] モードを切り替える `ChangeMode API` を追加しました- `"mode": "normal"` を指定するとすべての新規コネクションを受け付けます - `"mode": "block_new_session"` を指定することで新規セッションをブロックすることが可能です - `"mode": "block_new_connection"` を指定することで新規コネクションをブロックすることが可能です - [ADD] 現在のモードを取得する `GetMode API` を追加しました #### クラスター機能 詳細は [クラスター機能](CLUSTER.html) をご確認ください。 - [ADD] クラスター機能利用時にどのノードへも接続ができない場合 `NO-ACCEPTABLE-NODE` を出力するようにしました - [ADD] 複数 Sora でクラスターを構築し、冗長化する機能を追加しました - [ADD] クラスター機能利用時に新規のチャネルへの接続する際、同時接続に余裕のある Sora ノードに割り当てる機能を追加しました - [ADD] クラスター機能利用時に既存のチャネルへの接続する際、そのチャネルへの接続が存在する Sora ノードに割り当てる機能を追加しました - [ADD] シグナリング接続時に別の Sora ノードにリダイレクトする `"type": "redirect"` を追加しました- リダイレクト先のシグナリング URL が `"location": "wss://node01.example.com/signaling"` に含まれます - [ADD] リダイレクト先のシグナリング URL を利用する際に `"redirect": true` を `"type": "connect"` に追加できるようにしました - [ADD] sora.conf にクラスター利用時にリダイレクトに利用する `cluster_signaling_url` の設定を追加しました- `cluster_signaling_url = wss://node01.example.com/signaling` - [ADD] sora.conf にクラスター利用時の Sora ノード名を指定する `cluster_node_name` の設定を追加しました- `cluster_node_name = node01@192.0.2.10` - [ADD] sora.conf にクラスター利用時に API URL を指定する `cluster_api_url` の設定を追加しました- `cluster_api_url = https://node01.example.com/` - [ADD] sora.conf にクラスター利用時のノード間通信に使用するポート番号を指定する [cluster_listen_min_port](SORA_CONF.html#7aa8c7) と [cluster_listen_max_port](SORA_CONF.html#354463) の設定を追加しました- デフォルトは [cluster_listen_min_port](SORA_CONF.html#7aa8c7) が `49010` で、 [cluster_listen_max_port](SORA_CONF.html#354463) が `49020` です - [ADD] クラスターに参加するための [JoinCluster](EXPERIMENTAL_API.html#17f3f5) API を追加しました- クラスターからの離脱は `bin/sora stop` で可能です - [ADD] クラスターに参加しているノード一覧を取得するための [ListClusterNodes](EXPERIMENTAL_API.html#a70901) API を追加しました - [ADD] クラスターに割り当てられているチャネル ID 一覧を取得するための [ListClusterChannels](EXPERIMENTAL_API.html#0a4459) API を追加しました #### 音声冗長化機能 **この機能は Chrome 96 以降で利用可能です** - [ADD] `sora.conf` に 音声冗長化機能を有効にする `audio_red` を追加しました。- デフォルトは `false` です - 音声冗長化についての詳細は[PSA: opus+red enabled by default in M96](https://groups.google.com/g/discuss-webrtc/c/5761etCrSuA/m/VrbQL3_LBwAJ) を参照ください - [ADD] 1 チャネルへの接続が `audio_red` への対応が混在していてもやりとりできるようにしました。 #### 録画機能 - [ADD] AV1 の録画に対応しました- この機能は Chrome 96 以降で利用可能です - [ADD] [StartRecording](API.html#c5b527) API にて `metadata` を指定可能にしました- `metadata` は JSON オブジェクトである必要があります - `metadata` はオプションです - [ADD] `recording.report` や録画メタデータファイルに [StartRecording](API.html#c5b527) API で指定した `metadata` を出力するようにしました- 指定しなければ `metadata` が出力されません - [ADD] シグナリング通知を利用している場合、録画開始時に ["event_type": "recording.started"](SIGNALING_NOTIFY.html#7698a8) が通知されるようになりました - [ADD] シグナリング通知を利用している場合、録画終了時に ["event_type": "recording.stopped"](SIGNALING_NOTIFY.html#421054) が通知されるようになりました - [ADD] `sora.conf` に録画関連をシグナリング通知で送信するかどうかを指定する [signaling_notify_recording](SORA_CONF.html#cfe368) を追加しました #### 統計エクスポーター機能 クライアントから送られてきた統計情報を HTTP/2 経由で外部へ出力する機能です。 詳細は [統計エクスポーター機能](STATS_EXPORTER.html) をご確認ください。 - [ADD] `sora.conf` に統計エクスポーターの接続先を指定する [stats_collector_url](SORA_CONF.html#98b67f) を追加しました- `stats_collector_url = http://h2c.example.com:5890/collector` - `stats_collector_url = https://h2.example.com/collector` - [ADD] 統計コレクターへ送信時の HTTP ヘッダーに `x-sora-stats-exporter-type` を追加しました- ヘッダーの値は `type` の値が入ります - [ADD] `sora.conf` に統計エクスポーターの数を指定する [stats_exporter_number](SORA_CONF.html#a047ec) を追加しました- デフォルトは `5` です - [ADD] `sora.conf` に [stats_exporter_tls_fullchain_file](SORA_CONF.html#9f17b8) を追加しました - [ADD] `sora.conf` に [stats_exporter_tls_privkey_file](SORA_CONF.html#20eda2) を追加しました - [ADD] `sora.conf` に [stats_exporter_tls_verify_cacert_file](SORA_CONF.html#bcd961) を追加しました - [ADD] 頻繁に送らない項目を定義しました- 1 h に 1 回送ります - codec / local-candidate / remote-candidate / certificate / peer-connection / track-stream #### スポットライト機能 フォーカス/アンフォーカス挙動変更 API を追加しました。 - [ADD] スポットライトのフォーカス/アンフォーカス挙動を変更する [RequestSpotlightRid](API.html#5c2650) API` を追加しました - [ADD] スポットライトのフォーカス/アンフォーカス挙動をリセットする [ResetSpotlightRid](API.html#680344) API を追加しました - [ADD] スポットライトのフォーカス/アンフォーカス挙動を一括で変更する [BatchRequestSpotlightRid](API.html#a2e06c) API を追加しました #### ICE コネクションステート機能 詳細は [ICE コネクションステート機能](ICE_CONNECTION_STATE.html) をご確認ください。 - [ADD] `sora.conf` に [ice_connection_state_disconnected_timeout](SORA_CONF.html#3a2e9b) を追加しました- デフォルトは `5 s` です - [ADD] `sora.conf` に [ice_connection_state_failed_timeout](SORA_CONF.html#7484a4) を追加しました- デフォルトは `10 s` です - [ADD] `sora.log` に warning で `ICE-CONNECTION-DISCONNECTED` が出力されるようになりました- `1000 ms` 間隔で 5 秒間 `STUN Binding-Request` を送っても 1 度も `STUN Binding-Success` が返ってこない場合に出力されます - `1000 ms` は `sora.conf` の [ice_connection_state_disconnected_timeout](SORA_CONF.html#3a2e9b) にて変更可能です - [ADD] `sora.log` に `error` で `ICE-CONNECTION-FAILED` が出力されるようになりました- この場合 Sora は接続を切断します - `50 ms` 間隔で 10 秒間 `STUN Binding-Request` を送っても 1 度も `STUN Binding-Success` が返ってこない場合に出力されます - `50 ms` は `sora.conf` の [ice_connection_state_failed_timeout](SORA_CONF.html#7484a4) にて変更可能です #### DataChannel 機能 - [CHANGE] 利用しない DataChannel を作成しない仕組みを追加しました- `sora.conf` の [signaling_notify](SORA_CONF.html#d88348) が無効の場合は `label: notify` の DataChannel は作成しません - `sora.conf` の [e2ee](SORA_CONF.html#3dddc6) が無効の場合は `label: e2ee` の DataChannel は作成しません - `sora.conf` の [user_agent_stats](SORA_CONF.html#b8b6ef) が無効の場合は `label: stats` の DataChannel は作成しません - [CHANGE] `dcsctp_association_max_retrans` を廃止しました- 切断判定には ICE コネクションステート機能が利用されます #### メッセージング機能 詳細は [メッセージング機能](MESSAGING.html) をご確認ください。 DataChannel を利用したメッセージをユーザーが提起して自由に送ることができる機能です。ラベルは `#` から始まる必要があります。 - [ADD] `type: connect` に `data_channels` を追加しました- メッセージ機能は `[{"label": "#abc", "direction": "sendrecv"}, ...]` で指定可能です - メッセージのラベルを指定する `label` を追加しました- `^#[a-zA-Z0-9][a-zA-Z0-9-]{1,30}$` - メッセージのメッセージの方向を指定する `direction` を追加しました- `sendrecv` / `sendonly` / `recvonly` のどれかを指定して下さい - 方向はクライアントから見た視点で `role` と同様です - メッセージの順番を指定する [ordered](MESSAGING.html#17e8c5) を追加しました- デフォルトは `true` です - メッセージのリトライ時間を指定する [max_packet_life_time](MESSAGING.html#3b5bc1) を追加しました- デフォルト指定無しです - 単位はミリ秒です - メッセージのリトライ回数を指定する [max_retransmits](MESSAGING.html#02a10a) を追加しました- デフォルト指定無しです - メッセージの圧縮を指定する [compress](MESSAGING.html#fbaa9b) を追加しました- デフォルトは `false` です - [ADD] `sora.conf` に [data_channel_messaging](SORA_CONF.html#1d5746) を追加しました- デフォルトは `false` です - [ADD] 認証成功時の払い出しで `data_channels` を指定できるようにしました- `"type": "connect"` 時に、指定された `data_channels` を上書きできます - [ADD] `sora.conf` に [data_channel_messaging_only](SORA_CONF.html#93c61c) を追加しました- デフォルトは `false` です #### ユーザーエージェント統計 API リモート統計情報 API の名前を変更し整理した API です。 リモート統計情報 API は 2022 年 6 月リリースの Sora にて廃止しますので、 ユーザーエージェント統計情報 API に切り替えをお願いします。 - [CHANGE] `remote_stats` をデフォルト `false` にしました - [ADD] `sora.conf` に `user_agent_stats` を追加しました- デフォルトは `true` です - `remote_stats` は 2022 年 6 月にて廃止されます - [ADD] [ListUserAgentStats](EXPERIMENTAL_API.html#f9a4fe) API を追加しました- [GetAllRemoteStats](OBSOLETE_API.html#3a6504) の代替 API です - [ADD] [ListChannelUserAgentStats](EXPERIMENTAL_API.html#df496a) API を追加しました- [GetChannelRemoteStats](OBSOLETE_API.html#bbd252) の代替 API です - [ADD] [GetUserAgentStats](EXPERIMENTAL_API.html#a078ba) API を追加しました- [GetConnectionRemoteStats](OBSOLETE_API.html#2f926d) の代替 API です ## 2021.1.4 **リリース**: 2021-10-29 **対応 Chrome**: M95 以降 **対応 Firefox**: 93 以降 **対応 Safari**: 15.1 以降 **対応 Edge**: 95 以降 ### 変更履歴 - [FIX] ネットワークが不安定な場合に録画が失敗する問題を修正しました - [FIX] Safari を利用した場合に特定条件で復号が失敗する問題を修正しました ## 2021.1.2 **リリース**: 2021-09-17 **対応 Chrome**: M93 以降 **対応 Firefox**: 92 以降 **対応 Safari**: 14.1 以降 **対応 Edge**: 93 以降 ### 変更履歴 - [UPDATE] デモ機能で利用している sora-demo を 2021.1.6 にアップデートしました - [ADD] 切断 API の `reason` を指定した場合に、指定した `reason` が、イベントウェブフック `connection.destroyed` に `disconnect_api_reason` として含まれるようになりました- 今まで `reason` として入ってきていたのと同じ値が入ります - [ADD] `"type": "disconnect"` に `reason` を指定した場合に、指定した `reason` が、イベントウェブフック `connection.destroyed` に `type_disconnect_reason` として含まれるようになりました - [ADD] イベントウェブフック `connection.*` の `data` に `"created_time": "connection.created 時の UNIX 時刻"` を追加しました - [ADD] `sora.conf` にスポットライトでフォーカスされた後、一定時間追い出されなくなる [default_spotlight_focus_min_interval](SPOTLIGHT.html#966f51) を追加しました- デフォルトは `2000 ms` です - [FIX] スポットライト機能で複数人が音を出し続けていると頻繁にフォーカスが入れ替わる問題を修正しました- アンフォーカス後のフォーカスは、最低でも [default_spotlight_delayed_focus_interval](SPOTLIGHT.html#794eec) だけ待つようになりました - [FIX] スポットライト機能でアンフォーカスからフォーカスに変わるタイミングで音声や映像が配信されなくなる場合がある問題を修正しました - [FIX] スポットライト機能で自動アンフォーカスが指定した時間よりも速く行われる問題を修正しました - [FIX] IPv6 のみで正常に接続できない場合がある問題を修正しました - [FIX] クライアントから `"type": "candidate"` を送ることができる回数を 20 から 50 に変更しました - [FIX] DataChannel におけるエンドポイント障害検出カウンターのリセットタイミングを修正しました - [FIX] 一部の HTTP API のバリデーションが正常に動作していない問題を修正しました - [FIX] シグナリングが DataChannel に切り替わったタイミングで WebSocket のアイドルタイムアウトが無制限になるように修正しました - [FIX] SRTP/SRTCP の暗号が AES-GCM の場合に、長時間配信すると正常に復号できなくなる問題を修正しました - [FIX] sora.conf の不要なコメントを削除しました ## 2021.1 **リリース**: 2021-06-23 **対応 Chrome**: M91 以降 **対応 Firefox**: 89 以降 **対応 Safari**: 14.1 以降 **対応 Edge**: 91 以降 ### 廃止情報 #### role の upstream と downstream を廃止 `role` の `upstream` と `downstream` を廃止しました。 詳細は [role の upstream と downstream を廃止](OBSOLETE.html#a8c580) をご確認ください。 #### allow_client_id_assignment 設定を廃止 接続時や認証成功時に、常に client_id を指定できるようになり、 `sora.conf` の `allow_client_id_assignment` を廃止しました。 詳細は [client_id を指定する設定の廃止](OBSOLETE.html#b2acda) をご確認ください。 #### 旧サイマルキャスト API を廃止 `Sora_20180820.ChangeSimulcastQuality` API を廃止しました。 詳細は [旧サイマルキャスト画質変更 API の廃止](OBSOLETE.html#9e15a8) をご確認ください。 ### 互換なしの変更情報 廃止以外の互換性がない機能変更はありません。 ### 実験的機能から正式機能へ昇格 - `Sora_20201120.PushChannelByRole` API - `Sora_20201120.DisconnectChannelByRole` API ### ハイライト - スポットライト機能に rid 指定機能を追加しました - スポットライト機能に遅延フォーカス機能を追加しました - スポットライト機能に自動アンフォーカス機能を追加しました - スポットライト機能にフォーカスなしの音声配信機能を追加しました - シグナリングを WebSocket から DataChannel へ切り替える機能を追加しました - DataChannel 経由のシグナリング利用時に WebSocket の切断を無視する機能を追加しました - より少ない CPU リソースでより多くの接続を処理できるようになりました ### 変更履歴 - [UPDATE] デモ機能で利用している sora-demo を 2021.1 にアップデートしました - [UPDATE] より少ない CPU リソースで多くの接続を処理できるようになりました - [ADD] TURN-TCP 利用時の [Proxy Protocol v1](https://www.haproxy.com/blog/haproxy/proxy-protocol/) へ対応しました- これに伴い [TURN-TLS、TURN-TCP、シグナリングで 443 番ポートを使用する](PRODUCTION.html#14258d) の内容が Sora 2021.1 向けに変更されています - nginx の変更はしなくても動作しますが、変更をお勧めします - [ADD] シグナリング `"type": "offer"` 時に配信で有効になっている `audio` または `video` の `mid` を含めるようにしました- 例: `"type": "offer", "mid": {"audio": "audio_lFaJYL", "video": "video_lMjsoq"}` - [ADD] `"type": "udpate"` の代わりに `"type": "re-offer"` を送れるように、 `sora.conf` に `use_re_offer` を追加しました- デフォルトは `false` です - この設定は 2021 年 12 月リリースの Sora にてデフォルト `true` に変更されます - この設定は 2022 年 6 月リリースの Sora にて廃止され、常に `"type": "re-offer"` が送られるようになります - [ADD] シグナリング通知メタデータの利用時に、 `metadata_list` の代わりに `data` を送れるように、 `sora.conf` に `unuse_metadata_list` を追加しました- デフォルトは `false` です - この設定は 2021 年 12 月リリースの Sora にてデフォルト `true` に変更されます - この設定は 2022 年 6 月リリースの Sora にて廃止され、常に `data` が送られるようになります - [FIX] 録画機能の利用時で映像が送られてこない際に WebM の PixelWidth / PixelHeight が 0 になる問題を修正しました - [FIX] 不安定な回線や音声パケットが送られてこなくなる場合にクライアント側でリップシンクが正常に行われず、音声と映像がずれてしまう問題を修正しました - [FIX] 音声クロックレートが 48000 Hz 固定になってしまう問題を修正しました - [FIX] スポットライトレガシーで recvonly が利用できてしまう問題を修正しました - [FIX] TURN-TCP で問題があった際に、シグナリングを切断しない限り接続が残り続ける問題を修正しました #### 統計機能 - [ADD] RTP ヘッダー拡張の統計情報を追加しました - [ADD] サイマルキャストの rid 単位の RTP 統計情報を追加しました - [ADD] サイマルキャストの rid 単位の RTP ヘッダー拡張統計情報を追加しました - [ADD] RTCP 統計情報を `rtcp` に移動しました- 2021 年 12 月のリリースにて `rtp` から RTCP 関連の統計情報を削除します #### スポットライト機能 **実験的機能** - [CHANGE] デフォルトの `r0` の `maxFramerate` を `1.0` から `5.0` に変更しました #### スポットライト機能: rid 指定 **実験的機能** スポットライト利用時にフォーカス、アンフォーカスそれぞれで受信する映像を接続ごとに指定できるようになりました。 これによりモバイル端末や回線が不安定な場合は映像を一切受信しないなどの設定ができます。 - [ADD] アンフォーカス時に受信する rid を指定できるように、 `sora.conf` に [default_spotlight_unfocus_rid](SORA_CONF.html#a7cd9b) を追加しました- デフォルトは `r0` - `none`, `r0`, `r1`, `r2` を指定可能 - [ADD] フォーカス時に受信する rid を指定できるように、 `sora.conf` に [default_spotlight_focus_rid](SORA_CONF.html#c71c97) を追加しました- デフォルトは `r1` - `none`, `r0`, `r1`, `r2` を指定可能 - [ADD] アンフォーカス時に受信する rid を指定できるように、シグナリング `"type": "connect"` に `spotlight_unfocus_rid` を追加しました- デフォルトは `sora.conf` の [default_spotlight_unfocus_rid](SORA_CONF.html#a7cd9b) の値が採用されます - `none`, `r0`, `r1`, `r2` を指定可能 - [ADD] フォーカス時に受信する rid を指定できるように、シグナリング `"type": "connect"` に `spotlight_focus_rid` を追加しました- デフォルトは `sora.conf` の [default_spotlight_focus_rid](SORA_CONF.html#c71c97) の値が採用されます - `none`, `r0`, `r1`, `r2` を指定可能 - [ADD] アンフォーカス時に受信する rid を指定できるように、認証成功時の払い出しに、 `spotlight_unfocus_rid` を追加しました- デフォルトは `sora.conf` の [default_spotlight_unfocus_rid](SORA_CONF.html#a7cd9b) の値が採用されます - `"type": "connect"` 時に、指定された `spotlight_unfocus_rid` を上書きできます - `none`, `r0`, `r1`, `r2` を指定可能 - [ADD] フォーカス時に受信する rid を指定できるように、認証成功時の払い出しに `spotlight_focus_rid` を追加しました- デフォルトは `sora.conf` の [default_spotlight_focus_rid](SORA_CONF.html#c71c97) の値が採用されます - `"type": "connect"` 時に、指定された `spotlight_focus_rid` を上書きできます - `none`, `r0`, `r1`, `r2` を指定可能 #### スポットライト機能: 遅延フォーカス **実験的機能** スポットライト利用時に、ちょっとした物音やあいづちではすぐにフォーカスされないように、フォーカスを遅延させる機能を追加しました。 この機能によりサーバーからクライアントへのパケット流量を減らすことができるようになりました。 - [ADD] アンフォーカス時にフォーカスを遅延させるかどうかを指定できるように、 `sora.conf` に [default_spotlight_delayed_focus](SPOTLIGHT.html#8b9a4e) を追加しました- デフォルトは `true` - [ADD] アンフォーカス時にフォーカスを遅延させる時間を指定できるように、 `sora.conf` に [default_spotlight_delayed_focus_interval](SPOTLIGHT.html#794eec) を追加しました- デフォルトは `2000 ms` #### スポットライト機能: フォーカスなしの音声配信 **実験的機能** スポットライト利用時に、他の人にフォーカスが移った場合でも音声を配信し続ける機能を追加しました。 この機能によりスポットライトの数が少ない場合でも、他の人がフォーカスされたことにより音声が送られなくなる、といったことがなくなりました。 - [ADD] フォーカスなしでも音声を配信するかどうかを指定できるように、 `sora.conf` に [default_spotlight_unfocus_audio](SPOTLIGHT.html#27f670) を追加しました- デフォルトは `true` - [ADD] フォーカスなしでも音声を配信する上限レートを指定できるように、 `sora.conf` に [default_spotlight_unfocus_audio_rate_limit](SPOTLIGHT.html#91cb49) を追加しました- デフォルトは `2` - 単位は `1 音声ストリーム = 50 packets / s` です #### スポットライト機能: 自動アンフォーカス機能 **実験的機能** スポットライト利用時に、一定時間音声が配信されていない場合はアンフォーカスする機能を追加しました。 この機能によりサーバーからクライアントへのパケット流量を減らすことができるようになりました。 - [ADD] 音がない場合に自動でアンフォーカスするかどうかを指定できるように、 `sora.conf` に [default_spotlight_auto_unfocus](SPOTLIGHT.html#9db9f6) を追加しました- デフォルトは `true` - [ADD] 自動でアンフォーカスする無音時間を指定できるように、 `sora.conf` に [default_spotlight_auto_unfocus_interval](SPOTLIGHT.html#4636fe) を追加しました- デフォルトは `10 s` - 1 ms 以上、30 s 以下 - API でフォーカスが固定されている場合は自動アンフォーカスの対象外になります #### DataChannel 機能: シグナリングの WebSocket から DataChannel への切り替え機能 **実験的機能** > **注釈** > > DataChannel は TURN を利用するため UDP が通らない場合でも問題なく繋がります。 > **重要** > > DataChannel 機能を利用する場合は Sora JavaScript SDK 2021.1 以降が必要になります シグナリングやシグナリング通知、プッシュ通知などで利用している WebSocket から DataChannel へ切り替えます。 **ただし WebSocket は切断判定に利用するため、Sora から切断することはありません** 。 - [ADD] `sora.conf` に [default_data_channel_signaling](SORA_CONF.html#adceef) を追加しました- デフォルトは `false` です - [ADD] シグナリング `"type": "connect"` で `data_channel_signaling: boolean` を指定できるようにしました- デフォルトは `sora.conf` の [default_data_channel_signaling](SORA_CONF.html#adceef) に設定された値です - [ADD] 認証成功時の払い出しで `data_channel_signaling: boolean` を指定できるようにしました- デフォルトは `sora.conf` の [default_data_channel_signaling](SORA_CONF.html#adceef) に設定された値です - `"type": "connect"` 時に、指定された `data_channel_signaling` を上書きできます - [ADD] シグナリング `"type": "offer"` 時に `data_channel_signaling: boolean` を払い出すようにしました- この払い出しは data_channel_signaling が true の時のみ有効です - [ADD] WebSocket から DataChannel へ切り替わった場合は `"type": "switched"` が WebSocket 経由で送られるようにしました- `"type": "switched"` を送ったタイミングからWebSocket 経由の `"type": "ping"` の間隔が 5 秒から 30 秒へ変更されます - `"type": "switched"` を送ったタイミングからWebSocket 経由の `"type": "pong"` を確認しなくなります 以下の機能が DataChannel に切り替わります。 - シグナリング- DataChannel の `label` は `signaling` です - 以下が利用できるメッセージタイプです- `"type": "re-offer"` - `"type": "re-answer"` - `"type": "disconnect"` - シグナリング通知- DataChannel の `label` は `notify` です - 以下が利用できるメッセージタイプです- `"type": "notify"` - プッシュ通知- DataChannel の `label` は `push` です - 以下が利用できるメッセージタイプです- `"type": "push"` - E2EE- DataChannel の `label` は `e2ee` です - 統計情報- DataChannel の `label` は `stats` です - 以下が利用できるメッセージタイプです- `"type": "req-stats"` - `"type": "stats"` #### DataChannel 機能: WebSocket の切断を無視する機能 **実験的機能** > **重要** > > WebSocket の切断を切断判定に利用しない場合、 DataChannel におけるエンドポイント障害検出が切断の判断に利用されます。 > この判断は `sora.conf` の `dcsctp_association_max_retrans` の値に依存します。 - [ADD] `sora.conf` に [default_ignore_disconnect_websocket](SORA_CONF.html#58fe04) を追加しました- デフォルトは `false` です - この値を `true` にした場合、 DataChannel 経由でのシグナリング有効時に WebSocket を切断しても、Sora はクライアントの切断と見なさずに接続が継続します - [ADD] `"type": "connect"` 時に `ignore_disconnect_websocket: boolean` を指定できるようにしました- デフォルトは `sora.conf` に設定された値です - この値を `true` にした場合、 DataChannel 経由でのシグナリング有効時に WebSocket を切断しても、Sora はクライアントの切断と見なさずに接続が継続します - [ADD] 認証成功時の払い出しに `ignore_disconnect_websocket: boolean` を指定できるようにしました- デフォルトは `sora.conf` に設定された値です - `"type": "connect"` 時に、指定された `ignore_disconnect_websocket` を上書きできます - この値を `true` にした場合、 DataChannel 経由でのシグナリング有効時に WebSocket を切断しても、Sora はクライアントの切断と見なさずに接続が継続します - [ADD] `"type": "offer"` 時に `data_channel_signaling` が `true` の場合 `ignore_disconnect_websocket: boolean` を払い出すようにしました #### DataChannel 機能: メッセージの圧縮機能 **実験的機能** DataChannel で送受信するメッセージを圧縮して送受信できる機能です。 `"type": "offer"` 時に送られてくる `data_channels: [{"label": "signaling", "compress": true}, ...]` のように compress が true になっている場合は圧縮して送る必要があります。 - [ADD] `"type": "offer"` 時に DataChannel の情報を送るようにしました- `data_channels: [{"label": "