ブラウザでwebrtc - iosゲートウェイ作ってみた

27
WebRTC Meetup Tokyo #14 ブブブブブ iOS ブブブブブブブブブブブ Build WebRTC - iOS Gateway on Browser 2017.03.23 ブブブブブブブブブブ ブブブブブブ @massie_g 1

Upload: mganeko

Post on 05-Apr-2017

514 views

Category:

Technology


2 download

TRANSCRIPT

Page 1: ブラウザでWebRTC - iOSゲートウェイ作ってみた

WebRTC Meetup Tokyo #14

ブラウザで iOS ゲートウェイ作ってみたBuild WebRTC - iOS Gateway on Browser

2017.03.23インフォコム株式会社がねこまさし@massie_g

1

Page 2: ブラウザでWebRTC - iOSゲートウェイ作ってみた

自己紹介• がねこまさし / @massie_g

• インフォコム株式会社 に所属– 技術調査と社内での利用を推進するチーム

• WebRTC Meetup Tokyo スタッフの一人• WebRTC Beginners Tokyo 講師の一人• WebRTC 入門 2016 を HTML5Experts.jp に連載してました

– https://html5experts.jp/series/webrtc2016/

2

Page 3: ブラウザでWebRTC - iOSゲートウェイ作ってみた

今日のお題• iOS のブラウザでは、まだ WebRTC が使えない

– Webkit では WebRTC 対応が進んでいる様子。が、 Safari に入るかは Apple 次第• でも、今ある技術を使って、無理やりコミュニケーションできる!

– Canvas, Web Audio, WebSocket を利用• 先行している試みを パクって 手本にして実現

– 音声: @leader22 「 WebAudio でなんちゃって WebRTC 」• http://leader22.github.io/slides/webaudio_tokyo-1/

– 画像: @voluntas 「 WebRTC SFU Sora ノススメ」のスナップショット機能• https://gist.github.com/voluntas/0d6621d15947a24e710b0610093a5d20

3

Page 4: ブラウザでWebRTC - iOSゲートウェイ作ってみた

DEMO• PC Chrome iOS Safari

– ぱくたそ の写真を使わせていただいています– https://www.pakutaso.com

• ソースコード– https://github.com/mganeko/webrtcexpjp/tree/master/gateway

• ちょっと残念な部分もありますが…– 縦の写真が上手く扱えない 4

Page 5: ブラウザでWebRTC - iOSゲートウェイ作ってみた

PC Chrome iOS Safari (1) Video

5

getUserMedia()

MediaStream

<video>

<canvas>

Blob JPEB

setInterval()

drawImage()

toBlob()

WorkerWebSocket(socket.io)

BlobJPEB

socket.ioServer

postMessage()

WorkerWebSocket(socket.io) ArrayBuffer

postMessage()

ArrayBuffer

<img>

Blob

createObjectURL()

PC Chrome iOS Safari

Page 6: ブラウザでWebRTC - iOSゲートウェイ作ってみた

PC Chrome iOS Safari (2) Audio

6

getUserMedia()

MediaStream

Worker

WebSocket(socket.io)

socket.ioServer

Worker a

WebSocket(socket.io)

PC Chrome iOS Safari

WebAudio

ScriptProcessor [Float32Array]

MediaStreamAudioSourceNode

[Uint8Array]

compress

postMessage()

ArrayBuffer

(decompress)

WebAudio

6

AudioBufferSource

ArrayBuffer

decoceAudioData()

AudioDestinationNode

postMessage()

Page 7: ブラウザでWebRTC - iOSゲートウェイ作ってみた

PC Chrome iOS Safari : Image

7

<img>

toDataURL ()

WorkerWebSocket(socket.io) DataURL

socket.io Server

postMessage()

<img>

<img>

<img>

<canvas>

drawImage()

DataURL

toBlob ()

<img>

DataURL

img.src

WorkerWebSocket(socket.io)

postMessage()

DataURL

iOS SafariPC Chrome

Page 8: ブラウザでWebRTC - iOSゲートウェイ作ってみた

通信データ量の削減:画像• TCP の通信では、条件が厳しくなると、どんどん遅延が発生

– 本来はリアルタイム映像、音声通信には不向き– なるべく通信に余力ができるよう、データ量の削減が必須

• 画像 240x180 / 毎秒– RGB の RAW…   240x180x24bit = 1 Mbit, 129 kb

– PNG … 約 760 kbit, 96 kb

– JPEG … 約 110 kbit, 14 kb

– → 最終的に、 2 秒に 1 回に … 56 kbit/sec8

Page 9: ブラウザでWebRTC - iOSゲートウェイ作ってみた

通信データ量の削減:画像

9

1/8

Page 10: ブラウザでWebRTC - iOSゲートウェイ作ってみた

通信データ量の削減:音声

10

• サンプリング周波数はプラットフォーム依存(※ブラウザ依存ではない)– 44.1kHz (Mac)  ← こちらの例で計算– 48kHz (Windows, Linux, iOS)

• 圧縮– WebAudio 元データ… 44.1kHz × 32bit 実数 = 1411 kbps– 16bit リニア PCM 化 … 44.1kHz × 16bit 整数 = 705 kbps

• ※CD は 44.1kHz ×16bit × 2ch(Stereo) = 1411 kbps– サンプリング周波数を半分の 22 kHz に … 350 kbps– μ-law 圧縮 22kHz, 8bit 整数 … 175 kbps

• ※G.711 は 8kHz, 8bit 整数 … 64kbps– mp3 圧縮 … 36 kbps を指定

Page 11: ブラウザでWebRTC - iOSゲートウェイ作ってみた

11

1/40

通信データ量の削減:音声

Page 12: ブラウザでWebRTC - iOSゲートウェイ作ってみた

μ-law アルゴリズム• 音声圧縮アルゴリズム、非可逆• サンプル当たりのビット数を削減 … 今回は 8bit• IP 電話の G.711 規格で使われるアルゴリズム

– G.711 では、サンプリング周波数は 8kHz → 64kbps • Wikipedia

• https://ja.wikipedia.org/wiki/%CE%9C-law%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0

– 北アメリカと日本のデジタル通信システムで μ-law 使用 … PCMU

– ヨーロッパでは類似の A-law アルゴリズムを使用 … PCMA• WiFi では使えなくはないが、 LTE ではまだキツイ(圧縮不足)• 参考: WebAudio で原始的な音声圧縮をやってみた

– http://qiita.com/massie_g/items/49183a03b015b9ea27eb– ソース: https://github.com/mganeko/webrtcexpjp/blob/master/tool/mulow.html

12

Page 13: ブラウザでWebRTC - iOSゲートウェイ作ってみた

μ-law アルゴリズムでは対数を利用

13

リニア PCM :直線的な 8 段階 対数:小さい音は細かく、大きい音は粗く

Page 14: ブラウザでWebRTC - iOSゲートウェイ作ってみた

μ-law アルゴリズム

14

μ = 255 ( 8 ビット)

Page 15: ブラウザでWebRTC - iOSゲートウェイ作ってみた

WebRTC と PCMU/PCMA

15

[Firefox の SDP]

a=rtpmap:109 opus/48000/2a=rtpmap:9 G722/8000/1a=rtpmap:0 PCMU/8000a=rtpmap:8 PCMA/8000

[Chrome の SDP]

a=rtpmap:111 opus/48000/2a=rtcp-fb:111 transport-cca=fmtp:111 minptime=10;useinbandfec=1a=rtpmap:103 ISAC/16000a=rtpmap:104 ISAC/32000a=rtpmap:9 G722/8000a=rtpmap:0 PCMU/8000a=rtpmap:8 PCMA/8000a=rtpmap:106 CN/32000a=rtpmap:105 CN/16000a=rtpmap:13 CN/8000a=rtpmap:126 telephone-event/8000

Page 16: ブラウザでWebRTC - iOSゲートウェイ作ってみた

オマケ: G.722 • サンプリング周波数 16kHz 、 48, 56, 64kbps

• ADPCM (adaptive differential pulse code modulation)

• 圧縮のアルゴリズム(たぶんこんな感じ)– 前のサンプルとの差分

• 小さい値になりやすい– 差分を対数的に表現

• 小さい差分は細かく• 大きい差分はおおざっぱに

16

リニア PCM ADPCM

ケータイ Watch ケータイ用語の基礎知識よりhttp://k-tai.watch.impress.co.jp/cda/article/keyword/2936.html

Page 17: ブラウザでWebRTC - iOSゲートウェイ作ってみた

lamejs による MP3 圧縮• より音声データを圧縮するために MP3 を利用• lamejs

– https://github.com/zhuker/lamejs

• ストリーミングではなく、細切れの MP3 データを生成• 入力は 16bit 整数の配列

– チャネル(ステレオ /モノ)、サンプルレート を指定可能• 圧縮後は 8bit 整数の配列

– ビットレート (kbps) を指定可能– 下限あり:  22kHz の場合 >= 32kbps  、 24kHz の場合 >= 36kbpsぐらい

17

Page 18: ブラウザでWebRTC - iOSゲートウェイ作ってみた

Sample from GitHubvar channels = 1, sampleRate = 44100, kbps = 128; // mono, 44.1kHz, 128kbps

var mp3encoder = new lamejs.Mp3Encoder(channels, sampleRate, kbps);

var sampleBlockSize = 1152; // better to use  576 * n

var samples = new Int16Array(44100); // 1sec sample

var mp3Data = [];

for (var i = 0; i < samples.length; i += sampleBlockSize) {

sampleChunk = samples.subarray(i, i + sampleBlockSize);

var mp3buf = mp3encoder.encodeBuffer(sampleChunk);

if (mp3buf.length > 0) { mp3Data.push(mp3buf); }

}

var mp3buf = mp3encoder.flush(); //finish writing mp3

if (mp3buf.length > 0) { mp3Data.push(new Int8Array(mp3buf)); }18

Page 19: ブラウザでWebRTC - iOSゲートウェイ作ってみた

lamejs 利用にあたっての工夫• MP3 データのオーバーヘッドの抑制

– ヘッダ + タグ = 132byte

– 一度に変換する音声ブロックを、なるべく長く– WebAudio の ScriptProcessor の上限 (16384 サンプル / 回 ) で取得

• 370 ms (44.1kHz), 340 ms (48kHz)

19

ヘッダ 圧縮後データ MP3 タグ4byte 128byte1500~ 2000 byte

• 圧縮前のサンプルの半減:  44.1kHz→22.05kHz, 48kHz→24kHz に• ビットレート下限の調整

– 下限あり:  22kHz の場合 >= 32kbps  、 24kHz の場合 >= 36kbpsぐらい• WebWorker で圧縮 … 1 ブロックあたり 50ms ~ 100ms

Page 20: ブラウザでWebRTC - iOSゲートウェイ作ってみた

通信量の削減→安定して動作• 画像 … 56kbps

• 音声 … 36 kbps

20

トータル 92kbps

1/401/8

Page 21: ブラウザでWebRTC - iOSゲートウェイ作ってみた

ブラウザ MCU と iOS ゲートウェイの結合

21

ブラウザA

ブラウザB

ブラウザC

MCU

iOS Safari

画像 /2 秒ごと、 MP3 音声画像

参考: WebRTC Meetup Tokyo #11ブラウザで MCU 作ってみたBuild MCU on browserhttps://www.slideshare.net/mganeko/webrtc-build-mcu-on-browserhttps://speakerdeck.com/mganeko/build-webrtc-mcu-on-browser

ブラウザ

Page 22: ブラウザでWebRTC - iOSゲートウェイ作ってみた

DEMO

• PC Chrome ブラウザ MCU iOS Safari

• PC Chrome

22

Page 23: ブラウザでWebRTC - iOSゲートウェイ作ってみた

MCUサーバー役の仕組み:Video

23

RTCPeerConnection A

MediaStream<video> タグ

<canvas> タグ

drawImage()

requestAnimationFrame() で継続的に描画

<img> タグ drawImage()WorkerWebSocket(socket.io) DataURL

Blob JPEB

toBlob()Blob JPEB

from iOS

to iOS setInterval()

Page 24: ブラウザでWebRTC - iOSゲートウェイ作ってみた

MCU サーバー役の仕組み:Audio

24

RTCPeerConnection A

MediaStream

AudioContext .createMediaStreamSource()で生成

MediaStreamAudioSourceNode MediaStreamAudioSourceNode

MediaStreamAudioSourceNode

ScriptProcessor

合成(合算)

WorkerWebSocket(socket.io)

MP3[Uint8Array]

[Uint16Array]

[Flaoat32Array]

lamejs

to iOS

Page 25: ブラウザでWebRTC - iOSゲートウェイ作ってみた

MCU サーバー役の仕組み:録画も可能

25

MediaStream(Video A+B+C+D)

<canvas> タグ 配信用のものを利用

Web Audio API

MediaStream(Audio A+B+C)

録画用に改めて準備videoTracks[] MediaStreamTrack

MediaStreamTrackaidioTracks[]

MediaStream

新しく生成

MediaStream.addTrack()で追加

MediaStream.addTrack()で追加

MediaRecorder

WebM

Page 26: ブラウザでWebRTC - iOSゲートウェイ作ってみた

まとめ• iOS ブラウザで WebRTC が動かない… それがどうした!

– やりたいのは WebRTC ではなく、コミュニケーション• 今使えるもので、無理やりやってみよう!

– ブラウザの要素を自由に組み合わせられるのが「 Web 」 RTC

– Canvas, WebAudio, WebSocket

• なぜか音声コーデックの歴史をたどる旅に

26

Page 27: ブラウザでWebRTC - iOSゲートウェイ作ってみた

Thank you!

27