IOS11のSafariで動作するマイクからオーディオキャプチャを取得しようとしています サポートが最近追加された後
ただし、onaudioprocess
コールバックは呼び出されません。以下にサンプルページを示します。
<html>
<body>
<button onclick="doIt()">DoIt</button>
<ul id="logMessages">
</ul>
<script>
function debug(msg) {
if (typeof msg !== 'undefined') {
var logList = document.getElementById('logMessages');
var newLogItem = document.createElement('li');
if (typeof msg === 'function') {
msg = Function.prototype.toString(msg);
} else if (typeof msg !== 'string') {
msg = JSON.stringify(msg);
}
var newLogText = document.createTextNode(msg);
newLogItem.appendChild(newLogText);
logList.appendChild(newLogItem);
}
}
function doIt() {
var handleSuccess = function (stream) {
var context = new AudioContext();
var input = context.createMediaStreamSource(stream)
var processor = context.createScriptProcessor(1024, 1, 1);
input.connect(processor);
processor.connect(context.destination);
processor.onaudioprocess = function (e) {
// Do something with the data, i.e Convert this to WAV
debug(e.inputBuffer);
};
};
navigator.mediaDevices.getUserMedia({audio: true, video: false})
.then(handleSuccess);
}
</script>
</body>
</html>
ほとんどのプラットフォームでは、onaudioprocess
コールバックが呼び出されると、メッセージリストにアイテムが追加されます。ただし、iOSでは、このコールバックは呼び出されません。
Safariを使用してiOS 11で呼び出そうとするために、他にすべきことはありますか?
2つの問題があります。主なものは、iOS 11のSafariは、タップに応じて作成されない新しいAudioContext
を自動的に一時停止するように見えることです。 resume()
できますが、タップに対する応答のみです。
(更新:Chromeモバイルもこれを行い、Chromeデスクトップはバージョン70/2018年12月から同じ制限があります。)
したがって、MediaStream
を取得する前に作成するか、後でユーザーに再度タップさせる必要があります。
コードのもう1つの問題は、SafariでAudioContext
の先頭にwebkitAudioContext
が付いていることです。
作業バージョンは次のとおりです。
<html>
<body>
<button onclick="beginAudioCapture()">Begin Audio Capture</button>
<script>
function beginAudioCapture() {
var AudioContext = window.AudioContext || window.webkitAudioContext;
var context = new AudioContext();
var processor = context.createScriptProcessor(1024, 1, 1);
processor.connect(context.destination);
var handleSuccess = function (stream) {
var input = context.createMediaStreamSource(stream);
input.connect(processor);
var recievedAudio = false;
processor.onaudioprocess = function (e) {
// This will be called multiple times per second.
// The audio data will be in e.inputBuffer
if (!recievedAudio) {
recievedAudio = true;
console.log('got audio', e);
}
};
};
navigator.mediaDevices.getUserMedia({audio: true, video: false})
.then(handleSuccess);
}
</script>
</body>
</html>
(onaudioprocess
コールバックをより早く設定できますが、ユーザーがマイクへのアクセスを承認するまで空のバッファーを取得します。)
気をつけるべきもう1つのiOSバグ:iPod touchのSafari(iOS 12.1.1の時点)では、マイクがないと報告されます(あります)。したがって、そこにオーディオを要求すると、getUserMediaはError: Invalid constraint
で拒否します。
参考までに、これを行うnpmの microphone-stream パッケージを維持し、Node.jsスタイルのReadableStreamで音声を提供します。あなたまたは他の誰かが生のコードよりもそれを使用したい場合は、この修正で更新しました。
IOS 11.0.1で試してみましたが、残念ながらこの問題はまだ修正されていません。
回避策として、ScriptProcessorをビュッフェからSteamデータを取得し、xミリ秒ごとに処理する関数に置き換えることは理にかなっているのだろうか。しかし、それは機能の大きな変化です。