一度だけ組み立て、
あとは共有する。

SENCA は、高速な処理を重視して作ったメディアサーバーです。受け取ったデータは一度だけ組み立て、あとはコピーせずに各所で使い回します。ノードの中の部分どうしはメモリの上でつながっているので、外部のメッセージブローカーは要りません。設定は、同じ操作を同じ順に当てはめれば必ず同じ結果になる形で管理します。クラスターでは、独自に実装した Raft(合意の方式)でこれを全ノードに複製します。

  • データのコピーを減らした高速な処理
  • 通信の方式は自前で実装
  • 外部のメッセージブローカーは不要
  • Apache-2.0

プログラムの分担

3 つのプログラムに分け、外部のライブラリは本体の外で動かす。

GPU の SDK、コーデック、キャプチャ機器のドライバーといった外部のライブラリは、本体とは別のプロセスで動かします。別プロセスが異常終了しても、失敗するのはその処理だけです。別プロセスは起動し直され、ノード本体は動き続けます。

本体

ノード本体senca-node

映像の取り込み、メディアの処理、視聴者への配信、設定の管理を、1 つのプロセスで行います。外部のコーデックのライブラリは読み込みません。

コーデック

変換用の別プロセスsenca-codec-worker

エンコード・デコード・合成を担当します。ノード本体が複数起動してまとめて使い(プール)、パイプでやり取りします。大きな画像のデータは共有メモリで渡します。seccomp・Landlock・rlimit で、できることを絞って動きます。

キャプチャ

キャプチャ用の別プロセスsenca-capture-worker

V4L2・ALSA・DeckLink の機器から映像・音声を取り込み、エンコードしてからノード本体へ渡します。このプログラムが無くても、キャプチャ機器が使えないだけで、ほかの機能は動きます。

ノードの中

ストリームハブに集めて、そこから配信する。

  • ストリームハブ:ストリーム 1 本ごとに 1 つ用意する集約点です。配信者の接続が切れてもハブは残り、猶予時間(既定 30 秒)のうちに再接続すれば、同じ配信の続きになります。受け取ったデータをためる量には上限があり、処理が遅れると配信者からの読み込みを一時的に止めます(TCP のフロー制御によるバックプレッシャー)。
  • HLS のパッケージング:映像をセグメントに分けてまとめる処理を、ハブの中で 1 回だけ行い、結果をメモリに置きます。ライブの HLS ではディスクを使いません。
  • 購読者(視聴・送信):RTMP・SRT・RTSP での再生、WHEP での再生、外部への送信、パイプラインが、購読者としてハブからデータを受け取ります。処理が遅れて取りこぼした購読者は、次のキーフレームから再開するので、ほかの購読者を待たせません。新しく加わった購読者には、直近のキーフレームからの映像を先に渡します。
  • 録画:ライブと同じセグメントを、書き換えないファイルとして保存し、録画ごとのインデックスに追記します。書き込みが追いつかないときは、録画の側に欠けた部分として記録し、ライブは止めません。

取り込みと再生(ドキュメント) 録画(ドキュメント)

RTMP/RTMPS SRT WHIP MoQ pull キャプチャ │ │ │ │ │ │ ▼ ▼ ▼ ▼ ▼ ▼ ┌─ ストリームハブ(ためる量に上限あり) │ ├─ HLS のパッケージング → メモリ上のキャッシュ │ │ └→ HLS · LL-HLS · 字幕(WebVTT) │ ├─ 視聴・送信: RTMP/SRT/RTSP の再生 · WHEP │ │ 外部への送信 · パイプライン · MoQ │ └─ 録画 → segments/(書き換えない) │ recordings/{id}/index.jsonl └────────── │ エンコード・デコード・合成 ▼ senca-codec-worker(別プロセス・権限を絞って実行) 管理 API(REST・SSE)→ コントロールプレーン 単一ノード: control/log(追記して fsync) クラスター: Raft で複製(control/raft/) グリッド: ワークロードをノードへ配置 中継: エンコード済みのデータをノード間で転送

設定の管理

設定は、コマンドを順に当てはめて作る。

配信、トークン、録画の情報、予約、入力と出力、シークレット、パイプライン、ルームなどの設定を、まとめてコントロールプレーンのデータとして持っています。更新するときは、変更のコマンドを 1 件ずつ順に当てはめます。同じコマンドの列からは、どのノードでも同じ状態ができあがります。

単一ノードのとき

コマンドを 1 件ずつ control/log に追記し、ディスクへの書き込みを確定(fsync)してから API の応答を返します。1000 件ごとに状態の全体をスナップショットとして保存し、ログを空にします。

クラスターのとき(独自に実装した Raft)

投票に加わるノードは 1〜7 台です。どのノードに書き込んでも、リーダーへ転送されます。過半数と通信できない側では書き込めず、503 を返します。読み取りは、各ノードが手元の状態から返します。内部の時計の刻みは 100 ミリ秒で、リーダーと連絡が取れなくなってから選び直すまでの待ち時間は 1〜2 秒です。

クラスターとグリッド(ドキュメント)

ワークロードの配置(グリッド)

毎秒、同じ規則で配置を決める。

グリッドは、外部からの取り込み(pull)、外部への送信(push)、パイプライン、ルームをワークロード(ノードの上で動き続ける処理)として扱い、ノードと機器(GPU・キャプチャ機器)に割り当てます。配置の計算は、同じ条件からは必ず同じ結果になるように作っています。ノードが 1 台だけのときも、同じ仕組みで動きます。

生存の知らせ
各ノードは 1 秒ごとに、受けている配信、動かしているワークロード、機器の状態をリーダーへ送ります。この知らせは、全ノードで共有する記録(合意ログ)には書きません。
停止の判定
最後の知らせから 5 秒を超えたノードを「停止」と判定し、合意ログに記録します。GPU などの機器は 10 秒ごとに検出し直します。
配置の計画
リーダーが毎秒計算します。同じ入力からは、いつも同じ結果になります。結果は合意ログに記録され、各ノードは自分の分だけを動かします。
資源の見積もり
配置は実際の使用量ではなく、ワークロードごとに決めた見積もりの合計で計算します。たとえばパイプラインの AV1 のエンコードは、CPU 1500 ミリコア(1.5 コア分)と見積もります。
ノードの選び方
spread を選ぶと、配置した後の空きが多いノードへ、binpack を選ぶと空きが少ないノードへ詰めて置きます。入力の配信を受けているノードは大きく優先します(データを運ぶ手間を減らすため)。
優先度とデグレード
優先度の高いワークロードから配置します。空きが無ければ、より低い優先度のワークロードをデグレードさせるか、別へ移します。同じか高い優先度のワークロードを押しのけることはありません。
元に戻す
デグレードしたワークロードは、状態が変わってから 30 秒のクールダウンを置いて元に戻します。行ったり来たりを防ぐためです。
分断されたとき
過半数のノード(またはリーダー)との通信が 4 秒を超えて途絶えた少数側は、取り込み(pull)・送信(push)・パイプラインを止め、/readyz が 503 を返すようにします。

配置の設定の方法(ドキュメント)

配信の所有者

同じ配信を受けるのは、1 か所だけ。

  • 配信者がつないだノードは、その配信の所有権の取得をクラスターに提案します。提案が適用されると、新しいフェンシングトークン(所有者が替わるたびに増える番号)を受け取って所有者になります。
  • ほかのノードが同じ配信の配信者を受けていれば、そちらの接続を切ります。後からつないだ方が優先され、同じ配信が 2 つのノードで同時に公開されることはありません。
  • 配信が終わったとき(再接続の猶予が過ぎたとき)や、ノードが停止と判定されたときは、所有権を解放します。
  • 録画と字幕の作成は、所有者のノードが行います。

ノード間の中継

どのノードでも見られる。
転送は 1 本だけ。

  • 所有者ではないノードに視聴の要求が来ると、そのノードは所有者からエンコード済みのデータを受け取り、手元の写し(ミラー)から配信します。ノード間は 1 本の接続にまとめて運びます。
  • 同じノードに何人の視聴者がいても、所有者からの転送は配信ごとに 1 本です。転送のときに変換はしません。
  • 写しを作れないときは、所有者のノードへ 307 で転送先を案内します(予備の経路)。録画は、録画したノードへ案内するか、S3 互換のストレージから返します。

クラスターとグリッド(ドキュメント)

ROOMS

ルームは 1 つのノードに置く

ルーム(ビデオ通話)は、グリッドのワークロードとして、ちょうど 1 つのノードに置かれます。別のノードにつないだ参加者には、ルームのあるノードを案内します。複数のノードで受け付ける設定(カスケード)のルームでは、つないだノードで受け付けます。参加者の状態は、ほかのノードへ複製しません。

MEDIA PIPELINES

ルームのノードが毎秒そろえる

メディアパイプライン(会議の録画や配信)は、ルームを置いたノードが 1 秒ごとに参加者を確かめ、エクスポートする配信・合成・出力を、あるべき状態にそろえます。作るものの ID は決まった規則で付けるので、作り直しても同じ ID になります。

QUIC

1 つの UDP ポートで 3 つの方式

--quic を指定すると、1 つのポートで HTTP/3(h3)と MoQ(moqt-22)を受け付けます。どちらかは接続の最初の交渉(ALPN)で見分けます。HTTP/3 の上の WebTransport を使った MoQ も受け付けます。

実装の方針

通信の方式は自前で。暗号の計算は、検証されたライブラリで。

通信から切り離して試験する

通信の方式の実装は、ネットワークや時計に直接触れない形で書いています。そのため、実際の通信なしで細かく試験できます。Raft は、毎回同じ結果が再現できるシミュレーションで試験しています。

外部のライブラリは一覧で管理

製品で使ってよい外部のライブラリは、一覧を作って決めています。TLS 1.3・DTLS 1.2・SRTP・QUIC の接続の手順と、データを暗号化して運ぶ部分は自前で実装しています。AES・SHA・署名などの暗号の計算には、RustCrypto などのライブラリを使います。

FFmpeg は試験の相手としてだけ使う

FFmpeg やブラウザーは、つないで動作を確かめる相手として使います。製品には含めません。

セキュリティ コーデックと特許の方針(ドキュメント)

部品の地図

役割ごとに、層を分けています。

SENCA の中の部品を、役割ごとに 5 つの層に並べました。下の層ほど、データの形や通信の方式に近い部分です。

使う側の道具

ノード本体と、SENCA を外から操作するための道具です。

  • ノード本体サーバーとして起動する実行ファイル(senca-node)です。
  • Rust のクライアント管理 API を Rust から使うためのライブラリ(senca-client)です。型の付いたデータ、一覧のページ送り、再送しても二重に実行しない仕組み、ETag、イベントの受信(SSE)を扱います。
  • 送信用の SDKRTMP・SRT で映像を送るための SDK です。C から呼べる、互換性を保つ形のインターフェース(C ABI)を持ちます。

制御と分散

設定の複製、ワークロードの配置、配信の所有者の管理、ノード間の中継です。

  • 設定の管理設定を「コマンドを順に適用する」形で管理します。API トークン・JWT による認証と、エラーの返し方もここで決めています。
  • 設定の複製(Raft)クラスターのノード間で設定を複製する、独自に実装した Raft です。リーダーの選び直しを安定させる仕組み(PreVote・CheckQuorum)、投票者の入れ替え、スナップショット、ファイルへの保存に対応します。
  • ワークロードの配置(スケジューラー)ワークロードをどのノードで動かすかを決めます。資源が足りないときに処理の一部を外して動かし続ける仕組み(デグレード)、停止の検出、分断されたときに少数側のワークロードを止める仕組み(フェンシング)も担当します。
  • ノード間の中継ノード同士を 1 本の接続でつなぎ、複数の配信をまとめて運びます。優先度を付けて送り、同じ配信を求める視聴の要求は 1 つにまとめます。
  • ルーム(ビデオ通話)参加の手続きのやり取り(シグナリング)、ルームの状態、スポットライト、転送フィルター、参加トークン、Webhook を扱います。
  • 録画の管理ライブ配信と共有する、書き換えないセグメントのファイルと、録画ごとに追記だけをするインデックスで録画を管理します。
  • S3 互換のストレージS3 の署名(SigV4)を付けた要求を組み立てます。応答の XML は大きさに上限を設けて読み取ります。
  • クラウドの配信サービスCloudflare Stream・Amazon IVS・MediaLive と連携し、インジェストエンドポイントの作成と削除を行います。

メディアの処理

変換、合成、字幕、キャプチャです。

  • コーデックの呼び出しコーデックを共通の形で扱います。GPU メーカーの SDK や、ロイヤリティフリーのコーデックのライブラリは、実行時に読み込みます。
  • コーデックの隔離コーデックを別プロセスに分けて動かします。ノード本体の側では、そのプロセスをまとめて管理します。
  • パイプライン処理の部品のつなぎ方(グラフ)を表し、保存する前の検証と版の管理を行います。別プロセスの中で、デコード・板書の補正・合成・音声のミックス・エンコードを実際に動かす部分も含みます。
  • 合成と音声ミキサー複数の映像を 1 つの画面に重ね、複数の音声を 1 つにまとめます。
  • 板書の補正斜めから撮った板を正面から見た形に直し、照明のむらを補正して文字を強調します。書き変わったことも検出します。
  • 字幕音声をデコードせずに切り出して、音声認識・翻訳のサービスへ送ります。返ってきた結果をまとめ、WebVTT の字幕にします。
  • キャプチャV4L2・ALSA・DeckLink の機器と、テスト用に生成した映像を入力として扱います。取り込みは隔離した別プロセスで行います。
  • 画像の処理色の変換、拡大縮小、PNG・JPEG の読み書き、画質の指標の計算を行います。

ファイル形式と符号の解析

映像・音声のデータの形を読み書きします。ここでは変換はしません。

  • メディアの共通の扱いメディアのデータの表し方、ID、時刻の計算を、ほかの部品と共有します。
  • HLS・LL-HLSプレイリストを作り、映像を短いセグメントに分けます。
  • MPEG-2 TS映像・音声を 1 本にまとめる処理(多重化)と、その逆(分離)を行います。
  • MP4断片に分けた MP4(fragmented MP4)と通常の MP4 を書き出し、読み込みます。
  • FLV・AMF0RTMP で使うデータの形式です。FLV は従来の形式と Enhanced RTMP v2 に対応します。AMF0 は大きさの上限を厳しく決めて読み取ります。
  • H.264・H.265・AV1映像の符号の構造(NAL・SPS・PPS・OBU など)を読み取ります。
  • AAC・Opus音声の設定とパケットの構造を読み取ります(変換はしません)。

通信の方式(プロトコル)

すべて自前で実装しています。ネットワークや時計から切り離して書いているので、単体で試験できます。

  • RTMP接続の確立(ハンドシェイク)、データの分割(チャンク)、セッションの管理を行います。
  • SRTlive モードで、待ち受け(listener)と、こちらからの接続(caller)の両方に対応します。
  • RTSPRTSP 1.0 のクライアントとサーバーです。
  • RTP・RTCP・SDP映像・音声の運び方と、受信の揺れをならすバッファー、接続条件の交渉(offer/answer)を扱います。
  • WebRTCサーバー側の WebRTC と、ルームの SFU(受け取った映像を変換せずに各参加者へ転送する仕組み)の中心です。
  • ICE・STUN・TURN相手との通り道を見つけ、ファイアウォールを越えるための方式です。TURN はサーバーとクライアントの両方があります。
  • DTLS・SRTP・SCTPWebRTC の暗号化(DTLS 1.2・SRTP)と、データを送る DataChannel(SCTP)です。
  • TLS 1.3HTTPS・RTMPS などの暗号化です。QUIC で使う形も含みます。
  • QUIC・HTTP/3・WebTransportQUIC v1 と、その上の HTTP/3(ヘッダーの圧縮 QPACK を含む)と WebTransport です。
  • MoQMedia over QUIC(draft-22)のセッション、中継、映像・音声との対応付けを行います。
  • HTTP/1.1・WebSocket管理 API や HLS の配信に使う HTTP/1.1 を厳密に読み取り、組み立てます。WebSocket にも対応します。
次のページ セキュリティ