独自のOBS-webをセットアップする

私たちは皆、Flashが過去のものとなり、Chromeのようなメインストリームのブラウザがバージョン88のアップデートでそれに別れを告げたことを知っています。では、現在のウェブ上でのライブストリーミングのための最適なソリューションは何でしょうか？それがWebRTCです。

WebRTCは、ビデオとオーディオストリームをシームレスに送信する能力を持つ、手間のかからないライブストリーミングのためのチケットです。これは、オンラインでライブコンテンツを共有する方法を簡素化し、複雑なものを簡単に見せる技術です。WebRTCを通じて、ウェブサイトは仲介者の助けなしにブラウザとブラウザ/ブラウザとサーバー間のポイントツーポイント接続を確立し、ビデオストリーム、オーディオストリーム、または他の任意のデータの送信を実現できます。

簡単に言えば、これはユーザーがもはやOBS（Open Broadcaster Software）のようなストリーミングソフトウェアを使用する必要がなく、ウェブページを開くだけでライブを開始できることを意味します。

# **WebRTCでのストリーミングとは？**

WebRTCの基礎的な実装は間違いなく複雑ですが、ウェブ上での使用は驚くほど簡単です。わずか数行のコードで、ピアツーピア接続を確立し、データ送信を容易にすることができます。ブラウザは複雑なWebRTC機能を3つの主要なAPIに抽象化しています：

1. **MediaStream:** このAPIを使用すると、オーディオとビデオストリームを取得できます。
2. **RTCPeerConnection:** これはピアツーピア接続の確立とオーディオおよびビデオデータの送信を担当します。
3. **RTCDataChannel:** このAPIは任意のアプリケーションデータの送信に使用されます。

ライブストリーミングを開始するには、最初の2つのWebRTC APIだけが必要です。まず、オーディオとビデオフィードを表すMediaStreamオブジェクトを取得します。その後、RTCPeerConnectionを使用してピアツーピア接続を確立し、この接続を通じてMediaStreamをライブサーバーにアップロードします。この単純な相互作用がウェブ上のリアルタイム放送を可能にします。

![WebRTC Streaming](https://trtc.io/media/4404f960-5516-4c17-a702-68c1418352d7.png)

# **ライブストリームの収集**

ライブストリーミングコンテンツの収集は、MediaStreamオブジェクトの取得方法に依存します。WebRTCはこの目的のための特定のインターフェースを提供しています。

最も一般的に使用されるインターフェースは`navigator.mediaDevices.getUserMedia`で、これはマイクとカメラを開いてオーディオとビデオストリームをキャプチャします。もう一つのオプションは`navigator.mediaDevices.getDisplayMedia`で、これは共有画面ウィンドウ（デスクトップ、アプリケーション、またはブラウザタブなど）からオーディオとビデオをキャプチャします。

これらのインターフェースにはいくつかの制限があります：

1. HTTPSまたはローカル開発のためのlocalhostなどの安全なコンテキストでのみ使用できます。
2. iOS 14.3以上のバージョンでのみWKWebViewで`getUserMedia`の使用をサポートし、`getDisplayMedia`インターフェースはモバイルデバイスではサポートされていません。

幸いなことに、WebRTCは`captureStream`インターフェースを提供し、MediaStreamsの定義を大幅に拡張しています。この多様性により、単一の固定ソースから離れて、多様でダイナミックなストリーミングコンテンツが可能になります。

`HTMLMediaElement`と`HTMLCanvasElement`で`captureStream`メソッドを呼び出すことで、現在の要素のアクティブにレンダリングされているコンテンツをキャプチャし、リアルタイムのMediaStreamオブジェクトを作成できます。簡単に言えば、VideoやCanvasを通じて表示されているものは、ビデオ、オーディオ、画像、またはカスタム描画であっても、放送用のライブストリームに変換できます。

しかし、異なるブラウザで`video.captureStream`を実装する際にいくつかの問題が発生しました：

1. **Chromeブラウザ**: バージョン88以降、`video.captureStream`で取得したビデオストリームは、WebRTCを介して受信者が適切に再生できません。この時点で、Chromeはこの問題を完全に解決していません。唯一の回避策は、ブラウザ設定でハードウェアエンコーディングオプションを無効にすることですが、ユーザーフレンドリーではありません。
2. **Firefoxブラウザ**: `captureStream`メソッドには "moz" プレフィックスを含める必要があります。つまり、正しく機能させるには`mozCaptureStream`を使用する必要があります。
3. **Safariブラウザ**: Video要素は`captureStream`メソッドを完全にサポートしていません。

結果として、私たちは最終的に`video.captureStream`メソッドの使用を放棄し、代わりに`canvas.captureStream`を使用して様々なカスタムストリームを生成しました。

# **キャプチャしたコンテンツの前処理**

Canvasを通じてビデオと画像のみをキャプチャし、それらをリアルタイムストリームに変換する場合、単一ソースのビデオストリームしか生成できません。複数のオーディオとビデオストリームを単一のストリームに組み合わせることはできないでしょうか？リアルタイムストリームを生成する前に、Canvasを通じてキャプチャした視覚コンテンツにミキシングと前処理を行い、`WebAudio`インターフェースを使用してキャプチャしたオーディオに同様のミキシングと前処理を適用することができます。このアプローチにより、OBS（Open Broadcaster Software）の機能のほとんどをウェブに持ち込むことができます。

CanvasとWebAudioの強力な支援により、OBS-webは簡単に実現できますの設計と実装における基本的なアプローチの概要です。

まず、基本的なミキシング機能を実装しました。これにより、複数のビデオとオーディオストリームを1つに組み合わせることができます。さらに、ユーザーは各ビデオフィードのサイズと位置をカスタマイズし、各オーディオソースの音量を調整できます。以下の図に示すとおりです：

![obs2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957687/1844c68a-a650-510f-210e-faa5783c78d4.png)


次に、各ビデオフィードに対して、ミラーフリップやフィルター効果などの個別の前処理効果を実装します：

![obs3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957687/cfd82ce3-a39f-dc32-9503-d32e73af7fed.png)


最後に、ビジュアルにウォーターマーク、テキスト、その他の補足コンテンツを追加すれば、OBS-webの基本機能はほぼカバーされています！全体的な効果は以下の画像を参照してください：

![Screenshot 2024-12-17 at 15.22.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957687/06f73d15-75cd-ce49-b608-525a8e60dd78.png)


ビジュアルのレンダリングにCanvasを使用する際、WebGLを活用してレンダリングパフォーマンスを向上させ、GPUアクセラレーションを利用してより高速なレンダリング速度を実現できます。さらに、WebGL Shadersを使用することで、より洗練されたビジュアル効果を達成し、ブラウザの固有の機能を最大限に活用できます。同時に、`MediaStream`、`HTMLVideoElement`、`HTMLAudioElement`などの入力ソースをサポートする基本的な構成プロトコルを開発しました。このプロトコルは、ルールに従ってビデオとオーディオストリームの処理タスクを定義し、データの変更に応じて動的にビジュアルとサウンドの処理を駆動します。この設計の柔軟性により、新しい効果をシームレスに統合でき、開発効率が向上します。

OBS-webの実装中に発生する可能性のある一般的な問題とその解決策を以下にまとめます：

1. `RequestAnimationFrame` **の制限：** ほとんどの場合、Canvasのレンダリングはフレームの再描画に`requestAnimationFrame`に依存しています。このアプローチにはパフォーマンスの向上やリソースの節約など多くの利点がありますが、ウェブページが非アクティブな状態（非表示または最小化）にある場合に制限があります。この間、`requestAnimationFrame`の実行が一時停止し、Canvasのコンテンツが静的なままになり、実質的にフレームレート0のライブストリームになってしまいます。ライブストリーミングシナリオでこの問題に対処するために、ブラウザのvisibilitychangeイベントを監視する解決策を実装しました。現在のページが表示されている場合（`document.hidden`属性が`false`）、フレームレンダリングには引き続きrequestAnimationFrameを使用します。しかし、ページが表示されていない場合（`document.hidden`属性が`true`）、フレームレンダリングにはsetIntervalを使用するように切り替えます。

2. **WebAudio ContextとInteractivity：** 自動ビデオ再生を防ぐために使用される戦略と同様に、WebAudioコンテキストオブジェクトは、ページとのユーザーインタラクションが検出されない場合、サスペンド状態で開始します。この状態では、WebAudioコンテキストに対する操作は効果がありません。ブラウザとのユーザーインタラクションがある場合にWebAudioコンテキストをアクティブ化し、"running"状態に移行させて、オーディオ操作を効果的に実行する必要があります。

3. **AudioContextとMedia Element Source：** `createMediaElementSource`メソッドを使用して`HTMLVideoElement`と`HTMLAudioElement`からオーディオを抽出する場合、各要素は1回だけ抽出できます。同じ要素を再度抽出しようとするとエラーが発生します。これに対処するために、最初に生成された結果を保存して再利用する必要があります。

これらの課題と解決策は、OBS-webのスムーズな運用を確保し、高品質で中断のないライブストリーミングを可能にするために不可欠です。

これで、OBSの機能のほとんどをウェブに持ち込み、OBSソフトウェアのダウンロードとインストールの必要性を排除しました。しかし、このプロセスをできるだけ簡素化する方法はありますか？

私たちは喜んでこの問題の解決策を見つけたと言えます。

# **WebRTCストリーミングSDKを始める**

そこで、WebRTCストリーミングSDKの使用をお勧めします。これは上記のすべての機能を統合し、ブラウザの互換性とパフォーマンスの問題に焦点を当てています。

WebRTCストリーミングSDKを使用すると、様々なライブストリームをキャプチャし、これらのストリームにローカルでミキシングと前処理を行うことができます。例えば、ピクチャーインピクチャーレイアウト、ミラーとフィルター効果の追加、ウォーターマークやテキストの追加などが可能で、その後、処理されたオーディオとビデオストリームをTencent Cloudのライブストリーミングバックエンドにアップロードできます。

注目すべき点は、ストリームを中断することなく、ストリーミングプロセス中にリアルタイムの視覚的および音声効果を実行できることです。この機能により、ローカル放送に似た効果さえ達成できます。

GitHubでいくつかのオープンソースWebRTCストリーミングSDKを見つけることができます。SDKを選択する際は、特定の要件、必要な制御レベル、スケーラビリティ、およびチームの専門知識などの要因を考慮してください。また、これらのSDKは無料でオープンソースですが、大規模に展開する場合はサーバーコストとメンテナンスを処理する必要があることを覚えておいてください。