困っている事
webAudioAPIを利用してマイク入力データを利用している中で
- 別タブに切り替えた時に、タブの録音中マークが消えない(PC)
- ホームボタンを押した時に画面上に赤い帯が残る(iOS)
環境
PC
- MacBook Pro 2016
- macOS Mojave 10.14.6
- Chrome 79.0.3945.88(Official Build) (64 ビット)
スマホ
- iPhone 6s
- iOS13.3
- safari
手順
- タブがアクティブじゃなくなった事を検知して
- マイクの入力トラックを解放する
タブがアクティブじゃなくなった事を検知
コード
function setEventListener() {
let hidden, visibilityChange;
if (typeof document.hidden !== "undefined") { // Opera 12.10 や Firefox 18 以降でサポート
hidden = "hidden";
visibilityChange = "visibilitychange";
} else if (typeof document.msHidden !== "undefined") {
hidden = "msHidden";
visibilityChange = "msvisibilitychange";
} else if (typeof document.webkitHidden !== "undefined") {
hidden = "webkitHidden";
visibilityChange = "webkitvisibilitychange";
}
document.hiddenStatus = hidden;
if (hidden === undefined) {
console.log("This demo requires a browser, such as Google Chrome or Firefox, that supports the Page Visibility API.");
} else {
document.addEventListener(visibilityChange, browserBlorFunction, {once: true});
}
}
async function browserBlurFunction() {
if (document.hidden) {
// 非表示状態になった時の動作
await stopRecording();
}
}
解説
この記事に全て書いてあります!
[iOS/Android]ブラウザでページが非表示になったことを検知する方法
今回はタブがアクティブではない時の体験を損なわない事を目的としていたので、
Page Visibility APIのみの利用をしています。
簡単に言うと、「ページが表示されているかどうか」を判定してくれるAPIです。
EventListenerに登録して利用可能です!
この機能によって追加されたプロパティであるdocument.hidden
で現在のブラウザの表示状態を取得できるので、
document.hidden === true
の時に、マイク入力解放関数を実行します。
ちなみに
同じような動作をさせたい時のグローバルイベントハンドラーとしてwindow.onblur
があります。
これはウィンドウの切り替えを意味するものでありページの表示を検知するものではありません。
そのためwindow.onblur
にマイク入力解放のコードをセットしても、
iPhoneでホームボタンを押した後は冒頭で紹介した赤い帯が出るし、
タブを切り替えてもブラウザの丸いマークは残ったままです。
マイクの入力を解放する
コード
//streamsには、mediaStreamそのものが入っています。
function stopRecording() {
let tracks = streams.getTracks();
tracks.forEach(function (track) {
track.stop();
});
}
//streamsへの格納
navigator.mediaDevices.getUserMedia({audio: true})
.then(mediaStream => {
gotStream(mediaStream);
}).catch(e => {
alert('Error getting audio');
});
}
let streams = null;
function gotStream(stream){
streams = stream;
//以下音声の処理...
}
解説
マイク入力はmediaDevices.getUserMediaより取得しており、その際に取得したmediaStreamTrackを停止させる事により、入力を解放します。
trackの停止
mediaStreamTrack.readyStateと言うプロパティの値が"ended"
になる時、入力デバイスからのデータを受け取らなくなります。
"ended"は入力デバイスがこれ以上データを提供することがなく、新しいデータも一切提供されないことを示します。
引用元:mediaStreamTrack.readyState
そのための関数として、
MediaStreamTrack.stop()
トラックに関連付けられたソースの再生を停止し、ソースとトラックの関連付けを解除します。トラックの状態はendedに設定されます。
こちらが用意されているので、それを使いましょう!
mediaStream.getTracks
function stopRecording() {
let tracks = streams.getTracks();
tracks.forEach(function (track) {
track.stop();
});
}
これでmediaStreamTrack.readyStateがendedになるため、記事冒頭で紹介した動作は起こらなくなります。
最後に
人生初Qiita記事書いてみました!
ちなみにsafariのアプリを完全に落とせば同じ事は達成できます()
今年は頑張ってアウトプットしていくぞぉ