18
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

VaporAdvent Calendar 2018

Day 17

Vapor でWebRTCを使ったビデオチャットを作成したまとめ

Last updated at Posted at 2019-03-12

はじめに

ビデオチャット機能を実装したいとの要望があり、 WebRTC について調べました。
WebRTC はとても面白く、魅力的な技術でしたが、同時にとても手強かったため、忘備録&記憶の整理用この記事を書きました。

同じ頃に Swift製 WebFrameWork である Vapor に興味が沸き、「WebRTC のサーバーサイドを Vapor で書けば一度に両方の技術を取得できるのでは?」と思い、WebRTC 用のシグナリングサーバーを Vapor で作成しました。
作成した Swift 製のシグナリングサーバーはこちらです。

https://simple-video-chat.work/

4文字以上の任意のルーム名を URL の後ろに入力し iOS 以外の異なるブラウザ同士でアクセスするとビデオチャットが始まります。

Ex: https://simple-video-chat.work/xxxx

勉強用に作成したため、いつまで残すかわかりません。ソースコードはこちらです。

O-Junpei/simple-video-chat-server

ハンズオンで WebRTC の概要を理解する

@massie_g さんと @yusuke84 さんのハンズオンが素晴らしいのため、まず最初に取り掛かる事をお勧めします。
ブラウザ間でビデオチャットが表示されると感動します。

WebRTCハンズオン 概要編
https://qiita.com/massie_g/items/916694413353a3293f73

WebRTCハンズオン 準備編
https://qiita.com/massie_g/items/6141a1020dd8bdf6574e

WebRTCハンズオン 本編
https://qiita.com/yusuke84/items/43a20e3b6c78ae9a8f6c

シグナリングサーバーを作成する

(上記ハンズオンに目を通した前提で進めます。)
WebRTCハンズオン本編 STEP3 で作られているようなシグナリングサーバーを Vapor で実装します。
シグナリングサーバーは通信相手の情報を交換する役割、ちょうどブラウザ同士の電話番号(SDPと呼ばれます)を交換するイメージです。
今回は同じルーム(URL)にアクセスしている相手にSDPを転送するシグナリングサーバーを作成しました。

configure.swift
var websocketClients: [String: [WebSocket]] = [:]

// WebSockets
let wss = NIOWebSocketServer.default()
wss.get("socket", String.parameter) { ws, req in
    let room = try req.parameters.next(String.self)
    // roomがなければ初期化、既にある場合はcloseを削除
    if websocketClients[room] == nil {
        websocketClients[room] = []
    } else {
        websocketClients[room] = websocketClients[room]!.filter({
            !$0.isClosed
        })
    }
    websocketClients[room]!.append(ws)
    ws.onText { ws, text in
        for client in websocketClients[room]! {
            if client.isClosed {
                return
            }
            if ws === client {
                print("slip sender")
            } else {
                // roomが一緒
                client.send(text)
            }
        }
    }
}
services.register(wss, as: WebSocketServer.self)

参考: Vapod Docs Using WebSockets
参考: VaporでWebSocketを使ったチャットアプリを作る

HTML ページの生成

シグナリングサーバーができたので、次はフロント(HTML)をのレンダリング機能を作成します。
routes.swiftは Rails における config/routes.rb で、ルーティングの設定を行うことができます。
4文字以上のルーム名が入力された場合はビデオチャットページ index.html へ、それ以外は Vapor のデフォルトページ welcome.heml をレンダリングしています。
index.htmlの中身(JS)はハンズオンからお借りしました。

routes.swift
import Vapor

/// Register your application's routes here.
public func routes(_ router: Router) throws {
    // Top
    router.get { req in
        return try req.view().render("welcome")
    }
 
    // room
    router.get("/", String.parameter) { req -> Future<View> in
        let room = try req.parameters.next(String.self)
        if room.count < 4 {
            return try req.view().render("welcome")
        }
        return try req.view().render("index")
    }
}

参考: Getting Started | Leaf

デプロイ

作成した Vapor のアプリケーションを Docker化し、GCPのCompute Engin にデプロイしました。
以下の構成になっています。

Untitled Diagram.png

以下のコマンドでローカルでも実行できます。

$ docker run -d -p 80:80 kabigon/simple-video-chat:latest

完成

Android のChorme と PC の Chorme で繋げています。
スクリーンショット 2019-03-12 9.49.17.png

早く知りたかったこと、詰まったこと

シグナリングサーバー(WebSocket)のデバックがしたい

wsta は シンプルな WebSocket クライアントです。
HomeBrew で簡単にインストールすることができ、シグナリングサーバーのデバッグに役立ちます。

$ brew tap esphen/wsta https://github.com/esphen/wsta.git
$ brew install wsta

ターミナルを2つ開き、WebSocket で接続する。
片方に入力した文字が転送される。

$ wsta wss://simple-video-chat.work/socket/xxxx // or
$ wsta ws://localhost:8080/socket/xxxx

WebRTC は localhost 以外はSSL 必須

WebRTC を使うには SSLが必要です。
オンラインで使う場合はlet's encrypt などでSSL化してあげましょう。

WebRTC のデバッグをしたい

chrome://webrtc-internals/ と打ち込むとWebTRTC のデバッグができます。
参考: WebRTCデバッグ入門

NginxによるリバースプロキシとWebSocketを同時に使用する時は設定が必要

WebSocketのハンドシェイク時に使われる Upgrade ヘッダと Connection ヘッダ は Hop-by-Hop ヘッダ である。 通常のEnd-to-End headerと異なり基本的に一度の転送に対して有効なヘッダなため、ReverseProxyを間に挟んでいる場合これらのheaderはバックエンドサーバまで届かない。

Nginxによるリバースプロキシ + WebSocket を使う時は注意が必要です。
nginx.conf ファイルに以下を追記します。

proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

参考: Nginxを用いたWebSocketサーバのReverseProxy構成及びSSL/TLS接続

iOS のブラウザ(Safari & Chorme)では WebRTCは使えない場合がある

制限が多く、思ったように動かない場合が多いため注意が必要です。
(追記: Safari 12.1 で映像コーデック VP8 に対応することで、 WebRTC は主要ブラウザで問題なく利用することができるようになる。とのことです。)

参考: Safari と WebRTC について
参考: WebRTC の今

iOS アプリでWebRTC を使ったビデオチャットアプリを作りたい

iOS アプリのブラウザ(WebView)では制限が多いため、WebRTC に対応したブラウザを CocoaPods などでインストールする必要があります。
以下の記事がとても良かったのでおすすめです。

SwiftでWebRTC実装ハンズオン 事前準備編
https://qiita.com/tnoho/items/3b94371e59fe8ad6ce03

SwiftでWebRTC実装ハンズオン 本編
https://qiita.com/tnoho/items/f5afa3ba749eed9b9716

ただ、上記記事のソースコードは Swift3 で書かれており、少し古くなってしまっているので、Swift4.2 で書き直しました。
近いうちにこの記事の続きとして公開します。

やっぱり辛い逃げよう

WebRTCを自前で実装すると大変です。

18
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?