WebRTC
JavaScriptからWebカメラを扱う
WebRTCとは,簡単に言えば,端末のメディアデバイス(カメラやマイク)をWebブラウザのJavaScriptから扱うための規格である.Safari&iOSは11から対応している.
Videoに関しては,ChromeとSafari,つまりAndroidとiOSで書法というか扱い方の詳細に違いがあるので,クライアントのWebブラウザをを検出して,分岐させて両方書いておく必要がある.
セキュアHTTP(https://での接続)
WebRTCを使うためには,https://
で始まるセキュアHTTPで接続する必要がある.
コード例
どのブラウザでアクセスしているかの文字列UserAgent
を最初に取得し,iOSデバイス,Androidデバイス,PCのChrome, MacのSafariをそれぞれ切り分けて分岐処理を行う.
iOSとAndroidはスマホ本体を縦にして撮影している,つまりカメラから取得できる画像が縦長(3:4)であると想定し,PCのChromeとSafariは横長(4:3)であると想定する.
なお,ボタンをスマホブラウザから押しやすくするために,skeletonという軽量CSSフレームワークを利用している.
<!DOCTYPE html>
<!-- WSCameraImage_drawToVideoArea.html -->
<html lang="ja">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta charset="utf-8" />
<title>スマホやPCのカメラをWebブラウザから使う</title>
<script type="text/javascript" src="./WSCameraImage_drawToVideoArea.js">
</script>
<!-- skeltonフレームワークを使う -->
<link rel="stylesheet" href="./style/normalize.css" />
<link rel="stylesheet" href="./style/skeleton.css" />
</head>
<body>
<div id="display_user_agent">
</div>
<div>
<!-- skeltonフレームワークを使った押しやすいボタン.クラスを指定するだけ -->
<button class="button button=primary" onclick="startVideo()">Start</button><br/>
<!-- ビデオ表示エリア -->
<video id="local_video" autoplay playsinline></video>
</div>
</body>
</html>
// WSCameraImage_drawToCanvas.js
'use strict';
function startVideo() {
if(navigator.getUserMedia || navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia || navigator.msGetUserMedia){
if(window.thisBrowser == 'ios'){
// for iOS Devices
// スマホを立てて撮影を想定
const medias = {audio: false,
video: {width: 480,
height: 640,
facingMode : {exact: "environment"}}};
// facingModeというのは,背面カメラと顔カメラのどちらを使うか
// 'environment'を指定すると背面カメラ,
// 'user'を指定すると顔カメラになる
navigator.getUserMedia(medias,
(stream) => {
window.localVideo.srcObject = stream;
},
(error) => {
alert('navigator.getUserMedia() error:' + error);
});
}
else if(window.thisBrowser == 'android'){
// for Android Chrome (with both Front and Back Camera)
// iOSと同じくスマホを立てて撮影しているのを想定
const medias = {audio: false,
video: {width: 480,
wheight: 640,
facingMode:{exact: "environment"}}};
navigator.mediaDevices.getUserMedia(medias) // ChromeはPCもAndroidもPromiseで記述する
.then(stream => {
window.localVideo.src = window.URL.createObjectURL(stream);
})
.catch(error => {
console.error('navigator.mediaDvice.getUserMedia() error:', error);
return;
});
}
else if(window.thisBrowser == 'pcchrome'){
// PC Chrome (with only 1 Camera for Face)
const medias = {audio: false,
video: {width: 640,
wheight: 480}};
navigator.mediaDevices.getUserMedia(medias)
.then(stream => {
window.localVideo.src = window.URL.createObjectURL(stream);
})
.catch(error => {
console.error('navigator.mediaDvice.getUserMedia() error:', error);
return;
});
}
else if(window.thisBrowser == 'pcsafari'){
// for Mac Safari (with only 1 Camera for Face)
const medias = {audio: false,
video: {width:640,
height:480}};
navigator.getUserMedia(medias,
(stream) => {
window.localVideo.srcObject = stream;
},
(error) => {
console.error('navigator.getUserMedia() error:', error);
});
}
}
}
window.addEventListener('load', () => {
// ブラウザ情報が入っているUserAgenetを取得し,全部小文字の文字列にする
window.userAgentInLowerCase = window.navigator.userAgent.toLowerCase();
// UserAgentを表示
document.getElementById("display_user_agent").innerHTML =
window.userAgentInLowerCase;
// 各ブラウザで切り分ける
if(userAgentInLowerCase.indexOf('iphone') != -1 ||
userAgentInLowerCase.indexOf('ipad') != -1)
window.thisBrowser = 'ios';
if(userAgentInLowerCase.indexOf('android') != -1)
window.thisBrowser = 'android';
else if(userAgentInLowerCase.indexOf('chrome') != -1)
window.thisBrowser = 'pcchrome';
else if(userAgentInLowerCase.indexOf('safari') != -1)
window.thisBrowser = 'pcsafari';
else
alert('Cannot use this program for your browser');
window.localVideo = document.getElementById('local_video');
}, false);
window.addEventListener('unload', () => {
}, false);
DataURL形式
WebSocketで送るために画像を文字列にする
DataURL
とは,画像や音などのメディアを,WebSocketのメッセージとして送ることができるような形式,すなわちテキスト情報にエンコードしたものである.
WebRTCから得られたビデオストリームをそのままDataURLにはできない(単に対応していないという問題だけではなく,縦横サイズを統一するために整えたりする必要がある)ので,video
タグの内容をgetImageData()
関数で,クロップ(切り抜き)&縮小しながら取得し,そこで得られたImageData
オブジェクトが持つtoDatURL()
関数を実行してDataURL形式に変換して取り出す.
受け取り側で復号する
DataURL形式は文字列なので,サーバ側ではこれまでのWebSocketメッセージと同じように扱うが,それを再度受け取ったクライアント側ではデコードする必要がある.この時のヘッダをsplit
する文字列に注意する.
セキュアWebSocket(wss://での接続)とTornadoサーバ側の準備
WebRTCを使う場合,必ずhttps://
で接続する必要があると前述したが,その結果WebSocketもセキュアWebSocket(wss://)である必要がある.