Help us understand the problem. What is going on with this article?

Phoenix Channelを使ってWebRTCのシグナリングをするメモ #beamlangtokyo

More than 1 year has passed since last update.

Elixir初心者向けハンズオン vol2で学んだことを振り返りつつメモ書いています。

前にWebRTCのシグナリングサーバーにMilkcocoaを使って見るメモ #webrtcjp #mlkccaという記事を書いたのですが、これのPhoenix.channel版をやってみます。

内容的にはWebRTC側の要素が多いかも

作ったもの

ビデオチャット - Phoenix Channelでシグナリングをするようにしています。

Elixirハンズオンでやったこれと

WebRTCハンズオンでやったこれ

二つの組み合わせです。

Phoenix Channel

ハンズオンの資料を参照。

PhoenixはWebSocketをそのまま使うのではなく、 WebSocket上に作られた複数のChannel(PhoenixChannel)を使って クライアントとサーバーの双方向通信を行います。

  • WebSocket上に仮想的なレイヤーを作って通信を行う仕組み
  • Socket.ioのルーム機能みたいなものを実装している
  • JS以外にもSwiftなどのクライアントが存在する

WebRTCのシグナリングの修正点

基本はこちらの記事の手順で進めたあとの話になります。

イベント追加

lib/demo_web/channels/chat_channel.exsignalingイベントを追加

lib/demo_web/channels/chat_channel.ex

(省略)

    def handle_in("signaling", payload, socket) do
        broadcast! socket, "signaling", payload
        {:reply, {:ok, payload}, socket}
    end

(省略)

サーバーサイドはこれだけ。

UUIDの生成

今回はdemoという名前のPhoenixアプリケーションを作成し、assets/js/demo.jsに追記していきました。

Milkcocoa版の時と同様ですが、SDPを送る際に、自分自身に情報が送られるとFailed to set remote answer sdp: Called in wrong state: STATE_INPROGRESSなどのエラーがでるため自分自身には情報が送られてこないようにする必要があります。

アクセスごとにUUIDを付与して自分自信への情報は省くようにします。

Phoenix Channelでそういう機能ないのかな (ありそう)

assets/js/demo.js
'use strict';

import {Socket} from "phoenix"

const UUID = uuid();

function uuid() {
  let 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;
}



(省略)


sdpとIceCandidateの送信

どちらもchan.push()を使って送信するようにします。

assets/js/demo.js

(省略)


function sendSdp(sessionDescription) {
        console.log('---sending sdp ---');
        $textForSendSdp.value = sessionDescription.sdp;
        const message = JSON.stringify(sessionDescription);
        console.log('sending SDP=' + message);
        //ws.send(message);
        chan.push('signaling', {body: message, uuid:UUID})
}


(省略)


 function sendIceCandidate(candidate) {
        console.log('---sending ICE candidate ---');
        const message = JSON.stringify({ type: 'candidate', ice: candidate });
        console.log('sending candidate=' + message);
        // ws.send(message);
        chan.push('signaling', {body: message, uuid:UUID})
    }


(省略)

signalingイベントを受け取る処理を追加

SDP情報が送られてきたときの処理です。

if(msg.uuid === UUID) return;では先ほどのUUID話で送られてきたUUIDが自分のものだった場合は何もしないようにしています。

assets/js/demo.js

(省略)

    chan.on("signaling", msg => {

      const message = JSON.parse(msg.body);
      if(msg.uuid === UUID) return; //送られてきたUUIDが自分のものだった場合は何もしない

      if (message.type === 'offer') {
        // offer 受信時
        console.log('Received offer ...');
        $textToReceiveSdp.value = message.sdp;
        const offer = new RTCSessionDescription(message);
        setOffer(offer);
      }
      else if (message.type === 'answer') {
          // answer 受信時
          console.log('Received answer ...');
          $textToReceiveSdp.value = message.sdp;
          const answer = new RTCSessionDescription(message);
          setAnswer(answer);
      }
      else if (message.type === 'candidate') {
          // ICE candidate 受信時
          console.log('Received ICE candidate ...');
          const candidate = new RTCIceCandidate(message.ice);
          console.log(candidate);
          addIceCandidate(candidate);
      }
    })

(省略)

これでPhoenix Channel経由でシグナリングができるようになりました。

所感

Phoenix自体今日初めて触りましたが使い勝手よくErlang VMを利用できる仕組みはすごいですね。(小並感

Socket.ioなどの既存システムとうまく連携できる仕組みがあると過去のシステムの乗り換えハードルが下がって良さそう。(ブリッジする仕組みありそうな気がする)

n0bisuke
プロトタイピング専門スクール「プロトアウトスタジオ」で教えたりしてます。 プロフ -> https://dotstud.io/members/n0bisuke
https://protoout.studio
dotstudio
全ての人がモノづくりを楽しむ世界を目指して活動しています。
https://dotstud.io
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした