WebRTCのシグナリングをSignalRでやってみた(実装編)
2019-07-01
azblob://2022/11/11/eyecatch/2019-07-01-webrtc-signaling-by-signalr-2-000.jpg

はじめに

前回は「解説編」として、WebRTC、シグナリング、SignalRについて解説しました。今回は実装編として、実際にアプリケーションを作っていきます。

開発環境

  • Windows 10 Home 1809
  • Visual Studio Community 2017
  • .NET Core 2.2
  • Google Chrome 75

サンプルコード

サンプルコードはGitHubで公開しています。

kadoshita-yoshiki-fixer/SignalRSignaling: SignalRを用いたWebRTCシグナリング

プロジェクト作成

プロジェクト作成は、公式のドキュメント通りに進めれば大丈夫です。今回使用したSignalRのクライアントライブラリのバージョンは@aspnet/signalr@1.1.4です。 また、ドキュメントではプロジェクト名を「SignalRChat」としていますが、今回は「SignalRSignaling」としました。

実装(サーバー側)

作業の流れは、公式ドキュメントとほぼ同じですが、シグナリング処理を行うために「SignalR ハブを作成する」の箇所を一部変更しています。 違いは、こちらです。

  • ChatHubSignalingHub
  • SendMessageSendSDP
  • Clients.All.SendAsyncClients.Others.SendAsync
  • ReceiveMessageReceiveSDP

今回作るものがチャットではなくシグナリングのアプリケーションであること、扱うデータがメッセージではなくSDPであることから、名前を変更しました。ほかの部分の変更はありません。 また、Clients.All.SendAsyncClients.Others.SendAsyncとしたのは、SDPを自分以外の相手に送るためです。 Clients.以降の文字列によって、どのクライアントにデータを送るのかをコントロールすることができます。

クライアントの指定送信したクライアント他のクライアント
All
Caller×
Others×

これら以外にも、IDを指定して特定のクライアントだけにデータを送ったり、グループを指定して特定のグループのクライアント全員にデータを送ったりと、柔軟にコントロールすることができます。

ASP.NET SignalR ハブ API ガイド - サーバー (c#) | Microsoft Docs

実装(クライアント側)

クライアント側のコードのうち、ポイントを掻い摘んで解説します。

カメラ映像の取得

このコードだけでカメラの映像を取得することができます。ここで取得した映像をWebRTCで相手に送ります。 余談ですが、 audio のみを true とすればボイスチャットになりますし、 navigator.mediaDevices.getDisplayMedia を使用すれば画面共有ができます。

navigator.mediaDevices.getUserMedia({ video: true, audio: true })
.then(stream => {
    localStream = stream;
    $('#localVideo').get(0).srcObject = stream;
}).catch(err => console.error(err));

SignalR接続

SignalR関連の処理はたったこれだけです。connection.invokeの第1引数で指定しているのは、サーバー側のメソッド名です。このようにクライアント側からサーバー側の処理を実行することができます。 逆に、サーバー側からクライアント側の処理を実行するときは、Clients.All.SendAsyncの第1引数で指定したクライアント側の処理が実行されます。このような処理のスタイルを「RPC(Remote Procedure Call)」と言います。

let connection = new signalR.HubConnectionBuilder()
    .withUrl('/signalingHub').build();

//省略
connection.invoke('SendSDP', JSON.stringify(_pc.localDescription))
                .catch(err => console.error(err));

connection.on('ReceiveSDP', sdpStr => {
    let sdpObject = JSON.parse(sdpStr);
    //省略
});

RTCPeerConnection

WebRTCはRTCPeerConnectionというオブジェクトを用いて通信が行われます。このオブジェクトから通信経路候補情報を受け取ったり(onicecandidate)、映像ストリームを追加したり(addStream)して、WebRTCの処理を行います。

let _pc = new RTCPeerConnection({
    iceServers: [{
        urls: 'stun:stun.l.google.com:19302'
    }]
});

実行

Visual StudioのF5キーを押すとアプリケーションが起動します。自動でブラウザが開くので、カメラの映像が表示されているか確認してください。アクセス許可のダイアログが表示されている場合は許可してください。 同じアドレスを別のウィンドウでも開き、片方のウィンドウのconnectボタンを押すとSignalRを使用したSDPの交換が行われます。その後接続が確立するとP2Pでカメラの映像が送受信されます。

おわりに

SignalRは今回初めて使ってみましたが、わずかなコードで簡単にリアルタイムWebの機能が実現できるので、とても素晴らしいライブラリだと感じました。また、今回のようにASP.NET Coreを使用すれば、Windowsに限らず様々な環境でアプリケーションを動かすことができます。 皆さんもWebRTCやSignalRを使ってリアルタイムWebアプリケーションを作ってみてはいかがでしょうか?