入社面接の LT で使った Media Capture and Streams と Web Audio API を連動させたデモが動かなくなってたので調整してみた。その時に必要になった GitHub を複数アカウントで利用する方法をメモっとく。
だいぶ前に作ったやつ
Web Audio API のアプリにありがちなリズムマシンに、Media Capture and Streams で録音機能をつけてボイスパーカッションみたいにもできるやつ。
- 修正前(ちゃんと動かない)
- 修正後
Media Capture and Streams まわりの仕様変更
デモを作った1年半前は問題なく動作してたけど以下の仕様が変わったようで動かなくなってた(Chromeで確認)。
- MediaStream.stop() が廃止になった(参考)
- Media Capture and Streams まわりが https でないと動作しない(localhostの場合は大丈夫)
以前書いた記事(Media Capture and Streams と Web Audio API で実現する録画・録音・ WAVファイルの生成 | CYOKODOG)のデモもほとんど動かなくなってた。(iframe使って動くようにしないと...)
複数アカウントで GitHub を使用する
gh-pages で https は以下がチェックオンになってれば使えるんだけど、gh-pages に www.cyokodog.net の独自ドメインを割り当ててるので http になってしまう。 なので GitHub に別アカウント作ってそっちの gh-pages を利用する。
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>