はじめに
SENCA は、ライブ配信・録画・リアルタイム通信のためのメディアサーバーです。Rust で書かれていて、Apache-2.0 ライセンスで公開しています。
senca-node を 1 台で動かしても、複数のノード(サーバー)を束ねたクラスターとして動かしてもかまいません。SENCA ではこのクラスターを「グリッド」と呼びます。
全体像をひとことで言うと、取り込んだストリームはストリームごとのハブ(ストリームハブ)に集まり、そこから配信・録画・加工へ分かれていきます。設定や状態はコントロールプレーン(設定・トークン・所有権などを管理する部分)でひとまとめに管理し、1 台ならディスク上の追記ログに、クラスターなら Raft で複数のノードに記録します。コーデックだけは権限を絞った別プロセスで動かし、H.264/H.265 は GPU メーカーの SDK を通してしか扱いません。
このドキュメントは v0.0.1 を対象にしています。
実行ファイル
| 実行ファイル | 役割 |
|---|---|
senca-node | 本体です。映像・音声の取り込み、メディアの処理、配信、全体の制御を 1 つのプロセスで行います |
senca-codec-worker | コーデックを実行する別プロセスです。senca-node がこれを複数起動し、まとめて使います。senca-node とはパイプで通信し、大きなフレームは共有メモリで受け渡します。権限を絞ったサンドボックスの中で動きます |
senca-capture-worker | キャプチャデバイス(V4L2・ALSA・DeckLink)を扱う別プロセスです。このファイルがなくても senca-node は動きます。使えなくなるのはキャプチャデバイスだけです |
senca-node は、自分と同じディレクトリにある senca-codec-worker と senca-capture-worker を探して起動します。
senca-codec-worker を別の場所に置く場合は、--codec-worker-bin でその場所を指定します。
全体の構成
全体の構成は次の図のとおりです。取り込んだストリームは、ストリームごとのハブに集まり、そこから配信・録画・加工へ分かれます。
図の stream hub がストリームハブ、packager が HLS のパッケージャー(セグメントに分ける処理)、recorder が録画の処理、LiveCache が HLS 用のメモリ上のキャッシュにあたります。AU(アクセスユニット)は、エンコード済みの映像 1 フレーム分のデータです。
制御プレーン(設定と状態の管理)
制御プレーンは、「何をどう動かすか」を管理する部分です。ストリーム、トークン、録画の情報、予約、入力、出力、シークレット、パイプライン、ルームといった設定は、どれもコントロールプレーンのデータです。コントロールプレーンは届いたコマンドを順に適用して更新するので、同じコマンドを同じ順で適用すれば必ず同じ状態になります。
1 台で動かすときは、コマンドを 1 件ずつ control/log に追記し、fsync(ディスクへの書き込みを確定させる操作)が終わってから API に応答します。1000 件たまるごとに状態全体を control/snapshot.json に保存し、ログを空にします。
クラスターでは、同じコマンドを Raft で複数のノードに複製します。Raft は、複数台が合意しながら同じ記録を持つための仕組みで、SENCA は独自に実装しています。投票に加わるノードは 1〜7 台です。書き込みはどのノードに送ってもリーダーへ転送されます。ネットワークが分断されて過半数と通信できなくなった側では、書き込みは 503 で断られます。読み取りは、各ノードが手元に持っている状態から返します。
クラスターについて詳しくは、クラスターとグリッド を参照してください。
ハブ・HLS の分割・録画
ハブはストリームごとに 1 つのタスクとして動きます。配信者との接続が切れてもすぐには消えず、猶予時間内に再接続があれば同じストリームのまま配信を続けます。猶予時間は --reconnect-grace で指定でき、既定は 30 秒です。入力のキューには上限があり、ハブの処理が遅れたときは配信者からの読み込みをいったん止めます。TCP の流量制御で配信者側を待たせる形です。
HLS 用のセグメントへの分割と多重化は、ハブの中で 1 回だけ行い、結果をメモリ上のキャッシュに置きます。ライブの HLS ではディスクを使いません。
録画の処理は、録画中のストリームがあるときだけ動きます。ライブ配信と同じセグメントを segments/ に変更しないファイルとして書き込み、録画ごとのインデックス(録画を構成するセグメントの一覧。recordings/{id}/index.jsonl)に追記していきます。処理が追いつかずキューがあふれたら、録画側でセグメントを捨てて欠落(gap)として記録します。ライブ配信はその間も止まりません。書き込みの途中で止まっていた録画は、次の起動時に interrupted として閉じます(運用 を参照)。
コーデックを動かす別プロセス
H.264/H.265 のエンコード・デコードには、GPU メーカーの SDK(NVENC/NVDEC・oneVPL・AMF・VA-API)を使います。 AV1・VP8/VP9・Opus には、ロイヤリティフリーのライブラリ(dav1d・SVT-AV1・libvpx・libopus)を使います。
これらのライブラリは、実行時に dlopen で読み込みます。読み込むのは senca-node ではなく senca-codec-worker です。
senca-codec-worker は、seccomp・Landlock・rlimit などで権限を制限した別プロセスとして動きます。
詳しくは セキュリティ と コーデックと特許 を参照してください。
senca-codec-worker やライブラリがない環境でも、受け取ったストリームをそのまま配信・録画するだけなら動きます。変換・静止画・サムネイルを求められたときは 503 CAPACITY_UNAVAILABLE を返します。
グリッド(ワークロードの配置)
グリッドは、ワークロードをどのノードで動かすかを決める仕組みです。ワークロードとは、pull 入力、push 出力、パイプライン、ルーム、メディアパイプラインのように、ノードの上で動き続けるもののことです。
各ノードの資源(CPU・メモリ・帯域・GPU・キャプチャデバイス)を集計し、Raft のリーダーが割り当てを決めて、結果を複製されるログに記録します。ノードやデバイスが停止するとワークロードは別のノードへ移り、移す先がなければ機能を一部落としたまま動き続けます。資源が戻れば元の状態に戻ります。1 台で動かしているときも仕組みは同じです。
詳しくは クラスターとグリッド を参照してください。
ノード間の中継
クラスターでは、ストリームを受け取っていないノードに視聴者がつながることもあります。そのときは、ストリームを持っているノードからエンコード済みの AU を受け取り、手元の複製から配信します。
ノード間の転送は 1 本の接続にまとめ、上流からはストリームごとに 1 本だけ流します。同じノードに視聴者が 100 人いても、転送は 1 回分で済みます。
リアルタイムのルーム
ルームは、WebRTC の SFU(参加者の映像・音声を変換せずに、ほかの参加者へ転送する中継サーバー)です。 サイマルキャスト、スポットライト、転送の絞り込み、DataChannel に対応し、E2EE(エンドツーエンド暗号化)のデータは復号せずにそのまま転送します(パススルー)。
シグナリング(接続の取り決めのやり取り)は WebSocket(GET /signaling)で行い、参加には参加トークンが要ります。ルームはグリッドのワークロードの一つとして、どれか 1 つのノードに割り当てられます。
詳しくは リアルタイムのルーム を参照してください。
メディアパイプライン
メディアパイプラインは、ルームの参加者の映像・音声を SENCA のストリームとしてエクスポートする機能です。 エクスポートしたストリームは、合成、録画、RTMP などでの外部への送信、文字起こしにつなげられます。 詳しくは メディアパイプライン を参照してください。
データの扱い方
受け取ったメディアデータは一度だけ組み立て、あとはコピーせずに同じものを共有します。新しくデータを作るのは、TS・fMP4 への多重化や暗号化のように形式を変えるときだけです。ノードの中の各部分はメモリ上の通り道でつながっていて、同じマシンの中で TCP や外部のメッセージブローカーを経由することはありません。
処理の遅い購読者は、取りこぼしに気づいた時点で次のキーフレームから再開します。そのため、1 人の遅れがほかの購読者を待たせることはありません。新しくつながった購読者には、直近の GOP(キーフレームから次のキーフレームの手前までのひとまとまり)を先に渡します。
機能の一覧
| 分野 | 主な機能 | ページ |
|---|---|---|
| 取り込み | RTMP/RTMPS(Enhanced RTMP による AV1・VP9・H.265)、SRT(listener・caller、AES 暗号化)、WHIP | 取り込みと再生 |
| 再生 | HLS(TS・fMP4・LL-HLS)、RTMP play、WHEP、RTSP play、署名付きの再生 URL | 取り込みと再生 |
| 録画 | ライブ配信と並行した録画、VOD、MP4 のエクスポートし、予約録画、保持期間、法的保全(legal hold)、障害後の復旧 | 録画 |
| 入力・出力 | RTMP・RTSP・SRT・HLS の pull、キャプチャデバイス、RTMP・SRT の push、PaaS 連携(クラウドの配信サービスとの連携)、シークレット | 入力と出力 |
| 加工 | パイプライン(デコード・合成・板書補正・音声ミキサー・エンコード)、配信制作の操作、静止画・サムネイル | パイプライン |
| 字幕 | 外部の音声認識・翻訳サービスと連携した、WebVTT による HLS の字幕 | 字幕と翻訳 |
| クラスター | Raft による設定と状態の複製、mTLS、ストリームの所有権の管理、グリッドによる配置とデグレード、ノード間の中継 | クラスターとグリッド |
| ルーム | SFU、参加トークン、ブラウザー用 SDK | リアルタイムのルーム |
| メディアパイプライン | ルームのエクスポート・合成・録画・外部への送信・文字起こし | メディアパイプライン |
| 認証・保護 | API トークンと権限、JWT、署名付き URL、シークレットの暗号化保存、外部への接続の制限 | セキュリティ |
| 運用 | ヘルスチェック、ログ・監査ログ、SSE、障害後の復旧、バックアップ、drain(受け付けを止めて移す操作)、停止 | 運用 |
| コーデック | ハードウェアコーデックとロイヤリティフリーのコーデック、特許への対応方針 | コーデックと特許 |
| API | REST(OpenAPI)、SSE、TypeScript・Rust のクライアント | 管理 API と SDK |
管理画面(リポジトリの apps/console)は、--console-dir を指定すると /console/ で開けます。
ブラウザーから WHIP で配信するためのページ(リポジトリの apps/sender-web)は、--sender-dir を指定すると /sender/ で開けます。
スマートフォン・タブレット・Mac からは、Android 向けと iOS・iPadOS・macOS 向けの配信アプリ(リポジトリの apps/sender-android・apps/sender-apple)を使い、SRT か RTMP で送れます。アプリのカメラのズームなどは、VISCA over IP で離れた場所から操作できます。
対応していないこと
- 録画の共有ストレージ。録画は各ノードのローカルディスクに保存します。S3 互換のオブジェクトストレージへのアップロードについては、録画 を参照してください
- 読み取りの線形化(クラスター全体で最新の状態を読み取ることを保証する機能)。読み取りは、各ノードが手元に持っている状態から返します
- AAC のエンコード・デコード。AAC は中身を変えずにそのまま中継することだけができます。そのため、AAC の音声を WebRTC へ送ることはできません
関連するページ
この文書の原文は、リポジトリの docs/guide/ja/01-overview.md にあります。内容は現在の版(v0.0.1)に合わせています。