有線接続したAndroid端末をWebカメラ的に使う（ブラウザ上での映像表示）

## イントロ
こちらは、[WebRTC Advent Calendar 2014](http://qiita.com/advent-calendar/2014/webrtc)の21日目のエントリーです。

# 実現すること

![構成図.png](https://qiita-image-store.s3.amazonaws.com/0/50868/db5ce547-b679-8f5b-88eb-72585ea4b640.png)


PC に USB で有線接続された Android端末を用い、その Android端末のカメラ映像を PC のブラウザ上に表示させる、というものを実現します。PC に USB接続された Android端末を、Webカメラ的に使うイメージです。

このようなことをやろうとした経緯は「[以前の投稿（Android端末をプレゼン用途でWebカメラ的に使おうとした話【設計編】）](http://qiita.com/youtoy/items/419b44b06ac95c7c1429)」をご覧ください。


# 実装や設定の概要

上記の内容を実現する方法は、おおまかにはこのようになります。
 ※ PC でも Android端末上でも、Chrome を利用

- 概要
  1. getUserMedia を使い、カメラ映像をブラウザ上に表示するページを実装＠ローカルPC。
  2. Android端末の USBデバッグを有効にし、PC と USB で接続された状態にする。
  3. 手順2の内容を「localhost:8080」などといった形で、ローカルPC上で参照できるよう、PC側でサーバ立ち上げ。
  4. Android側と PC側の両方で Chrome を起動し、PC側の Chrome からリモートデバッグ。  
   その際、Android からローカルPCのサーバを参照できるよう、Port forwarding を設定。
  5. PC側の Chrome のインスペクタで、Android上の Chrome の表示内容を、PC側で表示。


# 実装や設定の詳細

# 手順1：カメラ映像をブラウザ上に表示

getUserMedia を使ったカメラ映像取得・取得した映像のブラウザ上への表示、を実装します。
Javascript の部分は下記のように、だいたいはよくある感じの実装です（ htmlファイルには、「id を video とした videoタグ」を配置しています ）。

```js

navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
window.URL = window.URL || window.webkitURL;

if (navigator.getUserMedia) {
  navigator.getUserMedia (
    {
      video: true,
      audio: true
    },
    function(localMediaStream) {
      var video = document.querySelector('video');
      video.src = window.URL.createObjectURL(localMediaStream);
    },
    function(err) {
      console.log("エラー: " + err);
    }
  );
} else {
  alert('getUserMediaがサポートされていません');
}

```

ただし、この実装だと、この後に行う「Android端末の Chrome上で、Android端末のカメラ映像を取得する」という部分で、フロントカメラの映像が取得されてしまい、Webカメラ的に利用するのには不便です。

そこで、バックカメラを利用できるよう以下のような処理に変更します。以下は、Chrome for Android のバックカメラを指定する処理になっています。 
＃ Firefox だとフロントカメラ／バックカメラの選択が、カメラの利用許可の選択時に行えるのですが・・・

- 参考：  
[MediaStreamTrack.getSources()](https://simpl.info/getusermedia/sources/)

```js

navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
window.URL = window.URL || window.webkitURL;


if (navigator.getUserMedia) {
  var selectCam = null;

  if (typeof MediaStreamTrack === 'undefined'){
    alert('MediaStreamTrackがサポートされていません');
  } else {
    MediaStreamTrack.getSources(function(data) {
      for (var i = 0; i != data.length; ++i) {
        if ((data[i].kind === 'video')&&(data[i].facing === 'environment')) {
          selectCam = data[i].id;
        }
      }
        
      navigator.getUserMedia (
      {
        video: {
        optional: [{sourceId: selectCam}]
      },
        audio: true
      },
      function(localMediaStream) {
        var video = document.querySelector('video');
        video.src = window.URL.createObjectURL(localMediaStream);
      },
      function(err) {
        console.log("エラー: " + err);
      });
    });
  }
} else {
  alert('getUserMediaがサポートされていません');
}

```

## 手順2〜4：Android端末の Chrome上で、USB接続されているローカルPCの htmlファイルを表示

ここで、Android の Chrome（※ Android 4.0以上 ＋ Chrome for Android ）の、リモートデバッグ機能を利用します。

- 参考：  
[Remote Debugging on Android with Chrome - Google Chrome](https://developer.chrome.com/devtools/docs/remote-debugging)

そのために、まずは Android端末の設定で USBデバッグを有効にしておき、Android端末と PC を USB接続します。

### PC上でのサーバ立ち上げ

ローカルPC上の html を「localhost:8080」などといった形で参照できるよう、PC側でサーバ立ち上げます。
いくつか方法はありますが、今回は Python を使った簡易サーバの起動を行いました。
ターミナル／コマンドプロンプト上で htmlファイルなどがあるフォルダへ移動し、「 python -m SimpleHTTPServer 8080 」を実行します。

PC上のブラウザから「localhost:8080」にアクセスし、先ほど準備した htmlファイルが表示できることを確認してみてください。

### リモートデバッグの設定

その後、Android側 と PC側とで、それぞれ Chrome を起動します。
PC側の Chrome で、以下の画像にあるとおり「デバイスを検証」を選択します。

「![Chromeでデバイスを検証の選択.jpg](https://qiita-image-store.s3.amazonaws.com/0/50868/44ccef96-d8c1-afb8-12ab-7717a719c1c1.jpeg)」  

「デバイスを検証」の選択をした後の画面で、「Discover USB devices」にチェックを入れます。
そうすると、以下の画像にあるとおり、接続した端末の名前と（以下の例では Nexus 5）、Android の Chrome で開いているタブの一覧が表示されます。

![USBデバイスの検出.jpg](https://qiita-image-store.s3.amazonaws.com/0/50868/33cdcf4d-1d16-cda7-50dc-482caec0d63e.jpeg)

これで、PC上の Chrome から、Android上の Chrome で開いている Webページの内容などを見ることができるようになりました。

### ポートフォワーディングとスクリーンキャスト

しかし、これだけだと、Android上の Chrome から、ローカルPCに立ち上げたサーバを有線経由で参照できません。そのために Port forwarding を設定します。

上記の画像で、「Discover USB devices」の右側にある「Port forwarding...」を選択します。
その後の画面で、以下の画像の赤枠内のとおりに設定します。

![ポートフォワーディング.jpg](https://qiita-image-store.s3.amazonaws.com/0/50868/506f8579-53d9-62eb-aca7-a61c0036e8ce.jpeg)

そして、画像中の矢印で示した「Enable port forwarding」にチェックを入れ、その右のボタン「Done」を押して下さい。

そうすると、Android上の Chrome で「 localhost:8080 」にアクセスすると、PC側でローカルで立ち上げたサーバにアクセスできます。
そして、Android上の Chrome で開いているタブの一覧が見えている以下の画像の画面（PC上の Chrome で表示させた画面）で、赤矢印で示した「inspect」を選択します。

![インスペクタの選択.jpg](https://qiita-image-store.s3.amazonaws.com/0/50868/f22455d7-af19-eecb-5b08-3258595953e2.jpeg)

そうすると、以下のようなデバッグ用のウィンドウが表示されます。
以下の画像の青で塗りつぶした部分に、Android上の Chrome で表示した Webページが表示されていると思います。もし、その部分が表示されてないようでしたら、画像の赤矢印で示した部分を押して「screencast」を有効にしてください。

![インスペクタ表示後.jpg](https://qiita-image-store.s3.amazonaws.com/0/50868/142c57bf-c6c4-bb37-04be-9b6df556f180.jpeg)

これで、今回やろうとしていた内容が実現できました。