がねこまさし

Firebaseで楽々シグナリング──WebRTC入門2016番外編

連載: WebRTC入門2016 (5)

こんにちは! 2014年に連載した「WebRTCを使ってみよう!」シリーズのアップデートとしてお送りしているこの連載ですが、今回はもとの連載にはなかった内容を番外編としてお届けします。

httpsのハードル

前回は複数人、複数会議室で利用できるようにして、実用的なアプリを作る準備ができました。ところが実際に使おうとすると、Chromeのセキュリティポリシーと向き合わなくてはなりません。

「getUserMedia()やService Workerなどの強力なAPIは、セキュアな環境でなくては利用できない」というポリシーは今のWebの状況に合わせたものだと思います。では、その環境をどうやって用意すればよいのでしょうか?

もちろん証明書を取得して、きちんとサーバーを立てるのがまっとうなやり方です。最近はLet’s Encryptなど無料で証明書を発行するサービスもあります(参考:“Let’s Encrypt – how get to free SSL for WebRTC”)。とはいえ、試験的な利用でそこまで準備するのは大変というのも、正直なところです。そこで今回は、比較的とっつきやすい方法をご紹介します。

Webサーバー

HTMLやJavaScriptなどの静的コンテンツを配置できる手段はいくつかあります。エンジニアの皆さんであれば、次の2つをすでに利用されている方々も多いのではないでしょうか?

  • GitHub Pages
  • Google App Engine

どちらも http / https の両方でアクセスできますし、独自ドメインで利用することも可能です。(※利用方法についてはWebに多くの情報がありますので、そちらをご参照ください)

また、シグナリングで利用するFirebaseにも静的コンテンツのホスティング機能があります。

シグナリングサーバー

シグナリングにはsocket.ioなど、WebSocketを活用した仕組みが使われる例が多いようです。もちろん他の方法(例えば手動シグナリング)でもいいのですが、サーバーとクライアント(ブラウザ)で双方向に通信するにはWebSocketが適切なのでしょう。

https://~から取得されたHTML/JavaScriptからWebSocketサーバーに接続する場合には、そちらもセキュアでなくてはなりません。(ws://~ではなく、wss://~)。WebSocketを利用したシグナリングサーバーを自分で用意する場合、そちらでも証明書が必要になります。

そこで今回はリアルタイムメッセージングに利用できるBaaSであるFirebaseを使って、シグナリングの仕組みを構築したいと思います。

Firebaseでシグナリングを実現するには

まずはFirebaseにサインアップし、必要なキーやURLを入手しましょう。

(※手順については今回は省略させていただきます。あしらかず)

ブラウザでFirebaseの機能を利用するために、必要なライブラリを読み込んでおきます。今回はデータベースを利用するので、必要なjsファイルは次の通りとなります。

それから取得しておいたキーとURLを用いてFirebaseに接続します。

シグナリングで送りたいモノ

前回の記事にもあるように、シグナリングでは2つの通信ケースがあります。

  • ルーム内の他のメンバー全員(接続している他のクライアントすべて)に送る
  • 特定のメンバー(特定のクライアント)だけに送る

また後者のためには、特定のメンバーを識別するための何らかのIDが必要となります。

  • クライアント側で、重ならない/重なりにくい ようにIDを決める(UUID、タイムスタンプ、乱数など)
  • サーバー側でIDを振り出す

Firebaseを使うとデータベースに格納されるオブジェクトのすべてにIDが振られるので、今回はそれを利用します。

データベースの構造

Firebaseはデータベースによる階層構造をもったデータの永続化と、その追加/変更/削除のイベント通知が行えます。今回は次のようなアプリ/ルーム/メンバーの階層構造としました。

firebase_structure_1

例えばルーム”test”にメンバー”bbb”が参加する場合、次の2カ所のイベントを待ち受けています。

  • multi/room_test/_broadcast_ の child_added イベント
  • multi/room_test/_direct_/member_bbb の child_added イベント

また、multi/room_test/_join_ はメッセージのやりとり以外の用途で使います。

メンバーのIDの決定

メンバーを特定してメッセージを送るには、メンバーを識別するIDが必要です。先ほどは仮に”bbb”としましたが、実際には衝突を避けるためにFirebase側で振り出されるキーを利用することにしました。

データベースにパスを指定してpush()すると、子要素が追加されて、そのキーが返っています。その値を使って先ほどの子要素の内容を更新しています。

ここまで終わった時のDatabaseの内容をFirebaseのコンソールで見てみると、次のようになっています。

firebase_join

ルーム内へのブロードキャスト

シグナリングの流れは前回と同じです。

multi_callme_simple

  • 新たに通信を開始したい人(member_xxxx)が、通信開始の合図のルーム内にブロードキャスする(“call me”)

“test”ルームにブロードキャストする場合には、 multi/room_test/_broadcast_ の下を使います。

各メンバーはこのブロードキャストのイベントを待ち受けていて、typeに応じて処理を行います。

socket.ioでは自分自身からメッセージは飛んで来ませんが、Firebaseでは自分でpush()してもイベントが飛んでくるので、それは無視しています。

特定のメンバーへのメッセージ

通信開始の合図である”call me”以外は、特定のメンバー宛のメッセージのやり取りになります。例えば member_bbb 宛のメッセージは、この下にpush()します。

  • multi/room_test/direct/member_bbb

Offer/Answerの交換やICE Candidateのやり取りは、すべてこちらのメンバー宛のメッセージになります。

Firebaseのルール設定

Firebaseのデータベースにはアクセスのルール指定があります。デフィルトではread/writeにAuth必要なルールが生成されていますが、今回のサンプルでは特定のパス以下はAuth不要で読み書きできるよう、ルールを追加しました。

NAT越えの設定 STUNの設定

せっかくFirebaseでメッセージをやり取りできるので、NATを超えてWebRTCで通信できるようにしましょう。

NATを超えて通信を行うには、ローカルネットワークでのIPアドレスではなく、グローバルIPを伝える必要があります。今回は詳しく説明しませんが、そのための仕組みがSTUNです。GoogleがSTUNサーバーを公開しているので、それを使わせてもらいましょう。

2014年の記事では”url” と指定していましたが、現在の仕様では”urls”と指定する必要があります。

このようにSTUNサーバーを指定することで、通信経路の候補(ICE Candidate)に、STUN経由で取得した情報も含まれるようになります。

動かしてみよう

今回のサンプルをGitHub Pagesで公開しています。Firebaseもしばらく(〜2016年9月末の予定)使える状態にしておきますので、皆さんもお試しください。

※シグナリングの手段以外は、前回のソースと同様の処理になっています。

使い方

  • URLの後ろに ?room という形で、好きなルーム名を指定してください
    • https://mganeko.github.io/webrtcexpjp/basic2016/multi_firebase.html?お好きなルーム名
  • ルーム名を指定せずに multi_firebase.html を開くと、ランダムにルーム名を決定します
  • [Start Video]をクリックし、カメラの映像とマイクの音声を取得します
  • 通信相手にも同じルーム名を指定してブラウザ(Chrome/Firebox)でアクセスしてもらいます
    • ?room も含むURLを伝えてください
    • “Mail link of this room” をクリックすると、URLを送るためのメーラーが開きます。宛先を指定して送信してください
  • 通信相手にも[Start Video]をクリックし、カメラの映像とマイクの音声を取得してもらいます
  • 自分、あるいは相手から[Connect]ボタンを押してください
  • Firebase経由で情報が交換され、P2P通信が始まります
  • このサンプルでは、同じルームに同時に4人まで(3人の相手と)通信することができます

トラブルシューティング

  • 異なるPCで通信できない場合
    • → ルーム名が一致しているか確認していください
    • ルーム名を指定せずにブラウザでアクセスすると、ランダムにルーム名が決定されます
    • 異なるPCでは、それぞれ異なるルーム名がランダムに決定されます
  • 一度接続できたが、その後できなくなった場合
    • ルーム内の過去のブロードキャストメッセージが残っている可能性があります
    • ルーム名を変更して、再度接続してみてください
  • (例えば)会社と自宅で通信できない場合
    • → NATだけでなく、FirewallでUDP通信やポートが制限されている可能性があります
    • ※Firewallを超えての通信については、次回の記事で取り上げる予定です

Edge同士での通信

webrtc.orgが提供しているadapter.jsを使うと、多くのブラウザの差異を吸収することができます。最新のhttps://webrtc.github.io/adapter/adapter-latest.jsを読み込めば、Microsoft EdgeのサポートしてるORTCを、WebRTCのオブジェクトのインターフェイスを通して利用することができます。

残念ながらサポートしているビデオコーデックの制限で、ChromeやFirefoxとのビデオ通信はできませんが、Edge同士であれば今回のFirebaseを使ったシグナリングでビデオ/オーディオのP2P通信を行うことができます。

edge_firebase

注意点

  • Edgeでは、同一のカメラを複数のウィンドウ/タブで利用することができません。同一PCで通信する場合は、複数のカメラを用意してください
  • Edgeでは現在のところSTUNはサポートされていない(TURNのみサポート)ため、今回のサンプルでNATを越えた通信はできません

次回は

今回はFirebaseを使ってシグナリングを実現しました。次回はNAT/Firewallを超えてのWebRTC通信についてお届けする予定です。

Powered byNTT Communications

tag list

アクセシビリティ イベント エンタープライズ デザイン ハイブリッド パフォーマンス ブラウザ プログラミング マークアップ モバイル 海外 高速化 Angular2 AngularJS Canvas Chrome Cordova CSS de:code ECMAScript Edge Firefox Google Google I/O 2014 HTML5 Conference 2013 html5j IoT JavaScript Microsoft Node.js PhoneGap Polymer React Safari SkyWay TypeScript UI UX W3C W3C仕様 Webアプリ Web Components WebGL WebRTC WebSocket