web-dev-qa-db-ja.com

ios11でonaudioprocessが呼び出されない

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で呼び出そうとするために、他にすべきことはありますか?

20
John Farrelly

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で音声を提供します。あなたまたは他の誰かが生のコードよりもそれを使用したい場合は、この修正で更新しました。

24
Nathan Friedly

IOS 11.0.1で試してみましたが、残念ながらこの問題はまだ修正されていません。

回避策として、ScriptProcessorをビュッフェからSteamデータを取得し、xミリ秒ごとに処理する関数に置き換えることは理にかなっているのだろうか。しかし、それは機能の大きな変化です。

4
Daniel Wu

ただ疑問に思う...あなたはSafariの設定で有効になっている設定を持っていますか? iOS11ではデフォルトで有効になっていますが、気付かずに無効にしただけかもしれません。

enter image description here

2
damianmr