🌙

Google AntigravityでYouTubeっぽいライブ配信サービスを作ってみた

に公開

YouTube自作してみた🗼

YouTubeの生配信基盤に興味があったので、Google CloudのLive Stream APIを使ってチャット欄付きライブ配信アプリケーションを作成しました。開発は全てGoogle Antigravityで行いました。

ソースコードはGitHubリポジトリにて公開しています。

使用したツールやサービス🖲

ライブ配信基盤の技術選定📺

ライブ配信サービスを内製する場合、AWSの Amazon IVS / AWS Elemental MediaLive や Google Cloudの Live Stream API などの選択肢がありますが、今回はYouTubeに寄せるためGoogle製のLive Stream APIを使用しました。

全体構成🍕🎢

ライブ配信サービスを実装するには配信側視聴側で2つのインターフェースを作る必要があります。配信側はフルマネージドサービスのLive Stream APIで完結させ、視聴側は3つのコンテナで動かすことにしました。
大まかなディレクトリ構成は以下の通りです。

streaming-service/
├── .github/workflows         # CI/CD
├── frontend                  # 動画プレーヤー(視聴側)
├── chat-server               # チャットサーバー(視聴側)
├── nginx                     # リバースプロキシ(視聴側)
└── gcloud-script/livestream  # Live Stream API スクリプト(配信側)

実装の手順

配信側の実装🎬

ドキュメントの手順に沿って、REST APIを使ってインプットエンドポイントとチャンネルを作成します。
https://docs.cloud.google.com/livestream/docs/quickstarts/quickstart-hls?hl=ja

思わぬ費用が発生しないようにするため、配信を開始/停止する度にリソースの生成/削除を行えるようにスクリプトを組んでおきます。カスタマイズしない場合はこのスクリプトを実行するだけでOBSから配信することが可能になります。

https://github.com/R-ukyo/streaming-service/blob/main/gcloud-script/livestream/README.md

視聴側の実装1 動画プレーヤー▶️

動画を視聴する画面を実装します。これはブラウザで動作するWebアプリケーションです。使用する言語やフレームワークは様々な選択肢がありますが、今回は Next.js/TypeScript を採用しました。
個人的には、フロントエンドもバックエンドもJSで書けることやSDKが充実していることなどから、迷ったらJS(TS)のフレームワークを使うようにしています。

https://nextjs.org/

フロントエンドはReactで動画プレーヤーとチャット欄を作ります。
Antigravityに「黄色ベースでYouTubeみたいなUIにして」と雑に頼んだところ一発でそれっぽいUIを作ってきました。 AntigravityやGeminiがGoogle製だからなのか、LLMの性能が上がったからなのか、尋常じゃないクオリティのUIがパッと出てきてビビりました。


あまりにもYouTubeすぎるUI


コメントや関連動画なども作ってくれた

バックエンドAPIは生配信されている動画ファイルをCloud Storageから取ってきてブラウザに返す役割をします。HLS周りの詳しい実装は割愛しますが、Antigravityが良い感じに作ってくれました。

視聴側の実装2 チャットサーバー🗨️

チャットを管理するサーバーを実装します。Next.jsはWebSocketに対応していないので、別のNode.jsコンテナにSocket.IOでWebSocketサーバーを立てます。
今回は簡易実装としてチャット履歴の保存場所をファイルシステム(JSONファイルに保存)とし、アプリケーションの起動ごとにデータをクリアすることにしました。

視聴側の実装3 リバースプロキシ↗

フロントエンドからのリクエストを動画配信サーバー(Next.js)とチャットサーバー(Socket.IO)に振り分けるためのリバースプロキシをNginxで立てます。

https://github.com/R-ukyo/streaming-service/blob/main/nginx/default.conf

ローカル環境で動かす

視聴側1~3のコンテナを立ち上げるためにDockerfileとdocker-compose.ymlを定義します。docker compose upするとすべてのコンテナが立ち上がり、localhost:8080で配信画面を見ることができます。

https://github.com/R-ukyo/streaming-service/blob/main/.devcontainer/docker-compose.yml

Cloud Runにデプロイ

視聴側1~3のコンテナイメージをビルドし、Artifact Registryへのpushが行われるようにGitHub Actionsワークフローを定義します。mainブランチの対象ファイルを編集してgit pushするとワークフローが起動するように設定しておきます。

https://github.com/R-ukyo/streaming-service/actions

Cloud Runのデプロイは手動で行います。
Cloud Runはマルチコンテナに対応しているので、IngressコンテナをNginxとして、それに依存する形で他の2コンテナを設定します。コンテナイメージのURLはArtifact Registryにpushされたものを指定します。


選択を押すとArtifact Registryから選択できる


コンテナを3つ設定

適宜必要な環境変数を設定します。


環境変数設定の例

チャット履歴はインメモリボリュームに保存することにします。


サイズ大きすぎたかも

サービスのスケーリングは節約のため0~1にしておきます。ゼロスケールするため再アクセス時にインスタンス起動待ちが発生します。(リビジョンスケーリングでも可)


サービスのスケーリング

認証を「公開アクセスを許可する」、Ingressを「すべて」に設定すると、コンソール上のURLが有効化されてアクセスできるようになります。


認証


Ingress

OBSで配信してみる🎥

最初に作った配信開始スクリプトをローカルで実行すると、RTMPのURLとストリームキーが取得できます。それをOBSの配信設定に貼り付け、配信を開始すればOKです。

Cloud Runで公開したURLもしくはlocalhostを開くと、下記のようにOBSでの配信がリアルタイムで(YouTubeのように)見れるようになります。チャット欄も書き込めます。


リポジトリのREADMEには動画もあります

費用💵

かかった費用は大半がLive Stream APIの料金で、7.26時間利用して1,145円でした。Live Stream API以外はほぼ無料で利用できました。


SKU別利用料金

Live Stream APIはコーデックと解像度の設定によって料金が大きく変わります。今回はH.264/HDを使用したので、SDにすると半額くらいになりそうです。また、チャンネルがアクティブだと配信していなくても課金されるので、配信が終わったらチャンネルを停止するようにしましょう。

料金は、各チャンネルがアクティブだった時間(STOPPED または STOPPING 以外の StreamingState)に基づいて時間単位で課金され、入力と出力の解像度によって異なります。チャンネルは、入力ストリームがなくてもアクティブにできます。

詳しい料金体系はドキュメントを参照してください。
https://cloud.google.com/livestream/pricing?hl=ja#pricing_tables

Google Antigravityすごい🛸

ここまでの実装はほぼ全てGoogle Antigravityを使ったバイブコーディング一本で行いました。しかも無料枠のみで!数年前ではあり得ない速度とクオリティで開発ができてびっくりしました。

https://antigravity.google/

あとがき

Google CloudのLive Stream APIにはまだコンソール画面がなかったりネット上にも情報が少ないですが、YouTubeを支えるメディア配信基盤には関心が高いユーザーも多いと思われますので、これからのアップデートに大いに期待したいです。

参考資料

Live Stream APIについて

Google Cloudのカスタマーエンジニアの方が詳細に解説してくれています。
https://zenn.dev/google_cloud_jp/articles/4368b5e38e0dad

DeNAでの導入事例もあるようです。
https://cloud.google.com/blog/ja/topics/customers/dena-live-stream-api

Discussion