# 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/) を正式リリースしました - Sora 2023.1.0 より、サポート提供期間をメジャーアップデートがリリースされた日から 12 ヶ月後の月末最終日までに変更しました ## レガシー録画機能の廃止について 2023 年 12 月リリースの Sora 2023.2.0 で新しい録画機能を追加しました。 今までの録画機能はレガシー録画機能と名前を変更しました。 **2025 年** 12 月リリース予定の Sora でレガシー録画機能を廃止します。 移行については [レガシー録画機能から新しい録画機能への移行](LEGACY_RECORDING_TO_RECORDING.html) をご覧ください。 廃止については [レガシー録画機能の廃止](DEPRECATED.html#0e8157) をご覧ください。 レガシー録画機能をご利用のお客様は、新しい録画機能へ移行をご検討ください。 機能や移行に関してのご不明点などがあれば、サポートまでお問い合わせください。 ## レガシーストリーム(非マルチストリーム)機能の廃止予定について 2024 年 6 月リリース予定の Sora にてレガシーストリーム機能をデフォルトで無効にする予定です。 **2025 年** 6 月リリース予定の Sora でレガシーストリーム機能を廃止予定です。 レガシーストリーム機能をご利用のお客様は、マルチストリーム機能へ移行をご検討ください。 機能や移行に関してのご不明点などがあれば、サポートまでお問い合わせください。 ## CentOS 7 版の提供終了ついて CentOS 7 は 2024 年 6 月末でサポートが終了となるのに合わせて、Sora の CentOS 7 版については以下のとおりとなります。 **パッケージの提供** : 2023 年 12 月にリリースの 2023.2.0、およびその後リリースされる可能性のある 2023.2.x の提供をもって終了 **サポートの終了** : 2023.2.0 およびおよびその後リリースされる可能性のある 2023.2.x に対しては 2024 年 12 月末で終了 CentOS 7 版をご利用のお客様は、早めに OS の変更をご検討の上、移行先の OS をサポートまでご連絡下さい。 # 古いドキュメントについて [古いドキュメント](OLD_DOCUMENT.html) をご確認ください。 # このドキュメントについて このドキュメントは WebRTC SFU Sora 2023.2.7 に対応しています。 - [2023.1.x から 2023.2.x への移行](2023_1_TO_2023_2.html) - [レガシー録画機能から新しい録画機能 (セッション単位) への移行](LEGACY_RECORDING_TO_RECORDING.html) - [リリースノート](RELEASE_NOTE.html) - [用語集](GLOSSARY.html) - [既知の問題](KNOWN_ISSUES.html) - [実験的機能](EXPERIMENTAL.html) - [非推奨機能](DEPRECATED.html) - [廃止機能](OBSOLETE.html) - [FAQ](FAQ.html) - [トラブルシューティング](TROUBLESHOOTING.html) - [Sora が期待どおりに動かない場合、または、動作に問題がある場合](SUPPORT.html) - [Sora の仕様や使い方に関して質問がある場合](INQUIRY.html) - [サポートライフサイクル](SUPPORT_LIFECYCLE.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) - [アプリケーション連携チュートリアル](APP_INTEGRATE_TUTORIAL.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) - [ウェブフック](WEBHOOK.html) - [認証ウェブフック](AUTH_WEBHOOK.html) - [認証ウェブフック成功時の払い出し](AUTH_WEBHOOK_RETURN.html) - [セッションウェブフック](SESSION_WEBHOOK.html) - [イベントウェブフック](EVENT_WEBHOOK.html) - [ウェブフックの型定義](WEBHOOK_TYPE.html) - [API](API.html) - [シグナリング API](API_SIGNALING.html) - [サイマルキャスト API](API_SIMULCAST.html) - [スポットライト API](API_SPOTLIGHT.html) - [プッシュ API](API_PUSH.html) - [録画 API](API_RECORDING.html) - [レガシー録画 API](API_LEGACY_RECORDING.html) - [統計 API](API_STATS.html) - [ライセンス API](API_LICENSE.html) - [実験的 API](EXPERIMENTAL_API.html) - [セッション API](EXPERIMENTAL_API_SESSION.html) - [シグナリング API](EXPERIMENTAL_API_SIGNALING.html) - [モード API](EXPERIMENTAL_API_MODE.html) - [RTP 転送 API](EXPERIMENTAL_API_RTP_FORWARDING.html) - [シグナリング通知メタデータ拡張 API](EXPERIMENTAL_API_SIGNALING_NOTIFY_METADATA_EXT.html) - [RTP ストリーム停止/再開 API](EXPERIMENTAL_API_RTP_STREAM_PAUSE_RESUME.html) - [転送フィルター API](EXPERIMENTAL_API_FORWARDING_FILTER.html) - [統計 API](EXPERIMENTAL_API_STATS.html) - [ユーザーエージェント統計情報 API](EXPERIMENTAL_API_USER_AGENT_STATS.html) - [音声ストリーミング API](EXPERIMENTAL_API_AUDIO_STREAMING.html) - [非推奨 API](DEPRECATED_API.html) - [廃止 API](OBSOLETE_API.html) - [クラスター機能チュートリアル](CLUSTER_TUTORIAL.html) - [クラスター機能](CLUSTER.html) - [クラスター API](EXPERIMENTAL_API_CLUSTER.html) - [開発者ツール](DEVTOOLS.html) - [マルチストリーム機能](MULTISTREAM.html) - [サイマルキャスト機能](SIMULCAST.html) - [スポットライト機能](SPOTLIGHT.html) - [OBS Studio (WHIP) 対応機能](WHIP.html) - [TURN 機能](TURN.html) - [録画機能 (セッション単位)](RECORDING.html) - [レガシー録画機能](LEGACY_RECORDING.html) - [メッセージング機能](MESSAGING.html) - [ICE コネクションステート機能](ICE_CONNECTION_STATE.html) - [モード機能](MODE.html) - [ヘルスチェック機能](OK.html) - [配信ワーカー機能](PUBLISH_WORKER.html) - [音声ストリーミング機能](AUDIO_STREAMING.html) - [転送フィルター機能](FORWARDING_FILTER.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 Python (C++) SDK](PYTHON_SDK.html) - [Sora C (C++) SDK ](C_SDK.html) - [WebRTC 負荷試験ツール Zakuro](ZAKURO.html) - [WebRTC 録画合成ツール Hisui](HISUI.html) - [WebRTC 統計コレクター Kohaku](KOHAKU.html) - [音声ストリーミングゲートウェイ Suzu](SUZU.html) - [Sora Archive Uploader](SORA_ARCHIVE_UPLOADER.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) # 2023.1.x から 2023.2.x への移行 ## 概要 2023.1.x から 2023.2.x への移行について注意点をまとめています。 もし不明点がある場合はサポートまでお問い合わせください。 ## 2023.1.x へのローリングアップデートによるクラスター切り戻しはできません 2023.1.x から 2023.2.0 に切り替えた後、 2023.1.x へローリングアップデートによるクラスターの切り戻しは行えません。 切り戻しを行いたい場合はクラスターの再構築が必要になります。 不明点などはサポートまでお問い合わせください。 ## クラスター関連ログの出力先を `cluster.jsonl` へ変更 2023.2.0 からクラスター関連ログ出力を `sora.jsonl` から `cluster.jsonl` に変更しました。 Sora は 2023.2.0 から、クラスターをベースとする仕組みに変更しました。 そのため、クラスターを無効にした状態でも、内部的にはクラスターを前提とする仕組みで動作するようになりました。 これにより、 `sora.conf` の `cluster` が `false` でも `cluster.jsonl` が出力されるようになりました。 ログローテーションなどは `sora.jsonl` と同様に扱っていただくようお願いします。 詳細については [ログファイル](LOG.html) をご確認ください。 ## `sora.conf` の `signaling_notify_metadata` を `false` に設定した場合の挙動の変更 `sora.conf` のシグナリング通知メタデータを含めないようにする設定の `signaling_notify_metadata を false にした` 際の挙動を変更しました。 今までは `signaling_notify_metadata` を `false` に設定した場合、 `data` 自体が含まれなくなっていましたが、 今回の変更から、 `data` はシグナリング通知が有効であれば含まれるようになりました。 `signaling_notify_metadata` を `false` にした場合、 `data` に含まれる `metadata` や `authn_metadata` や `authz_metadata` は含まれなくなります。 ### 2023.1.x まで `signaling_notify_metadata` を `false` にした場合、 `data` は含まれません。 ``` { "type": "notify", "event_type": "connection.created", } ``` ### 2023.2.0 から `signaling_notify_metadata` を `false` にした場合、 `data` は含まれます。 ただし、その中の `metadata` や `authn_metadata` や `authz_metadata` は含まれません。 ``` { "type": "notify", "event_type": "connection.created", "data": [ { "client_id": "4D40YWH56N5S99QHJV6GAPNHB0", "bundle_id": "4D40YWH56N5S99QHJV6GAPNHB0", "connection_id": "4D40YWH56N5S99QHJV6GAPNHB0", }, { "client_id": "FCX8X05SJS3Y18RD5MYFZS62RR", "bundle_id": "FCX8X05SJS3Y18RD5MYFZS62RR", "connection_id": "FCX8X05SJS3Y18RD5MYFZS62RR", } ] } ``` ### シグナリング通知の `data` が含まれなくなる設定 `sora.conf` の以下の設定を全て `false` にした場合、シグナリング通知の `data` が含まれなくなりました - [signaling_notify_metadata](SORA_CONF.html#2d9340) - [signaling_notify_client_id](SORA_CONF.html#fc78ca) - [signaling_notify_bundle_id](SORA_CONF.html#f2a58f) - [signaling_notify_connection_id](SORA_CONF.html#7882d6) - [signaling_notify_connection_created_timestamp](SORA_CONF.html#7fe7b3) ## セッションウェブフック `session.updated` の送信 2023.2.x から `session.updated` ウェブフックを送信するようになりました。 [session_updated_webhook_interval](SORA_CONF.html#4612dc) の設定値の間隔でセッションの状態が通知されるようになります。 もし `session.updated` ウェブフックを受け取る必要がない場合は、 `sora.conf` の `ignore_session_updated_webhook` を `true` に設定してください。 ## ウェブフックなどに利用する信頼された CA 証明書のインストール Sora 2023.2.x から Sora に組み込んでいる CA 証明書ではなく、OS 組み込みの CA 証明書を利用するよう変更しました。 そのため Ubuntu と RHEL (または CentOS) では OS 組み込みの証明書が必要になります。 - Ubuntu の場合は `apt install ca-certificates` で証明書をインストールする必要があります - RHEL (または CentOS) では `dnf install ca-certificates` で証明書をインストールする必要があります ### 影響を受ける機能 - 認証ウェブフック - セッションウェブフック - イベントウェブフック - 音声ストリーミング機能 - 統計エクスポーター機能 ただし、以下の設定で cacert_file を指定している場合は、この影響を受けません。 - [webhook_tls_verify_cacert_file](SORA_CONF.html#7036dc) - [audio_streaming_tls_verify_cacert_file](SORA_CONF.html#feef99) - [stats_exporter_tls_verify_cacert_file](SORA_CONF.html#bcd961) ## ログ出力を JSONL 形式に変更 `sora.log` と `internal.log` のログ出力形式を [JSONL](https://jsonlines.org/) 形式に変更しました。 これは `sora.conf` の `legacy_log_format` を廃止したためです。 2023 年 12 月リリースの Sora にて `legacy_log_format` の設定を廃止しました。 ## ログ出力ファイルの拡張子を `jsonl` に変更 すべての JSONL 形式のログファイルの拡張子を `jsonl` に変更しました。 これは `sora.conf` の `legacy_log_extension` を廃止したためです。 2023 年 12 月リリースの Sora にて `sora_conf-legacy_log_extension` の設定を廃止しました。 ## ウェブフックの audio と video 項目の JSON をフラット構造に変更 ウェブフックで利用する audio と video 項目の JSON 構造を `{"audio": true, "audio_codec_type": "OPUS"}` のようなフラット構造に変更しました。 これは `sora.conf` の `legacy_webhook_audio_video_json_structure` を廃止したためです。 2023 年 12 月リリースの Sora にて `legacy_webhook_audio_video_json_structure` の設定を廃止しました。 以下は変更内容です。 ### ウェブフックリクエスト 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 録画メタデータファイルのフラット化の内容はウェブフック audio / video と同様です。 - `{"audio": {"codec_type": "OPUS"}}` は `{"audio": true, "audio_codec_type": "OPUS"}` へフラット化しました - `{"video": {"bit_rate": 1000, "codec_type": "VP9", "height": 480, "width": 640}` は `{"video": true, "video_bit_rate": 1000, "video_codec_type": "VP9", "video_height": 480, "video_width": 640}` へフラット化しました ## レガシー録画から新しい録画への移行 **レガシー録画は 2025 年 12 月リリースの Sora にて廃止します。それまでに移行をお願いします** Sora 2023.2.x から新しくセッション単位の録画機能を追加し、既存の録画機能をレガシー録画機能としました。 - セッション生成ウェブフックの戻り値に `“recording”: true` を含めることで、チャネル開始前に録画開始 API を実行することなく、録画を開始できるようになりました - チャネル終了後に録画終了 API を実行しなくても、セッションの終了時に録画が終了するようになりました - 分割録画で `expire_time` が指定できるようになりました - 接続単位で録画をブロックし、録画ファイルの出力を拒否できるようになりました 詳細は [レガシー録画機能から新しい録画機能 (セッション単位) への移行](LEGACY_RECORDING_TO_RECORDING.html) をご確認ください。 ## クラスターを構成する Sora ノードの `data/` ディレクトリが消えた場合の挙動の変更 [contact_node_name_list](CLUSTER.html#a3d0fd) 設定でクラスターのノードを指定していない場合、 2023.2.0 よりも前は `data/` ディレクトリが消えたノードは、再起動後に [JoinCluster](EXPERIMENTAL_API_CLUSTER.html#17f3f5) API を使って クラスターに再参加させる必要がありました。 2023.2.0 からは `data/` ディレクトリが消えた場合でも、 [JoinCluster](EXPERIMENTAL_API_CLUSTER.html#17f3f5) API の実行は不要になります。 もしこのケースで [JoinCluster](EXPERIMENTAL_API_CLUSTER.html#17f3f5) API を使用した場合には、既に参加済みとしてエラー応答が返されるようになります。 そのため、 2023.2.0 以降の Sora クラスターでは、ローリングアップデート時の [JoinCluster](EXPERIMENTAL_API_CLUSTER.html#17f3f5) API 呼び出しが不要になります。 # レガシー録画機能から新しい録画機能 (セッション単位) への移行 > **重要** > > レガシー録画機能は 2025 年 12 月リリースの Sora にて廃止します。 Sora 2023.2.0 から新しくセッション単位の録画機能を追加し、既存の録画機能をレガシー録画機能としました。 ## レガシー録画機能ではできて、新しい録画機能ではできないこと ### セッションが存在しない状態では録画の開始ができなくなった レガシー録画機能では `20161101.StartRecording API` を利用することで、セッションが存在しない状態でも録画を開始することができました。 新しい録画機能ではセッションが生成される前に録画を開始することはできません。 代わりにセッションが生成されたタイミングで、 セッションウェブフック `session.created` の戻り値に `"recording": true` を指定することで、 セッション生成と同時に録画を開始することができます。 ### セッションをまたいだ録画ができなくなった レガシー録画機能では、一度録画を開始したら録画の期限が来るか、 `StopRecording` API を実行するまでは録画が続いてしまい、 録画したままという状態が残ってしまうことがありました。 新しい録画機能では、セッションが終了したタイミングで録画も終了するため、誰もそのチャネルに接続していないにもかかわらず、 録画したままという状態はなくなります。 ## 変更点 ### API の変更 - レガシー録画で利用していた `20161101.StartRecording` API と `20161101.StopRecording` API はバージョンを `20231220` に変更してください - レガシー録画で利用していた [StartRecording](API_LEGACY_RECORDING.html#c5b527) API は [StartRecording](API_RECORDING.html#c5b527) API を利用してください - レガシー録画で利用していた [StopRecording](API_LEGACY_RECORDING.html#fd0de5) API は [StopRecording](API_RECORDING.html#fd0de5) API を利用してください - レガシー録画で利用していた [GetStartedRecording](API_LEGACY_RECORDING.html#8095d0) API は [GetSession](EXPERIMENTAL_API_SESSION.html#427a59) API を利用してください - レガシー録画で利用していた [ListStartedRecording](API_LEGACY_RECORDING.html#838360) API は [ListSessions](EXPERIMENTAL_API_SESSION.html#748f19) API を利用してください - レガシー録画で利用していた [ListArchiving](API_LEGACY_RECORDING.html#d4ba61) API には代わりの API がありません、今後 GetSessionRecordingState API を提供予定です- API の変更についてのご質問がある場合はサポートまでご連絡ください ### セッション生成時の録画開始 セッションが存在しないタイミングでの録画開始はできなくなりました。 代わりにセッションが生成されたタイミングで、 セッションウェブフック `session.created` の戻り値に `"recording": true` を指定することで、 セッション生成と同時に録画を開始することができます。 録画を開始するための API を実行する必要はありません。 ### セッション破棄時の録画終了 セッション破棄時に録画を終了するようになりました。 録画を終了するための API を実行する必要はありません。 `expire_time` で指定した時間よりも先にセッションが破棄された場合は、その時点で録画を終了します。 ### expire_time のオプション化 レガシー録画では `StartRecording` API の `expire_time` は必須でしたが、 新しい録画では `expire_time` はオプションに変更しています。 - `expire_time` を指定しない場合は未定義になります。ウェブフックなどでは項目が含まれなくなります- レガシー録画では `expire_time` 未定義の場合は `0` が入っていました - `expire_time` が未指定の場合は、 `expired_at` も項目として含まれなくなります - `expire_time` に `0` は指定できなくなり、 `0` より大きい値のみ指定可能になりました - 分割録画ファイルのみ出力を行う場合でも `expire_time` が指定できるようになりました ### セッションウェブフック `recording.started` と `recording.report` への切り替え 今まで録画開始/終了のウェブフックはイベントウェブフックで送信していましたが、 新しい録画機能ではセッションウェブフックを利用します。 録画開始 `recording.started` と録画レポート `recording.report` ウェブフックの中身は以下が異なります。 - `session_id` を追加しています - `session_metadata` を追加しています - 録画メタデータが指定された場合、 `recording_metadata` を追加しています- `metadata` を `recording_metadata` に変更しています - イベントウェブフック固有の `log_written` を削除しています それ以外は同じです。 接続単位の録画ファイルに関してのイベントウェブフック `archive.*` については、変更はありません。 ### `report-.json` ファイルの `metadata` を `recording_metadata` に変更 録画メタデータが指定された場合の項目を `metadata` から `recording_metadata` に変更しています。 ### 接続単位の録画ブロック機能 今までの録画機能では接続単位での録画ブロックができませんでしたが、 新しい録画機能では認証成功時に `"recording_block": true` を払い出すことで、 その接続の録画をブロックし、録画ファイルを出力しなくなります。 この機能は新しい録画機能だけで利用できます。 ## レガシー録画機能と新しい録画機能の同時利用 レガシー録画機能と新しい録画機能 (セッション単位) は、異なるチャネルであれば同時に利用できます。 例えば、channel_id a ではレガシー録画機能、channel_id b では新しい録画機能(セッション単位)といった利用が可能です。 ## レガシー録画の無効化 `sora.conf` にて [legacy_recording](SORA_CONF.html#632f06) を `false` にすることでレガシー録画機能を無効にできます。 # リリースノート **CHANGE** : 後方互換性のない変更 **UPDATE** : 後方互換性がある変更 **ADD** : 後方互換性がある追加 **FIX** : バグ修正 ## 2023.2.7 **バグフィックスアップデート** **リリース**: 2024-04-24 - [FIX] レガシー録画機能または録画機能(セッション単位)利用時の録画停止処理中に、新規コネクションが参加した際に、そのコネクションが切断されるまで、録画停止処理が完了しない問題を修正しました - [FIX] レガシー録画機能にて録画停止処理中に録画の開始および [StopRecording](API_LEGACY_RECORDING.html#fd0de5) API 実行した際 `RECORDING-INTERNAL-ERROR` が返されていたのを `STOPPING-RECORDING` を返すように修正しました - [FIX] クラスター有効時に、ごく稀にノード起動に失敗することがある問題を修正しました ## 2023.2.5 **ホットフィックスアップデート** **リリース**: 2024-03-08 - [FIX] 録画機能で録画中、出力済の分割録画ファイルのファイルディスクリプタを掴み続ける問題を修正しました ## 2023.2.4 **ホットフィックスアップデート** > **重要** > > このリリースはクラスターをご利用いただいているお客様にのみ提供しております。 **リリース**: 2024-02-27 - [FIX] クラスター利用時にでリーダーノードがダウンした場合に、他のノードのセッションも終了してしまう問題を修正しました ## 2023.2.3 **バグフィックスアップデート** **リリース**: 2024-02-07 - [FIX] `"multistream": false` を指定して接続した場合に、配信/視聴ができない問題を修正しました - [FIX] セッションウェブフックが一部の HTTP サーバーで正常に処理できず、エラーになる問題を修正しました - [FIX] データチャネルの終了時にクライアント側でワーニングが出力される問題を修正しました ## 2023.2.2 **バグフィックスアップデート** **リリース**: 2024-01-04 ### 変更履歴 - [FIX] `sora.conf` の [event_webhook_url](SORA_CONF.html#e1a4d2) が未指定の状態で録画を開始した場合、セッションが破棄されない問題を修正しました - [FIX] ウェブフックで mTLS 利用時に、特定の条件下でクライアント証明書を送らなくなる問題を修正しました- ウェブフックで HTTPS を利用する場合は TLS 1.2 のみを利用するように変更しました - [FIX] ウェブフックで mTLS 利用時に、 CA 証明書が指定されていない場合に OS 組み込みの証明書を利用できない問題を修正しました - [FIX] 統計エクスポーターで mTLS 利用時に、 CA 証明書が指定されていない場合に OS 組み込みの証明書を利用できない問題を修正しました - [FIX] 音声ストリーミングで mTLS 利用時に、 CA 証明書が指定されていない場合に OS 組み込みの証明書を利用できない問題を修正しました - [FIX] API ログの書き込みに失敗した場合でも、 API の処理を中断しないように修正しました - [FIX] [PurgeClusterNode](EXPERIMENTAL_API_CLUSTER.html#13b35a) API の API ログ操作名が `LeaveCluster` となっていたのを `PurgeClusterNode` に修正しました - [FIX] クラスターに参加済のノードが、別クラスターに対する [JoinCluster](EXPERIMENTAL_API_CLUSTER.html#17f3f5) API を受け入れてしまう問題を修正しました - [FIX] 録画機能で大幅にパケットの到着が遅れている場合、分割録画に失敗することがある問題を修正しました ## 2023.2.0 **メジャーアップデート** **リリース**: 2023-12-20 ### ハイライト - セッション単位で録画する新しい録画機能を追加しました- 今までの録画機能は [レガシー録画機能](LEGACY_RECORDING.html) と名前を変更しました - レガシー録画機能と新しい録画機能は別チャネルであれば同時に利用することができます - レガシー録画機能は 2025 年 12 月リリース予定の Sora にて廃止されます - 詳細は [録画機能 (セッション単位)](RECORDING.html) をご確認ください - 接続単位で録画をブロックできる機能を追加しました- 今まではチャネルに参加している全ての接続が録画されていましたが、新しい録画機能では接続単位で録画をブロックできるようになりました - 新しい録画機能でのみ利用できます - より大規模な配信を可能にする配信ワーカー機能を追加しました- 今まで音声や映像をクライアントに配信するワーカーは 1 つでしたが、配信するワーカーを複数にすることで、より多くのユーザーに配信することができるようになりました - データチャネルの負荷を下げるために SCTP パケットのチェックサム計算を省略する機能を追加しました- 利用するにはクライアント側もチェックサム計算を省略する機能に対応している必要があります - ウェブフックで IPv6 アドレスが利用できるようになりました - ウェブフックなどでルート CA 証明書に OS 組み込みのものを利用するようにしました ### 正式版 - [セッションウェブフック](SESSION_WEBHOOK.html) が正式版になりました - [DataChannel 経由のシグナリング](DATA_CHANNEL_SIGNALING.html) が正式版になりました - [メッセージング機能](MESSAGING.html) が正式版になりました ### 廃止情報 - `sora.conf` の `legacy_log_format` を廃止しました- 詳細は [sora.conf の legacy_log_format の廃止](OBSOLETE.html#daeabd) をご確認ください - `sora.conf` の `legacy_log_extension` を廃止しました- 詳細は [sora.conf の legacy_log_extension の廃止](OBSOLETE.html#c35c81) をご確認ください - `sora.conf` の `legacy_webhook_audio_video_json_structure` を廃止しました- 詳細は [sora.conf の legacy_webhook_audio_video_json_structure の廃止](OBSOLETE.html#a7613b) をご確認ください ### 破壊的変更 - `sora.conf` の [signaling_notify_metadata](SORA_CONF.html#2d9340) を `false` にした場合でもシグナリング通知の `data` が含まれるようになりました - `sora.conf` の以下の設定を全て `false` にした場合、シグナリング通知の `data` が含まれなくなりました- [signaling_notify_metadata](SORA_CONF.html#2d9340) - [signaling_notify_client_id](SORA_CONF.html#fc78ca) - [signaling_notify_bundle_id](SORA_CONF.html#f2a58f) - [signaling_notify_connection_id](SORA_CONF.html#7882d6) - [signaling_notify_connection_created_timestamp](SORA_CONF.html#7fe7b3) - 実験的機能のクラスター機能利用時のセッションウェブフック [session.destroyed](SESSION_WEBHOOK.html#ccb165) に `connections` が含まれなくなりました - 実験的機能のクラスター機能のログを `cluster.jsonl` に出力するよう変更しました - 実験的機能のセッションウェブフック [audio-streaming.started](SESSION_WEBHOOK.html#e7b17a) に `max_connections` と `total_connections` が含まれなくなりました - 実験的機能のセッションウェブフック [audio-streaming.started](SESSION_WEBHOOK.html#e7b17a) に `max_connections` と `total_connections` が含まれなくなりました ### 変更履歴 - [CHANGE] ウェブフックなどで利用するルート CA 証明書に OS 組み込みのものを利用するように変更しました- Ubuntu の場合は `apt install ca-certificates` でインストールされる証明書を利用します - RHEL の場合は `dnf install ca-certificates` でインストールされる証明書を利用します - 詳細は [ウェブフックリクエストなどの送信先サーバー証明書の検証に利用する OS 組み込みのルート CA 証明書について](WEBHOOK.html#e8a845) をご確認ください - [UPDATE] DataChannel を利用したメッセージングのみで接続する場合に `role` が `sendrecv` 以外でも接続ができるようになりました - [ADD] シグナリング `"type": "offer"` に `channel_id` と `session_id` を追加しました - [ADD] `connection.jsonl` の `ice_connection_state` に ICE コネクションステート `checking` と `disconnected` だった時間を追加しました - [ADD] Sora が利用している Erlang VM の設定を追加できる環境変数 `SORA_ADDITIONAL_ERL_ARGS` を追加しました - [ADD] 認証成功時の払い出しに検証用の RTP パケットロスシミュレーターの設定値、 `rtp_packet_loss_simulator_incoming` と `rtp_packet_loss_simulator_outgoing` が指定できるようになりました - [ADD] `sora.jsonl` と `internal.jsonl` に UUIDv4 を Base32 でエンコードしたユニークな ID を含めるようにしました- `"id": "base32(uuidv4)"` - [FIX] データチャネルで利用する SCTP のストリーム ID 採番を RFC 8832 に準拠させました - [FIX] 録画機能で H.264 利用時に送られてくる分割ペイロードが壊れている場合は処理をスキップするように修正しました #### OBS WHIP **これは実験的機能です** - [ADD] OBS WHIP で User-Agent として送られてくる情報を sora_client としてウェブフックで送信するようにしました```javascript "sora_client": { "raw": "Mozilla/5.0 (OBS-Studio/30.0.0; Mac OS X; ja-JP)", "type": "OBS-Studio", "version": "30.0.0", "environment": "environment":"Mozilla/5.0 (OBS-Studio/30.0.0; Mac OS X; ja-JP)" }, ``` - [ADD] OBS WHIP で AV1 が動作するようにしました- OBS WHIP で AV1 を配信する仕組みは 2024 年 4 月 現在、 OBS には組み込まれていません #### 転送フィルター機能 **これは実験的機能です** 転送フィルターに `version` や `metadata` が指定できるようになりました。 `version` を指定することで、転送フィルターの更新 API が並列で実行されても期待した値に変更することができるようになりました。 - [ADD] 転送フィルターに `version` を設定できるようになりました - [ADD] 転送フィルターに `metadata` を設定できるようになりました - [ADD] 転送フィルター API [CreateChannelForwardingFilter](EXPERIMENTAL_API_FORWARDING_FILTER.html#fe98d1) と [CreateConnectionForwardingFilter](EXPERIMENTAL_API_FORWARDING_FILTER.html#d80a51) に `version` を指定できるようになりました - [ADD] 転送フィルター API [CreateChannelForwardingFilter](EXPERIMENTAL_API_FORWARDING_FILTER.html#fe98d1) と [UpdateChannelForwardingFilter](EXPERIMENTAL_API_FORWARDING_FILTER.html#36fc45) に `metadata` を指定できるようになりました - [ADD] 転送フィルター API [CreateConnectionForwardingFilter](EXPERIMENTAL_API_FORWARDING_FILTER.html#d80a51) と [UpdateConnectionForwardingFilter](EXPERIMENTAL_API_FORWARDING_FILTER.html#23ed63) に `metadata` を指定できるようになりました - [ADD] 転送フィルター API [UpdateChannelForwardingFilter](EXPERIMENTAL_API_FORWARDING_FILTER.html#36fc45) と [UpdateConnectionForwardingFilter](EXPERIMENTAL_API_FORWARDING_FILTER.html#23ed63) API に指定した `expected_version` が既存の `version` と一致していない場合は更新エラーになるようになりました- `expected_version` が既存のバージョンと一致した場合のみ `desired_version` で指定した値で `version` の値を更新します - [ADD] セッションウェブフックの戻り値に `version` と `metadata` を指定できるようになりました - [ADD] 認証成功の払い出し時に `version` と `metadata` を指定できるようになりました - [ADD] シグナリング時に `version` と `metadata` を指定できるようになりました #### セッション API - [ADD] 指定したセッションを取得する [GetSession](EXPERIMENTAL_API_SESSION.html#427a59) API を追加しました- `channel_id` を指定してセッションを取得します - [ADD] セッション一覧を取得する [ListSessions](EXPERIMENTAL_API_SESSION.html#748f19) API を追加しました- 全てのセッション一覧を取得します #### 録画機能 - [ADD] `sora.conf` に単一録画ファイルと分割録画ファイルの両方を出力する機能を有効にするかどうかを指定する [recording_dual_output](SORA_CONF.html#4cc9c0) を追加しました- デフォルトは `true` です - `false` に指定した場合は `単一録画ファイルと分割録画ファイルの両方が出力` のパターンを指定できなくなります - [ADD] `sora.conf` に録画期限の最大値を指定する [recording_max_expire_time](SORA_CONF.html#f3ff8d) を追加しました- デフォルトは `86400 s` です - 設定できる最大値は `86400 s` です - レガシー録画機能では一括録画と一括&分割録画で `expire_time` が指定できます - 新しい録画機能(セッション単位)では一括録画、分割録画、一括&分割録画で `expire_time` が指定できます - [ADD] `sora.conf` に分割録画時の分割時間の最大値を指定する [recording_max_split_duration](SORA_CONF.html#927da9) を追加しました- デフォルトは `86400 s` です - 設定できる最大値は `86400 s` です - [ADD] `sora.conf` に一括録画を含む場合に録画期限の設定を要求する [recording_expire_time_required](SORA_CONF.html#fcfa2d) を追加しました- **この設定は一括録画時に録画ファイルが大きくなりすぎるのを防ぐための設定です** - デフォルトは `false` です - この設定を `true` にした場合、一括録画を含む場合に `expire_time` が必須になります - この設定を `true` にした場合、レガシー録画機能では `expire_time` に `0` 以外の値を指定する必要があります - この設定を `true` にした場合、新しい録画機能(セッション単位)では `expire_time` の値を指定する必要があります - この設定を `true` にした場合でも分割録画のみの場合は `expire_time` は必須になりません #### 新しい録画機能 (セッション単位) 今までの録画機能は [レガシー録画機能](LEGACY_RECORDING.html) と名前を変更しました。 レガシー録画機能と新しい録画機能は別チャネルであれば同時に利用することができます。 - [ADD] `sora.conf` にレガシー録画を有効にするかどうか指定する [legacy_recording](SORA_CONF.html#632f06) を追加しました- デフォルトは `true` です - `false` にした場合、レガシー録画機能が利用できなくなります - この設定は移行用の設定で、 2025 年 12 月リリース予定の Sora にて廃止されます。 - [ADD] セッションウェブフック `session.created` 時に `"recording": true` を指定することで録画を開始します - [ADD] セッションウェブフック `session.created` 時に `"recording_expire_time"` を指定することができるようになりました- セッション破棄時に録画は自動で終了します - セッション破棄前に期限が来た場合はそこで録画は終了します - [ADD] セッションウェブフック `session.created` 時に `"recording_split_duration"` を指定することができるようになりました - [ADD] セッションウェブフック `session.created` 時に `"recording_split_only"` を指定することができるようになりました - [ADD] セッションウェブフック `session.created` 時に `"recording_metadata"` を指定することができるようになりました - [ADD] セッションウェブフック `recording.started` を追加しました - [ADD] セッションウェブフック `recording.report` を追加しました - [ADD] 新しい録画用の [StartRecording](API_RECORDING.html#c5b527) API を追加しました- セッション破棄時に自動で録画は終了します - `expire_time` がオプションになっています - `expire_time` デフォルトは未定義です - [ADD] 新しい録画用の [StopRecording](API_RECORDING.html#fd0de5) API を追加しました 詳細については [録画機能 (セッション単位)](RECORDING.html) をご確認ください。 移行については [レガシー録画機能から新しい録画機能 (セッション単位) への移行](LEGACY_RECORDING_TO_RECORDING.html) をご確認ください。 #### 新しい録画機能 (セッション単位) における接続単位の録画ブロック機能 **これは実験的機能です** **この機能は新しい録画機能 (セッション単位) でのみ利用できます。レガシー録画機能では利用できません** - [ADD] 認証成功時に `"recording_block": true` を払い出すことで、その接続の録画をブロックし、録画ファイルの出力を拒否できるようになりました- これは録画が有効になっていない場合に払い出しても問題ありません - この値を途中で変更することはできません - [ADD] イベントウェブフック `connection.{created, updated, destroyed}` の `data` に `"recording_block"` の項目を追加しました- 認証成功時に `"recording_block": true` を払い出していれば `true` に、それ以外は `false` になります #### シグナリング通知メタデータ `sora.conf` で `signaling_notify_metadata` を `false` にした際の挙動を変更しました。 - [CHANGE] `sora.conf` の `signaling_notify_metadata` を `false` にした際でも `data` 項目が含まれるようになりました- `data` の `metadata` と `authn_metadata` と `authz_metadata` は含まれません - [CHANGE] `sora.conf` で以下の設定を全て `false` にした場合、シグナリング通知の `data` が含まれなくなりました- [signaling_notify_metadata](SORA_CONF.html#2d9340) - [signaling_notify_client_id](SORA_CONF.html#fc78ca) - [signaling_notify_bundle_id](SORA_CONF.html#f2a58f) - [signaling_notify_connection_id](SORA_CONF.html#7882d6) - [signaling_notify_connection_created_timestamp](SORA_CONF.html#7fe7b3) - [FIX] `sora.conf` で `signaling_notify_metadata` を `false` にした際にも、シグナリング通知の `data` 項目の `authn_metadata` と `authz_metadata` が含まれてしまう問題を修正しました #### 外部への HTTP リクエストに HTTP ヘッダーを追加 ウェブフックや統計エクスポーター、音声ストリーミングを利用した際の外部への HTTP リクエストに、 `x-sora-` prefix とは別に `sora-` prefix の HTTP ヘッダーを追加しました。 これは [RFC 6648](https://datatracker.ietf.org/doc/html/rfc6648) による `x-` prefix の非推奨化に準拠するためです。 今後 `x-sora-` prefix は非推奨になります。 現時点で具体的な時期は決まっていませんが、将来的に 1 年以上の移行期間を設けて廃止する予定です。 - [ADD] セッションウェブフックに `sora-session-webhook-type` ヘッダーを追加しました- すでにある `x-sora-session-webhook-type` ヘッダーは将来的に廃止予定です - [ADD] イベントウェブフックに `sora-event-webhook-type` ヘッダーを追加しました- すでにある `x-sora-event-webhook-type` ヘッダーは将来的に廃止予定です - [ADD] 統計エクスポーターに `sora-stats-exporter-type` ヘッダーを追加しました- すでにある `x-sora-stats-exporter-type` ヘッダーは将来的に廃止予定です - [ADD] セッションウェブフックに `sora-session-id` ヘッダーを追加しました - [ADD] イベントウェブフックに `sora-connection-id` ヘッダーを追加しました - [ADD] イベントウェブフックに `sora-session-id` ヘッダーを追加しました #### ウェブフック - [CHANGE] セッションウェブフック `audio-streaming.started` に `max_connections` と `total_connections` が含まれなくなりました - [CHANGE] セッションウェブフック `audio-streaming.stopped` に `max_connections` と `total_connections` が含まれなくなりました - [CHANGE] クラスター機能利用時のセッションウェブフック `session.destroyed` に `connections` が含まれなくなりました - [ADD] `sora.conf` にウェブフックで IPv6 利用する [webhook_ipv6](SORA_CONF.html#6c895b) を追加しました- デフォルトは `false` です - この設定を有効にしない限りウェブフックで IPv6 は利用できません - [ADD] `sora.conf` にイベントウェブフック `connection.updated` の送信間隔を変更する [connection_updated_webhook_interval](SORA_CONF.html#e67c3b) を追加しました- デフォルトは `1 min` です - 最小は `1 min` です - 最大は `10 min` です - 時間単位は `min` のみが指定できます - [ADD] `sora.conf` に 録画イベントウェブフック `split-archive.available` を送信しないようにする [ignore_split_archive_available_webhook](SORA_CONF.html#a62b1e) を追加しました- デフォルトは `false` です - [ADD] 接続イベントウェブフック `connection.{created, updated, destroyed}` に ICE コネクションステートが `checking` と `disconnected` だった時間の項目を追加しました- `data.ice_connection_state.total_checking_duration_ms` に `checking` だった合計時間(ミリ秒)が入ります - `data.ice_connection_state.total_disconnected_duration_ms` に `disconnected` だった合計時間(ミリ秒)が入ります - [ADD] 認証ウェブフックに `spotlight_focus_rid` と `spotlight_unfocus_rid` を追加しました- `spotlight` が `true` の時だけ追加されます - [ADD] 接続イベントウェブフック `connection.{created, updated, destroyed}` に ICE コネクションステートの `checking` と `disconnected` の時間を通知する項目を追加しました- `ice_connection_state` 項目を追加しました - `ice_connection_state` に `total_checking_duration_ms` に `checking` だった合計時間(ミリ秒)が入ります - `ice_connection_state` に `total_disconnected_duration_ms` に `disconnected` だった合計時間(ミリ秒)が入ります ```javascript "data": { "ice_connection_state": { "total_checking_duration_ms": 0, "total-disconnected_duration_ms": 0 } } ``` - [ADD] セッションウェブフック [session.updated](SESSION_WEBHOOK.html#2a5b1b) を追加しました- クラスターが有効時には `connections` は含まれません - 録画機能 (セッション単位) 有効時に `recording` 項目が含まれます - [ADD] セッションウェブフック `session.destroyed` に `reason` が含まれるようになりました- `reason` には以下が含まれます- `normal`- 正常終了 - `terminated_api`- [TerminateSession](EXPERIMENTAL_API_SESSION.html#ba022b) API を利用した終了 - `abort`- 異常終了 - [ADD] `sora.conf` にセッションウェブフック [session.updated](SESSION_WEBHOOK.html#2a5b1b) を送信しないようにする [ignore_session_updated_webhook](SORA_CONF.html#0901a0) を追加しました- デフォルトは `false` です - [ADD] `sora.conf` にセッションウェブフック [session.updated](SESSION_WEBHOOK.html#2a5b1b) の送信間隔を変更する [session_updated_webhook_interval](SORA_CONF.html#4612dc) を追加しました- デフォルトは `1 min` です - 最小は `1 min` です - 最大は `10 min` です - 時間単位は `min` のみが指定できます - [FIX] 認証ウェブフックで `simulcast_rid` は `spotlight` が `true` の場合は追加しないようにしました- `simulcast` が `true` かつ `spotlight` が `false` の時だけ追加されます #### データチャネル - [ADD] データチャネルの SCTP のパケットのチェックサム計算を省略する仕組みを追加しました- データチャネルは DTLS レイヤーでデータ保護が行われているため、 SCTP のチェックサムは追加の整合性を得ることができないため省略することができます - クライアント側もチェックサム計算を省略する機能に対応している必要があります - データチャネル利用時の CPU リソースがクライアント、SFU ともに節約されます - [ADD] SCTP のチェックサムを省略した回数の統計情報を追加しました- `total_received_sctp_zero_checksum` - `total_sent_sctp_zero_checksum` #### クラスター機能 **これは実験的機能です** `Sora 2023.1.x` で構築されているクラスターは `Sora 2023.2.x` へローリングアップデートで移行できます。 > **警告** > > 2023.2.x から 2023.1.x へのローリングアップデートは行えません。クラスターを再構築する必要があります。 - [CHANGE] クラスター関連のログは `cluster.jsonl` に出力するよう変更しました - [ADD] 最新のバージョンと 1 世代前のバージョンの Sora ノードが混在する状態でのクラスター運用ができるようになりました- 全てのクラスターに参加するノードが同じバージョンになるまでは 1 世代前のバージョンと混在できる仕組みを追加しました - `Sora 2023.2.x` と `2023.1.x` で、特定のノードのアップデートが難しい場合でも、先に他のノードをアップデートすることができるようになります - クラスターに 1 世代前のバージョンのノードが混在している場合、新しい接続は全て古いバージョンのクラスターの仕組みを利用します - 全てのノードが新しいバージョンのクラスターになったタイミングで、新しいバージョンのクラスターの仕組みを利用しはじめます 詳細については [クラスター機能](CLUSTER.html) をご確認ください。 > **注釈** > > [InitCluster](EXPERIMENTAL_API_CLUSTER.html#621990) API でクラスターを初期化する際には、新旧バージョンは混在させないでください。また `Sora 2023.2.x` で構成されたクラスターに [JoinCluster](EXPERIMENTAL_API_CLUSTER.html#17f3f5) API で `Sora 2023.1.x` のノードを参加させることはできません。 #### 配信ワーカー機能 **これは実験的機能です** 配信ワーカー機能は音声や映像を配信するワーカーを複数用意することで、 1 チャネルで高ビットレートの映像をより多くのクライアントに配信することができるようになります。 - [ADD] sora.conf に音声や映像の 1 配信に利用する配信ワーカー数を指定する [rtp_publish_worker_number](SORA_CONF.html#512b8c) を追加しました- デフォルトの配信ワーカー数は 1 です - 同時に 100 クライアント以上へ配信する場合はまず 10 を設定することを推奨します - ワーカー数が 10 であれば 1 チャネル 1000 クライアント以上の配信ができるようになります - 最小は 1 で、最大は 500 です ワーカー数の設定を 10 以上で検討している場合はまずサポートにご相談ください。 詳細については [配信ワーカー機能](PUBLISH_WORKER.html) をご確認ください。 #### シグナリング通知メタデータ拡張機能 **これは実験的機能です** - [ADD] 認証成功時に、シグナリング通知メタデータ拡張の初期値を払い出す `signaling_notify_metadata_ext` を追加しました。- sora.conf にて [signaling_notify_metadata_ext](SORA_CONF.html#e94720) を有効にしている必要があります - デフォルトは `{}` です #### 統計エクスポーター **これは実験的機能です** - [ADD] `sora.conf` に統計エクスポーターをデフォルトで有効にするかどうかの [default_stats_exporter](SORA_CONF.html#010de6) を追加しました- デフォルトは `true` です - [ADD] 認証成功時の払い出しで接続単位で統計エクスポーターを有効にするかどうかを指定する `stats_exporter` を追加しました- `false` を設定した場合は `stats_collector_url` が指定されていたとしても統計情報がエクスポートされません #### H.265 **これは実験的機能です** 2024 年 4 月 現在、WebRTC H.265 のプロファイルに対応している WebRTC ライブラリはありません。 現在 [仕様策定中](https://datatracker.ietf.org/doc/html/draft-ietf-avtcore-hevc-webrtc) です。 - [ADD] H.265 サイマルキャストに対応しました - [ADD] `sora.conf` に H.265 のデフォルトレベル ID を指定する [default_h265_param_level_id](SORA_CONF.html#d15808) を追加しました- デフォルトは `93` (3.1) です - [ADD] 認証払い出し時に H.265 のデフォルトレベル ID を指定する `video_h265_params` を追加しました- `"video_h265_params": {"level_id": 93}` のように指定できます - level_id の値は 0 から 255 の間である必要があります - [ADD] シグナリング時に H.265 のデフォルトレベル ID を指定する `h265_params` を追加しました- `"video": {"codec_type": "H265", "h265_params": {"level_id": 93}}` のように指定できます - level_id の値は 0 から 255 の間である必要があります - [ADD] `sora.conf` に、シグナリング時に H.265 のパラメータ指定を許可するかどうか設定する [signaling_h265_params](SORA_CONF.html#8ed4e9) を追加しました- デフォルトは `false` です ## 2023.1.3 **バグフィックスアップデート** **リリース**: 2023-10-17 ### 変更履歴 - [FIX] 録画機能利用時、分割録画に失敗かつ分割録画ファイルが一つ以上生成されている場合に、終了処理に失敗する問題を修正しました- 終了中の失敗のため、録画処理自体には影響はありません - [FIX] サイマルキャスト機能の `simulcast_encodings` と `spotlight_encodings` の `scalabilityMode` のデフォルト値を `L1T1` に修正しました- AV1 サイマルキャスト利用時に `L1T1` 以外の `scalabilityMode` を利用すると録画ができない問題があります - [FIX] データチャネルを利用したメッセージング機能利用時に、パケロスが発生すると一定期間パケットを破棄してしまうことがある問題を修正しました- この問題は `ordered` が `true` で `max_retransmits` や `max_packet_life_time` が設定されている場合に発生します - [FIX] クラスター機能利用時に、ノードの起動・停止と新規チャネルへの接続が重なると接続に失敗することがある問題を修正しました - [FIX] `sora.conf` の `default_simulcast_rid` の設定値が設定に反映されない問題を修正しました - [FIX] 依存している OpenSSL を 3.1.3 にアップデートしました ## 2023.1.2 **バグフィックスアップデート** **リリース**: 2023-08-10 ### 変更履歴 - [FIX] Safari 側の問題により Safari 14 系および Safari 15 系の一部で Sora に接続できない問題を修正しました- Safari 15.6 以降では問題が修正されていることを確認しています ## 2023.1.1 **バグフィックスアップデート** **リリース**: 2023-07-14 ### 変更履歴 - [ADD] connection ログに `ice_connection_state` という ICE コネクション機能の統計情報を追加しました- サポートにて問題をより素早く解決しやすくするための追加です - [ADD] connection ログに `network_status` に不安定レベル毎の統計情報を追加しました- サポートにて問題をより素早く解決しやすくするための追加です - [ADD] [GetStatsConnection](API_STATS.html#e79b61) API に `ice_connection_state` の統計情報を追加しました - [ADD] [GetStatsConnection](API_STATS.html#e79b61) API に `network_status` にレベル毎の統計情報を追加しました - [FIX] CentOS 7 x86_64 利用時にセグメンテーション違反で Sora が落ちてしまう問題を修正しました - [FIX] DTLS 再ネゴシエーションの挙動を修正しました - [FIX] スポットライト機能利用時に OBS での WHIP が利用できない問題を修正しました- 新しく WHIP エンドポイント URL 指定時に `spotlight=true` を指定することで利用できるようにしました - ただし、音声がそのままでは配信されないため [FocusSpotlightFixed](API_SPOTLIGHT.html#beaf88) API を利用して音声を配信する必要があります - [FIX] ICE コネクションステート機能で `disconnected` 時のクライアント状態確認の挙動を修正しました - [FIX] [PutSignalingNotifyMetadata](EXPERIMENTAL_API_SIGNALING_NOTIFY_METADATA_EXT.html#a20c95) API の結果の誤字を修正しました - [FIX] [JoinCluster](EXPERIMENTAL_API_CLUSTER.html#17f3f5) API のエラー応答の誤字を修正しました ## 2023.1.0 **メジャーアップデート** **リリース**: 2023-06-28 ### サポート期間変更 - Sora 2023.1.0 より、サポート提供期間をメジャーアップデートがリリースされた日から **12 ヶ月後の月末最終日まで** に変更しました - 2023年 6 月リリースの Sora 2023.1.0 およびその後リリースされる可能性のある Sora 2023.1.x は、2024 年 6 月 30 日までサポート対象となります 詳細は [サポートライフサイクル](SUPPORT_LIFECYCLE.html) をご確認ください。 ### ハイライト - OBS で WebRTC を利用した配信を実現する WHIP に対応しました- 詳細は [OBS (WHIP) 機能](WHIP.html) をご確認ください - VP9 / AV1 でのサイマルキャストに対応しました- 詳細は [VP9 と AV1 でのサイマルキャスト](SIMULCAST.html#860410) をご確認ください - メディアストリームを柔軟に制御するための [転送フィルター機能](FORWARDING_FILTER.html) を追加しました - 音声ストリーミング機能に自動開始/停止機能を追加しました- 詳細は [自動開始/停止機能](AUDIO_STREAMING.html#1492a6) をご確認ください - IPv6 のみの環境での動作に対応しました- 詳細は [ipv6_only](SORA_CONF.html#5e9e68) をご確認ください ### 互換なしの変更情報 - 移行用の設定である `sora_conf-legacy_webhook_audio_video_json_structure` の設定のデフォルトを `false` に変更しました- 詳細は [sora.conf の legacy_webhook_audio_video_json_structure の廃止](OBSOLETE.html#a7613b) をご確認ください - 移行用の設定である `legacy_log_format` の設定のデフォルトを `false` に変更しました- 詳細は [sora.conf の legacy_log_format の廃止](OBSOLETE.html#daeabd) をご確認ください - 移行用の設定である `legacy_log_extension` の設定のデフォルトを `false` に変更しました- 詳細は [sora.conf の legacy_log_extension の廃止](OBSOLETE.html#c35c81) をご確認ください ### 廃止情報 - Ubuntu 18.04 向けパッケージのサポートを終了しました- 詳細は [Ubuntu 18.04 サポートの終了](OBSOLETE.html#afde12) をご確認ください - `sora.conf` の `split_archive_legacy_prefix` を廃止しました- 詳細は [sora.conf の split_archive_legacy_prefix の廃止](OBSOLETE.html#050276) をご確認ください - `sora.conf` の `default_multistream` を廃止しました- 詳細は [sora.conf の default_multistream の廃止](OBSOLETE.html#615559) をご確認ください - `sora.conf` の `dcsctp_heartbeat_interval` を廃止しました- 詳細は [DataChannel で利用している SCTP 関連の実験的な設定の廃止](OBSOLETE.html#0af146) をご確認ください - `sora.conf` の `dcsctp_slow_start_tcp_style` を廃止しました- 詳細は [DataChannel で利用している SCTP 関連の実験的な設定の廃止](OBSOLETE.html#0af146) をご確認ください ### 変更履歴 - [CHANGE] データチャネル関連の設定である `dcsctp_heartbeat_interval` を廃止しました - [CHANGE] データチャネル関連の設定である `dcsctp_slow_start_tcp_style` を廃止しました - [CHANGE] サイマルキャスト利用時に `"active": false` を指定したストリームは、 `~r0` といった SDP が生成されます- r1 と r2 が false の場合は `a=simulcast:recv r0;~r1;~r2` のような SDP が生成されます - これは [RFC 8853: Using Simulcast in SDP and RTP Sessions](https://www.rfc-editor.org/rfc/rfc8853.html) に準拠しています - [CHANGE] `sora.conf` のウェブフックの audio と video 項目のレガシーな入れ子構造を利用する `sora_conf-legacy_webhook_audio_video_json_structure` のデフォルト値を `false` に変更しました- これは移行用設定です - [CHANGE] `sora.conf` のログフォーマットのレガシー形式を維持する `legacy_log_format` のデフォルト値を `false` に変更しました- これは移行用設定です - [CHANGE] `sora.conf` の JSONL 形式で出力しているログのレガシー拡張子を `.log` に維持する `legacy_log_extension` のデフォルト値を `false` に変更しました- これは移行用設定です - [UPDATE] RHEL 9.2 に対応しました - [UPDATE] RHEL 8.8 に対応しました - [ADD] 録画イベントウェブフック `recording.started` に `data.start_timestamp` を追加しました - [ADD] 録画イベントウェブフック `recording.started` に `data.split_duration` を追加しました - [ADD] `sora.conf` に IPv6 アドレスのみを利用する [ipv6_only](SORA_CONF.html#5e9e68) の設定を追加しました - [ADD] クラスター機能が有効な際、セッションウェブフックに `external_signaling_url` 項目を追加しました- `sora.conf` の [external_signaling_url](SORA_CONF.html#d6bf68) に指定されている値がそのまま入ります - [ADD] モードが `block_new_connection` の場合は、接続に失敗する仕組みを追加しました - [ADD] イベントウェブフックにログの書き込みが成功したかどうかを示す `log_written` フラグを追加しました- イベントウェブフックログの書き込みが成功した場合は `"log_written": true` が含まれます - イベントウェブフックログの書き込みが失敗した場合は `"log_written": false` が含まれます - イベントウェブフックログには常に `log_written` が含まれます - [ADD] 録画機能で録画ファイル生成に失敗したファイル情報を `recording.report` ウェブフックやファイルに `failed_archives` という項目で追加しました - [ADD] 録画機能の `recording.report` イベントウェブフックに `"file_written"` フラグを追加しました- `report-*.json` ファイルの書き込みに成功した場合 `"file_written": true` が含まれます - `report-*.json` ファイルの書き込みに失敗した場合 `"file_written": false` が含まれます - `report-*.json` ファイルには常に `file_written` が含まれます - [ADD] 認証ウェブフックに `id` を追加しました - [FIX] IPv6 のみの環境で Firefox が正常に動作しない問題を修正しました - [FIX] Sora 終了中に HTTP API が呼ばれるとクラッシュログが出力される問題を修正しました - [FIX] 認証ウェブフックで `simulcast` が `false` の場合でも `simulcast_rid` が含まれていた問題を修正しました- `simulcast` が `false` の場合は `simulcast_rid` は含まれなくなります - [FIX] 録画機能で H.264 でまれに録画が失敗してしまう問題を修正しました - [FIX] スポットライト機能でフォーカスが当たっていない場合でも、無音の音声パケットが配信されてしまう問題を修正しました #### パッケージファイル名の変更 OS 名とバージョンの間に `-` を入れるようにし、x86_64 もアーキテクチャを追加しました。 展開後のディレクトリにアーキテクチャは含まれません。 - [CHANGE] `sora-2023.1.0-ubuntu22.04-arm64v8.tar.gz` から `sora-2023.1.0-ubuntu-22.04-arm64v8.tar.gz` に変更しました- `ubuntu22.04` を `ubuntu-22.04` に変更しました - [CHANGE] `sora-2023.1.0-ubuntu20.04-arm64v8.tar.gz` から `sora-2023.1.0-ubuntu-20.04-arm64v8.tar.gz` に変更しました- `ubuntu20.04` を `ubuntu-20.04` に変更しました - [CHANGE] `sora-2023.1.0-ubuntu22.04.tar.gz` から `sora-2023.1.0-ubuntu-22.04-x86_64.tar.gz` に変更しました- `ubuntu22.04` を `ubuntu-22.04` に変更しました - ファイル名に `-x86_64` を追加しました - [CHANGE] `sora-2023.1.0-ubuntu20.04.tar.gz` から `sora-2023.1.0-ubuntu-20.04-x86_64.tar.gz` に変更しました- `ubuntu20.04` を `ubuntu-20.04` に変更しました - ファイル名に `-x86_64` を追加しました - [CHANGE] `sora-2023.1.0-ubuntu20.04.tar.gz` から `sora-2023.1.0-ubuntu-20.04-x86_64.tar.gz` に変更しました- `ubuntu20.04` を `ubuntu-20.04` に変更しました - ファイル名に `-x86_64` を追加しました - [CHANGE] `sora-2023.1.0-rhel9.2.tar.gz` から `sora-2023.1.0-rhel-9.2-x86_64.tar.gz` に変更しました- `rhel9.2` を `rhel-9.2` に変更しました - ファイル名に `-x86_64` を追加しました - [CHANGE] `sora-2023.1.0-rhel8.8.tar.gz` から `sora-2023.1.0-rhel-8.8-x86_64.tar.gz` に変更しました- `rhel8.8` を `rhel-8.8` に変更しました - ファイル名に `-x86_64` を追加しました - [CHANGE] `sora-2023.1.0-centos7.9.tar.gz` から `sora-2023.1.0-centos-7.9-x86_64.tar.gz` に変更しました- `centos7.9` を `centos-7.9` に変更しました - ファイル名に `-x86_64` を追加しました #### セッション破棄 API - [ADD] 指定したセッションを終了させる [TerminateSession](EXPERIMENTAL_API_SESSION.html#ba022b) API を追加しました- `channel_id` の指定は必須で、 `session_id` がオプションで指定できます #### ヘルスチェック - [ADD] `http://:5000/.ok` で Sora のヘルスチェックができるようになりました- 単体利用時には問題が無ければ常に 200 OK を返します - クラスター利用時には `initial` と `block_new_connection` モード時には `503 Service Unavailable` を返します 詳細は [ヘルスチェック機能](OK.html) をご確認ください。 #### シグナリング通知 - [ADD] シグナリング通知の `"event_type": "connection.created"` に `timestamp` を追加しました- data にも `"data": [{"timestamp": "2023-06-28T10:00:00.999999", ...}, .. ]` のように `timestamp` が含まれるようになります - [ADD] シグナリング通知の `"event_type": "connection.created"` に `timestamp` を含める設定 [signaling_notify_connection_created_timestamp](SORA_CONF.html#7fe7b3) を `sora.conf` に追加しました- デフォルトは `true` です #### 映像コーデックパラメーター指定機能 - [ADD] ウェブフックに映像コーデックパラメーター `"video_vp9_params": {"profile_id": 0}` を追加しました- この設定を利用する場合 `legacy_webhook_audio_video_json_structure` が `false` である必要があります - [ADD] ウェブフックに映像コーデックパラメーター `"video_av1_params": {"profile": 0}` を追加しました- この設定を利用する場合 `sora_conf-legacy_webhook_audio_video_json_structure` が `false` である必要があります - [ADD] ウェブフックに映像コーデックパラメーター `"video_h264_params": {"profile_level_id": ""}` を追加しました- この設定を利用する場合 `sora_conf-legacy_webhook_audio_video_json_structure` が `false` である必要があります - [ADD] シグナリング接続時に H.264 のプロファイルレベル ID を `"video": {"codec_type": "H264", "h264_params": {"profile_level_id": "42e01f"}` のように指定できるようになりました- この指定を利用する場合は [signaling_h264_params](SORA_CONF.html#b32e49) が `true` である必要があります - `h264_params` を指定する場合は、 `codec_type` は `H264` である必要があります - [ADD] シグナリング接続時に VP9 のプロファイル ID を `"video": {"codec_type": "VP9", "vp9_params": {"profile_id": 0}}` のように指定できるようになりました- この指定を利用する場合は [signaling_vp9_params](SORA_CONF.html#3261ea) が `true` である必要があります - `vp9_params` を指定する場合は、 `codec_type` は `VP9` である必要があります - profile_id には 0 から 3 までの値を指定できます - [ADD] シグナリング接続時に AV1 のプロファイルを `"video": {"codec_type": "AV1", "av1_params": {"profile": 0}}` のように指定できるようになりました- この指定を利用する場合は [signaling_av1_params](SORA_CONF.html#91f3b8) が `true` である必要があります - `av1_params` を指定する場合は、 `codec_type` は `AV1` である必要があります - profile には 0 から 2 までの値を指定できます - [ADD] 認証成功時払い出しに VP9 のプロファイル ID を指定できる `"video_vp9_params": {"profile_id": 0}` を追加しました- この設定を利用する場合 `sora_conf-legacy_webhook_audio_video_json_structure` が `false` である必要があります - profile_id には 0 から 3 までの値を指定できます - [ADD] 認証成功時払い出しに AV1 のプロファイルを指定できる `"video_av1_params": {"profile": 0}` を追加しました- この設定を利用する場合 `sora_conf-legacy_webhook_audio_video_json_structure` が `false` である必要があります - profile には 0 から 2 までの値を指定できます - [ADD] 認証成功時払い出しに H.264 のプロファイルを指定できる `"video_h264_params": {"profile_level_id": "42e01f"}` を追加しました- この設定を利用する場合 `sora_conf-legacy_webhook_audio_video_json_structure` が `false` である必要があります - `h264_profile_level_id` は 2024 年 6 月リリース予定の Sora にて廃止します - [ADD] `sora.conf` に VP9 のプロファイル ID のデフォルト値を指定する [default_vp9_param_profile_id](SORA_CONF.html#ab0de9) を追加しました- デフォルトは 0 が設定されています - 0 から 3 までの値を指定できます - [ADD] `sora.conf` に AV1 のプロファイルのデフォルト値を指定する [default_av1_param_profile](SORA_CONF.html#319e30) を追加しました- デフォルトは 0 が設定されています - 0 から 2 までの値を指定できます - [ADD] `sora.conf` に H.264 のプロファイルレベル ID のデフォルト値を指定する [default_h264_param_profile_level_id](SORA_CONF.html#1581db) を追加しました- 既存の [default_h264_profile_level_id](SORA_CONF.html#8a25f5) は 2024 年 6 月リリース予定の Sora にて廃止します #### OBS (WHIP) 対応 OBS が対応予定の WebRTC (WHIP) で配信ができるようになりました。 - [ADD] `sora.conf` に OBS (WHIP) を有効にする [whip](SORA_CONF.html#615414) を追加しました- デフォルトは `false` です - [ADD] `sora.conf` に OBS (WHIP) の Bearer トークンを認証ウェブフックの `metadata` に対応させるキーを指定する [whip_bearer_token_metadata_key](SORA_CONF.html#699f57) を追加しました- OBS (WHIP) からの接続についても Bearer トークンを利用した認証機能が利用できます - デフォルトは未指定です - [ADD] WHIP 向けエンドポイント URL `https://example.com/whip/` を追加しました- クエリー文字列で `client_id` と `bundle_id` を指定できるようになりました - [ADD] WHIP 向けリソース URL `https://example.com/whip-resource//` を追加しました- PATCH と DELETE メソッドに対応しています - [ADD] WHIP を利用した際、認証ウェブフックに `whip: true` を追加しました- WHIP を利用していない接続の場合はこの項目は含まれません 詳細は [OBS (WHIP) 対応機能](WHIP.html) をご確認ください。 #### VP9 / AV1 サイマルキャスト対応 - [UPDATE] VP9 と AV1 でのサイマルキャスト機能に対応しました- Chrome 113 以降でスポットライト機能にて VP9 と AV1 が利用できるようになりました - Edge 113 以降でスポットライト機能にて VP9 が利用できるようになりました - [UPDATE] 認証成功時の払い出し `simulcast_encodings` と `spotlight_encodings` で `scalabilityMode` を指定できるようになりました- デフォルトでは `scalabilityMode` に `L1T3` が設定されています - [UPDATE] [simulcast_encodings_file](SORA_CONF.html#dead73) と [spotlight_encodings_file](SORA_CONF.html#6115fb) で `scalabilityMode` を指定できるようになりました 詳細は [scalabilityMode](SIMULCAST.html#918c4d) をご確認ください。 #### Lyra 録音機能 - [ADD] 録画機能に Lyra コーデックを利用した際に WebM ファイルで録音する仕組みを追加しました 詳細は [Lyra コーデックの録画ファイル](RECORDING.html#b9f8bb) をご確認ください。 #### 転送フィルター機能 今まで [PauseRtpStream](EXPERIMENTAL_API_RTP_STREAM_PAUSE_RESUME.html#de7a52) / [ResumeRtpStream](EXPERIMENTAL_API_RTP_STREAM_PAUSE_RESUME.html#43002a) API で実現していたメディアストリームの停止/再開をより細かく、柔軟に設定をできるようにした、 転送フィルター機能を追加しました。 - [ADD] セッション生成時 `forwarding_filter` を指定することでチャネル単位の転送フィルターを追加できるようになりました - [ADD] シグナリング接続時に `forwarding_filter` を指定することで接続単位の転送フィルターを追加できるようになりました - [ADD] 認証成功時に `forwarding_filter` を指定することで接続単位の転送フィルターを追加できるようになりました - [ADD] チャネル単位でチャネルとコネクションの転送フィルターを確認できる [ListForwardingFilters](EXPERIMENTAL_API_FORWARDING_FILTER.html#a1dd75) API を追加しました - [ADD] チャネル単位の転送フィルターを作成する [CreateChannelForwardingFilter](EXPERIMENTAL_API_FORWARDING_FILTER.html#fe98d1) API を追加しました - [ADD] チャネル単位の転送フィルターを更新する [UpdateChannelForwardingFilter](EXPERIMENTAL_API_FORWARDING_FILTER.html#36fc45) API を追加しました - [ADD] チャネル単位の転送フィルターを削除する [DeleteChannelForwardingFilter](EXPERIMENTAL_API_FORWARDING_FILTER.html#9410fd) API を追加しました - [ADD] コネクション単位の転送フィルターを作成する [CreateConnectionForwardingFilter](EXPERIMENTAL_API_FORWARDING_FILTER.html#d80a51) API を追加しました - [ADD] コネクション単位の転送フィルターを更新する [UpdateConnectionForwardingFilter](EXPERIMENTAL_API_FORWARDING_FILTER.html#23ed63) API を追加しました - [ADD] コネクション単位の転送フィルターを削除する [DeleteConnectionForwardingFilter](EXPERIMENTAL_API_FORWARDING_FILTER.html#0d65da) API を追加しました - [ADD] 転送フィルターで転送がブロックされたタイミングでシグナリング通知する機能を追加しました - [ADD] 転送フィルターで転送がブロックが解除されたタイミングでシグナリング通知する機能を追加しました - [ADD] `sora.conf` に転送フィルターをシグナリング経由で指定できるかどうかを設定する [signaling_forwarding_filter](SORA_CONF.html#d15a40) を追加しました- デフォルト は `false` です - [ADD] `sora.conf` に転送フィルターのブロックの状態が変わったタイミングでシグナリング通知を飛ばすかどうかを設定する [signaling_notify_forwarding_filter](SORA_CONF.html#338e96) を追加しました- デフォルト は `true` です 詳細は [転送フィルター機能](FORWARDING_FILTER.html) をご確認ください。 #### SDP 再利用機能 今までマルチストリーム利用した際に、クライアント切断してもその SDP が残ってしまう問題がありました。 今回のリリースで、SDP を再利用する仕組みにより SDP が残る問題を解決しました。 - [CHANGE] `recycle_media_section` が `true` の際に、SDP を再利用する仕組みを追加しました - [ADD] `sora.conf` に SDP の再利用を行う [recycle_media_section](SORA_CONF.html#d3e2b5) 設定を追加しました- デフォルトは `true` です #### 音声ストリーミング機能 - [ADD] 音声ストリーミングの結果通知の状態を確認する [ListAudioStreamingResultPushState](EXPERIMENTAL_API_AUDIO_STREAMING.html#70450f) API を追加しました - [ADD] 音声ストリーミング機能にサブスクライブが 0 になると音声ストリーミングを停止し、サブスクライブが 1 以上になると音声ストリーミングを開始する機能を追加しました- この機能はセッション生成時に指定できます - この機能が有効になっている場合は音声ストリーミング開始/終了 API は利用できません - [ADD] セッションウェブフックの払い出しに音声ストリーミングの自動開始と停止を有効にする `audio_streaming_auto` を追加しました- この設定を利用する場合は必ず `audio_streaming` を `true` で払い出す必要があります - [ADD] `sora.conf` に音声ストリーミングのウェブフックを送信するかどうかを設定する [ignore_audio_streaming_webhook](SORA_CONF.html#8f086b) を追加しました- デフォルトは `true` で、送信しません - [ADD] 音声ストリーミング機能の開始のウェブフック `audio-streaming.started` を追加しました- `sora.conf` にて [ignore_audio_streaming_webhook](SORA_CONF.html#8f086b) を `false` にすることで送信します - [ADD] 音声ストリーミング機能の終了のウェブフック `audio-streaming.stopped` を追加しました- `sora.conf` にて [ignore_audio_streaming_webhook](SORA_CONF.html#8f086b) を `false` にすることで送信します #### WebSocket 経由シグナリングでの ping / pong / stats のインターバルやタイムアウトの設定 WebSocket 経由でのシグナリングにおいて、 `"type": "ping"` や `"type": "pong"` のインターバルやタイムアウトを設定できるようになりました。 また `"type": "ping"` 送信時の `"stats": true` にする間隔を指定できるようになりました。 - [CHANGE] `"type": "ping"` 時におくる `"stats": true` の間隔を 5 秒から 30 秒に変更しました - [ADD] `sora.conf` に ping を送信する間隔を指定する [websocket_signaling_ping_interval](SORA_CONF.html#27aae2) 設定を追加しました- デフォルトは `5 s` です - 最小は `5 s` です - 最大は `300 s` です - [ADD] `sora.conf` に pong のタイムアウト時間を指定する [websocket_signaling_pong_timeout](SORA_CONF.html#140464) 設定を追加しました- デフォルトは `60 s` です - 最小は `60 s` です - 最大は `600 s` です - [ADD] `sora.conf` に ping 送信時に `"stats": true` にする間隔を指定する [websocket_stats_timer_interval](SORA_CONF.html#67a631) 設定を追加しました- デフォルトは `30 s` です - 最小は `30 s` です - 最大は `600 s` です #### クラスター機能利用時のディスク障害時の対応を追加 - [CHANGE] クラスター利用時に `block_new_connection` モードへ遷移した場合には新規接続のリダイレクトを行わないように変更しました - [ADD] クラスター利用時にディスク障害が発生した際に、 `block_new_connection` モードへ遷移する機能を追加しました # 用語集 ## クライアント クライアントは Sora と WebSocket や WebRTC で接続している個を指し、各接続にはユニークな ID が与えられます。 1. **1 接続 1 クライアントの原則**:- Sora における各接続はそれぞれ別個のクライアントとして扱われます。つまり、1 つの接続は 1 つのクライアントとして扱われます 2. **ユニークな ID であるコネクション ID の割り当て**:- クライアントが Sora に接続すると、その接続には固有の ID (コネクション ID) が割り当てられます 3. **複数クライアントのサポート**:- SDK を利用することで、ユーザーは複数のクライアントを使用し、複数の接続を確立することが可能です 4. **同一ユーザーによる接続の統合**:- 同じユーザーが複数の接続を行う場合、これらの接続に同じクライアント ID を指定することで、ユーザーを一意に識別できます 5. **クライアント ID の自動割り当て**:- クライアント ID を指定しない場合、 Sora はコネクション ID をクライアント ID として自動的に割り当てます ## チャネル チャネルは Sora で使用される「ルーム」や「グループ」として機能する、独立したコミュニケーションのスペースです。 1. **コミュニケーションの制限**:- チャネルに接続したクライアントは、そのチャネル内でのみ音声、映像、データのやりとりが可能です。異なるチャネルのクライアント間での直接のコミュニケーションはできません 2. **複数チャネルへのアクセス**:- 一つのウェブブラウザを使用して、複数のクライアントが同時に複数のチャネルにアクセスすることが可能です 3. **チャネル ID**:- 利用者はチャネルに 255 バイトまでの値を ID として指定できます ## セッション セッションは実際にチャネルに参加しているクライアントの集まりを指し、各セッションにはユニークな ID が与えられます。 1. **セッションの存在**:- チャネルに 1 つ以上のクライアントが接続している状態を「セッションが存在する」と言い、逆にクライアントが 1 人も接続していない場合は「セッションが存在しない」と言います 2. **セッションの生成**:- セッションは、セッションがまだ存在しないチャネルにクライアントが接続した時に生成されます。 3. **セッションの破棄**:- 全てのクライアントがチャネルから切断した後、一定期間が経過するとセッションは破棄されます。 4. **セッション ID**:- セッションには Sora が自動で生成する一意の ID が割り当てられます ## コネクション コネクションはクライアントが接続している状態を指し、各コネクションにはユニークな ID が与えられます。 1. **コネクションの生成**:- クライアントが接続し、認証に成功した後、WebRTCが確立されるとコネクションが生成されます 2. **コネクションの破棄**:- クライアントが切断すると、そのコネクションは破棄されます 3. **コネクション ID の自動割り当て**:- コネクションには Sora が自動で生成する一意の ID が割り当てられます ## ロール Sora のロールは、クライアントが音声や映像をどのように取り扱うかを決定する役割を果たします。 1. **sendrecv (送受信)**:- sendrecv ロールを選択したクライアントは、音声および映像の送受信が可能です。これは、クライアントが他のクライアントと音声や映像を交換する、双方向のコミュニケーションができる状態を意味します 2. **sendonly (送信のみ)**:- sendonly ロールを選択したクライアントは、音声および映像の送信のみが可能です。これは、自分の音声や映像を他のクライアントに送ることはできますが、他からの音声や映像を受け取ることはできない状態を意味します 3. **recvonly (受信のみ)**:- recvonly ロールを選択したクライアントは、音声および映像の受信のみが可能です。これは、他のクライアントからの音声や映像は受け取ることができますが、自分から送ることはできない状態を意味します 4. **ロールの選択タイミング**:- クライアントは接続時にのみロールを選択できます。一度選択されたロールは、その後の接続中に変更することはできません 5. **ロールとメッセージング機能の独立性**:- ロールの選択はSoraのメッセージング機能には影響しません。メッセージング機能の方向性(送信、受信、またはその両方)については、別の項目「direction」で管理されます # 既知の問題 **既知の問題の詳細についてはサポートまでお問い合わせください** ## ウェブフック - 録画アーカイブ失敗のウェブフックの filename / file_path が分割録画ファイルにならない- 次のメジャーバージョンアップにて修正予定です ## サイマルキャスト録画 - Windows 版 Chrome で H.264 のサイマルキャストを録画した場合に画質が悪くなります - AV1 サイマルキャスト時の録画を利用する場合 `scalabilityMode` が `L1T1` 以外では正常に再生できません ## マルチストリーム - `"type": "sendrecv"` 利用時に音声のみや映像のみを指定した場合でも、音声と映像の両方が送られてきます- 今後改善予定です ## OBS WHIP/WHEP 対応機能 ### スポットライト利用時に音声が自動で配信されない - OBS 側の WHIP に利用している WebRTC スタック実装で音量レベルを音声パケットに載せてこないため判断ができません- [FocusSpotlightFixed](API_SPOTLIGHT.html#beaf88) API を利用して OBS の接続にフォーカスをあてることで音声を配信できます - WHIP でのスポットライト有効時は音声を自動で配信する仕組みを導入するか、OBS 側の WHIP に利用している WebRTC スタックへ貢献することを検討しています ## 仕様としての制限 ### マルチトラック - 1 つのストリームに 1 オーディオトラック、1 ビデオトラックしか設定できません- マルチトラックへの対応は検討していますが未定です # 実験的機能 > **重要** > > 実験的機能を本番環境で利用する場合は **必ず** サポートまでご連絡ください。 ## 概要 実験的機能とは、正式リリースに向けて積極的に改善を行っている機能、および正式リリースを行うかについて決定を保留にしている機能であり、 今後、後方互換性のない仕様変更を行う可能性があります。 仕様の変更はあるものの、動作が不安定であることやバグを多く含んでいることを意味するものではなく、ご利用の場合はサポートの対象となります。 また、実験的機能に関するお客様からのお問い合わせやフィードバックを基に、今後の開発方針を決定することがあります。 ごく稀に、正式リリースを見合わせて削除する機能もありますので、具体的な機能については以下の一覧でご確認いただくとともに、 実際に本番環境でご利用いただく場合は事前にサポートまでご連絡いただきますようお願いします。 ## 実験的機能一覧 ### 正式リリースに向けて改善を進めている機能 - [モード機能](MODE.html)- 2024 年 6 月リリースの Sora にて正式リリースの予定です - [転送フィルター機能](FORWARDING_FILTER.html)- 2024 年 6 月リリースの Sora にて正式リリースの予定です - [音声ストリーミング機能](AUDIO_STREAMING.html)- 2024 年 6 月リリースの Sora にて正式リリースの予定です - 録画ブロック機能- 2024 年 6 月リリースの Sora にて正式リリースの予定です - SDP 再利用機能- 2024 年 6 月リリースの Sora にて正式リリースの予定です - [クラスター機能](CLUSTER.html)- 2024 年 12 月リリースの Sora にて正式リリースの予定です - [センシティブデータ](SENSITIVE_DATA.html)- 2024 年 12 月リリースの Sora にて正式リリースの予定です - [シグナリング通知メタデータ拡張 API](EXPERIMENTAL_API_SIGNALING_NOTIFY_METADATA_EXT.html)- 2024 年 12 月リリースの Sora にて正式リリースの予定です - [OBS (WHIP) 対応](WHIP.html)- OBS で TURN やサイマルキャストが利用できるようになったら正式リリース予定です - H.265 対応- Safari で無設定で利用できるようになったら正式リリース予定です - 映像コーデックパラメーター指定機能- VP9 / AV1 / H264 / H265 - 2024 年 6 月リリースの Sora にて正式リリースの予定です - [統計エクスポーター機能](STATS_EXPORTER.html) - [配信ワーカー機能](PUBLISH_WORKER.html) - [統計 API](EXPERIMENTAL_API_STATS.html) - [GenerateCrashLog](EXPERIMENTAL_API.html#26eea6) API - [GetStatsReport](EXPERIMENTAL_API_STATS.html#bbbfca) API - Opus パラメーター指定機能 - ウェブフック HTTP ヘッダー ### 正式リリースを行うかについて検討を保留にしている機能 - [RTP 転送 API](EXPERIMENTAL_API_RTP_FORWARDING.html) - [RTP ストリーム停止/再開 API](EXPERIMENTAL_API_RTP_STREAM_PAUSE_RESUME.html)- 転送フィルター機能で機能が満たせるため - [ListChannels](EXPERIMENTAL_API_SIGNALING.html#b27c42) API - [E2EE 機能](E2EE.html) - 片方向配信時の視聴側帯域推定を利用した配信ビットレートの自動変更機能 - 映像コーデックのビットレートを 15Mbps より大きく指定した場合 - Lyra コーデック対応- Google が継続的に開発を行うか不透明なため ### 削除予定がある機能 現時点で、削除予定の機能はありません。 # 非推奨機能 ここでは今後廃止される非推奨の機能について説明していきます。 不明点はサポートまでお問い合わせください。 ## CentOS 7 対応 CentOS 7 は 2024 年 6 月末でサポートが終了となるのに合わせて、Sora の CentOS 7 版については以下のとおりとなります。 **パッケージの提供**: 2023 年 12 月にリリース予定の 2023.2.0、およびその後リリースされる可能性のある 2023.2.x の提供をもって終了 **サポートの終了**: 2023.2.0 およびおよびその後リリースされる可能性のある 2023.2.x に対しては 2024年12月末で終了 - [EOL CentOS | End of Life (EOL) | Lifecycle](https://endoflife.software/operating-systems/linux/centos) CentOS 7 版をご利用のお客様は、早めに OS の変更をご検討の上、移行先の OS をサポートまでご連絡下さい ## レガシー録画機能の廃止 > **重要** > > **2025 年 12 月リリース予定の Sora にて廃止** [レガシー録画機能](LEGACY_RECORDING.html) を廃止します。 今後は [録画機能 (セッション単位)](RECORDING.html) をご利用ください。 移行に関しては [レガシー録画機能から新しい録画機能 (セッション単位) への移行](LEGACY_RECORDING_TO_RECORDING.html) をご確認ください。 - 2024 年 12 月リリース予定の Sora にて [legacy_recording](SORA_CONF.html#632f06) のデフォルトを false に変更します - 2025 年 12 月リリース予定の Sora にて [legacy_recording](SORA_CONF.html#632f06) の設定を廃止し、レガシーレコーディングを廃止します ## レガシーストリーム(非マルチストリーム)機能の廃止 > **重要** > > **2025 年 6 月リリース予定の Sora にて廃止予定** 今後は [マルチストリーム](MULTISTREAM.html) をご利用ください。 移行に関してはサポートまでご連絡ください。 - 2024 年 6 月リリース予定の Sora にてレガシーストリーム機能を有効にする [legacy_recording](SORA_CONF.html#632f06) の設定をデフォルトを `false` として追加します - 2025 年 6 月リリース予定の Sora にてレガシーストリーム機能を有効にする [legacy_recording](SORA_CONF.html#632f06) の設定を廃止し、レガシーストリーミングを廃止します ## 認証成功時の払い出し h264_profile_level_id の廃止 > **重要** > > **2024 年 6 月リリース予定の Sora にて廃止** 認証成功時の払い出しで H264 のプロファイルレベルの値を指定する h264_profile_level_id を廃止します。 `"video_h264_params": {"profile_level_id": ...}` をご利用ください。 ## sora.conf の default_h264_profile_level_id の廃止 > **重要** > > **2024 年 6 月リリース予定の Sora にて廃止** H264 のプロファイルレベルのデフォルト値を指定する default_h264_profile_level_id を廃止します。 [default_h264_param_profile_level_id](SORA_CONF.html#1581db) をご利用ください。 ## ウェブフックと統計エクスポーターの HTTP ヘッダー `x-sora` prefix の非推奨化 > **重要** > > 現時点では廃止予定はありませんが、将来的に 1 年の移行期間をもうけて廃止する予定です。 `x-sora` prefix とは別に `sora` prefix の HTTP ヘッダーを追加しました。 これは [RFC 6648](https://datatracker.ietf.org/doc/html/rfc6648) による `x-` prefix の非推奨化に準拠するためです。 `x-sora` prefix は非推奨になります。現時点では廃止予定はありませんが、将来的に 1 年以上の移行期間を経て廃止される予定です。 - セッションウェブフックの `x-sora-session-webhook-type` ヘッダーは非推奨です、 `sora-session-webhook-type` ヘッダーを利用してください - イベントウェブフックの `x-sora-event-webhook-type` ヘッダーは非推奨です、 `sora-event-webhook-type` ヘッダーを利用してください - 統計エクスポーターの `x-sora-stats-exporter-type` ヘッダーは非推奨です、 `sora-stats-exporter-type` ヘッダーを利用してください ## API [非推奨 API](DEPRECATED_API.html) をご確認ください # 廃止機能 ## 概要 廃止機能とはすでに廃止された機能です。 API の廃止については [廃止 API](OBSOLETE_API.html) をご確認ください。 ## sora.conf の legacy_log_format の廃止 **2023 年 12 月リリースの Sora にて廃止** sora ログや internal ログをレガシーフォーマットで出力する `sora.conf` の `legacy_log_format` 設定を廃止しました。 ## sora.conf の legacy_log_extension の廃止 **2023 年 12 月リリースの Sora にて廃止** JSONL 形式で出力するログの拡張子を `.log` でファイル出力する `sora.conf` の `legacy_log_extension` 設定を廃止しました。 ## 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` 設定を廃止しました。 ## DataChannel で利用している SCTP 関連の実験的な設定の廃止 **2023 年 6 月リリースの Sora にて廃止** DataChannel で利用している SCTP 関連の実験的な設定である dcsctp_heartbeat_interval と dcsctp_slow_start_tcp_style の設定を廃止しました。 ## 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` を指定せずに接続した場合は常にマルチストリームが有効になります。 ## 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_SIGNALING.html#39de6a) API をご利用ください - `Sora_20151104.DisconnectChannelDownstream` API を廃止しました- 今後は [DisconnectChannelByRole](API_SIGNALING.html#39de6a) API をご利用ください - `Sora_20160711.PushUpstream` API を廃止しました- 今後は [PushChannelByRole](API_PUSH.html#bc57a2) API をご利用ください - `Sora_20160711.PushDownStream` API を廃止しました- 今後は [PushChannelByRole](API_PUSH.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_SIGNALING.html#d388f3) API をご利用ください - `Sora_20151104.Disconnect` API を廃止しました- 今後は [DisconnectClient](API_SIGNALING.html#e91c0b) API をご利用ください ## 旧サイマルキャスト画質変更 API の廃止 **2021 年 6 月リリースの Sora にて廃止しました** - `Sora_20180820.ChangeSimulcastQuality`- 今後は [RequestRtpStream](API_SIMULCAST.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 全般 ### 片方向配信には対応していますか? 対応しています。多くの視聴者に配信を行いたい場合はサポートまでご相談ください。 ### 双方向配信には対応していますか? 対応しています。WebRTC のマルチストリームという技術を利用して実現しています。 2024 年 4 月 の時点で 1 チャネルに参加するクライアントは 12 までを推奨としています。 1 チャネルで 12 より多いクライアントで双方向の配信を行いたい場合は [スポットライト機能](SPOTLIGHT.html) を検討するかサポートまでお問い合わせ下さい。 ### 音声検出による映像の切り替えには対応していますか? 対応しています。Sora 独自のスポットライト機能という名前で提供しています。 この機能は多人数で会議を行う場合に、クライアントやサーバーの負荷を減らせる技術です。 100 名以上が 1 チャネルに参加できます。 詳細は [スポットライト機能](SPOTLIGHT.html) をご確認ください ### スクリーンキャプチャ機能には対応していますか? 2024 年 4 月 の時点でスクリーンキャプチャ機能はブラウザでは 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](WHIP.html#b23b22) で同じ値を指定してください。 > **注釈** > > シグナリング時に `bundle_id` を指定する場合は `sora.conf` の [signaling_bundle_id](SORA_CONF.html#279311) を `true` にする必要があります。 `bundle_id` が同じ接続では送信のみの音声と映像を送受信側で受信しなくなります。 ### 映像コーデックは何がお勧めですか? すべてのブラウザ、さらにほぼすべての端末で動作する VP9 か H.264 がお勧めです。 ただし、端末に VP9 のハードウェアアクセラレータが搭載されていることはほとんどないため、 H.264 を採用した方が電池消費量は減ります。 一方で、H.264 は一部の Android 端末で正常に動作しないことがあります。 すべての環境が Chrome に統一できる場合は AV1 をお勧めします。 ### H.264 や VP9 での映像配信に対応していますか? ブラウザがそれぞれのコーデックに対応していれば、 Sora は問題なく配信できます。 2024 年 4 月 の時点では ... - Chrome M120 は VP8、 VP9、 AV1、 H.264 に対応しています - Firefox 120 は VP8、 VP9、 H.264 に対応しています - Edge 120 は VP8、 VP9、 H.264 に対応しています - Safari 17.1 は VP8、 VP9、 H.264 に対応しています- 実験的機能として H.265 対応が追加されています - 実験的機能として AV1 対応が追加されています 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 では最大 50 Mbps での配信ができますが、 今のところは 15 Mbps より大きなビットレートでの配信はサポート対象外とさせていただいています。 配信自体はできますが、クライアント、サーバーともに不安定になることがあるためです。 今後、高いビットレートでの配信を安定して実現できるようにしていく予定です。 ### 4K 30fps を実現したいのですができますか? できます。ただしクライアント側の負荷がとても高くなるため、かなり条件は厳しいです。 クライアントの負荷が高い場合、 ブラウザは自動的に解像度やフレームレートを下げる仕組みが入っているため、 4K 30fps を配信するためにはソフトウェアエンコードでの配信はかなり厳しいです。 そのため 4K 30fps に対応したハードウェアエンコーダーが必要になります。 時雨堂が公開している SDK はハードウェアエンコーダーに対応していますので、 対応しているハードウェアを用意していただければと思います。 また、時雨堂では [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 には対応していますか? 対応しています。 2024 年 4 月 の時点では、シグナリング機能とメッセージング機能として 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_PUSH.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 をクライアントに送る ```mermaid sequenceDiagram participant C as クライアント participant S as Sora participant A as アプリケーションサーバー C->>+S: "type": "connect" S->>+A: 認証ウェブフック A-->>-S: 200 OK
"allowed": true S-)-C: "type": "offer" C-)S: "type": "answer" note over C,S: WebRTC 確立 ``` 外部の 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_SIGNALING.html#2ec3a0) をご確認ください。 ### 指定したコネクションを切断した際に切断理由を含めることはできますか? できます。 `reason` を指定することで、イベントウェブフック `connection.destroyed` の `disconnect_api_reason` として指定した値が入ってきます。 詳細は [DisconnectConnection](API_SIGNALING.html#2ec3a0) をご確認ください。 ### 指定したクライアントのみを切断することはできますか? できます。 Sora はチャネル ID とクライアント ID を指定して接続を切断できます。 詳細は [DisconnectClient](API_SIGNALING.html#e91c0b) をご確認ください。 ### 指定したチャネルの配信者や視聴者のみを切断することはできますか? できます。 Sora はチャネル ID を指定して配信者や視聴者のみを接続を切断できます。 詳細は [DisconnectChannelByRole](API_SIGNALING.html#39de6a) をご確認ください。 ### 指定した配信者の映像を、指定した視聴者が受信しないことはできますか? できます。Sora は配信者、視聴者のコネクション ID を指定して映像を Sora で一時的に止めることができます。 詳細は [PauseRtpStream](EXPERIMENTAL_API_RTP_STREAM_PAUSE_RESUME.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 と VP9 と H.264 と AV1 、また音声コーデックは Opus と Lyra に対応しています。 録画ファイルは WebM 形式で保存されます。 H.265 の録画には現時点で対応していません。 ### 音声のみを録音できますか? できます。Opus と Lyra コーデックで音声のみの録音が可能になります。 `webma` ファイルではなく `webm` ファイルで出力されますのでご注意ください。 ### 録画した WebM のサイズの例を教えてください 基本的には指定したビットレートで決まります。 例として、VP8 と Opus の組み合わせの WebM で、 VP8 の解像度が 640x480 でビットレートが 300kbps 程度、音声ありの場合、 1 分の映像で約 2.5 M バイトです。 ### 録画が終了するタイミングを教えて下さい 録画終了するタイミングは 3 つあります。 1. [StopRecording](API_LEGACY_RECORDING.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 で UDP と TCP、TLS でどの経路が選択されるかはどう決められますか? クライアント側の実装に依存します。Sora はクライアントがどの経路を選択するかには関与しません。 ### TURN IPv6 に対応していますか? 対応しています。 ### TURN の FQDN 設定はどのようなときに設定が必要ですか? NAT64/DNS64 ネットワーク環境に対しては TURN の FQDN を設定する必要があります。 ## ウェブフック ### ウェブフックのリクエスト送信先は複数登録できますか? できません。 もし、送信先を複数にしたい場合は、登録した送信先のアプリケーションサーバーなどで対応をお願いします。 ### ウェブフックにベーシック認証は利用できますか? できます。 `sora.conf` にて [webhook_basic_authn](SORA_CONF.html#081a9f) の設定を有効にして下さい。 詳細については [ウェブフックリクエスト送信先のサーバーがベーシック認証を利用している場合](WEBHOOK.html#2a13ea) をご確認ください。 ### ウェブフックのタイムアウト値を設定できますか? できます。 `sora.conf` にて [webhook_response_timeout](SORA_CONF.html#e81d13) を設定することで、ウェブフックのレスポンスのタイムアウトが変更できます。 ### イベントウェブフックの session.updated の送信間隔を 1 分から変更できますか? できます。 `sora.conf` にて [session_updated_webhook_interval](SORA_CONF.html#4612dc) に `3 min` と設定することで、 session.updated のイベントウェブフックリクエストの送信間隔を 3 分に変更できます。 ### イベントウェブフックの session.updated を送らない設定はできますか? できます。 `sora.conf` にて [ignore_session_updated_webhook](SORA_CONF.html#0901a0) を `true` を設定することで、 session.updated のイベントウェブフックリクエストが送信されなくなります。 ### イベントウェブフックの connection.updated の戻り値を使用して切断などはできますか? できません。切断をする場合は Sora が持つ切断 API を使用してください。 ### イベントウェブフックの connection.updated の送信間隔を 1 分から変更できますか? できます。 `sora.conf` にて [connection_updated_webhook_interval](SORA_CONF.html#e67c3b) に `3 min` と設定することで、 connection.updated のイベントウェブフックリクエストの送信間隔を 3 分に変更できます。 ### イベントウェブフックの 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` が割り当てられます。 ### イベントウェブフックの処理が遅くなった場合の挙動はどうなりますか? イベントウェブフックワーカーがキューを持っており、もしそのワーカーがリクエストを処理中の場合、キューに追加されます。 そのリクエストの処理が終わりったらキューから取り出され処理されます。 ### 認証ウェブフックの同時接続数の項目を利用してセッション単位の接続数制限をかけることはできますか? できますが、厳密な制限をすることはできません。厳密な制限をかける場合はアプリ側で行っていただく必要があります。 詳細は [認証ウェブフックに含まれる同時接続数について](AUTH_WEBHOOK.html#258559) をご確認ください。 ## 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 ノードでもクラスターを構築できますか? できます。ただし推奨していません。 2 ノードの場合、どちらかのノードに障害が発生するとクラスター全体が止まってしまうため、 可用性は 1 ノードの場合よりも低くなります。 そのため 3 ノード以上でクラスターを組むことをお勧めします。 ### クラスターからノードを離脱させたい場合はどうすれば良いですか? Sora を終了することで離脱を行います。丁寧に離脱したい場合はモード切替で [新規コネクションブロックモード](MODE.html#0b67d3) を指定し、 すべての接続を切断してから終了してください。 もしそのノードが今後もクラスターに参加しない場合、 [PurgeClusterNode](EXPERIMENTAL_API_CLUSTER.html#13b35a) API を利用してクラスターからそのノードの情報を完全消去してください。 なおノード情報を完全消去せずに、一度に過半数のノードを離脱させてしまうと、 残ったノードも接続を処理できなくなってしまうので注意が必要です。 詳細については [全ノードが半数以下のグループに所属した場合の挙動](CLUSTER.html#c1120e) をご確認ください。 ### クラスターのディザスタリカバリーには対応していますか? 対応していません。今後対応予定はありますが、リリース時期は未定です。 ### クラスターのリレーには対応していますか? 対応していません。 2024 年にリリース予定です。 ### クラスターの最大ノード数はいくつですか? クラスターを構築するノードの最大数は 10 を想定しています。 これ以上のノード数でのクラスター構築を検討されている場合はサポートまでご連絡ください。 ## その他 ### IP アドレスは複数指定できますか? できますが、運用が複雑になるため、現時点ではドキュメントには記載していません。 もし、IP アドレスの複数指定を利用したい場合は、サポートまでお問い合わせください。 基本的には、クライアントごとに IP アドレスを変更したい場合は、認証時の戻り値を使用してください。 ### 配信者は音声と映像を配信し、視聴者は音声のみを受信することはできますか? できます。視聴者は配信者からの映像や音声のどちらかだけを受け取るよう指定できます。 詳細は [配信または視聴メディアの選択](SIGNALING.html#7cd3d2) をご確認ください。 ### 複数のユーザーの中で、発言していないユーザーは低画質な映像のみを配信し、発言しているユーザーは音声と高画質な映像を配信することはできますか? スポットライト機能を利用すればできます。 詳細は [スポットライト機能](SPOTLIGHT.html) をご確認ください ### サイマルキャストに対応していますか? 対応しています。ブラウザは Chrome と Edge と Safari の最新バージョンに対応しています。 それ以外のブラウザでは配信はできませんが、視聴はできます。 映像コーデックは VP8、VP9、AV1、H.264、H.265 に対応しています。 - VP8 サイマルキャストは Chrome と Edge と Safari が対応しています - VP9 サイマルキャストは Chrome と Edge が対応しています - AV1 サイマルキャストは Chrome のみが対応しています - H.264 サイマルキャストは Chrome と Edge と Safari が対応しています - H.265 サイマルキャストは Safari 実験的機能のみが対応しています ### 映像や音声を WebRTC 以外で出力する仕組みはありますか? [StartForwardingRtp](EXPERIMENTAL_API_RTP_FORWARDING.html#c734b8) API と [StopForwardingRtp](EXPERIMENTAL_API_RTP_FORWARDING.html#729828) API を利用することで、 外部のサーバーに対して WebRTC の DTLS (暗号部分) を除いた RTP パケットを送ることができます。 FFmpeg などを使用することで、 RTP から HLS や MPEG-DASH などに変換することもできます。 ### 映像の配信を一時的に止める仕組みはありますか? [PauseRtpStream](EXPERIMENTAL_API_RTP_STREAM_PAUSE_RESUME.html#de7a52) API と [ResumeRtpStream](EXPERIMENTAL_API_RTP_STREAM_PAUSE_RESUME.html#43002a) API を利用することで、 指定した接続からの映像の配信を一時的に停止できます。 ### HLS 配信はできますか? Sora 単体ではできません。ただし、Sora の [RTP 転送 API](EXPERIMENTAL_API_RTP_FORWARDING.html) を利用して FFmpeg などに転送することで、HLS での配信ができます。 **こちらのドキュメントは古いため参考程度にお願いします** [HLS 配信](HLS.html) をご確認ください。 ### 追いかけ再生はできますか? Sora 単体ではできません。 ただし、Sora の [RTP 転送 API](EXPERIMENTAL_API_RTP_FORWARDING.html) を利用して FFmpeg などに転送することで、HLS での配信ができます。 そのため、この HLS での配信を利用することで追いかけ再生を実現できます。 **こちらのドキュメントは古いため参考程度にお願いします** [HLS 配信](HLS.html) をご確認ください。 ### WebRTC 確立するまでにかかる時間は知ることができますか? [GetStatsReport](EXPERIMENTAL_API_STATS.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 チャネルで最大何クライアントまで対応していますか? 2023.2.7 時点で最大 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.conf` の設定 [websocket_signaling_ping_interval](SORA_CONF.html#27aae2) と [websocket_signaling_pong_timeout](SORA_CONF.html#140464) で変更できます。 ### Sora の DataChannel を利用したシグナリングの Sora 側からの切断条件は何ですか? Sora は定期的に接続状態を確認する仕組みを持っており、その仕組みで切断かどうかを判断しています。 詳細は [ICE コネクションステート](ICE_CONNECTION_STATE.html) をご確認ください。 ### Sora 1 台のサーバーでは最大同時接続数はいくつですか? 現状 1 台では 5000 接続までを推奨しています。 多くの接続を 1 台で行いたい場合、まずはサポートまでご相談ください。 ### Sora が対応している OS は何ですか? 2023.2.7 の時点では以下の OS に対応しています。 - Ubuntu 22.04 LTS x86_64 - Ubuntu 20.04 LTS x86_64 - Red Hat Enterprise Linux 9 x86_64- マイナーバージョンアップ版は全てサポート対象です - 可能な限り最新のバージョンをご利用ください - Red Hat Enterprise Linux 8 x86_64- マイナーバージョンアップ版は全てサポート対象です - 可能な限り最新のバージョンをご利用ください - CentOS 7 x86_64- 新規でのお客様向けには提供は行っておらず、既存のお客様向けにのみ提供しています - カーネルが古く Sora の性能が引き出せないため、非推奨としています - CentOS 7 のサポートが終了する 2024 年 6 月にて 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.jsonl と connection.jsonl はローテションされませんので必要な部分で 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.jsonl` を確認してみてください。 このログで映像の送信側と受信側の統計情報が確認できますので、 映像が乱れたり止まったりした接続の `connection_id` を記録しておいて下さい。 - total_received_rtcp_rtpfb_generic_nack - total_sent_rtcp_rtpfb_generic_nack この値が多ければ多いほど「再送要求」の回数が多く、回線が不安定だったことが把握できます。 `connection.jsonl` の詳細については [connection ログ](LOG.html#f2e264) をご確認ください。 ### Sora が突然終了しました Sora は何か問題があり Sora が終了した場合 `erl_crash.dump` というログを出力します。 このログが出力された場合はサポート問い合わせの手順に従ってサポートまでご連絡ください。 もし `erl_crash.dump` が出力されずに Sora が終了した場合はカーネル側から停止された可能性があります。 まずは OOM Killer で殺されていないかどうかを確認してみてください。 ### Sora で利用している Erlang VM のフラグを指定することはできますか? > **重要** > > この設定を利用する場合はサポートまでお問い合わせください できます。環境変数 `SORA_ADDITIONAL_ERL_ARGS` を利用してください。 ## SDK Sora の SDK は基本的にシグナリング処理のための SDK です。 WebRTC 部分は webrtc.org が提供しているライブラリを利用しています。 ### Sora の SDK へのサポートはありますか? Sora の SDK サポートは提供していません。また有償のサポートも提供していません。 もしアドバイスが必要だったり、問題が起きたりした場合は Discord へお願いします。バグ対応は最優先で行います。 ### Discord サーバーの招待 URL SDK の質問や相談については `sora-sdk-faq` を利用してください。 - 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 Python SDK- 投稿時に `sora-python-sdk` タグを指定してください - Sora C SDK- 投稿時に `sora-c-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) ### Unity SDK はありますか? Sora の Unity SDK に関しては以下をご確認ください。 C++ SDK をベースにしています。 - [Sora Unity SDK ドキュメント — ora Unity SDK ドキュメント](https://sora-unity-sdk.shiguredo.jp/) - [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) ### Python SDK はありますか? Sora の Python SDK に関しては以下をご確認ください。 C++ SDK をベースにしています。 - [Sora Python SDK ドキュメント — Sora Python SDK](https://sora-python-sdk.shiguredo.jp/) - [WebRTC SFU Sora Python SDK](https://github.com/shiguredo/sora-python-sdk) ### JavaScript SDK は認証付き HTTP Proxy に対応していますか? JavaScript SDK はブラウザで動作するため、ブラウザが WebRTC での HTTP Proxy に対応している必要があります。 主要なブラウザは HTTP Proxy に対応済みです。利用する場合はブラウザで HTTP Proxy の設定をしてください。 ### iOS / Android / Unity / C++ SDK / Python SDK は認証付き HTTP Proxy に対応していますか? 対応しています。ただし Basic 認証のみの対応で、 **OS の設定や PAC ファイルへの対応は未定です** 。 - iOS SDK- 最新版で対応済みです - Android SDK- 最新版で対応済みです - C++ SDK- 最新版で対応済みです - Unity SDK- 最新版で対応済みです - Python SDK- 最新版で対応済みです - C 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_STATS.html#bbbfca) API の `total_ongoing_connections` で現在 Sora に接続している同時接続数が確認できます。 ### ライセンス期限のタイムゾーンを教えてください UTC です。 ### クラスター利用時に同一のライセンスを利用する方法はありますか? あります。 `最大ノード数ライセンス` を契約することで、 1 つのクラスター構築時に同一のライセンスを利用できるようになります。 `最大ノード数ライセンス` では、 1 クラスターで同一のライセンスを最大いくつのノードに適用できるかがあらかじめ定義されています。 クラスターを構築する際に、その最大ノード数までは同一ライセンスを利用できます。 詳細は [最大ノード数ライセンス](LICENSE.html#aee259) をご確認ください。 ### 最大ノード数ライセンスで契約できる最大ノード数はいくつですか? 最大ノード数は 10 を想定しています。 ## アップデート ### アップデートは有償ですか? ライセンスをご契約いただいている期間は、無償でアップデートを提供させていただきます。 ### アップデートのタイミングは決まっていますか? 原則として毎年 6 月と 12 月に、機能の追加や改善、削除を目的としたアップデートを行います。 その他、必要に合わせて不定期に修正のアップデートを行うことがあります。 詳細は [サポートライフサイクル](SUPPORT_LIFECYCLE.html) をご確認ください。 ### Sora のバージョン表記 バージョン表記: ``` YYYY.MAJOR.FIX ``` - `YYYY` はリリースした年を示します - `MAJOR` はその年のメジャーアップデートのリリース回数を示します - `FIX` はバグフィックスアップデートおよびホットフィックスアップデートのリリース回数を示します 詳細は [サポートライフサイクル](SUPPORT_LIFECYCLE.html) をご確認ください。 ## サポート ### 古いバージョンの Sora のサポートは提供していますか? 以前は最新バージョンの利用に対してのみサポートを提供していましたが、Sora 2023.1.0 以降はサポート提供期間を約 12 ヶ月間に変更しました。 詳細は [サポートライフサイクル](SUPPORT_LIFECYCLE.html) をご確認ください。 ### 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.conf` の設定 [websocket_signaling_ping_interval](SORA_CONF.html#27aae2) と [websocket_signaling_pong_timeout](SORA_CONF.html#140464) で変更できます。 これは Sora がクライアントが疎通不能だと判断して切断した、正常な終了です。 まずはクライアントのネットワーク状況を確認してみてください。 WebSocket が詰まることを回避する方法としては、 [DataChannel 経由のシグナリング](DATA_CHANNEL_SIGNALING.html) の利用を検討してください。 ### sora ログに `tcp_closed` という文字列が含まれている場合 この場合、通信に TURN-TCP が採用されており、OS 側で TCP の切断を検知し、接続を終了しています。 connection ログの `turn_transport_type` で `tcp` になっているかどうかを確認してみてください。 OS による TCP の切断に関しては Sora 側で対処できる事は基本的にはありません。 ## VP9 の映像が乱れる Windows で Intel の GPU を利用している場合に、VP9 のハードウェアアクセラレーターが正常に動作しないことがあります。 この場合は VP9 を利用せずに、他のコーデックを利用する事で回避してください。 ハードウェアアクセラレーターを明示的に無効にすることで回避することもできますが、 こちらはあまり現実的ではありません。 `chrome://flags/#disable-accelerated-video-decode` を `Disabled` にする事で、 ハードウェアアクセラレーターを利用しなくなります。 ![image](https://i.gyazo.com/b8838400a258ecd95a242a620fb8222c.png) ### 問題が発生した場合の確認方法 `chrome://webrtc-internals` の `inbound-rtp` を見ていただき、 `[codec]` と `decoderImplementation` を確認してみてください。 ここで VP9 と `ExternalDecoder` となっている場合、 VP9 のデコードにハードウェアアクセラレーターが利用されていることが確認できます。 ![image](https://i.gyazo.com/4ac60a51e49160723dcbd2feb438c8da.png) # Sora が期待どおりに動かない場合、または、動作に問題がある場合 Sora が期待どおりに動かない場合、 または動作に問題がある場合の問い合わせ時の事前確認と注意事項をまとめています。 ## 事前確認 問い合わせの前に、まずは以下の項目について事前に確認をお願いします。 ### サポートしている Sora のバージョン - Sora 2023.1.x- 2024 年 6 月 30 日までサポート - Sora 2023.2.x- 2024 年 12 月 31 日までサポート ### 利用している Sora のバージョンがサポート期限内かどうかを確認してください もし、サポートしているバージョンを利用していない場合は、 サポートしているバージョンへのアップデート後に問題が再現するかの確認をお願いします。 ### Sora の SDK サポートについては Sora サポート範囲外のため Discord サーバーの各チャンネルをご利用ください **時雨堂コミュニティサーバー**: SDK の質問や相談については `sora-sdk-faq` を利用してください。 - 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 Python SDK- 投稿時に `sora-python-sdk` タグを指定してください - Sora C SDK- 投稿時に `sora-c-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 Archive Uploader - 各種クラウドサービス 上記はすべて Sora のサポート範囲外となります。 ## 問い合わせの場合、お送り頂く情報 > **重要** > > 前述の事前の確認後、以下の情報を **必ず** お送り下さい。 情報をお送り頂くときは `テキストファイル` でお送りください。 - サーバーやクライアントのスペック- わかれば機種名 - CPU - メモリ - ディスク - Linux Kernel のバージョン- `uname -a` の出力 - OS の種類、バージョン- Ubuntu、 Red Hat Enterprise Linux、CentOS のどれを使っているか - 使っているバージョン - Sora のバージョン- 2022.1.2 など - クラスターを利用している場合はクラスターの構成 - Sora の **sora.conf 設定ファイル** - Sora の log ディレクトリ以下すべてのログファイル- クラスターを利用している場合は全ノードのログ - tar.gz または zip などで圧縮し、パッケージ提供時にお送りしているログアップローダーを利用してお送りください - 評価中の場合は tar.gz または zip などで圧縮し、メールにてお送り下さい - 問題発生時の前後 1 週間分をめどにお送りください ### 詳細な問題発生状況 **何をどうすると問題が発生したのかの状況を可能な限り詳細にお教え下さい** > **重要** > > 以下の情報については **必ず** お送り下さい。 - シグナリングの情報- チャネル ID - セッション ID - コネクション ID - 音声の有無- コーデック - ビットレート - 映像の有無- コーデック - ビットレート - 解像度 - サイマルキャスト機能の有無 - マルチストリーム機能の有無 - スポットライト機能の有無 - 問題が発生したブラウザバージョン- Chrome 119.0.6045.159 や Safari 17.1 など - 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 の仕様や使い方に関して不明点がある場合は Sora のバージョンとドキュメントの URL を添えてお送りください。 # サポートライフサイクル ## 概要 Sora 2023.1.0 より、サポートの提供期間を変更します。 ## 変更内容 これまでは Sora の最新バージョンの利用に対してのみサポートを提供していましたが、Sora 2023.1.0 以降はサポートの提供期間をより長く変更します。 また、合わせて Sora のアップデートを以下のとおりに区別します。 ### メジャーアップデート **サポート提供期間**: **メジャーアップデートがリリースされた日から 12 ヶ月後の月末最終日まで** - 原則として毎年 6 月と 12 月に、機能の追加や改善、削除を目的として行うアップデートをメジャーアップデートといいます - このアップデートでは、以前のバージョンと後方互換性のない新機能が含まれたり、以前のバージョンの機能が削除されたりする場合があります > **重要** > > - 2023 年 6 月 28 日にリリースされた Sora 2023.1.0 は、2024 年 6 月 30 日までサポートを提供します > - 2023 年 12 月 20 日にリリースされた Sora 2023.2.0 は、2024 年 12 月 31 日までサポートを提供します ### バグフィックスアップデート **サポート提供期間**: **修正の対象となるメジャーアップデートがリリースされた日から 12 ヶ月後の月末最終日まで** - メジャーアップデートをリリースして以降、次のメジャーアップデートまでの約 6 ヶ月の間に、問題の修正を目的として不定期に行うアップデートをバグフィックスアップデートといいます ### ホットフィックスアップデート **サポート提供期間**: **修正の対象となるメジャーアップデートがリリースされた日から 12 ヶ月後の月末最終日まで** - メジャーアップデート、バグフィックスアップデート以外に、ごく稀に緊急のアップデートが必要と判断する場合に行うアップデートをホットフィックスアップデートといいます - 最新バージョン以外にも、アップデートの必要があると判断する以前のバージョン、およびその両方に対してリリースを行う可能性があります ### Sora のバージョン表記 **YYYY.MAJOR.FIX** - `YYYY` はリリースした年を示します - `MAJOR` はその年のメジャーアップデートのリリース回数を示します- Sora 2023.1.0 は、2023 年の 1 回目のメジャーアップデートであることを示します - `FIX` は バグフィックスアップデートおよびホットフィックスアップデートのリリース回数を示します- Sora 2023.2.1 は、Sora 2023.2.0 に対する 1 回目のバグフィックスアップデートもしくはホットフィックスアップデートであることを示します - `FIX` のリリース回数は社内のみのリリースも含むことがあるため、公開時のリリース回数は飛ぶ可能性があります ## ライフサイクル例 ![image](https://i.gyazo.com/8162ff066ea4680fa70733b00b4e622b.png) ## 対応 OS のサポートライフサイクル ### Ubuntu 22.04 LTS **スタンダードサポートまで対応** 2027 年 4 月 30 日にスタンダードサポートが終了するため、 2026 年 6 月リリース予定の Sora までがサポート対象となります。 ### Ubuntu 20.04 LTS **スタンダードサポートまで対応** 2025 年 4 月 30 日にスタンダードサポートが終了するため、 2024 年 6 月リリース予定の Sora までがサポート対象となります。 ### Red Hat Enterprise Linux 9 **メンテナンスサポートまで対応** 2032 年 5 月 31 日にメンテナンスサポートが終了するため、 2031 年 6 月リリース予定の Sora までがサポート対象となります. ### Red Hat Enterprise Linux 8 **メンテナンスサポートまで対応** 2029 年 5 月 31 日にメンテナンスサポートが終了するため、 2028 年 6 月リリース予定の Sora までがサポート対象となります。 # チュートリアル ## 概要 このチュートリアルでは、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` していけば参加者を増やせます。 開発ツールでは気軽にいろいろな設定を試せるようになっています。触ってみてください。 ## 次のステップ [本番稼働に向けて](PRODUCTION.html) で Sora の本番稼働向けの設定を行ってください。 Sora はいろいろな機能を持っていますので、一通りドキュメントをご確認下さい。 ドキュメントで不明な点がありましたら、お気軽にお問い合わせください。 > **注釈** > > アプリケーション連携チュートリアル は Sora を利用したアプリケーション連携用のチュートリアルを Python にて説明しています。 ## トラブルシューティング ### タイムアウトが起きてつながらない場合 > **重要** > > 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 をなんとなく体験したあとに、 本番環境に向けてどのような準備が必要なのか、どの機能を使っていけばいいのかをまとめたものです。 不明点などはサポートまでお問い合わせください。 ## 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 ``` ## ウェブフックなどで利用する CA 証明書のインストール もしウェブフックなどで HTTPS サーバへのアクセスを行う場合に、 自前で CA 証明書を設定しない場合、信頼された CA 証明書のインストールを行ってください。 - Ubuntu は `apt install ca-certificates` でインストールされる証明書を利用します - RHEL (または CentOS) は `dnf install ca-certificates` でインストールされる証明書を利用します ### 影響を受ける機能 - 認証ウェブフック - セッションウェブフック - イベントウェブフック - 音声ストリーミング機能 - 統計エクスポーター機能 ただし、以下の設定で自前で CA 証明書を指定している場合は、この影響を受けません。 - [webhook_tls_verify_cacert_file](SORA_CONF.html#7036dc) - [audio_streaming_tls_verify_cacert_file](SORA_CONF.html#feef99) - [stats_exporter_tls_verify_cacert_file](SORA_CONF.html#bcd961) ## HTTP API のループバックアドレスからのみのアクセス > **重要** > > この設定を導入することを強く推奨します Sora の HTTP API は TLS を利用したセキュアな通信機能や認証機能を持ち合わせていません。 そのため、本番環境では `sora.conf` の [api_loopback_address_only](SORA_CONF.html#9d6140) の値を `true` にしてください。 こうすることでループバックアドレスからのみ HTTP API が叩けるようになります。 アプリケーションからの HTTP API へのアクセスは Nginx などのリバースプロキシ経由で利用してください。 ## シグナリングのループバックアドレスからのみのアクセス > **重要** > > この設定を導入することを強く推奨します Sora の WebSocket は TLS を利用したセキュアな通信機能を持ち合わせていません。 そのため、本番環境では `sora.conf` の [signaling_loopback_address_only](SORA_CONF.html#e22105) の値を `true` にしてください。 こうすることでループバックアドレスからのみシグナリングが叩けるようになります。 WebRTC クライアントからシグナリングへのアクセスは Nginx などのリバースプロキシ経由で利用してください。 ## ファイルディスクリプタ数の設定 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/; } # OBS (WHIP) 向けのシグナリングを Sora に Proxy します location ~ ^/(whip|whip-resource)/ { proxy_pass http://127.0.0.1:5000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Authorization $http_authorization; } # 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 ``` ### Ubuntu 20.04 または 22.04 の Nginx で Unix Domain Socket を利用する際の注意点 SIGTERM を利用するようにしないと、リスタートすることができません。 ```console $ sudo vim /lib/systemd/system/nginx.service ``` ```systemd # Stop dance for nginx # ======================= # # ExecStop sends SIGSTOP (graceful stop) to the nginx process. # If, after 5s (--retry QUIT/5) nginx is still running, systemd takes control # and sends SIGTERM (fast shutdown) to the main process. # After another 5s (TimeoutStopSec=5), and if nginx is alive, systemd sends # SIGKILL to all the remaining processes in the process group (KillMode=mixed). # # nginx signals reference doc: # http://nginx.org/en/docs/control.html # [Unit] Description=A high performance web server and a reverse proxy server Documentation=man:nginx(8) After=network.target [Service] Type=forking PIDFile=/run/nginx.pid ExecStartPre=/usr/sbin/nginx -t -q -g 'daemon on; master_process on;' ExecStart=/usr/sbin/nginx -g 'daemon on; master_process on;' ExecReload=/usr/sbin/nginx -g 'daemon on; master_process on;' -s reload # 変更前の設定 # ExecStop=-/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pid # 変更後の設定 ExecStop=-/sbin/start-stop-daemon --quiet --stop --signal TERM --pidfile /run/nginx.pid TimeoutStopSec=5 KillMode=mixed [Install] WantedBy=multi-user.target ``` `ExecStop=-/sbin/start-stop-daemon --quiet --stop --signal TERM --pidfile /run/nginx.pid` に変更してください。 その後、以下のコマンドを実行してください。 ```console $ sudo systemctl daemon-reload $ sudo systemctl restart nginx ``` ## カーネルパラメーターの適用 Sora は UDP を利用します。音声や映像の配信では大量の UDP を処理するため Linux のデフォルトの設定だと厳しい場合があります。 そのため、パラメーターの変更を推奨しています。 詳細は [Linux カーネルチューニング](LINUX_KERNEL_TUNING.html) をご確認ください。 ## SDK の利用 Sora へ接続をする場合は弊社がオープンソースとして公開している SDK を利用してください。 これらのライブラリは弊社によって最新版の Sora で動作するようにメンテナンスされています。 導入もとても簡単になっているので、是非利用してください。 > **重要** > > SDK に関する質問・要望・バグなどの報告は Discord の利用をお願いします。 > Sora のライセンス契約の有無に関わらず、 > 応答時間と問題の解決を保証しませんのでご了承ください。 > > ただし、明らかなバグについては優先的に対応しますので、ご安心ください。 SDK の質問や相談については `sora-sdk-faq` を利用してください。 - 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 Python SDK- 投稿時に `sora-python-sdk` タグを指定してください - Sora C SDK- 投稿時に `sora-c-sdk` タグを指定してください ## やりたいことが 1:1 の双方向配信の場合 配信が 1:1 の双方向の場合はマルチストリーム機能を利用してください。 詳細は [マルチストリーム機能](MULTISTREAM.html) をご確認ください。 ## やりたいことが複数人での双方向配信の場合 複数人で双方向の配信を行いたい場合はスポットライト機能を検討してください。 スポットライト機能を利用することで、クライアントとサーバー側の負荷をかなり抑えられるようになります。 詳細は [スポットライト機能](SPOTLIGHT.html) をご確認ください。 ## やりたいことが 1:多 の双方向配信の場合 配信が 1:多 の片方向の場合でもマルチストリーム機能を利用してください。 `role` に `sendonly` と `recvonly` を利用してください。 詳細は [マルチストリーム機能](MULTISTREAM.html) をご確認ください。 ## やりたいことが OBS からの配信の場合 OBS からの配信を行いたい場合は OBS (WHIP) 対応機能を利用してください。 詳細は [OBS (WHIP) 対応機能](WHIP.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 にコピーしてください。 ```console $ 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 のライセンスは Sora 1 起動 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.jsonl- Sora の開始、終了や問題があった場合に出力されますので、まずはこの監視をお願いします - ログローテーションされませんので、ログローテーションをお願いします - 週次ログローテーションを推奨します - cluster.jsonl- Sora クラスターに関するログが出力されます - **Sora クラスターを利用していない場合も出力されます** - ログローテーションされませんので、ログローテーションをお願いします - 週次ログローテーションを推奨します - auth_webhook.jsonl- auth_webhook で外部に送信する処理をすべて書き込みます - ログローテーションされませんので、ログローテーションをお願いします - 週次ログローテーションを推奨します - session_webhook.jsonl- session_webhook で外部に送信する処理をすべて書き込みます - ログローテーションされませんので、ログローテーションをお願いします - 週次ログローテーションを推奨します - session_webhook_error.jsonl- session_webhook で外部への送信が失敗した処理を書き込みます - ログローテーションされませんので、ログローテーションをお願いします - 週次ログローテーションを推奨します - event_webhook.jsonl- event_webhook で外部に送信する処理をすべて書き込みます - ログローテーションされませんので、ログローテーションをお願いします - 週次ログローテーションを推奨します - event_webhook_error.jsonl- event_webhook で外部に送信が失敗した処理を書き込みます - ログローテーションされませんので、ログローテーションをお願いします - 週次ログローテーションを推奨します ### Sora のサポートに関係するログ - connection.jsonl- 接続が切断した際にクライアントとサーバーの統計情報を出力するログです - ログローテーションされませんので、ログローテーションをお願いします - 週次ログローテーションを推奨します - signaling.jsonl- シグナリングでやりとりされている offer/answer/candidate/re-offer/re-answer と接続終了を記録したログです - ログローテーションされませんので、ログローテーションをお願いします - 週次ログローテーションを推奨します - api.jsonl- 一部の API 操作に関するログを出力します - ログローテーションされませんので、ログローテーションをお願いします - 週次ログローテーションを推奨します - 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 ログに `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 ログ - internal ログ - api ログ - signaling ログ - connection ログ - auth_webhook ログ - session_webhook ログ - session_webhook_error ログ - event_webhook ログ - event_webhook_error ログ - cluster ログ - connection_created_wait_timeout_error ログ ### id Sora が出力する全ての JSONL 形式のログには UUIDv4 を Base32 でエンコードした `"id"` が含まれます。 `"id": "JKBYVZA3KN6QH249B6QTKDCX8M"` ## auth_webhook ログ **出力ファイル名**: auth_webhook.jsonl ```javascript { "timestamp": "2024-01-19T02:44:22.799941Z", "id": "7N7RTNSEVN43ZB7NVXGAYPETJ4", "req": { "timestamp": "2024-01-19T02:44:22.793747Z", "id": "1EYTQSFVZ56MZ2BRZC12GQYQKW", "version": "2023.2.2", "label": "WebRTC SFU Sora", "node_name": "sora@127.0.0.1", "role": "sendrecv", "channel_id": "sora", "connection_id": "9SRMRSDWA959XFN74DCV3Z6XA0", "multistream": true, "simulcast": false, "spotlight": false, "audio": true, "audio_codec_type": "OPUS", "video": true, "video_codec_type": "VP9", "video_bit_rate": 500, "video_vp9_params": { "profile_id": 0 }, "data_channel_signaling": true, "ignore_disconnect_websocket": false, "channel_connections": 0, "channel_sendrecv_connections": 0, "channel_sendonly_connections": 0, "channel_recvonly_connections": 0, "sora_client": { "raw": "Sora JavaScript SDK 2023.2.0", "type": "Sora JavaScript SDK", "version": "2023.2.0", "environment": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" }, "e2ee": false }, "res": { "allowed": true, "client_id": "client-01" }, "url": "http://192.0.2.1:9000/webhook/auth" } ``` ### auth_webhook ログの `res` 項目について 認証ウェブフックが正常に動作しなかった場合、 レスポンスの JSON が取得できないため `res` 項目は書き込まれません。 - auth_webhook_url が未指定の場合でも `{"allowed": true}` が `res` 項目として出力されます - auth_webhook_url にアクセスができない場合は出力されません - auth_webhook_url のステータスコードが 2XX 系以外の場合は出力されません- エラーは sora ログに出力されます - auth_webhook_url のステータスコードが 2XX 系でも戻り値の JSON がパースできない場合は出力されません- エラーは sora ログに出力されます ## session_webhook ログ **出力ファイル名**: session_webhook.jsonl ```javascript { "id": "XJ227VDDFH60BAB833C1R2HDBW", "timestamp": "2024-04-19T05:32:25.583312Z", "req": { "id": "D5PAF0ZHDX00B4VAWMZAR866MR", "label": "WebRTC SFU Sora", "timestamp": "2024-04-19T05:32:24.280641Z", "type": "session.created", "version": "2024.1.0", "node_name": "sora@127.0.0.1", "session_id": "NAA3DGPJQH2J7FDV698RZ9X6R0", "channel_id": "sora", "multistream": true, "spotlight": false, "created_time": 1713504744, "created_timestamp": "2024-04-19T05:32:24.277809Z" }, "url": "http://192.0.2.1/webhook/session", "res": { "recording": true } } ``` ### session_webhook ログの `res` 項目について 認証ウェブフックが正常に動作しなかった場合、 レスポンスの JSON が取得できないため `res` 項目は書き込まれません。 - session_webhook_url にアクセスができない場合は出力されません - session_webhook_url のステータスコードが 2XX 系以外の場合は出力されません- エラーは sora ログに出力されます - session_webhook_url のステータスコードが 2XX 系でも戻り値の JSON がパースできない場合は出力されません- エラーは sora ログに出力されます ## connection ログ **出力ファイル名**: connection.jsonl Sora は接続単位で統計情報を保持しています。クライアント側の統計情報とサーバー側の統計情報の両方をログとして出力します。 クライアント側の統計情報はユーザーエージェント統計情報機能を利用しているため、 SDK 側がユーザーエージェント統計機能に対応している必要があります。 こちらのログはログローテーションしないため、ローテーションが必要となります。 ## sora ログ **出力ファイル名**: sora.jsonl sora ログは主にサポートで利用するためのログを出力します。そのためエラーメッセージがかなり技術的な表現になっています。 - sora ログは何かあって大量のログが出たとしてもうまい具合にスキップする機能が入っています ### UTC に固定 sora ログのタイムスタンプは RFC 3339 UTC (マイクロ秒) 形式に固定されています。 `timestamp` という項目でタイムスタンプが出力されます。 ```javascript { "id": "QGJMC1AF3552V448N8F53CZBJ4", "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" } ``` ### クラスター利用時 ```javascript { "id": "QR6YX8VW8H76N6S3B7HBCXJ4PM", "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" } ``` ### オプション情報 ```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" } ``` ### 出力例 シグナリング接続時に認証サーバーがステータスコード 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" } ``` シグナリング接続時の `"type": "connect"` で指定する JSON が間違っており、Sora 側から切断した際に出力される `INVALID-JSON` の出力例は次のとおりです。 ```javascript { "msg": "INVALID-JSON | reason=...", "node": "sora@127.0.0.1", "level": "error", "domain": [ "sora", "signaling" ], "channel_id": "sora", "timestamp": "2023-11-02T02:12:35.854402Z", "sora_version": "2022.2.0" } ``` シグナリングに WebSocket を利用している場合に、指定時間に一度も `"type": "pong"` が返ってこない場合Sora 側から切断した際に出力される `PONG-TIMEOUT-ERROR` の出力例は次の通りです。 指定時間のデフォルト値は 60 秒です。 `sora.conf` の設定 [websocket_signaling_pong_timeout](SORA_CONF.html#140464) で変更できます。 ```javascript { "msg": "PONG-TIMEOUT-ERROR | reason=<<\"WebSocket\">>", "node": "sora@127.0.0.1", "role": "sendrecv", "level": "error", "domain": [ "sora", "signaling" ], "simulcast": false, "spotlight": false, "timestamp": "2023-11-02T02:12:35.854402Z", "channel_id": "sora", "multistream": true, "sora_version": "2023.1.0", "connection_id": "174QEZP34D45B6S7665Y32MSQ0" } ``` ### 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` が返ってこない場合に出力します - これらの時間は `sora.conf` の設定 [websocket_signaling_ping_interval](SORA_CONF.html#27aae2) と [websocket_signaling_pong_timeout](SORA_CONF.html#140464) で変更できます。 - 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- 認証ウェブフックの戻り値で内部エラーが発生した場合出力します - セッションウェブフック- SESSION-WEBHOOK-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 を終了します。 - SORA-NODE-DUPLICATED- 同一ノード名の 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 ``` > **注釈** > > 利用できる単位が制限されている設定項目も存在します。 ## 範囲表記 - `2..10` と書いてある場合 2 以上、10 以下の値を指定できることを表しています - `2..10 s` と書いてある場合は 2 秒以上、10 秒以下の値を指定できることを表しています ## 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 ``` ## ipv6_only **デフォルト**: false IPv6 アドレスのみを利用するようになります。この設定はシグナリングや API には影響しません。 ```ini ipv6_only = true ``` ## devtools **デフォルト**: false Sora には機能をすぐに試してもらえるように開発ツールが含まれています。 開発ツールを有効にする場合は、 `true` を指定し、有効にしてください。 詳細は [開発者ツール](DEVTOOLS.html) をご確認ください。 ```ini devtools = true ``` ## rtp_publish_worker_number **デフォルト**: 1 音声や映像の 1 配信に利用する配信ワーカー数を指定してください。 ```ini rtp_publish_worker_number = 1 ``` ## 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 セッションが存在しない状態で、新規接続が来た際にセッション生成に利用できる時間を指定してください。 この時間はセッションウェブフックにかかる時間も含まれます。 ```ini session_created_timeout = 5 s ``` ## session_destroyed_timeout **デフォルト**: 15 s **範囲**: 0..300 s セッションに同時接続数が 0 になった場合、セッション破棄する時間を指定してください。 ```ini session_destroyed_timeout = 15 s ``` ## session_updated_webhook_interval **デフォルト**: 1 min **範囲**: 1..10 min **単位**: min のみ セッション更新時のセッションウェブフック `session.updated` の間隔を指定してください。 時間単位には 分 `min` のみ指定できます。 ```ini session_updated_webhook_interval = 1 min ``` ## 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_ipv6 **デフォルト**: false ウェブフックで IPv6 を利用するかどうかを指定してください。 この設定を `true` にしない限り、ウェブフックでは IPv4 が利用されます。 ```ini webhook_ipv6 = true ``` ## webhook_response_timeout **デフォルト**: 5 s **範囲**: 1..600 s ウェブフックのレスポンスタイムアウト時間を指定してください。 ```ini webhook_response_timeout = 5 s ``` ## connection_updated_webhook_interval **デフォルト**: 1 min **範囲**: 1..10 min **単位**: min のみ 接続更新時のイベントウェブフック `connection.updated` の間隔を指定してください。 時間単位には 分 `min` のみ指定できます。 ```ini connection_updated_webhook_interval = 1 min ``` ## 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 ``` > **重要** > > この設定がない場合、 OS 組み込みのルート CA 証明書を利用してサーバー証明書をチェックします。 > OS 組み込みのルート CA 証明書については [ウェブフックリクエストなどの送信先サーバー証明書の検証に利用する OS 組み込みのルート CA 証明書について](WEBHOOK.html#e8a845) をご確認ください。 ## 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 = false ``` ## ignore_session_updated_webhook **デフォルト**: false セッションウェブフックのセッションの更新時に `session_webhook_url` に指定された URL へ `session.updated` を送るかどうかを指定してください。 デフォルトではリクエストの送信を行います。 ```ini ignore_session_updated_webhook = false ``` ## ignore_session_vanished_webhook **デフォルト**: true モードが `block_new_session` または `block_new_connection` の際に、 `session_webhook_url` に指定された URL に `session.vanished` リクエストを送るかどうか指定してください。 デフォルトではリクエストの送信を行いません。 ```ini ignore_session_vanished_webhook = false ``` ## ignore_audio_streaming_webhook **デフォルト**: true 音声ストリーミング機能で音声が送信された場合に、 `event_webhook_url` に登録された URL に `audio_streaming.started` と `audio_streaming.stopped` リクエストを送るかどうかを指定してください。 デフォルトではリクエストの送信を行いません。 ```ini ignore_audio_streaming_webhook = false ``` ## 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 ``` ## ignore_split_archive_available_webhook **デフォルト**: false 録画機能で、分割録画を含む場合に分割した録画ファイルが利用可能になった際、 `split-archive.available` リクエストを送信するかどうかを指定してください。 デフォルトではリクエストの送信を行います。 ```ini ignore_split_archive_available_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` は違うディレクトリを指定してください ## recording_max_expire_time **デフォルト**: 86400 s **範囲**: 1..86400 s 録画時に指定する `expire_time` の最大値を指定してください。 ```ini recording_max_expire_time = 10 min ``` ## recording_max_split_duration **デフォルト**: 86400 s **範囲**: 1..86400 s 録画で分割または一括&分割録画時に `split_duration` の最大値を指定してください。 ```ini recording_max_split_duration = 10 min ``` ## recording_expire_time_required **デフォルト**: false > **重要** > > この設定は一括録画時に録画ファイルが大きくなりすぎるのを防ぐための設定です。 録画で一括または一括&分割録画時に `expire_time` の指定を必須にするかどうかを指定してください。 ```ini recording_expire_time_required = true ``` ## recording_dual_output **デフォルト**: true 録画で一括&分割録画を利用できるようにするかどうかを指定してください。 > **重要** > > この設定が false になっている際に一括&分割録画をしようとするとエラーになります ```ini recording_dual_output = 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_connection_created_timestamp **デフォルト**: true シグナリング通知機能が有効な際、`"event_type": "connection.created"` に `timestamp` を含むかどうかを指定してください。 ```ini signaling_notify_connection_created_timestamp = 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 > **注釈** > > この設定を 0 にすることでクライアントからシグナリング通知メタデータを指定できなくなります。 クライアントから接続時に送られてくるシグナリング通知メタデータの最大サイズをバイト単位で指定してください。 ```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_notify_forwarding_filter **デフォルト**: true シグナリング通知機能が有効な際、 転送フィルターのブロック開始とブロック解除の通知をするかどうかを指定してください。 ```ini signaling_notify_forwarding_filter = true ``` ## signaling_vp9_params **デフォルト**: false シグナリングで VP9 のパラメーターを指定できるようにするかを指定してください。 ```ini signaling_vp9_params = true ``` ## signaling_av1_params **デフォルト**: false シグナリングで AV1 のパラメーターを指定できるようにするかを指定してください。 ```ini signaling_av1_params = true ``` ## signaling_h264_params **デフォルト**: false シグナリングで H.264 のパラメーターを指定できるようにするかを指定してください。 ```ini signaling_h264_params = true ``` ## signaling_h265_params **デフォルト**: false シグナリングで H.265 のパラメーターを指定できるようにするかを指定してください。 ```ini signaling_h265_params = true ``` ## signaling_bundle_id **デフォルト**: false シグナリングでバンドル ID を指定できるようにするかを指定してください。 ```ini signaling_bundle_id = true ``` ## websocket_signaling_ping_interval **単位指定必須** **デフォルト**: 5 s **範囲**: 5..300 s WebSocket 経由のシグナリングの場合に、サーバーからクライアントへネットワーク死活監視のために `"type": "ping"` を送信する間隔を指定してください。 > **重要** > > ここで指定する値は [websocket_signaling_pong_timeout](SORA_CONF.html#140464) より短くしてください。 ```ini websocket_signaling_ping_interval = 5 s ``` ## websocket_signaling_pong_timeout **単位指定必須** **デフォルト**: 60 s **範囲**: 60..600 s WebSocket 経由のシグナリングの場合に、クライアントから返却される `"type": "pong"` のタイムアウト時間を指定してください。 この時間内に `"type": "pong"` が返却されない場合はサーバーから接続を切断します。 > **重要** > > ここで指定する値は [websocket_signaling_ping_interval](SORA_CONF.html#27aae2) より長くしてください。 ```ini websocket_signaling_pong_timeout = 60 s ``` ## websocket_stats_timer_interval **単位指定必須** **デフォルト**: 60 s **範囲**: 5..600 s WebSocket 経由のシグナリングの場合に、サーバーからクライアントに統計情報の送信を要求する `"stats": true` を設定する間隔を指定してください。 ```ini websocket_stats_timer_interval = 60 s ``` ## 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 **単位指定必須** **デフォルト**: 60 s **範囲**: 5..600 s シグナリング経路を DataChannel に切り替えた際にクライアントへの統計情報を要求する間隔を指定してください。 ```ini data_channel_stats_timer_interval = 60 s ``` ## data_channel_stats_max_retransmits > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: 指定なし **範囲**: 0..8 シグナリング経路を DataChannel に切り替えた際にクライアントが統計情報を送信するときのメッセージの再送回数を指定してください。 ```ini data_channel_stats_max_retransmits = 1 ``` ## whip **デフォルト**: false OBS (WebRTC) が利用する WHIP 形式のシグナリングを有効にするかどうか指定してください。 ```ini whip = true ``` ## whip_bearer_token_metadata_key **デフォルト**: 指定なし OBS (WebRTC) が利用する WHIP 形式のシグナリング時の Authentication ヘッダーに含まれるトークンを、メタデータとして送信する際のキーを指定してください。 ```ini whip_bearer_token_metadata_key = access_token ``` ## 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` 設定で上書きできます。 ### ドメイン名が 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_vp9_param_profile_id **デフォルト**: 0 **範囲**: 0..3 VP9 で利用するプロファイル ID のデフォルト値を指定してください。 ```ini default_vp9_param_profile_id = 2 ``` ## default_av1_param_profile **デフォルト**: 0 **範囲**: 0..2 AV1 で利用するプロファイルのデフォルト値を指定してください。 ```ini default_av1_param_profile = 0 ``` ## default_h264_param_profile_level_id **デフォルト**: 42e01f H.264 で利用するプロファイルレベル ID のデフォルト値を文字列で指定してください。 ```ini default_h264_param_profile_level_id = 42e01f ``` ## default_h265_param_level_id > **重要** > > 2024 年 4 月 現在、このプロファイルを利用できる WebRTC クライアントが存在しません。 **デフォルト**: 93 **範囲**: 0..255 H.265 で利用するレベル ID のデフォルト値を数値で指定してください。 ```ini default_h265_param_level_id = 93 ``` ## default_simulcast_rid **デフォルト**: r0 サイマルキャスト利用時に、視聴する rid を指定せずに接続した場合に採用される rid の値を指定してください。 デフォルトでは r0 になっています。 `r1` または `r2` にすることもできます。 ```ini default_simulcast_rid = r0 ``` ## default_forwarding_pli_interval > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **単位指定必須** **デフォルト**: 10 s **範囲**: 1..90 s RTP 転送 API 利用時に、クライアントに対して PLI を送る間隔を指定してください。 ```ini default_forwarding_pli_interval = 10 s ``` 録画機能併用時には、 `20 s` より大きな値を指定したとしても、録画機能の PLI 送信間隔 `20 s` が適用されます。 もし `default_forwarding_pli_interval` に `20 s` より小さな値を指定した場合は、 PLI 送信間隔には `default_forwarding_pli_interval` の値が適用されます。 録画機能の利用を継続し、RTP 転送機能を停止したタイミングで、 録画機能の PLI 送信間隔 `20 s` が適用されます。 ## forwarding_simulcast > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **単位指定必須** **デフォルト**: single RTP 転送 API 利用時にサイマルキャストの転送オプションを指定してください。 - `single` は最も優先度の低いストリームのみを転送します - `all` はすべてのストリームを転送します ```ini forwarding_simulcast = all ``` ## signaling_forwarding_filter **デフォルト**: false 転送フィルターをシグナリング接続時に設定できるかどうかを指定してください。 ```ini signaling_forwarding_filter = true ``` ## audio_streaming_url **デフォルト**: 指定なし 統計コレクターの URL を指定してください。 http を指定した場合は HTTP/2 (h2c) で送られます。 https の場合は HTTP/2 (h2) で送られます。 統計コレクターは HTTP/2 に対応している必要があります。 ```ini audio_streaming_url = http://192.0.2.10:48080/speech ``` ```ini audio_streaming_url = https://suzu.example.com/speech ``` ## default_audio_streaming_result_push **デフォルト**: true 音声ストリーミングゲートウェイからのレスポンスをシグナリングプッシュ通知で送ることをデフォルトで行うかを指定してください。 ```ini default_audio_streaming_result_push = true ``` ## default_audio_streaming_language_code **デフォルト**: 指定なし 音声ストリーミングゲートウェイ接続時に HTTP ヘッダー `sora-audio-streaming-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 ``` > **重要** > > この設定がない場合、 OS 組み込みのルート CA 証明書を利用してサーバー証明書をチェックします。 > OS 組み込みのルート CA 証明書については [ウェブフックリクエストなどの送信先サーバー証明書の検証に利用する OS 組み込みのルート CA 証明書について](WEBHOOK.html#e8a845) をご確認ください。 ## recycle_media_section **デフォルト**: true SDP でアクティブではなくなったメディアセクション (m=) を再利用する機能を有効化するかどうかを指定してください。 ```ini recycle_media_section = false ``` ## hide_origin_username **デフォルト**: false 有効にした場合は SDP の Offer 時に送られる o= の username の部分を `shiguredo...SORA-` から `_` に変更します。 ```ini hide_origin_username = false ``` ## connection_created_wait_timeout **単位指定必須** **デフォルト**: 30 s **範囲**: 1..600 s 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#6c680e) をご確認ください。 ```ini simulcast_encodings_file = etc/simulcast_encodings.json ``` ## spotlight_encodings_file **デフォルト**: なし スポットライトで利用するエンコーディングパラメーターのカスタマイズを JSON 形式のファイルで指定してください。 詳細は [スポットライト利用時の映像のエンコーディングパラメーターのカスタマイズ](SPOTLIGHT.html#bd05eb) をご確認ください。 ```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 **範囲**: 1..300 s ICE コネクションステートが `checking` から `disconnected` の状態に移行するまでの時間を指定してください。 ```ini ice_connection_state_disconnected_timeout = 5 s ``` ## ice_connection_state_failed_timeout > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: 10 s **範囲**: 1..300 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.jsonl` の `event_metadata` を **"REDACTED"** に書き換えます - `session_webhook.jsonl` の `session_metadata` と `event_metadata` を **"REDACTED"** に書き換えます - `event_webhook.jsonl` の `event_metadata` を **"REDACTED"** に書き換えます ## default_h264_profile_level_id > **注意** > > この設定は 2024 年 6 月リリース予定の Sora にて廃止します > 代わりに default_h264_param_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_collector_url = http://192.0.2.10:5890/collector ``` ```ini stats_collector_url = https://kohaku.example.com/collector ``` ## default_stats_exporter > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: true [stats_collector_url](STATS_EXPORTER.html#98b67f) に URL が指定されている場合に、 統計エクスポーターをデフォルトで有効にするかどうかを指定してください。 この設定を `false` にした場合に、統計エクスポーターを有効にするには、 認証成功時の払い出しで `"stats_exporter": true` を払い出す必要があります。 ```ini default_stats_exporter = true ``` ## 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 ``` > **重要** > > この設定がない場合、 OS 組み込みのルート CA 証明書を利用してサーバー証明書をチェックします。 > OS 組み込みのルート CA 証明書については [ウェブフックリクエストなどの送信先サーバー証明書の検証に利用する OS 組み込みのルート CA 証明書について](WEBHOOK.html#e8a845) をご確認ください。 ## node_name **デフォルト**: 指定なし クラスター機能で利用するノード名を指定してください。 ノード名の @ の前には、正規表現 `[0-9A-Za-z_\\-]+` にマッチする文字列を指定してください。 また @ の後ろには、サーバーのドメイン名(FQDN)や、IP アドレスを指定してください。 ```ini node_name = sora@192.0.2.10 ``` ## cluster **デフォルト**: false クラスター機能を利用するかどうかを指定してください。 ```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 **デフォルト**: true H.265 が利用できるようになります。 ```ini h265 = true ``` ## lyra > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: false 一部の SDK で [Lyra](https://github.com/google/lyra) が利用できるようになります。 ```ini lyra = true ``` ## lyra_param_bitrate > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: 6000 **設定**: 3200、6000、9200 Lyra で利用するビットレートのデフォルト値を指定してください。 ```ini lyra_param_bitrate = 9200 ``` ## legacy_recording **デフォルト**: true > **危険** > > この設定は 2025 年 12 月リリースの Sora にて廃止されます > **注意** > > この設定は 2024 年 12 月リリースの Sora にてデフォルトが false に変更されます レガシー録画を利用するかどうかを指定してください。 `false` にすることでレガシー録画の API が利用できなくなります。 ```ini legacy_recording = false ``` ### `legacy_recording` を `false` にする際の注意点 クラスター機能利用時にレガシー録画の録画予約が存在する状態で、 `legacy_recording` を `false` にした場合でも、レガシー録画の録画予約は停止されません。 そのため、 `legacy_recording` を `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_hdrext_abs_capture_time > **注意** > > この設定を利用する場合は事前にサポートまでご連絡ください **デフォルト**: false RTP ヘッダー拡張 `http://www.webrtc.org/experiments/rtp-hdrext/abs-capture-time` を利用するかどうかを指定してください。 ## 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 ### sysctl sysctl にて、以下の値を設定することを推奨します。 このあたりの値はサーバースペックによりますので、こちらは推奨値となります。 ``` sudo sysctl -w net.core.rmem_default=33554432 sudo sysctl -w net.core.rmem_max=33554432 sudo sysctl -w net.core.wmem_default=33554432 sudo sysctl -w net.core.wmem_max=33554432 sudo sysctl -w net.core.somaxconn=65535 sudo sysctl -w net.core.optmem_max=25165824 sudo sysctl -w net.core.netdev_max_backlog=65536 sudo sysctl -w net.ipv4.tcp_mem='786432 1048576 26777216' sudo sysctl -w net.ipv4.tcp_rmem='8192 87380 33554432' sudo sysctl -w net.ipv4.tcp_wmem='8192 65536 33554432' sudo sysctl -w net.ipv4.udp_mem='65536 131072 262144' sudo sysctl -w net.ipv4.udp_rmem_min=16384 sudo sysctl -w net.ipv4.udp_wmem_min=16384 ``` # IPv6 での動作について ## 概要 Sora は WebRTC とウェブフックが IPv6 での動作に対応しています。ただし、ブラウザ側やサーバー側が非対応な場合があります。 特に、IPv6 での TURN 機能にクライアントが対応していない場合は接続できないことがあります。 ## お問い合わせの際の情報について IPv6 環境は様々な組み合わせがあるため、問題を解析するには多くの情報が必要になります。 お問い合わせの際は以下の情報をお送りください。 - クライアント側の IPv6 の有無について - Sora 側の IPv6 の設定の有無について - Sora が動作しているサーバーの A または AAAA レコードの有無について - クライアントが IPv4 または IPv6 または IPv4 と IPv6 どの環境かについて 他にも何か気づいた点などがありましたらそちらも合わせてお問い合わせください。 ## IPv6 のみ Sora の WebRTC を IPv6 のみの通信のみでの動作させます。 `sora.conf` にて [ipv6_only](SORA_CONF.html#5e9e68) を `true` にすることで、 WebRTC の接続を IPv6 のみに制限することができます。 シグナリングや API 部分を IPv6 のみにしたい場合は Nginx 側の設定を変更してください。 ## ウェブフックの IPv6 対応 Sora のウェブフックは IPv6 での動作に対応しています。 `sora.conf` にて [webhook_ipv6](SORA_CONF.html#6c895b) を `true` にすることで、 ウェブフックの接続で IPv6 を利用する事ができます。 # メタデータ ## 概要 Sora では様々なメタデータを扱っているため、それぞれのメタデータの説明をしています。 ## 接続時の認証メタデータ指定 クライアントが Sora へ接続する際に、認証に利用する `metadata` を指定できます。 これは認証ウェブフックに `metadata` として含まれます。 ```javascript { "type": "connect", "role": "sendrecv", "channel_id": "sora", "metadata": {"spam": "egg"} } ``` この値はクライアントと Sora だけで共有される値です。他のクライアントには一切共有されません。 ## 認証ウェブフック成功時のメタデータ払い出し 認証ウェブフック成功時に `metadata` を払い出すことができます。 この値は Sora が `"type": "offer"` をクライアントへ送る際に `metadata` として送られます。 ```javascript { "allowed": true, "metadata": {"spam": "egg"} } ``` ```javascript { "type": "offer", "sdp": "...", "metadata": {"spam": "egg"} } ``` この値は Sora とクライアントだけで共有される値です。他のクライアントには一切共有されません。 ## 認証ウェブフック成功時のイベントメタデータ払い出し 認証ウェブフック成功時に `event_metadata` を払い出すことができます。 この値は Sora がイベントウェブフックリクエストを送信する際に `event_metadata` として含まれます。 ```javascript { "allowed": true, "event_metadata": {"spam": "egg"} } ``` ```javascript { "type": "connection.created", "event_metadata": {"spam": "egg"} } ``` この値は Sora と認証ウェブフックとイベントウェブフック先のサーバーとのみで共有されます。 クライアントには通知されません。 ## 接続時のシグナリング通知メタデータ指定 シグナリング接続時の `"type": "connect"` で `signaling_notify_metadata` が指定できます。 ここで指定した値は同じチャネルに参加しているクライアントと新しく参加するクライアントに通知されます。 ```javascript { "type": "connect", "signaling_notify_metadata": {"spam": "egg"} } ``` ```javascript { "type": "connection.created", "authn_metadata": {"spam": "egg"} "metadata": {"spam": "egg"} } ``` ### シグナリング通知メタデータ拡張が有効な場合 シグナリング通知メタデータ拡張有効になっている場合は以下のように `authn_metadata` のみに値が含まれます。 ```javascript { "type": "connection.created", "authn_metadata": {"spam": "egg"} "metadata": {} } ``` もしこのシグナリング通知メタデータを接続時にしていさせたくない場合、 [signaling_notify_authn_metadata_max_size](SORA_CONF.html#a8c147) を `0` に設定してください。 ## 認証ウェブフック成功時のシグナリング通知メタデータ払い出し 認証ウェブフック成功時に `signaling_notify_metadata` を払い出すことができます。 この値は同じチャネルに参加しているクライアントと新しく参加するクライアントに通知されます。 もし接続時に `signaling_notify_metadata` が指定されていた場合は、 認証成功時のシグナリング通知メタデータ払い出しで **上書き** されます。 ```javascript { "allowed": true, "signaling_notify_metadata": {"spam": "egg"} } ``` ```javascript { "type": "connection.created", "authz_metadata": {"spam": "egg"} "metadata": {"spam": "egg"} } ``` ### シグナリング通知メタデータ拡張が有効な場合 シグナリング通知メタデータ拡張が有効になっている場合は以下のように `authz_metadata` のみに値が含まれます。 ```javascript { "type": "connection.created", "authz_metadata": {"spam": "egg"} "metadata": {} } ``` ## シグナリング通知メタデータ拡張 **[シグナリング通知メタデータ拡張](SIGNALING_NOTIFY_METADATA_EXT.html) を利用すると接続ごとに状態を持てるようになり、** : API でそのメタデータを変更し、通知することができるようになります。 本来、シグナリング通知メタデータは接続時か認証成功払い出し時にしか指定できず一度指定したら変更できません。 シグナリング通知メタデータ拡張を利用した場合は HTTP API を利用して途中でメタデータの値を変更できます。 この機能を有効にするとシグナリング時の通知メタデータに指定した値は `metadata` に含まれなくなります。 ## セッション生成時のセッションメタデータ払い出し セッション生成時に送信される [session.created](SESSION_WEBHOOK.html#1d1984) の戻り値に指定することで `session_metadata` を払い出すことができます。 この値は一定間隔で送られる [session.updated](SESSION_WEBHOOK.html#2a5b1b) と、 このセッションが終了した時に送られる [session.destroyed](SESSION_WEBHOOK.html#ccb165) に含まれます。 ```javascript { "session_metadata": "" } ``` ## 一括録画ファイルメタデータ archive-.json 録画機能で一括録画を指定した際に `archive//` 以下に生成されるファイルです。 かならず `archive-.webm` ファイルとペアになります。 ## 分割録画ファイルメタデータ split-archive-_.json 録画機能で分割録画を指定した際に `archive//` 以下に生成されるファイルです。 かならず `split-archive-_.webm` ファイルとペアになります。 ## 録画(セッション単位) の StartRecording API で指定するメタデータ [StartRecording](API_RECORDING.html#c5b527) API では `metadata` を指定できます。 この値は以下のセッションウェブフックに `recording_metadata` として含まれます。 - [recording.started](SESSION_WEBHOOK.html#9b5c58) - [recording.report](SESSION_WEBHOOK.html#920a02) - [session.updated](SESSION_WEBHOOK.html#2a5b1b) また、 `report-.json` ファイルにも記録されます。 ## 録画(セッション単位) のセッションウェブフック `session.created` で指定するメタデータ 録画(セッション単位) ではセッションウェブフック `session.created` の戻り値として、 `recording_metadata` を払い出すことができます。 ``` { "recording": true, "recording_metadata": "" } ``` この値は以下のセッションウェブフックに `recording_metadata` として含まれます。 - [recording.started](SESSION_WEBHOOK.html#9b5c58) - [recording.report](SESSION_WEBHOOK.html#920a02) - [session.updated](SESSION_WEBHOOK.html#2a5b1b) また、 `report-.json` ファイルにも記録されます。 ## レガシー録画の StartRecording API で指定するメタデータ [StartRecording](API_LEGACY_RECORDING.html#c5b527) API では `metadata` を指定できます。 この値は、以下のイベントウェブフックに `metadata` として含まれます。 - [recording.started](EVENT_WEBHOOK.html#9b5c58) - [recording.report](EVENT_WEBHOOK.html#920a02) また、 `report-.json` ファイルにも記録されます。 # センシティブデータ > **注意** > > この機能を利用する場合は事前にサポートまでご連絡ください > **警告** > > この機能は [実験的機能](EXPERIMENTAL.html) のため、正式版では仕様が変更される可能性があります ## 概要 Sora ではログと API で出力されるセンシティブデータを **"REDACTED"** という文字列に書き換えます。 ## 対象ログと項目 Sora のログは以下の内容のセンシティブデータを **"REDACTED"** に書き換えて出力します。 - `auth_webhook.jsonl` の `event_metadata` を **"REDACTED"** に書き換えて出力します。 - `session_webhook.jsonl` の `session_metadata` と `event_metadata` を **"REDACTED"** に書き換えて出力します。 - `event_webhook.jsonl` の `event_metadata` を **"REDACTED"** に書き換えて出力します。 ### event_webhook_error ログ > **重要** > > `event_webhook_error.jsonl` の `event_metadata` については "REDACTED" の書き換えは行いません ### session_webhook_error ログ > **重要** > > `session_webhook_error.jsonl` の `session_metadata` と `event_metadata` については "REDACTED" の書き換えは行いません ## 書き換えをスキップする > **重要** > > この書き換えを無効にすることは推奨していません。 センシティブなデータを利用している場合は、 **"REDACTED"** への書き換えをスキップする設定を提供しています。 `sora.conf` の [skip_redact_sensitive_data](SORA_CONF.html#00d209) を `true` にすることでセンシティブなデータの **"REDACTED"** への書き換えをスキップします。 ## 録画メタデータの扱いについて StartRecording API やセッションウェブフックの戻り値で指定できる録画メタデータについてはセンシティブなデータとして扱っていません。 これは録画ファイル出力時の録画メタデータファイルに含まれ、映像合成時に利用する事を想定しているためです。 # アプリケーション連携チュートリアル > **重要** > > このドキュメントに書かれているサンプルコードについては Sora サポートの対象外です。 このドキュメントは Sora のウェブフックと API を利用したアプリケーションサーバー開発者向けです。 ## 概要 Sora はウェブフックと API を利用して、アプリケーションサーバーと連携することができます。 ### ウェブフック ウェブフックは認証と払い出し、そしてコネクションやセッション、録画などの状況の取得です。 Sora から一定間隔で送られてくるウェブフックを利用する事で定期的な状態を取得することができます。 どのコネクションが何分繫いでいたかの把握や、そのセッションは何分で終了させるといったことも実現できます。 ウェブフックは Sora からアプリケーションサーバーへ `HTTP/1.1` でリクエストで送信します。 ### API ウェブフックはコネクションの切断、セッションの破棄、統計情報の取得などアプリケーションサーバーが必要とするタイミングで送信することができます。 API はアプリケーションサーバーから Sora へ `HTTP/1.1` でリクエストを送信する必要があります。 ## JSON Sora がアプリケーションに送信するウェブフックの JSON は `snake_case` を採用しています。 `camelCase` ではないことに注意してください。 `snake_case` の JSON はシグナリング、ウェブフック、 API で利用します。 ## ウェブフックのローカル開発 Sora をサーバーに立て、ウェブフックの送信先をローカルにしたい場合には [ngrok](https://ngrok.com/) がお勧めです。 ### ngrok の利用方法 **URL**: ngrok は無料プランでも、静的ドメインを一つ利用する事ができるため、 この静的ドメインを Sora 側に指定することにより、ローカルのウェブフックを利用することができます。 ngrok は Windows / Linux / macOS で利用可能です。 また ngrok が HTTPS を終端し、HTTP でアプリケーションサーバーにリクエストを送信するため、 アプリケーションサーバー側を HTTPS にする必要はありません。 ### シーケンス図 ngrok を利用した場合のシーケンス図です。 `--domain` には example ではなく ngrok のダッシュボードに表示されているドメインを指定してください。 ```mermaid sequenceDiagram participant C as クライアント participant S as Sora participant NS as Ngrok Server
https://example.ngrok-free.app box ローカル環境 participant NC as Ngrok Client
$ ngrok http --domain=example.ngrok-free.app 8080 participant A as ローカルアプリケーション
http://localhost:8080 end C ->>+ S: "type": "connect" S ->>+ NS: 認証ウェブフック NS ->>+ NC: 認証ウェブフック NC ->>+ A: 認証ウェブフック A -->>- NC: 200 OK
"allowed": true NC -->>- NS: 200 OK
"allowed": true NS -->>- S: 200 OK
"allowed": true S ->>- C: "type": "offer" ``` ## サンプルコードについて アプリケーションサーバーのサンプルコードを Python を利用しています。 あくまで例であり、実際のアプリケーションでの利用は想定しておりません。 現在は [OpenAI ChatGPT](https://openai.com/chatgpt/) や [GitHub Copilot](https://github.com/features/copilot/) を利用する事で、 他の言語への変換がとても簡単に行えるようになったこともあり、 サンプルコードに利用するプログラミング言語を Python に統一しています。 Python 3.12 以降で動作確認をしています。 ## aiohttp サンプルコードでは Python の非同期 HTTP ライブラリである `aiohttp` を利用しています。 `$ pip install aiohttp` でインストールして利用してください。 ### Django 風 ウェブフックの処理を行うコードです。 このドキュメントではこちらの書き方を利用します。 ```python from aiohttp import web async def auth_webhook(request: web.Request) -> web.Response: return web.json_response({"allowed": True}) app = web.Application() app.router.add_routes( [ web.post("/auth", auth_webhook), ] ) if __name__ == "__main__": web.run_app(app, port=8000) ``` ### Flask 風 デコレーターを利用して、ウェブフックの処理を行うコードです。 Django 風と Flask 風、どちらを利用するかは好みの問題ですので、 好きな方を利用してください。 ```python from aiohttp import web routes = web.RouteTableDef() @routes.post("/auth") async def auth_webhook(request: web.Request) -> web.Response: return web.json_response({"allowed": True}) app = web.Application() app.router.add_routes(routes) if __name__ == "__main__": web.run_app(app, port=8000) ``` ## ウェブフック HTTP 実装 ウェブフックを処理するコードです。 `sora.conf` の以下の設定に URL を指定してください。 - [auth_webhook_url](SORA_CONF.html#36a99a) - [session_webhook_url](SORA_CONF.html#76fa79) - [event_webhook_url](SORA_CONF.html#e1a4d2) 例として ngrok を利用している URL を指定しています。 ```ini auth_webhook_url = https://example.ngrok-free.app/auth session_webhook_url = https://example.ngrok-free.app/session event_webhook_url = https://example.ngrok-free.app/event ``` 認証が常に成功するようなコードになっています。 ```python from aiohttp import web async def auth_webhook(request: web.Request) -> web.Response: return web.json_response({"allowed": True}) async def session_webhook(request: web.Request) -> web.Response: return web.Response(status=204) async def event_webhook(request: web.Request) -> web.Response: return web.Response(status=204) app = web.Application() app.router.add_routes( [ web.post("/auth", auth_webhook), web.post("/session", session_webhook), web.post("/event", event_webhook), ] ) if __name__ == "__main__": web.run_app(app, port=8000) ``` ## ウェブフック HTTPS 対応 Sora のウェブフックは HTTPS にも対応しています。 Sora の HTTPS はサーバ証明書のチェックをデフォルトで OS に組み込まれた証明書を利用して行います。 自前で用意した証明書などを利用したい場合は [webhook_tls_verify_cacert_file](SORA_CONF.html#7036dc) を利用してください。 詳細は [ウェブフックリクエストなどの送信先サーバー証明書の検証に利用する OS 組み込みのルート CA 証明書について](WEBHOOK.html#e8a845) をご確認ください。 ```python import ssl from aiohttp import web async def auth_webhook(request: web.Request) -> web.Response: return web.json_response({"allowed": True}) async def session_webhook(request: web.Request) -> web.Response: return web.Response(status=204) async def event_webhook(request: web.Request) -> web.Response: return web.Response(status=204) app = web.Application() app.router.add_routes( [ web.post("/auth", auth_webhook), web.post("/session", session_webhook), web.post("/event", event_webhook), ] ) # サーバー証明書 certfile: str = "192.0.2.1.pem" # サーバー証明書のプライベートキー keyfile: str = "192.0.2.1-key.pem" if __name__ == "__main__": # SSL コンテキストの作成 ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) ssl_context.load_cert_chain(certfile, keyfile) # HTTPS サーバーとして起動 web.run_app(app, port=4433, ssl_context=ssl_context) ``` ## ウェブフック mTLS (mutual-TLS またはクライアント認証) 対応 Sora のウェブフックは mTLS にも対応しています。 その場合、アプリケーションサーバー側に、Sora に設定した証明書の CA 証明書を指定する必要があります。 ```python import ssl from aiohttp import web async def auth_webhook(request: web.Request) -> web.Response: return web.json_response({"allowed": True}) async def session_webhook(request: web.Request) -> web.Response: return web.Response(status=204) async def event_webhook(request: web.Request) -> web.Response: return web.Response(status=204) app = web.Application() app.router.add_routes( [ web.post("/auth", auth_webhook), web.post("/session", session_webhook), web.post("/event", event_webhook), ] ) # サーバー証明書 certfile: str = "192.0.2.1.pem" # サーバー証明書のプライベートキー keyfile: str = "192.0.2.1-key.pem" # クライアント証明書のCA証明書 cafile: str = "ca.pem" if __name__ == "__main__": # SSL コンテキストの作成 ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) ssl_context.load_cert_chain(certfile, keyfile) ssl_context.load_verify_locations(cafile) # クライアント証明書の検証を要求 ssl_context.verify_mode = ssl.CERT_REQUIRED # HTTPS サーバーとして起動 web.run_app(app, port=4433, ssl_context=ssl_context) ``` ## ウェブフック IPv6 対応 Sora は昨今の IPv4 事情を考慮して IPv6 にも対応しています。 `sora.conf` の `webhook_ipv6` を `true` にすることで、 IPv6 のみのウェブフックエンドポイントと通信をすることができます。 ## 認証ウェブフック Sora 自体は認証処理を持っていません。 そのため、アプリケーションサーバー側で認証の仕組みを開発する必要があります。 Sora は [auth_webhook_url](SORA_CONF.html#36a99a) に指定した URL にクライアントから送られてきた情報などを、 アプリケーションサーバに対して HTTP (または HTTPS) リクエストとして送信します。 ### 認証メタデータ 認証ウェブフックにはクライアントが送ってくる `metadata` が含まれます。 これはクライアントが自由に値を含められる場所で、ここの値を使って認証を行うことを推奨しています。 ```python from aiohttp import web async def auth_webhook(request: web.Request) -> web.Response: data = await request.json() # metadata がない場合は None が返る metadata = data.get("metadata") if not metadata: # metadata がない場合は認証を許可しない # 認証を拒否する場合は 'allowed': False と 'reason': '認証失敗理由' を返す # この認証失敗理由はクライアントまで通知されるので注意すること return web.json_response({"allowed": False, "reason": "metadata not found"}) # 認証を許可する JSON を返す return web.json_response({"allowed": True}) ``` ### 認証メタデータに JWT 認証メタデータの中に `access_token` として JWT が入ってきた場合の処理です。 [PyJWT](https://github.com/jpadilla/pyjwt) を利用して、JWT をデコードして認証を行います。 ```python import os import jwt from aiohttp import web async def auth_webhook(request: web.Request) -> web.Response: data = await request.json() metadata = data.get("metadata") if not metadata: return web.json_response({"allowed": False, "reason": "metadata not found"}) access_token = metadata.get("access_token") if not access_token: return web.json_response({"allowed": False, "reason": "access_token not found"}) # 環境変数からシークレットキーを取得 secret = os.environ.get("JWT_SECRET_KEY") if not secret: return web.json_response({"allowed": False, "reason": "secret key not found"}) try: # PyJWT を利用して JWT をデコードし、署名を検証する jwt.decode(access_token, secret, algorithms=["HS256"]) except jwt.InvalidTokenError: # トークンが無効の場合は認証を拒否 return web.json_response({"allowed": False, "reason": "invalid token"}) # 認証を許可する JSON を返す return web.json_response({"allowed": True}) ``` ### イベントメタデータ 認証ウェブフックで、認証成功時にイベントメタデータを払い出すことができます。 イベントメタデータはイベントウェブフックの `connection.{created, updated, destroyed}` に含まれます。 このイベントメタデータは Sora とアプリケーションサーバー間だけでやり取りされ、クライアントには送られません。 そのためデータベースの `Primary Key` などを入れておいたりすることができます。 ```python from aiohttp import web async def auth_webhook(request: web.Request) -> web.Response: # ここでデータベースなどの値を引っ張る account_pk = 1 # イベントメタデータ event_metadata = { "account_pk": account_pk, } # 認証を許可する JSON を返す return web.json_response({"allowed": True, "event_metadata": event_metadata}) return web.json_response({"allowed": True, "event_metadata": event_metadata}) ``` イベントメタデータはウェブフックログには `REDACTED` として記録されます。 これはセンシティブデータを含んでいる可能性があるためです。 `REDACTED` については [センシティブデータ](SENSITIVE_DATA.html) をご確認ください。 ```mermaid sequenceDiagram participant C as クライアント participant S as Sora participant A as アプリケーション C ->>+ S: "type": "connect" S ->>+ A: 認証ウェブフック A -->>- S: 200 OK
"allowed": true
"event_metadata": {"account_pk": 1} S ->>+ A: セッションウェブフック
session.created A -->>- S: 200 OK S ->>- C: "type": "offer" note over C,S: WebRTC 確立 S ->>+ A: イベントウェブフック
connection.created
"event_metadata": {"account_pk": 1} A -->>- S: 200 OK S ->>+ A: イベントウェブフック
connection.updated
"event_metadata": {"account_pk": 1} A -->>- S: 200 OK note over S,A: connection.updated は一定間隔で送信 C -) S: "type": "disconnect" S -) C: "Close" note over C,S: WebRTC 切断 S ->>+ A: イベントウェブフック
connection.destroyed
"event_metadata": {"account_pk": 1} A -->>- S: 200 OK ``` ## セッションウェブフック セッションウェブフックはセッション単位の変化を通知するためのウェブフックです。 Sora は `session_webhook_url` に指定した URL にセッションの変化を HTTP リクエストとして送信します。 ### セッション セッションはチャネルで少なくとも 1 つのクライアントが接続しているチャネルの状態を指します。 ### セッションメタデータ ```python from aiohttp import web async def session_webhook(request: web.Request) -> web.Response: # ここでデータベースなどの値を引っ張る room_pk = 2 return web.json_response({"session_metadata": {"room_pk": room_pk}}) ``` ### セッション録画開始 セッションウェブフックの `session.created` の戻り値に `recording: true` を含める事で、 そのセッションが開始したタイミングから録画を開始することができます。 ```python from aiohttp import web async def session_webhook(request: web.Request) -> web.Response: # このセッションで録画を有効にする return web.json_response({"recording": True}) ``` ## イベントウェブフック イベントウェブフックはコネクション単位での変化を通知するためのウェブフックです。 - コネクションが接続したら、コネクション接続のイベントが送信されます - コネクションが接続している間は、コネクション更新のイベントが一定間隔で送信されます- デフォルトでは 1 分間隔で送信されますが、 [connection_updated_webhook_interval](SORA_CONF.html#e67c3b) で変更可能です - コネクションが切断したら、コネクション切断のイベントが送信されます ### connection.{created,updated,destroyed} ```python from aiohttp import web async def event_webhook(request: web.Request) -> web.Response: data = await request.json() match data.get("type"): case "connection.created": # connection.created イベントの処理 # データベースに保存したりする pass case "connection.updated": # connection.updated イベントの処理 # データベースに保存したりする pass case "connection.destroyed": # connection.destroyed イベントの処理 # データベースに保存したりする pass case _: # 未対応のイベントの処理 pass return web.Response(status=204) ``` ## API Sora の API は、パスを利用せず、ヘッダーを利用して判定する方式を採用しています。 - **メソッドは常に POST を利用します** - **パスは常に / を利用します** - `x-sora-target` ヘッダーを利用して、どの API にアクセスするかを判定します ## 指定したチャネルのコネクションを切断する ```python import asyncio import aiohttp async def main(): url = "https://sora.example.com" headers = { "X-Sora-Target": "Sora_20151104.DisconnectConnection", } data = { "channel_id": "sora", "connection_id": "T34CDBMRJS1B5BVPF17RTBQA3C", } async with aiohttp.ClientSession() as session: # Nginx で api の prefix を /api に設定している場合は以下のように変更 # response = await session.post(f"{url}/api", json=data, headers=headers) response = await session.post(url, json=data, headers=headers) print(response.status) response_data = await response.text() print(response_data) if __name__ == "__main__": asyncio.run(main()) ``` ## 接続してから 3 分経過したコネクションを切断する イベントウェブフック [connection.updated](EVENT_WEBHOOK.html#5430cd) と、 コネクション切断 [DisconnectConnection](API_SIGNALING.html#2ec3a0) API を利用して、 接続してから 3 分経過したコネクションを切断します。 ```python import aiohttp from aiohttp import web async def auth_webhook(request: web.Request) -> web.Response: return web.json_response({"allowed": True}) async def session_webhook(request: web.Request) -> web.Response: return web.Response(status=204) async def event_webhook(request: web.Request) -> web.Response: data = await request.json() match data.get("type"): case "connection.updated": if data.get("minutes", 0) >= 3: channel_id = data.get("channel_id") connection_id = data.get("connection_id") url = "https://sora.example.com/api" headers = { "X-Sora-Target": "Sora_20151104.DisconnectConnection", } data = { "channel_id": channel_id, "connection_id": connection_id, } async with aiohttp.ClientSession() as session: async with session.post( url, headers=headers, json=data, ) as response: if response.status != 200: # エラー処理 pass case _: # 見知らぬイベントの処理 pass return web.Response(status=204) app = web.Application() app.router.add_routes( [ web.post("/auth", auth_webhook), web.post("/session", session_webhook), web.post("/event", event_webhook), ] ) if __name__ == "__main__": web.run_app(app, port=8000) ``` ### シーケンス図 ```mermaid sequenceDiagram participant C as クライアント participant S as Sora participant A as アプリケーション C ->>+ S: "type": "connect" S ->>+ A: 認証ウェブフック A -->>- S: 200 OK
"allowed": true S ->>+ A: セッションウェブフック
session.created A -->>- S: 200 OK S ->>- C: "type": "offer" note over C,S: WebRTC 確立 S ->>+ A: イベントウェブフック
connection.created
"minutes": 0 A -->>- S: 200 OK S ->>+ A: イベントウェブフック
connection.updated
"minutes": 1 A -->>- S: 200 OK S ->>+ A: イベントウェブフック
connection.updated
"minutes": 2 A -->>- S: 200 OK note over C,A: WebRTC 確立してから 10 分経過 S ->>+ A: イベントウェブフック
connection.updated
"minutes": 10 A -->>- S: 200 OK A ->>+ S: DisconnectConnection API S -->>- A: 200 OK S -) C: "Close" note over C,S: WebRTC 切断 S ->>+ A: イベントウェブフック
connection.destroyed
"minutes": 10 A -->>- S: 200 OK ``` # WebSocket 経由のシグナリング ## 概要 > **重要** > > Sora の SDK を利用する場合は、ここに書かれているシグナリングの細かい仕様を把握する必要は基本的にありません。 Sora のシグナリングにはデフォルトでは WebSocket を使用します。 ## 用語 ### channel_id 接続のグルーピングに利用する ID です。 接続時に任意の文字列、最大 255 バイトまでを自由に指定できます。 ### session_id channel_id への接続が 0 から 1 に切り替わったタイミングで生成される id です。 1 から 0 になり、一定期間が経過したタイミングでセッションは破棄されます。 セッションが破棄された後、 再度同一 channel_id で接続が 0 から 1 になった場合、新しい session_id が生成されます。 セッションごとのユニークな値です。 UUIDv4 で生成した値を Base32 でエンコードした値で、Sora が払い出します。指定はできません。 ### 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 です。 ```javascript { "type": "connect", "role": "sendonly", "channel_id": "Spam" } ``` #### role そのクライアントの役割を指定します。この設定は必須です。 `role` には `sendrecv` / `sendonly` / `recvonly` のどれかを指定してください。 - sendrecv- マルチストリーム、スポットライトで利用できます。送信及び受信を行います - sendonly- すべてで利用できます。送信のみを行い、受信を行いません - recvonly- すべてで利用できます。受信のみを行い、送信を行いません #### channel_id `channel_id` は 1-255 バイトまでの文字列であればどのような文字列でも指定できます。 #### 配信または視聴メディアの選択 **この項目はオプションです** `audio` と `video` を指定することにより配信、または視聴するメディアを選択することができます。 `role` に `sendrecv` または `sendonly` を指定した場合は配信するメディア、 `recvonly` を指定したときは視聴するメディアについての指定となります。 この設定が未指定の場合は、 `true` がデフォルトで指定され、映像と音声両方の配信、または映像と音声両方の受信が行われます。 以下の例では `role` に `sendrecv` が指定されており、音声のみが配信されます。 ```javascript { "type": "connect", "role": "sendrecv", "channel_id": "Spam", "video": false } ``` > **注釈** > > `role` に `sendrecv` が指定された場合は常に映像と音声両方を受信します。 以下の例では `role` に `sendonly` が指定されており、映像のみが配信されます。 ```javascript { "type": "connect", "role": "sendonly", "channel_id": "Spam", "audio": false } ``` 以下の例では `role` に `recvonly` が指定されており、音声のみが受信されます。 ```javascript { "type": "connect", "role": "recvonly", "channel_id": "Spam", "video": false } ``` #### オーディオコーデック指定 **この項目はオプションです** 配信者や視聴者はオーディオコーデックを指定できます。 この設定はオプションです。 この設定が指定されない場合は、 `OPUS` がデフォルトで設定されます。 > **重要** > > Lyra は一部の Sora SDK では利用できません。 - Opus- "OPUS" - Lyra- "LYRA" ```javascript { "type": "connect", "role": "sendonly", "channel_id": "Spam", "audio": { "codec_type":"OPUS" } } ``` #### オーディオビットレート指定 **この項目はオプションです** > **重要** > > オーディオビットレートは指定しないことをおすすめします。指定しないことで最適なビットレートが採用されます。 配信者はオーディオビットレートの最大値を指定できます。 このビットレート指定は Opus にのみ有効で、 Lyra には適用されません。 Lyra の場合は `lyra_params` の `bitrate` を指定してください。 - bit_rate- 6-510 ```javascript { "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 の設定を指定できます。 - opus_params- channels- 1-8 - maxplaybackrate- 8000-48000 - stereo- boolean - sprop_stereo- boolean - minptime- integer 3-120 - useinbandfec- boolean - usedtx- boolean - **この機能を有効にした場合は録画がおかしくなります** ```javascript { "type": "connect", "role": "sendonly", "channel_id": "Spam", "audio": { "codec_type": "OPUS", "opus_params": { "stereo": false, "useinbandfec": false } } } ``` #### オーディオの Lyra 設定指定 > **注意** > > この機能は実験的機能です。この機能を利用される場合は必ず事前にサポートまでご連絡ください **この項目は Lyra を使う場合必須です** 配信者は Lyra の設定を指定できます。 - lyra_params- version- string - 1.2.0 や 1.3.0 といった Lyra のバージョンを指定します - bitrate- integer 3200 or 6000 or 9200 ```javascript { "type": "connect", "role": "sendonly", "channel_id": "Spam", "audio": { "codec_type": "LYRA", "lyra_params": { "version": "1.3.0", "bitrate": 6000 } } } ``` #### ビデオコーデック指定 **この項目はオプションです** 配信者や視聴者はビデオコーデックを指定できます。 この設定はオプションです。 この設定が指定されない場合は、VP9 がデフォルトで設定されます。 - VP8- `"VP8"` - VP9- "`VP9"` - AV1- `"AV1"` - Chrome M96 以降で利用できます - Sora SDK で利用できます - H.264- `"H264"` - H.265- `"H265"` - Sora iOS/Android SDK で利用できます - Safari では実験的機能を有効にすることで利用できます ```javascript { "type": "connect", "role": "sendonly", "channel_id": "Spam", "video": { "codec_type":"VP9" } } ``` #### ビデオビットレート指定 **この項目はオプションです** 配信者はビデオビットレートの最大値を指定できます。単位は **kbps** です。 - bit_rate- 1-50000 ```javascript { "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` に指定した値が採用されます。 #### ビデオの VP9 設定指定 > **注意** > > この機能は実験的機能です。この機能を本番環境で利用される場合は必ず事前にサポートまでご連絡ください 配信者は VP9 のプロファイル ID を指定できます。 VP9 のプロファイル ID を指定をする場合は、あわせて `codec_type` に `VP9` を指定する必要があります。 - vp9_params- profile_id- integer - 0-3 この値を指定するには `sora.conf` にて [signaling_vp9_params](SORA_CONF.html#3261ea) を `true` に設定する必要があります。 ```javascript { "type": "connect", "role": "sendonly", "channel_id": "Spam", "video": { "codec_type": "VP9", "vp9_params": { "profile_id": 2 } } } ``` #### ビデオの AV1 設定指定 > **注意** > > この機能は実験的機能です。この機能を本番環境で利用される場合は必ず事前にサポートまでご連絡ください 配信者は AV1 のプロファイル を指定できます。 AV1 のプロファイル を指定をする場合は、あわせて `codec_type` に `AV1` を指定する必要があります。 - av1_params- profile- integer - 0-2 この値を指定するには `sora.conf` にて [signaling_av1_params](SORA_CONF.html#91f3b8) を `true` に設定する必要があります。 ```javascript { "type": "connect", "role": "sendonly", "channel_id": "Spam", "video": { "codec_type": "AV1", "av1_params": { "profile": 0 } } } ``` #### ビデオの H.264 設定指定 > **注意** > > この機能は実験的機能です。この機能を本番環境で利用される場合は必ず事前にサポートまでご連絡ください 配信者は H.264 のプロファイルレベル ID を指定できます。 H.264 のプロファイルレベル ID を指定をする場合は、あわせて `codec_type` に `H264` を指定する必要があります。 - h264_params- profile_level_id- string - "42e01f" など この値を指定するには `sora.conf` にて [signaling_h264_params](SORA_CONF.html#b32e49) を `true` に設定する必要があります。 ```javascript { "type": "connect", "role": "sendonly", "channel_id": "Spam", "video": { "codec_type": "H264", "h264_params": { "profile_level_id": "42e01f" } } } ``` #### ビデオの H.265 設定指定 > **注意** > > この機能は実験的機能です。この機能を本番環境で利用される場合は必ず事前にサポートまでご連絡ください > **警告** > > この機能はまだ対応しているライブラリが存在しません。 配信者は H.265 のプロファイルレベル ID を指定できます。 H.265 のプロファイルレベル ID を指定をする場合は、あわせて `codec_type` に `H265` を指定する必要があります。 - h265_params- level_id- integer - 93 など この値を指定するには `sora.conf` にて [signaling_h265_params](SORA_CONF.html#8ed4e9) を `true` に設定する必要があります。 ```javascript { "type": "connect", "role": "sendonly", "channel_id": "Spam", "video": { "codec_type": "H265", "h265_params": { "level_id": 93 } } ``` #### 認証メタデータ **この項目はオプションです** 認証するための判断材料としてメタデータを使用できます。 認証メタデータは必須ではありません。 ```javascript { "type": "connect", "role": "sendonly", "channel_id": "Spam", "metadata": "1234abcd" } ``` 認証メタデータは、そのまま認証サーバーに送られます。詳細は [認証ウェブフック](AUTH_WEBHOOK.html) をご確認ください。 #### client_id の指定 **この項目はオプションです** > **重要** > > `client_id` の値は重複することができます。 1-255 バイトまでの文字列であれば、どのような文字列でも指定できます。 ```javascript { "type": "connect", "role": "sendonly", "channel_id": "Spam", "client_id": "egg-ham" } ``` #### bundle_id の指定 **この項目はオプションです** > **重要** > > `bundle_id` の値は重複することができます。 1-255 バイトまでの文字列であれば、どのような文字列でも指定できます。 マルチストリーム利用時に `bundle_id` が同じ接続からの音声や映像、メッセージングを受信しなくなります。 この値を指定するには `sora.conf` にて [signaling_bundle_id](SORA_CONF.html#279311) を `true` に設定する必要があります。 ```javascript { "type": "connect", "role": "sendonly", "channel_id": "Spam", "bundle_id": "spam_egg" } ``` #### マルチストリーム **この項目はオプションです** 他のクライアントのストリームを複数受信できる仕組みです。デフォルトで有効です。 もしマルチストリームを使わない場合は明示的に `"multistream": false` を指定してください。 ```javascript { "type": "connect", "role": "sendrecv", "channel_id": "spam", "multistream": false } ``` 詳細は [マルチストリーム機能](MULTISTREAM.html) をご確認ください。 #### サイマルキャスト **この項目はオプションです** 自分が配信する映像のストリームを複数本にすることで、 受信側にどのストリームを受信するかを選択させることができるようになります。 サイマルキャストを有効にする場合には `"multistream": true` も明示的に指定する必要があります。 ```javascript { "type": "connect", "role": "sendrecv", "channel_id": "spam", "multistream": true, "simulcast": true } ``` 詳細は [サイマルキャスト機能](SIMULCAST.html) をご確認ください。 #### スポットライト **この項目はオプションです** 話をした人にフォーカスを当てて、フォーカスが当たっている人は高画質な映像と音声で配信、 フォーカスが当たっていない人は低画質な映像で配信するという、クライアントの負荷を下げる仕組みです。 ```javascript { "type": "connect", "role": "sendrecv", "channel_id": "spam", "multistream": true, "simulcast": true, "spotlight": true } ``` 詳細は [スポットライト機能](SPOTLIGHT.html) をご確認ください。 #### 転送フィルター > **注意** > > この機能は実験的機能です。 **この項目はオプションです** 接続時に転送フィルターを指定することで、条件に該当する他のチャネル参加者の音声や映像の受信をブロックする仕組みです。 - forwarding_filter- 受信をブロックする条件を指定します - 接続後は [転送フィルター API](EXPERIMENTAL_API_FORWARDING_FILTER.html) を利用してフィルターの変更、削除ができます この値を指定するには `sora.conf` にて [signaling_forwarding_filter](SORA_CONF.html#d15a40) を `true` に設定する必要があります。 ```javascript { "type": "connect", "role": "sendrecv", "channel_id": "spam", "forwarding_filter": { "action": "block", "rules": [ [ {"field": "kind", "operator": "is_in", "values": ["audio"]} ] ] } } ``` 詳細は [転送フィルター機能](FORWARDING_FILTER.html) をご確認ください。 #### sdp **この項目はオプションです** Sora SDK や Sora クライアントで生成した offer SDP を Sora のログに記録します。 この項目は、ログの記録にのみ利用します。 ```javascript { "type": "connect", "role": "sendrecv", "channel_id": "spam", "sdp": "..." } ``` #### sora_client **この項目はオプションです** Sora SDK や Sora クライアントの情報を文字列で送ることができます。 これはログに記録されたり、認証ウェブフックリクエストで送信されたりします。 ```javascript { "type": "connect", "role": "sendrecv", "channel_id": "sora", "sora_client": "Sora JavaScript SDK 2021.1.0" } ``` #### environment **この項目はオプションです** Sora SDK や Sora クライアントの利用環境を文字列で送ることができます。 これはログに記録されたり、認証ウェブフックリクエストで送信されたりします。 Sora JavaScript SDK では userAgent の情報が入ります。 ```javascript { "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 のバージョンを文字列で送ることができます。 これはログに記録されたり、認証ウェブフックリクエストで送信されたりします。 ```javascript { "type": "connect", "role": "sendrecv", "channel_id": "sora", "libwebrtc": "Shiguredo-Build M90.4430@{#3} (90.4430.3.1 dee77cf2)" } ``` ### "type": "offer" 認証ウェブフックが認証成功を返すと、Sora は以下のような JSON をクライアントに送ります。 SDK を利用している場合は、この仕様を意識する必要はありません。 ```javascript { "type": "offer", "sdp": "", "channel_id": "sora", "session_id": "05JTBDGM1H3GB7FK0B1CJ45JE0", "connection_id": "ECF3W1RGMD02DETH30CDZTHNRW", "client_id": "ECF3W1RGMD02DETH30CDZTHNRW", "bundle_id": "ECF3W1RGMD02DETH30CDZTHNRW", "multistream": true, "simulcast": false, "spotlight": false, "version": "2023.2.0", "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" } ] } ``` - channel_id- `"type": "connect"` の `channel_id` で指定した値が入ります - session_id- UUIDv4 を Base32 でエンコードしたユニークな ID が入ります - 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 を生成します。 ```javascript { "type": "answer", "sdp": "" } ``` その後、必要があればクライアントは取得した candidate を送ります。 ```javascript { "type": "candidate", "candidate": "candidate:3179889176 1 tcp 1518214911 192.168.1.10 0 typ host tcptype active generation 0" } ``` ### "type": "disconnect" クライアントからこのメッセージを送ると、Sora は WebSocket を切断します。また、WebRTC 側も終了します。 クライアントから切断する際には、このメッセージを送るようにしてください。 ```javascript { "type": "disconnect" } ``` オプションとして reason を指定することもできます。この値は `connection.destroyed` の `type_disconnect_reason` として含まれます。 ```javascript { "type": "disconnect", "reason": "NO-ERROR" } ``` ### "type": "ping" サーバーからクライアント側に定期的に送られる通知です。この値をクライアントが受け取った場合は、すぐに以下の JSON を Sora に送信してください。 ```javascript { "type": "pong" } ``` `"type": "ping"` を送ってから指定時間の間に一度も `"type": "pong"` が返ってこない場合、 Sora は正常な通信が行えていないと判断して、Sora からシグナリングの接続を切断します。 指定時間はデフォルトでは 60 秒に設定されており、この値は `sora.conf` の設定 [websocket_signaling_pong_timeout](SORA_CONF.html#140464) で変更できます。 #### stats > **注意** > > この機能は WebSocket 経由でのシグナリングの時のみ有効です `sora.conf` にて `user_agent_stats` を `true` にしている場合は、 `"type": "ping"` 時に `"stats": true` が送られてきます。 ```javascript { "type": "ping", "stats": true } ``` この値を受け取った場合は、WebRTC の統計情報を取得して `"type": "pong"` 送信時に `stats` をキーにして値を含んで応答してください。 ```javascript { "type": "pong", "stats": [{"type": "..."}, {"type": "..."}] } ``` ### "type": "notify" サーバーからクライアントに対して、参加しているチャネルの情報が通知されるようになります。 詳細は [シグナリング通知機能](SIGNALING_NOTIFY.html) をご確認ください。 ### "type": "push" Sora の [プッシュ API](API_PUSH.html) や [シグナリング通知メタデータ拡張機能](SIGNALING_NOTIFY_METADATA_EXT.html) 、 [音声ストリーミング機能](AUDIO_STREAMING.html) 利用時にクライアントに送信されるプッシュ通知です。 `data` 内に各機能に応じた情報が設定されます。 ```javascript { "type": "push", "data": { : , : , ... } } ``` ## シグナリングエラー 切断時の reason を利用してハンドリングできます。 - Sora のシグナリング失敗時には必ず WebSocket が切断されます。 - どのようなエラーでも、ステータスコードは固定で 4490 が返ってきます。 - reason にはエラーメッセージが入ります ``` "DUPLICATED-CHANNEL-ID" ``` > **重要** > > Sora はライセンスの期限が切れていたとしても、クライアントには **EXCEED-MAX-CONNECTIONS** というエラーを返します。 * - 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 情報が含まれていなかった場合のエラー * - 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` の設定 [connection_created_wait_timeout](SORA_CONF.html#0509af) で変更できます。 ```ini // これは 10 秒待っても、シグナリングが成功しない場合は接続を切断する設定です connection_created_wait_timeout = 10 s ``` このログが sora.jsonl に出力された場合は、 `log/connection_created_wait_timeout_error/` 以下に詳細なログが出力されます。 ## シーケンス図 ### 認証ウェブフックなし ```mermaid sequenceDiagram autonumber participant C as クライアント participant S as WebRTC SFU Sora participant A as アプリケーションサーバー C->>+S: "type": "connect" S->>-C: "type": "offer" C->>S: "type": "answer" C->>S: "type": "candidate" note over C,A: WebRTC 確立 S->>+A: イベントウェブフック
"type": "connection.created" A-->-S: 200 OK C->>S: "type": "disconnect" S->>+A: イベントウェブフック
"type": "connection.destroyed" A-->>-S: 200 OK S->>C: Websocket Close ``` ### 認証ウェブフックあり ```mermaid sequenceDiagram autonumber participant C as クライアント participant S as WebRTC SFU Sora participant A as アプリケーションサーバー C->>+S: "type": "connect" S->>+A: 認証ウェブフック A-->>-S: 200 OK
{"allowed": "true"} S->>-C: "type": "offer" C->>S: "type": "answer" C->>S: "type": "candidate" note over C,A: WebRTC 確立 S->>+A: イベントウェブフック
"type": "connection.created" A-->-S: 200 OK C->>S: "type": "disconnect" S->>+A: イベントウェブフック
"type": "connection.destroyed" A-->>-S: 200 OK S->>C: Websocket Close ``` # 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- 対応済みです - 最新版の Python SDK- 対応済みです - 最新版の C 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 キロバイト以内に収まるようにしてください。 64 キロバイト以上のメッセージを送る場合は、大きくても 64 キロバイト以下のメッセージなるように分割して送るようにしてください。 ## シグナリング切り替え 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" **DataChannel シグナリングで新しく追加されたタイプです** Sora からクライアントに stats 情報を要求します。 #### "type": "stats" クライアントから Sora に stats 情報を送ります。 ## DataChannel 関連の設定 ### data_channel_stats_timer_interval シグナリングを DataChannel 経由に切り替えた際に、 Sora からクライアントへ統計情報の要求を送る間隔の設定です。 デフォルトは `60 s` です。 ## シーケンス図 ### 認証ウェブフックあり ```mermaid sequenceDiagram autonumber participant C as クライアント participant S as Sora participant A as アプリケーションサーバー C->>+S: "type": "connect" S->>+A: 認証ウェブフック A-->>-S: 200 OK
{"allowed": "true"} S->>-C: "type": "offer" C->>S: "type": "answer" C->>S: "type": "candidate" note over C,A: WebRTC 確立 S->>+A: イベントウェブフック
"type": "connection.created" A-->-S: 200 OK note over C,A: DataChannel 確立 S->>C: "type": "switched" note over C,A: これ以降は DataChannel が利用される ``` ### DataChannel シグナリング ```mermaid sequenceDiagram autonumber participant C as クライアント participant S as Sora note over C,S: WebRTC 確立 note over C,S: DataChannel 確立 S->>C: "type": "switched" note over C,S: これ以降は DataChannel が利用される S->>C: "type": "re-offer" note right of S: label: signaling C->>S: "type": "re-answer" note left of C: label: signaling S->>C: "type": "notify" note right of S: label: notify S->>C: "type": "push" note right of S: label: push S->>C: "type": "req-stats" note right of S: label: stats C->>S: "type": "stats" note left of C: 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; vp9_params?: VP9Params; av1_params?: AV1Params; h264_params?: H264Params; h265_params?: H265Params; }; type VP9Params = { // 0..3 profile_id?: number; }; type AV1Params = { // 0..2 profile?: number; }; type H264Params = { profile_level_id?: string; }; type H265Params = { level_id?: 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; }; type ForwardingFilterRuleField = "connection_id" | "client_id" | "kind"; type ForwardingFilterRuleOperator = "is_in" | "is_not_in"; type ForwardingFilterRuleKindValue = "audio" | "video"; type ForwardingFilterRule = { field: ForwardingFilterRuleField; operator: ForwardingFilterRuleOperator; values: [string]; }; type ForwardingFilterAction = "block" | "allow"; type ForwardingFilter = { version?: string; metadata?: JSONValue; action?: ForwardingFilterAction; rules: [[ForwardingFilterRule]]; }; // SoraClient type SoraClient = { environment?: string; raw?: string; type?: string; version?: string; commit_short?: string; libwebrtc?: string; }; // RTCRtpEncodingParameters // https://w3c.github.io/webrtc-pc/#dom-rtcrtpencodingparameters type SimulcastEncoding = { // https://www.w3.org/TR/webrtc/#dom-rtcrtpcodingparameters-rid rid: SimulcastRid; // https://www.w3.org/TR/webrtc/#dom-rtcrtpencodingparameters-active active?: boolean; // https://www.w3.org/TR/webrtc/#dom-rtcrtpencodingparameters-scaleresolutiondownby scaleResolutionDownBy?: number; // https://www.w3.org/TR/webrtc/#dom-rtcrtpencodingparameters-maxbitrate maxBitrate?: number; // https://w3c.github.io/webrtc-extensions/#dom-rtcrtpencodingparameters-maxframerate maxFramerate?: number; // https://w3c.github.io/webrtc-extensions/#dom-rtcrtpencodingparameters-adaptiveptime adaptivePtime?: boolean; // https://www.w3.org/TR/webrtc-svc/#dom-rtcrtpencodingparameters-scalabilitymode scalabilityMode?: 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; forwarding_filter?: ForwardingFilter; audio_streaming_language_code?: string; e2ee?: boolean; sdp?: string; sora_client?: string; 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; channel_id: string; session_id: string; client_id: string; bundle_id: string; connection_id: string; metadata?: JSONValue; config?: JSONValue; encodings?: SimulcastEncoding[]; mid: Mid; version: string; 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 | SignalingNotifyForwardingBlocked | SignalingNotifyForwardingAllowed | SignalingNotifyNetworkStatus | SignalingNotifyRtpStreamPause | SignalingNotifyRtpStreamResume; // 接続中のクライアントの情報 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; }; // "forwarding.blocked" type SignalingNotifyForwardingBlocked = { type: "notify"; event_type: "forwarding.blocked"; kind: ForwardingFilterRuleKindValue; destination_connection_id: string; source_connection_id: string; }; // "forwarding.allowed" type SignalingNotifyForwardingAllowed = { type: "notify"; event_type: "forwarding.allowed"; kind: ForwardingFilterRuleKindValue; destination_connection_id: string; source_connection_id: string; }; // "network.status" type SignalingNotifyNetworkStatus = { type: "notify"; event_type: "network.status"; unstable_level: 0 | 1 | 2 | 3; }; // "rtp_stream.pause" type SignalingNotifyRtpStreamPause = { type: "notify"; event_type: "rtp_stream.pause"; recv_connection_id: string; send_connection_id: string; }; // "rtp_stream.pause" type SignalingNotifyRtpStreamResume = { type: "notify"; event_type: "rtp_stream.resume"; stream_id: string; }; // 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 がシグナリング利用に接続する WebSocket やデータチャネルを利用して、 自身の状態や、他のコネクションの状態をリアルタイムに通知する機能です ## シグナリング通知を利用することで実現できること - 配信されているストリームに対してユーザー名を表示する - 新しくチャネルに参加したクライアントのユーザー名を通知する - 現在のネットワークの状態をクライアント画面に表示する - 離脱したユーザーの名前を表示する - 録画の開始や停止をクライアントに通知する - スポットライト機能を利用した場合に、配信が切り替わったことをクライアントに通知する ## シグナリング通知の有効 / 無効について シグナリング通知はデフォルトで有効になっています。 シグナリング通知を無効にした場合はシグナリング通知が送られてこなくなります。 無効にするには、 `sora.conf` でシグナリング通知の無効を指定するか、または、認証ウェブフックの戻り値で無効を指定する必要があります。 ### sora.conf での指定 `sora.conf` でシグナリング通知の有無を指定する方法です。 `sora.conf` で `signaling_notify = false` を指定することで、シグナリング通知が無効になります。 ただし、この値は認証ウェブフックの戻り値で上書きできます。 ### 認証ウェブフックの戻り値での指定 認証ウェブフックの戻り値を利用して、クライアントごとに signaling_notify の true / false を指定する方法です。 認証ウェブフックの戻り値に `{"signaling_notify": false}` を指定することで、そのクライアントに対して signaling_notify を無効にできます。 ```javascript { "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 **デフォルト**: true `sora.conf` で `signaling_notify_client_id = false` を指定することで、シグナリング通知時にクライアント ID を含まなくなります。 ただし [スポットライト機能のシグナリング通知](SIGNALING_NOTIFY.html#dcfbb9) には常にクライアント ID が含まれます。 ### signaling_notify_bundle_id **デフォルト**: true `sora.conf` で `signaling_notify_bundle_id = false` を指定することで、シグナリング通知時にバンドル ID を含まなくなります。 ただし [スポットライト機能のシグナリング通知](SIGNALING_NOTIFY.html#dcfbb9) には常にバンドル ID が含まれます。 ### signaling_notify_connection_id **デフォルト**: true `sora.conf` で `signaling_notify_connection_id = false` を指定することで、シグナリング通知時にコネクション ID を含まなくなります。 ただし [スポットライト機能のシグナリング通知](SIGNALING_NOTIFY.html#dcfbb9) 、 [転送フィルターのシグナリング通知](SIGNALING_NOTIFY.html#efa550) 、 [RTP ストリーム停止と再開のシグナリング通知](SIGNALING_NOTIFY.html#ec23ca) には常にコネクション ID が含まれます。 ### signaling_notify_connection_created_timestamp **デフォルト**: true これは `event_type` が `connection.created` の時のみ有効になります。 `sora.conf` で `signaling_notify_connection_created_timestamp = false` を指定することで、シグナリング通知時にコネクション生成時刻を含まなくなります。 ### signaling_notify_media **デフォルト**: true `sora.conf` で `signaling_notify_media = false` を指定することで、シグナリング通知時に音声や映像の情報を含まなくなります。 ただし [スポットライト機能のシグナリング通知](SIGNALING_NOTIFY.html#dcfbb9) には常に音声や映像の情報が含まれます。 ### signaling_notify_metadata **デフォルト**: true `signaling_notify_metadata` は、ユーザーが参加や離脱したときに送られるシグナリング通知に含まれるメタデータです。 シグナリング通知メタデータの詳細は [シグナリング通知メタデータ](SIGNALING_NOTIFY_METADATA.html) をご確認ください。 `sora.conf` で `signaling_notify_metadata = false` を指定すると [コネクションのシグナリング通知](SIGNALING_NOTIFY.html#5b6b0a) でシグナリング通知メタデータおよびシグナリング通知メタデータ拡張の情報を含まなくなります。 ### signaling_notify_metadata_ext **デフォルト**: false `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` は、自身に通知されます - timestamp- string - RFC3339 (マイクロ秒) - `connection.created` の時に、コネクション生成時間が含まれます - 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, authz_metadata, auth_metadata- json - [シグナリング通知メタデータ](SIGNALING_NOTIFY_METADATA.html) で利用する項目です。 - `sora.conf` で、 `signaling_notify_metadata` を `false` にすることでこの値は含まれなくなります - data- json 型のリスト- json 型の中身は、以下の sora.conf の設定により変化します- [signaling_notify_client_id](SORA_CONF.html#fc78ca) - [signaling_notify_bundle_id](SORA_CONF.html#f2a58f) - [signaling_notify_connection_id](SORA_CONF.html#7882d6) - [signaling_notify_connection_created_timestamp](SORA_CONF.html#7fe7b3) - [signaling_notify_metadata](SORA_CONF.html#2d9340) - 上記の設定が全て `false` になり、通知する値がなくなった場合、この値は含まれなくなります - 設定値による json 型の中身は、 [sora.conf の設定内容と connection.created 出力の例](SIGNALING_NOTIFY.html#2729eb) をご確認ください - 新規でチャネルに接続した際に、すでにチャネルに参加している接続一覧の情報がはいります- チャネル内で 1 つめの接続である場合は、この値は空のリストになります - 接続を開始して初回の `connection.created` の場合のみこの値が入ります ## sora.conf の設定内容と connection.created 出力の例 `data` に含まれる項目を例に sora.conf の設定内容と `connection.created` 出力の例を示します。 ### デフォルト デフォルトでは全て `true` であり、値が通知されます。 ```ini # 全てコメントアウトされているため、デフォルト値が適用される # signaling_notify_client_id = false # signaling_notify_bundle_id = false # signaling_notify_connection_id = false # signaling_notify_connection_created_timestamp = false # signaling_notify_metadata = false ``` **一部項目を省略しています** ```javascript { "type": "notify", "event_type": "connection.created", "session_id": "P24NZ0AX2D6FX15VFHEGBXGMEW", "bundle_id": "WHSSBG91XS7NXEVYY0F51YFEEW", "client_id": "client3", "connection_id": "WHSSBG91XS7NXEVYY0F51YFEEW", "timestamp": "2023-12-18T07:12:11.876287Z", "authn_metadata": {"spam": "egg"}, "authz_metadata": "bacon", "metadata": "bacon", "data": [ { "bundle_id": "KKBFZTQXDD6H7FD2NYCQX8S474", "client_id": "client1", "connection_id": "KKBFZTQXDD6H7FD2NYCQX8S474", "timestamp": "2023-12-18T07:11:56.585769Z", "authn_metadata": 10, "authz_metadata": {"authz": true}, "metadata": {"authz": true} }, { "bundle_id": "4D40YWH56N5S99QHJV6GAPNHB0", "client_id": "client2", "connection_id": "4D40YWH56N5S99QHJV6GAPNHB0", "timestamp": "2023-12-18T07:11:58.685769Z", "authn_metadata": 10, "metadata": 10 } ] } ``` ### client_id を通知しない `signaling_notify_client_id = false` を指定すると、client_id が含まれなくなります。 ```ini signaling_notify_client_id = false # signaling_notify_bundle_id = false # signaling_notify_connection_id = false # signaling_notify_connection_created_timestamp = false # signaling_notify_metadata = false ``` **一部項目を省略しています** ```javascript { "type": "notify", "event_type": "connection.created", "session_id": "P24NZ0AX2D6FX15VFHEGBXGMEW", "bundle_id": "WHSSBG91XS7NXEVYY0F51YFEEW", "connection_id": "WHSSBG91XS7NXEVYY0F51YFEEW", "timestamp": "2023-12-18T07:12:11.876287Z", "authn_metadata": {"spam": "egg"}, "authz_metadata": "bacon", "metadata": "bacon", "data": [ { "bundle_id": "KKBFZTQXDD6H7FD2NYCQX8S474", "connection_id": "KKBFZTQXDD6H7FD2NYCQX8S474", "timestamp": "2023-12-18T07:11:56.585769Z", "authn_metadata": 10, "authz_metadata": {"authz": true}, "metadata": {"authz": true} }, { "bundle_id": "4D40YWH56N5S99QHJV6GAPNHB0", "connection_id": "4D40YWH56N5S99QHJV6GAPNHB0", "timestamp": "2023-12-18T07:11:58.685769Z", "authn_metadata": 10, "metadata": 10 } ] } ``` ### metadata を通知しない `signaling_notify_metadata = false` を指定すると `metadata`, `authz_metadata`, `authn_metadata` が含まれなくなります。 ```ini # signaling_notify_client_id = false # signaling_notify_bundle_id = false # signaling_notify_connection_id = false # signaling_notify_connection_created_timestamp = false signaling_notify_metadata = false ``` **一部項目を省略しています** ```javascript { "type": "notify", "event_type": "connection.created", "session_id": "P24NZ0AX2D6FX15VFHEGBXGMEW", "bundle_id": "WHSSBG91XS7NXEVYY0F51YFEEW", "connection_id": "WHSSBG91XS7NXEVYY0F51YFEEW", "timestamp": "2023-12-18T07:12:11.876287Z", "data": [ { "bundle_id": "KKBFZTQXDD6H7FD2NYCQX8S474", "connection_id": "KKBFZTQXDD6H7FD2NYCQX8S474", "timestamp": "2023-12-18T07:11:56.585769Z" }, { "bundle_id": "4D40YWH56N5S99QHJV6GAPNHB0", "connection_id": "4D40YWH56N5S99QHJV6GAPNHB0", "timestamp": "2023-12-18T07:11:58.685769Z" } ] } ``` ### client_id と bundle_id と connection_id を通知しない 通知が不要のものを複数指定することができます。 ```ini signaling_notify_client_id = false signaling_notify_bundle_id = false signaling_notify_connection_id = false # signaling_notify_connection_created_timestamp = false # signaling_notify_metadata = false ``` **一部項目を省略しています** ```javascript { "type": "notify", "event_type": "connection.created", "session_id": "P24NZ0AX2D6FX15VFHEGBXGMEW", "timestamp": "2023-12-18T07:12:11.876287Z", "authn_metadata": {"spam": "egg"}, "authz_metadata": "bacon", "metadata": "bacon", "data": [ { "timestamp": "2023-12-18T07:11:56.585769Z", "authn_metadata": 10, "authz_metadata": {"authz": true}, "metadata": {"authz": true} }, { "timestamp": "2023-12-18T07:11:58.685769Z", "authn_metadata": 10, "metadata": 10 } ] } ``` ### data 内の項目全てを通知しない ```ini signaling_notify_client_id = false signaling_notify_bundle_id = false signaling_notify_connection_id = false signaling_notify_connection_created_timestamp = false signaling_notify_metadata = false ``` `data` 項目に関する通知を不要に設定すると、 `data` 項目自体が送信されなくなります。 **一部項目を省略しています** ```javascript { "type": "notify", "event_type": "connection.created", "session_id": "P24NZ0AX2D6FX15VFHEGBXGMEW" } ``` ### "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 - 切り替わった配信が固定されているかどうかが入ります ```javascript { "type": "notify", "event_type": "spotlight.focused", "client_id": "4D40YWH56N5S99QHJV6GAPNHB0", "bundle_id": "4D40YWH56N5S99QHJV6GAPNHB0", "connection_id": "4D40YWH56N5S99QHJV6GAPNHB0", "spotlight_number": 3, "audio": true, "video": true, "fixed": false } ``` ```javascript { "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" 録画開始時に通知されます。 接続前にセッションウェブフック `session.created` で `"recording": true` や `StartRecording` API によって録画が開始されていた場合、 `connection.created` の後に通知されます。 ```javascript { "type": "notify", "event_type": "recording.started", "client_id": "4D40YWH56N5S99QHJV6GAPNHB0", "bundle_id": "4D40YWH56N5S99QHJV6GAPNHB0", "connection_id": "4D40YWH56N5S99QHJV6GAPNHB0" } ``` ### "event_type": "recording.stopped" 録画終了時に通知されます。 `StopRecording` API が実行されたタイミング、または期限が切れたタイミングで通知されます。 ```javascript { "type": "notify", "event_type": "recording.stopped", "client_id": "4D40YWH56N5S99QHJV6GAPNHB0", "bundle_id": "4D40YWH56N5S99QHJV6GAPNHB0", "connection_id": "4D40YWH56N5S99QHJV6GAPNHB0" } ``` ## 転送フィルターのシグナリング通知 **これは実験的機能です** ### "event_type": "forwarding.blocked" ```javascript { "type": "notify", "event_type": "forwarding.blocked", "kind": "video", "destination_connection_id": "FCX8X05SJS3Y18RD5MYFZS62RR", "source_connection_id": "SM7WDVYRTH739BB47ZSPQQ2BT4" } ``` ### "event_type": "forwarding.allowed" ```javascript { "type": "notify", "event_type": "forwarding.allowed", "kind": "video", "destination_connection_id": "FCX8X05SJS3Y18RD5MYFZS62RR", "source_connection_id": "SM7WDVYRTH739BB47ZSPQQ2BT4" } ``` ## ネットワークのシグナリング通知 **これは実験的機能です** ネットワークのシグナリング通知は、上記の `connection.*` とは別に `network.*` が通知されます。 ### "event_type": "network.status" この event_type は、 `signaling_notify` を有効にしている全員に通知されます。 この通知を利用することで、ネットワークの状態をクライアントが把握できるようになります。 ### 送られる条件 現時点では映像を Sora に対して配信していることが通知の条件になります。 以下は通知されません - 受信のみ - 音声だけの配信 ### 現在の判定材料 - クライアント、またはサーバーからの再送要求の頻度 ### クライアントに送信される JSON の仕様 - event_type- string - `network.status` が入ります - unstable_level- integer - ネットワークの不安定レベルが入ります- 0- とても安定したネットワークです - 1- 安定したネットワークです - 2- 不安定なネットワークです - 3- とても不安定なネットワークです ```javascript { "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 ストリームが停止される送信側および受信側の接続に通知されます。 ```javascript { "type": "notify", "event_type": "rtp_stream.pause", "recv_connection_id": "4D40YWH56N5S99QHJV6GAPNHB0", "send_connection_id": "4SW2CB0E1D01S23W3G6JFCEN98" } ``` ### "event_type": "rtp_stream.resume" RTP ストリーム再開時に通知されます。RTP ストリームが再開される送信側および受信側の接続に通知されます。 ```javascript { "type": "notify", "event_type": "rtp_stream.resume", "stream_id": "4D40YWH56N5S99QHJV6GAPNHB0" } ``` ## シーケンス図 ### コネクション関連の通知 ```mermaid sequenceDiagram participant C1 as クライアント1 participant C2 as クライアント2 participant S as Sora participant A as アプリケーションサーバー C1 ->>+ S: type: "connect"
client_id: "client1" S ->>+ A: 認証ウェブフック A -->>- S: 200 OK S ->>+ A: セッションウェブフック A -->>- S: 200 OK S -->>- C1: type: "offer" C1 -) S: type: "answer" note over C1, S: WebRTC 確立 par S ->>+ A: イベントウェブフック
"type": "connection.created" A -->>- S: 200 OK and S -) C1: type: "notify"
event_type: "connection.created"
client_id: "client1" end note over C1, S: 1 分経過 par S ->>+ A: イベントウェブフック
"type": "connection.updated" A -->>- S: 200 OK and S -) C1: type: "notify"
event_type: "connection.updated"
client_id: "client1" end C2 ->>+ S: type: "connect"
client_id: "client2" S ->>+ A: 認証ウェブフック A -->>- S: 200 OK S -->>- C2: type: "offer" C2 -) S: type: "answer" note over C2, S: WebRTC 確立 par S ->>+ A: イベントウェブフック
"type": "connection.created" A -->>- S: 200 OK and S -) C2: type: "notify"
event_type: "connection.created"
client_id: "client2" and S -) C1: type: "notify"
event_type: "connection.created"
client_id: "client2" end C1 ->> S: type: "disconnect" note over C1, S: 切断 par S ->>+ A: イベントウェブフック
"type": "connection.destroyed" A -->>- S: 200 OK and S -) C2: type: "notify"
event_type: "connection.destroyred"
client_id: "client1" end ``` 録画関連の通知 ------------------------ ```mermaid sequenceDiagram participant C as クライアント participant S as Sora participant A as アプリケーションサーバー C ->>+ S: type: "connect"
client_id: "client1" S ->>+ A: 認証ウェブフック A -->>- S: 200 OK S ->>+ A: セッションウェブフック A -->>- S: 200 OK
recording: true S -->>- C: type: "offer" C -) S: type: "answer" note over C, S: WebRTC 確立 par S ->>+ A: イベントウェブフック
"type": "connection.created" A -->>- S: 200 OK and S -) C: type: "notify"
event_type: "connection.created"
client_id: "client1" S -) C: type: "notify"
event_type: "recording.started"
client_id: "client1" end A ->>+ S: StopRecording API S -->>- A: 200 OK S -) C: type: "notify"
event_type: "recording.stopped"
client_id: "client1" S ->>+ A: イベントウェブフック
"type": "archive.available" A -->>- S: 200 OK S ->>+ A: イベントウェブフック
"type": "recording.report" A -->>- S: 200 OK ``` # シグナリング通知メタデータ ## 概要 `signaling_notify_metadata` はクライアントの状態が変化したときに送られる、シグナリング通知に含まれるメタデータです。 シグナリング接続時、または認証ウェブフック成功の戻り値に `signaling_notify_metadata` で JSON 値を指定することで利用できるようになります。 新しく参加した際に、すでにそのチャネルに参加しているクライアントの `signaling_notify_metadata` の値がリストで共有されます。 ## 注意 ### シグナリング通知メタデータの認証成功時払い出しによる上書き 接続時に指定したシグナリング通知メタデータは、認証成功時に `signaling_notify_metadata` の払い出しによって上書きされます。 詳細は [接続時のシグナリング通知メタデータを認証払い出し時のシグナリング通知メタデータで上書き](SIGNALING_NOTIFY_METADATA.html#2f3416) をご確認ください。 ### シグナリング通知メタデータ拡張 [シグナリング通知メタデータ拡張機能](SIGNALING_NOTIFY_METADATA_EXT.html) を有効にしている場合、 `metadata` はシグナリング通知メタデータ拡張で利用されるため、 `signaling_notify_metadata` で指定した値は `metadata` には含まれません。 - 接続時に指定したシグナリング通知メタデータは `authn_metadata` として含まれます - 認証成功時に払い出したシグナリング通知メタデータは `authz_metadata` として含まれます ## 設定 `sora.conf` で [signaling_notify_metadata](SORA_CONF.html#2d9340) を `false` を指定することで、 シグナリング通知時に `metadata` や `authn_metadata` や `authz_metadata` を含まなくなります。 設定を行ったときの出力例は [sora.conf の設定内容と connection.created 出力の例](SIGNALING_NOTIFY.html#2729eb) をご確認ください。 ## シグナリング接続時での指定 `"type": "connect"` 接続時に `signaling_notify_metadata` で JSON 値を指定できます。 ```javascript { "type": "connect", "role": "sendrecv", "channel_id": "sora", "signaling_notify_metadata": {"authn": true} } ``` シグナリング接続時に指定した値は、通知時に `metadata` として通知されます。 また `auth_metadata` としても通知されます。 `"data"` にはすでにそのチャネルが参加しているクライアントの情報がリストで含まれます。 ```javascript { "type": "notify", "event_type": "connection.created", "authn_metadata": {"authn": true}, "metadata": {"authn": true} "data": [ { "connection_id": "KKBFZTQXDD6H7FD2NYCQX8S474", "authz_metadata": "xyz", "metadata": "xyz" }, { "connection_id": "4D40YWH56N5S99QHJV6GAPNHB0", "authn_metadata": 10, "metadata": 10 } ] } ``` ### シグナリング接続時に指定できるシグナリング通知メタデータのサイズ制限 > **重要** > > シグナリング接続時に指定できるシグナリング通知メタデータのサイズはのデフォルトは 64 KiB (65536 バイト) です。 メタデータのサイズはメタデータ拡張機能をエンコード済みの JSON 、つまり文字列としてサイズを計算します。 例えば `{"a":"b"}` の場合は 9 バイトで、 `{"a":"b","c":1200}` は 18 バイトです。 最大値を変更したい場合は `sora.conf` の [signaling_notify_authn_metadata_max_size](SORA_CONF.html#a8c147) を変更してください。 また、シグナリング通知メタデータを接続時に指定できなくする場合は [signaling_notify_authn_metadata_max_size](SORA_CONF.html#a8c147) を `0` にしてください。 ## 認証ウェブフックの戻り値での指定 認証ウェブフックでの戻り値は、シグナリング接続時に指定した値を上書きします。 ```javascript { "allowed": true, "signaling_notify_metadata": "authz" } ``` 認証ウェブフックの戻り値で指定した値は、通知時に `metadata` としても通知されます。 また `authz_metadata` としても通知されます。 `"data"` にはすでにそのチャネルが参加しているクライアントの情報がリストで含まれます。 ```javascript { "type": "notify", "event_type": "connection.created", "authn_metadata": "authz", "metadata": "authz" "data": [ { "connection_id": "KKBFZTQXDD6H7FD2NYCQX8S474", "authz_metadata": "xyz", "metadata": "xyz" }, { "connection_id": "4D40YWH56N5S99QHJV6GAPNHB0", "authn_metadata": 10, "metadata": 10 } ] } ``` すでに参加しており、他のクライアントが参加してきた場合や離脱した場合は以下の通りになります。 ```javascript { "type": "notify", "authz_metadata": {"username": "alice"}, "metadata": {"username": "alice"}, } ``` ### 認証成功時払い出しのシグナリング通知メタデータのサイズ制限 制限はありません。 ## 接続時のシグナリング通知メタデータを認証払い出し時のシグナリング通知メタデータで上書き 接続時に指定したシグナリング通知メタデータは、 認証成功時の払い出しのシグナリング通知メタデータで上書きされます。 ### 接続時に指定したシグナリング通知メタデータ 接続時に指定したシグナリング通知メタデータを `"authn"` と指定しています。 ```javascript { "type": "connect", "role": "sendrecv", "channel_id": "sora", "signaling_notify_metadata": {"authn": true} } ``` ### 認証成功時に払い出したシグナリング通知メタデータ 認証成功時にシグナリング通知メタデータを `"authz"` と払い出しています。 ```javascript { "allowed": true, "signaling_notify_metadata": "authz" } ``` ### クライアントへ送られるシグナリング通知メタデータ 認証成功時に払い出したシグナリング通知メタデータである `"authz"` が `metadata` として通知されます。 ```javascript { "type": "notify", "event_type": "connection.created", "authn_metadata": {"authn": true}, "authz_metadata": "authz", "metadata": "authz", "data": [] } ``` # シグナリング通知メタデータ拡張機能 > **警告** > > シグナリング通知メタデータ拡張機能は実験的機能のため正式版では仕様が変更される可能性があります ## 概要 シグナリング通知メタデータ拡張機能(以降メタデータ拡張機能)は、 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 バイトです。 ## メタデータ拡張の初期値 メタデータ拡張機能の初期値を認証ウェブフックの成功時に。払い出すことができます。 ```javascript { "allowed": true, "signaling_notify_metadata_ext": { "abc": 10 } } ``` 払い出す値は JSON Object である必要があります。 ## 利用方法 **開発ツールを利用します** > **注意** > > シグナリング通知メタデータ拡張 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 では認証の判断や状態の通知などを全てウェブフックを利用します。 認証ウェブフックやセッションウェブフックの一部では、ウェブフックの戻り値で設定を払い出すことができます。 ## ウェブフックリクエスト - ウェブフックは HTTP/1.1 で送信します - `content-type` は `application/json` です ## ウェブフックの設定 - ウェブフック URL を設定しない場合は、ウェブフックリクエストを送信しません - ウェブフックログを出力しないという設定はありません ### 認証ウェブフック **設定**: `auth_webhook_url` に認証ウェブフックの URL を指定します。 **ログ**: `auth_webhook.jsonl` に認証ウェブフックのログが出力されます 詳細は [認証ウェブフック](AUTH_WEBHOOK.html) をご確認ください。 ### セッションウェブフック **設定**: `session_webhook_url` にセッションウェブフックの URL を指定します。 **ログ**: `session_webhook.jsonl` に認証ウェブフックのログが出力されます 詳細は [セッションウェブフック](SESSION_WEBHOOK.html) をご確認ください。 ### イベントウェブフック **イベント**: `event_webhook_url` にイベントウェブフックの URL を指定します。 **ログ**: `event_webhook.jsonl` に認証ウェブフックのログが出力されます 詳細は [イベントウェブフック](EVENT_WEBHOOK.html) をご確認ください。 ## ウェブフックリクエストなどの送信先サーバー証明書の検証に利用する OS 組み込みのルート CA 証明書について Sora は外部サーバーに HTTPS で通信を行う際、デフォルトでは OS に組み込まれた信頼された CA 証明書を利用します。 - Ubuntu は `apt install ca-certificates` でインストールされる証明書を利用します - RHEL (または CentOS) は `dnf install ca-certificates` でインストールされる証明書を利用します それぞれの OS の CA 証明書のパス以下になります。 - Ubuntu は `/etc/ssl/certs/ca-certificates.crt` のパスにある信頼された CA 証明書を利用します - RHEL (または CentOS) は `/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem` のパスにある信頼された CA 証明書を利用します OS の証明書の読み込みに失敗した場合は、サーバーから送られてくる証明書の検証を行わないようになり、接続毎に `warning` ログが出力されます。 ウェブフックで利用する CA 証明書は [webhook_tls_verify_cacert_file](SORA_CONF.html#7036dc) に指定することができます。 音声ストリーミングや統計エクスポーターでも CA 証明書を指定することができます。 - [audio_streaming_tls_verify_cacert_file](SORA_CONF.html#feef99) - [stats_exporter_tls_verify_cacert_file](SORA_CONF.html#bcd961) ## ウェブフックリクエスト送信先のサーバーがベーシック認証を利用している場合 もしウェブフックリクエスト送信先のサーバーがベーシック認証を利用している場合は、 `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 は `sora.conf` にて CA 証明書を指定しない限り OS に組み込まれた信頼された CA 証明書を利用します。 そのため、自己署名証明書などの正規の認証局から発行されていない証明書を使用した場合には、信頼できないと判断しエラーになります。 この場合は `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) にクライアント秘密鍵を指定します。 送信先のサーバーが自己証明書などを利用している場合は [webhook_tls_verify_cacert_file](SORA_CONF.html#7036dc) にサーバー CA 証明書を指定します。 ## ウェブフックリクエスト送信先が IPv6 アドレスのみ対応している場合 Sora は `sora.conf` にて `webhook_ipv6` を `true` にすることで、 IPv6 のみのサーバーに対して、ウェブフックリクエストを送信できるようになります。 ## `connection.updated` と `session.updated` ウェブフック [session.updated](SESSION_WEBHOOK.html#2a5b1b) と [connection.updated](EVENT_WEBHOOK.html#5430cd) は一定間隔で送信してくるウェブフックです。 これらのウェブフックをアプリケーションサーバー側で記録しておくことで、 もし何か障害が発生しウェブフックが通知されなくなった場合でも、 そのコネクションが存在するかどうかの判断を行う事ができるようになります。 ## ウェブフックの順番保証 Sora は一部のイベントウェブフックリクエストを送信する際、順番を保証して送信します。 - `connection.created` の前に `connection.destroyed` が送信されることはありません - `archive.started` の前に `archive.available` や `split-archive.available` や `split-archive.end` が送信されることはありません ## ウェブフックエラーメッセージ これらのエラーメッセージは sora.jsonl に出力されます。 - AUTH-WEBHOOK-INTERNAL-ERROR - SESSION-WEBHOOK-INTERNAL-ERROR - EVENT-WEBHOOK-ERROR ### reason - reason に nxdomain が含まれる場合- DNS A レコードまたは AAAA レコードが存在しない # 認証ウェブフック ## 概要 Sora 自体はクライアントの接続を認証する機能を持っていません。認証する場合は外部に認証サーバーを用意する必要があります。 Sora はシグナリング経由で送られてきた情報や、 そのチャネルに接続している情報を POST リクエストで `sora.conf` の [auth_webhook_url](SORA_CONF.html#36a99a) に指定された URL へ送信します。 このとき送信する情報は JSON 形式です。 ## 注意 シグナリング `"type": "connect"` 経由で送られてきた情報がそのまま認証ウェブフックのリクエストとして送信されるわけではありません。 ### ログの出力 `sora.conf` の [auth_webhook_url](SORA_CONF.html#36a99a) を有効にしない場合でも `log/auth_webhook.jsonl` は生成されます。 ## HTTP ヘッダー > **警告** > > この機能は [実験的機能](EXPERIMENTAL.html) のため、正式版では仕様が変更される可能性があります > **注釈** > > JSON のパース時の判断などに利用してください。 ### sora-connection-id 認証ウェブフックの HTTP ヘッダー に `sora-connection-id` というヘッダー名でコネクション ID が入ってきます。 コネクション ID が `WCJC78EWK935N7P7Z8FYAKFW9M` の場合は `sora-connection-id: WCJC78EWK935N7P7Z8FYAKFW9M` のように値が入ってきます。 ## 設定 ### auth_webhook_url **デフォルト**: 未設定 認証可否の判断に使用する HTTP リクエストの送信先を `sora.conf` の [auth_webhook_url](SORA_CONF.html#36a99a) に設定します。 認証ウェブフック機能を使用する場合は指定してください。 HTTP のレスポンスは認証の可否に関わらず、 200 OK 等 200 番台のステータスコードを返す必要があります。 ```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 を送ります。 ```javascript { "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/120.0.6099.109 Safari/537.36", "raw": "Sora JavaScript SDK 2023.2.0", "type": "Sora JavaScript SDK", "version": "2023.2.0" }, "spotlight": false, "timestamp": "2022-06-08T07:51:32.593704Z", "version": "2023.2.0", "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 フォーマットで入ってきます - マイクロ秒まで含まれています - id- Base32-UUIDv4 です - ウェブフック毎に割り当てられるユニークな値です - e2ee- クライアントが E2EE を有効にしているかどうかが入ってきます - `true` の場合は E2EE を利用する接続です - multistream- マルチストリームでの接続要求を出しているかどうかの値が入ってきます - クライアントが送ってこない場合は `true` が設定されます - `true` の場合はマルチストリームを希望している接続です - simulcast- サイマルキャストでの接続要求を出しているかどうかの値が入ってきます - `true` の場合はサイマルキャストを希望している接続です - クライアントが送ってこない場合は `false` が設定されます - simulcast_rid- `simulcast` が `true` かつ `spotlight` が `false` の場合のみこの値が入ってきます - サイマルキャストでの受け取る rid を指定します - spotlight- スポットライトでの接続要求を出しているかどうかの値が入ってきます - クライアントが送ってこない場合は `false` が設定されます - spotlight_focus_rid- `spotlight` が `true` の場合のみこの値が入ってきます - スポットライトでフォーカスされた参加者の映像を受信する rid を指定します - spotlight_unfocus_rid- `spotlight` が `true` の場合のみこの値が入ってきます - スポットライトでフォーカスされていない参加者の映像を受信する rid を指定します - spotlight_number- **この項目はオプションです** - クライアントが送ってこない場合は、この値は含まれません - `spotlight_number` をシグナリングの connect 時に送ってきた場合に値が入ります - role- 以下が入ってきます - `sendrecv` (送受信) - `sendonly` (送信) - `recvonly` (受信) - metadata- **この項目はオプションです** - ユーザーが定義を自由にできる値です - JSON で使用できる形式ならどんな値でも指定できます - `"type": "connect"` で `metadata` が送られてこない場合、アプリケーション側にも送られません - authn_metadata- この項目は metadata と同じです - metadata の別名です - `"type": "connect"` で `metadata` が送られてこない場合、アプリケーション側にも送られません - channel_id- 認証対象のクライアントが接続要求を出しているチャネル ID です - client_id- 認証対象のクライアントが利用要求を出しているクライアント ID です - bundle_id- 認証対象のコネクションが利用要求を出しているバンドル ID です - connection_id- Base32-UUIDv4 です - 認証対象のコネクションに割り当てられたユニークな ID です - channel_connections- 現在そのチャネルの接続数です - 自分は含まれません - channel_sendrecv_connections- 現在そのチャネルで送受信をしている配信者の接続数です - 自分は含まれません - channel_sendonly_connections- 現在そのチャネルで送信のみをしている配信者の接続数です - 自分は含まれません - channel_recvonly_connections- 現在そのチャネルの配信を受信のみしている視聴者の接続数です - 自分は含まれません - audio- `true` または `false` が入ってきます - `false` の場合は `audio` を使用しません - audio_codec_type- **この項目はオプションです** - `audio` が `false` の場合は含まれません - コーデックの種類は `OPUS` または `LYRA` です - audio_bit_rate- **この項目はオプションです** - `audio` が `false` やクライアントが送ってこない場合、含まれません - この設定は `audio_codec_type` が `OPUS` の時のみ有効です - [default_audio_bit_rate](SORA_CONF.html#07627a) に値を指定していた場合はその値が利用されます - 最小が 6 で、最大が 510 です - 単位は `kbps` です - video- `true` または `false` が入ってきます - `false` の場合は `video` を使用しません - video_codec_type- **この項目はオプションです** - `video` が `false` の場合は含まれません - コーデックはクライアントが送ってこない場合はデフォルトで `VP9` が使用されます - コーデックの種類は `VP8`、 `VP9`、 `AV1`、 `H264`、 `H265` です - video_bit_rate- **この項目はオプションです** - `video` が `false` の場合は含まれません - ビットレートはクライアントが送ってこない場合は `sora.conf` の [default_video_bit_rate](SORA_CONF.html#620132) が使用されます - デフォルトは 500 です - 最小が 1 で、最大が 30000 です - 15000 より大きい値は現時点でサポート範囲外です - 単位は `kbps` です - metadata- **この項目はオプションです** - ユーザーが定義を自由にできる値です - JSON で使用できる形式ならどんな値でも指定できます - `"type": "connect"` で `metadata` が送られてこない場合、アプリケーション側にも送られません - authn_metadata- **この項目はオプションです** - この項目は metadata と同じです - metadata の別名です - `"type": "connect"` で `metadata` が送られてこない場合、アプリケーション側にも送られません - data_channel_signaling- シグナリングの DataChannel 切り替えをするかどうか - ignore_disconnect_websocket- シグナリングの DataChannel 切り替え時に WebSocket の切断を無視するかどうか - data_channels- **この項目はオプションです** - DataChannel を利用したメッセージングの定義が入ってきます - forwarding_filter- **この項目はオプションです** - 転送フィルターが入ってきます - クライアントが指定しない場合は入ってきません - sora_client- **この項目はオプションです** - クライアントから送られてきた情報が入ってきます ## 認証ウェブフックに含まれる同時接続数について - channel_connections - channel_sendrecv_connections - channel_sendonly_connections - channel_recvonly_connections これら認証ウェブフックに含まれる同時接続数は WebRTC が確立した後に +1 され、WebRTC が切断されたタイミングで -1 されます。 そのため認証タイミングと WebRTC 確立時の時間差が存在します。 さらに、認証ウェブフックは並列で処理されるため、アプリ側でこの同時接続数の値を利用した厳密な同時接続数の制限を行う事はできません。 もし厳密なチャネル単位での同時接続数を制限したい場合は、 イベントウェブフック `connection.created` を利用して、 アプリ側でデータベースでロックを取ってカウントを行い、ロックを取って数値をチェックして認証を行ってください。 ## sora_client 認証ウェブフックの `sora_client` にはクライアントから送られてきた情報が入ってきます。 クライアントから情報が送られてこなければ含まれません。 Sora SDK を利用している場合は必ず入ってきます。 ```javascript "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": "2023.2.0" }, ``` - type- オプションです - クライアントから送られてきた Sora SDK またはクライアントのタイプが入ってきます - raw- オプションです - クライアントから送られてきた sora_client の値がそのまま入ってきます - version- オプションです - クライアントから送られてきた Sora SDK またはクライアントのバージョンが入ってきます - commit_short- オプションです - クライアントから送られてきた Sora SDK のコミットハッシュが入ってきます - environment- オプションです - クライアントから送られてきた端末情報が入ってきます - libwebrtc- オプションです - クライアントから送られてきた libwebrtc のバージョン情報が入ってきます ## 認証成功時のレスポンス JSON 認証に成功した場合は、以下の JSON を 200 番台で返してください。 ```javascript { "allowed": true } ``` Sora は "allowed" が true の場合は認証を成功と判断して処理をします。 ### 認証成功時の払い出し項目 認証成功時に様々な項目を払い出すことができます。 詳細は [認証ウェブフック成功時の払い出し](AUTH_WEBHOOK_RETURN.html) をご確認ください。 ## 認証失敗時のレスポンス JSON 認証に失敗した場合は、以下の JSON を返してください。 ```javascript { "allowed": false, "reason": "" } ``` > **注釈** > > 認証失敗の場合も HTTP レスポンスのステータスコードは 200 番台である必要があります Sora は `"allowed"` が `false` で、 `"reason"` が含まれている場合に認証失敗と判断して処理します。 `"reason"` は必須です、何かしらエラー理由を **100 バイト以内** の文字列を指定してください。 認証に失敗した場合、認証サーバーから送られてきた "reason" の内容は文字列としてクライアントに送られます。 ``` "<認証サーバーから送られてきた reason>" ``` ## 認証ウェブフック成功時の払い出し 認証サーバーは認証成功時に様々な値を出すことができます。 ```javascript { "allowed": true, "event_metadata": { "pk": 1 } } ``` 詳細は [認証ウェブフック成功時の払い出し](AUTH_WEBHOOK_RETURN.html) をご確認ください。 ## 認証ウェブフックログ `sora.conf` の [auth_webhook_log](SORA_CONF.html#116686) を `true` にしている場合は `log/auth_webhook.jsonl` が出力されます。 > **重要** > > `auth_webhook_log` はデフォルトで `true` です。 このログには認証ウェブフックのリクエストとレスポンス、ウェブフック URL、タイムスタンプが含まれます。 - req- 認証ウェブフックの送信リクエストがそのまま入ります - res- 認証ウェブフックの戻り値がそのまま入ります - url- auth_webhook_url を指定していない場合はログに含まれません - timestamp- RFC3339 フォーマットのタイムスタンプが入ります - UTC です ### auth_webhook_url あり / レスポンスあり ```javascript { "req": { "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": "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": "2023.2.0" }, "spotlight": false, "timestamp": "2020-12-07T09:16:54.079650Z", "version": "2023.2.0", "video": true, "video_bit_rate": 1000, "video_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 がありません ```javascript { "req": { "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": "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": "2023.2.0" }, "spotlight": false, "timestamp": "2020-12-07T06:30:56.240917Z", "version": "2023.2.0", "video": true, "video_bit_rate": 1000, "video_codec_type": "VP9" }, "timestamp": "2020-12-07T06:30:56.252785Z", "url": "http://127.0.0.1:3001/sora/authn/webhook" } ``` ### auth_webhook_url なし - url がありません ```javascript { "req": { "audio": true, "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": "2023.2.0" }, "spotlight": false, "timestamp": "2020-12-07T06:26:58.916204Z", "version": "2023.2.0", "video": true, "video_bit_rate": 1000, "video_codec_type": "VP9" }, "res": { "allowed": true }, "timestamp": "2020-12-07T06:26:58.916242Z" } ``` ## エラーメッセージ これらエラーメッセージは sora.jsonl に出力されます。 ### AUTH_WEBHOOK_RESPONSE_UNEXPECTED_STATUS_CODE 認証サーバーが返すステータスコードが 200 系ではなかった場合に出力されます。 例えばステータスコードが 400 だと出力されます。 ### INVALID_AUTH_WEBHOOK_RESPONSE_JSON 認証サーバーが返す JSON に必須で項目が含まれていない場合に出力されます。 例えば `allowed` が含まれていない場合に出力されます。 ### AUTH-WEBHOOK-RESPONSE-BAD-JSON 認証サーバーが返す JSON のデコードに失敗した場合に出力されます。 例えば `{"a: b"}` といったような JSON と判断できない場合に出力されます。 ## シーケンス図 ### 認証成功 ```mermaid sequenceDiagram autonumber participant C as クライアント participant S as Sora participant A as アプリケーションサーバー C->>+S: "type": "connect" S->>+A: 認証ウェブフック A-->>-S: 200OK
{"allowed": true} S-->>-C: "type": "offer" C->>S: "type": "answer" note over C,A: WebRTC 確立 ``` ### 認証拒否 ```mermaid sequenceDiagram autonumber participant C as クライアント participant S as Sora participant A as アプリケーションサーバー C->>+S: "type": "connect" S->>+A: 認証ウェブフック A-->>-S: 200OK
{"allowed": false, "reason": "reject"} S->>C: WebSocket Close
{"reason": "reject"} ``` # 認証ウェブフック成功時の払い出し ## 概要 Sora では認証ウェブフック成功時に様々な値を外部の認証サーバーから払い出すことができます。 Sora は払い出された値を反映した状態でクライアントへの接続要求 `("type": "offer")` を送ります。 ## 範囲表記 `2..10` と書いてある場合 2 以上、10 以下の値を指定できることを表しています。 ## audio の払い出し クライアントが指定してきた音声のコーデックやビットレートなどのパラメーターに対して、 認証サーバー側で新たに値を払い出すことで、上書きを行えます。 クライアントが指定してきた値を上書きできるため、 サーバー側でそれぞれのクライアントに対して、音声のコーデックやビットレートをコントロールできます。 ### 払い出し例 この機能を使用する場合は、認証成功時のレスポンス JSON に `audio` や `audio_codec_type` や `audio_bit_rate` を指定してください。 ここで使用できるのはシグナリングの `"type": "connect"` 時に指定できる `audio` の値です。 ```javascript { "allowed": true, "audio": true, "audio_codec_type": "OPUS", "audio_bit_rate": 64 } ``` #### 指定できる値 - audio- `true` または `false` または object が指定できます > **注意** > > audio_codec_type や audio_bit_rate 等の audio 関連のパラメーターを指定する場合は、あわせて `audio` に `true` を指定する必要があります - audio_codec_type- "OPUS" - codec_type を指定しないこともできます - audio_bit_rate- 6..510 - 単位は kbps です - **デフォルトで最適なビットレートが選択されるようになっているため指定する必要はありません** - audio_opus_params- [オーディオの Opus 設定指定](SIGNALING.html#c82100) をオブジェクトとして指定できます- [オーディオの Opus 設定指定](SIGNALING.html#c82100) の `opus_params` を `audio_opus_params` に変更して指定してください - audio_lyra_params- [オーディオの Lyra 設定指定](SIGNALING.html#ba1209) をオブジェクトとして指定できます- [オーディオの Lyra 設定指定](SIGNALING.html#ba1209) の `lyra_params` を `audio_lyra_params` に変更して指定してください ## video の払い出し クライアントが指定してきた映像のコーデックやビットレートなどのパラメーターに対して、 認証サーバー側で新たに値を払い出すことで、上書きを行えます。 クライアントが指定してきた値を上書きできるため、 サーバー側でそれぞれのクライアントに対して、映像のコーデックやビットレートを指定できます。 ### 払い出し例 この機能を使用する場合は、認証成功時のレスポンス JSON に `video` や `video_codec_type` や `video_bit_rate` を指定してください。 ここで使用できるのはシグナリングの `"type": "connect"` 時に指定できる `video` の値です。 ```javascript { "allowed": true, "video": true, "video_codec_type": "VP9", "video_bit_rate": 1000 } ``` #### 指定できる値 - "video"- true または false または object が指定できます > **注意** > > video_codec_type や video_bit_rate 等の video 関連のパラメーターを指定する場合は、あわせて `video` に `true` を指定する必要があります - "video_codec_type"- この項目を指定する場合は `"video": true` をあわせて指定してください - 文字列で指定できます - "VP8" - "VP9" - "AV1" - "H264" - "H265"- `sora.conf` にて [h265](SORA_CONF.html#2e0d28) を `true` にしている必要があります - codec_type を指定しないこともできます - "video_bit_rate"- 1..30000- サポートされている値は 1..15000 です - 単位は kbps です - video_bit_rate を指定しないこともできます - video_vp9_params- [ビデオの VP9 設定指定](SIGNALING.html#b7556a) をオブジェクトとして指定できます- [ビデオの VP9 設定指定](SIGNALING.html#b7556a) の `vp9_params` を `video_vp9_params` に変更して指定してください - video_av1_params- [ビデオの AV1 設定指定](SIGNALING.html#48f92d) をオブジェクトとして指定できます- [ビデオの AV1 設定指定](SIGNALING.html#48f92d) の `av1_params` を `video_av1_params` に変更して指定してください - video_h264_params- [ビデオの H.264 設定指定](SIGNALING.html#ffc4cb) をオブジェクトとして指定できます- [ビデオの H.264 設定指定](SIGNALING.html#ffc4cb) の `h264_params` を `video_h264_params` に変更して指定してください - video_h265_params- [ビデオの H.265 設定指定](SIGNALING.html#bfe45b) をオブジェクトとして指定できます- [ビデオの H.265 設定指定](SIGNALING.html#bfe45b) の `h265_params` を `video_h265_params` に変更して指定してください ## client_id の払い出し Sora は認証成功時の戻り値に `client_id` を認証サーバーから返すことができます。 シグナリング接続時にも、 認証成功時の戻り値にも `client_id` を指定しない場合は `connection_id` と同じ値が `client_id` に割りあてられます。 ```javascript { "allowed": true, "client_id": "spam" } ``` - client_id- 1 から 255 の長さの文字列 ## bundle_id の払い出し Sora は認証成功時の戻り値に `bundle_id` を認証サーバーから返すことができます。 `bundle_id` を指定した場合、マルチストリーム利用時に `bundle_id` の値が同じ接続からの音声や映像、メッセージング、シグナリング通知を受信しなくなります。 シグナリング接続時にも、 認証成功時の戻り値にも `bundle_id` を指定しない場合は `connection_id` と同じ値が `bundle_id` に割りあてられます。 ```javascript { "allowed": true, "bundle_id": "spam" } ``` - bundle_id- 1 から 255 バイトの文字列 ## simulcast / simulcast_rid の払い出し Sora は、認証成功時のタイミングで接続単位での `simulcast` と `simulcast_rid` の値を認証サーバーから払い出すことができます。 ```javascript { "allowed": true, "simulcast": true } ``` ```javascript { "allowed": true, "simulcast": true, "simulcast_rid": "r0" } ``` この値は `sora.conf` の `default_simulcast_rid` の値を上書きします。 ## simulcast_encodings の払い出し Sora は、認証成功時のタイミングで接続単位での `simulcast_encodings` の値を認証サーバーから払い出すことができます。 ```javascript { "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#6c680e) をご確認ください。 ## spotlight_encodings の払い出し Sora は、認証成功時のタイミングで接続単位での `spotlight_encodings` の値を認証サーバーから払い出すことができます。 ```javascript { "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#6c680e) をご確認ください。 ## spotlight / spotlight_number の払い出し Sora は、認証成功時のタイミングで接続単位での `spotlight` と `spotlight_number` の値を認証サーバーから払い出すことができます。 ```javascript { "allowed": true, "spotlight": true } ``` ```javascript { "allowed": true, "spotlight": true, "spotlight_number": 3 } ``` ## data_channel_signaling の払い出し Sora は、認証成功時のタイミングで接続単位での `data_channel_signaling` の値を認証サーバーから払い出すことができます。 ```javascript { "allowed": true, "data_channel_signaling": true } ``` この値は `"type": "connect"` の `data_channel_signaling` や `sora.conf` の [default_data_channel_signaling](SORA_CONF.html#adceef) の値を上書きします。 ### 認証成功時にクライアントが受け取る JSON ```javascript { "type": "offer", "sdp": "", "data_channel_signaling": true, "ignore_disconnect_websocket": false } ``` ## ignore_disconnect_websocket の払い出し Sora は、認証成功時のタイミングで接続単位での `ignore_disconnect_websocket` の値を認証サーバーから払い出すことができます。 ```javascript { "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` も送られます。 ```javascript { "type": "switched", "ignore_disconnect_websocket": "", } ``` ## data_channels の払い出し Sora は、認証成功時のタイミングで接続単位での `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" } ] } ``` `data_channels` の詳細仕様は [data_channels 仕様](MESSAGING.html#ad1989) をご確認ください。 ## metadata の払い出し Sora は、認証成功時のタイミングで `metadata` という値を認証サーバーから払い出すことができます。 ```javascript { "allowed": true, "metadata": {"spam": "egg"} } ``` 認証サーバーが認証成功時に `metadata` を含めた場合、クライアントへ送る `"type": "offer"` に `metadata` をそのまま送ります。 この機能を使うことで、認証成功のタイミングでユーザー毎に任意の値を送ることができます。 ### 認証成功時にクライアントが受け取る JSON 認証成功の場合は Offer 送信時の JSON に `metadata` が含められます。 ```javascript { "type": "offer", "sdp": "", "metadata": {"spam": "egg"} } ``` ## event_metadata の払い出し **event_metadata はクライアントには送られません** Sora は、認証成功時のタイミングで `event_metadata` という値を認証サーバーから払い出すことができます。 認証サーバーが認証成功時に `event_metadata` を含めた場合、 イベントウェブフックリクエスト送信時に `event_metadata` という項目が追加されます。 ```javascript { "allowed": true, "event_metadata": {"pk": 1} } ``` `event_metadata` はクライアントに知られることのない値です。 Sora イベントウェブフックリクエスト送信先のサーバーのみが知り得る値となります。 ### 使用例 この `event_metadata` の値は、クライアントに知られることはありません。そのためユーザー ID を直接入れておくという仕組みも使用できます。 こうすることで通知の際、サーバー側がユーザーの判定をしやすくなります。 ## シグナリング経由での通知機能の払い出し Sora は、認証成功時のタイミングで `signaling_notify` という値を認証サーバーから払い出すことができます。 ```javascript { "allowed": true, "signaling_notify": true } ``` `signaling_notify` の値を返すことで、クライアントごとにシグナリング通知を受け取るかどうかを指定できるようになります。 シグナリング経由での通知機能の詳細は ["type": "notify"](SIGNALING.html#c4828f) をご確認ください ### シグナリング経由での通知機能を利用したメタデータの払い出し Sora は、認証成功時のタイミングで `signaling_notify_metadata` という値を認証サーバーから払い出すことができます。 ここに値を指定することで、参加時や離脱時に外の参加者に情報を通知できます。 ```javascript { "allowed": true, "signaling_notify_metadata": { "username": "spam" } } ``` 詳細は [signaling_notify_metadata](SORA_CONF.html#2d9340) をご確認ください。 ## シグナリング通知メタデータ拡張機能の初期値払い出し Sora は、認証成功時のタイミングで `signaling_notify_metadata_ext` という値を認証サーバーから払い出すことができます。 払い出しを利用する場合はシグナリング通知メタデータ拡張が有効である必要があります。 払い出した値がシグナリング通知メタデータ拡張の初期値として使用されます。 ```javascript { "allowed": true, "signaling_notify_metadata_ext": { "mute": true } } ``` ## 録画ブロックの払い出し > **重要** > > 録画ブロック機能は新しい録画機能(セッション単位)でのみ利用できます。 Sora は、認証成功時のタイミングで `recording_block` という値を認証サーバーから払い出すことができます。 ここに `true` を設定することで、録画有効時にその接続の録画をブロックすることができます。 録画がブロックされた接続の録画ファイルは出力されません。 未指定の場合は `recording_block` は `false` として扱われます。 ```javascript { "allowed": true, "recording_block": true } ``` ## ipv4_address と ipv6_address の払い出し Sora は、認証成功時のタイミングで `ipv4_address` または `ipv6_address` を認証サーバーから払い出すことができます。 `ipv4_address` と `ipv6_address` は片方だけでも、両方返しても問題ありません。 ```javascript { "allowed": true, "ipv4_address": "192.0.2.10", "ipv6_address": "2001:0DB8::10" } ``` この値は SDP の offer 時の a=candidate と TURN-UDP と TURN-TCP の URL の払い出しに使用されます。 `sora.conf` の [ipv4_address](SORA_CONF.html#04becc) と [ipv6_address](SORA_CONF.html#30f40f) のがこの戻り値で上書きされます。 指定する IP アドレスを間違えると繋がらなくなるため、使用には注意してください。 この機能を使用することでクライアント毎に経路を指定できます。 ## turn_fqdn 払い出し Sora は、認証成功時のタイミングで接続単位での `turn_fqdn` の値を認証サーバーから払い出すことができます。 ```javascript { "allowed": true, "turn_fqdn": "sora-turn.example.com" } ``` この値は `sora.conf` の [turn_fqdn](SORA_CONF.html#6513e4) の値を上書きします。 指定する FQDN を間違えると繋がらなくなるため、使用には注意してください。 ## turn_tls_fqdn の 払い出し Sora は、認証成功時のタイミングで接続単位での `turn_tls_fqdn` の値を認証サーバーから払い出すことができます。 ```javascript { "allowed": true, "turn_tls_fqdn": "sora-turn.example.com" } ``` この値は sora.conf の `turn_tls_fqdn` の値を上書きします。指定する FQDN を間違えると繋がらなくなるため、使用には注意してください。 この機能は `sora.conf` の [turn_tls_fqdn](SORA_CONF.html#3bfd30) の値を上書きします。 ## user_agent_stats の払い出し Sora は、認証成功時のタイミングで接続単位での `user_agent_stats` の値を認証サーバーから払い出すことができます。 ```javascript { "allowed": true, "user_agent_stats": true } ``` この値は `sora.conf` の [user_agent_stats](SORA_CONF.html#b8b6ef) の値を上書きします。 ## audio_streaming_language_code の払い出し Sora は、認証成功時のタイミングで音声ストリーミングのランゲージコードの値を認証サーバーから払い出すことができます。 ```javascript { "allowed": true, "audio_streaming_language_code": "ja-JP" } ``` この値は接続時の `audio_streaming_language_code` と `sora.conf` の [default_audio_streaming_language_code](SORA_CONF.html#856531) の値を上書きします。 ## stats_exporter の払い出し Sora は、認証成功時のタイミングで統計エクスポートをするかどうかの値を認証サーバから払い出すことができます。 ```javascript { "allowed": true, "stats_exporter": false } ``` この値は `sora.conf` の [default_stats_exporter](STATS_EXPORTER.html#010de6) の値を上書きします。 ## h264_profile_level_id の払い出し > **注意** > > この機能は 2024 年 6 月リリース予定の Sora で廃止されます。 > `"video_h264_params": {"profile_level_id": "42e01f"}` を使用してください。 Sora は、認証成功時のタイミングで接続単位での `h264_profile_level_id` の値を認証サーバーから払い出すことができます。 ```javascript { "allowed": true, "h264_profile_level_id": "42e01f" } ``` この値は `sora.conf` の [default_h264_profile_level_id](SORA_CONF.html#8a25f5) の値を上書きします。 ## turn_tcp_only / turn_tls_only の払い出し > **重要** > > この設定は検証時のみ利用してください。 Sora は、認証成功時のタイミングで接続単位での `turn_tcp_only` または `turn_tls_only` の値を認証サーバーから払い出すことができます。 ```javascript { "allowed": true, "turn_tcp_only": true } ``` ```javascript { "allowed": true, "turn_tls_only": true } ``` この値は `sora.conf` の [turn_tcp_only](SORA_CONF.html#479c51) や [turn_tls_only](SORA_CONF.html#58d702) の値を上書きします。 ## rtp_packet_loss_simulator_incoming / rtp_packet_loss_simulator_outgoing の払い出し > **重要** > > この設定は検証時のみ利用してください。 **範囲**: 0..100 Sora は、認証成功時のタイミングで接続単位での RTP パケットロスシミュレーターの値を認証サーバーから払い出すことができます。 ```javascript { "allowed": true, "rtp_packet_loss_simulator_outgoing": 5 } ``` ```javascript { "allowed": true, "rtp_packet_loss_simulator_incoming": 5 } ``` この値は `sora.conf` の [rtp_packet_loss_simulator_incoming](SORA_CONF.html#5c9058) や [rtp_packet_loss_simulator_outgoing](SORA_CONF.html#1206b6) の値を上書きします。 ## シーケンス図 ```mermaid sequenceDiagram participant C as クライアント participant S as Sora participant A as アプリケーションサーバー C->>+S: "type": "connect" S->>+A: 認証ウェブフック note right of A: ここで払い出しする A-->>-S: 200 OK
"allowed": true S-)-C: "type": "offer" C-)S: "type": "answer" note over C,S: ICE 確立 note over C,S: DTLS 確立 note over C,S: WebRTC 確立 ``` # セッションウェブフック ## 概要 セッションウェブフックは、セッションの状態を送信するウェブフックです。 例えばチャネルに誰も接続していない状態で新しく接続されたタイミングや、 誰も接続しない状態が一定時間続いたタイミングで、 ウェブフックを利用してセッションの状態などを HTTP リクエストで送信する機能です。 また、セッション開始時にウェブフックの戻り値で音声ストリーミングや録画開始などを指定することができ、 今まで API を叩いていた処理をウェブフックで行うことができるようになります。 ## 目的 セッションは実際にチャネルに参加しているクライアントの集まりです。 もともと Sora にはチャネルを作るという概念がありません。 チャネルに誰も接続していない状態で、新しく接続があれば、チャネルが利用されている状態になります。 そのため、チャネルが利用されているかどうかの判断は HTTP API を利用したり、 イベントウェブフックリクエストの送信を利用したりして、アプリケーション側で判断する必要がありました。 このセッションウェブフックは、新しくチャネルに状態を持たせ、 その状態をウェブフックリクエストで送信することで、API やイベントウェブフックを利用せずに、 チャネルの状態を判断することができるようになります。 ## セッション ID 特定の期間チャネルに接続していたクライアントをグルーピングするために、 Sora はセッション ID という値を払い出します。 セッション ID は Sora が指定するため、書き換えることはできません。 セッション ID は UUIDv4 を Base32 でエンコードした 26 バイトの文字列です。 ## HTTP ヘッダー > **警告** > > この機能は [実験的機能](EXPERIMENTAL.html) のため、正式版では仕様が変更される可能性があります > **注釈** > > JSON のパース時の判断などに利用してください。 ### sora-session-webhook-type > **注意** > > `x-sora-session-webhook-type` は非推奨です、 `sora-session-webhook-type` を利用してください セッションウェブフックの HTTP ヘッダー に `sora-session-webhook-type` または `x-sora-session-webhook-type` というヘッダー名でセッションウェブフックのタイプが入ってきます。 `type` が `session.created` の場合は `sora-session-webhook-type: session.created` または `x-sora-session-webhook-type: session.created` のように値が入ってきます。 ### sora-session-id セッションウェブフックの HTTP ヘッダー に `sora-session-id` というヘッダー名でセッション ID が入ってきます。 セッション ID が `46NNAV9S0X3TD778A1JBYYCBS8` の場合は `sora-session-id: 46NNAV9S0X3TD778A1JBYYCBS8` のように値が入ってきます。 ## 設定 ### 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.destroyed` のセッションウェブフックリクエストを送信するまでの時間を指定します。 デフォルトでは 15 秒です。 ```ini session_destroyed_timeout = 15 s ``` ### session_updated_webhook_interval `session.updated` の送信間隔を指定します。 デフォルトでは 1 min (1 分) です。単位は min しか指定できません。 ```ini session_updated_webhook_interval = 1 min ``` ## ログ セッションウェブフックのログは `log/session_webhook.jsonl` に出力されます。 これは `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 - string (RFC3339 UTC マイクロ秒) - セッション生成時間 * - multistream - boolean - マルチストリームが有効かどうか * - spotlight - boolean - スポットライトが有効かどうか * - external_signaling_url - string - (クラスター機能が有効の場合) 接続先の external_signaling_url ```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", "external_signaling_url": "wss://node-01.example.com/signaling", "type": "session.created", "version": "2023.2.0" } ``` ### connections connections に入ってくる以下の二つは RFC3339 形式の時間ではなく `null` が入ってくる場合があります。 - connection_created_timestamp - connection_destroyed_timestamp これは、認証は成功し、セッションに参加はしたが、何らかの理由で WebRTC が確立に失敗した場合発生します。 両方ともの値に null が入ってきます。 ### 戻り値 セッションウェブフックは `"type": "session.created"` の戻り値を指定できます。 #### session_metadata `session_metadata` を指定した場合、セッション更新時の `session.updated` とセッション破棄時の `"type": "session.destroyed"` のウェブフックリクエストに `session_metadata` が含まれます。 ```javascript { "session_metadata": "" } ``` #### recording `recording` を `true` を指定した場合、セッション単位の録画を開始します。 詳細は [録画機能 (セッション単位) の session.created](RECORDING.html#3cec61) をご確認ください。 ```javascript { "recording": true } ``` #### recording_expire_time `recording` が `true` の場合のみ有効です。録画の有効期限を秒単位で指定します。 `recording_expire_time` を `3600` を指定した場合、 3600 秒後に録画は終了します。 詳細は [録画機能 (セッション単位) の session.created](RECORDING.html#3cec61) をご確認ください。 ```javascript { "recording_expire_time": 3600 } ``` #### recording_split_only `recording` が `true` の場合のみ有効です。録画を分割のみで行うかどうかを指定します。 `recording_split_only` を `true` に指定した場合、録画は分割のみで行われます。 詳細は [録画機能 (セッション単位) の session.created](RECORDING.html#3cec61) をご確認ください。 ```javascript { "recording_split_only": true } ``` #### recording_split_duration `recording` が `true` の場合のみ有効です。分割録画の分割時間を秒単位で指定します。 `recording_split_duration` を `60` を指定した場合、 60 秒ごとに録画が分割されます。 詳細は [録画機能 (セッション単位) の session.created](RECORDING.html#3cec61) をご確認ください。 ```javascript { "recording_split_duration": 60 } ``` #### recording_metadata `recording` が `true` の場合のみ有効です。recording.report ウェブフックやレポートファイルに含まれます。 詳細は [録画機能 (セッション単位) の session.created](RECORDING.html#3cec61) をご確認ください。 ```javascript { "recording_metadata": {"spam": "egg"} } ``` #### forwarding_filter `forwarding_filter` を指定した場合、転送フィルターをセッションに対して反映することができます。 転送フィルタールールの詳細については [転送フィルター機能](FORWARDING_FILTER.html) をご確認ください。 ```javascript { "forwarding_filter": { "action": "allow", "rules": [ // チャネルに接続しているすべてのコネクションに音声のみ転送する [ {"field": "kind", "operator": "is_in", "values": ["audio"]} ] ] } } ``` #### audio_streaming `audio_streaming` を `true` に指定した場合、そのセッションで音声ストリーミングが有効になります。 音声ストリーミング機能の詳細については [音声ストリーミング機能](AUDIO_STREAMING.html) をご確認ください。 ```javascript { "audio_streaming": true } ``` #### audio_streaming_auto `audio_streaming_auto` を `true` に指定した場合、そのセッションで音声ストリーミングが有効になり、 かつ自動開始、自動停止機能が有効になります。 この設定を `true` にするときには `audio_streaming` も `true` に設定する必要があります。 詳細は [audio_streaming 関連の払い出し設定の組み合わせによる動作](AUDIO_STREAMING.html#e28478) をご確認ください。 ```javascript { "audio_streaming": true, "audio_streaming_auto": true } ``` ## session.destroyed **セッション破棄** 同時接続数が 0 になったチャネル ID が一定時間経過したタイミングで、 `session.destroyed` ウェブフックリクエストを送信します。 * - キー - 型 - 内容 * - type - string - "session.destroyed" * - 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 - string (RFC3339 UTC マイクロ秒) - セッション生成時間 * - destroyed_time - integer (UNIX 時間) - セッション破棄時間 * - destroyed_timestamp - string (RFC3339 UTC マイクロ秒) - セッション破棄時間 * - multistream - boolean - マルチストリームが有効かどうか * - spotlight - boolean - スポットライトが有効かどうか * - total_connections - integer - 延べ接続数 * - max_connections - integer - 最大同時接続数 * - connections - array (object) - (クラスター機能が無効の場合) セッションに参加した接続情報 * - session_metadata - json - (値がある場合) session.created の戻り値で指定した値 * - external_signaling_url - string - (クラスター機能が有効の場合) 接続先の external_signaling_url * - reason - string - セッションが破棄された理由 ("normal", "terminated_api", "abort") ```javascript { "channel_id": "sora", "connections": [ { "audio": true, "audio_codec_type": "OPUS", "client_id": "W9QE86Z0BS1QFFPZ2QB5DRZ2HC", "bundle_id": "W9QE86Z0BS1QFFPZ2QB5DRZ2HC", "connection_id": "W9QE86Z0BS1QFFPZ2QB5DRZ2HC", "connection_created_timestamp": "2021-12-01T05:44:23.051704Z", "connection_destroyed_timestamp": "2021-12-01T05:44:57.083215Z", "role": "sendrecv", "simulcast": false, "video": true, "video_bit_rate": 1000, "video_codec_type": "VP9", "video_vp9_params": { "profile_id": 0 }, }, { "audio": true, "audio_codec_type": "OPUS", "client_id": "JXMYW6GPX54EH0HGA5X4130FBM", "bundle_id": "JXMYW6GPX54EH0HGA5X4130FBM", "connection_id": "JXMYW6GPX54EH0HGA5X4130FBM", "connection_created_timestamp": "2021-12-01T05:44:21.500272Z", "connection_destroyed_timestamp": "2021-12-01T05:44:56.878019Z", "role": "sendrecv", "simulcast": false, "video": true, "video_bit_rate": 1000, "video_codec_type": "VP9", "video_vp9_params": { "profile_id": 0 }, }, { "audio": true, "audio_codec_type": "OPUS", "client_id": "F8VK9R71BN5S5EDE737C8XAA3C", "bundle_id": "F8VK9R71BN5S5EDE737C8XAA3C", "connection_id": "F8VK9R71BN5S5EDE737C8XAA3C", "connection_created_timestamp": "2021-12-01T05:44:19.811385Z", "connection_destroyed_timestamp": "2021-12-01T05:44:55.897819Z", "role": "sendrecv", "simulcast": false, "video": true, "video_bit_rate": 1000, "video_codec_type": "VP9", "video_vp9_params": { "profile_id": 0 }, }, { "audio": true, "audio_codec_type": "OPUS", "client_id": "VBYS5TV5S510F98GS2VK015AKG", "bundle_id": "VBYS5TV5S510F98GS2VK015AKG", "connection_id": "VBYS5TV5S510F98GS2VK015AKG", "connection_created_timestamp": "2021-12-01T05:44:14.716974Z", "connection_destroyed_timestamp": "2021-12-01T05:44:57.197372Z", "role": "sendrecv", "simulcast": false, "video": true, "video_bit_rate": 1000, "video_codec_type": "VP9", "video_vp9_params": { "profile_id": 0 }, } ], "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, "session_metadata": {"spam": "egg"}, "type": "session.destroyed", "version": "2023.2.0" } ``` ### reason session.destroyed には reason が含まれ、セッションが破棄された理由が入ります。 - `"normal"` は通常のセッション破棄 - `"terminated_api"` は TerminateSession API によるセッション破棄 - `"abort"` は異常発生のセッション破棄 ### クラスター有効時 クラスター有効時には `connections` 項目は含まれません。 ```javascript { "channel_id": "sora", "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", "reason": "normal", "total_connections": 4, "session_metadata": {"spam": "egg"}, "external_signaling_url": "wss://node-01.example.com/signaling", "type": "session.destroyed", "version": "2023.2.0" } ``` ## session.updated **セッション更新** > **注釈** > > このウェブフックリクエストの送信を停止することができます。 > `sora.conf` の [ignore_session_updated_webhook](SORA_CONF.html#0901a0) を `true` にしてください。 `session.created` 送信後、一定間隔で `session.updated` ウェブフックリクエストを送信します。 送信間隔はデフォルトで 1 分です。 [session_updated_webhook_interval](SORA_CONF.html#4612dc) で送信間隔を変更できます。 `session.updated` の状態を記録することで、もし何らかの理由で `session.destroyed` が送信されなかった場合でも、 そのセッションが存在しているかどうかの判断を行う事ができるようになります。 * - キー - 型 - 内容 * - type - string - "session.updated" * - 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 - string (RFC3339 UTC マイクロ秒) - セッション生成時間 * - multistream - boolean - マルチストリームが有効かどうか * - spotlight - boolean - スポットライトが有効かどうか * - total_connections - integer - 延べ接続数 * - max_connections - integer - 最大同時接続数 * - connections - array (object) - (クラスター機能が有効の場合) セッションに参加した接続情報 * - session_metadata - json - (値がある場合) session.created の戻り値で指定した値 * - external_signaling_url - string - (クラスター機能が有効の場合) 接続先の external_signaling_url ```javascript { "channel_id": "sora", "connections": [ { "audio": true, "audio_codec_type": "OPUS", "client_id": "W9QE86Z0BS1QFFPZ2QB5DRZ2HC", "bundle_id": "W9QE86Z0BS1QFFPZ2QB5DRZ2HC", "connection_id": "W9QE86Z0BS1QFFPZ2QB5DRZ2HC", "connection_created_timestamp": "2021-12-01T05:44:23.051704Z", "connection_destroyed_timestamp": "2021-12-01T05:44:57.083215Z", "role": "sendrecv", "simulcast": false, "video": true, "video_bit_rate": 1000, "video_codec_type": "VP9", "video_vp9_params": { "profile_id": 0 }, }, { "audio": true, "audio_codec_type": "OPUS", "client_id": "JXMYW6GPX54EH0HGA5X4130FBM", "bundle_id": "JXMYW6GPX54EH0HGA5X4130FBM", "connection_id": "JXMYW6GPX54EH0HGA5X4130FBM", "connection_created_timestamp": "2021-12-01T05:44:21.500272Z", "connection_destroyed_timestamp": "2021-12-01T05:44:56.878019Z", "role": "sendrecv", "simulcast": false, "video": true, "video_bit_rate": 1000, "video_codec_type": "VP9", "video_vp9_params": { "profile_id": 0 }, }, { "audio": true, "audio_codec_type": "OPUS", "client_id": "F8VK9R71BN5S5EDE737C8XAA3C", "bundle_id": "F8VK9R71BN5S5EDE737C8XAA3C", "connection_id": "F8VK9R71BN5S5EDE737C8XAA3C", "connection_created_timestamp": "2021-12-01T05:44:19.811385Z", "connection_destroyed_timestamp": "2021-12-01T05:44:55.897819Z", "role": "sendrecv", "simulcast": false, "video": true, "video_bit_rate": 1000, "video_codec_type": "VP9", "video_vp9_params": { "profile_id": 0 }, }, { "audio": true, "audio_codec_type": "OPUS", "client_id": "VBYS5TV5S510F98GS2VK015AKG", "bundle_id": "VBYS5TV5S510F98GS2VK015AKG", "connection_id": "VBYS5TV5S510F98GS2VK015AKG", "connection_created_timestamp": "2021-12-01T05:44:14.716974Z", "connection_destroyed_timestamp": "2021-12-01T05:44:57.197372Z", "role": "sendrecv", "simulcast": false, "video": true, "video_bit_rate": 1000, "video_codec_type": "VP9", "video_vp9_params": { "profile_id": 0 }, } ], "created_time": 1638337454, "created_timestamp": "2021-12-01T05:44:14.523736Z", "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, "session_metadata": {"spam": "egg"}, "external_signaling_url": "wss://node-01.example.com/signaling", "type": "session.updated", "version": "2023.2.0" } ``` ### クラスター有効時 クラスター有効時には `connections` 項目は含まれません。 ```javascript { "channel_id": "sora", "created_time": 1638337454, "created_timestamp": "2021-12-01T05:44:14.523736Z", "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, "session_metadata": {"spam": "egg"}, "external_signaling_url": "wss://node-01.example.com/signaling", "type": "session.updated", "version": "2023.2.0" } ``` ### 録画機能 (セッション単位) 有効時 セッションで録画機能 (セッション単位) が有効な場合、 `"recording"` が含まれます。 録画が有効ではない場合は `"recording"` 項目は含まれません。 * - キー - 型 - 内容 * - recording_id - string - 録画機能 (セッション単位) の ID * - recording_metadata (オプション) - JSON Value - 録画機能 (セッション単位) のメタデータ * - split_only - boolean - セッションでの録画が分割のみかどうか * - expire_time (オプション) - integer - セッションでの録画期限 * - expired_at (オプション) - integer - セッションでの録画期限 (Unix time) * - split_duration (オプション) - integer - セッションでの録画分割有効時の分割時間 * - start_timestamp - string - セッションでの録画が開始された時刻 (RFC 3339 (UTC)) ```javascript { "channel_id": "sora", "created_time": 1638337454, "created_timestamp": "2021-12-01T05:44:14.523736Z", "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, "session_metadata": {"spam": "egg"}, "external_signaling_url": "wss://node-01.example.com/signaling", "type": "session.destroyed", "version": "2023.2.0", "recording": { "recording_id": "WHEJ888HQ55KDCFE3TZ4VPFQHR", "recording_metadata": {"spam": "egg"}, "expire_time": 3600, "expired_at": 1615527737, "split_duration": 3600, "split_only": false, "start_timestamp": "2021-03-12T04:42:17.455668Z" } } ``` ## session.vanished > **重要** > > このウェブフックリクエストが送信されるには > `sora.conf` の [ignore_session_vanished_webhook](SORA_CONF.html#85718d) が `false` である必要があります。 Sora のモードが `block_new_session` または `block_new_connection` の時に、 すべてのセッションがなくなったタイミングでウェブフックリクエストを送信します。 ```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": "2023.2.0" } ``` ## recording.started > **重要** > > このウェブフックリクエストが送信されるにはセッションベースの録画を利用する必要があります **録画開始** - data.start_timestamp- 録画機能 (セッション単位) を開始したタイムスタンプが入ります - data.expire_time- **この項目はオプションです** - API による開始を行った場合は [StartRecording](API_RECORDING.html#c5b527) API で指定した `expire_time` が入ります - session.created ウェブフックリクエストの戻り値により録画を開始した場合は戻り値 `recording_expire_time` が入ります - 指定していない場合は `expire_time` の項目が入ってきません - data.expired_at- **この項目はオプションです** - API による開始を行った場合は [StartRecording](API_RECORDING.html#c5b527) API で指定した `expire_time` から計算した有効期限 (UNIX Time) が入ります - session.created ウェブフックリクエストの戻り値により録画を開始した場合は戻り値 `recording_expire_time` から計算した有効期限 (UNIX Time) が入ります - `expire_time` を指定していない場合は `expired_at` の項目が入ってきません - data.split_duration- **この項目はオプションです** - API による開始を行った場合は [StartRecording](API_RECORDING.html#c5b527) API で指定した `split_duration` が入ります - session.created ウェブフックリクエストの戻り値により録画を開始した場合は戻り値 `recording_split_duration` が入ります - 指定していない場合は `split_duration` の項目が入ってきません - data.split_only- API による開始を行った場合は [StartRecording](API_RECORDING.html#c5b527) API で指定した `split_only` が入ります - session.created ウェブフックリクエストの戻り値により録画を開始した場合は戻り値 `recording_split_only` が入ります - 指定していない場合は `false` が入ります - data.recording_metadata- **この項目はオプションです** - API による開始を行った場合は [StartRecording](API_RECORDING.html#c5b527) API で指定した `metadata` が入ります - session.created ウェブフックリクエストの戻り値により録画を開始した場合は戻り値 `recording_metadata` が入ります - 指定していない場合は `recording_metadata` の項目が入ってきません ```javascript { "type": "recording.started", "id": "", "version": "", "label": "", "node_name": "", "channel_id": "", "session_id": "", "session_metadata": "", "timestamp": "", "data": { "channel_id": "", "recording_id": "", "recording_metadata": "", "split_only": "", "created_at": "", "expire_time": "", "expired_at": "", "start_timestamp": "", "split_duration": "" } } ``` ## recording.report > **重要** > > このウェブフックリクエストが送信するには、セッションベースの録画を利用する必要があります > **注釈** > > セッションが終了したタイミングでの `recording.report` は `session.destroyed` の **後** に送信されます。 **録画結果報告** - data.archives[].start_time_offset- 録画を開始してから何秒経過した後にこの録画が開始したかを表しています - data.archives[].stop_time_offset- 録画を開始してから何秒経過した後にこの録画が終了したかを表しています - data.recording_metadata- StartRecording API で指定した metadata 、または `session.created` で払い出した `recording_metadata` が入ります - 指定していない場合は `recording_metadata` の項目が入ってきません - data.expired_at- 期限が切れた日時を UNIX Time で返します ### 一括録画時 recording.report ```javascript { "type": "recording.report", "id": "", "version": "", "label": "", "node_name": "", "channel_id": "", "session_id": "", "timestamp": "", "data": { "channel_id": "", "session_id": "", "recording_id": "", "recording_metadata": "", "split_only": "", "split_duration": "", "created_at": "", "expire_time": "", "expired_at": "", "file_path": "", "filename": "", "file_written": "", "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": "" } ], "failed_archives": [ { "label": "", "node_name": "", "client_id": "", "bundle_id": "", "connection_id": "" }, { "label": "", "node_name": "", "client_id": "", "bundle_id": "", "connection_id": "" } ] } } ``` ### 分割録画時 recording.report ```javascript { "type": "recording.report", "id": "", "version": "", "label": "", "node_name": "", "channel_id": "", "session_id": "", "timestamp": "", "data": { "channel_id": "", "session_id": "", "recording_id": "", "recording_metadata": "", "split_only": "", "split_duration": "", "created_at": "", "expire_time": "", "expired_at": "", "file_path": "", "filename": "", "file_written": "", "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": "" } ], "failed_archives": [ { "label": "", "node_name": "", "client_id": "", "bundle_id": "", "connection_id": "" }, { "label": "", "node_name": "", "client_id": "", "bundle_id": "", "connection_id": "" } ] } } ``` ## audio-streaming.started > **重要** > > このウェブフックリクエストが送信されるには > `sora.conf` の [ignore_audio_streaming_webhook](SORA_CONF.html#8f086b) が `false` である必要があります。 以下の 2 つの条件で音声ストリーミングが開始した時にウェブフックリクエストを送信します。 - [StartAudioStreaming](EXPERIMENTAL_API_AUDIO_STREAMING.html#0f1087) API が実行されるか、またはセッションウェブフックで `audio_streaming: true` 払い出されたタイミングでウェブフックリクエストを送信します。 - 音声ストリーミングの [ウェブフック](AUDIO_STREAMING.html#a62cea) を利用時に[SubscribeAudioStreamingResultPush](EXPERIMENTAL_API_AUDIO_STREAMING.html#d26262) API が呼び出される、もしくはクライアントが接続されて、そのチャネルで音声ストリーミングの結果をサブスクライブしているクライアント数が 1 以上になった場合 [session.created](SESSION_WEBHOOK.html#1d1984) よりも必ず **後に** ウェブフックが送信されます。 * - キー - 型 - 内容 * - type - string - "audio-streaming.started" * - 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 - string (RFC3339 UTC マイクロ秒) - セッション生成時間 * - multistream - boolean - マルチストリームが有効かどうか * - spotlight - boolean - スポットライトが有効かどうか * - session_metadata - json - (値がある場合) session.created の戻り値で指定した値 * - external_signaling_url - string - (クラスター機能が有効の場合) 接続先の external_signaling_url * - data - object - 音声ストリーミング固有 data には以下が含まれます。 * - キー - 型 - 内容 * - audio_streaming_auto - boolean - 自動開始/停止が有効かどうか * - audio_streaming_started_timestamp - string (RFC3339 UTC マイクロ秒) - 音声ストリーミングを開始した時間 ```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": "2022-12-01T05:44:14.523912Z", "type": "audio-streaming.started", "version": "2023.2.0", "session_metadata": {"spam": "egg"}, "external_signaling_url": "wss://node-01.example.com/signaling", "data": { "audio_streaming_auto": true, "audio_streaming_started_timestamp": "2021-12-01T05:44:16.523912Z" } } ``` ## audio-streaming.stopped > **重要** > > このウェブフックリクエストが送信されるには > `sora.conf` の [ignore_audio_streaming_webhook](SORA_CONF.html#8f086b) が `false` である必要があります。 以下の 3 つの条件で音声ストリーミングが停止した時にウェブフックリクエストを送信します。 - セッションが終了した場合 - [StopAudioStreaming](EXPERIMENTAL_API_AUDIO_STREAMING.html#bad1bb) API が呼び出す場合 - 音声ストリーミングの [ウェブフック](AUDIO_STREAMING.html#a62cea) を利用時に[UnsubscribeAudioStreamingResultPush](EXPERIMENTAL_API_AUDIO_STREAMING.html#b63656) API が呼び出される、もしくはクライアントが切断されて、そのチャネルで音声ストリーミングの結果をサブスクライブしているクライアント数が 0 になった場合 [session.destroyed](SESSION_WEBHOOK.html#ccb165) よりも必ず **前に** ウェブフックが送信されます。 * - キー - 型 - 内容 * - type - string - "audio-streaming.started" * - 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 - string (RFC3339 UTC マイクロ秒) - セッション生成時間 * - multistream - boolean - マルチストリームが有効かどうか * - spotlight - boolean - スポットライトが有効かどうか * - session_metadata - json - (値がある場合) session.created の戻り値で指定した値 * - external_signaling_url - string - (クラスター機能が有効の場合) 接続先の external_signaling_url * - data - object - 音声ストリーミング固有 data には以下が含まれます。 * - キー - 型 - 内容 * - audio_streaming_auto - boolean - 自動開始/停止が有効かどうか * - audio_streaming_started_timestamp - string (RFC3339 UTC マイクロ秒) - 音声ストリーミングを開始した時間 * - audio_streaming_stopped_timestamp - string (RFC3339 UTC マイクロ秒) - 音声ストリーミングを停止した時間 ```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": "2022-12-01T05:44:14.523912Z", "type": "audio-streaming.stopped", "version": "2023.2.0", "session_metadata": {"spam": "egg"}, "external_signaling_url": "wss://node-01.example.com/signaling", "data": { "audio_streaming_auto": true, "audio_streaming_started_timestamp": "2021-12-01T05:44:16.523912Z", "audio_streaming_stopped_timestamp": "2021-12-01T05:44:16.523912Z" } } ``` ## API ### TerminateSession API セッションを強制的に終了させる API です。 `channel_id` を指定して、セッションを終了させます。 `session_id` を追加で指定することができますが、 `session_id` が見つからない場合はエラーになります。 API 実行中に新規の接続が来た場合、その接続はいったん保留して、セッション破棄後に新規セッションでの接続として扱います。 ## シーケンス図 ```mermaid sequenceDiagram autonumber participant C1 as クライアント1 participant C2 as クライアント2 participant S as Sora participant A as アプリケーションサーバー C1->>S: type: connect S->>+A: 認証ウェブフック A-->>-S: 200 OK S->>+A: セッションウェブフック
type: session.created A-->>-S: 200 OK S->>C1: type: offer C1->>S: type: answer Note over C1,A: クライアント1 WebRTC 確立 S->>+A: イベントウェブフック
type: connection.created A-->>-S: 200 OK C2->>S: type: connect S->>+A: 認証ウェブフック A-->>-S: 200 OK S->>C2: type: offer C2->>S: type: answer Note over C1,A: クライアント2 WebRTC 確立 S->>+A: イベントウェブフック
type: connection.created A-->>-S: 200 OK C1->>S: "type": "disconnect" S->>+A: イベントウェブフック
type: connection.destroyed A-->>-S: 200 OK S->>C1: WebSocket Close Note over C1,A: クライアント1 WebRTC 切断 C2->>S: "type": "disconnect" S->>+A: イベントウェブフック
type: connection.destroyed A-->>-S: 200 OK S->>C2: WebSocket Close Note over C1,A: クライアント2 WebRTC 切断 note right of S: 接続数 0 から 15 秒経過 S->>+A: セッションウェブフック
type: session.destroyed A-->>-S: 200 OK note right of S: セッションがすべて破棄された S->>+A: セッションウェブフック
type: session.vanished A-->>-S: 200 OK ``` ## クラスター時の挙動について ### セッションが存在していたノードで障害が起きた場合でも、 `session.destroyed` は送信されます 別のノードが `session.destroyed` を送信します。その際 `reason` 項目には `abort` が入ります。 `reason` が `abort` の場合、以下の情報が **最新の状態** ではない場合があります。 - `total_connections` - `max_connections` ### セッションが存在していたノードで障害が起きた際、同一ウェブフックが複数回送られる事があります 以下のウェブフックは複数回送られる可能性はあります、その際はウェブフックの `"id"` は同一になります。 - `session.destroyed` - `recording.started` - `recording.report` - `audio-streaming.stopped` # イベントウェブフック ## 概要 Sora は、予め設定しておいた URL に、シグナリングの接続や切断、 録画の終了といった様々なイベントを HTTP リクエストとして送信するウェブフックの機能を持っています。 この機能を使うことで、Sora のイベントをアプリケーション側と簡単に連携できます。 ## 注意 `sora.conf` の [event_webhook_url](SORA_CONF.html#e1a4d2) を有効にしない場合でも `log/event_webhook.jsonl` は生成されます。 ## 設定 ### event_webhook_url **デフォルト**: 未設定 イベントウェブフックリクエスト送信先の URL です。イベントウェブフック機能を利用する場合は指定してください。 この URL には HTTPS の URL を指定することもできます。 HTTPS の URL を指定する場合、リクエスト送信先のアプリケーションについて基本的には正規の認証局から発行された証明書を利用してください。 独自の証明書を利用する場合は [ウェブフックリクエスト送信先のサーバーが自己署名証明書などを利用している場合](WEBHOOK.html#467c4b) をご確認ください。 HTTP のレスポンスは 200 OK 等の 200 番台のステータスコードの必要があります。 ### connection_updated_webhook_interval **デフォルト**: `1 min` イベントウェブフック `connection.updated` の送信間隔を設定します。設定は分単位 (min) のみで行えます。 詳細は [connection_updated_webhook_interval](SORA_CONF.html#e67c3b) をご確認ください。 ### ignore_connection_updated_webhook **デフォルト**: false イベントウェブフック `connection.updated` の送信有無を設定します。 詳細は [ignore_connection_updated_webhook](SORA_CONF.html#f3f12a) をご確認ください。 ## HTTP ヘッダー > **警告** > > この機能は [実験的機能](EXPERIMENTAL.html) のため、正式版では仕様が変更される可能性があります > **注釈** > > JSON のパース時の判断などに利用してください。 ### sora-event-webhook-type > **注意** > > `x-sora-event-webhook-type` は非推奨です、 `sora-event-webhook-type` を利用してください イベントウェブフックの HTTP ヘッダー に `sora-event-webhook-type` と `x-sora-event-webhook-type` というヘッダー名でイベントウェブフックのタイプが入ってきます。 `type` が `connection.created` の場合は `sora-event-webhook-type: connection.created` と `x-sora-event-webhook-type: connection.created` のように値が入ってきます。 ### sora-session-id イベントウェブフックの HTTP ヘッダー に `sora-session-id` というヘッダー名でセッション ID が入ってきます。 セッション ID が `46NNAV9S0X3TD778A1JBYYCBS8` の場合は `sora-session-id: 46NNAV9S0X3TD778A1JBYYCBS8` のように値が入ってきます。 ### sora-connection-id イベントウェブフックの HTTP ヘッダー に `sora-connection-id` というヘッダー名でコネクション ID が入ってきます。 コネクション ID が `7WSWCM0Z2H0614W5PJERR3F5WR` の場合は `sora-connection-id: 7WSWCM0Z2H0614W5PJERR3F5WR` のように値が入ってきます。 ## 接続イベント - `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 のノード名が入ってきます - log_written- イベントウェブフックログの書き込みが成功したかどうかが入ってきます - 書き込みが成功した場合は `true` が入ってきます - 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- `true` または `false` が入ってきます - `false` の場合は `audio` を使用しません - audio_codec_type- **この項目はオプションです** - `audio` が `false` の場合は含まれません - コーデックの種類は `OPUS` または `LYRA` です - audio_bit_rate- **この項目はオプションです** - `audio` が `false` やクライアントが送ってこない場合、含まれません - この設定は `audio_codec_type` が `OPUS` の時のみ有効です - [default_audio_bit_rate](SORA_CONF.html#07627a) に値を指定していた場合はその値が利用されます - 最小が 6 で、最大が 510 です - 単位は `kbps` です - video- `true` または `false` が入ってきます - `false` の場合は `video` を使用しません - video_codec_type- **この項目はオプションです** - `video` が `false` の場合は含まれません - コーデックはクライアントが送ってこない場合はデフォルトで `VP9` が使用されます - コーデックの種類は `VP8`、 `VP9`、 `AV1`、 `H264`、 `H265` です - video_bit_rate- **この項目はオプションです** - `video` が `false` の場合は含まれません - ビットレートはクライアントが送ってこない場合は `sora.conf` の [default_video_bit_rate](SORA_CONF.html#620132) が使用されます - デフォルトは 500 です - 最小が 1 で、最大が 30000 です - 15000 より大きい値は現時点でサポート範囲外です - 単位は `kbps` です - video_vp9_params- **この項目はオプションです** - `video` が `false` の場合は含まれません - 詳細は [ビデオの VP9 設定指定](SIGNALING.html#b7556a) をご確認ください - video_av1_params- **この項目はオプションです** - `video` が `false` の場合は含まれません - 詳細は [ビデオの AV1 設定指定](SIGNALING.html#48f92d) をご確認ください - video_h264_params- **この項目はオプションです** - `video` が `false` の場合は含まれません - 詳細は [ビデオの H.264 設定指定](SIGNALING.html#ffc4cb) をご確認ください - video_h265_params- **この項目はオプションです** - `video` が `false` の場合は含まれません - 詳細は [ビデオの H.265 設定指定](SIGNALING.html#bfe45b) をご確認ください - 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 バイトの文字列です - ice_connection_state- total_checking_duration_ms- ICE 接続の状態が `checking` になった時間の合計 (ミリ秒) です - total_disconnected_duration_ms- ICE 接続の状態が `disconnected` になった時間の合計 (ミリ秒) です - recording_block- 録画(セッション単位)時に録画をブロックするかどうかが入ってきます - `true` であれば録画をブロックします - `false` であれば録画をブロックしません ### connection.created **接続** シグナリングの接続が成功して、WebRTC としての通信が開始できるようになった時の状態を送信します。 - data.channel_connections- 現在そのチャネルに接続しているクライアントの接続数です - 自分は含まれます - data.channel_sendrecv_connections- 現在そのチャネルで送受信している配信者の接続数です - 自分は含まれます - data.channel_sendonly_connections- 現在そのチャネルを送信のみしている配信者の接続数です - 自分は含まれます - data.channel_recvonly_connections- 現在そのチャネルを受信のみしている視聴者の接続数です - 自分は含まれます ```javascript { "type": "connection.created", "channel_id": "", "session_id": "", "client_id": "", "bundle_id": "", "connection_id": "", "timestamp": "", "event_metadata": "", "data": { "ice_connection_state": { "total_checking_duration_ms": "", "total_disconnected_duration_ms": "" }, "recording_block": "", "created_time": "", "created_timestamp": "", "audio": "", "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": "", "video_bit_rate": "", "video_codec_type": "" }, "id": "", "label": "", "node_name": "", "log_written": "", "role": "", "multistream": "", "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 形式 (マイクロ秒) で入ってきます ```javascript { "type": "connection.destroyed", "channel_id": "", "session_id": "", "client_id": "", "bundle_id": "", "connection_id": "", "timestamp": "", "event_metadata": "", "data": { "ice_connection_state": { "total_checking_duration_ms": "", "total_disconnected_duration_ms": "" }, "recording_block": "", "created_time": "", "created_timestamp": "", "destroyed_time": "", "destroyed_timestamp": "", "audio": "", "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": "", "video_bit_rate": "", "video_codec_type": "" }, "id": "", "label": "", "node_name": "", "log_written": "", "role": "", "multistream": "", "simulcast": "", "spotlight": "", "version": "" } ``` ### connection.updated **接続状態更新** > **注釈** > > このウェブフックリクエストの送信を停止することができます。 > `sora.conf` の [ignore_connection_updated_webhook](SORA_CONF.html#f3f12a) を `true` にしてください。 `connection.created` を送信したタイミングから、クライアントごとの接続状態が、それぞれ一定間隔で送信されます。 送信間隔はデフォルトで 1 分です。 [connection_updated_webhook_interval](SORA_CONF.html#e67c3b) で送信間隔を変更できます。 - data.channel_connections- 現在そのチャネルに接続しているクライアントの接続数です - 自分が含まれます - data.channel_sendrecv_connections- 現在そのチャネルで送受信している配信者の接続数です - 自分が含まれます - data.channel_sendonly_connections- 現在そのチャネルを送信のみしている配信者の接続数です - 自分が含まれます - data.channel_recvonly_connections- 現在そのチャネルを受信のみしている視聴者の接続数です - 自分が含まれます ```javascript { "type": "connection.updated", "channel_id": "", "session_id": "", "client_id": "", "bundle_id": "", "connection_id": "", "timestamp": "", "event_metadata": "", "data": { "ice_connection_state": { "total_checking_duration_ms": "", "total_disconnected_duration_ms": "" }, "recording_block": "", "audio": "", "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": "", "video_bit_rate": "", "video_codec_type": "" }, "id": "", "label": "", "node_name": "", "log_written": "", "role": "", "multistream": "", "simulcast": "", "spotlight": "", "version": "" } ``` ### connection.failed **接続失敗** > **重要** > > このイベントを受信する場合は、 `sora.conf` にて [ignore_connection_failed_webhook](SORA_CONF.html#45096a) を無効にする必要があります。 シグナリング接続 **成功前** に失敗や異常が起きたりした場合に送信されます。 シグナリング接続成功後に失敗や異常が起きた場合は、 [connection.destroyed](EVENT_WEBHOOK.html#6c02d0) が送信されます。 ```javascript { "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": "", "node_name": "", "log_written": "", "multistream": "", "simulcast": "", "spotlight": "", "version": "" } ``` ## 録画・録音イベント ### recording.started > **重要** > > このイベントには `event_metadata` は含まれません **録画開始** - data.start_timestamp- [StartRecording](API_LEGACY_RECORDING.html#c5b527) API を実行したタイムスタンプが入ります - data.expire_time- [StartRecording](API_LEGACY_RECORDING.html#c5b527) API で指定した expire_time が入ります - data.expired_at- [StartRecording](API_LEGACY_RECORDING.html#c5b527) API で指定した expire_time から計算した有効期限が入ります - data.split_duration- **この項目はオプションです** - [StartRecording](API_LEGACY_RECORDING.html#c5b527) API で指定した split_duration が入ります - 指定していない場合は `split_duration` の項目が入ってきません - data.split_only- **この項目はオプションです** - [StartRecording](API_LEGACY_RECORDING.html#c5b527) API で指定した split_only が入ります - 指定していない場合は `false` が入ります - data.metadata- **この項目はオプションです** - [StartRecording](API_LEGACY_RECORDING.html#c5b527) API で指定した metadata が入ります - 指定していない場合は `metadata` の項目が入ってきません ```javascript { "type": "recording.started", "id": "", "version": "", "label": "", "node_name": "", "log_written": "", "channel_id": "", "timestamp": "", "data": { "channel_id": "", "recording_id": "", "metadata": "", "split_only": "", "created_at": "", "expire_time": "", "expired_at": "", "start_timestamp": "", "split_duration": "" } } ``` ### recording.report > **重要** > > このイベントには `event_metadata` は含まれません **録画結果報告** - data.archives[].start_time_offset- [StartRecording](API_LEGACY_RECORDING.html#c5b527) API を叩いてから何秒経過した後にこの録画が開始したかを表しています - data.archives[].stop_time_offset- [StartRecording](API_LEGACY_RECORDING.html#c5b527) API を叩いてから何秒経過した後にこの録画が終了したかを表しています - data.metadata- [StartRecording](API_LEGACY_RECORDING.html#c5b527) API で指定した metadata が入ります - 指定していない場合は `metadata` の項目が入ってきません - data.expired_at- 期限が切れた日時を UNIX Time で返します #### 一括録画時 recording.report ```javascript { "type": "recording.report", "id": "", "version": "", "label": "", "node_name": "", "log_written": "", "channel_id": "", "timestamp": "", "data": { "channel_id": "", "recording_id": "", "metadata": "", "split_only": "", "created_at": "", "expire_time": "", "expired_at": "", "file_path": "", "filename": "", "file_written": "", "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": "" } ], "failed_archives": [ { "label": "", "node_name": "", "client_id": "", "bundle_id": "", "connection_id": "" }, { "label": "", "node_name": "", "client_id": "", "bundle_id": "", "connection_id": "" } ] } } ``` #### 分割録画時 recording.report ```javascript { "type": "recording.report", "id": "", "version": "", "label": "", "node_name": "", "log_written": "", "channel_id": "", "timestamp": "", "data": { "channel_id": "", "recording_id": "", "metadata": "", "split_only": "", "split_duration": "", "created_at": "", "expire_time": "", "expired_at": "", "file_path": "", "filename": "", "file_written": "", "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": "" } ], "failed_archives": [ { "label": "", "node_name": "", "client_id": "", "bundle_id": "", "connection_id": "" }, { "label": "", "node_name": "", "client_id": "", "bundle_id": "", "connection_id": "" } ] } } ``` ## 録画・録音保存イベント ### archive.started **録画ファイル保存開始** - data.start_timestamp- この録画が開始された時間 (UTC) を RFC 3339 形式 (マイクロ秒) で表しています ```javascript { "type": "archive.started", "id": "", "version": "", "label": "", "node_name": "", "log_written": "", "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": true, "audio_codec_type": "", "video": true, "video_codec_type": "", "video_bit_rate": "", "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_LEGACY_RECORDING.html#c5b527) API を叩いてから何秒経過した後にこの録画が開始したかを表しています - data.stop_time_offset- [StartRecording](API_LEGACY_RECORDING.html#c5b527) API を叩いてから何秒経過した後にこの録画が終了したかを表しています - data.stats- サポート向けに、録画に使用したパケット情報の統計を格納しています - 内部向け情報のため、予告なく変更されることがあります ```javascript { "type": "archive.available", "id": "", "version": "", "label": "", "node_name": "", "log_written": "", "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": true, "audio_codec_type": "", "video": true, "video_codec_type": "", "video_bit_rate": "", "video_height": "", "video_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- サポート向けに、録画に使用したパケット情報の統計を格納しています - 内部向け情報のため、予告なく変更されることがあります ```javascript { "type": "split-archive.available", "id": "", "version": "", "label": "", "node_name": "", "log_written": "", "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": "", "audio": true, "audio_codec_type": "", "video": true, "video_codec_type": "", "video_bit_rate": "", "video_height": "", "video_width": "", "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- サポート向けに、録画に使用したパケット情報の統計を格納しています - 内部向け情報のため、予告なく変更されることがあります ```javascript { "type": "split-archive.end", "id": "", "version": "", "label": "", "node_name": "", "log_written": "", "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": "", "audio": true, "audio_codec_type": "", "video": true, "video_codec_type": "", "video_bit_rate": "", "file_path": "", "filename": "", "stats": {}, "start_time": "", "start_time_offset": "", "start_timestamp": "", "stop_time": "", "stop_time_offset": "", "stop_timestamp": "", } } ``` ### archive.failed **録画ファイル保存失敗** ```javascript { "type": "archive.failed", "id": "", "version": "", "label": "", "node_name": "", "log_written": "", "timestamp": "", "channel_id": "", "session_id": "", "client_id": "", "bundle_id": "", "connection_id": "", "event_metadata": "", "data": { "recording_id": "", "session_id": "", "file_path": "", "filename": "", "audio": true, "audio_codec_type": "", "video": true, "video_codec_type": "", "video_bit_rate": "", "video_height": "", "video_width": "", "stats": {}, "start_time": "", "start_timestamp": "", "stop_time": "", "stop_timestamp": "", } } ``` ## スポットライト機能 ### spotlight.focused **フォーカス設定** フォーカスされた際にウェブフックが飛びます。 ```javascript { "type": "spotlight.focused", "channel_id": "", "client_id": "", "bundle_id": "", "connection_id": "", "timestamp": "", "spotlight_number:": "", "fixed": "", "id": "", "label": "", "version": "", "node_name": "", "log_written": "", "audio": "", "video": "" } ``` ### spotlight.unfocused **フォーカス解除** フォーカスが外れた際にウェブフックが飛びます。 ```javascript { "type": "spotlight.unfocused", "channel_id": "", "client_id": "", "bundle_id": "", "connection_id": "", "timestamp": "", "spotlight_number:": "", "audio": "", "id": "", "label": "", "version": "", "node_name": "", "log_written": "", "audio": "", "video": "" } ``` ## シーケンス図 ### connection.* ```mermaid sequenceDiagram participant C as クライアント participant S as WebRTC SFU S participant A as アプリケーションサーバー note over C,A: 認証成功 S->>C: "type": "offer" C->>S: "type": "answer" note over C,S: WebRTC 確立 S->>+A: イベントウェブフック
"type": "connection.created" A-->>-S: 200 OK note over C,S: 接続から 1 分経過 S->>+A: イベントウェブフック
"type": "connection.updated" A-->>-S: 200 OK C->>S: "type": "disconnect" S->>+A: イベントウェブフック
"type": "connection.destroyed" A-->-S: 200 OK S->>C: WebSocket Close ``` ### event_metadata ```mermaid sequenceDiagram participant C as クライアント participant S as WebRTC SFU S participant A as アプリケーションサーバー C->>+S: "type": "connect" S->>+A: 認証ウェブフック A-->>-S: 200 OK
"allowed: true,
"event_metadata": {"pk": 1} S->>C: "type": "offer" C->>S: "type": "answer" note over C,S: WebRTC 確立 S->>+A: イベントウェブフック
"type": "connection.created",
"event_metadata": {"pk": 1} A-->>-S: 200 OK note over C,S: 接続から 1 分経過 S->>+A: イベントウェブフック
"type": "connection.updated",
"event_metadata": {"pk": 1} A-->>-S: 200 OK C->>S: "type": "disconnect" S->>+A: イベントウェブフック
"type": "connection.destroyed",
"event_metadata": {"pk": 1} A-->-S: 200 OK S->>C: 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; vp9_params?: VP9Params; av1_params?: AV1Params; h264_params?: H264Params; h265_params?: H265Params; }; type VP9Params = { // 0..3 profile_id?: number; }; type AV1Params = { // 0..2 profile?: number; }; type H264Params = { profile_level_id?: string; }; type H265Params = { level_id?: 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; }; type ForwardingFilterRuleField = "connection_id" | "client_id" | "kind"; type ForwardingFilterRuleOperator = "is_in" | "is_not_in"; type ForwardingFilterRuleKindValue = "audio" | "video"; type ForwardingFilterRule = { field: ForwardingFilterRuleField; operator: ForwardingFilterRuleOperator; values: [string]; }; type ForwardingFilterAction = "block" | "allow"; type ForwardingFilter = { version?: string; metadata?: JSONValue; action?: ForwardingFilterAction; rules: [[ForwardingFilterRule]]; }; // SoraClient type SoraClient = { environment?: string; raw?: string; type?: string; version?: string; commit_short?: string; libwebrtc?: string; }; // RTCRtpEncodingParameters // https://w3c.github.io/webrtc-pc/#dom-rtcrtpencodingparameters type SimulcastEncoding = { // https://www.w3.org/TR/webrtc/#dom-rtcrtpcodingparameters-rid rid: SimulcastRid; // https://www.w3.org/TR/webrtc/#dom-rtcrtpencodingparameters-active active?: boolean; // https://www.w3.org/TR/webrtc/#dom-rtcrtpencodingparameters-scaleresolutiondownby scaleResolutionDownBy?: number; // https://www.w3.org/TR/webrtc/#dom-rtcrtpencodingparameters-maxbitrate maxBitrate?: number; // https://w3c.github.io/webrtc-extensions/#dom-rtcrtpencodingparameters-maxframerate maxFramerate?: number; // https://w3c.github.io/webrtc-extensions/#dom-rtcrtpencodingparameters-adaptiveptime adaptivePtime?: boolean; // https://www.w3.org/TR/webrtc-svc/#dom-rtcrtpencodingparameters-scalabilitymode scalabilityMode?: string; }; ``` ## 完全な型定義 ### 認証ウェブフック ```typescript // 認証ウェブフックリクエスト type AuthWebhookRequest = { 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; simulcast_rid?: SimulcastRid; spotlight: boolean; spotlight_focus_rid?: "none" | SimulcastRid; spotlight_unfocus_rid?: "none" | SimulcastRid; audio: boolean; audio_codec_type?: string; audio_bit_rate?: number; video: Video; video_codec_type?: string; video_bit_rate?: number; video_vp9_params?: VP9Params; video_av1_params?: AV1Params; video_h264_params?: H264Params; video_h265_params?: H265Params; data_channel_signaling: boolean; ignore_disconnect_websocket: boolean; data_channels?: [DataChannel]; forwarding_filter?: ForwardingFilter; auth_metadata?: JSONValue; metadata?: JSONValue; whip?: boolean; sora_client?: SoraClient; channel_connections: number; channel_sendrecv_connections: number; channel_sendonly_connections: number; channel_recvonly_connections: number; e2ee: boolean; }; // 認証ウェブフック成功レスポンス // 200 OK で返してください type AuthWebhookAcceptResponse = { allowed: true; audio?: boolean; audio_codec_type?: string; audio_bit_rate?: number; audio_lyra_params?: LyraParams; audio_opus_params?: OpusParams; video?: boolean; video_codec_type?: string; video_bit_rate?: number; video_vp9_params?: VP9Params; video_av1_params?: AV1Params; video_h264_params?: H264Params; video_h265_params?: H265Params; client_id?: string; bundle_id?: string; 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]; data_channel_signaling?: boolean; ignore_disconnect_websocket?: boolean; data_channels?: [DataChannel]; metadata?: JSONValue; event_metadata?: JSONValue; signaling_notify?: boolean; signaling_notify_metadata?: JSONValue; signaling_notify_metadata_ext?: JSONValue; recording_block?: boolean; ipv4_address?: string; ipv6_address?: string; turn_fqdn?: string; turn_tls_fqdn?: string; user_agent_stats?: boolean; stats_exporter?: boolean; audio_streaming_language_code?: string; h264_profile_level_id?: string; turn_tcp_only?: boolean; turn_tls_only?: boolean; rtp_packet_loss_simulator_incoming?: number; rtp_packet_loss_simulator_outgoing?: number; }; // 認証ウェブフック失敗レスポンス // 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; // cluster = true の時のみ含まれる external_signaling_url?: string; channel_id: string; session_id: string; multistream: boolean; spotlight: boolean; created_time: number; created_timestamp: string; }; // 200 OK で返してください type SessionWebhookCreatedResponse = { session_metadata?: JSONValue; forwarding_filter?: ForwardingFilter; audio_streaming?: boolean; audio_streaming_auto?: boolean; recording?: boolean; recording_metadata?: JSONValue; recording_expire_time?: number; recording_split_only?: boolean; recording_split_duration?: number; }; // セッションウェブフック更新リクエスト type SessionWebhookUpdatedRequest = { type: "session.updated"; timestamp: string; id: string; version: string; label: string; node_name: string; // cluster = true の時のみ含まれる external_signaling_url?: string; channel_id: string; session_id: string; multistream: boolean; spotlight: boolean; created_time: number; created_timestamp: string; max_connections: number; total_connections: number; session_metadata?: JSONValue; // 録画機能 (セッション単位) が有効な時のみ recording?: SessionRecording; // クラスター有効の場合は含まれない connections?: [SessionConnection]; }; // セッションウェブフック破棄リクエスト type SessionWebhookDestroyedRequest = { type: "session.destroyed"; timestamp: string; id: string; version: string; label: string; node_name: string; // cluster = true の時のみ含まれる external_signaling_url?: string; channel_id: string; session_id: string; multistream: boolean; spotlight: boolean; created_time: number; created_timestamp: string; destroyed_time: number; destroyed_timestamp: string; reason: "normal" | "terminated_api" | "abort"; max_connections: number; total_connections: number; session_metadata?: JSONValue; // クラスター有効の場合は含まれない connections?: [SessionConnection]; }; type SessionRecording = { recording_id: string; // 未指定の場合は含まれない recording_metadata?: JSONValue; // 未指定の場合は含まれない expire_time?: number; // expire_time が未指定の場合は含まれない expired_at?: number; split_only: boolean; split_duration?: number; start_timestamp: string; }; type SessionConnection = { role: Role; client_id: string; bundle_id: string; connection_id: string; simulcast: boolean; audio: boolean; audio_codec_type?: string; audio_bit_rate?: number; video: boolean; video_codec_type?: string; video_bit_rate?: number; video_vp9_params?: VP9Params; video_av1_params?: AV1Params; video_h264_params?: H264Params; video_h265_params?: H265Params; // 認証は成功したが WebRTC が確立できなかった場合、 null が入ってくる connection_created_timestamp: string | null; // 認証は成功したが WebRTC が確立できなかった場合、 null が入ってくる connection_destroyed_timestamp: string | null; event_metadata?: JSONValue; }; // セッションウェブフック全破棄リクエスト type SessionWebhookVanishedRequest = { type: "session.vanished"; timestamp: string; id: string; version: string; label: string; node_name: string; // cluster = true の時のみ含まれる external_signaling_url?: string; }; // セッションウェブフック音声ストリーミング開始リクエスト type SessionWebhookAudioStreamingStartedRequest = { type: "audio-streaming.started"; timestamp: string; id: string; version: string; label: string; node_name: string; // cluster = true の時のみ含まれる external_signaling_url?: string; channel_id: string; session_id: string; multistream: boolean; spotlight: boolean; created_time: number; created_timestamp: string; session_metadata?: JSONValue; data: AudioStreamingStartedData; }; type AudioStreamingStartedData = { audio_streaming_auto: boolean; audio_streaming_started_timestamp: string; }; // セッションウェブフック音声ストリーミング停止リクエスト type SessionWebhookAudioStreamingStoppedRequest = { type: "audio-streaming.stopped"; timestamp: string; id: string; version: string; label: string; node_name: string; // cluster = true の時のみ含まれる external_signaling_url?: string; channel_id: string; session_id: string; multistream: boolean; spotlight: boolean; created_time: number; created_timestamp: string; session_metadata?: JSONValue; data: AudioStreamingStoppedData; }; type AudioStreamingStoppedData = { audio_streaming_auto: boolean; audio_streaming_started_timestamp: string; audio_streaming_stopped_timestamp: string; }; ``` ### セッションウェブフック (録画) ```typescript type SessionWebhookRecordingStartedRequest = { type: "recording.started"; timestamp: string; id: string; version: string; label: string; node_name: string; channel_id: string; session_id: string; session_metadata?: JSONValue; data: SessionWebhookRecordingStartedData; }; type SessionWebhookRecordingStartedData = { channel_id: string; session_id: string; recording_id: string; recording_metadata?: JSONValue; split_only: boolean; split_duration?: number; created_at: number; expire_time?: number; expired_at?: number; start_timestamp: string; }; type SessionWebhookRecordingReportRequest = { type: "recording.report"; timestamp: string; id: string; version: string; label: string; node_name: string; channel_id: string; session_id: string; session_metadata?: JSONValue; data: SessionWebhookRecordingReportData; }; type SessionWebhookRecordingReportData = { channel_id: string; session_id: string; recording_id: string; recording_metadata?: JSONValue; split_only: boolean; split_duration?: number; created_at: number; expire_time?: number; expired_at?: number; file_path: string; filename: string; file_written: boolean; start_timestamp: string; stop_timestamp: string; archives: [SessionWebhookRecordingReportArchive]; failed_archives: [SessionWebhookRecordingReportFailedArchive]; }; type SessionWebhookRecordingReportArchive = { 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 SessionWebhookRecordingReportFailedArchive = { label: string; node_name: string; client_id: string; bundle_id: string; connection_id: string; }; ``` ### イベントウェブフック ```typescript // イベントコネクション生成ウェブフックリクエスト type EventWebhookConnectionCreatedRequest = { type: "connection.created"; timestamp: string; id: string; log_written: boolean; 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: boolean; audio_codec_type?: AudioCodecType; audio_bit_rate?: number; video: boolean; video_codec_type?: VideoCodecType; video_bit_rate?: number; video_vp9_params?: VP9Params; video_av1_params?: AV1Params; video_h264_params?: H264Params; video_h265_params?: H265Params; recording_block: boolean; 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; ice_connection_state: IceConnectionState; total_received_bytes: number; total_sent_bytes: number; }; // イベントコネクション更新ウェブフックリクエスト type EventWebhookConnectionUpdatedRequest = { type: "connection.updated"; timestamp: string; id: string; log_written: boolean; 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: boolean; audio_codec_type?: AudioCodecType; audio_bit_rate?: number; video: boolean; video_codec_type?: VideoCodecType; video_bit_rate?: number; video_vp9_params?: VP9Params; video_av1_params?: AV1Params; video_h264_params?: H264Params; video_h265_params?: H265Params; recording_block: boolean; 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; ice_connection_state: IceConnectionState; total_received_bytes: number; total_sent_bytes: number; }; // イベントコネクション破棄ウェブフックリクエスト type EventWebhookConnectionDestroyedRequest = { type: "connection.destroyed"; timestamp: string; id: string; log_written: boolean; 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: boolean; audio_codec_type?: AudioCodecType; audio_bit_rate?: number; video: boolean; video_codec_type?: VideoCodecType; video_bit_rate?: number; video_vp9_params?: VP9Params; video_av1_params?: AV1Params; video_h264_params?: H264Params; video_h265_params?: H265Params; recording_block: boolean; 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; ice_connection_state: IceConnectionState; 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; log_written: boolean; 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; }; type IceConnectionState = { total_checking_duration_ms: number; total_disconnected_duration_ms: number; }; ``` ### イベントウェブフック (録画) ```typescript type EventWebhookRecordingStartedRequest = { type: "recording.started"; timestamp: string; id: string; log_written: boolean; 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; split_duration?: number; created_at: number; expire_time: number; expired_at: number; start_timestamp: string; }; type EventWebhookRecordingReportRequest = { type: "recording.report"; timestamp: string; id: string; log_written: boolean; 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; file_written: boolean; start_timestamp: string; stop_timestamp: string; archives: [EventWebhookRecordingReportArchive]; failed_archives: [EventWebhookRecordingReportFailedArchive]; }; 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 EventWebhookRecordingReportFailedArchive = { label: string; node_name: string; client_id: string; bundle_id: string; connection_id: string; }; type EventWebhookArchiveStartedRequest = { type: "archive.started"; timestamp: string; id: string; log_written: boolean; 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 EventWebhookArchiveStartedData = { recording_id: string; channel_id: string; session_id: string; client_id: string; bundle_id: string; connection_id: string; created_at: number; audio: boolean; audio_codec_type?: string; audio_bit_rate?: number; video: boolean; video_codec_type?: string; video_bit_rate?: number; video_vp9_params?: VP9Params; video_av1_params?: AV1Params; video_h264_params?: H264Params; start_time: number; start_time_offset: number; start_timestamp: string; }; type EventWebhookArchiveAvailableRequest = { type: "archive.available"; timestamp: string; id: string; log_written: boolean; 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: boolean; audio_codec_type?: string; audio_bit_rate?: number; video: boolean; video_codec_type?: string; video_bit_rate?: number; video_height?: number; video_width?: number; video_vp9_params?: VP9Params; video_av1_params?: AV1Params; video_h264_params?: H264Params; 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; log_written: boolean; 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: boolean; audio_codec_type?: string; audio_bit_rate?: number; video: boolean; video_codec_type?: string; video_bit_rate?: number; video_height?: number; video_width?: number; video_vp9_params?: VP9Params; video_av1_params?: AV1Params; video_h264_params?: H264Params; 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; log_written: boolean; 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: boolean; audio_codec_type?: string; audio_bit_rate?: number; video: Video; video_codec_type?: string; video_bit_rate?: number; video_vp9_params?: VP9Params; video_av1_params?: AV1Params; video_h264_params?: H264Params; 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; log_written: boolean; 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: boolean; audio_codec_type?: string; audio_bit_rate?: number; video: boolean; video_codec_type?: string; video_bit_rate?: number; video_height?: number; video_width?: number; video_vp9_params?: VP9Params; video_av1_params?: AV1Params; video_h264_params?: H264Params; start_time: number; start_timestamp: string; stop_time: number; stop_timestamp: string; stats: JSONValue; }; ``` ### イベントウェブフック (スポットライト) ```typescript type EventWebhookSpotlightFocusedRequest = { type: "spotlight.focused"; timestamp: string; id: string; log_written: boolean; 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; log_written: boolean; 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 のライブラリを使用しています。 [🥧 HTTPie for Terminal — 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 指定したチャネルの指定したロールの接続を切断します。 **リクエスト JSON** * - キー - 型 * - channel_id - string * - role - string (sendrecv | sendonly | recvonly) * - reason (オプション) - object ```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", "vp9_params": { "profile_id": 0 } } }, { "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", "vp9_params": { "profile_id": 0 } } }, { "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", "vp9_params": { "profile_id": 0 } } } ] ``` ## 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", "vp9_params": { "profile_id": 0 } } }, { "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", "vp9_params": { "profile_id": 0 } } } ] ``` # サイマルキャスト 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 を受信し始めます。 ```console $ 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 ```console $ 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](SORA_CONF.html#ad2156) に指定したディレクトリに置かれます。 ## StartRecording **x-sora-target**: Sora_20231220.StartRecording 指定したチャネルの録画を開始します。 クラスター機能利用時には、クラスター内のどのノードで実行しても開始された録画情報はすべてのノードで共有されます。 * - キー - 型 * - channel_id - string * - expire_time (オプション) - integer * - split_duration (オプション) - integer * - split_only (オプション) - boolean * - metadata (オプション) - object - `expire_time` を指定しない場合は未指定になります- `expire_time` を指定しない場合、録画の期限が無くなります - `expire_time` を指定する範囲は `1` から `86400` までで、秒数を指定してください- 指定できる最大値はデフォルトで `86400` で [recording_max_expire_time](SORA_CONF.html#f3ff8d) に指定した値で変わります - `split_only` は `true` か `false` を指定して下さい。指定しない場合は `false` が指定されます - `split_only` を `true` に指定する場合は `split_duration` を指定する必要があります - `split_duration` を指定する範囲は `1` から `86400` までで、秒数を指定して下さい- 指定できる最大値はデフォルトで `86400` で、 [recording_max_split_duration](SORA_CONF.html#927da9) に指定した値で変わります - `metadata` は JSON オブジェクトを指定してください- この `metadata` は `recording.report` ウェブフックやレポートファイルに `recording_metadata` として含まれるようになります。 ### 一括録画を行いたい場合 - `split_only` を `false` に指定するか、未指定にしてください ### 分割録画を行いたい場合 - `split_only` を `true` に指定してください - `split_duration` を指定してください ### 一括&分割録画を行いたい場合 - `sora.conf` の [recording_dual_output](SORA_CONF.html#4cc9c0) を `true` に指定してください - `split_only` を `false` に指定するか、未指定にしてください - `split_duration` を指定してください ### expire_time が指定無し ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20231220.StartRecording \ channel_id=sora \ -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" } 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, "session_id": "96D7CQDEMS5CHCKDX46REWWTX4", "recording_id": "C0YTCRZM715BKATBXWFPKTYGRM" } ``` ### expire_time が 3600 ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20231220.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, "session_id": "96D7CQDEMS5CHCKDX46REWWTX4", "recording_id": "C0YTCRZM715BKATBXWFPKTYGRM" } ``` ### split_only が true ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20231220.StartRecording \ channel_id=sora \ 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", "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, "session_id": "96D7CQDEMS5CHCKDX46REWWTX4", "recording_id": "MK4J54QBGS4ES0MCSZMF6C9M9M", "split_duration": 3600, "split_only": true } ``` ### エラー - "STARTED-RECORDING"- 指定したチャネル ID で、すでに録画が開始している ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20231220.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_20231220.StopRecording 指定したチャネルの録画を停止します。 この API は非同期です。200 が返ってきた場合でも録画ファイルや録画メタデータファイルが生成されていることを保証しません。 イベントウェブフックの [archive.available](EVENT_WEBHOOK.html#de9132) または [recording.report](SESSION_WEBHOOK.html#920a02) の通知を利用してください。 * - キー - 型 * - channel_id - string ```console $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20231220.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_20231220.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", "session_id": "96D7CQDEMS5CHCKDX46REWWTX4", "recording_id": "C0YTCRZM715BKATBXWFPKTYGRM" } ``` ### エラー - NOT-STARTED-RECORDING- 指定したチャネルの録画が開始されていない - "NOT-CLUSTER-MAJORITY"- クラスターで半数以下のグループに所属している # レガシー録画 API > **注意** > > レガシー録画機能 API は 2025 年 12 月リリースの Sora にて廃止されます。 > 今後は [録画機能 (セッション単位) API](API_RECORDING.html) をご利用ください。 > **重要** > > レガシー録画機能と録画機能 (セッション単位) はチャネル単位で異なる仕組みを同時に利用できます。 > 例えば、channel_id a ではレガシー録画機能、channel_id b では録画機能(セッション単位)のように利用する事ができます。 録画されたファイルは `sora.conf` の [archive_dir](SORA_CONF.html#ad2156) に指定したディレクトリに置かれます。 ## 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` に指定した場合、録画の期限が無くなります - 指定できる最大値はデフォルトで `86400` で [recording_max_expire_time](SORA_CONF.html#f3ff8d) に指定した値で変わります - `split_only` は `true` か `false` を指定して下さい。指定しない場合は `false` が指定されます - `split_only` を `true` に指定する場合は `expire_time` は `0` を指定する必要があります - `split_only` を `true` に指定する場合は `split_duration` を指定する必要があります - `split_duration` を指定する範囲は `1` から `86400` までで、秒数を指定して下さい- 指定できる最大値はデフォルトで `86400` で、 [recording_max_split_duration](SORA_CONF.html#927da9) に指定した値で変わります - `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](SESSION_WEBHOOK.html#920a02) の通知を利用してください。 * - キー - 型 * - 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 録画が有効かどうかを確認します。 * - キー - 型 * - 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, "created_at": 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", "vp9_params": { "profile_id": 0 } } } ] ``` - 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 - 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 を取得した時点の不安定レベル - total_unstable_level0- 不安定レベル 0 の回数 - total_unstable_level1- 不安定レベル 1 の回数 - total_unstable_level2- 不安定レベル 2 の回数 - total_unstable_level3- 不安定レベル 3 の回数 - ice_connection_state- total_connected_req- `connected` 状態での疎通確認用のリクエスト送信回数 - total_connected_ack- `connected` 状態での疎通確認用の応答受信回数 - total_checking_req- `checking` 状態での疎通確認用のリクエスト送信回数 - total_checking_ack- `checking` 状態での疎通確認用の応答受信回数 - total_disconnected_req- `disconnected` 状態での疎通確認用のリクエスト送信回数 - total_disconnected_ack- `disconnected` 状態での疎通確認用の応答受信回数 - total_connected_to_checking- `connected` 状態から `checking` 状態へ遷移した回数 - total_checking_to_disconnected- `checking` 状態から `disconnected` 状態へ遷移した回数 - total_disconnected_to_failed- `disconnected` 状態から `failed` 状態へ遷移した回数 - total_checking_to_connected- `checking` 状態から `connected` 状態へ遷移した回数 - total_disconnected_to_checking- `disconnected` 状態から `checking` 状態へ遷移した回数 - total_checking_duration_ms- `checking` 状態であった時間の合計 - total_disconnected_duration_ms- `disconnected` 状態であった時間の合計 - 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_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_received_sounding_rtp - 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_generic_nack_cache_hit- 再送要求に答えた総数 - total_generic_nack_cache_miss- 再送要求に答えられなかった総数 - total_pli_trigger- 再送要求が限界に来たため全画面要求(PLI) を送信した総数 - 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_allocate_request - total_received_binding_request - total_received_channel_bind_request - total_received_channel_data - total_received_create_permission_request - total_received_expired_channel_number - total_received_invalid_channel_data - total_received_refresh_request - total_received_send_indication - total_received_stun_invalid - total_received_stun_unknown - total_received_turn_binding_error - total_received_turn_binding_request - total_received_turn_binding_success - total_received_turn_invalid_stun - total_received_turn_unknown - total_received_turn_unknown_stun - total_received_unknown_channel_number - total_received_unknown_packet - 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_sctp_zero_checksum- SCTP チェックサムを 0 で受信した総数 - total_sent_sctp_zero_checksum- SCTP チェックサムを 0 で送信した総数 - 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 - cc- bwe_period - congestion_window - delay_based_estimated_bitrate - pacer_data_window - pacer_padding_window - round_trip_time - stable_target_bitrate - target_bitrate ## 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", "cc": { "bwe_period": 0, "congestion_window": 0, "delay_based_estimated_bitrate": 0, "pacer_data_window": 0, "pacer_padding_window": 0, "round_trip_time": 0, "stable_target_bitrate": 0, "target_bitrate": 0 }, "data_channel": { "#test": { "compress": false, "direction": "sendrecv", "ordered": true, "protocol": "", "total_data_channel_abandon_message": 0, "total_data_channel_ack_message": 0, "total_data_channel_open_message": 0, "total_data_channel_retransmit_message": 0, "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_data_channel_abandon_message": 0, "total_data_channel_ack_message": 0, "total_data_channel_open_message": 0, "total_data_channel_retransmit_message": 0, "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_data_channel_abandon_message": 0, "total_data_channel_ack_message": 0, "total_data_channel_open_message": 0, "total_data_channel_retransmit_message": 0, "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_data_channel_abandon_message": 0, "total_data_channel_ack_message": 0, "total_data_channel_open_message": 0, "total_data_channel_retransmit_message": 0, "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_data_channel_abandon_message": 0, "total_data_channel_ack_message": 0, "total_data_channel_open_message": 0, "total_data_channel_retransmit_message": 0, "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_data_channel_abandon_message": 0, "total_data_channel_ack_message": 0, "total_data_channel_open_message": 0, "total_data_channel_retransmit_message": 0, "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 }, "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_decrypt_skipped_audio_srtp": 717, "total_decrypt_skipped_srtp": 1599, "total_decrypt_skipped_video_srtp": 882, "total_received": 5706, "total_received_byte_size": 1879672, "total_received_rtp": 5331, "total_received_rtp_byte_size": 1846412, "total_received_intra_frame": 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": 79, "total_received_sounding_rtp": 0, "total_received_srtp_invalid": 0, "total_sent": 5548, "total_sent_byte_size": 2015913, "total_sent_rtp": 5364, "total_sent_rtp_byte_size": 2001101, "total_ulpfec_recovered": 0 }, "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_sctp_zero_checksum": 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, "total_sent_sctp_zero_checksum": 0 }, "signaling": { "total_received_signaling_pong": 0, "total_sent_signaling_ping": 0 }, "simulcast": { "r0": { "rtp": { "total_decrypt_skipped_srtp": 0, "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_decrypt_skipped_srtp": 0, "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_decrypt_skipped_srtp": 0, "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 }, "ice_connection_state": { "total_checking_ack": 1, "total_checking_duration_ms": 7, "total_checking_req": 1, "total_checking_to_connected": 1, "total_checking_to_disconnected": 0, "total_connected_ack": 12, "total_connected_req": 12, "total_connected_to_checking": 0, "total_disconnected_ack": 0, "total_disconnected_duration_ms": 0, "total_disconnected_req": 0, "total_disconnected_to_checking": 0, "total_disconnected_to_failed": 0 }, "network_status": { "unstable_level": 0, "total_unstable_level0": 2, "total_unstable_level1": 0, "total_unstable_level2": 0, "total_unstable_level3": 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_invalid_channel_data": 0, "total_received_refresh_request": 4, "total_received_send_indication": 3, "total_received_stun_invalid": 0, "total_received_stun_unknown": 0, "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_received_unknown_packet": 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 は実験的機能のため、正式版では仕様が変更される可能性があります。 ### GenerateCrashLog **この API はテスト目的のためだけに利用してください** **x-sora-target**: Sora_20221221.GenerateCrashLog 意図的に Sora のクラッシュログを発生させます。クラッシュログの監視のテストなどに利用してください。 * - キー - 型 * - info - object ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20221221.GenerateCrashLog \ info:='{"spam": "egg"}' \ -vvv ``` ## その他の 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 は [実験的機能](EXPERIMENTAL.html) のため、正式版では仕様が変更される可能性があります。 ## TerminateSession **x-sora-target**: Sora_20230628.TerminateSession 指定したセッションを終了させる API です、そのセッションに接続しているクライアントはすべて切断します。 * - キー - 型 * - channel_id - string * - session_id (オプション) - string ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20230628.TerminateSession \ channel_id=sora \ session_id=JJJ5BFH7QN6DQBTKSS7JA8ZYQR \ -vvv POST / HTTP/1.1 Accept: application/json, */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 66 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.6.0 x-sora-target: Sora_20230628.TerminateSession { "channel_id": "sora", "session_id": "JJJ5BFH7QN6DQBTKSS7JA8ZYQR" } HTTP/1.1 200 OK content-length: 43 content-type: application/json date: Tue, 23 May 2023 09:59:06 GMT server: Cowboy { "session_id": "JJJ5BFH7QN6DQBTKSS7JA8ZYQR" } ``` ## GetSession **x-sora-target**: Sora_20231220.GetSession 指定したチャネルのセッションを表示する API です。 * - キー - 型 * - channel_id - string * - session_id (オプション) - string 戻り値の項目はセッションウェブフック `session.updated` と同様です。 ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20231220.GetSession \ channel_id=sora \ -vvv POST / HTTP/1.1 Accept: application/json, */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 66 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.6.0 x-sora-target: Sora_202312020.GetSession { "channel_id": "sora" } HTTP/1.1 200 OK content-length: 43 content-type: application/json date: Tue, 23 May 2023 09:59:06 GMT server: Cowboy { "label": "WebRTC SFU Sora", "node_name": "sora@127.0.0.1", "version": "2023.2.0", "channel_id": "sora", "session_id": "JJJ5BFH7QN6DQBTKSS7JA8ZYQR" "session_metadata": {"spam": "egg"}, "created_time": 1638337454, "created_timestamp": "2021-12-01T05:44:14.523736Z", "multistream": true, "spotlight": false, "max_connections": 4, "total_connections": 4, "external_signaling_url": "wss://node-01.example.com/signaling", "connections": [ { "audio": true, "audio_codec_type": "OPUS", "client_id": "W9QE86Z0BS1QFFPZ2QB5DRZ2HC", "bundle_id": "W9QE86Z0BS1QFFPZ2QB5DRZ2HC", "connection_id": "W9QE86Z0BS1QFFPZ2QB5DRZ2HC", "connection_created_timestamp": "2021-12-01T05:44:23.051704Z", "connection_destroyed_timestamp": "2021-12-01T05:44:56.878019Z", "role": "sendrecv", "simulcast": false, "video": true, "video_bit_rate": 1000, "video_codec_type": "VP9", "video_vp9_params": { "profile_id": 0 }, }, { "audio": true, "audio_codec_type": "OPUS", "client_id": "JXMYW6GPX54EH0HGA5X4130FBM", "bundle_id": "JXMYW6GPX54EH0HGA5X4130FBM", "connection_id": "JXMYW6GPX54EH0HGA5X4130FBM", "connection_created_timestamp": "2021-12-01T05:44:23.051704Z", "connection_destroyed_timestamp": "2021-12-01T05:44:56.878019Z", "role": "sendrecv", "simulcast": false, "video": true, "video_bit_rate": 1000, "video_codec_type": "VP9", "video_vp9_params": { "profile_id": 0 }, }, { "audio": true, "audio_codec_type": "OPUS", "client_id": "F8VK9R71BN5S5EDE737C8XAA3C", "bundle_id": "F8VK9R71BN5S5EDE737C8XAA3C", "connection_id": "F8VK9R71BN5S5EDE737C8XAA3C", "connection_created_timestamp": "2021-12-01T05:44:23.051704Z", "connection_destroyed_timestamp": "2021-12-01T05:44:56.878019Z", "role": "sendrecv", "simulcast": false, "video": true, "video_bit_rate": 1000, "video_codec_type": "VP9", "video_vp9_params": { "profile_id": 0 }, } ] } ``` ### クラスターが有効な場合 `connections` 項目が含まれなくなります。 ```javascript { "label": "WebRTC SFU Sora", "node_name": "sora@127.0.0.1", "version": "2023.2.0", "channel_id": "sora", "session_id": "JJJ5BFH7QN6DQBTKSS7JA8ZYQR" "session_metadata": {"spam": "egg"}, "created_time": 1638337454, "created_timestamp": "2021-12-01T05:44:14.523736Z", "multistream": true, "spotlight": false, "max_connections": 4, "total_connections": 4, "external_signaling_url": "wss://node-01.example.com/signaling" } ``` ### 録画機能 (セッション単位) が有効な場合 `recording` 項目が含まれるようになります。 * - キー - 型 - 内容 * - recording_id - string - 録画機能 (セッション単位) の ID * - recording_metadata - JSON Value - 録画機能 (セッション単位) のメタデータ * - expire_time - integer - セッションでの録画期限 * - expired_at - integer - セッションでの録画期限 (Unix time) * - split_only - boolean - セッションでの録画が分割のみかどうか * - split_duration (オプション) - integer - セッションでの録画分割有効時の分割時間 * - start_timestamp - string - セッションでの録画が開始された時刻 (RFC 3339 (UTC)) ```javascript { "label": "WebRTC SFU Sora", "node_name": "sora@127.0.0.1", "version": "2023.2.0", "channel_id": "sora", "session_id": "JJJ5BFH7QN6DQBTKSS7JA8ZYQR", "session_metadata": {"spam": "egg"}, "created_time": 1638337454, "created_timestamp": "2021-12-01T05:44:14.523736Z", "multistream": true, "spotlight": false, "max_connections": 4, "total_connections": 4, "external_signaling_url": "wss://node-01.example.com/signaling", "recording": { "recording_id": "WHEJ888HQ55KDCFE3TZ4VPFQHR", "recording_metadata": {"spam": "egg"}, "expire_time": 3600, "expired_at": 1615527737, "split_duration": 3600, "split_only": false, "start_timestamp": "2021-03-12T04:42:17.455668Z" } } ``` ## ListSessions **x-sora-target**: Sora_20231220.ListSessions Sora の全てのセッションを表示する API です。 - 録画機能 (セッション単位) が有効な場合は `"recording"` 項目が追加されます ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20231220.ListSessions \ -vvv POST / HTTP/1.1 Accept: application/json, */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 66 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.6.0 x-sora-target: Sora_202312020.ListSessions HTTP/1.1 200 OK content-length: 43 content-type: application/json date: Tue, 23 May 2023 09:59:06 GMT server: Cowboy [ { "label": "WebRTC SFU Sora", "node_name": "sora@127.0.0.1", "version": "2023.2.0", "channel_id": "sora", "session_id": "JJJ5BFH7QN6DQBTKSS7JA8ZYQR", "session_metadata": {"spam": "egg"}, "created_time": 1638337454, "created_timestamp": "2021-12-01T05:44:14.523736Z", "multistream": true, "spotlight": false, "max_connections": 4, "total_connections": 4, "connections": [ { "audio": true, "audio_codec_type": "OPUS", "client_id": "W9QE86Z0BS1QFFPZ2QB5DRZ2HC", "bundle_id": "W9QE86Z0BS1QFFPZ2QB5DRZ2HC", "connection_id": "W9QE86Z0BS1QFFPZ2QB5DRZ2HC", "connection_created_timestamp": "2021-12-01T05:44:23.051704Z", "connection_destroyed_timestamp": "2021-12-01T05:44:56.878019Z", "role": "sendrecv", "simulcast": false, "video": true, "video_bit_rate": 1000, "video_codec_type": "VP9", "video_vp9_params": { "profile_id": 0 } }, { "audio": true, "audio_codec_type": "OPUS", "client_id": "JXMYW6GPX54EH0HGA5X4130FBM", "bundle_id": "JXMYW6GPX54EH0HGA5X4130FBM", "connection_id": "JXMYW6GPX54EH0HGA5X4130FBM", "connection_created_timestamp": "2021-12-01T05:44:23.051704Z", "connection_destroyed_timestamp": "2021-12-01T05:44:56.878019Z", "role": "sendrecv", "simulcast": false, "video": true, "video_bit_rate": 1000, "video_codec_type": "VP9", "video_vp9_params": { "profile_id": 0 } }, { "audio": true, "audio_codec_type": "OPUS", "client_id": "F8VK9R71BN5S5EDE737C8XAA3C", "bundle_id": "F8VK9R71BN5S5EDE737C8XAA3C", "connection_id": "F8VK9R71BN5S5EDE737C8XAA3C", "connection_created_timestamp": "2021-12-01T05:44:23.051704Z", "connection_destroyed_timestamp": "2021-12-01T05:44:56.878019Z", "role": "sendrecv", "simulcast": false, "video": true, "video_bit_rate": 1000, "video_codec_type": "VP9", "video_vp9_params": { "profile_id": 0 } } ] }, { "label": "WebRTC SFU Sora", "node_name": "sora@127.0.0.1", "version": "2023.2.0", "channel_id": "sora", "session_id": "JJJ5BFH7QN6DQBTKSS7JA8ZYQR", "session_metadata": {"spam": "egg"}, "created_time": 1638337454, "created_timestamp": "2021-12-01T05:44:14.523736Z", "multistream": true, "spotlight": false, "max_connections": 4, "total_connections": 4, "connections": [ { "audio": true, "audio_codec_type": "OPUS", "client_id": "W9QE86Z0BS1QFFPZ2QB5DRZ2HC", "bundle_id": "W9QE86Z0BS1QFFPZ2QB5DRZ2HC", "connection_id": "W9QE86Z0BS1QFFPZ2QB5DRZ2HC", "connection_created_timestamp": "2021-12-01T05:44:23.051704Z", "connection_destroyed_timestamp": "2021-12-01T05:44:56.878019Z", "role": "sendrecv", "simulcast": false, "video": true, "video_bit_rate": 1000, "video_codec_type": "VP9", "video_vp9_params": { "profile_id": 0 }, }, { "audio": true, "audio_codec_type": "OPUS", "client_id": "JXMYW6GPX54EH0HGA5X4130FBM", "bundle_id": "JXMYW6GPX54EH0HGA5X4130FBM", "connection_id": "JXMYW6GPX54EH0HGA5X4130FBM", "connection_created_timestamp": "2021-12-01T05:44:23.051704Z", "connection_destroyed_timestamp": "2021-12-01T05:44:56.878019Z", "role": "sendrecv", "simulcast": false, "video": true, "video_bit_rate": 1000, "video_codec_type": "VP9", "video_vp9_params": { "profile_id": 0 }, } ], "recording": { "recording_id": "WHEJ888HQ55KDCFE3TZ4VPFQHR", "recording_metadata": {"spam": "egg"}, "expire_time": 3600, "expired_at": 1615527737, "split_duration": 3600, "split_only": false, "start_timestamp": "2021-03-12T04:42:17.455668Z" } } ] ``` ### クラスターが有効な場合 `connections` 項目が含まれなくなります。 ```javascript [ { "label": "WebRTC SFU Sora", "node_name": "sora@127.0.0.1", "version": "2023.2.0", "channel_id": "sora", "session_id": "JJJ5BFH7QN6DQBTKSS7JA8ZYQR", "session_metadata": {"spam": "egg"}, "created_time": 1638337454, "created_timestamp": "2021-12-01T05:44:14.523736Z", "multistream": true, "spotlight": false, "max_connections": 4, "total_connections": 4, "external_signaling_url": "wss://node-01.example.com/signaling" }, { "label": "WebRTC SFU Sora", "node_name": "sora@127.0.0.1", "version": "2023.2.0", "channel_id": "sora", "session_id": "JJJ5BFH7QN6DQBTKSS7JA8ZYQR", "session_metadata": {"spam": "egg"}, "created_time": 1638337454, "created_timestamp": "2021-12-01T05:44:14.523736Z", "multistream": true, "spotlight": false, "max_connections": 4, "total_connections": 4, "external_signaling_url": "wss://node-01.example.com/signaling", "recording": { "recording_id": "WHEJ888HQ55KDCFE3TZ4VPFQHR", "recording_metadata": {"spam": "egg"}, "expire_time": 3600, "expired_at": 1615527737, "split_duration": 3600, "split_only": false, "start_timestamp": "2021-03-12T04:42:17.455668Z" } } ] ``` # シグナリング API > **注意** > > この API は [実験的機能](EXPERIMENTAL.html) のため、正式版では仕様が変更される可能性があります。 ## 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 は [実験的機能](EXPERIMENTAL.html) のため、正式版では仕様が変更される可能性があります。 ## ChangeMode **x-sora-target**: Sora_20211215.ChangeMode Sora のモードを変更します。 * - キー - 型 * - mode - string (normal | block_new_session | block_new_connection) `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 は [実験的機能](EXPERIMENTAL.html) のため、正式版では仕様が変更される可能性があります。 指定したチャネル 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 は [実験的機能](EXPERIMENTAL.html) のため、正式版では仕様が変更される可能性があります。 ## 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"}' \ 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.PutSignalingNotifyMetadata { "channel_id": "sora", "connection_id": "0FQE5EA5YN3FS13P01QZ1JG8R0", "metadata": { "abc": "efg" }, "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: 13 content-type: application/json date: Thu, 26 Nov 2020 03:47:52 GMT server: Cowboy { "abc": "efg" } ``` push を有効にした場合は、そのチャネルのすべてのクライアントに以下のようなプッシュ通知が送られます。 ```javascript { "type": "push", "data": { "action": "PutMetadata", "connection_id": "0FQE5EA5YN3FS13P01QZ1JG8R0", "metadata": {"abc": "efg"}, "type": "signaling_notify_metadata_ext" } } ``` - action- "PutMetadata" 固定 - connection_id- シグナリング通知メタデータの項目が変更された接続の ID - metadata- 作成、または更新したメタデータ ## 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 \ push:=true \ -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", "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: 13 content-type: application/json date: Thu, 26 Nov 2020 03:51:48 GMT server: Cowboy { "abc": "efg" } ``` push を有効にした場合は、そのチャネルのすべてのクライアントに以下のようなプッシュ通知が送られます。 ```javascript { "type": "push", "data": { "action": "DeleteMetadata", "connection_id": "0FQE5EA5YN3FS13P01QZ1JG8R0", "metadata": {"abc": "efg"}, "type": "signaling_notify_metadata_ext" } } ``` - action- "DeleteMetadata" 固定 - connection_id- シグナリング通知メタデータの項目が変更された接続の ID - metadata- 削除したメタデータ ## 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 \ push:=true \ -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", "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: 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", "value": "efg", "type": "signaling_notify_metadata_ext" } } ``` - action- "PutMetadataItem" 固定 - 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 {} ``` push を有効にした場合は、そのチャネルのすべてのクライアントに以下のようなプッシュ通知が送られます。 ```javascript { "type": "push", "data": { "action": "DeleteMetadataItem", "connection_id": "0FQE5EA5YN3FS13P01QZ1JG8R0", "key": "abc", "type": "signaling_notify_metadata_ext" } } ``` - action- "DeleteMetadataItem" 固定 - connection_id- シグナリング通知メタデータの項目が変更された接続の ID - key- シグナリング通知メタデータの項目が変更されたキー # RTP ストリーム停止/再開 API > **注意** > > この API は [実験的機能](EXPERIMENTAL.html) のため、正式版では仕様が変更される可能性があります。 ## 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 は [実験的機能](EXPERIMENTAL.html) のため、正式版では仕様が変更される可能性があります。 転送フィルター API はチャネル単位やコネクション単位で音声や映像の転送をフィルターする機能です。 ## ListForwardingFilters **x-sora-target**: Sora_20230628.ListForwardingFilters 指定したチャネルについて、チャネル単位とコネクション単位両方の転送フィルターを表示します。 また、`blocked` オプションの指定により音声と映像のブロック状況を表示します。 * - キー - 型 * - channel_id - string * - blocked (オプション) - boolean - `blocked` を指定しない場合は `false` が指定されます - `version` が指定されていフィルターに対しては `version` 項目が追加されます - `metadata` が指定されているフィルターに対しては `metadata` 項目が追加されます ``` $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20230628.ListForwardingFilters \ channel_id=sora \ blocked:=true \ -vvv POST / HTTP/1.1 Accept: application/json Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 39 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/2.6.0 x-sora-target: Sora_20230628.ListForwardingFilters { "channel_id": "sora", "blocked": true } HTTP/1.1 200 OK content-length: 712 content-type: application/json date: Fri, 16 Jun 2023 02:36:06 GMT server: Cowboy { "channel_forwarding_filter": { "action": "block", "rules": [ [ { "field": "kind", "operator": "is_in", "values": [ "video", "audio" ] } ] ] }, "connection_forwarding_filters": [ { "action": "allow", "connection_id": "6V9VANDZZH71HCQGVKBWKJ8GS0", "rules": [ [ { "field": "kind", "operator": "is_in", "values": [ "video" ] } ] ] }, { "action": "allow", "connection_id": "XEDQM589M520Z50KM7C6C5PRB0", "rules": [ [ { "field": "kind", "operator": "is_in", "values": [ "audio" ] } ] ] } ], "blocked": [ { "destination_connection_id": "6V9VANDZZH71HCQGVKBWKJ8GS0", "kind": "audio", "source_connection_id_list": [ "ASJDFJ1PF94JN6DV59JQZ1HNDR" ] }, { "destination_connection_id": "XEDQM589M520Z50KM7C6C5PRB0", "kind": "video", "source_connection_id_list": [ "ASJDFJ1PF94JN6DV59JQZ1HNDR", "6V9VANDZZH71HCQGVKBWKJ8GS0" ] } ] } ``` ### レスポンス レスポンスの内容は以下の通りです。転送フィルターについての詳細は [転送フィルタールールの仕様](FORWARDING_FILTER.html#86374f) をご確認ください。 - channel_forwarding_filter- 指定したチャネルに設定されているチャネル単位の転送フィルターを表示します - connection_forwarding_filters- 指定したチャネルに設定されているコネクション単位の転送フィルターを配列で表示します - blocked- destination_connection_id- ブロックされている送信先のコネクション ID - kind- ブロックされているメディア (audio または video) - source_connection_id_list- ブロックされている送信元のコネクション ID の配列 ## CreateChannelForwardingFilter **x-sora-target**: Sora_20230628.CreateChannelForwardingFilter 指定したチャネルに対して転送フィルターを作成します。 チャネル単位での転送フィルター作成は **送信元からの音声や映像を送信先に転送するかどうか** です。 送信先はチャネルに参加しているすべてのコネクションです。 指定した送信先だけにブロックをさせたい場合は [CreateConnectionForwardingFilter](EXPERIMENTAL_API_FORWARDING_FILTER.html#d80a51) を使用してください。 転送フィルターの指定方法についての詳細は [転送フィルタールールの仕様](FORWARDING_FILTER.html#86374f) をご確認ください。 * - キー - 型 * - channel_id - string * - action (オプション) - string (block | allow) * - rules - array of object * - version (オプション) - string * - metadata (オプション) - json object - `action` の指定がない場合は `block` が指定されます - `rules` は転送フィルターの対象を配列で指定します。 `rules` で指定する array of object の object の内容は以下の通りです * - キー - 型 * - field - string (connection_id | client_id | kind) * - operator - string (is_in | is_not_in) * - value - array of string ``` $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20230628.CreateChannelForwardingFilter \ channel_id=sora \ action=block \ rules:='[ [ {"field": "connection_id", "operator": "is_in", "values": ["XEDQM589M520Z50KM7C6C5PRB0"]}, {"field": "client_id", "operator": "is_not_in", "values": ["screen-share"]}, {"field": "kind", "operator": "is_in", "values": ["video"]} ] ]' \ -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 283 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/3.2.1 x-sora-target: Sora_20230628.CreateChannelForwardingFilter { "action": "block", "channel_id": "sora", "rules": [ [ { "field": "connection_id", "operator": "is_in", "values": [ "XEDQM589M520Z50KM7C6C5PRB0" ] }, { "field": "client_id", "operator": "is_not_in", "values": [ "screen-share" ] }, { "field": "kind", "operator": "is_in", "values": [ "video" ] } ] ] } 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: * access-control-max-age: 1000 content-length: 261 content-type: application/json date: Thu, 22 Jun 2023 07:28:35 GMT server: Cowboy { "action": "block", "channel_id": "sora", "rules": [ [ { "field": "connection_id", "operator": "is_in", "values": [ "XEDQM589M520Z50KM7C6C5PRB0" ] }, { "field": "client_id", "operator": "is_not_in", "values": [ "screen-share" ] }, { "field": "kind", "operator": "is_in", "values": [ "video" ] } ] ] } ``` ## UpdateChannelForwardingFilter **x-sora-target**: Sora_20230628.UpdateChannelForwardingFilter 指定したチャネルの転送フィルターの設定を、 `rules` と `action` の内容で置き換えます。 > **注意** > > この API を実行するには事前に指定したチャネル単位の転送フィルターが作成されている必要があります * - キー - 型 * - channel_id - string * - action (オプション) - string (block | allow) * - rules - array of object * - expected_version (オプション) - string * - desired_version (オプション) - string * - metadata (オプション) - json object - `action` の指定がない場合は `block` が指定されます - `rules` は転送フィルターの対象を配列で指定します。 `rules` で指定する array of object の object の内容は以下の通りです * - キー - 型 * - field - string (connection_id | client_id | kind) * - operator - string (is_in | is_not_in) * - value - array of string ``` $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20230628.UpdateChannelForwardingFilter \ channel_id=sora \ action=block \ rules:='[ [ {"field": "connection_id", "operator": "is_in", "values": ["XEDQM589M520Z50KM7C6C5PRB0"]}, {"field": "client_id", "operator": "is_not_in", "values": ["screen-share"]}, {"field": "kind", "operator": "is_in", "values": ["video"]} ] ]' \ -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 283 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/3.2.2 x-sora-target: Sora_20230628.UpdateChannelForwardingFilter { "action": "block", "channel_id": "sora", "rules": [ [ { "field": "connection_id", "operator": "is_in", "values": [ "XEDQM589M520Z50KM7C6C5PRB0" ] }, { "field": "client_id", "operator": "is_not_in", "values": [ "screen-share" ] }, { "field": "kind", "operator": "is_in", "values": [ "video" ] } ] ] } 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: * access-control-max-age: 1000 content-length: 261 content-type: application/json date: Thu, 22 Jun 2023 07:40:11 GMT server: Cowboy { "action": "block", "channel_id": "sora", "rules": [ [ { "field": "connection_id", "operator": "is_in", "values": [ "XEDQM589M520Z50KM7C6C5PRB0" ] }, { "field": "client_id", "operator": "is_not_in", "values": [ "screen-share" ] }, { "field": "kind", "operator": "is_in", "values": [ "video" ] } ] ] } ``` ## DeleteChannelForwardingFilter **x-sora-target**: Sora_20230628.DeleteChannelForwardingFilter 指定したチャネルの転送フィルターの設定を削除します。 > **注意** > > この API を実行するには事前に指定したチャネル単位の転送フィルターが作成されている必要があります * - キー - 型 * - channel_id - string ``` $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20230628.DeleteChannelForwardingFilter \ 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/3.2.2 x-sora-target: Sora_20230628.DeleteChannelForwardingFilter { "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: * access-control-max-age: 1000 content-length: 21 content-type: application/json date: Thu, 22 Jun 2023 07:48:10 GMT server: Cowboy { "channel_id": "sora" } ``` ## CreateConnectionForwardingFilter **x-sora-target**: Sora_20230628.CreateConnectionForwardingFilter 指定したチャネルの特定コネクションに対して転送フィルターを作成します。 コネクション単位での転送フィルター作成は **指定したコネクションに送信元からの音声や映像を送信先に転送するかどうか** です。 指定した送信先だけブロックをしたい場合に利用します。 転送フィルターの指定方法についての詳細は [転送フィルタールールの仕様](FORWARDING_FILTER.html#86374f) をご確認ください。 * - キー - 型 * - channel_id - string * - connection_id - string * - action (オプション) - string (block | allow) * - rules - array of object * - version (オプション) - string * - metadata (オプション) - json object - `action` の指定がない場合は `block` が指定されます - `rules` は転送フィルターの対象を配列で指定します。 `rules` で指定する array of object の object の内容は以下の通りです * - キー - 型 * - field - string (connection_id | client_id | kind) * - operator - string (is_in | is_not_in) * - value - array of string ``` $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20230628.CreateConnectionForwardingFilter \ channel_id=sora \ connection_id=EQ13WT731S1EK452YRJVFGYAY8 \ action=block \ rules:='[ [ {"field": "connection_id", "operator": "is_in", "values": ["XEDQM589M520Z50KM7C6C5PRB0"]}, {"field": "client_id", "operator": "is_not_in", "values": ["screen-share"]}, {"field": "kind", "operator": "is_in", "values": ["video"]} ] ]' \ -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 330 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/3.2.2 x-sora-target: Sora_20230628.CreateConnectionForwardingFilter { "action": "block", "channel_id": "sora", "connection_id": "EQ13WT731S1EK452YRJVFGYAY8", "rules": [ [ { "field": "connection_id", "operator": "is_in", "values": [ "XEDQM589M520Z50KM7C6C5PRB0" ] }, { "field": "client_id", "operator": "is_not_in", "values": [ "screen-share" ] }, { "field": "kind", "operator": "is_in", "values": [ "video" ] } ] ] } 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: * access-control-max-age: 1000 content-length: 306 content-type: application/json date: Thu, 22 Jun 2023 07:50:04 GMT server: Cowboy { "action": "block", "channel_id": "sora", "connection_id": "EQ13WT731S1EK452YRJVFGYAY8", "rules": [ [ { "field": "connection_id", "operator": "is_in", "values": [ "XEDQM589M520Z50KM7C6C5PRB0" ] }, { "field": "client_id", "operator": "is_not_in", "values": [ "screen-share" ] }, { "field": "kind", "operator": "is_in", "values": [ "video" ] } ] ] } ``` ## UpdateConnectionForwardingFilter **x-sora-target**: Sora_20230628.UpdateConnectionForwardingFilter 指定したチャネルの特定コネクションに対する転送フィルターの設定を、 `rules` と `action` の内容で置き換えます。 > **注意** > > この API を実行するには事前に指定したコネクション単位の転送フィルターが作成されている必要があります * - キー - 型 * - channel_id - string * - connection_id - string * - action (オプション) - string (block | allow) * - rules - array of object * - expected_version (オプション) - string * - desired_version (オプション) - string * - metadata (オプション) - json object - `action` の指定がない場合は `block` が指定されます - `rules` は転送フィルターの対象を配列で指定します。 `rules` で指定する array of object の object の内容は以下の通りです * - キー - 型 * - field - string (connection_id | client_id | kind) * - operator - string (is_in | is_not_in) * - value - array of string ``` $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20230628.UpdateConnectionForwardingFilter \ channel_id=sora \ connection_id=T9J5FM3NTH6JH4JKFGTSHB1BA0 \ action=block \ rules:='[ [ {"field": "connection_id", "operator": "is_in", "values": ["XEDQM589M520Z50KM7C6C5PRB0"]}, {"field": "client_id", "operator": "is_not_in", "values": ["screen-share"]}, {"field": "kind", "operator": "is_in", "values": ["video"]} ] ]' \ -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 330 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/3.2.2 x-sora-target: Sora_20230628.UpdateConnectionForwardingFilter { "action": "block", "channel_id": "sora", "connection_id": "EQ13WT731S1EK452YRJVFGYAY8", "rules": [ [ { "field": "connection_id", "operator": "is_in", "values": [ "XEDQM589M520Z50KM7C6C5PRB0" ] }, { "field": "client_id", "operator": "is_not_in", "values": [ "screen-share" ] }, { "field": "kind", "operator": "is_in", "values": [ "video" ] } ] ] } 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: * access-control-max-age: 1000 content-length: 306 content-type: application/json date: Thu, 22 Jun 2023 07:54:29 GMT server: Cowboy { "action": "block", "channel_id": "sora", "connection_id": "EQ13WT731S1EK452YRJVFGYAY8", "rules": [ [ { "field": "connection_id", "operator": "is_in", "values": [ "XEDQM589M520Z50KM7C6C5PRB0" ] }, { "field": "client_id", "operator": "is_not_in", "values": [ "screen-share" ] }, { "field": "kind", "operator": "is_in", "values": [ "video" ] } ] ] } ``` ## DeleteConnectionForwardingFilter **x-sora-target**: Sora_20230628.DeleteConnectionForwardingFilter 指定したチャネルの特定コネクションの転送フィルターを削除します。 > **注意** > > この API を実行するには事前に指定したコネクション単位の転送フィルターが作成されている必要があります * - キー - 型 * - channel_id - string * - connection_id - string ``` $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20230628.DeleteConnectionForwardingFilter \ channel_id=sora \ connection_id=T9J5FM3NTH6JH4JKFGTSHB1BA0 \ -vvv 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/3.2.2 x-sora-target: Sora_20230628.DeleteConnectionForwardingFilter { "channel_id": "sora", "connection_id": "EQ13WT731S1EK452YRJVFGYAY8" } 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: * access-control-max-age: 1000 content-length: 66 content-type: application/json date: Thu, 22 Jun 2023 07:57:39 GMT server: Cowboy { "channel_id": "sora", "connection_id": "EQ13WT731S1EK452YRJVFGYAY8" } ``` # 統計 API > **注意** > > この API は [実験的機能](EXPERIMENTAL.html) のため、正式版では仕様が変更される可能性があります。 ## 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 は [実験的機能](EXPERIMENTAL.html) のため、正式版では仕様が変更される可能性があります。 ## 統計情報更新のタイミングについて この統計情報は、クライアントからシグナリングで送信されてくる統計情報の最新の値を返します。 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 は [実験的機能](EXPERIMENTAL.html) のため、正式版では仕様が変更される可能性があります。 ## 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" } ``` ## ListAudioStreamingResultPushState **x-sora-target**: Sora_20230628.ListAudioStreamingResultPushState 指定したチャネルのセッションのコネクション毎のサブスクライブの状態を表示します。 * - キー - 型 * - channel_id - string ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20230628.ListAudioStreamingResultPushState \ 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_20230628.ListAudioStreamingResultPushState { "channel_id": "sora" } HTTP/1.1 200 OK content-length: 195 content-type: application/json date: Thu, 18 May 2023 02:30:34 GMT server: Cowboy [ { "connection_id": "B2JPGFZPMD3H973Y811MF8ZZ70", "subscribe": true }, { "connection_id": "KT116Z11KX5Y547KA1V12HW8PG", "subscribe": false }, { "connection_id": "A5GYXGRYAX6590M3AFH7F9Z2H4", "subscribe": false } ] ``` # 非推奨 API ## 概要 非推奨 API は廃止日が設定されている API です。 基本的には以下のルールで廃止をしますが、例外はあります。不明点がある場合はサポートまでご連絡下さい。 - API が非推奨 API になった場合、代替 API がない場合は廃止までにすくなくとも 1 年以上の期間を設けます - API が非推奨 API になった場合、代替 API がある場合は廃止までにすくなくとも 6 ヶ月以上の期間を設けます ## レガシー録画 API > **注意** > > [レガシー録画機能 API](API_LEGACY_RECORDING.html) は 2025 年 12 月リリースの Sora にて廃止されます。 > 今後は [録画機能 (セッション単位) API](API_RECORDING.html) をご利用ください。 # 廃止 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 のクラスター機能をひととおり使ってみるところまでを説明します。 ## 前提 クラスター特有ではない Sora の設定や起動方法、シグナリングで使用する nginx の設定等については [チュートリアル](TUTORIAL.html) を参照してください。 ### ライセンス ノード数分のライセンスが必要になります。 Sora 3 台でクラスターを構築する場合は通常のライセンスが 3 つ、もしくは 3 ノード以上に対応した 最大ノード数ライセンスが 1 つ必要です。 ## クラスターの構築 まず、ここでは 3 ノードの Sora クラスターを構築する手順を示します。 それぞれのノードのノード名は **sora1@192.0.2.101**, **sora2@192.0.2.102**, **sora3@192.0.2.103** とします。 > **重要** > > `ノード名(node_name)` はクラスター内のすべてのノードのそれぞれがユニークである必要があります > **注釈** > > クラスターを構築する際、クラスター間の通信に使うネットワークは、 > 可能な限りプライベートネットワークを利用してください。 > > クラスター間の通信には各ノードの `node_name` で指定した @ 以下の IP アドレスまたはドメイン名を使用します。 ここでのクラスター構築では、3 台のサーバーがそれぞれ TCP/IP で通信できる状態になっていること、 そして Sora の tar.gz が展開されて `bin/sora` が実行できるようになっていることを前提としています。 1. クラスター間の通信に必要な TCP のポートをすべて開放します- TCP 4369- ポート番号の変更はできません、必ずこのポートを開放してください - TCP 49010-49020- `sora.conf` にて変更できますがデフォルトをお勧めします 2. 最初のノード(**sora1@192.0.2.101**)の `sora.conf` にクラスターの設定をします```ini node_name = sora1@192.0.2.101 cluster = true external_signaling_url = wss://sora-node1.example.com/signaling external_api_url = https://sora-node1.example.com/api contact_node_name_list = sora1@192.0.2.101, sora2@192.0.2.102, sora3@192.0.2.103 ``` 3. 最初のノード(**sora1@192.0.2.101**)の Sora を `bin/sora daemon` で起動します 4. 次のノード(**sora2@192.0.2.102**)の `sora.conf` も最初のノードと同様にクラスターの設定をします```ini node_name = sora2@192.0.2.102 cluster = true external_signaling_url = wss://sora-node2.example.com/signaling external_api_url = https://sora-node2.example.com/api contact_node_name_list = sora1@192.0.2.101, sora2@192.0.2.102, sora3@192.0.2.103 ``` 5. 次のノード(**sora2@192.0.2.102**)の Sora を `bin/sora daemon` で起動します 6. 最後のノード(**sora3@192.0.2.103**)の `sora.conf` にもクラスターの設定をします```ini node_name = sora3@192.0.2.103 cluster = true external_signaling_url = wss://sora-node3.example.com/signaling external_api_url = https://sora-node3.example.com/api contact_node_name_list = sora1@192.0.2.101, sora2@192.0.2.102, sora3@192.0.2.103 ``` 7. 最後のノード(**sora3@192.0.2.103**)の Sora を `bin/sora daemon` で起動します 8. 最初のノード(**sora1@192.0.2.101**)の Sora に [InitCluster](EXPERIMENTAL_API_CLUSTER.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.0.2.102", "sora3@192.0.2.103"]' ``` 9. 最初のノード(**sora1@192.0.2.101**)の Sora に [ListClusterNodes](EXPERIMENTAL_API_CLUSTER.html#a70901) APIを実行し、ノード一覧を取得します```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20211215.ListClusterNodes ``` 結果として、 **sora1@192.0.2.101** から **sora3@192.0.2.103** の 3 ノードの一覧が取得できれば、クラスターの構築は完了です。 ### クラスター構築のトラブルシューティング クラスター構築時に躓きやすいポイントと確認事項を示します。 - ノード間通信ができない場合- Sora はノード間通信を行うため、ファイアウォールの開放が必要です - [ポートの開放](CLUSTER.html#90df52) にあるとおりに、EPMD と sora の Listen ポートの開放を確認してください - ライセンス違反のエラーが出る場合- [最大ノード数ライセンス](LICENSE.html#aee259) ではないライセンスを使っている場合には、すべてのノードで異なるライセンスが設定されている必要があります - [最大ノード数ライセンス](LICENSE.html#aee259) のライセンスを使っている場合には、指定されたノード数まで同じライセンスを利用できます - [最大ノード数ライセンス](LICENSE.html#aee259) とそうではないライセンスを混在させて利用することもできますが、それぞれについて上記の条件が満たされている必要があります - contact_node_not_intialized エラーが出る場合- 未初期化のノードを contact_node_name に指定した場合に発生します - concact_node_name に指定するノードは [InitCluster](EXPERIMENTAL_API_CLUSTER.html#621990) で初期化したノードか、[JoinCluster](EXPERIMENTAL_API_CLUSTER.html#17f3f5) API でクラスターに参加したノードを指定する必要があります ## クラスター操作 上記のクラスターの構築の手順で、クラスターの構築と初期化が完了していることを前提とします。 ### クラスターのノード一覧の取得 構築済みのクラスター内のノード名 **sora1@192.0.2.101**、 **sora2@192.0.2.102**、 **sora3@192.0.2.103** のいずれかで [ListClusterNodes](EXPERIMENTAL_API_CLUSTER.html#a70901) API を実行して、 クラスター内のノード一覧を取得します。 ```console $ http POST 127.0.0.1:3000/ 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: * access-control-max-age: 1000 content-length: 1057 content-type: application/json date: Fri, 08 Dec 2023 07:51:19 GMT server: Cowboy [ { "connected": true, "external_api_url": "https://sora-node1.example.com/api", "external_signaling_url": "wss://sora-node1.example.com/signaling", "license_max_connections": 100, "license_max_nodes": 3, "license_serial_code": "DOC123-SRA-E002-201303-N3-100", "license_type": "Experimental", "mode": "normal", "node_name": "sora1@192.0.2.101", "version": "2023.2.0" }, { "connected": true, "external_api_url": "https://sora-node2.example.com/api", "external_signaling_url": "wss://sora-node2.example.com/signaling", "license_max_connections": 100, "license_max_nodes": 3, "license_serial_code": "DOC123-SRA-E002-201303-N3-100", "license_type": "Experimental", "mode": "normal", "node_name": "sora2@192.0.2.102", "version": "2023.2.0" }, { "connected": true, "external_api_url": "https://sora-node3.example.com/api", "external_signaling_url": "wss://sora-node3.example.com/signaling", "license_max_connections": 100, "license_max_nodes": 3, "license_serial_code": "DOC123-SRA-E002-201303-N3-100", "license_type": "Experimental", "mode": "normal", "node_name": "sora3@192.0.2.103", "version": "2023.2.0" } ] ``` ### クラスターチャネル割り当て一覧の取得 接続済みのチャネルのノードへの割り当てを確認するために、[ListClusterChannels](EXPERIMENTAL_API_CLUSTER.html#0a4459) API を実行します。 まず、構築済みのクラスターに複数のチャネルで接続しておきます。 次に、クラスター内のいずれかのノードで [ListClusterChannels](EXPERIMENTAL_API_CLUSTER.html#0a4459) API を実行して、クラスターのチャネル割り当ての一覧を取得し、チャネルと割り当てられているノードを確認します。 ```console $ http POST 127.0.0.1:3000/ 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: * access-control-max-age: 1000 content-length: 342 content-type: application/json date: Mon, 11 Dec 2023 03:53:49 GMT server: Cowboy [ { "channel_id": "hisui", "owners": [ { "connected": true, "node_name": "sora1@192.0.2.101" } ] }, { "channel_id": "kohaku", "owners": [ { "connected": true, "node_name": "sora2@192.0.2.102" } ] }, { "channel_id": "sora", "owners": [ { "connected": true, "node_name": "sora3@192.0.2.102" } ] }, { "channel_id": "zakuro", "owners": [ { "connected": true, "node_name": "sora3@192.0.2.102" } ] } ] ``` ### クラスターからノードを削除する 構築済みのクラスター内からノードを削除してみます。 ここでは、ノード名 **sora1@192.0.2.101**、 **sora2@192.0.2.102**、 **sora3@192.0.2.103** の 3 ノードで構築されているクラスターから、 **sora3@192.0.2.103** のノードを削除します。 ノードの削除には [PurgeClusterNode](EXPERIMENTAL_API_CLUSTER.html#13b35a) API を使用します。 初めに、 **sora3@192.0.2.103** の Sora を bin/sora stop で停止します。 次に、 **sora3@192.0.2.103** ノードの `data/` ディレクトリを削除します。 **sora1@192.0.2.101** のノードで [ListClusterNodes](EXPERIMENTAL_API_CLUSTER.html#a70901) API を実行して、 クラスターのノードから **sora3@192.02.103** のノードが見えなくなっていることを確認します。 ```console $ http POST 127.0.0.1:3000/ 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: * access-control-max-age: 1000 content-length: 704 content-type: application/json date: Fri, 08 Dec 2023 08:06:39 GMT server: Cowboy [ { "connected": true, "external_api_url": "https://sora-node1.example.com/api", "external_signaling_url": "wss://sora-node1.example.com/signaling", "license_max_connections": 100, "license_max_nodes": 3, "license_serial_code": "DOC123-SRA-E002-201303-N3-100", "mode": "normal", "node_name": "sora1@192.0.2.101", "version": "2023.2.0" }, { "connected": true, "external_api_url": "https://sora-node2.example.com/api", "external_signaling_url": "wss://sora-node2.example.com/signaling", "license_max_connections": 100, "license_max_nodes": 3, "license_serial_code": "DOC123-SRA-E002-201303-N3-100", "license_type": "Experimental", "mode": "normal", "node_name": "sora2@192.0.2.102", "version": "2023.2.0" } ] ``` クラスターから **sora3@192.0.2.103** ノードの情報を削除するために、 **sora1@192.0.2.101** または **sora2@192.0.2.102** ノードのいずれかで [PurgeClusterNode](EXPERIMENTAL_API_CLUSTER.html#13b35a) API を実行します。 この API を実行する際の `target_node_name` には削除するノード名を指定します。 今回指定するノード名は、 **sora3@192.0.2.103** です。 ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20220629.PurgeClusterNode target_node_name=sora3@192.0.2.103 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: * access-control-max-age: 1000 content-length: 40 content-type: application/json date: Mon, 11 Dec 2023 02:03:09 GMT server: Cowboy { "target_node_name": "sora3@192.0.2.103" } ``` ### クラスターにノードを追加する 構築済みのクラスターにノードを追加してみます。 ノード名 **sora1@192.0.2.101**、 **sora2@192.0.2.102** の 2 ノードで構築されているクラスターへ、 API を使用して **sora4@192.0.2.104** ノードを追加します。 ノードの追加には [JoinCluster](EXPERIMENTAL_API_CLUSTER.html#17f3f5) API を使用します。 クラスターに **sora4@192.0.2.104** ノードを追加するために、 **sora4@192.0.2.104** ノードで [JoinCluster](EXPERIMENTAL_API_CLUSTER.html#17f3f5) API を実行します。 この API を実行する際の `contact_node_name` には既存のクラスターのノード名を指定します。 今回指定するノード名は、 **sora1@192.0.2.101** または **sora2@192.0.2.102** のいずれかです。 ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20211215.JoinCluster contact_node_name=sora1@192.0.2.101 HTTP/1.1 200 OK content-length: 80 content-type: application/json date: Mon, 11 Dec 2023 02:33:35 GMT server: Cowboy { "node_name_list": [ "sora1@192.0.2.101", "sora2@192.0.2.102", "sora4@192.0.2.104" ] } ``` [ListClusterNodes](EXPERIMENTAL_API_CLUSTER.html#a70901) API を使用して、クラスターに追加されていることを確認します。 ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20211215.ListClusterNodes HTTP/1.1 200 OK content-length: 1057 content-type: application/json date: Mon, 11 Dec 2023 02:34:04 GMT server: Cowboy [ { "connected": true, "external_api_url": "https://sora-node1.example.com/api", "external_signaling_url": "wss://sora-node1.example.com/signaling", "license_max_connections": 100, "license_max_nodes": 3, "license_serial_code": "DOC123-SRA-E002-201303-N3-100", "license_type": "Experimental", "mode": "normal", "node_name": "sora1@192.0.2.101", "version": "2023.2.0" }, { "connected": true, "external_api_url": "https://sora-node2.example.com/api", "external_signaling_url": "wss://sora-node2.example.com/signaling", "license_max_connections": 100, "license_max_nodes": 3, "license_serial_code": "DOC123-SRA-E002-201303-N3-100", "license_type": "Experimental", "mode": "normal", "node_name": "sora2@192.0.2.102", "version": "2023.2.0" }, { "connected": true, "external_api_url": "https://sora-node4.example.com/api", "external_signaling_url": "wss://sora-node4.example.com/signaling", "license_max_connections": 100, "license_max_nodes": 3, "license_serial_code": "DOC123-SRA-E002-201303-N3-100", "license_type": "Experimental", "mode": "normal", "node_name": "sora4@192.0.2.104", "version": "2023.2.0" } ] ``` # クラスター機能 > **注意** > > この機能を利用する場合は事前にサポートまでご連絡ください > **警告** > > この機能は [実験的機能](EXPERIMENTAL.html) のため、正式版では仕様が変更される可能性があります ## 概要 これは複数の Sora でクラスターを構成し、冗長化、負荷分散を行うための仕組みです。 ## 目的 可用性を高めるため Sora 複数台でクラスターを組み、冗長化やロードバランシングを実現します。 ## 用語 **ノード** : クラスターに参加している Sora です ## 特徴 > **注釈** > > これらの仕組みは `sora.conf` にてクラスター機能を有効にした場合に使用できます ### クライアントへの複数シグナリング設定 Sora SDK にシグナリング URL を複数指定することで、いずれかの ノードが正常に動作していれば Sora に繋がります。 ### ノード選択 / ロードバランス機能 クラスターを構築しているノードの中で `現在の同時接続数` を `ライセンスの最大同時接続数` で割った値が一番小さいノードに、新規チャネル ID の担当を割り当てます。 この値がすべて同じ場合は、接続しに行ったノード自身が新規チャネル ID を担当します。 すでに、そのチャネル ID がクラスター内部で利用されている場合は、 そのチャネル ID を担当しているノードへ接続先が割り当てられます。 ### シグナリングのリダイレクト機能 > **重要** > > Sora の SDK を利用している場合は、 > 基本的にここに書かれているリダイレクトの細かい仕様を把握する必要はありません。 `"type": "connect"` を送った際、認証処理に入る前に `{"type": "redirect", "location": "wss://sora1.example.com/signaling"}` が Sora から送られてくる場合があります。 この場合は、送られてきた location の URL にシグナリング URL を切り替えて再度 `type: connect` を行ってください。 その際は `{type: connect, redirect: true}` のように `redirect: true` を追加情報として入れてください。 ### HTTP API のリダイレクト機能 チャネル ID を指定する HTTP API を利用する場合、リダイレクトが発生することがあります。 指定されたチャネル ID を他ノードが担当している場合に、ステータスコード 307 (Temporary Redirect)の HTTP 応答により、クライアントにそのノードへのリダイレクトを要求します。 ステータスコード 307 の HTTP 応答受信時の処理は、HTTP のクライアントとして使用するツールやライブラリにより異なります。 必要に応じて、リダイレクト応答の Location ヘッダーへアクセスを継続するようにしてください。 たとえば、`curl` コマンドの場合は、 `-L` オプションを指定することでリダイレクト先への再要求を行います。 ### クラスター自動参加機能 クラスターにノードが自動で参加する機能です。 Sora はクラスターが有効な際、起動時に `sora.conf` の [contact_node_name_list](CLUSTER.html#a3d0fd) に存在する ノード名に対してクラスターの参加を自動で試みます。 また、そのノードが一度でもクラスターに参加したことがある場合は、そのクラスターに参加していた時の ノード一覧を利用して、クラスターへの参加を自動で試みます。 ### クラスター手動参加機能 > **重要** > > `sora.conf` の [contact_node_name_list](CLUSTER.html#a3d0fd) を利用したクラスター自動参加機能の利用を推奨しています。 クラスターを手動で構築する機能です。既存のクラスターに参加する際に、クラスターに参加させるノードで [JoinCluster](EXPERIMENTAL_API_CLUSTER.html#17f3f5) API を実行します。 すでクラスターに参加しているいずれかのノードの名前を `contact_node_name` に指定してください。 クラスターに参加していて、初期化済みであれば、どのノードでもかまいません。 ### クラスター自動復旧 クラスターで利用しているネットワークに障害が発生した際には、個々のノードはクラスターを構成する他のノードへの接続を試みて、復旧処理を行います。 ### ネットワーク分断時の接続受け付けの停止 ネットワーク分断時には Sora のノード間で通信ができずに、クラスター内の情報の整合性が取れなくなる可能性があります。 この情報の不整合を回避するために、Sora は自分がクラスター内の半数以下のグループに属した場合には、既存の接続を切断し、 さらに新規接続の受け付けも停止します。 ### 特定ノードへの新規チャネル ID の割り当て停止 [モード機能](MODE.html) の [新規コネクションブロックモード](MODE.html#0b67d3) または [新規セッションブロックモード](MODE.html#041e1c) になっている場合は、 そのノードに対して新規チャネル ID の割り当てを行いません。 ### 録画情報の共有 録画の情報はクラスター内部で共有されます。 たとえば [StartRecording](API_LEGACY_RECORDING.html#c5b527) API をあるノードに対して実行した後にそのノードが停止しても 録画情報は他のノードに残り続けます。 ### ネットワーク障害やノード障害 Sora のクラスター機能はネットワーク障害やノード障害が発生した際に、 自動で新規接続の受け付けの停止とそこからの復旧を試みます。 #### 発生しうる問題と新規接続の受け付け停止 ネットワーク障害等が発生した場合には、 Sora のノード間で通信ができず、クラスター内の情報の整合性が取れなくなる可能性があります。 たとえば、5 ノードのクラスターが 3 ノードからなるグループ A と 残りの 2 ノードからなるグループ B の 2 グループに分断されるということが起こりえます。 それぞれのグループ内では通信ができるものの、他グループへの通信ができないという状態です。 この状態ですべてのノードが接続を受け付けると、同じチャネル ID を指定していても、 あるクライアントはグループ A に繋がり、別のクライアントは グルーブ B につながる可能性があり、 それぞれのクライアント間で音声と映像が届かなくなります。 このような状況を防止するため、Sora は自分が半数以下のグループに属した場合に、新規接続の受け付けを停止します。 また、ノード数が半数以下のクラスターに参加しているノードは、接続中のすべての接続を切断し、その後は接続を受け入れません。 その後、クラスター自動復旧機能により、通信できるノードが過半数のグループとなった場合には、自動で新規接続の受け付けを再開します。 #### 全ノードが半数以下のグループに所属した場合の挙動 ネットワーク障害等が発生したことで、いずれのグループも通信できるノードが半数以下になった場合、 どこグループでも新規接続はまったく受け付けられない状態になります。 この状態でも Sora は、永続化しておいたノード一覧を利用し自動でクラスターの復旧を試みます。 そして、クラスターが復旧して過半数のグループができた場合は新規接続が可能になります。 ### クラスター環境での録画 #### 録画情報の共有 録画の情報はクラスター内部で共有されます。 たとえばレガシー録画の [StartRecording](API_LEGACY_RECORDING.html#c5b527) API をあるノードまたに対して実行した後にそのノードが停止しても 録画情報は他のノードに残り続けます。 また指定したチャネル ID に接続がない状態であれば、 [StopRecording](API_RECORDING.html#fd0de5) API はどのノードに対しても実行できます。 たとえば、あるチャネル ID でレガシー録画の [StartRecording](API_LEGACY_RECORDING.html#c5b527) API が実行された後に、 ノード A に接続がきて録画が開始したとします。 このノード A がノード障害等で終了した後に、同じチャネル ID で別の接続がノード B に来た場合には ノード B で録画が進行します。 #### 録画ファイルの出力ノード `archive-.json`, `archive-.webm` の録画ファイルは、接続を担当するノードで 出力されます。 次のような場合には同一の `recording_id` に属する録画ファイルが、 複数ノードにまたがって出力されることがありますのでご注意ください。 1. [レガシー録画機能](LEGACY_RECORDING.html) でチャネル ID を指定して録画開始 2. ノード A に指定したチャネル ID の接続が来てしばらくして切断、録画ファイルがノード A に作られる 3. ノード A が停止 4. ノード B に指定したチャネル ID に接続が来てしばらくして切断、録画ファイルがノード B に作られる #### `report-.json` ファイルの出力ノード あるチャネルに対して、 [StopRecording](API_LEGACY_RECORDING.html#fd0de5) API を実行した場合には録画が終了し、 `report-.json` ファイルが出力されます。 このファイルの出力ノードは次のとおりです。 - そのチャネルに接続したクライアントがひとつもなかった場合はどのノードで出力されるかは未定です- ただし、クラスター内のいずれかのノードで出力されます - そのチャネルに接続中のクライアントがいる場合は、チャネルの担当ノードで出力されます - そのチャネルに接続したクライアントが過去にいた場合は 2 パターンがありえます- クライアントが接続したノードが生存し続けている場合はそのノードで出力されます - ノードが落ちている、または停止した後に再起動した場合にはどのノードで出力されるかは未定です- ただし、クラスター内のいずれかのノードで出力されます #### `report-.json` ファイルが一時的に出力されない場合 全ノードが半数以下に所属した場合には `report-.json` ファイルが出力されません。 5 ノードのクラスターがあるとして、いくつか例を示します。 - ネットワーク障害が発生し、2 + 2 + 1 に分断された場合 - ノード障害(運用での停止も含む)が発生し、3 ノードが停止した場合 - ノード障害で 1 ノードが停止した状態でネットワーク障害が発生し、 2 + 2 に分断された場合 このあとに分断が解消し、過半数のグループができたあとに [StopRecording](API_LEGACY_RECORDING.html#fd0de5) API を 実行すると `report-.json` ファイルが出力されます。 #### `report-.json` ファイルの archives の内容と実際に出力される録画ファイルが一致しない場合 録画中のノードがクラスターから分離された場合に `report-.json` ファイルの `archives` に全ての録画ファイルが含まれないケースがあります。 録画中のノードがクラスターから分離された場合は別のノードが `report-.json` ファイルを出力しますが、クラスター分離前に共有された録画情報の内容で出力し、 分離直後に作成された録画ファイルは含まれないためです。 ## 設定 ### cluster クラスター機能を利用する場合、 `sora.conf` にて [cluster](SORA_CONF.html#b2cd99) を `true` を設定する必要があります。 デフォルトでは `cluster` は有効になっていません。 > **重要** > > cluster = true にして Sora を起動した場合、 > Sora は [InitCluster](EXPERIMENTAL_API_CLUSTER.html#621990) API を実行するか、クラスターに参加して過半数のグループになったタイミングでのみ利用可能になります。 ```ini cluster = true ``` ### node_name クラスター機能を利用する際のノード名を指定して下さい。 この名前はクラスター内のノードの識別に使われます。 具体的には、クラスターノード間の通信相手の特定や、 `sora.conf` の [contact_node_name_list](CLUSTER.html#a3d0fd) 、 [JoinCluster](EXPERIMENTAL_API_CLUSTER.html#17f3f5) API、 [PurgeClusterNode](EXPERIMENTAL_API_CLUSTER.html#13b35a) API で指定する名前として利用します。 > **重要** > > `node_name` はクラスター内のすべてのノードでユニークである必要があります ノード名の @ の前には、正規表現 `[0-9A-Za-z_\\-]+` にマッチする任意の文字列を指定してください。 また @ の後ろには、他のノードからアクセス可能なこのノードのドメイン名(FQDN)や、IP アドレスを指定してください。 @ の後ろにホスト名("." を含まない文字列)のみを指定すると、ノード間で通信が行えなくなってしまいますので、ご注意ください。 ```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](SORA_CONF.html#a3d0fd) が指定されていた場合、 起動時に自分以外のノード名に対して自動でクラスターの参加を試みます。 > **注釈** > > 自分自身のノード名が `contact_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 ``` 例えば、上記の設定の場合は、シグナリングのリダイレクトが必要な際に Sora から `{"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/api ``` ### cluster_listen_{min,max}_port `sora.conf` にてクラスター情報の同期に利用する TCP の受信ポートの範囲を指定してください。 デフォルトでは 49010 - 49020 が指定されています。 ```ini cluster_listen_min_port = 49010 cluster_listen_max_port = 49020 ``` ## API ### クラスター初期化 API クラスターを構築するときは、まずクラスターの初期化を行います。 > **重要** > > クラスターの初期化はクラスターを初めて構築する際と、クラスターが破綻した際に行う必要があります。 クラスターの初期化を実行する場合は `20221221.InitCluster` API をクラスター構築するいずれかのノードで実行します。 `node_name_list` にはクラスターを構成するノードを、 `20221221.InitCluster` API を実行するノードを含め指定してください。 API の詳細は [InitCluster](EXPERIMENTAL_API_CLUSTER.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@192.0.2.8", "node-01@192.0.2.5"]' \ -vvv POST / HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Content-Length: 83 Content-Type: application/json Host: 127.0.0.1:3000 User-Agent: HTTPie/3.2.2 x-sora-target: Sora_20221221.InitCluster { "node_name_list": [ "node-02@192.0.2.7", "node-03@192.0.2.8", "node-01@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: * access-control-max-age: 1000 content-length: 80 content-type: application/json date: Wed, 06 Dec 2023 06:52:47 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_CLUSTER.html#17f3f5) API をご確認ください。 下記は、これから参加する既存クラスター内の node-01@192.0.2.5 ノードを contact_node_name に指定して、新規に参加させるノードで [JoinCluster](EXPERIMENTAL_API_CLUSTER.html#17f3f5) APIを実行しています。 ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20211215.JoinCluster \ contact_node_name=node-01@192.0.2.5 HTTP/1.1 200 OK content-length: 80 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 あるノードが障害で再度の参加が難しい、またはスケールインのためにノード破棄する場合は、 破棄するノードを停止後に [PurgeClusterNode](EXPERIMENTAL_API_CLUSTER.html#13b35a) API を利用して、そのノード情報を完全消去してください。 `20220629.PurgeClusterNode` API は、クラスターに参加している破棄するノード以外のどのノードでもかまわないので 1 回だけ実行します。 この API で完全消去した結果はクラスター内部で共有されます。 > **警告** > > PurgeClusterNode API はクラスターからノードを完全に消去するための API です。 > 再度参加するノードに対しては基本的に使用しないでください。 > この API を含めた運用の手順は [クラスター運用](CLUSTER.html#0233aa) をご確認ください。 ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20220629.PurgeClusterNode \ target_node_name=node-01@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: * access-control-max-age: 1000 content-length: 40 content-type: application/json date: Wed, 06 Dec 2023 07:16:06 GMT server: Cowboy { "target_node_name": "node-01@192.0.2.5" } ``` 詳細は [PurgeClusterNode](EXPERIMENTAL_API_CLUSTER.html#13b35a) API をご確認ください。 ### クラスターノード一覧 API 詳細は [ListClusterNodes](EXPERIMENTAL_API_CLUSTER.html#a70901) API をご確認ください。 ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20211215.ListClusterNodes HTTP/1.1 200 OK content-length: 1006 content-type: application/json date: Tue, 16 Nov 2021 08:36:25 GMT server: Cowboy [ { "external_api_url": "http://192.0.2.5:3000/", "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": "2023.2.0" }, { "external_api_url": "http://192.0.2.7:3000/", "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": "2023.2.0" }, { "external_api_url": "http://192.0.2.8:3000/", "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": "2023.2.0" } ] ``` ### クラスターチャネル割り当て一覧 API 詳細は [ListClusterChannels](EXPERIMENTAL_API_CLUSTER.html#0a4459) API をご確認ください。 ```console $ http POST 127.0.0.1:3000/ x-sora-target:Sora_20211215.ListClusterChannels HTTP/1.1 200 OK content-length: 461 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", "connected": true } ] }, { "channel_id": "lemon", "owners": [ { "node_name": "node-01@192.0.2.5", "connected": true } ] }, { "channel_id": "hisui", "owners": [ { "node_name": "node-03@192.0.2.5", "connected": true } ] }, { "channel_id": "zakuro", "owners": [ { "node_name": "node-03@192.0.2.5", "connected": true } ] } ] ``` ## クラスター運用 ### 推奨ノード数 Sora のクラスター構築ノード数は 3 ノードが推奨となっております。 ### クラスターからの一時的な離脱 モード切り替え API を利用し、 [新規コネクションブロックモード](MODE.html#0b67d3) または [新規セッションブロックモード](MODE.html#041e1c) に 切り替えます。 その後、すべての接続がいなくなったタイミングでノードを終了してください。 一時的に離脱したノードは、再起動するとそのままクラスターに参加して動作します。 ### 一時的に離脱したノードを含めるクラスターノード一覧 [ListClusterNodes](EXPERIMENTAL_API_CLUSTER.html#a70901) API では現在クラスターに参加しているノードの一覧が返ります。 > **注釈** > > 結果に一時的に離脱したノードを含めない場合には、 `include_all_known_nodes` に `false` を指定して API を実行します。 ### クラスターからノード情報の完全消去 > **重要** > > 恒久的にノードを破棄する場合には、必ず、この作業を行ってください。 特定のクラスターノードで障害が起きた後、復旧が難しい場合は [PurgeClusterNode](EXPERIMENTAL_API_CLUSTER.html#13b35a) API を利用して、 クラスターに参加しているノードから、障害が起きたノードの情報を完全消去してください。 また、スケールインのためにノードを破棄する場合も同様に [PurgeClusterNode](EXPERIMENTAL_API_CLUSTER.html#13b35a) API を 利用して、破棄したノードの情報を完全消去してください。 この作業はクラスターの新鮮さを保つために必要な作業となります。 この作業を行わないと存在していないノードが残り続けることで過半数かどうかの判断を誤る場合があります。 > **警告** > > PurgeClusterNode API はクラスターからノードを完全に消去するための API です。 > 近い将来に再び参加するノードに対しては基本的に使用しないでください。 ### クラスターのアップデート > **重要** > > ローリングアップデートを行ってください。 > ここでのローリングアップデートとは 1 台ずつノードのアップデートを行っていく事です。 > 1 台のアップデートが終わり次第、次のアップデートを行ってください。 > 同時に複数のノードのアップデートは行わないでください。 1. アップデート対象のノードを [ChangeMode](MODE.html#3af05f) API で [新規コネクションブロックモード](MODE.html#0b67d3)または [新規セッションブロックモード](MODE.html#041e1c) に切り替えます- 必要があれば [ListChannels](EXPERIMENTAL_API_SIGNALING.html#b27c42) API と [DisconnectChannel](API_SIGNALING.html#a87366) API を利用して既存接続を切断します 2. すべての接続がなくなったら Sora を停止させます 3. 新しいバージョンの Sora へ入れ替えます 4. 新しいバージョンの Sora を起動します 5. [ListClusterNodes](EXPERIMENTAL_API_CLUSTER.html#a70901) API で新しいバージョンの Sora がクラスターに参加できているかを確認します > **警告** > > 自動でクラスターに参加する処理がエラーになる可能性もあるため、 > [ListClusterNodes](EXPERIMENTAL_API_CLUSTER.html#a70901) API で新しいバージョンの Sora がクラスターに参加できているかを必ず確認してください。 > 確認せずに他ノードのローリングアップデートを行った場合、クラスターに参加できていないままのノードが出てしまう > 可能性があります。 > さらに、複数のノードが参加できずに過半数を割ってしまうと、クラスターがまったく稼働しなくなる可能性もあります。 上の手順を **1 ノードごと** に繰り返してください。 ### Sora のバージョンダウン [クラスターのアップデート](CLUSTER.html#c99fc7) の仕組みを使って、Sora のバージョンを下げることはできません。 そのため、クラスターのアップデート後に何らかの問題が発生し、 以前のバージョンに戻したい場合には、クラスターの再構築を行う必要があります。 再構築の際には、事前に全ノードを停止し、 `data/` ディレクトリを削除した上で、 以前のバージョンの Sora を使用してクラスターの構築を行ってください。 ### クラスター破綻からの再構築手順 クラスターのうち、過半数のノードが停止した場合、クラスターのすべてのノードは接続を受け付けなくなります。 この状態からでも、停止したノードを再開させ、過半数のノードが正常に戻ったタイミングで、接続を受け付け始めます。 その場合は、ここで書かれている手順は必要ありません。 ただし、停止したノードがディスク障害などで `data/` ディレクトリを失ってしまったときや、使っていた IP アドレスが使えなくなってしまうなどの理由で、再開できないこともあります。 ここでは、3 ノードクラスターを組んでいたものの、うち 2 つのサーバーがディスク障害で `data/` ディレクトリを失った状態からの再構築手順を示します。 > **注釈** > > `data/` ディレクトリを失ってしまうと、「未初期化」状態になるため、再度クラスターへの参加手順が必要です。 > **注釈** > > `node_name` に IP アドレスを使う場合、IP アドレスが変わると `node_name` も変える必要があります。 > その際は `data/` ディレクトリを削除する必要があります。 - まずすべての Sora プロセスを停止状態にします - ディスク障害がおきたサーバーでは- Sora をインストールしなおします - 必要に応じて sora.conf 設定を行います - ディスク障害がおきなかったサーバーでは- `data/` ディレクトリを削除します - これを忘れると正しい再構築ができません、必ず削除してください - ここまでで、完全にまっさらの Sora クラスターを構築する準備ができたことになります - すべてのノードを起動します - [InitCluster](EXPERIMENTAL_API_CLUSTER.html#621990) API を発行し、クラスターを初期化します 以上の手順で、あたらしい 3 ノードのクラスターが動き始めます。 ### ノード名変更手順 sora.conf の `node_name` を変更する際の手順を示します。 この手順は、例えば Sora が動作するサーバーの IP アドレスが変わり、 `node_name` の IP アドレス部分を 変更する場合に必要になります。 - 対象のノードを停止します - `data/` ディレクトリを削除します- これを忘れるとノード名変更が正しく実行できません、必ず削除してください - クラスターの起動しているノードのいずれかに対し、 [PurgeClusterNode](EXPERIMENTAL_API_CLUSTER.html#13b35a) API を発行し、対象のノードをクラスターから削除します - sora.conf の `node_name` を変更します - 対象のノードを起動します - [JoinCluster](EXPERIMENTAL_API_CLUSTER.html#17f3f5) API でクラスターにあらたに参加します- [contact_node_name_list](CLUSTER.html#a3d0fd) を利用している場合にはこの手順は必要ありません > **警告** > > この手順では、 `data/` ディレクトリの削除を含むため、対象のノードは「未初期化」状態になります。 > 複数のノードの名前変更が必要な場合には、1 ノードずつこの手順を実行することを推奨します。 > 1 ノードの変更のたびに、 [ListClusterNodes](EXPERIMENTAL_API_CLUSTER.html#a70901) を使ってクラスターに正しく > 参加したことを確認して次のノードの手順に取り掛かってください。 #### ノード名を変更する場合の [contact_node_name_list](CLUSTER.html#a3d0fd) の扱い ノード名の変更をするときに、クラスター自動参加を利用する方法を示します。 クラスター自動参加を使わずに [JoinCluster](EXPERIMENTAL_API_CLUSTER.html#17f3f5) API を使う場合は この説明は関係しません。 関連する sora.conf の設定は [contact_node_name_list](CLUSTER.html#a3d0fd) です。 この設定は sora 起動時のときのみ利用されます。 また、一度クラスターに参加して初期化済みとなった場合には、正しいノードリストを知っているため、 この設定は無視されます。 以下、具体的に、3 ノードクラスターがあり、全ノードの IP アドレスが変わる状況を考えます。 状況: - 現状のノード名: `sora1@192.0.2.101`, `sora2@192.0.2.102`, `sora3@192.0.2.103`- 既にクラスターを組んでいる - それぞれを新規のノード名 `sora1@198.51.100.1`, `sora2@198.51.100.2`, `sora3@198.51.100.3` に変更する- まず sora1 を入れ替える - それが成功した後に sora2 を入れ替える - それが成功した後に sora3 を入れ替えと進める 現状のノードでは、既にクラスターを組んでいるため `concact_node_name_list` は利用されません。 そのため、sora.conf の設定を変更する必要はありません。 新しいノードでは、起動時に [contact_node_name_list](CLUSTER.html#a3d0fd) が利用されます。 入れ替えは順番に実行する必要があるため、現状のノードのみが起動中である状態や 新規ノードのみの状態、または混在している状態がありえます。 - 最初に sora1 を入れ替える際には、残り2ノードは現状のノード `sora2@192.0.2.102`, `sora3@192.0.2.103` です - 途中で sora2 を入れ替える際には、残り2ノードは現状のノード `sora3@192.0.2.103` と新規`sora1@198.51.100.1` が混在しています - 最後に sora3 を入れ替える際には、残り2ノードは新規のノード `sora1@198.51.100.1`, `sora2@198.51.100.2` です このパターンに対して、ノード個別に [contact_node_name_list](CLUSTER.html#a3d0fd) を設定するのは複雑になってしまいます。 しかし、 [contact_node_name_list](CLUSTER.html#a3d0fd) に指定したノードのうち、起動していないノードは無視されますので、 既存ノードと新規ノードをすべて `sora1@192.0.2.101`, `sora2@192.0.2.102`, `sora3@192.0.2.103` `sora1@198.51.100.1`, `sora2@198.51.100.2`, `sora3@198.51.100.3` 指定することで、全ノードの入れ替えに対応できます。 > **注釈** > > 既存と新規の対応するノードが同時に起動することがないようにしてください。 > たとえば、 `sora1@198.51.100.1` を起動する前には、かならず `sora1@192.0.2.101` を停止した上で、 > `sora1@192.0.2.101` が再び起動することがないようにしてください。 ### ロードバランサーの導入 クラスター機能を利用した場合は、シグナリング URL に対してロードバランサーが利用できます。 ただし、ロードバランス自体は Sora が行うため、 ロードバランサーの導入はシグナリング URL の 1 本化が目的となります。 - ロードバランサーは WebSocket に対応している必要があります - ロードバランサーで TLS 終端はせず TLS で Sora へ接続する必要があります - Sora はロードバランサー経由以外にクライアントと直接接続できる必要があります- これはリダイレクトが発生し、ロードバランサーを経由せずに接続する可能性があるためです - Sora の WebSocket 通信は 30 秒に 1 回通信を発生させるため、ロードバランサーのタイムアウトは 30 秒以上にする必要があります ```mermaid sequenceDiagram participant C as クライアント participant LB as ロードバランサー participant S1 as Sora1 participant S2 as Sora2 participant A as アプリケーションサーバー C->>LB: wss://sora.example.com/signaling LB->>S1: wss://0001.sora.example.com/signaling note over B,S1: WebSocket 確立 C->>+LB: "type": "connect" LB->>+S1: "type": "connect" S1-->>-LB: "type": "redirect"
"location": "wss://0002.sora.example.com/signaling" LB->>-C: "type": "redirect"
"location": "wss://0002.sora.example.com/signaling" note over B,S1: WebSocket 切断 C->>S2: wss://0002.sora.example.com/signaling note over B,S1: WebSocket 確立 C->>+S2: "type": "connect" S2->>+A: 認証ウェブフック A-->>-S2: "allowed": true S2->>-C: "type": "offer" C->>S2: "type": "answer" note over B,S2: WebRTC 確立 ``` もしシグナリング URL の 1 本化を検討している方で、不明点がある場合はサポートまでご連絡ください。 ### ログの出力 クラスターに関するログは `log/cluster.jsonl` に生成されます。 ログの詳細については [ログファイル](LOG.html) をご確認ください。 ## 注意 ### ライセンス クラスターの 1 ノードにつき 1 ライセンスが必要になります。 3 台のノードでクラスターを構築する場合は 3 ライセンスが必要になります。 > **注釈** > > [最大ノード数ライセンス](LICENSE.html#aee259) を利用することで、同一ライセンスを複数ノードで利用できるようになります。 > クラスターを利用する場合は [最大ノード数ライセンス](LICENSE.html#aee259) を利用することを推奨します。 ### ポートの開放 以下のポートを開放して下さい - epmd(Erlang Port Mapper Daemon)で利用する TCP ポート- 4369 - ノード間通信に利用する TCP ポート- 49010 - 49020 - `sora.conf` の `cluster_listen_{min,max}_port` にて指定できます ### ノード間通信の暗号化 Sora のノード間通信は暗号化されておりません。 そのため、安全なプライベートネットワークの利用を推奨します。 もし、パブリックネットワークを利用してクラスターを構築する場合は、ノード間の通信を暗号化する必要があります。その場合は Tailscale の利用をお勧めします。 [Tailscale · Best VPN Service for Secure Networks](https://tailscale.com/) 参考までに、下記は弊社の Tailscale 利用事例です。 [ベアメタルサーバーを利用したクラウドサービスで発生する課題を Tailscale で解決する · Tailscale](https://tailscale.com/ja/customers/shiguredo/) ### クラスターのノード数 #### 最低ノード数 Sora は最低 3 ノードのクラスターを構築してください。 - 1 ノードで構築されたクラスターはクラスターを構築していないのと同様です - 2 ノードで構築されたクラスターは片方のノードが停止すると、正常なノードも過半数の条件を満たさなくなるため接続を受け付けなくなってしまいます #### 最大ノード数 クラスターを構築するノードの最大数は 10 ノードを想定しています。 これ以上のノード数を検討されている場合はサポートまでご連絡ください。 ### クラスター構成情報ファイル > **危険** > > このファイルは Sora が内部で利用するためのファイルのため、指示がある場合以外は触らないでください。 Sora でクラスターを利用する場合、クラスター参加後のノード情報を永続化するためのファイルを `data/` ディレクトリ以下に生成します。 #### Sora のバージョンアップ時 Sora のバージョンアップ時に `data/` ディレクトリをコピーする必要はありません。 このファイルが無い場合、 Sora の起動の際に生成されます。 ### クラスターからのノードの完全消去について クラスターからノードを完全に消去させる場合は `bin/sora stop` で停止させた後に、 クラスターを構成してる実行中のノードのいずれかに対して、 消去するノードのノード名を target_node_name に指定して [PurgeClusterNode](EXPERIMENTAL_API_CLUSTER.html#13b35a) API を実行します。 > **警告** > > [PurgeClusterNode](EXPERIMENTAL_API_CLUSTER.html#13b35a) API はクラスターからノードを完全に消去するための API です。 > 再度参加するノードに対しては基本的に使用しないでください。 ### PurgeClusterNode API で完全消去したノードの再度の参加 > **警告** > > [PurgeClusterNode](EXPERIMENTAL_API_CLUSTER.html#13b35a) API はクラスターからノードを完全に消去するための API です。 > 通常は、再度参加するノードに対しては使用しないでください。 > ここの説明は、長期間に渡ってクラスターに参加できないため、苦肉の策として > [PurgeClusterNode](EXPERIMENTAL_API_CLUSTER.html#13b35a) API を使った場合の説明です。 > **警告** > > [PurgeClusterNode](EXPERIMENTAL_API_CLUSTER.html#13b35a) APIでクラスターから消去したノードは、 > 以下に示す手順を経ずに再起動してはいけません。 クラスターからノードを完全消去した場合、そのまま再度参加をすることはできません。 再度クラスターに参加する場合は `data/` ディレクトリを削除する必要があります。 PurgeClusterNode API を実行して、さらにそのノードの `data/` ディレクトリを削除した場合、そのノードは 完全に新規のノードとして取り扱われます。 この状態になったノードは新規ノードですので、 [JoinCluster](EXPERIMENTAL_API_CLUSTER.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/` ディレクトリ内のデータ そのため、再利用する場合には下記の手順で、クラスター A に関する情報を無くす必要があります。 - [contact_node_name_list](CLUSTER.html#a3d0fd) は新しい別クラスター B のノードのリストに変更するか、または、リストを空にする - `data/` ディレクトリを削除する > **警告** > > 以上の手順を踏まずに別クラスター B に参加させようとすると、最悪の場合には A と B がひとつになった > クラスターになってしまう場合があります。 上記の手順の後は Sora を起動し、クラスター参加の手順に従って、ノードをクラスターに参加させます。 ## シーケンス図 ### Sora から別ノードへのリダイレクトを要求される ```mermaid sequenceDiagram participant C as クライアント participant S1 as Sora1 participant S2 as Sora2 participant S3 as Sora3 participant A as アプリケーションサーバー C->>S1: "type": "connect" note over S1: このノードは同時接続が多かったので、
Sora2 へリダイレクト提案 S1->>C: "type": "redirect" C->>S2: "type": "connect", "redirect": true S2->>+A: 認証ウェブフック A-->>-S2: 200 OK
{"allowed": true} S2->>C: "type": "offer" C->>S2: "type": "answer" note over C, A: WebRTC 確立 S2->>+A: イベントウェブフック
"type": "connection.created" A-->>-S2: 200 OK ``` # クラスター API > **注意** > > この API は [実験的機能](EXPERIMENTAL.html) のため、正式版では仕様が変更される可能性があります。 ## InitCluster **x-sora-target**: Sora_20221221.InitCluster クラスターを初期化する際に実行する必要がある API です。 クラスター初期化時に、参加させるいずれかのノードに対して行ってください。 `node_name_list` にはクラスターに参加するノードのリストを指定してください。 API が成功すると、そのリストのノードで構成されるクラスターが構築されます。 > **ヒント** > > InitCluster API の実行はひとつのクラスターにつき一度だけ必要です。 > InitCluster API 後に、そのクラスターにノードを追加する場合には [JoinCluster](EXPERIMENTAL_API_CLUSTER.html#17f3f5) API を使います。 > > InitCluster API が次に必要になるのはクラスターが破綻した場合です。 > 詳細は [クラスター破綻からの再構築手順](CLUSTER.html#7c3099) を参照してください。 * - キー - 型 * - 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@192.0.2.8", "node-01@192.0.2.5"]' ``` ## JoinCluster **x-sora-target**: Sora_20211215.JoinCluster 指定したクラスターノードに参加します。 参加したいクラスターに属するノードのいずれかを `contact_node_name` で指定してください。 クラスターに属していれば、どのノードでもかまいません。 - 参加したいクラスターがすでに初期化されている必要があります。 - クラスターに参加するためには、参加したいクラスターの過半数のノードが正常に稼働している必要があります > **注釈** > > 新規にクラスターを作成する場合には、まず [InitCluster](EXPERIMENTAL_API_CLUSTER.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`` * - 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: 1554 content-type: application/json date: Tue, 16 Nov 2021 09:22:16 GMT server: Cowboy [ { "external_api_url": "http://192.0.2.5:3000/", "license_max_connections": 500, "license_max_nodes": 10, "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": "2023.2.0" }, { "api_url": "http://192.0.2.7:3000/", "license_max_connections": 500, "license_max_nodes": 10, "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": "2023.2.0" }, { "external_api_url": "http://192.0.2.8:3000/", "license_max_connections": 500, "license_max_nodes": 10, "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": "2023.2.0" }, { "external_api_url": "http://192.0.2.9:3000/", "license_max_connections": 500, "license_max_nodes": 10, "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": "2023.2.0" }, { "external_api_url": "http://192.0.2.10:3000/", "license_max_connections": 500, "license_max_nodes": 10, "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": "2023.2.0" } ] ``` ## ListClusterChannels **x-sora-target**: Sora_20211215.ListClusterChannels クラスターチャネル割り当て一覧を表示します。 * - キー - 型 - 内容 * - channel_id - string - チャネル ID * - owners - string - 担当ノード owners には以下が含まれます。 * - キー - 型 - 内容 * - node_name - string - ノード名 * - 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: 341 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", "connected": true } ] }, { "channel_id": "lemon", "owners": [ { "node_name": "node-01@192.0.2.5", "connected": true } ] }, { "channel_id": "hisui", "owners": [ { "node_name": "node-03@192.0.2.8", "connected": true } ] }, { "channel_id": "zakuro", "owners": [ { "node_name": "node-03@192.0.2.8", "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.8 \ -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.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: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.8" } ``` ```console $ http POST 127.0.0.1:3001/ x-sora-target:Sora_20220629.PurgeClusterNode \ target_node_name=node-03@192.0.2.8 \ -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.8" } 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.8" }, "error_type": "NODE-IS-ALIVE" } ``` # 開発者ツール ## 概要 時雨堂がオープンソースとして開発している [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 サーバーへ参加してください。 開発者ツールについての質問やバグ報告は Discord の `#sora-tool-faq` チャンネルにお願いします。 # マルチストリーム機能 ## 概要 マルチストリームとは一つの PeerConnection の中で複数の映像や音声を動的に追加したり削除したりする仕組みです。 この機能を利用することで、複数の PeerConnection を管理せずに複数の映像や音声、データのやりとりが利用できます。 > **注釈** > > Sora ではデフォルトでマルチストリームを利用します。 ## 制限 - 配信側は音声 1 トラック、映像 1 トラック固定です - 動的に配信側のトラックを追加したりするマルチトラックには対応していません ## ブラウザ Chrome、Firefox、Safari、Edge と主要ブラウザすべてでマルチストリームを利用できます。 ## SDK 全ての SDK でマルチストリームを利用できます。 ## シグナリング仕様 > **重要** > > Sora の SDK を利用する場合は、ここに書かれているシグナリングの仕様を把握する必要は基本的にありません。 マルチストリームを利用する場合は、ユーザーが参加や離脱をするたびに SDP を交換する必要があります。 ### "type": "connect" マルチストリームはデフォルトで有効になっています。 ```javascript { "type": "connect", "role": "sendrecv", "channel_id": "sora" } ``` マルチストリームを無効にする場合は `"type": "connect"` 時に `"multistream": false` を追加しますが、 マルチストリームを無効にすることは推奨しません。基本的にマルチストリームを有効にしたまま利用してください。 ```javascript { "type": "connect", "role": "sendrecv", "channel_id": "sora", "multistream": false } ``` ### "type": "re-offer" ```javascript { "type": "re-offer", "sdp": ".." } ``` ### "type": "re-answer" `"type": "re-offer"` が送られてきた場合、 クライアントから Sora へ送るメッセージは `"type": "re-answer"` を送る必要があります。 ```javascript { "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` に指定することで無効にできます。 > **注釈** > > 設定を無効にした状態で、高いビットレートの配信者が増えていく場合、 > クライアント側の転送量が増え、さらにデコードの負荷も高くなってしまいます。 > そのため配信が安定的にできなくなり、結果的にクライアント側で配信ビットレートを下げるといった挙動が発生します。 > > 参加者が増えた場合でも高いビットレートを維持したいという状況ではない限りは設定を無効にすることは推奨しません。 ## シーケンス図 ```mermaid sequenceDiagram autonumber participant C1 as クライアント1 participant C2 as クライアント2 participant S as Sora note over C1,S: クライアント1 認証成功 S->>+C1: "type": "offer" C1->>-S: "type": "answer" note over C1,S: クライアント1 WebRTC 確立 S->>C1: シグナリング通知
クライアント1
"type": "connection.created" note over C1,S: クライアント2 認証成功 S->>+C2: "type": "offer" C2->>-S: "type": "answer" S->>+C1: "type": "re-offer" C1->>-S: "type": "re-answer" note over C1,S: クライアント2 WebRTC 確立 par S->>C2: シグナリング通知
クライアント1
"type": "connection.created" and S->>C1: シグナリング通知
クライアント2
"type": "connection.created" end C2->>S: "type": "disconnect" S->>C2: WebSocket Close S->>C1: シグナリング通知
クライアント2
"type": "connection.destroyed" ``` # サイマルキャスト機能 ## 概要 サイマルキャスト (Simulcast) は、配信時に 1 つの RTCPeerConnection から複数種類のエンコードした映像を配信する技術です。 映像を配信する際、 Sora に対して、 1 つの RTCPeerConnection で複数種類のエンコードした映像を送信することにより、 受信者がどの映像を受信するかを選択できるようになります。 ## 注意 ### 現時点でのサイマルキャストの仕様 2024 年 4 月 時点でサイマルキャストで出力されるストリームの本数は解像度とビットレートに依存しています。 **解像度とビットレートとストリーム数の関係** * - 解像度 - ビットレート - ストリーム数 * - 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 に対応済みです。 > **注釈** > > Chrome M113 以降では JavaScript SDK を利用することで VP9 と AV1 利用できます。 ### 配信ブラウザの対応状況 **Firefox は配信に対応していません** 配信側は Chrome と Edge と Safari の最新バージョンに対応しています。 ### 視聴ブラウザの対応状況 視聴側は Chrome と Safari と Firefox と Edge の最新バージョンに対応しています。 ### 映像コーデック 配信時に利用できる映像コーデックは VP8 と VP9 と AV1 と H.264 と H.265 です。 ### VP9 と AV1 でのサイマルキャスト VP9 や AV1 でサイマルキャストを行う場合、ブラウザでは配信側が Chrome M113 以降である必要があります。 また設定では `scalabilityMode` と `scaleResolutionDownBy` の 2 つを設定する必要があります。 詳細は [scalabilityMode](SIMULCAST.html#918c4d) を参照してください。 ### H.265 でのサイマルキャスト H.265 でサイマルキャストを行う場合、ブラウザでは Safari Technology Preview の実験的機能で WebRTC H265 を有効にする必要があります。 ### 非対応機能 **以下はすべて今後対応予定です** - ULPFEC 機能には対応していません ## 映像の優先度 サイマルキャストでは 1 つのクライアントからの同じ映像を複数のエンコードで配信できます。 Sora では 1 つのクライアントから最大 3 種類のエンコードで映像を受信する仕組みが入っています。 この 3 種類の映像のそれぞれに r0 / r1 / r2 の 3 つの値を定義しています。 この値は rid と呼ばれています。 配信継続の優先度は r0 > r1 > r2 です。 例えば、回線が不安定だったりマシンの負荷が高かった場合、rid が r2 の映像の配信が最初に停止します。 さらに配信状況が悪化した場合は rid が r1 の映像の配信が停止します。 r0 の映像は必ず配信されます。 ## 映像の種類のデフォルト Sora ではサイマルキャストで配信する映像の種類にデフォルト値を設定しています。 ```javascript [ {"rid": "r0", "active": true, "scalabilityMode": "L1T1", "scaleResolutionDownBy": 4.0}, {"rid": "r1", "active": true, "scalabilityMode": "L1T1", "scaleResolutionDownBy": 2.0}, {"rid": "r2", "active": true, "scalabilityMode": "L1T1", "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 ファイルの記述方法 ```javascript [ {"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 で払い出す記述方法 ```javascript { "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 - scalabilityMode- **この設定は Chrome 113 / Edge 113 以降でしか利用できません** - オプション - string ### active: false の挙動 r1 の active を false にカスタマイズしている配信で r1 を受信をリクエストした場合、r0 が配信されます。 ```javascript [ {"rid": "r0", "active": true}, {"rid": "r1", "active": false}, {"rid": "r2", "active": true} ] ``` r0 の active を false にカスタマイズしている配信で r0 を受信をリクエストした場合、r1 が配信されます。 ```javascript [ {"rid": "r0", "active": false}, {"rid": "r1", "active": true}, {"rid": "r2", "active": true} ] ``` r0 と r1 の active を false にカスタマイズしている配信で r0 を受信をリクエストした場合、r2 が配信されます。 ```javascript [ {"rid": "r0", "active": false}, {"rid": "r1", "active": false}, {"rid": "r2", "active": true} ] ``` ### scalabilityMode **この設定は Chrome / Edge M113 以降でのみ有効です** > **注釈** > > [PSA: VP9/AV1 simulcast support in M113](https://groups.google.com/g/discuss-webrtc/c/-QQ3pxrl-fw?pli=1) > Chrome では VP9/AV1 サイマルキャストが利用できますが、Edge では VP9 サイマルキャストのみです。 VP9 または AV1 でサイマルキャストを利用する場合の条件として、 `scalabilityMode` と `scaleResolutionDownBy` を両方をすべての rid に対して設定する必要があります。 サイマルキャスト利用時に `scalabilityMode` に設定可能な値は `L1T1` 、 `L1T2` 、 `L1T3` のみです。 デフォルトでは `L1T1` が指定されています。特に理由がなければ `L1T1` を利用してください。 > **重要** > > AV1 でサイマルキャストやスポットライトを利用し、録画をする場合は `L1T1` を利用してください。 > L1T1 以外では正常に録画がされません。 #### 例 ```javascript [ {"rid": "r0", "active": true, "scaleResolutionDownBy": 4.0, "scalabilityMode": "L1T3"}, {"rid": "r1", "active": true, "scaleResolutionDownBy": 2.0, "scalabilityMode": "L1T3"}, {"rid": "r2", "active": true, "scaleResolutionDownBy": 1.0, "scalabilityMode": "L1T3"} ] ``` ## 配信側の利用方法 シグナリング開始時に指定できます。 ### シグナリング開始時 シグナリングの `"type": "connect"` 時に `"simulcast": true` を指定することで、有効になります。 映像コーデックは `VP8` または `H264` を選択してください。 ```javascript { "type": "connect":, "role": "sendonly", "channel_id": "sora", "video": {"codec_type": "VP8"}, "multistream": false, "simulcast": true } ``` マルチストリーム利用時にも利用できます。 ```javascript { "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` を選択してください ```javascript { "type": "connect":, "role": "recvonly", "channel_id": "sora", "video": {"codec_type": "VP8"}, "multistream": false, "simulcast": true, "simulcast_rid": "r2" } ``` マルチストリーム利用時にも指定できます。 ```javascript { "type": "connect":, "role": "recvonly", "channel_id": "sora", "video": {"codec_type": "VP8"}, "multistream": true, "simulcast": true, "simulcast_rid": "r2" } ``` ## 視聴側のストリームの変更 API 詳細は [サイマルキャスト API](API_SIMULCAST.html#adcbc8) をご確認ください ## シーケンス図 ```mermaid sequenceDiagram participant C1 as クライアント1 participant S as WebRTC SFU Sora participant C2 as クライアント2 C1->>S: "type": "connect",
"role": "sendonly",
"simulcast":"true" note over C1, S: クライアント1 WebRTC 確立 C2->>S: "type": "connect",
"role": "sendonly",
"simulcast":"true",
"simulcast_rid": "r1" note over C2, S: クライアント2 WebRTC 確立 par C1-)S: 映像
rid: r0 and C1-)S: 映像
rid: r1 S-)C2: 映像
rid: r1 and C1-)S: 映像
rid: r2 end ``` # スポットライト機能 > **重要** > > この機能は VP8 または H.264 で利用できます。また、Chrome M113 以降では JavaScript SDK を利用することで VP9 と AV1 でも利用できます。 ## 概要 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_SIMULCAST.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 ではスポットライトで配信する映像の種類にデフォルト値を設定しています。 ```javascript [ {"rid": "r0", "active": true, "scalabilityMode": "L1T3", "maxFramerate": 5.0, "scaleResolutionDownBy": 4.0}, {"rid": "r1", "active": true, "scalabilityMode": "L1T3", "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 ファイルの記述方法 ```javascript [ {"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 で払い出す記述方法 ```javascript { "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 - scalabilityMode- **この設定は Chrome でしか利用できません** - オプション - string - 詳細は [scalabilityMode](SIMULCAST.html#918c4d) を参照してください ## フォーカスする配信数 フォーカスする配信数はチャネル 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 サイマルキャスト無効。 ```javascript { "type": "connect", "channel_id": "sora", "role": "sendrecv", "spotlight": true, "simulcast": false, "multistream": true, "video": { "codec_type": "VP8", "bit_rate": 800 } } ``` #### spotlight_number フォーカス数はデフォルトの 1 ```javascript { "type": "connect", "channel_id": "sora", "role": "sendrecv", "spotlight": true, "simulcast": true, "multistream": true, "video": { "codec_type": "VP8", "bit_rate": 800 } } ``` フォーカス数は指定した値の 5 ```javascript { "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 を指定) といった設定もできます。 ```javascript { "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_SPOTLIGHT.html#cb7b53) をご確認ください。 - [FocusSpotlightFixed](API_SPOTLIGHT.html#beaf88) API- 特定のクライアントにフォーカスし続ける API - [FocusSpotlight](API_SPOTLIGHT.html#90a256) API- 特定のクライアントにフォーカスする API - [UnfocusSpotlight](API_SPOTLIGHT.html#1390bc) API- 特定のクライアントからアンフォーカスする API - [ChangeSpotlightNumber](API_SPOTLIGHT.html#17e930) API- フォーカスする数を変更する API - [RequestSpotlightRid](API_SPOTLIGHT.html#5c2650) API- 特定のクライアントのフォーカス/アンフォーカス時の rid を変更する API - [ResetSpotlightRid](API_SPOTLIGHT.html#680344) API- 特定のクライアントのフォーカス/アンフォーカス時の rid をリセットする API - [BatchRequestSpotlightRid](API_SPOTLIGHT.html#a2e06c) API- フォーカス/アンフォーカス時の rid を一括で変更する API ## シーケンス図 ```mermaid sequenceDiagram participant C1 as クライアント1 participant S as WebRTC SFU Sora participant C2 as クライアント2 C1->>S: "type": "connect",
"role": "sendrecv"
"spotlight": true,
"multistream": true,
"simulcast": true note over C1,S: クライアント1 WebRTC 確立 par C1-)S: 映像
rid: r0 and C1-)S: 映像
rid: r1 end C2->>S: "type": "connect",
"role": "sendrecv"
"spotlight": true,
"multistream": true,
"simulcast": true note over C2,S: クライアント2 WebRTC 確立 par C2-)S: 映像
rid: r0 and C2-)S: 映像
rid: r1 end par S-)C2: クライアント1映像
rid: r0 and S-)C1: クライアント2映像
rid: r0 end note over C1: クライアント1が話し始める S-)C2: クライアント1音声 note over C1: しゃべり初めて 2 秒経過 note right of S: r0 の代わりに r1 映像を配信 S-)C2: クライアント1映像
rid: r1 ``` # OBS Studio (WHIP) 対応機能 > **注意** > > この機能を利用する場合は事前にサポートまでご連絡ください > **警告** > > この機能は [実験的機能](EXPERIMENTAL.html) のため、正式版では仕様が変更される可能性があります ## 概要 [OBS Studio](https://obsproject.com/) が対応している [WHIP](https://datatracker.ietf.org/doc/html/draft-ietf-wish-whip) を利用した WebRTC 配信に対応しています。 ここでは Sora や OBS の WHIP 仕様について説明します。 ## 注意 - OBS の WHIP 実装の仕様を正としており RFC ドラフトの WHIP 仕様とは異なる可能性があります - Sora は [WHEP](https://datatracker.ietf.org/doc/html/draft-murillo-whep) へ対応していません - Sora SDK は WHIP や WHEP へ対応していません ### WHIP クライアントのお問い合わせについて WHIP クライアントに関する質問などの報告は Discord の利用をお願いします。 **URL**: Sora の WHIP クライアントについての質問やバグ報告は Discord の `#sora-sdk-faq` チャンネルにお願いします。 ## WHIP とは何か > **参考** > > [WebRTC-HTTP ingestion protocol (WHIP)](https://datatracker.ietf.org/doc/html/draft-ietf-wish-whip) WHIP は WebRTC-HTTP ingestion protocol の略で、 WebRTC では標準化されていないシグナリングをブロードキャスト/ストリーミング系の配信ツール向けに規定した規格です。 WHIP は仕様を小さくして、実装を簡単にすることで配信ツールが取り込みやすくしています。 クライアントが HTTP POST で Offer SDP を送信して、Answer SDP を受け取るというシンプルなシグナリング規格です。 OBS 30.0.0 にて WebRTC/WHIP が正式にサポートされました。 以下からダウンロードができます。 ### WHIP のシーケンス図 ```mermaid sequenceDiagram participant OBS as OBS participant WE as WHIP Endpoint participant MS as Media Server participant WS as WHIP Resource OBS->>+WE: HTTP POST (SDP Offer) WE-->>-OBS: HTTP 201 Created (SDP Answer) note over OBS,MS: WebRTC Connection OBS->>+WS: HTTP DELETE WS->>-OBS: HTTP 200 OK ``` ### Sora の WHIP のシーケンス図 Sora では WHIP エンドポイント、WHIP リソース、メディアサーバーすべてを Sora が担当します。 ```mermaid sequenceDiagram participant OBS as OBS participant S as Sora participant A as App OBS->>+S: HTTP POST (SDP Offer) S->>+A: 認証ウェブフック A-->>-S: 200 OK
allowed : true S-->>-OBS: HTTP 201 Created (SDP Answer) note over OBS,S: WebRTC Connection S->>+A: イベントウェブフック
connection.created A-->>-S: 200 OK OBS->>+S: HTTP DELETE S->>+A: イベントウェブフック
connection.destroyed A-->>-S: 200 OK S->>-OBS: HTTP 200 OK ``` ## OBS の WHIP 対応について > **警告** > > OBS の WHIP 対応については Discord の #sora-sdk-faq にてご相談ください。 [OBS 30.0.0](https://github.com/obsproject/obs-studio/releases/tag/30.0.0) の WHIP 対応では輻輳制御が実装されていません。 これは OBS の WHIP 対応するために利用している [libdatachannel](https://libdatachannel.org/) が輻輳制御に対応していないためです。 そのため、回線が不安定になったとしても、ビットレートを下げたりするといったことは行いません。 ## OBS 以外の WHIP クライアントへの対応について > **重要** > > Sora の WHIP 実装は OBS の WHIP 対応のみをサポートしています。 > それ以外のクライアントの WHIP 実装には対応していません。 新しい WHIP クライアントへの対応は有償での優先実装として対応を検討できますので、 対応希望の WHIP クライアントと優先実装については、サポートまでメールにてご連絡ください。 - GStreamer - FFmpeg ## Sora での利用方法 `sora.conf` にて [whip](SORA_CONF.html#615414) を `true` に指定してください。 ```ini whip = true ``` ### Bearer トークンを利用した認証機能を利用する場合 `sora.conf` にて [whip_bearer_token_metadata_key](SORA_CONF.html#699f57) を指定してください。 ```ini whip_bearer_token_metadata_key = access_token ``` 例えば、 `access_token` という文字列をした場合、 WHIP 接続時、認証ウェブフックに `"metadata": {"access_token": """}` が入ってきます。 `whip_bearer_token` を指定した場合は `"metadata": {"whip_bearer_token": """}` が入ってきます。 `whip_bearer_token_metadata_key` が未指定の場合は、 Bearer トークンが WHIP 接続時に送られてきたとしても Sora は無視して、 `metadata` も生成しません。 ## OBS での利用方法 OBS での利用方法は以下の通りです。 ![image](https://i.gyazo.com/f68934ea04634b0b845f3ae0d17ca4b3.jpg) 1. サービスに WHIP を選ぶ 2. サーバーに Sora が提供する WHIP エンドポイント URL を指定する- デフォルトでは `http://127.0.0.1:5000/whip/` 3. Bearer トークンには好きな文字列を指定する- Sora の認証ウェブフックの項目 `whip_bearer_token_metadata_key` で指定した値をキーとして、`"metadata": {"": """}` が認証サーバーに送信されます ### 切断方法 `Location` ヘッダーに入ってくるリソースエンドポイント URL に DELETE リクエストを送ることで切断できます。 OBS は配信終了することで切断リクエストを送りますので、意識する必要はありません。 ## Sora の OBS (WHIP) の挙動 - Sora は WHIP エンドポイント URL を提供します- デフォルトでは `http://127.0.0.1:5000/whip/` です - Sora の WHIP エンドポイントからの配信は、マルチストリームかつ配信のみ(sendonly)として扱われます - Sora の WHIP エンドポイントを利用した配信では、シグナリング通知は現時点では利用できません - Sora の WHIP リソース URL は WHIP エンドポイントのレスポンスに含まれる Location ヘッダーにて払い出されます ## WHIP エンドポイント URL Sora の OBS (WHIP) 対応は `"multistream": true, "role": "sendonly"` として機能します。 ### チャネル ID の指定 OBS ではリクエスト時に JSON でチャネル ID を指定することができません。そのため WHIP エンドポイント URL に `channel_id` を含めて指定します。 channel_id に URL に利用できない文字が含まれている場合は URL エンコードしてください。 `HTTP POST https://sora.example.com/whip/` `channel_id` が sora の WHIP エンドポイント URL 例: ``` https://sora.example.com/whip/sora ``` WHIP エンドポイントへの HTTP リクエストに対するレスポンスコードは 201 Created です。 ## WHIP リソース URL Sora では WHIP リソースエンドポイントは Location ヘッダーに含まれています。 以下は切断する例です。 `HTTP DELETE https://sora.example.com/whip-resource//` 以下は Trickle ICE を利用する例です。 `HTTP PATCH https://sora.example.com/whip-resource//` `` は 32 バイトのランダムな値を base32 でエンコードした文字列です。 WHIP リソース URL 例: ``` https://sora.example.com/whip-resource/sora/QBF6AFDWZGWM97BNS5YCBSXM54M01D0TFQ48MC9Z3ZJG8YPRQ1Z0 ``` > **注釈** > > OBS に Bearer トークンを指定した場合は、WHIP リソースエンドポイント URL にも Bearer トークンは送られます ## 認証仕様 WHIP では認証に Bearer トークンを指定することができます。 OBS でも認証情報に Bearer トークンを指定できます。 Sora は `sora.conf` で `whip_bearer_token_metadata_key` に文字列を指定していた場合、 OBS の HTTP POST 時に Authentication ヘッダーで送られてきた Bearer トークンを、 認証ウェブフックの `metadata` に `{"": ""}` を設定して認証サーバーに送信します。 Sora 自体は Bearer トークンのチェックやデコードなどは行いません。これらは認証ウェブフックのリクエストを受信した認証サーバーが行う必要があります。 ## ウェブフック仕様 ### whip `true` が入ってきます。 ### metadata `sora.conf` にて `whip_bearer_token_metadata_key` に指定した文字列をキーとして `metadata` に入ってきます。 ```ini whip_bearer_token_metadata_key = whip_bearer_token ``` もし文字列を `whip_bearer_token` にしていた場合は、 `"metadata": {"whip_bearer_token": ""}` が送られてきます。 OBS 側に設定した Bearer Token の値がそのまま入ってきます。 ### multistream `true` が入ってきます。 ### role `sendonly` が入ってきます。 ### channel_id WHIP エンドポイント URL に渡した値が利用されます。 > **注釈** > > URL デコード済みの値が入ります ### client_id WHIP エンドポイント URL にクエリ文字列として `client_id=` を指定した場合、その値が利用されます。 > **注釈** > > URL デコード済みの値が入ります ### bundle_id WHIP エンドポイント URL にクエリ文字列として `bundle_id=` を指定した場合、その値が利用されます。 > **注釈** > > URL デコード済みの値が入ります ### spotlight WHIP エンドポイント URL にクエリ文字列として `spotlight=` を指定した場合、その値が利用されます。 既知の問題として `spotlight = true` を指定して接続した場合、音声がそのままでは配信されません。 [FocusSpotlightFixed](API_SPOTLIGHT.html#beaf88) API を利用して OBS の接続にフォーカスを当てる必要があります。 詳細は [既知の問題 - OBS (WHIP) 対応機能](KNOWN_ISSUES.html#064ec7) を参照してください。 > **注釈** > > URL デコード済みの値が入ります ### audio / video OBS 側で指定した値を利用します。 OBS では音声は Opus のみ、映像は H.264 と AV1 が利用できます。 - `audio: true` - `audio_codec_type: "OPUS"` - `video: true` - `video_codec_type: "H264" | "AV1"` OBS 利用時にはビットレートの指定できないため、 Sora のデフォルトの値が入ってきますが、 OBS の WHIP 実装では SDP での最大ビットレートを無視します。 そのため OBS 側で設定したビットレートで配信が行われます。 ### simulcast > **注意** > > 現時点では OBS の WHIP 対応はサイマルキャストに未対応です。OBS 側の対応待ちです。 現時点では `false` が入ってきます。 ### その他 - `e2ee: false` - `spotlight: false` - `data_channel_signaling: false` - `ignore_disconnect_webhook: false` - `turn_transport_type: udp`- TURN が利用不可能な WHIP 実装の場合は udp が割り当てられます - TURN が利用可能な WHIP 実装の場合は udp または tcp が適切に割り当てられます ## クラスター利用時の挙動 > **注意** > > 現時点では OBS の WHIP 対応は `Link` ヘッダーを利用した TURN Urls の払い出しに未対応です。OBS 側の対応待ちです。 現時点ではクラスター利用時に、接続したノードが指定した `channel_id` の担当ノードでは無い場合、 担当ノードの IP アドレスを Answer SDP に含めます。 ### 将来的に OBS の WHIP 対応で TURN が対応された場合 クラスター利用時に、接続したノードが指定した `channel_id` の担当ノードでは無い場合、 担当ノードの TURN URLs を Link ヘッダーにて払い出します。 ## シーケンス図 ### シングルノード ```mermaid sequenceDiagram participant O as OBS participant S as Sora participant A as App O->>+S: HTTP POST https://sora.example.com/whip/
Offer SDP S->>+A: 認証ウェブフック

"channel_id": """multistream": true
"role": "sendonly" A-->>-S: "allowed": true S-->>-O: HTTP 201 Created
Answer SDP Note left of S: このタイミングで Link ヘッダーで、
TURN URLs を払い出す note over O,S: ICE 確立 note over O,S: DTLS 確立 note over O,S: WebRTC 確立 S->>+A: イベントウェブフック
"connection.created" A-->>-S: HTTP 200 OK O-)S: SRTP O-)S: SRTP O->>+S: HTTP DELETE https://sora.example.com/whip// S-->>-O: HTTP 200 OK note over O,S: WebRTC 終了 ``` ### マルチノード マルチノードを利用する場合、OBS に設定する WHIP エンドポイントは LB が提供するエンドポイントを利用します。 このシーケンス図では Sora が 2 ノードになっていますが、最低 3 ノード必要です。 ```mermaid sequenceDiagram participant O as OBS (WHIP) participant B as ブラウザ participant LB as LB participant S1 as Sora 1 participant S2 as Sora 2 participant A as App par B-xS1: WSS
https://node1.sora.example.com/signaling and B->>S2: WSS
https://node2.sora.example.com/signaling
note over B,S2: WebSocket 確立 end B->>S2: WSS "type": "connect" S2->>+A: 認証ウェブフック
"channel_id": "sora"
"multistream": true
"role": "recvonly" A-->>-S2: "allowed": true S2-)B: "type": "offer" B-)S2: "type": "answer" note over B,S2: WebRTC 確立 O->>+LB: HTTP POST
https://sora.example.com/whip/sora
Offer SDP LB->>+S1: HTTP POST
https://node2.sora.example.com/whip/sora
Offer SDP S1->>+S2: 担当ノードに内部通信で処理を Proxy S2->>+A: 認証ウェブフック
"channel_id": "sora"
"multistream": true
"role": "sendonly" A-->>-S2: "allowed": true S2-->>-S1: Sora 2 の IP アドレス または TURN URLs S1-->>-LB: HTTP 201 Created
Answer SDP LB-->>-O: HTTP 201 Created
Answer SDP Note left of S2: このタイミングで Link ヘッダーで、
TURN URLs を払い出す note over O,S2: WebRTC 確立 S1->>+A: イベントウェブフック
"connection.created" A-->>-S2: HTTP 200 OK O-)S2: SRTP S2-)B: SRTP O-)S2: SRTP S2-)B: SRTP O->>+S2: HTTP DELETE
https://node2.sora.example.com/whip/sora/ S2-->>-O: HTTP 200 OK note over O,S2: WebRTC 終了 ``` # TURN 機能 Sora は TURN 機能を内蔵しています。そのため TURN サーバーを別途立てる必要はありません。 ## 推奨設定 一番接続率が高くなる設定は以下の通りです。 - TURN-TCP を 443 番ポートで待ち受け - TURN-TLS を 443 番ポートで待ち受け 上記設定をしたい場合は [TURN-TLS、TURN-TCP、シグナリングで 443 番ポートを使用する](PRODUCTION.html#14258d) をご確認ください。 ## TURN はすべて同時に試される **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 - 外部サーバーから払い出し- なし - sora.conf の 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.jsonl` に `warning` メッセージが出力されます。 ## 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 のポートは動的に決まります。 ```mermaid sequenceDiagram autonumber participant C as クライアント participant nginx participant S as Sora C->>nginx: "type": "connect" over WSS note right of nginx: TLS 終端 nginx->>S: "type": "connect" over WS S->>nginx: "type": "offer" over WS nginx->>C: "type": "offer" over WSS C->>nginx: "type": "answer" over WSS note right of nginx: TLS 終端 nginx->>S: "type": "answer" over WS par C->>S: TURN-UDP Allocate-Request port=52520 and C->>nginx: TURN-TCP Allocate-Request port=443 nginx->>S: TURN-TCP Allocate-Request port=3478 and C->>nginx: TURN-TLS Allocate-Request port=443 note right of nginx: TLS 終端 nginx->>S: TURN-TCP Allocate-Request port=3478 end S->>C: TURN-UDP Allocate-Success C->>+S: TURN-UDP Permission-Request port=52520 S-->>-C: TURN-UDP Permission-Success C->>+S: TURN-UDP Channel-Request port=52520 S-->>-C: TURN-UDP Channel-Success C->>S: DTLS ClientHello over TURN port=52520 ``` # 録画機能 (セッション単位) ## レガシー録画機能から録画機能(セッション単位)への移行 [レガシー録画機能から新しい録画機能 (セッション単位) への移行](LEGACY_RECORDING_TO_RECORDING.html) を確認してください。 ## 概要 Sora では、配信している映像や音声を録画、録音して保存できます。 配信されている映像をできるかぎりそのまま保存するため、CPU リソースを最小限に抑えることができます。 出力される録画ファイルは WebM 形式です。映像のみの録画、音声のみの録音にも対応しています。 録画時には一切トランスコードを行っていません。配信された映像や音声をそのままに記録します。 ## 用語 **単一録画ファイル** : 切断または [StopRecording](API_RECORDING.html#fd0de5) API が実行されるか、録画期限が切れるか、セッションが終了した場合に一つのファイルとして出力される動画ファイル **分割録画ファイル** : `split_duration` で指定した時間ごとに区切られ分割されて出力される動画ファイル ## 録画ファイルの出力 録画ファイルの出力には 3 パターンあります。 ### 単一録画ファイルのみ出力 - `split_only` が未指定、または `false` に設定されている - `split_duration` が未指定 - `expire_time` は指定されていてもよい 上記を満たした場合、1 接続で 1 つ録画ファイルが出力されます。 ### 分割録画ファイルのみ出力 - `split_only` が `true` に指定されている - `split_duration` が指定されている - `expire_time` は指定されていてもよい 上記を満たした場合、分割された録画ファイルのみが出力されます。 ### 単一録画ファイルと分割録画ファイルの両方が出力 - `sora.conf` で `recording_dual_output` が `true` に指定されている - `split_only` が未指定、または `false` に指定されている - `split_duration` が指定されている - `expire_time` は指定されていてもよい 上記を満たした場合、 1 接続で 1 つの録画ファイルと分割された録画ファイルの両方が出力されます。 イベントウェブフックも単一録画、分割録画、両方のイベントウェブフックリクエストが送信されます。 ## 制限 ### コーデック 録画 (録音) は、映像コーデックに VP8 と VP9 と H.264 と AV1 、また音声コーデックに Opus と Lyra を選択した場合のみ利用できます。 > **警告** > > H.265 の録画には非対応です。 ### 解像度 WebRTC では配信側の CPU リソースが不足した場合や、 回線の品質が悪化した場合に解像度を動的に変更します。 そのため録画したデータの途中で解像度が低くなる可能性があります。 ### 音声や映像のクライアント側でのトラック削除 クライアント側でシグナリング接続時に音声や映像を有効にした状態で、 クライアント側で音声トラック、または映像トラックのどちらかを削除した場合でも録画は行われます。 さらに追加して戻した形であれば録画側も戻ります。 ただし、音声と映像両方のトラックを削除した場合は正常に録画が行われません。 ### マルチストリーム機能での録画 対応しています。 ### サイマルキャスト機能での録画 対応しています。 サイマルキャストを利用している際の録画は **一番優先度が低い** ストリーム、すなわちデフォルトでは最も高い画質の映像を録画します。 詳細はサイマルキャストの [映像の優先度](SIMULCAST.html#36c708) をご確認下さい。 ### スポットライト機能での録画 対応しています。 サイマルキャストを利用している際の録画は **一番優先度が低い** ストリーム、すなわちデフォルトでは最も高い画質の映像を録画します。 詳細はサイマルキャストの [映像の優先度](SIMULCAST.html#36c708) をご確認下さい。 ### キーフレーム要求間隔 録画機能利用時の Sora からのキーフレーム要求間隔は 20 秒に固定されています。 そのため、分割録画の最小時間は 20 秒 + `split_duration` に指定した秒数となります。 もし録画時のキーフレーム要求間隔を変更したい場合は、サポートまでご連絡ください。 ## 無変換録画 WebRTC 経由で流れてきている映像や音声を変換せず、 そのまま録画するファイルの形式に組み立て直してファイルを保存します。 そのため、CPU リソースを最小限に抑えられます。 ブラウザでの録画など、通常の録画は変換が入るため CPU に多くの負荷がかかります。 変換を行わないため、録画を終了した数秒後には録画したファイルを取得できます。 解像度は送られてきた映像の最大値を録画ファイルの解像度として使用します。 ## 録画の開始と終了について Sora の録画機能は **明示的にチャネルの録画を停止するか、 チャネルの録画開始から指定した期限が過ぎるか、 チャネルのセッションが終了するまでは、 そのチャネルでの配信を自動で録画する** といった機能になります。 ## 接続単位の録画ブロックについて 認証成功時に `"recording_block": true` を払い出すことでその接続の録画をブロックし、録画ファイルの出力を行わないようにすることができます。 録画ブロックは認証成功時の払い出し時のみ指定ができます。それ以外では指定できません。 そのため、録画ブロックの途中解除はできません。 ### シーケンス図 ```mermaid sequenceDiagram autonumber participant C as クライアント participant S as Sora participant A as アプリケーションサーバー C->>+S: "type": "connect" S->>+A: 認証ウェブフック A-->>-S: 200 OK
"recording_block": true S-->>-C: "type": "offer" C->>S: "type": "answer" note over C,A: WebRTC 確立 S->>+A: セッションウェブフック: "session.created" A-->>-S: 200 OK
"recording": true note over C,A: 録画開始 S->>+A: セッションウェブフック
"type": "recording.started" A-->>-S: 200 OK note over C,A: 録画ブロックしているため "archive.started" が飛ばない
さらに録画ファイルは出力されない ``` ## sora.conf の設定による録画指定制限 録画ファイルが大きくならないように、sora.conf の指定で録画開始時のオプションを制限することができます。 設定の詳細は以下をご確認ください。 - [recording_max_expire_time](SORA_CONF.html#f3ff8d) - [recording_max_split_duration](SORA_CONF.html#927da9) - [recording_expire_time_required](SORA_CONF.html#fcfa2d) - [recording_dual_output](SORA_CONF.html#4cc9c0) ## 録画関連イベントのウェブフックについて ### session.created ウェブフック > **注意** > > [sora.conf の設定による録画指定制限](RECORDING.html#a56297) を行っていた場合、制限に該当する指定を行っている場合は録画が開始されません。 払い出し時に以下の項目が指定できます。 - recording- boolean - そのセッションでの録画を開始するかどうかを指定します - オプション - recording_expire_time- integer - そのセッションでの録画期限を指定します - デフォルト値は未定義で、期限なしです - 指定する場合 0 より大きな値を指定してください - 単位は秒です - オプション - recording_split_only- boolean - そのセッションでの録画を分割のみにするかを指定します - デフォルト値は false で、分割を行いません - オプション - recording_split_duration- integer - そのセッションでの録画を分割する場合の分割時間を指定します - recording_split_only が true の場合は指定が必須です - オプション - recording_metadata- json value - そのセッションでの録画メタデータを指定します - オプション ### recording.started セッションウェブフック > **注釈** > > レガシー録画ではイベントウェブフックでしたが、セッションウェブフックに変更されています 録画開始 API が実行されたタイミングで `recording.started` リクエストを送信します。 詳しくは [recording.started](SESSION_WEBHOOK.html#9b5c58) をご確認ください。 ### recording.report セッションウェブフック 録画終了 API が実行されたか、 録画の期限が切れたか、 セッションが終了したタイミングで `recording.report` リクエストを送信します。 > **注釈** > > セッションが終了したタイミングでの `recording.report` は `session.destroyed` の **後** に送信されます。 詳しくは [recording.report](SESSION_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 は省略しています** ```javascript { "audio": true, "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": true, "video_bit_rate": 1000, "video_codec_type": "VP9", "video_vp9_params": { "profile_id": 0 }, "video_height": 480, "video_width": 640 } ``` ### report- 録画終了時に、それまでにそのセッションで録画したファイル一覧が記載されているレポートファイルが JSON 形式で出力されます。 録画終了は [StopRecording](API_RECORDING.html#fd0de5) API を使用して指定したチャネルに対する録画を停止するか、 録画の期限が切れるか、セッションが終了するかの 3 つのパターンがあります。 このファイルは主にマルチストリームや途中で切れてしまった場合などを考慮しており、 録画ファイルのグルーピングを目的としたファイルです。 ファイルは `/report-.json` に出力されます。 - トップレベルの start_timestamp- [StartRecording](API_RECORDING.html#c5b527) API を受け付た時刻を RFC 3339 (UTC) で表しています - トップレベルの stop_timestamp- [StopRecording](API_RECORDING.html#fd0de5) API を受け付た時刻か、 [StartRecording](API_RECORDING.html#c5b527) API で設定された期限の時刻を RFC 3339 (UTC) で表しています - archives 内の start_time_offset- [StartRecording](API_RECORDING.html#c5b527) API を叩いてから何秒経過した後にこの録画が開始したかを表しています - archives 内の stop_time_offset- [StartRecording](API_RECORDING.html#c5b527) API を叩いてから何秒経過した後にこの録画が終了したかを表しています ```javascript { "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_RECORDING.html#c5b527) API 実行時に `split_only: true` と `split_duration` の 2 つを指定することで、 録画ファイルを指定した間隔で出力する機能を提供しています。 > **重要** > > 分割の最小単位はキーフレームから次のキーフレームまでです。例えば `split_duration` を 1 秒に設定した場合は、1 秒経過後に次のキーフレームが来たタイミングで分割出力されます。 録画が完了したファイルは `sora.conf` の [archive_dir](SORA_CONF.html#ad2156) に指定したディレクトリに `recording_id` 名のディレクトリ以下にファイルが出力されます。 `recording_id` は [StartRecording](API_RECORDING.html#c5b527) API を実行したときに戻ってくる値です。 ### 録画ファイル分割出力のみを行う 録画開始 API 実行時に `split_only: true` と `split_duration` の 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 │ │ └── 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 は省略しています** ```javascript { "audio": true, "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": true, "video_bit_rate": 1000, "video_codec_type": "VP9", "video_vp9_params": { "profile_id": 0 }, "video_height": 480, "video_width": 640 } ``` ### split-archive-end- #### 分割録画終了メタデータファイル 分割録画終了メタデータファイルは `/split-archive-end-.json` に JSON 形式で出力されます。 **stats は省略しています** ```javascript { "audio": true, "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": true, "video_bit_rate": 1000, "video_codec_type": "VP9", "video_vp9_params": { "profile_id": 0 }, "video_height": 480, "video_width": 640 } ``` #### 録画ファイル分割出力終了時 接続単位での録画が終了したタイミングでイベントウェブフックリクエスト `split-archive.end` がリクエスト送信されます。 詳細は [split-archive.end](EVENT_WEBHOOK.html#31be7a) をご確認ください。 ### report- 録画終了時に、それまでにそのチャネルで録画したファイル一覧が記載されているレポートファイルが JSON 形式で出力されます。 録画終了は [StopRecording](API_RECORDING.html#fd0de5) API を使用して指定したチャネルに対する録画を停止するか、 録画の期限が切れるか、セッションが終了するかの 3 つのパターンがあります。 このファイルは主にマルチストリームや途中で切れてしまった場合などを考慮しており、 録画ファイルのグルーピングを目的としたファイルです。 ファイルは `/report-.json` に出力されます。 分割録画ファイル出力のみの場合は archives には `connection_id` や `client_id` といった接続情報と、 分割録画ファイルの最後のインデックス番号のみが含まれます。 - トップレベルの start_timestamp- [StartRecording](API_RECORDING.html#c5b527) API を受け付た時刻を RFC 3339 (UTC) で表しています - トップレベルの stop_timestamp- [StopRecording](API_RECORDING.html#fd0de5) API を受け付た時刻か、 [StartRecording](API_RECORDING.html#c5b527) API で設定された期限の時刻を RFC 3339 (UTC) で表しています - archives 内の start_time_offset- [StartRecording](API_RECORDING.html#c5b527) API を叩いてから何秒経過した後にこの録画が開始したかを表しています - archives 内の stop_time_offset- [StartRecording](API_RECORDING.html#c5b527) API を叩いてから何秒経過した後にこの録画が終了したかを表しています ```javascript { "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_RECORDING.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_RECORDING.html#c5b527) API を受け付た時刻を RFC 3339 (UTC) で表しています - トップレベルの stop_timestamp- [StopRecording](API_RECORDING.html#fd0de5) API を受け付た時刻か、 [StartRecording](API_RECORDING.html#c5b527) API で設定された期限の時刻を RFC 3339 (UTC) で表しています - archives 内の start_time_offset- [StartRecording](API_RECORDING.html#c5b527) API を叩いてから何秒経過した後にこの録画が開始したかを表しています - archives 内の stop_time_offset- [StartRecording](API_RECORDING.html#c5b527) API を叩いてから何秒経過した後にこの録画が終了したかを表しています ```javascript { "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) をご確認ください。 ## Lyra コーデックの録画ファイル ### Lyra の WebM 構造 Sora はコーデックの変換を行わないので、 音声コーデックに [Lyra](https://github.com/google/lyra) が指定されている場合には、 録画ファイルには Lyra でエンコードされた音声データが格納されます。 WebM は標準では Lyra に対応していないため、 Sora では独自に次のような `TrackEntry` を Lyra 用に定義しています。 **Lyra 用の TrackEntry** * - 項目名 - 値 * - TrackNumber - 2 * - TrackUID - 2 * - FlagLacing - 0 * - Language - "und" * - FlagDefault - 0 * - CodecID - "A_LYRA" * - SeekPreRoll - 80000000 * - TrackType - 2 * - Audio - ``Channels`` と ``SamplingFrequency`` を含んだ ``Audio`` 要素 * - CodecPrivate - Lyra のエンコード情報を含んだバイナリ文字列。詳細は後述。 Lyra 用の `CodecPrivate` バイナリの中身は次の通りです。 **Lyra 用の CodecPrivate** * - 項目名 - バイト長 - 値 * - マジックシグネチャ - 8 - "LyraHead" * - CodecPrivate 形式のバージョン - 1 - 1 * - チャネル数 - 1 - 整数値 * - DTX - 1 - 0=無効、1=有効 * - サンプルレート - 4 - リトルエンディアンの整数値 * - ビットレート - 4 - リトルエンディアンの整数値 * - Lyra のエンコードフォーマットバージョン - 可変長(バイナリ文字列の終端まで) - 文字列 なお `TrackEntry` およびその中の各項目の詳細については [WebM の仕様](https://www.matroska.org/technical/elements.html) を参照してください。 ### Lyra の WebM 再生方法 通常の動画プレイヤーでは Lyra でエンコードされた音声を含んだ録画ファイルを再生することはできません。 ただし以下のように FFmpeg と Lyra のコマンドラインデコーダを組み合わせることで WebM から音声だけを取り出してデコードおよび再生が行えます。 ```console # 1) FFmpeg を使って WebM ファイルから Lyra でエンコードされた音声データだけを取り出す # # [NOTE] # 以下の FFmpeg コマンドは WebM 内の音声データを未加工のまま取り出して単純に連結し、 # タイムスタンプやエンコードパラメーターの情報は出力ファイルには含まれていないことには注意。 # # 例えば、DTX が有効になっているとWebM 内の音声データのタイムスタンプは飛び飛びになるが、 # 出力時にはその情報は欠落して連結される。 $ ffmpeg -y -i archive.webm -vn -acodec copy -f u8 archive.lyra # 2) google/lyra リポジトリで提供されているコマンドラインデコーダを使って Lyra 音声ファイルをデコードする # コマンドを実行すると ${入力ファイル名}_decoded.wav という名前の WAV ファイルが作成される # # [NOTE] # - decoder_main コマンドのビルド方法は後述 # - --bitrate オプションの値はエンコード設定に合わせて指定する必要がある $ decoder_main --encoded_path archive.lyra --output_dir . --bitrate 6000 # 3) 適当な動画プレイヤーで WAV ファイルを再生する $ ffplay archive_decoded.wav ``` `decoder_main` コマンドのビルド方法は次の通りです。 ```console # 1) リポジトリをダウンロード $ git clone https://github.com/google/lyra.git $ cd lyra # 2) 今回は Android 関連のビルドは不要なので、その設定をコメントアウトする # (Android Studio が既に手元でセットアップ済みの場合には、この手順はスキップ可能) $ vim WORKSPACE # load("//:android_configure.bzl", "android_configure") # android_configure(name = "local_config_android") # load("@local_config_android//:android_configure.bzl", "android_workspace") # android_workspace() # 3) ビルド $ bazel build -c opt lyra/cli_example:decoder_main # 4) ビルドに成功したら以下のパスにデコードコマンドが配置される $ ls bazel-bin/lyra/cli_example/decoder_main ``` ## 録画ファイル合成ツール マルチストリームを録画した場合はそれぞれの接続に対して録画ファイルが出力されます。このそれぞれ分かれた録画ファイルを合成して一つにするツールをオープンソースとして公開しています。 詳細は [WebRTC 録画合成ツール Hisui](HISUI.html) をご確認ください。 ## 録画ファイルアップロードツール 録画ファイルを S3 または S3 互換オブジェクトストレージにアップロードするツールをオープンソースとして公開しています。 詳細は [Sora Archive Uploader](SORA_ARCHIVE_UPLOADER.html) をご確認ください ## 試してみる Sora では録画機能を試すための開発ツールを提供しています。 [開発ツール](DEVTOOLS.html) を参照の上、開発ツールを有効にしてください。 ここでは Sora が立っているサーバーは example.com としています。 ### 録画開始 録画を開始するにはセッションウェブフックで `"recording": true` を払い出すか録画開始 [StartRecording](API_RECORDING.html#c5b527) API を叩く必要があります。 ここでは API を叩いて録画を開始してみましょう。 録画を開始するにはセッションが存在する必要があるため、API を叩く前にクライアントの接続を行い、セッションを作成してください。 httpie: ``` $ http POST example.com:3000/ \ x-sora-target:Sora_20231220.StartRecording \ channel_id=sora -vvv ``` curl: ``` $ curl -X POST example.com:3000/ \ -H "x-sora-target: Sora_20231220.StartRecording" \ -d '{"channel_id": "sora"}' -vvv ``` その後 `https://example.com/sendonly.html` を開き、 connect ボタンを押して配信を開始します。 切断またはチャネルの録画終了、もしくはチャネルの録画期限が来たタイミングでクライアント単位の録画は終了します。 セッションが終了したタイミングで録画は終了します。 ### 録画終了 録画を終了するには全ての参加者が離脱し、セッションが終了するか、 API を叩く必要があります。 ここでは API を叩いて録画を終了してみましょう。 httpie: ``` $ http POST example.com:3000/ \ x-sora-target:Sora_20231220.StopRecording \ channel_id=sora -vvv ``` curl: ``` $ curl -X POST example.com:3000/ \ -H "x-sora-target: Sora_20231220.StopRecording" \ -d '{"channel_id": "sora"}' -vvv ``` その後 archive/ ディレクトリに webm 形式のファイルが出力されます。 Chrome または Firefox にドラッグアンドドロップして、動作を確認してください。 ## シーケンス図 ### 録画 API ```mermaid sequenceDiagram autonumber participant C as クライアント participant S as Sora participant A as アプリケーションサーバー note over C,A: 認証成功 S->>+A: セッションウェブフック: "session.created" A-->>-S: 200 OK S->>+C: "type": "offer" C->>-S: "type": "answer" note over C,A: WebRTC 確立 S->>+A: イベントウェブフック: "connection.created" A-->>-S: 200 OK A->>+S: HTTP API StartRecording S-->>-A: 200 OK note over C,A: 録画開始 S->>+A: セッションウェブフック
"type": "recording.started" A-->>-S: 200 OK S->>+A: イベントウェブフック
"type": "archive.started" A-->>-S: 200 OK A->>+S: HTTP API StopRecording S-->>-A: 200 OK note over C,A: 録画終了 S->>+A: イベントウェブフック
"type": "archive.available" A-->>-S: 200 OK S->>+A: セッションウェブフック
"type": "recording.report" A-->>-S: 200 OK ``` ### セッションウェブフック `"recording": true` で録画開始 ```mermaid sequenceDiagram autonumber participant C as クライアント participant S as Sora participant A as アプリケーションサーバー note over C,A: 認証成功 S->>+A: セッションウェブフック: "session.created" A-->>-S: 200 OK
"recording": true note over C,A: 録画開始 S->>+A: セッションウェブフック
"type": "recording.started" A-->>-S: 200 OK S->>+C: "type": "offer" C->>-S: "type": "answer" note over C,A: WebRTC 確立 S->>+A: イベントウェブフック: "connection.created" A-->>-S: 200 OK S->>+A: イベントウェブフック
"type": "archive.started" A-->>-S: 200 OK ``` ### 録画期限切れ ```mermaid sequenceDiagram autonumber participant C as クライアント participant S as Sora participant A as アプリケーションサーバー note over C,A: 認証成功 S->>+A: セッションウェブフック: "session.created" A-->>-S: 200 OK
"recording": true,
"recoding_expire_time": 3600 note over C,A: 録画開始 S->>+A: セッションウェブフック
"type": "recording.started" A-->>-S: 200 OK S->>+C: "type": "offer" C->>-S: "type": "answer" note over C,A: WebRTC 確立 S->>+A: イベントウェブフック: "connection.created" A-->>-S: 200 OK S->>+A: イベントウェブフック
"type": "archive.started" A-->>-S: 200 OK note over C,A: 期限切れにより録画終了 S->>+A: イベントウェブフック
"type": "archive.available" A-->>-S: 200 OK S->>+A: セッションウェブフック
"type": "recording.report" A-->>-S: 200 OK ``` ### クライアント切断 ```mermaid sequenceDiagram autonumber participant C as クライアント participant S as Sora participant A as アプリケーションサーバー note over C,A: 認証成功 S->>+A: セッションウェブフック: "session.created" A-->>-S: 200 OK
"recording": true note over C,A: 録画開始 S->>+A: セッションウェブフック
"type": "recording.started" A-->>-S: 200 OK S->>+C: "type": "offer" C->>-S: "type": "answer" note over C,A: WebRTC 確立 S->>+A: イベントウェブフック: "connection.created" A-->>-S: 200 OK S->>+A: イベントウェブフック
"type": "archive.started" A-->>-S: 200 OK C->>S: "type": "disconnect" S->>+A: イベントウェブフック
"type" :"connection.destroyed" A-->-S: 200 OK S->>C: WebSocekt Close note over C,A: クライアント切断に伴いクライアントの録画終了 S->>+A: イベントウェブフック
"type": "archive.available" A-->>-S: 200 OK ``` ### セッション破棄 ```mermaid sequenceDiagram autonumber participant C as クライアント participant S as Sora participant A as アプリケーションサーバー note over C,A: 認証成功 note over C,A: セッション生成 S->>+A: セッションウェブフック: "session.created" A-->>-S: 200 OK
"recording": true note over C,A: 録画開始 S->>+A: セッションウェブフック
"type": "recording.started" A-->>-S: 200 OK S->>+C: "type": "offer" C->>-S: "type": "answer" note over C,A: WebRTC 確立 S->>+A: イベントウェブフック: "connection.created" A-->>-S: 200 OK S->>+A: イベントウェブフック
"type": "archive.started" A-->>-S: 200 OK C->>S: "type": "disconnect" S->>+A: イベントウェブフック
"type" :"connection.destroyed" A-->-S: 200 OK S->>C: WebSocekt Close note over C,A: クライアント切断に伴いクライアントの録画終了 S->>+A: イベントウェブフック
"type": "archive.available" A-->>-S: 200 OK note over C,A: セッション破棄 S->>+A: セッションウェブフック: "session.destroyed" A-->>-S: 200 OK note over C,A: セッション破棄に伴いセッションの録画終了 S->>+A: セッションウェブフック: "recording.report" A-->>-S: 200 OK ``` # レガシー録画機能 > **注意** > > レガシー録画機能は 2025 年 12 月リリースの Sora にて廃止されます。 > 今後は [録画機能 (セッション単位)](RECORDING.html) をご利用ください。 > **重要** > > レガシー録画機能と録画機能 (セッション単位) はチャネル単位で異なる仕組みを同時に利用できます。 > 例えば、channel_id a ではレガシー録画機能、channel_id b では録画機能(セッション単位)のように利用する事ができます。 ## 概要 Sora では、配信している映像や音声を録画、録音して保存できます。 配信されている映像をできるかぎりそのまま保存するため、CPU リソースを最小限に抑えることができます。 出力される録画ファイルは WebM 形式です。映像のみの録画、音声のみの録音にも対応しています。 録画時には一切トランスコードを行っていません。配信された映像や音声をそのままに記録します。 ## 用語 **単一録画ファイル** : 切断または [StopRecording](API_LEGACY_RECORDING.html#fd0de5) API の実行、または録画期限が切れた場合に一つのファイルとして出力される動画ファイル **分割録画ファイル** : `split_duration` で指定した時間ごとに区切られ分割されて出力される動画ファイル ## 録画ファイルの出力 録画ファイルの出力には 3 パターンあります。 ### 単一録画ファイルのみ出力 - `split_duration` を指定していない 上記を満たした場合、1 接続で 1 つ録画ファイルが出力されます。 ### 分割録画ファイルのみ出力 - `split_duration` が指定されている - `expire_time` が `0` に指定されている - `split_only` が `true` に指定されている 上記を満たした場合、分割された録画ファイルのみが出力されます。 ### 単一録画ファイルと分割録画ファイルの両方が出力 - `sora.conf` で `recording_dual_output` が `true` に指定されている - `split_duration` が指定されている 上記を満たした場合、 1 接続で 1 つの録画ファイルと分割された録画ファイルの両方が出力されます。 イベントウェブフックも単一録画、分割録画、両方のイベントウェブフックリクエストが送信されます。 ## 制限 ### コーデック 録画 (録音) は、映像コーデックに VP8 と VP9 と H.264 と AV1 、また音声コーデックに Opus と Lyra を選択した場合のみ利用できます。 > **警告** > > H.265 の録画には非対応です。 ### 解像度 WebRTC では配信側の CPU リソースが不足した場合や、 回線の品質が悪化した場合に解像度を動的に変更します。 そのため録画したデータの途中で解像度が低くなる可能性があります。 ### 音声や映像のクライアント側でのトラック削除 クライアント側でシグナリング接続時に音声や映像を有効にした状態で、 クライアント側で音声トラック、または映像トラックのどちらかを削除した場合でも録画は行われます。 さらに追加して戻した形であれば録画側も戻ります。 ただし、音声と映像両方のトラックを削除した場合は正常に録画が行われません。 ### マルチストリーム機能での録画 対応しています。 ### サイマルキャスト機能での録画 対応しています。 サイマルキャストを利用している際の録画は **一番優先度が低い** ストリーム、すなわちデフォルトでは最も高い画質の映像を録画します。 詳細はサイマルキャストの [映像の優先度](SIMULCAST.html#36c708) をご確認下さい。 ### スポットライト機能での録画 対応しています。 サイマルキャストを利用している際の録画は **一番優先度が低い** ストリーム、すなわちデフォルトでは最も高い画質の映像を録画します。 詳細はサイマルキャストの [映像の優先度](SIMULCAST.html#36c708) をご確認下さい。 ### キーフレーム要求間隔 録画機能利用時の Sora からのキーフレーム要求間隔は 20 秒に固定されています。 そのため、分割録画の最小時間は 20 秒 + `split_duration` に指定した秒数となります。 もし録画時のキーフレーム要求間隔を変更したい場合は、サポートまでご連絡ください。 ## 無変換録画 WebRTC 経由で流れてきている映像や音声を変換せず、 そのまま録画するファイルの形式に組み立て直してファイルを保存します。 そのため、CPU リソースを最小限に抑えられます。 ブラウザでの録画など、通常の録画は変換が入るため CPU に多くの負荷がかかります。 変換を行わないため、録画を終了した数秒後には録画したファイルを取得できます。 解像度は送られてきた映像の最大値を録画ファイルの解像度として使用します。 ## 録画の開始と終了について Sora の録画機能は **明示的にチャネルの録画を停止するか、 チャネルの録画開始から指定した期限が過ぎるまでは、 そのチャネルでの配信を自動で録画する** といった機能になります。 ## sora.conf の設定による録画指定制限について 録画ファイルが大きくならないように、sora.conf の指定で録画開始時のオプションを制限することができます。 設定の詳細は以下をご確認ください。 - [recording_max_expire_time](SORA_CONF.html#f3ff8d) - [recording_max_split_duration](SORA_CONF.html#927da9) - [recording_expire_time_required](SORA_CONF.html#fcfa2d) - [recording_dual_output](SORA_CONF.html#4cc9c0) ## 録画関連イベントのウェブフックについて ### 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 は省略しています** ```javascript { "audio": true, "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": true, "video_bit_rate": 1000, "video_codec_type": "VP9", "video_vp9_params": { "profile_id": 0 }, "video_height": 480, "video_width": 640 } ``` ### report- 録画終了時に、それまでにそのチャネルで録画したファイル一覧が記載されているレポートファイルが JSON 形式で出力されます。 録画終了は [StopRecording](API_LEGACY_RECORDING.html#fd0de5) API を使用して指定したチャネルに対する録画を停止するか、 録画の期限が切れた場合のふたつのパターンがあります。 このファイルは主にマルチストリームや途中で切れてしまった場合などを考慮しており、 録画ファイルのグルーピングを目的としたファイルです。 ファイルは `/report-.json` に出力されます。 - トップレベルの start_timestamp- [StartRecording](API_LEGACY_RECORDING.html#c5b527) API を受け付た時刻を RFC 3339 (UTC) で表しています - トップレベルの stop_timestamp- [StopRecording](API_LEGACY_RECORDING.html#fd0de5) API を受け付た時刻か、 [StartRecording](API_LEGACY_RECORDING.html#c5b527) API で設定された期限の時刻を RFC 3339 (UTC) で表しています - archives 内の start_time_offset- [StartRecording](API_LEGACY_RECORDING.html#c5b527) API を叩いてから何秒経過した後にこの録画が開始したかを表しています - archives 内の stop_time_offset- [StartRecording](API_LEGACY_RECORDING.html#c5b527) API を叩いてから何秒経過した後にこの録画が終了したかを表しています ```javascript { "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_LEGACY_RECORDING.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_LEGACY_RECORDING.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 は省略しています** ```javascript { "audio": true, "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": true, "video_bit_rate": 1000, "video_codec_type": "VP9", "video_vp9_params": { "profile_id": 0 }, "video_height": 480, "video_width": 640 } ``` ### split-archive-end- #### 分割録画終了メタデータファイル 分割録画終了メタデータファイルは `/split-archive-end-.json` に JSON 形式で出力されます。 **stats は省略しています** ```javascript { "audio": true, "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": true, "video_bit_rate": 1000, "video_codec_type": "VP9", "video_vp9_params": { "profile_id": 0 }, "video_height": 480, "video_width": 640 } ``` #### 録画ファイル分割出力終了時 接続単位での録画が終了したタイミングでイベントウェブフックリクエスト `split-archive.end` がリクエスト送信されます。 詳細は [split-archive.end](EVENT_WEBHOOK.html#31be7a) をご確認ください。 ### report- 録画終了時に、それまでにそのチャネルで録画したファイル一覧が記載されているレポートファイルが JSON 形式で出力されます。 録画終了は [StopRecording](API_LEGACY_RECORDING.html#fd0de5) API を使用して指定したチャネルに対する録画を停止するか、 録画の期限が切れた場合のふたつのパターンがあります。 このファイルは主にマルチストリームや途中で切れてしまった場合などを考慮しており、 録画ファイルのグルーピングを目的としたファイルです。 ファイルは `/report-.json` に出力されます。 分割録画ファイル出力のみの場合は archives には `connection_id` や `client_id` といった接続情報と、 分割録画ファイルの最後のインデックス番号のみが含まれます。 - トップレベルの start_timestamp- [StartRecording](API_LEGACY_RECORDING.html#c5b527) API を受け付た時刻を RFC 3339 (UTC) で表しています - トップレベルの stop_timestamp- [StopRecording](API_LEGACY_RECORDING.html#fd0de5) API を受け付た時刻か、 [StartRecording](API_LEGACY_RECORDING.html#c5b527) API で設定された期限の時刻を RFC 3339 (UTC) で表しています - archives 内の start_time_offset- [StartRecording](API_LEGACY_RECORDING.html#c5b527) API を叩いてから何秒経過した後にこの録画が開始したかを表しています - archives 内の stop_time_offset- [StartRecording](API_LEGACY_RECORDING.html#c5b527) API を叩いてから何秒経過した後にこの録画が終了したかを表しています ```javascript { "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_LEGACY_RECORDING.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_LEGACY_RECORDING.html#c5b527) API を受け付た時刻を RFC 3339 (UTC) で表しています - トップレベルの stop_timestamp- [StopRecording](API_LEGACY_RECORDING.html#fd0de5) API を受け付た時刻か、 [StartRecording](API_LEGACY_RECORDING.html#c5b527) API で設定された期限の時刻を RFC 3339 (UTC) で表しています - archives 内の start_time_offset- [StartRecording](API_LEGACY_RECORDING.html#c5b527) API を叩いてから何秒経過した後にこの録画が開始したかを表しています - archives 内の stop_time_offset- [StartRecording](API_LEGACY_RECORDING.html#c5b527) API を叩いてから何秒経過した後にこの録画が終了したかを表しています ```javascript { "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) をご確認ください。 ## Lyra コーデックの録画ファイル ### Lyra の WebM 構造 Sora はコーデックの変換を行わないので、 音声コーデックに [Lyra](https://github.com/google/lyra) が指定されている場合には、 録画ファイルには Lyra でエンコードされた音声データが格納されます。 WebM は標準では Lyra に対応していないため、 Sora では独自に次のような `TrackEntry` を Lyra 用に定義しています。 **Lyra 用の TrackEntry** * - 項目名 - 値 * - TrackNumber - 2 * - TrackUID - 2 * - FlagLacing - 0 * - Language - "und" * - FlagDefault - 0 * - CodecID - "A_LYRA" * - SeekPreRoll - 80000000 * - TrackType - 2 * - Audio - ``Channels`` と ``SamplingFrequency`` を含んだ ``Audio`` 要素 * - CodecPrivate - Lyra のエンコード情報を含んだバイナリ文字列。詳細は後述。 Lyra 用の `CodecPrivate` バイナリの中身は次の通りです。 **Lyra 用の CodecPrivate** * - 項目名 - バイト長 - 値 * - マジックシグネチャ - 8 - "LyraHead" * - CodecPrivate 形式のバージョン - 1 - 1 * - チャネル数 - 1 - 整数値 * - DTX - 1 - 0=無効、1=有効 * - サンプルレート - 4 - リトルエンディアンの整数値 * - ビットレート - 4 - リトルエンディアンの整数値 * - Lyra のエンコードフォーマットバージョン - 可変長(バイナリ文字列の終端まで) - 文字列 なお `TrackEntry` およびその中の各項目の詳細については [WebM の仕様](https://www.matroska.org/technical/elements.html) を参照してください。 ### Lyra の WebM 再生方法 通常の動画プレイヤーでは Lyra でエンコードされた音声を含んだ録画ファイルを再生することはできません。 ただし以下のように FFmpeg と Lyra のコマンドラインデコーダを組み合わせることで WebM から音声だけを取り出してデコードおよび再生が行えます。 ```console # 1) FFmpeg を使って WebM ファイルから Lyra でエンコードされた音声データだけを取り出す # # [NOTE] # 以下の FFmpeg コマンドは WebM 内の音声データを未加工のまま取り出して単純に連結し、 # タイムスタンプやエンコードパラメーターの情報は出力ファイルには含まれていないことには注意。 # # 例えば、DTX が有効になっているとWebM 内の音声データのタイムスタンプは飛び飛びになるが、 # 出力時にはその情報は欠落して連結される。 $ ffmpeg -y -i archive.webm -vn -acodec copy -f u8 archive.lyra # 2) google/lyra リポジトリで提供されているコマンドラインデコーダを使って Lyra 音声ファイルをデコードする # コマンドを実行すると ${入力ファイル名}_decoded.wav という名前の WAV ファイルが作成される # # [NOTE] # - decoder_main コマンドのビルド方法は後述 # - --bitrate オプションの値はエンコード設定に合わせて指定する必要がある $ decoder_main --encoded_path archive.lyra --output_dir . --bitrate 6000 # 3) 適当な動画プレイヤーで WAV ファイルを再生する $ ffplay archive_decoded.wav ``` `decoder_main` コマンドのビルド方法は次の通りです。 ```console # 1) リポジトリをダウンロード $ git clone https://github.com/google/lyra.git $ cd lyra # 2) 今回は Android 関連のビルドは不要なので、その設定をコメントアウトする # (Android Studio が既に手元でセットアップ済みの場合には、この手順はスキップ可能) $ vim WORKSPACE # load("//:android_configure.bzl", "android_configure") # android_configure(name = "local_config_android") # load("@local_config_android//:android_configure.bzl", "android_workspace") # android_workspace() # 3) ビルド $ bazel build -c opt lyra/cli_example:decoder_main # 4) ビルドに成功したら以下のパスにデコードコマンドが配置される $ ls bazel-bin/lyra/cli_example/decoder_main ``` ## 録画ファイル合成ツール マルチストリームを録画した場合はそれぞれの接続に対して録画ファイルが出力されます。このそれぞれ分かれた録画ファイルを合成して一つにするツールをオープンソースとして公開しています。 詳細は [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 ```mermaid sequenceDiagram autonumber participant C as クライアント participant S as Sora participant A as アプリケーションサーバー note over C,A: 認証成功 S->>+C: "type": "offer" C->>-S: "type": "answer" note over C,A: WebRTC 確立 A->>+S: HTTP API StartRecording S-->>-A: 200 OK S->>+A: イベントウェブフック
"type": "recording.started" A-->>-S: 200 OK note over C,A: 録画中 S->>+A: イベントウェブフック
"type": "archive.started" A-->>-S: 200 OK A->>+S: HTTP API StopRecording S-->>-A: 200 OK note over C,A: 録画終了 S->>+A: イベントウェブフック
"type": "archive.available" A-->>-S: 200 OK S->>+A: イベントウェブフック
"type": "recording.report" A-->>-S: 200 OK ``` ### 録画期限切れ ```mermaid sequenceDiagram autonumber participant C as クライアント participant S as Sora participant A as アプリケーションサーバー note over C,A: 認証成功 S->>+C: "type": "offer" C->>-S: "type": "answer" note over C,A: WebRTC 確立 A->>+S: HTTP API StartRecording S-->>-A: 200 OK S->>+A: イベントウェブフック
"type": "recording.started" A-->>-S: 200 OK note over C,A: 録画中 S->>+A: イベントウェブフック
"type": "archive.started" A-->>-S: 200 OK note over C,A: 期限切れにより録画終了 S->>+A: イベントウェブフック
"type": "archive.available" A-->>-S: 200 OK S->>+A: イベントウェブフック
"type": "recording.report" A-->>-S: 200 OK ``` ### クライアント切断 ```mermaid sequenceDiagram autonumber participant C as クライアント participant S as Sora participant A as アプリケーションサーバー note over C,A: 認証成功 S->>+C: "type": "offer" C->>-S: "type": "answer" note over C,A: WebRTC 確立 A->>+S: HTTP API StartRecording S-->>-A: 200 OK S->>+A: イベントウェブフック
"type": "recording.started" A-->>-S: 200 OK note over C,A: 録画中 S->>+A: イベントウェブフック
"type": "archive.started" A-->>-S: 200 OK C->>S: "type": "disconnect" S->>+A: イベントウェブフック
"type" :"connection.destroyed" A-->-S: 200 OK S->>C: WebSocekt Close note over C,A: クライアント切断により録画終了 S->>+A: イベントウェブフック
"type": "archive.available" A-->>-S: 200 OK S->>+A: イベントウェブフック
"type": "recording.report" A-->>-S: 200 OK ``` # メッセージング機能 ## 概要 ここでは DataChannel を利用したメッセージング機能について説明します。 DataChannel は、WebRTC の機能の一つでデータの送受信を行える機能です。 ## 注意 - メッセージング機能を利用するためには、 `data_channel_signaling` が有効になっている必要があります - メッセージング機能は DataChannel プロトコル互換性を維持しつつ Sora 独自の仕組みを追加しています ## 制限 ### メッセージサイズ制限 > **注意** > > 1 回のメッセージで送れる値には制限がありますのでご注意ください。 詳しくは DataChannel シグナリングの [推奨メッセージサイズ](DATA_CHANNEL_SIGNALING.html#2b27d3) をご確認ください ## SDK 対応状況 - 最新版の JavaScript SDK- 対応済みです - 最新版の iOS SDK- 対応済みです - 最新版の Android SDK- 対応済みです - 最新版の Unity SDK- 対応済みです - 最新版の C++ SDK- 対応済みです - 最新版の Python SDK- 対応済みです ## DataChannel を利用したメッセージング機能を有効にする DataChannel を利用したメッセージングを利用する場合、 DataChannel シグナリングが有効になっている必要があります。 その上で `sora.conf` にて [data_channel_messaging](SORA_CONF.html#1d5746) を `true` に指定してください。 利用する場合は `{"type": "connect"}` 時に `data_channels` を指定してください。 ## メッセージング用 DataChannel の作成 > **重要** > > DataChannel を利用したメッセージングを利用する場合は、DataChannel シグナリングが有効になっている必要があります Sora では、Sora がシグナリングで使用する DataChannel 以外にも、メッセージング用の DataChannel を作成できます。 利用する場合は `{"type": "connect"}` 時に定義するか、認証成功時の払い出しで定義する必要があります。 Sora のメッセージング用 DataChannel は、DataChannel の属性である `label` を定義する際に `#` から始める必要があります。 ## data_channels 仕様 > **警告** > > 現時点では誰から送られたメッセージかを判断する仕組みはありません。 > **重要** > > メッセージは **送信者以外** の同一 `label` 、かつ、 `direction` が `sendrecv` > または `recvonly` のクライアントに送信されます。 ### label メッセージのラベルを指定します。先頭に `#` が付いている必要があります。 - `label` は `#` を含めて 32 文字まで指定できます - `label` には小文字大文字のアルファベットと `-` (ハイフン) しか利用できません- `#` の次の文字に `-` は指定できません - `^#[a-zA-Z0-9][a-zA-Z0-9-]{1,30}$` - 1 接続においてラベルは最大で 1024 まで指定できます ### compress メッセージを zlib にて圧縮するかどうかを指定します。 - `compress` が `true` の場合、圧縮/展開に `zlib.deflate` を利用します- 圧縮方式を変更することはできません ### direction メッセージの方向を指定します。 - `direction` には `sendrecv` / `sendonly` / `recvonly` が設定できます- `sendrecv` 時に **自分が送ったメッセージ** は自分には送られてきません クライアントからみた方向になります。 - `sendrecv` が設定されたラベルは送受信で利用できます - `sendonly` が設定されたラベルは送信のみが利用できます - `recvonly` が設定されたラベルは受信のみが利用できます ### ordered 順序保証を行うかどうか指定します。デフォルトでは `true` に設定され、順序保証を行います。 ### max_retransmits > **注意** > > max_retransmits と max_packet_life_time はどちらかしか指定できません。 最大再送回数を指定します。デフォルトでは未指定で、無制限に再送します。 ### max_packet_life_time > **注意** > > max_retransmits と max_packet_life_time はどちらかしか指定できません。 最大再送時間を指定します。デフォルトでは未指定で、無制限に再送します。 ### 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 を利用したメッセージングのみを有効にするには以下を満たす必要があります。 > **注釈** > > role は sendrecv / sendonly / recvonly のどれでも問題ありません - `sora.conf` の `default_data_channel_signaling` を `true` にする - `sora.conf` の `data_channel_messaging_only` を `true` にする - `sora.conf` の `data_channel_messaging` を `true` にする - `{"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"` を受信 ```mermaid sequenceDiagram autonumber participant C1 as クライアント1 participant C2 as クライアント2 participant C3 as クライアント3 participant S as Sora C1->>S: "type": "connect" note over C1,S: クライアント1 WebRTC 確立 C2->>S: "type": "connect" note over C2,S: クライアント2 WebRTC 確立 C1-)S: label: #35;spam "abc" send S-)C2: label: #35;spam "abc" send C3->>S: "type": "connect" note over C3,S: クライアント3 WebRTC 確立 C1-)S: label: #35;spam "xyz" send S-)C2: label: #35;spam "xyz" send S-)C3: label: #35;spam "xyz" send ``` # ICE コネクションステート機能 ## 概要 ICE コネクションステート機能は Sora に ICE コネクションによる状態管理を持たせた機能です。 ## 前提 この機能はクライアント側が意識する必要はありません。 ## 挙動 Sora は WebRTC が確立した後に TURN 上で ICE コネクションステートを更新し続けます。 ステートの更新には `STUN Binding-Request` と `STUN Binding-Success` を利用します。 - Sora は 2.5 秒間隔で `STUN Binding-Request` をクライアントへ送ります- `STUN Binding-Success` が 2.5 秒以内に一度も返ってこない場合、状態を `connected` から `checking` へ遷移します - 状態が `checking` へ遷移した場合、 Sora は 1 秒間隔で `STUN Binding-Request` をクライアントへ送ります- `STUN Binding-Success` が 5 秒以内に一度も返ってこない場合、状態を checking から disconnected へ遷移します - この 5 秒は `sora.conf` にて `ice_connection_state_disconnected_timeout` で変更できます - 状態が `disconnected` に遷移した場合、 Sora は 50 ミリ秒間隔で `STUN Binding-Request` をクライアントへ送ります- `STUN Binding-Success` が 10 秒以内に一度も返ってこない場合、状態を `disconnected` から `failed` へ遷移します - この 10 秒は `sora.conf` にて `ice_connection_state_failed_timeout` で変更できます - このタイミングで `sora.jsonl` に `warning` として `ICE-CONNECTION-STATE-DISCONNECTED` が出力されます - 状態が `failed` に遷移した場合、Sora はクライアントの接続を切断します- このタイミングで `sora.jsonl` に `error` として `ICE-CONNECTION-STATE-FAILED` が出力されます ## 設定 ICE コネクションステート機能は無効にすることはできません。 ただし、切断や失敗までの判定時間を `sora.conf` にてデフォルト値から変更できます。 ### ice_connection_state_disconnected_timeout この値は Sora が ICE コネクションステートを disconnected へと遷移する際にクライアントからの応答を待つ時間です。 デフォルトでは `5 s` が設定されています。 詳細は _sora_conf-ice_connection_state_disconnected_timeout をご確認ください。 ### ice_connection_state_failed_timeout この値は Sora が ICE コネクションステートを failed へと遷移する際にクライアントからの応答を待つ時間です。 デフォルトでは `10 s` が設定されています。 詳細は _sora_conf-ice_connection_state_failed_timeout をご確認ください。 ## ウェブフック コネクションの状態が `checking` と `disconnected` だった合計時間をイベントウェブフックで取得できます。 - 取得可能なイベントウェブフック- `connection.created` - `connection.updated` - ``connection.destroyed `` - `data.ice_connection_state.total_checking_duration_ms` に `checking` だった合計時間(ミリ秒)の合計が入ります - `data.ice_connection_state.total_disconnected_duration_ms` に `disconnected` だった合計時間(ミリ秒)の合計が入ります ```javascript { // 色々省略してます "type": "connection.destroyed", "channel_id": "sora", "connection_id": "GS4Q8PQ5PS3EXC30T6PM2R7Y20", "timestamp": "2023-08-16T05:42:13.970729Z", "bundle_id": "GS4Q8PQ5PS3EXC30T6PM2R7Y20", "client_id": "GS4Q8PQ5PS3EXC30T6PM2R7Y20", "data": { "ice_connection_state": { "total_checking_duration_ms": 5002, "total_disconnected_duration_ms": 10002 } } } ``` ## シーケンス図 > **重要** > > 図のタイムアウト値はデフォルト値を採用しています。 ### connected 正常な接続状態である connected を継続しているシーケンス図です。 ```mermaid sequenceDiagram participant C as クライアント participant S as Sora note over C,S: WebRTC 確立 note over S: ICE State connected S->>+C: STUN Binding-Request C-->>-S: STUN Binding-Success note left of S: 2.5 秒経過 S->>+C: STUN Binding-Request C-->>-S: STUN Binding-Success note left of S: 2.5 秒経過 S->>+C: STUN Binding-Request C-->>-S: STUN Binding-Success ``` ### connected -> checking 正常な接続状態である connected から一時的に反応が無く checking 状態へ切り替わるシーケンス図です。 ```mermaid sequenceDiagram participant C as クライアント participant S as Sora note over C,S: WebRTC 確立 note over S: ICE State connected S->>C: STUN Binding-Request note left of S: 2.5 秒経過したが反応がない note over S: ICE State checking S->>C: STUN Binding-Request note left of S: 1.0 秒経過 S->>C: STUN Binding-Request note left of S: 1.0 秒経過 S->>C: STUN Binding-Request ``` ### checking -> disconnected 一時的に反応が無い checking の状態が続いたため、 切断判断をするために短い間隔で疎通パケットを送信する disconnected 状態へ切り替わるシーケンス図です。 ```mermaid sequenceDiagram participant C as クライアント participant S as Sora note over C,S: WebRTC 確立 note over S: ICE State connected S->>C: STUN Binding-Request note left of S: 2.5 秒経過したが反応がない note over S: ICE State checking S->>C: STUN Binding-Request note left of S: 1.0 秒間隔で 5 秒間送り続けてるが反応がない note over S: ICE State disconnected S->>C: STUN Binding-Request note left of S: 50 ミリ秒 S->>C: STUN Binding-Request ``` ### disconnected -> failed 切断判断をするため短い間隔で疎通パケットを送り続けたが、反応が無かったため failed へと切り替わるシーケンス図です。 ```mermaid sequenceDiagram participant C as クライアント participant S as Sora note over C,S: WebRTC 確立 note over S: ICE State connected S->>C: STUN Binding-Request note left of S: 2.5 秒経過したが反応がない note over S: ICE State checking S->>C: STUN Binding-Request note left of S: 1 秒間隔で 5 秒間送り続けてるが反応がない note over S: ICE State disconnected S->>C: STUN Binding-Request note left of S: 50 ミリ秒間隔で 10 秒間送り続けてるが反応がない note over S: ICE State failed note left of S: S はクライアントを切断したと見なし切断処理を行う ``` ### disconnected -> checking -> connected 一定時間、不通になっていたため状態が disconnected になっていましたが、 checking を経て connected まで状態が戻るシーケンス図です。 ```mermaid sequenceDiagram participant C as クライアント participant S as Sora note over C,S: WebRTC 確立 note over S: ICE State connected S->>C: STUN Binding-Request note left of S: 2.5 秒経過したが反応がない note over S: ICE State checking S->>C: STUN Binding-Request note left of S: 1 秒間隔で 5 秒間送り続けてるが反応がない note over S: ICE State disconnected S->>C: STUN Binding-Request note left of S: 50 ミリ秒間隔で 10 秒間送り続ける C-->>S: STUN Binding-Success note over S: ICE State checking S->>C: STUN Binding-Request note left of S: 1 秒間隔で 5 秒間送り続ける C-->>S: STUN Binding-Success note over S: ICE State connected S->>C: STUN Binding-Request note left of S: 2.5 秒間隔で送り続ける C-->>S: STUN Binding-Success ``` # モード機能 > **注意** > > この機能を利用する場合は事前にサポートまでご連絡ください > **警告** > > この機能は [実験的機能](EXPERIMENTAL.html) のため、正式版では仕様が変更される可能性があります ## 概要 モード (mode) 機能 は、指定されているモードごとに Sora の挙動を変更する機能です。 ## 目的 現在の Sora 自体には認証の機能を持っていないため、一時的に接続をブロックするといった仕組みがありません。もしやるとしても認証サーバー側で処理をすることになり不便でした。 そこで、Sora 側にモード機能を持たせることで、モードを切り替えることで接続を気軽にブロックする機能を追加します。 また、クラスター機能が有効な場合には、起動直後のノードやネットワーク障害などで孤立したノードに特別なモードを割り当てることで、 「同じチャネルが複数のノードで処理されている」などといった不整合が発生することを防いでいます。 ## モード ### ノーマルモード このモードは何もせず、すべての新規接続を受け入れます。 ### 新規コネクションブロックモード このモードは新規の接続をブロックします。すでに接続しているコネクションはそのままです。 ### 新規セッションブロックモード このモードは新規セッションの作成をブロックします。すでに接続しているセッションやコネクションはそのままです。 そのためセッション(チャネルに 1 人以上接続しているアクティブな状態)が存在する場合は接続できますが、セッションが存在しない場合は新規の接続をブロックします。 ## ウェブフック ### session.vanished > **重要** > > このウェブフックリクエストが送信されるには `sora.conf` の [ignore_session_vanished_webhook](SORA_CONF.html#85718d) が `false` である必要があります。 このウェブフックは、新規コネクションブロック、または新規セッションブロックモード時にすべてのセッションが破棄されたタイミングで送信されます。 ```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" } ``` ## クラスター機能 ### チャネル ID のノード割り当て クラスター機能を利用した場合、 `mode` が [新規セッションブロックモード](MODE.html#041e1c) または [新規コネクションブロックモード](MODE.html#0b67d3) のノードに対して、 新規のチャネル ID を割り当てません。 ## シーケンス図 ### block_new_connection ```mermaid sequenceDiagram participant C1 as クライアント1 participant C2 as クライアント2 participant S as Sora participant A as アプリケーションサーバー note over S: Sora 起動 note over S: モード: normal C1->>S: "type": "connect" note over C1,S: クライアント1 WebRTC 確立 A->>S: ChangeMod API
mode=block_new_connection note over S: モード: block_new_connection break 接続失敗 C2->>S: "type": "connect" end A->>S: ChangeMod API
mode=normal note over S: モード: normal C2->>S: "type": "connect" note over C2,S: クライアント2 WebRTC 確立 ``` ### block_new_session ```mermaid sequenceDiagram participant C1 as クライアント1 participant C2 as クライアント2 participant C3 as クライアント3 participant S as Sora participant A as アプリケーションサーバー note over S: Sora 起動 note over S: モード: normal C1->>S: "type": "connect"
channel_id=spam note over C1,S: クライアント1 WebRTC 確立 A->>S: ChangeMod API
mode=block_new_session note over S: モード: block_new_session break 接続失敗 C2->>S: "type": "connect"
channel_id=ham end C3->>S: "type": "connect"
channel_id=spam note over C3,S: クライアント3 WebRTC 確立 ``` # ヘルスチェック機能 ## 概要 Sora にはヘルスチェック機能を搭載しています。 URL は固定で `/.ok` で、ポート番号はシグナリングに利用するポートでデフォルトは 5000 番です。 ポート番号を変更する場合は `sora.conf` の `signaling_port` を変更してください。 ## 確認 ```console $ http GET http://192.0.2.1:5000/.ok ``` ## 単体利用時 問題が無ければ `200 OK` が返ります。 ## クラスター利用時 問題が無ければ `200 OK` が返ります。 - ノードがクラスターに参加していない場合 `503 Service Unavailable` が返ります - `block_new_connection` モード時に `503 Service Unavailable` が返ります # 配信ワーカー機能 > **注意** > > この機能を利用する場合は事前にサポートまでご連絡ください > **警告** > > この機能は [実験的機能](EXPERIMENTAL.html) のため、正式版では仕様が変更される可能性があります ## 概要 配信ワーカー機能は Sora の内部で音声や映像を配信するワーカーを複数用意することで、 1 チャネルで高ビットレートの映像をより多くのクライアントに配信することをできるようにする機能です。 ## この機能を検討する基準 1 チャネルで複数クライアントへ配信する際、1 チャネルで 100 Mbps 以上の帯域を利用する際に検討してください。 ## 注意 この設定は基本的にチューニングの部類に入ります。そのため、サポートまでお気軽にご相談ください。 ### 音声と映像のみ 現時点で配信ワーカーは音声と映像のみに対応しており、メッセージングには対応していません。 将来的に対応する予定です。 ### マルチストリームとサイマルキャストのみ 現時点で配信ワーカーはマルチストリームとサイマルキャストのみに対応しており、 スポットライトには対応しておりません。 将来的に対応する予定です。 ## 設定 ### rtp_publish_worker_number `sora.conf` に音声や映像の 1 配信に利用する配信ワーカー数を指定する [rtp_publish_worker_number](SORA_CONF.html#512b8c) を追加しました - デフォルトの配信ワーカー数は 1 です - 同時に 100 クライアント以上へ配信する場合はまず 10 を設定することを推奨します - ワーカー数が 10 であれば 1 チャネル 1000 クライアント以上の配信がができるようになります - 最小は 1 で、最大は 500 です ワーカー数の設定を 10 以上で検討している場合はまずサポートにご相談ください。 ## 仕組み > **注釈** > > Sora の内部的な話のため、基本的に利用者は意識する必要はありません。 Sora では 1 クライアントが他のクライアントに音声や映像を配信する際、 1 つのワーカーが担当しています。この部分を複数ワーカーにすることで、 他のクライアントに配信する際の負荷を分散することができます。 たとえば 1 チャネルで 1000 クライアントに配信する場合、1 つのワーカーが 1000 クライアントに配信するのではなく、 10 個のワーカーが 100 クライアントずつに配信するようになります。 ## シーケンス図 ### 配信ワーカー 1 視聴者側への配信が直列。 ```mermaid sequenceDiagram participant Pub as 配信者 participant S as Sora participant Sub1 as 視聴者1 participant Sub2 as 視聴者2 Pub-)S: 音声と映像 S-)Sub1: 音声と映像 S-)Sub2: 音声と映像 ``` ### 配信ワーカー複数 視聴者側への配信が並列化される。 ```mermaid sequenceDiagram participant Pub as 配信者 participant S as Sora participant Sub1 as 視聴者1 participant Sub2 as 視聴者2 Pub-)S: 音声と映像 note right of S: 並列で配信 par S-)Sub1: 音声と映像 and S-)Sub2: 音声と映像 end ``` # 音声ストリーミング機能 > **注意** > > この機能を利用する場合は事前にサポートまでご連絡ください > **警告** > > この機能は [実験的機能](EXPERIMENTAL.html) のため、正式版では仕様が変更される可能性があります ## 概要 Sora に WebRTC で送られてきた音声を、接続ごとに HTTP/2 で外部へ出力し、外部から受信した結果をクライアントへプッシュで通知する機能です。 ## 注意 ### OBS (WHIP) 機能利用時の Opus の設定 OBS の Opus のビットレートがデフォルトの場合は正常に動作しない場合があります。 その場合はビットレートを 128 kbps まで下げて見てください。 ### IPv6 非対応 現時点で、音声ストリーミングは IPv6 を利用できません。 ## HTTP/2 - 音声ストリーミングゲートウェイは HTTP/2 に対応している必要があります - h2c と h2 の両方に対応しています - `http://` から始めると h2c を利用します - `https://` から始めると h2 を利用します ## 仕様 ### マルチストリームでのみ利用可能 音声ストリーミング機能はマルチストリームを有効にした状態でのみ利用できます。 ### 音声ストリーミングの配信 音声ストリーミング機能はセッション単位で有効になります。 実際に音声ストリーミングで音声が外部に配信されるのは、 `role` が `sendrecv` または `sendonly`、かつ `audio` が `true` になっている場合のみ有効になります。 > **注釈** > > 外部から受信した結果はロールなどは関係なく、サブスクライブしているすべてのクライアントが受信できます。 ### 言語コードの指定 音声ストリーミングを利用する場合、 言語コードを指定する必要があります。 シグナリング接続時、または認証成功時の払い出しで `{"audio_streaming_language_code": "ja-JP"}` のように指定してください。 指定するのは **文字列であればなんでもかまいません** 。Sora 自体は言語コードには関与しません。あくまでただの文字列として扱います。 > **注意** > > 言語コードが指定されていない接続は、音声ストリーミングが開始している場合でも音声ストリーミングを行いません。 > 言語コードは音声を解析するにあたり必要になるためこのような仕様になっています。 ### セッションウェブフック経由での開始 音声ストリーミングはセッション単位で開始、終了します。 セッション生成時から音声ストリーミングを開始したい場合、 セッションウェブフックの戻り値に `{"audio_streaming": true}` を指定することで音声ストリーミングが開始します。 そのセッションに参加してきた言語コードが指定されているクライアントはすべて音声ストリーミングが行われます。 ### セッション破棄時の音声ストリーミング終了 チャネルのセッションが終了したタイミングで音声ストリーミングは終了します。 ### API 経由での開始と終了 セッションの途中で音声ストリーミングを開始する場合は [StartAudioStreaming](EXPERIMENTAL_API_AUDIO_STREAMING.html#0f1087) API を利用する必要があります。 また、セッションの途中で音声ストリーミングを終了する場合は [StopAudioStreaming](EXPERIMENTAL_API_AUDIO_STREAMING.html#bad1bb) API を利用する必要があります。 ### 自動開始/停止機能 サブスクライブ中のコネクション数が 1 つ以上に増えたとき、自動的に音声ストリーミングが開始します。 逆に、サブスクライブ中のコネクション数が 0 になったときには、音声ストリーミングが自動的に停止します。 この機能を有効にすることで、サブスクライブが 0 の時は音声ストリーミングを行わなくなり、 転送量などを抑えることができます。 以下の方法でこの機能を有効にできます: - セッションウェブフックの `session.created` 時の払い出しで `{"audio_streaming": true, "audio_streaming_auto": true}` を指定した場合 > **注意** > > この機能が有効化されているときには、 > [StartAudioStreaming](EXPERIMENTAL_API_AUDIO_STREAMING.html#0f1087) API と [StopAudioStreaming](EXPERIMENTAL_API_AUDIO_STREAMING.html#bad1bb) API は利用できません。 > > この機能を停止するにはセッションを終了する必要があります。 > API を使用してセッションを終了する場合には、 [TerminateSession](EXPERIMENTAL_API_SESSION.html#ba022b) API を利用してください。 ### audio_streaming 関連の払い出し設定の組み合わせによる動作 #### 音声ストリーミングゲートウェイへの接続 セッションウェブフックの session.created 時に払い出した、 `audio_streaming`, `audio_streaming_auto` の組み合わせ毎の `配信者接続時` の音声ストリーミングゲートウェイへの接続の有無は下記の通りです。 * - audio_streaming の指定 - audio_streaming_auto の指定 - subscribe 数 - 音声ストリーミングゲートウェイへの接続 * - true - true [#f1]_ - 0 - 無し * - true - true [#f1]_ - 1 以上 - 有り * - true - false - 0 - 有り [#f2]_ * - true - false - 1 以上 - 有り [#f2]_ * - true - 指定なし - 0 - 有り [#f2]_ * - true - 指定なし - 1 以上 - 有り [#f2]_ * - false - false - 0 - 無し * - false - false - 1 以上 - 無し [#f3]_ * - false - 指定なし - 0 - 無し [#f3]_ * - false - 指定なし - 1 以上 - 無し [#f3]_ * - 指定なし - false - 0 - 無し * - 指定なし - false - 1 以上 - 無し [#f3]_ * - 指定なし - 指定なし - 0 - 無し [#f3]_ * - 指定なし - 指定なし - 1 以上 - 無し [#f3]_ [^#f1]: .. [#f1] audio_streaming_auto に true を指定する場合には、audio_streaming にも true を指定する必要があります [^#f2]: .. [#f2] 音声ストリーミングゲートウェイへの接続有無はサブスクライブの数に依存しません [^#f3]: .. [#f3] 接続には StartAudioStreaminga API の実行が必要です > **注意** > > audio_streaming_auto に true を指定したにもかかわらず、audio_streaming を指定しないか、または false を指定した場合は、不正な組み合わせのため audio_streaming_auto、audio_streaming の指定は無視されます #### クライアントへの解析結果の送信 セッションウェブフックの session.created 時に払い出した、 `audio_streaming`, `audio_streaming_auto` の組み合わせ毎の subscribe しているクライアントへの解析結果の送信有無は下記の通りです。 * - audio_streaming の指定 - audio_streaming_auto の指定 - subscribe 数 - クライアントへの解析結果の送信 * - true - true [#f4]_ - 0 - 無し * - true - true [#f4]_ - 1 以上 - 有り * - true - false - 0 - 無し * - true - false - 1 以上 - 有り * - true - 指定なし - 0 - 無し * - true - 指定なし - 1 以上 - 有り * - false - false - 0 - 無し * - false - false - 1 以上 - 無し * - false - 指定なし - 0 - 無し * - false - 指定なし - 1 以上 - 無し * - 指定なし - false - 0 - 無し * - 指定なし - false - 1 以上 - 無し * - 指定なし - 指定なし - 0 - 無し * - 指定なし - 指定なし - 1 以上 - 無し [^#f4]: .. [#f4] audio_streaming_auto に true を指定する場合には、audio_streaming にも true を指定する必要があります > **注意** > > audio_streaming_auto に true を指定したにもかかわらず、audio_streaming を指定しないか、または false を指定した場合は、不正な組み合わせのため audio_streaming_auto、audio_streaming の指定は無視されます ### 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": "レスポンスがそのまま含まれる" } } ``` ### ウェブフック 音声ストリーミングの開始、終了時にウェブフックを通知します。 このウェブフックはデフォルト無効です。 もし利用する場合は `sora.conf` の [ignore_audio_streaming_webhook](SORA_CONF.html#8f086b) を `false` にして通知を有効にしてください。 #### audio-streaming.started - セッションで音声ストリーミングが開始した場合に通知されます - 自動開始/停止が有効の場合は `"audio_streaming_auto": true` が入ってきます - 音声ストリーミングを開始した時間が `"audio_streaming_started_timestamp"` に入ってきます - このウェブフックはかならず `session.created` よりも後に送信されます ```javascript { "data": { "audio_streaming_auto": false, "audio_streaming_started_timestamp": "2023-05-01T08:23:58.489262Z" }, "id": "VWGZ8NK2C55XBCGQ54SECK7J08", "label": "WebRTC SFU Sora", "timestamp": "2023-05-01T08:24:20.757279Z", "type": "audio-streaming.started", "version": "2023.2.0", "max_connections": 1, "node_name": "sora@127.0.0.1", "session_id": "DYPX8R6F4D11ZEG6XCX6N8EEWM", "channel_id": "sora", "multistream": true, "spotlight": false, "created_time": 1682929437, "total_connections": 1, "created_timestamp": "2023-05-01T08:23:57.274844Z" } ``` #### audio-streaming.stopped - セッションで音声ストリーミング停止した場合に通知されます - 自動開始/停止が有効な場合は `"audio_streaming_auto": true` が入ってきます - 音声ストリーミングを開始した時間が `"audio_streaming_started_timestamp"` に入ってきます - 音声ストリーミングを停止した時間が `"audio_streaming_stopped_timestamp"` に入ってきます - このウェブフックはかならず `session.destroyed` よりも前に送信されます ```javascript { "data": { "audio_streaming_auto": false, "audio_streaming_started_timestamp": "2023-05-01T08:23:58.489262Z", "audio_streaming_stopped_timestamp": "2023-05-01T08:24:20.756785Z" }, "id": "VWGZ8NK2C55XBCGQ54SECK7J08", "label": "WebRTC SFU Sora", "timestamp": "2023-05-01T08:24:20.757279Z", "type": "audio-streaming.stopped", "version": "2023.2.0", "max_connections": 1, "node_name": "sora@127.0.0.1", "session_id": "DYPX8R6F4D11ZEG6XCX6N8EEWM", "channel_id": "sora", "multistream": true, "spotlight": false, "created_time": 1682929437, "total_connections": 1, "created_timestamp": "2023-05-01T08:23:57.274844Z" } ``` ## 設定 ### audio_streaming_url **デフォルト**: 指定なし 音声ストリーミングゲートウェイの URL を指定してください。 音声ストリーミングゲートウェイは HTTP/2 に対応している必要があります。 https または http から始まる URL を指定してください。 詳細は [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) をご確認ください。 > **注釈** > > CA 証明書を指定しない場合、OS 組み込みの証明書を利用します。詳細は [ウェブフックリクエストなどの送信先サーバー証明書の検証に利用する OS 組み込みのルート CA 証明書について](WEBHOOK.html#e8a845) をご確認ください。 ## API ### StartAudioStreaming API セッションが存在し、音声ストリーミングが開始していないチャネルに対して音声ストリーミングを開始します。 詳細は [StartAudioStreaming](EXPERIMENTAL_API_AUDIO_STREAMING.html#0f1087) をご確認ください。 > **注釈** > > この API は audio_streaming_auto が true の場合は利用できません。 ### StopAudioStreaming API セッションが存在し、音声ストリーミングが開始しているチャネルに対して音声ストリーミングを停止します。 > **注釈** > > 音声ストリーミングを終了すると、すべての接続のサブスクライブしている状態は初期化され、デフォルトの値に戻ります。 詳細は [StopAudioStreaming](EXPERIMENTAL_API_AUDIO_STREAMING.html#bad1bb) をご確認ください。 > **注釈** > > この API は audio_streaming_auto が true の場合は利用できません。 ### SubscribeAudioStreamingResultPush API 指定した接続が、音声ストリーミングゲートウェイからの戻り値のプッシュ通知をサブスクライブするよう設定します。 詳細は [SubscribeAudioStreamingResultPush](EXPERIMENTAL_API_AUDIO_STREAMING.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_AUDIO_STREAMING.html#b63656) をご確認ください。 ### ListAudioStreamingResultPushState API 指定したチャネルのセッションのコネクション毎のサブスクライブの状態を確認します。 ```javascript [ { "connection_id": "B2JPGFZPMD3H973Y811MF8ZZ70", "subscribe": true }, { "connection_id": "KT116Z11KX5Y547KA1V12HW8PG", "subscribe": false }, { "connection_id": "A5GYXGRYAX6590M3AFH7F9Z2H4", "subscribe": false } ] ``` 詳細は [ListAudioStreamingResultPushState](EXPERIMENTAL_API_AUDIO_STREAMING.html#70450f) をご確認ください。 ## 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 に返すゲートウェイです。 時雨堂が開発し、 OSS として公開しています。 ### 対応サービス - [Amazon Transcribe](https://aws.amazon.com/jp/transcribe/) - [Google Cloud Speech-to-Text](https://cloud.google.com/speech-to-text) ## シーケンス図 ### Suzu + AWS Transcribe ```mermaid sequenceDiagram autonumber participant C as クライアント participant S as Sora participant Suzu participant AWS Transcribe C->>S: SRTP C->>S: SRTP C->>S: SRTP note over C, AWS Transcribe: StartAudioStreaming API 実行 C->>S: SRTP S->>Suzu: Opus over HTTP/2 Suzu->>AWS Transcribe: Ogg over HTTP/2 C->>S: SRTP S->>Suzu: Opus over HTTP/2 Suzu->>AWS Transcribe: Ogg over HTTP/2 C->>S: SRTP S->>Suzu: Opus over HTTP/2 Suzu->>AWS Transcribe: Ogg over HTTP/2 AWS Transcribe->>Suzu: JSON over HTTP/2 Suzu->>S: JSON over HTTP/2 S->>C: シグナリングプッシュ通知 ``` ### 自動開始/停止 ```mermaid sequenceDiagram autonumber participant C as クライアント participant S as Sora participant A as アプリケーションサーバー participant Suzu S->>+A: セッションウェブフック
session.created A-->>-S: "audio_streaming": true
"audio_streaming_auto": true C->>S: SRTP C->>S: SRTP C->>S: SRTP A-->>+S: SubscribeAudioStreamingResultPush API 実行 S->>-A: 200 OK note right of S: Subscribe しているCが 1 になった S->>+A: セッションウェブフック
audio-streaming.started A-->>-S: 200 OK note over S, Suzu: Suzu への HTTP/2 コネクション接続 C->>S: SRTP S->>Suzu: Opus over HTTP/2 C->>S: SRTP S->>Suzu: Opus over HTTP/2 Suzu->>S: JSON over HTTP/2 S->>C: シグナリングプッシュ通知 C->>S: SRTP S->>Suzu: Opus over HTTP/2 A-->>+S: UnsubscribeAudioStreamingResultPush API 実行 S->>-A: 200 OK note right of S: Subscribe しているクライアントが 0 になった note over S, Suzu: Suzu への HTTP/2 コネクション切断 C->>S: SRTP ``` # 転送フィルター機能 > **注意** > > この機能を利用する場合は事前にサポートまでご連絡ください > **警告** > > この機能は [実験的機能](EXPERIMENTAL.html) のため、正式版では仕様が変更される可能性があります > **注釈** > > 転送とは Sora がクライアントから受信した音声や映像を他のクライアントに送信することを意味します。 ## 概要 転送フィルター機能は、Sora 側でクライアントへ転送する音声や映像のパケットをフィルターする機能です。 ## 目的 転送フィルター機能を使うことで、Sora から音声や映像のパケットをクライアントへ転送しなくなるため、 クライアントやサーバー側の負荷を減らすことができます。 また、接続直後に音声や映像を転送しなくすることもできます。 そのため、何らかのアクションを取ってから音声と映像を流し始めることができるようになります。 ## 注意 ### 利用可能なロール この機能は `role` が `sendrecv` または `recvonly` の場合にのみ利用できます。 ### データチャネルを利用したメッセージング データチャネルを利用したメッセージング機能は転送フィルター機能の対象外です。 ## 機能 > **注釈** > > チャネル単位、コネクション単位でフィルターが設定できます。 - 転送フィルターのルール指定は、チャネル単位、コネクション単位で指定できます - 転送フィルターのルールにはコネクション ID とクライアント ID と種類 (音声、映像) が指定できます - **転送フィルタールール** に指定するコネクション ID は 音声や映像の **送信元の** コネクション ID です。 - **転送フィルタールール** に指定するクライアント ID は 音声や映像の **送信元の** クライアント ID です。 - シグナリング指定時や認証成功時に **そのコネクションに対するフィルター** を指定できます - 転送フィルター更新時に転送フィルターのバージョンを確認し、一致した場合のみ更新することができます - 転送フィルターにメタデータを持たせることができます ## 転送フィルタールールの仕様 シグナリング、認証成功時の払い出し、セッション払い出し、API で共通のフィルタールールについて説明します。 フィルターは AND と OR が指定できます。ルールはリストとオブジェクトを利用して設定します。 > **重要** > > 転送フィルターのルールでは転送先のコネクション ID やクライアント ID を指定することはできません。 > 指定できるのは Sora に音声や映像を送信しているコネクションやクライアントの ID のみです。 ### チャネル単位でフィルターを設定する [CreateChannelForwardingFilter](EXPERIMENTAL_API_FORWARDING_FILTER.html#fe98d1) API またはセッション生成時の払い出しを利用することで、 指定したチャネルに参加している **すべてのコネクションへ音声や映像を送信するかどうか** を設定できます。 ### コネクション単位でフィルター設定する [CreateConnectionForwardingFilter](EXPERIMENTAL_API_FORWARDING_FILTER.html#d80a51) API 、シグナリング接続時の指定、または認証成功時の払い出しを利用することで、 指定したチャネルの **指定したコネクションへ音声や映像を送信するかどうか** を設定できます。 特定のコネクションに対してあるコネクションの映像を送りたくないなどが可能になります。 ### OR と AND トップレベルリストは OR を表しており、リストのリストでは AND を表しています。 `[[rule_1], [rule_2, rule_3]]` この場合は `(rule_1 OR (rule_2 AND rule_3))` という転送フィルタールールが適用されます。 `[[rule_1, rule_2]]` この場合は `(rule_1 AND rule_2)` という転送フィルタールールが適用されます。 > **警告** > > `[[[rule_1, rule_2], [rule_3]], [rule_5]]` のような 3 階層のルールは定義できません。 > 転送フィルターのルールで利用できるリストの階層は 2 階層までとなります。 ### action について 転送フィルターには `action` を指定できます。 アクションには `block` と `allow` が指定できます。 - `block` を指定した場合は、 rules にマッチした条件でのみ転送をブロックします - `allow` を指定した場合は、 rules にマッチした条件でのみ転送を許可します デフォルトでは `block` になります。 > **重要** > > `block` と `allow` では `allow` が優先されます。 > * チャネルで `block` 、コネクションで `allow` が指定されていた場合、コネクションの `allow` のみが適用されます > * チャネルで `allow` 、コネクションで `block` が指定されていた場合、チャネルの `allow` のみが適用されます > * チャネルで `allow` 、コネクションで `allow` が指定されていた場合、両方の `allow` が適用されます #### ケース 1 チャネル単位の転送フィルターでは映像を `block` にして設定している状態で、 ある接続の転送フィルターでは映像を `allow` に設定した場合、 その接続では `allow` の転送フィルターだけが有効になり、その接続に映像が転送されます。 #### ケース 2 チャネル単位の転送フィルターでは映像を `allow` にして設定している状態で、 ある接続の転送フィルターでは音声を `allow` に設定した場合、 その接続には音声と映像が転送がされます。 ### version について 転送フィルターに文字列でバージョンを `version` 項目で指定することができます。これはオプションです。 転送フィルター作成時に `version` を指定した場合、 転送フィルターを更新するには `expected_version` と `desired_version` を指定する必要があります。 `expected_version` は更新する転送フィルターの `version` を指定します。 転送フィルターのバージョンが異なった場合、転送フィルターの更新は失敗します。 転送フィルターのバージョンが一致した場合、転送フィルターの更新は成功します、 `desired_version` の値が、新しい `version` の値となります。 `version` を利用する事で転送フィルターを並列で実行されても期待した値に変更することができるようになります。 ### metadata について 転送フィルターにはメタデータを `metadata` 項目を指定することができます。これはオプションです。 転送フィルター作成、または更新時に `metadata` に JSON 値を指定することができます。 この `metadata` は転送フィルターの挙動には影響せず、転送フィルターの情報を自由に書き込める項目です。 `metadata` を利用する事で転送フィルターに関する情報を自由に管理することができるようになります。 ### rules の書き方 **すべての項目は必須です** - field- フィールドには `connection_id` と `client_id` と `kind` が指定できます - `connection_id`- フィルターの対象となる音声や映像の **送信元の** コネクション ID を指定してください - `client_id`- フィルターの対象となる音声や映像の **送信元の** クライアント ID を指定してください - `kind`- フィルターに音声や映像を指定できます - operator- オペレーターには `is_in` と `is_not_in` が指定できます - `is_in`- values に指定されたリストに含まれる値にマッチしている場合は転送フィルターの対象とする - `is_not_in`- values に指定されたリストに含まれる値にマッチしていない場合は転送フィルターの対象とする - values- バリューにはかならず文字列のリスト `["string", ...]` を指定してください - `field` に合った値を指定してください - `field` が `kind` の場合は `"audio"` または `"video"` を指定してください ```javascript { "action": "block", "rules": [ // チャネルに接続しているすべてのクライアントへ connection_id "S8YEN0TSE13JDC2991NG4XZ150" からの音声と映像をブロックし転送しない // また // チャネルに接続しているすべてのクライアントへ client_id が "screen-share" の音声をブロックし転送しない [ { "field": "connection_id", "operator": "is_in", "values": ["S8YEN0TSE13JDC2991NG4XZ150"] } ], [ { "field": "client_id", "operator": "is_in", "values": ["screen-share"] }, { "field": "kind", "operator": "is_in", "values": ["audio"] } ] ] } ``` ### field に `connection_id` を指定した場合 `kind` を指定しなくても `audio` と `video` がブロックされます。 ```javascript { "action": "block", "rules": [ // チャネルに接続しているすべてのコネクションへ connection_id "S8YEN0TSE13JDC2991NG4XZ150" からの音声と映像をブロックし転送しない [ { "field": "connection_id", "operator": "is_in", "values": ["S8YEN0TSE13JDC2991NG4XZ150"] } ] ] } ``` ### 送信元の指定をせずすべての音声と映像をブロックする `kind` を指定することで送信元の指定がないフィルターを作成できます。 音声と映像の両方をブロックするので `values` に `audio` と `video` 両方を指定しています。 ```javascript { "action": "block", "rules": [ // チャネルに接続しているすべてのコネクションに対して音声と映像をブロックし転送しない [ { "field": "kind", "operator": "is_in", "values": ["audio", "video"] } ] ] } ``` ## フィルタールールの適用 - チャネル単位でのフィルター- 転送フィルターのルールにマッチした条件で、すべてのコネクションに対して転送するかどうか - コネクション単位でのフィルター- 転送フィルターのルールでマッチした条件で、指定した `connection_id` に対して転送するかどうか - フィルターの優先度- チャネル単位でフィルターとコネクション単位でのフィルターに優先度はない - 優先度は `allow` と `block` にだけあり `allow` が優先される ## 転送フィルター共通 API の仕様 ### ListForwardingFilters API 指定したチャネルのチャネルとコネクション両方の転送フィルターを確認できます。 - channel_id- string - 必須 - blocked- boolean - オプション - ブロック状況を表示するかどうかを指定します ``` $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20230628.ListForwardingFilters \ channel_id=sora \ blocked:=true \ -vvv { "channel_forwarding_filter": { "action": "block", "rules": [ [{"field": "kind", "operator": "is_in", "values": ["audio", "video"]}] ] }, "connection_forwarding_filters": [ { "connection_id": "9PZ98RZV1H3RSEZ82SBBC289F8", "action": "allow", "rules": [ [{"field": "kind", "operator": "is_in", "values": ["audio"]}] ] }, { "connection_id": "8QA9YX7ZJX3150ZJ87874TBFMG", "action": "allow", "rules": [ [{"field": "kind", "operator": "is_in", "values": ["audio"]}] ] } ], "blocked": [ { "destination_connection_id": "9PZ98RZV1H3RSEZ82SBBC289F8", "source_connection_id_list": [ "2VJPS671HH1EH3HNY13SXHS5RG" ], "kind": "audio" }, { "destination_connection_id": "9PZ98RZV1H3RSEZ82SBBC289F8", "source_connection_id_list": [ "2VJPS671HH1EH3HNY13SXHS5RG", "C4D50FG8Q16BF4YCTT0V8YGSXM" ], "kind": "video" } ] } ``` ## チャネル単位の転送フィルター API の仕様 ### CreateChannelForwardingFilter API 指定したチャネルに対して Sora の転送フィルターを作成する API です。 - channel_id- string - 必須 - rules- `[[object, ...], [object, ...]]` - 必須 - 転送フィルターのルールを指定します - action - string - オプション - `block` または `allow` - デフォルトは `block` - version- string - オプション - 転送フィルターのバージョンを指定します - metadata- json value - オプション - 転送フィルターのメタデータを指定します ``` $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20230628.CreateChannelForwardingFilter \ channel_id=sora \ rules:='[ [ {"field": "client_id", "operator": "is_in", "values": ["screen-share"]}, {"field": "kind", "operator": "is_in", "values": ["video"]} ] ]' \ -vvv ``` ### UpdateChannelForwardingFilter API 指定したチャネルの転送フィルターを更新します。 - channel_id- string - 必須 - rules- `[[object, ...], [object, ...]]` - 必須 - 転送フィルターのルールを指定します - action - string - オプション - `block` または `allow` - デフォルトは `block` - expected_version- string - オプション - 転送フィルターの期待するバージョンを指定します - desired_version- string - オプション - 転送フィルターの更新成功後のバージョンを指定します - metadata- json value - オプション - 転送フィルターのメタデータを指定します ``` $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20230628.UpdateChannelForwardingFilter \ channel_id=sora \ rules:='[ [ {"field": "connection_id", "operator": "is_in", "values": ["RAV7EG7Z693NDCZFGGXZS7WBRC"]} ], [ {"field": "client_id", "operator": "is_in", "values": ["screen-share"]}, {"field": "kind", "operator": "is_in", "values": ["video"]} ] ]' \ -vvv ``` ### DeleteChannelForwardingFilter API 指定したチャネルの転送フィルターを削除します。 - channel_id- string - 必須 ``` $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20230628.DeleteChannelForwardingFilter \ channel_id=sora \ -vvv ``` ## コネクション単位の転送フィルター API の仕様 ### CreateConnectionForwardingFilter API 指定したチャネルの特定のコネクションの転送フィルターを作成します。 - channel_id- string - 必須 - connection_id- string - 必須 - rules- `[[object, ...], [object, ...]]` - 必須 - 転送フィルターのルールを指定します - action - string - オプション - `block` または `allow` - デフォルトは `block` - version- string - オプション - 転送フィルターのバージョンを指定します - metadata- json value - オプション - 転送フィルターのメタデータを指定します ``` $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20230628.CreateConnectionForwardingFilter \ channel_id=sora \ connection_id=T9J5FM3NTH6JH4JKFGTSHB1BA0 \ rules:='[ [ {"field": "client_id", "operator": "is_in", "values": ["screen-share"]}, {"field": "kind", "operator": "is_in", "values": ["video"]} ] ]' \ -vvv ``` ### UpdateConnectionForwardingFilter API 指定したチャネルの特定のコネクションの転送フィルターを更新します。 - channel_id- string - 必須 - connection_id- string - 必須 - rules- `[[object, ...], [object, ...]]` - 必須 - 転送フィルターのルールを指定します - action - string - オプション - `block` または `allow` - デフォルトは `block` - expected_version- string - オプション - 転送フィルターの期待するバージョンを指定します - desired_version- string - オプション - 転送フィルターの更新成功後のバージョンを指定します - metadata- json value - オプション - 転送フィルターのメタデータを指定します ``` $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20230628.UpdateConnectionForwardingFilter \ channel_id=sora \ connection_id=T9J5FM3NTH6JH4JKFGTSHB1BA0 \ rules:='[ [ {"field": "connection_id", "operator": "is_in", "values": ["RX1GD666HD53F3M36PB7KEZMBR"]}, {"field": "kind", "operator": "is_in", "values": ["video"]} ] ]' \ -vvv ``` ### DeleteConnectionForwardingFilter API 指定したチャネルの特定のコネクションの転送フィルターを削除します。 - channel_id- string - 必須 - connection_id- string - 必須 ``` $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20230628.DeleteConnectionForwardingFilter \ channel_id=sora \ connection_id=T9J5FM3NTH6JH4JKFGTSHB1BA0 \ -vvv ``` ## セッション生成時のチャネル単位転送フィルター仕様 セッション生成時に転送フィルターを指定することができます。 以下はセッション接続時には音声しか転送しないフィルター例です。 ```javascript { "forwarding_filter": { "action": "allow", "rules": [ [ {"field": "kind", "operator": "is_in", "values": ["audio"]} ] ] } } ``` `version` や `metadata` も指定できます。 > **注釈** > > セッション生成時に転送フィルターを指定した場合、 > API 経由で変更するには UpdateChannelForwardingFilter API を利用する必要があります。 ## シグナリング時のコネクション単位転送フィルター仕様 シグナリング接続時に **コネクション単位での転送フィルター** を指定することができます。 この転送フィルターは接続したコネクションにのみ影響します。 > **重要** > > シグナリング接続時に転送フィルターを指定する場合は `sora.conf` にて、 > [signaling_forwarding_filter](SORA_CONF.html#d15a40) を `true` に設定する必要があります。 以下は接続時に映像を転送せずに音声だけを自分に転送するフィルター例です。 ```javascript { "type": "connect", "role": "sendrecv", "channel_id": "sora", "forwarding_filter": { "action": "block", "rules": [ [ {"field": "kind", "operator": "is_in", "values": ["video"]} ] ] } } ``` `version` や `metadata` も指定できます。 > **注釈** > > シグナリング時に転送フィルターを指定した場合、 > API 経由で変更するには UpdateConnectionForwardingFilter API を利用する必要があります。 ## 認証成功時払い出し時のコネクション単位転送フィルターの仕様 認証成功時に、コネクション単位の転送フィルターを指定することができます。 以下は映像を転送せずに音声だけをそのコネクションに転送するフィルター例です。 ```javascript { "allowed": true, "forwarding_filter": { "action": "block", "rules": [ [ {"field": "kind", "operator": "is_in", "values": ["video"]} ] ] } } ``` `version` や `metadata` も指定できます。 > **注釈** > > 認証成功払い出し時に転送フィルターを作成した場合、 > API 経由で変更するには UpdateConnectionForwardingFilter API を利用する必要があります。 ## シグナリング通知 転送フィルターを作成、更新、削除したタイミングで、 転送フィルターによって転送されていないかどうかを、シグナリング経由で通知します。 転送フィルターが影響する範囲にのみ通知されます。 通知は送信側と受信側の両方に送られます。 - destination は映像または音声の送信先です - source は映像または音声の送信元です - destination_connection_id は映像または音声の送信先の connection_id です - souce_connection_id は映像または音声の送信元の connection_id です ### forwarding.blocked 転送フィルターによりブロックが有効になったタイミングで送信側と受信側に通知されます。 以下の通知は、 `source_connection_id` の送信元から `destination_connection_id` の送信先へ送信した音声をブロックすることを表しています。 ```javascript { "type": "notify", "kind": "audio", "event_type": "forwarding.blocked", "destination_connection_id": "14P91M6B5526928T14WGPW9H6G", "source_connection_id": "GHRNJAQ40S15KCF3MZF0N7QS8R" } ``` ### forwarding.allowed 転送フィルターによりブロックが解除されたタイミングで送信側と受信側に通知されます。 以下の通知は、 `source_connection_id` の送信元から `destination_connection_id` の送信先へ送信した音声のブロックが解除されたことを表しています。 ```javascript { "type": "notify", "kind": "audio", "event_type": "forwarding.allowed", "destination_connection_id": "14P91M6B5526928T14WGPW9H6G", "source_connection_id": "GHRNJAQ40S15KCF3MZF0N7QS8R" } ``` ## フィルター例 ### 特定のクライアントにだけ音声と映像を転送しない `CreateConnectionForwardingFilter` API で音声と映像を転送したくないクライアントに対してフィルターを設定してください ``` $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20230628.CreateConnectionForwardingFilter \ channel_id=sora \ connection_id=T9J5FM3NTH6JH4JKFGTSHB1BA0 \ action=block \ rules:='[ [ {"field": "kind", "operator": "is_in", "values": ["audio", "video"]} ] ]' \ -vvv ``` このフィルターは指定したコネクションに転送するパケットのフィルターを設定しています。 `kind` で `audio` と `video` が `is_in` に設定されており、 すべてのクライアントから Sora に送信されてくる audio と video を指定したクライアントに転送しなくなります。 ### 特定の connection_id の送信元以外の音声や映像を転送しない `CreateChannelForwardingFilter` API で音声と映像の転送を許可する送信元のコネクション ID を指定してください。 ``` $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20230628.CreateChannelForwardingFilter \ channel_id=sora \ action=block \ rules:='[ [ {"field": "connection_id", "operator": "is_not_in", "values": ["S8YEN0TSE13JDC2991NG4XZ150"]} ] ]' \ -vvv ``` このフィルターでは指定したチャネルに転送するパケットのフィルターを設定しています。 `operator` に `is_not_in` を指定することで指定したコネクション ID の送信元以外からのパケットの送信をブロックします。 ### 全体をブロックしているが、一時的に特定の connection_id の送信先だけには全クライアントの音声と映像を転送する `CreateChannelForwardingFilter` API で音声と映像の転送をブロックしてください。 ``` $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20230628.CreateChannelForwardingFilter \ channel_id=sora \ action=block \ rules:='[ [ {"field": "kind", "operator": "is_in", "values": ["audio", "video"]} ] ]' \ -vvv ``` `CreateConnectionForwardingFilter` API で一時的にブロックしない送信先の connection_id を指定してください。 ポイントはコネクション単位で `action` に `allow` を指定します。 `allow` は `block` を上書きします。 ``` $ http POST 127.0.0.1:3000/ \ x-sora-target:Sora_20230628.CreateConnectionForwardingFilter \ channel_id=sora \ connection_id=T9J5FM3NTH6JH4JKFGTSHB1BA0 \ action=allow \ rules:='[ [ {"field": "kind", "operator": "is_in", "values": ["audio", "video"]} ] ]' \ -vvv ``` これで全体をブロックした状態で、指定した connection_id の送信先にだけ音声や映像が転送されます。 ## FAQ ### チャネルとコネクションの転送フィルターはどちらが優先されますか? チャネルとコネクションで優先度は特にありません。 ただしアクションの `allow` が優先されます。 チャネルのアクションが `block` でコネクションのアクションが `allow` で、 同じコネクション ID を指定した場合は `allow` が優先されます。 ### 転送フィルターでブロックされたときの挙動を教えてください Sora は転送フィルターでブロックされた音声や映像パケットをクライアントに転送しません。 そのため受信側ではパケットが「何も送られてこない」という状態になります。 転送フィルターが更新、または削除や `allow` で転送される状態になるとパケットの転送を開始します。 ### 転送フィルターを有効にした場合は ontrack は SDK 側で発火しますか? 発火します。転送フィルターはあくまで **本来転送する音声や映像を Sora でフィルターする機能** のため、 SDK 側の ontrack 自体は発火します。 ### フィルターでブロックされたりブロック解除されたタイミングをクライアント側で知ることはできますか? Sora はシグナリング通知経由でブロック/ブロック解除されたタイミングで通知します。 これはブロックされた送信側と受信側両方に通知が飛びます。 ## シーケンス図 ### チャネル単位のブロック例 ```mermaid sequenceDiagram autonumber participant C1 as クライアント1 participant C2 as クライアント2 participant C3 as クライアント3 participant S as Sora participant A as アプリケーションサーバー note over C1,S: クライアント1: WebRTC 確立 note over C2,S: クライアント2: WebRTC 確立 par C1-)S: SRTP S-)C1: SRTP (C2) and C2-)S: SRTP S-)C2: SRTP (C1) and A->>+S: CreateChannelForwardingFilter
channel_id=sora
block,kind(audio,video) S-->>-A: 200 OK note right of S: 音声と映像をこのチャネル内で転送しない end note over C1,S: ブロックフィルターで転送がブロックされる par C1-)S: SRTP and C2-)S: SRTP and note over C3,S: クライアント3: WebRTC 確立 end par C1-)S: SRTP and C2-)S: SRTP and C3-)S: SRTP end A->>+S: DeleteChannelForwardingFilter
channel_id=sora S-->>-A: 200 OK note over C1,S: ブロックフィルターが削除された par C1-)S: SRTP S-)C1: SRTP (C2) S-)C1: SRTP (C3) and C2-)S: SRTP S-)C2: SRTP (C1) S-)C2: SRTP (C3) and C3-)S: SRTP S-)C3: SRTP (C2) S-)C3: SRTP (C1) end note over C1,S: 音声と映像の転送がブロックされなくなった ``` ### チャネルフィルターとコネクションフィルター組み合わせ例 - 音声と映像がブロックされる - connection_id 1 にだけ映像が転送される ```mermaid sequenceDiagram autonumber participant C1 as クライアント1
connection_id: 1 participant C2 as クライアント2
connection_id: 2 participant S as Sora participant A as アプリケーションサーバー note over C1,S: クライアント1: WebRTC 確立 note over C2,S: クライアント2: WebRTC 確立 par C1-)S: SRTP (音声) S-)C2: SRTP (音声) and C1-)S: SRTP (映像) S-)C2: SRTP (映像) and C2-)S: SRTP (音声) S-)C1: SRTP (音声) and C2-)S: SRTP (映像) S-)C1: SRTP (映像) and note right of S: 音声と映像をこのチャネル内で転送しない A->>+S: CreateChannelForwardingFilter
channel_id=sora
block,kind(audio,video) S-->>-A: 200 OK note right of S: 映像を connection_id=1 にだけ転送する A->>+S: CreateConnectionForwardingFilter
channel_id=sora
connection_id: 1
allow,kind(video) S-->>-A: 200 OK end note over C1,S: チャネル単位フィルターで音声と映像の転送がブロックされる note over C1,S: コネクション単位フィルターで映像の転送が connection_id: 1 には許可される par note right of S: ブロックされる C1-)S: SRTP (音声) and note right of S: ブロックされる C1-)S: SRTP (映像) and note right of S: ブロックされる C2-)S: SRTP (音声) and C2-)S: SRTP (映像) note right of S: 許可されているので転送する S-)C1: SRTP (映像) end A->>+S: DeleteConnectionForwardingFilter
channel_id=sora
connection_id: 1 S-->>-A: 200 OK note over C1,S: コネクション単位のフィルターが削除された par C1-)S: SRTP (音声) and C1-)S: SRTP (映像) and C2-)S: SRTP (音声) and C2-)S: SRTP (映像) end note over C1,S: 全員が音声と映像の転送がブロックされている ``` ### version を利用した変更保証 並列に転送フィルター更新 API が叩かれてもバージョンチェックをすることで更新結果を保証する。 ```mermaid sequenceDiagram participant S as Sora participant A as アプリケーションサーバー par A->>+S: UpdateChannelForwardingFilters API
{"expect_version": "spam", "desire_version": "ham", ...} S-->>-A: 200 OK note over A: 更新成功 and A->>+S: UpdateChannelForwardingFilters API
{"expect_version": "spam", "desire_version": "beacon", ...} S-->>-A: 400 Bad Request
{"message": "INVALID-VERSION", "version": "ham"} note over A: 更新失敗 end ``` # 統計エクスポーター機能 > **注意** > > この機能を利用する場合は事前にサポートまでご連絡ください > **警告** > > この機能は [実験的機能](EXPERIMENTAL.html) のため、正式版では仕様が変更される可能性があります ## 概要 Sora 経由で統計情報コレクターに向けて統計情報をエクスポートする機能です。 ## 注意 ### IPv6 非対応 現時点で、統計エクスポーターは IPv6 を利用できません。 ## 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 ``` ### default_stats_exporter `stats_collector_url` が指定されていた場合、デフォルトでは統計情報をコレクターに送信します。 もし、統計情報の送信を接続毎に行いたい場合、この設定を `false` にし、 統計情報を送信したい接続の認証成功時に `"stats_exporter": true` を払い出すようにしてください。 ```ini default_stats_exporter = false ``` ### 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 > **注釈** > > CA 証明書を指定しない場合、OS 組み込みの証明書を利用します。詳細は [ウェブフックリクエストなどの送信先サーバー証明書の検証に利用する OS 組み込みのルート CA 証明書について](WEBHOOK.html#e8a845) をご確認ください。 統計コレクターサーバーとの通信に HTTPS を利用した際、サーバー証明書のチェックを行う CA ファイルを PEM 形式で設定して下さい。 ```ini stats_exporter_tls_verify_cacert_file = /path/to/server_cacert.pem ``` ## エクスポーター 統計情報をコレクターに対して送ります。 ### 共通 - type- 統計情報の種類情報が入ります - node_name- Sora のノード名が入ります - クラスター機能を利用していない場合は `sora@127.0.0.1` です - version- Sora のバージョンが入ります - label- sora.conf に設定された label が入ります - timestamp- Sora が stats を送る直前の時間 RFC3339 形式の (UTC) が入ります ### HTTP ヘッダー > **注釈** > > JSON のパース時の判断などに利用してください。 > **注意** > > `x-sora-session-webhook-type` は非推奨です、 `sora-session-webhook-type` を利用してください 統計エクスポーターの HTTP ヘッダー に `sora-stats-exporter-type` と `x-sora-stats-exporter-type` というヘッダー名で統計エクスポーターのタイプが入ってきます。 `type` が `connection.user-agent` の場合は `sora-stats-exporter-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 が入ります - role - session_id- セッション ID が入ります - client_id - connection_id - multistream - simulcast - spotlight - stats ```javascript { "channel_id": "sora", "session_id": "78K3N8E5M551XEKEWR8QN77PHW", "client_id": "NCD5EF3ME900ZDJ3SE27Y6AB6R", "connection_id": "NCD5EF3ME900ZDJ3SE27Y6AB6R", "id": "N6W0DBF6A957B01BKNJJR1HC04", "label": "WebRTC SFU Sora", "multistream": true, "spotlight": false, "simulcast": true, "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", "node_name": "sora@127.0.0.1", "version": "2023.2.0" } ``` ### 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 シグナリング利用時 ```mermaid sequenceDiagram autonumber participant C as クライアント participant S as Sora participant kohaku as Stats Collector Kohaku participant tsdb as TimescaleDB note over C,tsdb: WebRTC 確立 C--)S: Stats over DataChannel S->>+kohaku: Stats over HTTP/2 kohaku->>+tsdb: Insert Stats tsdb-->>-kohaku: Ack kohaku-->>-S: 200 OK ``` # E2EE 機能 > **注意** > > この機能を利用する場合は事前にサポートまでご連絡ください > **警告** > > この機能は [実験的機能](EXPERIMENTAL.html) のため、正式版では仕様が変更される可能性があります ## 概要 E2EE とは End-to-End Encryption の略で、音声や映像を、 WebRTC SFU が保持しない暗号鍵を利用して暗号化した状態で WebRTC SFU に送る仕組みです。 そのため WebRTC SFU 側では音声や映像を解析することが不可能になります。 ## 既知の問題 **この問題は将来の Sora E2EE ライブラリのリリースで解決予定です** - 同一ページで同一チャネルに複数接続できない - 同一ページで複数チャネルに接続できない ## SDK 対応状況 現時点では Sora JavaScript SDK が E2EE に対応しています。 そのほかの 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 コーデック機能 > **注意** > > この機能を利用する場合は事前にサポートまでご連絡ください > **警告** > > この機能は [実験的機能](EXPERIMENTAL.html) のため、正式版では仕様が変更される可能性があります ## 概要 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 から使用するための仕組みです。 ## サンプル **URL**: ## ドキュメント ドキュメントは にて提供しています。 ## ライセンス 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-sdk-faq` で `sora-javascript-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-sdk-faq` で `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-sdk-faq` で `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-sdk-faq` で `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) をご確認ください。 ## サンプル **URL**: ## ライセンス 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-sdk-faq` で `sora-cpp-sdk` タグを指定してご利用ください。 # Sora Python (C++) SDK ## 概要 **URL**: Sora Python SDK は Sora を Python から使用するための仕組みです。 ## 特徴 - Sora C++ Python SDK をベースにしています - Windows / macOS / Linux といったプラットフォームに対応しています - それぞれのプラットフォーム向けのハードウェアエンコーダー / デコーダーに対応しています ## サンプル の example にサンプルがあります。 ## ドキュメント ドキュメントは にて提供しています。 ## ライセンス Sora Python SDK は [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) で公開しています。 ## サポートについて Sora Python SDK に関する質問・要望・バグなどの報告は Discord の利用をお願いします。 Sora のライセンス契約の有無に関わらず、応答時間と問題の解決を保証しませんのでご了承ください。 ただし、明らかなバグに関しては優先的に対応させていただきます。 Sora Python SDK に対する有償のサポートについては提供しておりません。 ## Discord **URL**: Discord にてコミュニティを運営しています。 なにか質問したい場合は Discord サーバーへ参加してください。 Sora Python SDK については `#sora-sdk-faq` で `sora-python-sdk` タグを指定してご利用ください。 # Sora C (C++) SDK ## 概要 **URL**: Sora C SDK は Sora を C から使用するための仕組みです。 ## 特徴 - macOS / Linux といったプラットフォームに対応しています - それぞれのプラットフォーム向けのハードウェアエンコーダー / デコーダーに対応しています - 他の SDK と異なり `libwebrtc` を利用せず、 libdatachannel を利用しているためバイナリサイズ、フットプリントが抑えられています - リリース周期を長めにすることを目標にしています 詳細は [Sora C SDK](https://github.com/shiguredo/sora-c-sdk) をご確認ください。 ## ライセンス 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-sdk-faq` で `sora-c-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 Archive Uploader ## 概要 [shiguredo/sora-archive-uploader: Sora Archive Uploader](https://github.com/shiguredo/sora-archive-uploader) Sora Archive Uploader は Sora の出力する録画ファイルを S3 または S3 互換のオブジェクトストレージに、アップロードするツールです。 Systemd timer などで定期的に実行することで、録画ファイルを自動的にアップロードすることができます。 問題になりがちな録画ファイルのアップロードに利用する帯域を制限する事ができます。 ## ライセンス Sora Archive Uploader は [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) で公開しています。 ## サポートについて Sora Archive Uploader のサポートやアドバイスは提供していません。 ## Discord **URL**: Discord にてコミュニティを運営しています。 なにか質問したい場合は Discord サーバーへ参加してください。 Sora Archive Uploader についての質問やバグ報告は Discord の `#sora-tool-faq` チャンネルにお願いします。 # 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 についての質問やバグ報告は Discord の `#sora-tool-faq` チャンネルにお願いします。 # 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 について ## 概要 2024 年 4 月 時点で Microsoft Edge 121 を使用して確認しています。 [Download New Microsoft Edge Browser | Microsoft](https://www.microsoft.com/en-us/edge) ## 現状 Chrome とほぼ同様の仕様で、特に問題なく動作します。 Edge 121 から AV1 もサポートされています。 # Apple Safari の WebRTC について ## 概要 2023 年 6 月時点で Safari 16.4 を使用して確認しています。 ## 注意点 - 音声が含まれているまたは音声のみの配信の場合 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 が実装されていません。 そのため、画面共有を利用するにはネイティブアプリケーションを利用する必要があります。 2023 年 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](https://www.apple.com/jp/safari/) や [Safari Technology Preview (Safari TP)](https://developer.apple.com/safari/technology-preview/) では実験的機能の挙動が異なります ### H.265 が利用可能 [Safari](https://www.apple.com/jp/safari/) や [Safari Technology Preview (Safari TP)](https://developer.apple.com/safari/technology-preview/) 最新版では開発メニューで有効にすることで H.265 が利用できます。 ### WebRTC AV1 が利用可能 [Safari](https://www.apple.com/jp/safari/) や [Safari Technology Preview (Safari TP)](https://developer.apple.com/safari/technology-preview/) 最新版では開発メニューで有効にすることで WebRTC AV1 が利用できます。 ### VP9 Profile 2 が利用可能 [Safari](https://www.apple.com/jp/safari/) や [Safari Technology Preview (Safari TP)](https://developer.apple.com/safari/technology-preview/) 最新版では開発メニューで有効にすることで VP9 Profile 2 が利用できます。 # 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 で利用しているオープンソースのライセンス一覧** ## Apache License 2.0 **URL**: - [erlang/otp](https://github.com/erlang/otp) - [openssl/openssl](https://github.com/openssl/openssl) - [uwiger/gproc](https://github.com/uwiger/gproc) - [rabbitmq/ra](https://github.com/rabbitmq/ra) - [rabbitmq/gen-batch-server](https://github.com/rabbitmq/gen-batch-server) - [rabbitmq/aten](https://github.com/rabbitmq/aten) - [rabbitmq/seshat](https://github.com/rabbitmq/seshat) - [shiguredo/swidden](https://github.com/shiguredo/swidden) - [shiguredo/jesse](https://github.com/shiguredo/jesse) - [shiguredo/kvconf](https://github.com/shiguredo/kvconf) - [shiguredo/base32_clockwork](https://github.com/shiguredo/base32_clockwork) - [shiguredo/sora-devtools](https://github.com/shiguredo/sora-devtools) ## ISC License **URL**: - [ninenines/cowboy](https://github.com/ninenines/cowboy) - [ninenines/cowlib](https://github.com/ninenines/cowlib) - [ninenines/ranch](https://github.com/ninenines/ranch) - [ninenines/gun](https://github.com/ninenines/gun) ## その他のライセンス [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. ``` [ferd/recon: Collection of functions and scripts to debug Erlang in production.](https://github.com/ferd/recon): ``` Copyright (c) 2012-2023, Fred Hebert 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. ``` # 古いリリースノート **UPDATE** : 後方互換性がある変更 **ADD** : 後方互換性がある追加 **CHANGE** : 後方互換性のない変更 **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] 音声ストリーミング機能でロールが `recvonly` の場合にプッシュ通知が受信できない問題を修正しました - [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` が `signaling.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_CLUSTER.html#621990) API を追加しました - [CHANGE] クラスター機能の [ListClusterNodes](EXPERIMENTAL_API_CLUSTER.html#a70901) API の `member_since` を廃止しました - [CHANGE] クラスター機能の [ListClusterChannels](EXPERIMENTAL_API_CLUSTER.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}` のように指定できるようになりました- この指定を利用する場合は `sora_conf-legacy_webhook_audio_video_json_structure` を `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_AUDIO_STREAMING.html#0f1087) API を追加しました - [ADD] 音声ストリーミングを終了する [StopAudioStreaming](EXPERIMENTAL_API_AUDIO_STREAMING.html#bad1bb) API を追加しました - [ADD] 音声ストリーミングの解析結果を購読する [SubscribeAudioStreamingResultPush](EXPERIMENTAL_API_AUDIO_STREAMING.html#d26262) API を追加しました - [ADD] 音声ストリーミングの解析結果を購読解除する [UnsubscribeAudioStreamingResultPush](EXPERIMENTAL_API_AUDIO_STREAMING.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 構造する `sora_conf-legacy_webhook_audio_video_json_structure` を追加しました- デフォルトでは `true` です - これは移行用設定です 詳細は ウェブフックの audio と video 項目の JSON 構造のフラット化 をご確認ください #### セッションウェブフックログを req/res 形式に変更 - [CHANGE] `session_webhook.jsonl` の出力形式を req/res 形式に変更しました - [CHANGE] `session_webhook_error.jsonl` の出力形式を req 形式に変更しました #### 録画とアーカイブ開始ウェブフックを追加 - [ADD] 録画開始ウェブフック [recording.started](SESSION_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_RECORDING.html#fd0de5) API の `redirect` を廃止しました ### 互換なしの変更情報 - マルチストリームをデフォルトで有効にしました- `sora.conf` の `default_multistream` を `false` にすることでマルチストリームがデフォルトではなくなります - この設定は 2023 年 6 月リリースの Sora にて廃止されます - 詳細は [sora.conf の default_multistream の廃止](OBSOLETE.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 の廃止](OBSOLETE.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 の廃止](OBSOLETE.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 の廃止](OBSOLETE.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 の廃止](OBSOLETE.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_STATS.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 の廃止](OBSOLETE.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 の廃止](OBSOLETE.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_CLUSTER.html#17f3f5) API の `cluster_node_name` を `contact_node_name` に変更しました - [CHANGE] [ListClusterNodes](EXPERIMENTAL_API_CLUSTER.html#a70901) API の `cluster_node_name` を `node_name` に変更しました - [ADD] クラスターから特定のノードの情報を完全消去する [PurgeClusterNode](EXPERIMENTAL_API_CLUSTER.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] ネットワーク障害等発生時に自動で復旧を試みる仕組みを追加しました- 詳細は以下をご確認ください - 通信できるノードが過半数未満となった場合の挙動 - 通信できるノードが過半数以上となった場合の挙動 - 全ノードが過半数未満に所属した場合の挙動 #### 最大ノード数対応ライセンス クラスター利用時に、複数のノードに同一のライセンスが利用できる最大ノードライセンスの提供を開始しました。 詳細は [最大ノード数ライセンス](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"` という文字列に書き換えます ## 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_SIGNALING.html#d3da2a) API をご利用ください。 - [ListChannelClients](OBSOLETE_API.html#a65eee) API を廃止しました- 今後は [ListChannelConnections](API_SIGNALING.html#d388f3) API をご利用ください ### 互換性なしの変更情報 **変更点の不明点についてはサポートまでお問い合わせください** **猶予期間を儲けない変更となっておりますのでご注意ください** - [ListConnections](API_SIGNALING.html#d3da2a) API の戻り値に含まれる `connection_created_timestamp_sec` の項目名を `created_time` に変更、単位を秒からマイクロ秒に変更しております - [ListChannelConnections](API_SIGNALING.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_STATS.html#bbbfca) API に合計セッション生成回数 `total_session_created` を追加しました - [ADD] [GetStatsReport](EXPERIMENTAL_API_STATS.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_CLUSTER.html#17f3f5) API を追加しました- クラスターからの離脱は `bin/sora stop` を実行します - [ADD] クラスターに参加しているノード一覧を取得するための [ListClusterNodes](EXPERIMENTAL_API_CLUSTER.html#a70901) API を追加しました - [ADD] クラスターに割り当てられているチャネル ID 一覧を取得するための [ListClusterChannels](EXPERIMENTAL_API_CLUSTER.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_LEGACY_RECORDING.html#c5b527) API にて `metadata` を指定可能にしました- `metadata` は JSON オブジェクトである必要があります - `metadata` はオプションです - [ADD] `recording.report` や録画メタデータファイルに [StartRecording](API_LEGACY_RECORDING.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_SPOTLIGHT.html#5c2650) API` を追加しました - [ADD] スポットライトのフォーカス/アンフォーカス挙動をリセットする [ResetSpotlightRid](API_SPOTLIGHT.html#680344) API を追加しました - [ADD] スポットライトのフォーカス/アンフォーカス挙動を一括で変更する [BatchRequestSpotlightRid](API_SPOTLIGHT.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_USER_AGENT_STATS.html#f9a4fe) API を追加しました- [GetAllRemoteStats](OBSOLETE_API.html#3a6504) の代替 API です - [ADD] [ListChannelUserAgentStats](EXPERIMENTAL_API_USER_AGENT_STATS.html#df496a) API を追加しました- [GetChannelRemoteStats](OBSOLETE_API.html#bbd252) の代替 API です - [ADD] [GetUserAgentStats](EXPERIMENTAL_API_USER_AGENT_STATS.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": "