ImageFluxで音声SNS風サービスを作ってみた! 低コスト大規模配信システムの作り方(後編)
本記事は2021年5月公開の記事をリライトしております。
こんにちは、テリーです。Clubhouseなどの音声SNSを使っていますか? 先日うちの娘がなんと「Clubhouseを使いたいからMacBook Airを買って!」といってきました。そこはiPod touchにたどり着いてほしかったけれど、MacBook Air M1でリアルiPhoneアプリを動かす調査するという名目ができたので買ってみました。
Clubhouseは2021年2月のブームが落ち着き、オワコンになったという説もあります。しかし一方で、Android版が2021年5月中にリリースされるという話や、大手SNSのFacebook、Twitter、Spotify、LinkedInなどが同様のサービスを始めるというウワサも出ています。2021年は第2次ラジオサービス元年と位置づけられるのか、これからの展開が楽しみになってきました。
今回は、話題沸騰中の音声SNS、Clubhouse(クラブハウス)と同等のWebサイトを、FirebaseとImageFlux Live Streamingを使って短いコードで実現する方法を2部構成で紹介します。前編では、Firebaseを使ったWebサイトの開発手順を説明しました。本記事は後編で、ImageFlux Live Streamingに接続し、WebRTCを用いた双方向音声通話と、多数のリスナーに向けたHLS視聴コードの書き方を紹介します。
3つのユーザー種別
Clubhouseは一度に1つの部屋にしか入れません。部屋に入っているユーザーを大きく分類すると、3つの種別にわけられます。
種別 | できること |
---|---|
モデレーター | 部屋を管理、話す、聞く、ミュート、昇格、降格、強制退室 |
スピーカー | 話す、聞く、ミュート |
リスナー | 聞く、挙手 |
部屋を開設した人がモデレーターです。その後に入室した人はリスナーとして参加し、モデレーターがリスナーに対して昇格操作をするとスピーカーになります。
音声データの流れの観点で見ると、モデレーターとスピーカーは、自分の声が相手に届き、自分以外の全員の声が自分に届きます。この状態を「双方向」といいます。リスナーは、自分の声は誰にも届きませんが、モデレーターとスピーカー全員の声が自分に届き、聞くことができます。この状態を「片方向」といいます。
各種別の画面。モデレーターとスピーカーは右下にマイクのアイコンがあるがリスナーにはない。モデレーター画面にはリスナーからスピーカーに昇格/降格させるボタン(「↑」「↓」)がある。
双方向=WebRTC、片方向=HLS
双方向か片方向かというのは大規模配信システムを構築するうえでとても重要です。なぜなら双方向の場合は遅延が許されないからです。声が10秒後に相手に届く状態ではトランシーバーで話しているような感覚になり、相手が話し終わるまで待たなければならず、活発な会話ができません。遅延が0.2〜0.5秒程度だと違和感なく会話をすることができます。
では片方向の場合も双方向と同じようにデータを送ればよいのではないか、と考えますが、片方向の場合は多少の遅延があっても視聴者には違和感がないため、コストの低い配信方式が選ばれます。YouTube Live、Abema、ニコニコ動画で採用されているHLSという方式です。遅延は10〜30秒程度です。リスナーが文字でコメントを打ち、配信者が声で返事を返すようなサービスではそれでもコミュニケーションが可能です。HLS方式では、配信サーバは動画・音声データをキャッシュサーバにキャッシュさせ、リスナーは連番のファイルをキャッシュサーバからダウンロードし順次再生します。リスナーの通信状況、通信速度、遅延状況を配信サーバが個別対応する必要がないため、サーバの負荷を分散できることが最大のメリットです。
双方向の場合は、すべての主要WebブラウザがWebRTCという仕組みを持っています。片方向の場合によく使われるHLS方式は、Safariブラウザだけが標準対応しています。それ以外のChrome、FirefoxはHLSデータをメディアとして認識しませんが、専用のJavaScriptのライブラリを読み込んで再生することができます。HLS方式のデータを再生させるためのライブラリで最も有名なものがhls.jsです。
ImageFlux Live Streamingでは、双方向の通信をするためのWebRTC方式のデータを、HLS方式のデータに変換し、配信することができます。そのため、Clubhouseのような双方向・片方向併用の配信サービスを低コストで実現することができます。
サンプルコード
これから本サービスの各種機能の実装を紹介しますが、それに先立ち、サンプルコードを提供します。コードを見ながら読み進めてください。
部屋一覧画面
部屋一覧画面(下図)は、本連載の前編で作成しました。作成方法は前編の記事をご覧ください。
部屋を開設 = チャンネル作成とWebRTC接続
まず双方向通話の始め方を説明します。
部屋一覧画面にある「Start A Room」という緑のボタンを押すと、CreateRoomというAPIを呼び出します。Cloud FunctionsのcreateRoom関数(functions/index.js 273行目付近)を参照してください。Cloud Functionsの関数のなかで、ImageFlux Live Streamingのエンドポイントに向けて、CreateMultistreamChannelWithHLSというAPIを呼びます。APIを呼ぶためのAPIを作成した形になるのは、ImageFlux Live StreamingのAPIを呼ぶためのACCESS_TOKENを、ユーザーに漏洩させないためです。ACCESS_TOKENが漏洩すると、配信中の部屋を閉じたり、割り込んだりなどの悪意のあるイタズラをされる可能性があります。
CreateMultistreamChannelWithHLS APIのオプションとして、event_webhook_urlを定義します。これはスピーカーの配信が開始・停止した場合に通知されるwebhookです。host.docker.internal:2002というホスト名とポート番号を使っていますが、ImageFlux Live Streamingのサーバ群からインターネット越しで、アクセス可能なホスト名に置き換えてください。
同様に、auth_webhook_urlというオプションも定義しています。これは配信開始直前にユーザー情報を識別し、不正アクセスでないか、権限のあるユーザーかなどをチェックし、場合によっては配信をお断りすることもできるwebhookです。こちらもImageFlux Live Streamingのサーバ群からインターネット越しで、アクセス可能なホスト名に置き換えてください。
functions/index.js279行目付近に当該のコードが出てきます。以下に示します。
const options = { hls: [{ durationSeconds: 2, startTimeOffset: -2, audio: { bps: 32000 } }], auth_webhook_url: "http://host.docker.internal:2002/imagefluxhouse/us-central1/AuthWebhook", event_webhook_url: "http://host.docker.internal:2002/imagefluxhouse/us-central1/EventWebhook", }; const channelInfo = await ImageFluxAPIInternal( "ImageFlux_20200316.CreateMultistreamChannelWithHLS", options );
CreateMultistreamChannelWithHLS APIのレスポンスJSONを、スピーカーのデータベースに関連付けて保存し、クライアントはその値を使用してWebRTC接続をします。src/components/AppSora.vueのコードが、WebRTC関連の処理を担当しています。
部屋にリスナーとして入室 = HLS再生
部屋一覧画面で、特定の部屋をクリックすると入室します。入室した直後はリスナーとなり、モデレーターとスピーカーに関連付けられたHLSのURLをhls.jsで再生します。src/components/AppHLS.vueとsrc/components/HLS.vueのコードが、HLS再生関連の処理を担当しています。
入室後の画面とボタン
入室後の画面はsrc/views/Room.vueのコードが担当しています。
画面に配置されている各種ボタン(上図参照)のうち、リスナーからスピーカーへの昇格ボタンおよび降格ボタンの動作は、Room.vueの後半(116-129行目)で記述しています。挙手・マイクミュート・退室ボタンのイベント処理は、src/components/AppFooter.vueで実装しています。
各ボタンが押されたときの処理のポイントを解説します。
リスナーからスピーカーへの昇格
モデレーターはリスナーをスピーカーに昇格させることができます。音声の再生方法が片方向から双方向に変わるため、HLS再生を停止し、WebRTCで接続します。Clubhouseアプリでは別画面でこの操作をおこなっていますが、本サンプルではページ数節約のため、同画面内の矢印アイコンのクリックで昇格操作をしています。Cloud FunctionsのUpgradeUser関数を呼んでいます。
スピーカーからリスナーへの降格
スピーカーは自分の意思でリスナーに降格できます。また、モデレーターはスピーカーをリスナーへ降格することが可能です。Clubhouseアプリでは別画面でこの操作をおこなっていますが、本サンプルではページ数節約のため、同画面内の矢印アイコンのクリックで降格操作をしています。Cloud FunctionsのUpgradeUser関数を呼んでいます。
挙手
リスナーが挙手ボタンを押すと、モデレーターに挙手アイコンでアピールできるようにします。この操作は音声再生と関係ないため、部屋にいる全員への表示のみです。Cloud FunctionsのSetHand関数を呼んでいます。
マイクミュート
モデレーターとスピーカーはマイクボタンを押すことで録音停止・再開を自分の意思でできるようにします。ミュートのオンオフ状態を部屋にいる全員に通知します。マイクをミュートにしたあと、Cloud FunctionsのSetMute関数を呼び出します。
おわりに
ImageFlux Live Streamingを使って、Clubhouse風の音声SNSサービスをつくってみました。ImageFlux Live Streamingを使ったサービスの提供を検討する場合の、参考にしてください。
ImageFlux Live Streamingのご紹介
ImageFlux Live Streamingとは、お客さま独自のライブ配信システムを、API/SDKを利用して素早く手軽に構築できるマネージドサービスです。配信基盤としてWebRTC SFU Soraを採用しており、WebRTCからHLSまで幅広い配信方式に対応しております。つくりたい配信サービスに適したAPIを使って、高速に開発を進めることができます。
ImageFluxはライブ配信のためのインフラとAPIを提供しております。ユーザーインターフェースや、ログイン認証、チャット、会員管理、投げ銭などの機能は、お客さま側で開発が必要です。
「システム開発の経験やリソースがなく、開発からおまかせしたい」といった方は、開発相談も承っておりますのでお気軽にご相談ください。
テリー (秋月 徹)
2002年よりケータイ向けライブ配信システムの開発・運用・販売を行い、プロ野球中継、音楽ライブコンサート、公営ギャンブル等の大規模ライブ配信システムの構築を担当。趣味のハッカソンでは得意の動画処理、映像処理を使ったサービスを短時間で考案・開発し、多数の優勝経験を持つ。