OBS Studioを操作するプログラムを書いてPHPerKaigi 2022のトーク動画をスケジュール配信した

4/9(土)〜4/11(月)にPHPをコアのテーマとした技術カンファレンス、PHPerKaigi 2022を主催しました。

今回は過去開催を通してスポンサー数、参加者数ともに最大になり、また久しぶりのオフライン会場でみなさんが楽しそうにしている様子を見られて主宰としてもとても嬉しい開催でした。

スポンサー、スピーカー、参加者、そしてスタッフのみなさま、ありがとうございました。

この記事では、今回初の試みとしてトーク配信の自動化に挑戦しましたので、その設計や実装についてご紹介します。

ネットワークの弱い環境でのオンラインイベント

PHPerKaigi 2022のメインコンテンツはPHPerたちによる技術トークです。今回の開催はオフライン会場(練馬区ココネリホール)とオンライン(ニコニコ生放送)のハイブリッド開催でしたが、企画段階では新型コロナウイルス感染症の感染拡大状況が読めず、場合によってはフルオンライン化の可能性もありました。

そのため、PHPerKaigi 2022はすべてのレギュラートーク(20分/40分)は事前収録して、オフライン会場では収録された動画を見る「パブリックビューイング」として開催しました。

iOSDC Japan 2020, 2021, PHPerKaigi 2021の3回、この形式でフルオンラインのカンファレンスを経験したので、事前収録と、事前収録した動画の配信には不安はありませんでした。

一方、オフライン+オンラインのハイブリッド形式は今回が初でした。さらに今回使用した会場には安定したネットワークが無く、フレッツ光などの固定回線を引き込むこともできないということで、動画の配信についてはリスクを下げる施策が必要でした。

今回はそのための施策としてAWSに立てたサーバから動画を配信するという方法を採用しました。

OBS Studioの使用

私の主催するカンファレンスでは2019年からOBS Studioを使っています。

OBS Studio (macOS版)

2019年〜2020年のオフライン開催では会場でOBS Studioを使ってスライドのHDMI画像とビデオカメラで撮影しているスピーカーの顔を合成して1つの動画にして、会場のスクリーンに投影したりYouTubeでのアーカイブ用に録画したりしていました。

また、2020年からのオンライン開催でもOBS Studioを使って事前収録された動画をニコニコ生放送に配信していました。(この録画・配信システムについては過去記事で紹介していますので興味ある方はご覧ください。)

そのため、OBS Studioの扱いには一定の経験値が蓄積されており、今回もコアはOBS Studioとしました。

どこでOBS Studioを動かすか

OBS Studioでは動画のリアルタイムレンダリングをするので基本的にはGPUが必要です1

私たちの録画・配信システムはOBS StudioをWindowsで使用していたので当初はどこかにWindowsインスタンスを立てて、と考えていたのですがGPU付きでWindowsを気軽に使えるサービスが見つけられず、またOBS StudioはWindows版, macOS版に加えてLinux版もあるということで、最終的にはAWSのEC2にLinuxのGPUインスタンス(g4dn.2xlarge)を立てて配信しました。

AWSのGPUインスタンスはNVIDIA T4 GPUを搭載したG4dnインスタンスとAMD Radeon Pro V520 GPUを搭載したG4adインスタンスがあります。今回はG4dnの中から、vCPUが8つ & メモリ32GBの g4dn.2xlarge というインスタンスを使用しました。

g4dn.2xlargeは東京リージョンでは$1.015/hourで使えます。開催1週間ほど前からリハーサルのために起動し、最終的には$350ほどの費用でした。

g4dn.2xlarge

PHPerKaigi 2022の動画は1,920×1,080 30fpsを基本にしていますがg4dn.2xlargeインスタンスでドロップすることなく安定して配信できていました。

ただ、あまりインスタンス比較を真面目にやっておらず、同一vCPU数 & メモリ数では半額になる G4ad インスタンスや、同じ G4dn インスタンスでも1つサイズの小さい g4dn.xlarge でも配信できた可能性はあります。次回以降はチューニングを試してみようと思います。

OBS Studioをどの様にコントロールするか

OBS Studioにはobs-websocketというプラグインがあり、これを使うとOBS StudioをWebSocketでコントロールできます。

PHPerKaigi 2022のタイムテーブル(= トークの放映タイミング)は私が開発・運営しているforteeが持っているのでforteeからトークの放映タイミングを取得してそれに従ってWebSocketでOBS Studioをコントロールして決まった時間に決まった動画を再生できれば良いことになります。

これを実現するために「スケジュールを受け取るためのHTTP REST API」と「OBS StudioをコントロールするためのWebSocket」を話すプログラムをGoで書きました。

https://github.com/hasegawa-tomoki/obs-controller

obs-controller

今回EC2に作ったサーバではApache + Let’s Encryptでobs-controllerのlistenするhttpをリバースプロキシしてforteeとの通信はhttpsにし、obs-controlelrはsystemdで起動しています。

Goを初めて使ったのでプロセス間通信はじめ相応の苦労があり自分で見ても美しくないプログラムなのですが、イベント開催日という締切がある中でなんとか書き切れて安心しました2

Goの達人のみなさま「ここはこうするんだぜ!」というのがあればPRお待ちしています。

fortee側実装

OBS Studioを使った過去の開催の経験から、カンファレンス当日には以下の操作が必要なことがわかっていました。

  1. トーク開始前にトーク用シーンの動画ソースを次のトークのものに差し替える
  2. 指定時刻になったらシーンをトーク用のものに切り替える
  3. トークが終わったらシーンを幕間(トークとトークの間)用のものに切り替える
  4. 幕間は複数のシーンを順番にループして切り替える

今回は、forteeにトーク時刻とトーク動画を指定して放映スケジュールを作る機能と、シーンの遷移(シーンシーケンス)を定義する機能を作りました。

スケジュール機能
シーンシーケンス機能

この例だと以下の様な動作になります。

  • 11:35になる少し前3にトーク用シーンの動画ソースを「PHPでEventLoopを書いて〜」のものに差し替える
  • 11:35になったらシーンをトーク用のものに切り替える
  • 11:35から23分44秒後にシーンを「[幕間] 30sec Track-me」に切り替える
  • 30秒後にシーンを「[幕間] 15sec Track-another」に切り替える
  • シーンを順番に切り替え「[幕間] 10min41sec Information」が終わったら次は一番上に戻る
  • 12:10になる少し前にトーク用シーンの動画ソースを「大規模サービス〜」のものに切り替える
  • (以下同じ)

つまり基本は「特定時刻に特定シーンに切り替える」「シーン切替後、一定の時間が経ったら次のシーンに切り替える」と、「シーン切替前に準備をする」だけです4

テスト

このシステムは今回初稼動で設定時に現場で苦労しそうだな、ということでforteeの各所にテスト機能を付けていました。

例えば、スケジュール機能の個別のトークとか、各シーンシーケンスにテストボタンを付けていて、押すとOBS Studioが個別トークの再生を開始したり、シーンシーケンスが動きだしたりする様になっています。

また、作成したスケジュール全体のテスト(リハーサル)のために「いま設定されているスケジュールから〇〇分引き算して実行」みたいなことができる様にして、プログラム完成から当日までの間に2〜3周リハーサルを回しました。

スケジュールテスト

このリハーサルの間にWebSocketのメッセージを取りこぼすバグが見つかったり、トーク名にダブルクオートが入っていると再生できない(恥ずかしい)バグが見つかったりしたので「やってよかった」という工程でした。

使ってみてどうだったか

ということでギリギリに完成し最低限のリハーサルで本番投入されたシステムでしたが、蓋を開けてみれば大安定で、何の問題もなく2.5日の開催を走り切れました。

Goのプログラムはひたすらイベントループを回ってる様な感じなので、よくもまあこんな長時間動き続けるものだと感心しました5

今回の開催ではまだ手動でタイムテーブルに従って設定変更していく様な箇所が残っていたのですがその箇所も自動化することはできるはずなので「事前収録したトークをタイムテーブルに従って放映する」「トークとトークの間は一定のパターンで動画を流す」という運営であれば全自動で実施できる様になるはずです。

「事前収録のオンラインカンファレンス」という形態がいつまで続くかはわかりませんが、ここ数年進めている「コードを書くことでカンファレンス運営にかかる工数を削減する」という試みは今年も成功できたな、と思っています。

と言う訳で…

ネットワークの弱い会場を使ってオフライン・オンラインのハイブリッド開催をしたよ、というレポートでした。

ややヒヤヒヤしたけどGoを初めて書いて動くモノが作れたし、作ったものが有効に動いてカンファレンス運営がとてもラクに安定したのでだいぶ満足度の高い開発でした。

obs-controllerのソースコードは公開していますが「誰でも簡単に使える機能」という感じではないのでfortee側では今回のOBS配信機能は(Zoomを使った事前収録システム同様に)特別に設定したカンファレンスでのみ使える様にしています。私がサポートスタッフとして入れば使うことも可能と思いますので興味がある方はTwitterででもお声がけください。

  1. CPUで殴り倒す、という方法もあるとは思いますが試していません
  2. プログラムがひととおり完成したのは開催の4〜5日前でした
  3. 今回の実装では10秒前
  4. 幕間のシーンではforteeのWeb画面を使っているところがあり、そういうところではWebブラウザのリロードが必要なのでこの準備の中でリロードしたりもしています
  5. 当たり前と言えば当たり前だけど、何かメモリリークとかで落ちそうじゃないですか