はじめに
このページの見出し
ソースから SENCA をビルドして 1 台のノードを起動し、OBS や FFmpeg から RTMP で送った映像を HLS で再生するまでを順にたどります。Docker で起動する方法は最後にあります。
先に知っておくとつまずかない点が 2 つあります。ストリームを作ったときに返る stream_key は 1 回しか表示されません。また、ライブの再生には有効期限のある署名付き URL が必要です。
コマンドは Linux x86_64(Ubuntu 26.04)で動作を確かめています。
必要なもの
- Linux(コーデックを動かす別プロセスの権限を絞るために、Linux の seccomp と Landlock を使います)
- Rust 1.90 以上(
Cargo.tomlのrust-versionで指定しています)と、C のリンカー - 試しに配信・再生するための FFmpeg(任意です。OBS やほかのプレイヤーでもかまいません)
- ロイヤリティフリーのコーデックのライブラリ(任意です。下の「コーデックのライブラリ」を参照してください)
ビルドする
本体とコーデック用のプログラムをビルドします。
cargo build --release -p senca-node -p senca-codec-worker
target/release/ に senca-node と senca-codec-worker ができます。senca-node は自分と同じディレクトリにある senca-codec-worker を起動するので、2 つは同じ場所に置いておきます。どうしても別の場所に置くなら、--codec-worker-bin でその場所を指定してください。
キャプチャデバイスを使うときは、コマンドに -p senca-capture も加えます。これで senca-capture-worker もできます。
コーデックのライブラリ
AV1・VP8/VP9・Opus のエンコードとデコードには、次の共有ライブラリを使います。senca-codec-worker が実行時に dlopen で読み込みます。
なくてもノードは動き、受け取った映像・音声をそのまま配信・録画するところまではできます。変換・静止画・サムネイルだけが使えず、503 になります。
| ライブラリ(soname) | 用途 | Ubuntu 26.04 のパッケージ |
|---|---|---|
libdav1d.so.7 | AV1 のデコード | libdav1d7 |
libSvtAv1Enc.so.2 | AV1 のエンコード | libsvtav1enc2 |
libvpx.so.12 | VP8・VP9 のエンコードとデコード(libvpx 1.16 の ABI だけに対応) | libvpx12 |
libopus.so.0 | Opus のエンコードとデコード | libopus0 |
ライブラリは次の順に探します。
--codec-lib-dir DIRで指定したディレクトリに、その名前のファイルがあれば読み込みます。--codec-lib-dirを指定しない場合は、環境変数SENCA_CODEC_LIB_DIRの値を使います。--codec-lib-dirを指定すると、その値でSENCA_CODEC_LIB_DIRを置き換えてsenca-codec-workerに渡します。値は:で区切って複数指定できます。- 見つからなければ、ファイル名だけを指定して
dlopenします。この場合は OS の標準の探し方(ld.so.cacheやLD_LIBRARY_PATH)に従います。
ディストリビューションのパッケージで入れたなら、--codec-lib-dir は要りません。別の場所に置いたライブラリを使うときだけ指定します。どのコーデックを読み込めたかは、GET /api/v1/capabilities の応答の codecs.transcode でわかります。
H.264/H.265 のソフトウェアコーデックは同梱しておらず、外から読み込むこともしません。H.264/H.265 を変換したい場合は、GPU とメーカーのドライバーを用意してください(コーデックと特許 を参照)。
ノードを起動する
./target/release/senca-node --data-dir ./data \
--http 127.0.0.1:8080 --rtmp 127.0.0.1:1935 \
--console-dir ./apps/console
--data-dir は必ず指定してください。省くとカレントディレクトリの out にデータを置きます。
待ち受けるアドレスの既定は HTTP が 0.0.0.0:8080、RTMP が 0.0.0.0:1935 です。この例では 127.0.0.1 を指定して、同じマシンからの接続だけを受け付けています。
API の応答や再生 URL には、外から見たときの URL(公開 URL)が入ります。既定は http://127.0.0.1:8080 と rtmp://127.0.0.1:1935 です。ポート番号や外から見たホスト名がこれと違うなら、--public-http-url と --public-rtmp-url で合わせます(設定 を参照)。
起動すると、標準エラー出力に次のようなログが出ます(サンドボックスに関する行は省いています)。
created the first admin token in ./data/control/bootstrap-admin-token (mode 0600)
2026-11-03T01:10:04.936Z senca-node 0.0.0 started (node f1be5f27675d35f8dd72b88676be8754)
2026-11-03T01:10:04.936Z http listening on 127.0.0.1:8080
2026-11-03T01:10:04.936Z rtmp listening on 127.0.0.1:1935
2026-11-03T01:10:04.942Z grid: registered (cpu 7200 m, mem 20422 MB, gpus 0, capture 0)
2026-11-03T01:10:04.942Z grid: became the scheduler (leader)
次の 2 つが ok と ready を返せば、ノードは動いています。
curl -s http://127.0.0.1:8080/healthz # ok
curl -s http://127.0.0.1:8080/readyz # ready
管理者トークンを取り出す
API を呼ぶにはトークンが要ります。既定のパスワードというものはなく、初回の起動時に作られる管理者トークンを使います。トークンは data_dir/control/bootstrap-admin-token(パーミッション 0600)に書き込まれ、権限は tenant:admin と node:admin、テナントは default、有効期限はありません。
これをシェルの変数に読み込んでおきます。
TOKEN=$(cat ./data/control/bootstrap-admin-token)
何でもできるトークンなので、試し終えたら用途ごとに権限を絞ったトークンを作り、このファイルは安全な場所へ移すか削除してください(セキュリティ を参照)。
ストリームを作成する
ストリームは配信 1 本の単位です。配信を受け付ける前に、まずこれを作ります。
curl -s -X POST http://127.0.0.1:8080/api/v1/streams \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"name":"demo"}'
応答(201、一部を抜粋):
{
"id": "60dd5cca4fa2785a5d8eefc3b1f5d1bc",
"name": "demo",
"generation": 1,
"desired_state": "running",
"observed_state": "waiting_input",
"hls": {"container": "ts", "segment_ms": 2000, "window": 6},
"ingest": {
"rtmp_url": "rtmp://127.0.0.1:1935/live",
"stream_key": "sk_zgo54TfcU8PEPmrJDH34OHnjYR5Ot6nv__hlyLSf4pk",
"whip_url": "http://127.0.0.1:8080/whip/60dd5cca4fa2785a5d8eefc3b1f5d1bc"
}
}
stream_keyが返されるのは、この応答と、キーを再発行したとき(POST /api/v1/streams/{id}/keys)だけです。 サーバーにはハッシュ値しか残らないので、ここで控えてください。
ID とキーはこのあと何度も使うので、変数に入れておきます。
SID=60dd5cca4fa2785a5d8eefc3b1f5d1bc
KEY=sk_zgo54TfcU8PEPmrJDH34OHnjYR5Ot6nv__hlyLSf4pk
RTMP で配信する
FFmpeg で試験用の映像と音声を送る
ffmpeg -re -f lavfi -i testsrc2=size=1280x720:rate=30 \
-f lavfi -i sine=frequency=440:sample_rate=48000 \
-c:v libx264 -preset veryfast -tune zerolatency -g 60 -pix_fmt yuv420p \
-c:a aac -b:a 128k \
-f flv "rtmp://127.0.0.1:1935/live/$KEY"
配信先の URL は、rtmp_url の後ろに stream_key をつなげたものです。RTMP の app 名は live で、live で始まる名前でもかまいません。
キーフレームの間隔は、HLS のセグメントの長さ(既定 2 秒)以下にします。上の例は 30 fps で -g 60 なので、ちょうど 2 秒ごとです。
OBS から配信する
[設定]→[配信]を次のようにします。
- サービス: カスタム
- サーバー:
rtmp://127.0.0.1:1935/live - ストリームキー:
sk_...(作成時に返されたstream_key)
あわせて[出力]で、キーフレームの間隔を 2 秒以下にしておきます。
配信が届いたことを確かめる
配信が届くと、GET /api/v1/streams/{id} の応答の observed_state が live に変わり、live の項目に受け取ったトラックの情報が入ります。
curl -s -H "Authorization: Bearer $TOKEN" http://127.0.0.1:8080/api/v1/streams/$SID
再生 URL を取得して再生する
ライブの再生には署名付きの URL を使います。発行するトークンには subscribe の権限が必要です。
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
http://127.0.0.1:8080/api/v1/streams/$SID/playback-url
{
"expires_at": "2026-11-03T01:16:01Z",
"playback": {
"hls": "http://127.0.0.1:8080/s/1793668561/nWqDQOWkMTMY3Z2GoC94Rw/live/60dd5cca4fa2785a5d8eefc3b1f5d1bc/index.m3u8",
"rtmp": "rtmp://127.0.0.1:1935/play/60dd5cca4fa2785a5d8eefc3b1f5d1bc?exp=1793668561&sig=nWqDQOWkMTMY3Z2GoC94Rw",
"whep": "http://127.0.0.1:8080/whep/60dd5cca4fa2785a5d8eefc3b1f5d1bc?exp=1793668561&sig=nWqDQOWkMTMY3Z2GoC94Rw"
}
}
本文を省くと、URL の有効期間は 300 秒です。1 時間使いたければ {"ttl_secs": 3600} のように送ります。指定できるのは 1 秒から --max-playback-ttl(既定 86400 秒)までです。期限切れの URL や署名が合わない URL には 403 が返ります。なお whep の URL は、--webrtc-udp を指定したノードでしか使えません(取り込みと再生 を参照)。
受け取った hls の URL で再生してみます。
ffplay "http://127.0.0.1:8080/s/.../index.m3u8"
# または
ffprobe -v error -show_entries stream=codec_name,width,height -of compact "http://127.0.0.1:8080/s/.../index.m3u8"
ブラウザーなら hls.js などの HLS プレイヤーで再生できます。署名付き URL の応答には Access-Control-Allow-Origin: * が付くので、別のオリジンのページからでも読めます。
管理画面は http://127.0.0.1:8080/console/ で開き、API トークンでログインします。ただし管理画面のプレイヤーは fMP4 の HLS か WHEP しか再生できず、既定の TS 形式のストリームは映りません。形式は hls.container で切り替えられます(取り込みと再生 を参照)。
録画する(任意)
録画を始めて、一覧に出てくることを確かめます。
curl -s -X POST -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' -d '{}' \
http://127.0.0.1:8080/api/v1/streams/$SID/recordings # 202 が返り、state は recording
curl -s -H "Authorization: Bearer $TOKEN" http://127.0.0.1:8080/api/v1/recordings
録画の停止、VOD での再生、MP4 へのエクスポートについては、録画 を参照してください。
停止する
Ctrl-C(SIGINT)か SIGTERM で止まります。録画中のものがあれば finalized として閉じてから終了します。SIGKILL や停電で強制的に止まったときは、書き込み途中だった録画を次の起動時に interrupted として閉じます(運用 を参照)。
Docker で動かす
リポジトリの Dockerfile と compose.yaml で、1 台のノードを立ち上げられます。
docker compose up -d --build
docker compose exec senca cat /var/lib/senca/control/bootstrap-admin-token
1 行目でイメージをビルドして起動し、2 行目で管理者トークンを表示します。接続先は次のとおりです。
- 管理 API・HLS・管理画面:
http://localhost:8080(管理画面は/console/) - RTMP:
rtmp://localhost:1935/live、SRT:localhost:9000/udp - 公開 URL は、compose の変数
SENCA_PUBLIC_HTTP(既定はhttp://localhost:8080)とSENCA_PUBLIC_RTMP(既定はrtmp://localhost:1935)で変えられます。 例:SENCA_PUBLIC_HTTP=https://media.example.com docker compose up -d
イメージの中身:
| 項目 | 内容 |
|---|---|
| ベースイメージ | Ubuntu 26.04(libvpx 1.16、つまり libvpx.so.12 が入っているため) |
| 実行ファイル | /opt/senca/bin/senca-node・senca-codec-worker・senca-capture-worker |
| コーデックのライブラリ | libdav1d7・libvpx12・libopus0・libsvtav1enc2。GPU 用に libva2・libva-drm2・libvpl2 も入っています。--codec-lib-dir /usr/lib/x86_64-linux-gnu を指定しています |
| 実行ユーザー | senca(uid 10001)。compose では、ルートファイルシステムを読み取り専用にし、/tmp を tmpfs にし、no-new-privileges を指定しています |
| データ | ボリューム /var/lib/senca(--data-dir) |
| 管理画面・配信ページ | /opt/senca/console(/console/ で開く)・/opt/senca/sender(/sender/ で開く) |
| ヘルスチェック | senca-node --healthcheck http://127.0.0.1:8080/readyz(10 秒ごと) |
| 公開するポート | 8080/tcp・1935/tcp・9000/udp・8443/udp |
--data-dir・--console-dir・--sender-dir・--codec-lib-dir はイメージの ENTRYPOINT で固定してあり、待ち受けるアドレスは CMD(compose では command)で渡します。command を書き換えるときは、--http なども含めて全部書き直してください。
WebRTC(WHIP・WHEP・ルーム)は、既定で UDP の 8443 番(--webrtc-udp 0.0.0.0:8443)を使います。ブラウザーなどの相手に知らせる IP アドレス(ICE の候補)は compose の変数 SENCA_PUBLIC_IP で指定します。既定の 127.0.0.1 のままだと、同じマシンのブラウザーからしかつながりません。たとえば SENCA_PUBLIC_IP=203.0.113.10 docker compose up -d のように起動します。docker run で起動する場合は、引数に --webrtc-public-ip <ホストの IP> を加えてください。これがないとコンテナーの中のアドレスを相手に伝えてしまい、ホストの外からはつながりません。
compose.yaml は、手元の作業中のファイルからイメージをビルドします。配布するイメージは、git archive HEAD | docker build -t senca/node:local - のようにコミット済みのソースから作ってください。
GPU をコンテナーに渡す例は compose.yaml のコメントにあります。NVIDIA の GPU なら NVIDIA Container Toolkit を、Intel・AMD の GPU なら /dev/dri を使います。イメージの中のライブラリの置き場所は x86_64 のパス(/usr/lib/x86_64-linux-gnu)で固定です。
次に読むページ
関連するページ
この文書の原文は、リポジトリの docs/guide/ja/02-quickstart.md にあります。内容は現在の版(v0.0.1)に合わせています。