こんにちは、WebRTCのハンズオンイベントを受けていてMilkcocoaとつなげてみたくなったのでやってみました。(眠い中まとめてて表現おかしいところあるかも...)
イベントページ: WebRTCハンズオン勉強会
React(ES2015)とMilkcocoaでリアルタイムチャットを作ってみる #reactnative_meetup #mlkcca
AndroidからMilkcocoaを使って見るメモ #mlkcca
こちらのハンズオンは@yusuke84さんと@massie_gさんが講師をやってくれました。また、@massie_gさんが過去にアドベントカレンダーでmilkcocoaでWebRTCのシグナリングをやってみたという記事を書いていたのを思い出してイベント後半でチャレンジしていました。
WebRTCハンズオンでやった内容
WebRTCハンズオン資料 INDEXが当日利用した資料です。
個人的には、 この資料ものすごく分かりやすいと思いました!
ざっくりの流れはこんな感じ
- 単語や仕組み説明
- [STEP1]とりあえず動画撮影とかを試して見る
- [STEP2]手動シグナリングで通信の仕組みを学ぶ
- [STEP3,4] シグナリングサーバーを立ててシグナリング
- メディアレコーダーで動画を扱ってみる
とりあえずの動作 [STEP1]
ボタンクリックすると接続してるカメラの映像を再生できます。
ソースコードはこちらです。
このハンズオンの資料はブランチごとにステップが分かれているので、途中でついていけなくなっても挽回できるやさしい設計です。
手動シグナリング [STEP2]
手動シグナリングのソースコードはこちらになります。
SDP情報を相手に渡すシグナリングをSDP情報のテキストをコピペして相手側のブラウザにペーストする 手動シグナリングを体験してみます。
これが仕組みを覚える上ではかなり重要に感じました。
SDPのやりとりとかは大体シグナリングサーバー経由で隠蔽されているので、接続開始までの知らぬ間にやりとりが発生していることがわかります。
Node.js上のWSサーバーでシグナリング [STEP3,4]
Node.js上のWSサーバーでシグナリングをするソースコードはこちらです。
手動シグナリングではSDPをコピペしてテキストを送ってましたが、WebSocket経由で接続してるクライアントを読み取ってシグナリングしてくれます。
Milkcocoaをシグナリングサーバーにしてみる
※ここからが本題
ここまででやったて思ったのが、テキスト送るだけならWebSocketでやりとりしてるソースコードを全てMilkcocoaに置き換えられそうってことでした。
- https://mlkcca.com/
- 複数プラットフォームをつなげるバックエンドサービス。リアルタイムにテキストやりとりができるのでシグナリングにも使える。
実際にMilkcocoaに書きかえたコードはこちらになります。
wsをMilkcocoaに書き換え
- SDP情報を送る際のsendSdp()
- ICE candidate生成し送信する際のsendIceCandidate()
などでws.send()してる箇所をds.send()に差し替えます。
これでMilkcocoaのsendメソッド経由で相手にSDP情報を送れます。
- ws.onmessageでメッセージの受信監視をしている箇所
この部分をds.on()に変更しMilkcocoaのsendメソッドを監視するようにします。
- これだけだとうまくいかず、エラーに
webrtc.js:281 setRemoteDescription(answer) ERROR: DOMException: Failed to set remote answer sdp: Called in wrong state: STATE_INPROGRESS
ncaught (in promise) DOMException: Error processing ICE candidate
などのエラーがでました。
懇親会のときの@massie_gさんの話によると、SDPを送る際にMilkcocoaだと自分にも情報が送られてきてしまうらしく、そこをハンドリングしないといけません。
socket.ioだと一つのクライアントが情報を送信したら、送信元には送られずに接続してる別のクライアントに対して送ってくれるらしいです。WebSocketも自分自身に情報が送られてしまいうまくいかないときがあるみたいです。
Milkcocoaの場合も同様でds.send()した場合は自分自身にも送られてきてしまいます。 エラーを消すためには 自分自身には情報が送られてこないようにする必要があります
- アクセスごとにUUIDを付与して自分自信への情報は省くように
UUIDを生成して定数化しておきます。
const UUID = uuid();
・
・(省略)
・
function uuid() {
var uuid = "", i, random;
for (i = 0; i < 32; i++) {
random = Math.random() * 16 | 0;
if (i == 8 || i == 12 || i == 16 || i == 20) {
uuid += "-"
}
uuid += (i == 12 ? 4 : (i == 16 ? (random & 3 | 8) : random)).toString(16);
}
return uuid;
}
情報を送る時はこのUUIDを付与してMilkcocoaに送ります。
・
・(省略)
・
ds.send({text:message,uuid:UUID});
・
・(省略)
・
ds.on()でsendイベントを監視し、送られてきたUUIDと自分自身のUUIDが同じ場合は何もしないという処理を追加しました。
ds.on('send', function(sended){
if(!sended.value.text) return;
if(sended.value.uuid === UUID) return;
・
・(省略)
・
これで試すと...相手の顔が!
無事にMilkcocoaでシグナリングができたようです。
仕組みがわかるとけっこう楽しいですね!
WebRTCConfとかに参加してても分からなかった内容が一気に解決した気がします。
まとめ
こんな感じで無事にMilkcocoaをシグナリングサーバーにすることができました。
テキストを送り合うだけなのでシグナリングでも色々なやり方が考えられそうですね笑
Lチカシグナリングが出てくるのを密かに期待してます。
11/1にWebRTC入門者LT会もあるので何か発表してみようかな...