Media Capture and Streams と MediaRecorder のその後と GitHubの複数アカウント利用方法メモ

入社面接の LT で使った Media Capture and Streams と Web Audio API を連動させたデモが動かなくなってたので調整してみた。その時に必要になった GitHub を複数アカウントで利用する方法をメモっとく。

だいぶ前に作ったやつ

Web Audio API のアプリにありがちなリズムマシンに、Media Capture and Streams で録音機能をつけてボイスパーカッションみたいにもできるやつ。

Media Capture and Streams まわりの仕様変更

デモを作った1年半前は問題なく動作してたけど以下の仕様が変わったようで動かなくなってた(Chromeで確認)。

  • MediaStream.stop() が廃止になった(参考

Mdeia Capture and Streams error

  • Media Capture and Streams まわりが https でないと動作しない(localhostの場合は大丈夫)

Mdeia Capture and Streams error

以前書いた記事(Media Capture and Streams と Web Audio API で実現する録画・録音・ WAVファイルの生成 | CYOKODOG)のデモもほとんど動かなくなってた。(iframe使って動くようにしないと...)

複数アカウントで GitHub を使用する

gh-pages で https は以下がチェックオンになってれば使えるんだけど、gh-pages に www.cyokodog.net の独自ドメインを割り当ててるので http になってしまう。 なので GitHub に別アカウント作ってそっちの gh-pages を利用する。

github https

ssh-keygen でサブアカウント用の SSH認証キー(id_rsa.subaccont、id_rsa.subaccont.pub)を作る。-f でファイル名を指定できる。

ssh-keygen -t rsa -f id_rsa.subname

~/.ssh/config にサブアカウントの SSH認証キーとホストの紐付けを追記する。

Host github
  HostName github.com
  IdentityFile ~/.ssh/id_rsa
  User git
Host subname.github.com
  HostName github.com
  IdentityFile ~/.ssh/id_rsa.subname
  User git

最後に公開鍵を GitHub に設定して、git clone や git remote add する時にホスト名を以下のように github.com を subname.github.com に変えれば利用できる。

git clone git@subname.github.com:subname/hoge.git 

Media Capture and Streams の停止処理

Media Capture and Streams のストリーム取得と停止処理ロジックはこんなかんじ。

var stream;
function startRec(){
  navigator.getUserMedia(
    {
        video: false,
        audio: true
    },
    function(s){
        stream = s;
        ...
    }
  );
}
function stopRec(){
  if(stream){
    stream.stop();
    stream = null;
  }
}

で、上記の stream.stop() が使えなくなってしまったので、以下のように修正すればオーケー。

stream.getAudioTracks()[0].stop();

ちなみに Firefox の場合は、MediaStream.stop() も利用可能(v47.0では)。

Chrome で MediaRecorder が使えるようになってた

MediaRecorder は Media Capture and Streams と連動されることで、手軽に録音処理ができる便利なやつなんだけど、以前は Firefox でしか動かなかった。 で、Chrome でも Firefox でも録音できるようにするには Web Audio API と連動される必要があって結構めんどくさい感じだった。詳しくは以下。

Firefox で録音してその音声ファイルをダウンロードするには以下のようなロジックで実現できたけど、Chrome だとこのままではうまく動作しない・・・

code

html
<h1>MediaRecorder Demo for Firefox</h1>
<button class="rec">REC</button>
<a class="download"></a>
<audio class="audio"></audio>
script
navigator.getUserMedia =
    navigator.getUserMedia ||
    navigator.webkitGetUserMedia ||
    navigator.mozGetUserMedia ||
    navigator.msGetUserMedia;
window.URL =
    window.URL ||
    window.webkitURL ||
    window.mozURL ||
    window.msURL;
var stream;
var recorder;
var recControl = function(){
    if(typeof MediaRecorder == 'undefined') return;
    if(!stream){
        el.rec.textContent = 'STOP';
        navigator.getUserMedia(
            {
                video: false,
                audio: true
            },
            function(s){
                stream = s;
                recorder = new MediaRecorder(stream);
                recorder.start();

                //Firefoxの場合、recorder.stop()されるとこれが動く
                recorder.ondataavailable = function(event) {
                    var blob = event.data;
                    var url = el.audio.src = URL.createObjectURL(blob);
                    el.audio.play();
                    //download link
                    el.download.href = url;
                    el.download.textContent = 'download'
                    el.download.download = 'output.wav';
                };
            },
            function(err){
                console.log(err.name ? err.name : err);
            }
        );
    }
    else{
        el.rec.textContent = 'REC';
        recorder.stop();
        stream.getAudioTracks()[0].stop();
        stream = undefined;
    }
}
var el = {
    audio : $DEMO[0].querySelector('.audio'),
    rec : $DEMO[0].querySelector('.rec'),
    download: $DEMO[0].querySelector('.download')
}
el.rec.addEventListener('click', recControl, false);

demo

html
<iframe style="height:250px" src="https://cyokosaturn.github.io/cyokodog_net_demo/media_recorder/demo01_for_firefox.html"></iframe>

Chrome の場合挙動が異なる

Firefox では、MediaRecorder.stop() すると MediaRecorder.ondataavailable() が動いて、その中で音声データが取得できるという流れだったんだけど、Chrome の場合は、MediaRecorder.start() してストリームが流れだすと同時に MediaRecorder.ondataavailable() も動き出してしまう模様。 なので Chrome の場合は、MediaRecorder.ondataavailable() 内で音声データをバッファして、MediaRecorder.stop() 直後にバッファデータから blob データを生成する必要がある。

code

script
var recordedChunks = [];
var stream;
var recorder;
var recControl = function(){
    if(typeof MediaRecorder == 'undefined') return;
    if(!stream){
        el.rec.textContent = 'STOP';
        navigator.getUserMedia(
            {
                video: false,
                audio: true
            },
            function(s){
                stream = s;
                recorder = new MediaRecorder(stream);
                recorder.start();

                //Chromeの場合、recorder.start()されるとこれが動く
                recorder.ondataavailable = function(event) {
                    if (event.data.size > 0) {
                      recordedChunks.push(event.data);
                    }
                };
            },
            function(err){
                console.log(err.name ? err.name : err);
            }
        );
    }
    else{
        el.rec.textContent = 'REC';
        recorder.stop();
        stream.getAudioTracks()[0].stop();
        stream = undefined;

        // 録音停止したらバッファした音声データをBlob変換する 
        var superBuffer = new Blob(recordedChunks);
        var url = el.audio.src = URL.createObjectURL(superBuffer);
        el.audio.play();

        //download link
        el.download.href = url;
        el.download.textContent = 'download'
        el.download.download = 'output.wav';
    }
}
var el = {
    audio : document.querySelector('.audio'),
    rec : document.querySelector('.rec'),
    download: document.querySelector('.download')
}
el.rec.addEventListener('click', recControl, false);

demo

html
<iframe style="height:250px" src="https://cyokosaturn.github.io/cyokodog_net_demo/media_recorder/demo01_for_chrome.html"></iframe>