🧊

WebRTC Conference Japan 2日目行ってきたメモ #WebRTCConfJP

昨日に引き続き、2日目。

ただBiz向けではなくDev向けのTrackにずっといたので、偏りがありますw

WebRTC Boot Camp

いわゆるハンズオン。

https://github.com/mganeko/bootcamp

  • カメラ・オーディオストリーム
  • WebRTCの制御
  • シグナリング(呼制御)

この3ステップを理解してないと、WebRTC開発はつらいよというところからハンズオン開始。
以下、完成したサンプルをベタ貼り。

HTML

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>WebRTC Handson</title>
  <style>
    body { font-size: 120%; text-align: center; }
    video { background-color: #000; }
  </style>
</head>
<body>

  <p>1から順に、AB画面それぞれでやるとつながるよ</p>

  <div>
   <video id="myVideo"   autoplay muted width="320" height="180"></video>
   <video id="yourVideo" autoplay muted width="320" height="180"></video>
    <br>
    <button type="button" id="cameraOn">[A1 / B1] Camera on</button>
    <button type="button" id="cameraOff">Camera off</button>
  </div>

  <p>
    [A2 / B4] Copy
    <br>
    <textarea id="sendSdp" rows="5" cols="70" readonly="readonly"></textarea>
    <br>
    <button type="button" id="syn">[A2] Syn</button>
  </p>

  <p>
    [B3 / A5] Paste
    <br>
    <textarea id="receiveSdp" rows="5" cols="70"></textarea>
    <br>
    <button type="button" id="synAck">[B3] SynAck</button>
    <button type="button" id="ack">[A5] Ack</button>
    <button type="button" id="disconn">Disconnect</button>
  </p>

  <script src="./main.js"></script>
</body>
</html>

js

(function(global) {
'use strict';

  // お約束
  navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
  global.RTCPeerConnection = global.RTCPeerConnection || global.webkitRTCPeerConnection || global.mozRTCPeerConnection;
  global.RTCSessionDescription = global.RTCSessionDescription || global.webkitRTCSessionDescription || global.mozRTCSessionDescription;

  // めんどくさいのでヘルパ
  function getElmByIdAndBindClick(id, func) {
    var el = document.getElementById(id);
    el.addEventListener('click', func, false);
  }
  function noop() {};
  function handleError(err) { console.error(err); }

  // グローバルにあると便利
  var myVideo   = document.getElementById('myVideo');
  var yourVideo = document.getElementById('yourVideo');
  var sendSDP    = document.getElementById('sendSdp');
  var receiveSDP = document.getElementById('receiveSdp');

  var myStream = null;
  var peer = null;

  // bind!
  getElmByIdAndBindClick('sendSdp', function(ev) { ev.target.select(); });
  getElmByIdAndBindClick('cameraOn',  startCamera);
  getElmByIdAndBindClick('cameraOff', stopCamera);
  getElmByIdAndBindClick('disconn', disconnect);
  // 厳密にはSYN/ACKとかじゃないけど便宜的に
  getElmByIdAndBindClick('syn',    syn);
  getElmByIdAndBindClick('synAck', synAck);
  getElmByIdAndBindClick('ack',    ack);


  // 自分用カメラON
  function startCamera() {
    navigator.getUserMedia(
      { video: true },
      function(stream) {
        myStream = stream;
        myVideo.src = global.URL.createObjectURL(myStream);
      },
      handleError
    );
  }

  // 自分用カメラOFF
  function stopCamera() {
    // 横着する
    myStream.getTracks().forEach(function(t) { t.stop(); });
    myStream = null;

    myVideo.pause();
    global.URL.revokeObjectURL(myVideo.src);
    myVideo.src = '';
  }

  // 通信先に自分のSDPを用意する
  function syn() {
    _openPeer();

    peer.createOffer(function(sdp) {
      peer.setLocalDescription(sdp, noop, handleError);
    }, handleError, {});
  }

  // もらったSDPでもって相手の情報を保存しつつ、自分のSDPを用意する
  function synAck() {
    _openPeer();

    var offer = new RTCSessionDescription({
      type: 'offer',
      // 相手側からコピーしてきたSDP
      sdp: receiveSDP.value
    });

    peer.setRemoteDescription(
      offer,
      function() {
        peer.createAnswer(function(sdp) {
          peer.setLocalDescription(sdp, noop, handleError);
        }, handleError, {});
      },
      handleError
    );
  }

  // 相手のSDPをもらったら、それで相手情報を保存する
  function ack() {
    var answer = new RTCSessionDescription({
      type: 'answer',
      // 相手側からコピーしてきたSDP
      sdp:  receiveSDP.value
    });

    peer.setRemoteDescription(answer, noop, handleError);
  }

  function disconnect() {
    _closePeer();
  }

  function _openPeer() {
    peer = new RTCPeerConnection({ iceServers:[] });

    peer.addEventListener('icecandidate', function(ev) {
      // 全部揃うまで待つ
      if (ev.candidate) { return; }
      sendSDP.value = peer.localDescription.sdp;
    }, false);

    peer.addEventListener('addstream', function(ev) {
      yourVideo.src = global.URL.createObjectURL(ev.stream);
    }, false);

    peer.addEventListener('removestream', function() {
      yourVideo.pause();
      global.URL.revokeObjectURL(yourVideo.src);
      yourVideo.src = '';
    }, false);

    peer.addStream(myStream);
  }

  function _closePeer() {
    peer.close();
    peer = null;
  }

}(this));

もちろん細かい制御はサボってます。
時間足りん!

  • streamを用意
  • peerConnectionを作る
  • offerしてSDPを用意
  • SDPを伝える
  • もらったSDPでanswerしてSDPを用意
  • SDPを伝える
  • どちらも相手情報を取得できたので、スタート

peer.jsとか使わずに書くと、やっぱそれなりに煩雑なコードになっちゃうし、まったく手軽ではないよなー・・。

てかコレを時間内に完成できる人、このハンズオン出る必要ない!
そして参加者の9割は絶対に完成できないってやる前からわかってたと思うの・・。

WebRTC on Native App (iOS/Android)

SkyWayのiOS/Android用のSDKを作ったときの話。

  • Google作のlibjingleというC++ラッパを使った
  • 2GB超えの大作SDKになった
  • libjingle Core
    • ビデオ・オーディオコーデックの処理(SW Codec)
    • RTP/RTCP
    • STUN/TURN
    • SDP ICE
  • libjingle自体の変化も速くてつらい
    • OS/実機 or Sim/32 or 64bit/Chip などの差でもコードがころころ変わる
  • 一括ビルドツールもあるけど・・
  • ハードウェアによってプロファイルが違うとかある
  • Androidはメーカーによって挙動違ったりする
  • オーディオまわりのほうが闇が深いらしい

門外漢過ぎてさっぱりわからんかった。

ここがつらいよWebRTC - WebRTC開発の落とし穴

パネルディスカッション。

どこまで対象にしてサポートしてるか

ブラウザのバージョン差異をどうするか

端末性能

  • 端末の内蔵カメラはそれなりに動くがマイクは怪しい
  • 外付けマイク強い
  • 元からWebRTCはVoLTE並の音質

つながらない問題

  • つながらないって言われる・・
    • PCのスペックが足りないとかはまだマシ
    • 接続数が増えてきてつながらないケースとかは切り分けつらい
  • 社内ネットワークでそもそもつながらない
  • っていうケースがあるだけで、基本的にはつながる
  • getUserMediaの許可まわりが一番多い
    • 全画面で説明するくらいでもいい
  • https://test.webrtc.org/ の社内版を用意したり

シグナリング/TURNサーバーどうしてるか

  • SkyWayおすすめ
  • 自作の場合、WebSocketのポート埋まってること多いので注意
  • TURNはAWS(US)でも特に困ってない
  • TURNは1台で良かったりする

WebRTCアプリケーションのテストの課題・解決方法について

SkyWayにおけるテストの話。

  • テストつらい
  • そもそもノウハウが少ない
    • 大企業でもリソースが・・
    • やるにしても手動つらい・・
  • VoIPのノウハウが使えない
  • Web屋の知らないスタックが多すぎる
  • NATの種類によっては、マッピング・フィルタリングの挙動が違う
    • UDPホールパンチングの可否がそれによって変わる

なので、自動テストツールつくった。

  • 先述のNATのタイプまでテストするので、AWSVPCで動かす
    • 中で特製のNAT(iptablesではなくスクラッチ)を使ってテストできる
    • そこで、Selenium同士が通信
  • テストパターンが多いのでそれなりに時間はかかる
  • http://status.skyway.io/
    • 今は映像だけをテストしてる(= 音声トラックはバンドルされてるのでたぶん大丈夫(質は別))
  • Seleniumを動かすためのシェルが一番泥臭い

Web屋の知らないスタックが多すぎる問題は本当に感じていて、そんなのを意識せずに使えるようになる日がこないものかと待ち望んでいる感じです・・。

WebRTC SFU コトハジメ

WebRTCといえばの人。

資料はコレ: https://gist.github.com/voluntas/4d2bd3e878965bdd747a

聞くのに忙しくてメモはありません。
というか、資料が全てとのこと。

すーぱーわかりやすく説明してもらってると思うんですけど、なるほどわからん!

P2PのWebRTCが結局スケールしなくてSFUになるなら、そもそもWebSocketで似たようなスタックは作れないものなのかってのが気になるので試してみようと思う

WebRTC Next Version時代のJavaScript開発

  • ライブラリやらプラットフォームが流行るとWebRTC力が下がる
    • 生身だと何もできないわからない -> 危険!
  • 次期WebRTC(ORTCとの統合的な)に備えよ
    • offer/answerモデルからの脱却
    • SDP -> JSON
  • EdgeにはORTCの一部が実装されてる

EdgeのORTCシーケンス

Object RTC API

  • [事前準備]
  • MediaStream
  • RTCIceGatherOptions
    • IceTransport / DtlsTransport
  • RtpSender / RtpReceiver
  • [/事前準備]
  • ここまでしてやっと通信開始
  • MediaStreamにaddTrack

例のadapter.jsだと、EdgeでもWebRTC1.0のコードで書けるらしい。
あとEdgeは同一のカメラを同一のブラウザで触れないとのこと。

WebRTCショートセッション4本勝負!

2日間の締めくくり。

スマホチャットアプリにおけるWebRTC通話アプリ開発事例

TriFort社の人。
サービスはコレかな?: http://startalk.trifort.jp/

  • LINEみたいなチャットアプリに、生放送機能をいれた
  • VoIPで組むか、WebRTCで組むか
    • 通話品質を試したがどちらも差異がなかったので、WebRTCに
  • スマホ基地局が変わった時に切断される
    • 再接続の仕組みをいれた
  • 1:Nだと7人くらい、N:Nでも5人くらいが限界(よくあるスマホ)
    • PCが親だと30人とかでもいける
    • コーデック変えればもうちょい伸びるかも?
  • IPv6対応しないとAppleにリジェクトされるらしいが・・?

WebRTCアプリを個人で開発・運営してみた話

イカデンワの人こと@mzsm_jより。

  • 通話相手を切り替えられる通話アプリがほしい
  • 開発1週間くらい
  • シグナリングサーバーはEasyRTC
    • ルーム機能が標準にあったから
  • ミュート機能はWebSocket
  • SFUではない
    • 音声だけなら
    • 8人以上は検証してないけど17人でもいけたらしい
  • アプリ: さくらVPS x STUN/TURN: ConoHa
  • SSL導入が面倒だった
  • Skype落ちた勢が避難してきてサーバー落ちた

色々なデバイスの映像を使ったWebブラウザでのWebRTC映像中継

デバイスWebAPIコンソーシアム

WebRTC x IoT その現状と可能性を探る

  • 北米のIoT事情
  • リモートカメラでWebRTC
  • IoTをMicroService化して組みあわせる視点
  • これからセキュリティやプライバシーも焦点になってくる
  • IoT x WebRTCで
    • 安心: カメラで見たい
    • AIと融合: 人の代わりに考えたり
    • コミュニケーションの多様化: ロボットが代わりに
    • 操作性: 操作をデータ化してアーカイブ
  • 近視眼的に捉えない
    • 海外社会の背景など加味しつつ、今できることを

おわりに

参加費がちょっと高かったけど、WebRTC情報って珍しい気がするし、色んなジャンルの話が聞けてよかったかなーと。
お弁当も出るし事前に資料を冊子にして渡してくれるし、いつもの勉強会とは違う感じでした。

WebRTCそれ自体に関してはやっぱりWeb屋としてはつらい分野が多くて、きっと実案件でも困るのはそのあたりな気がしてます。
限られた環境での簡単なビデオチャットとかなら作れる気はするけど、それ以上のニーズってどんなんがあるんやろ?