AudioNode.disconnect (), а затем .connect () не работает в Safari - PullRequest
0 голосов
/ 25 октября 2019

Я создал демонстрационный пример голосового помощника, который берет данные с микрофона, передает их в анализатор, а затем использует .getByteFrequencyData() для отображения визуальных изображений. Он работает следующим образом:

  1. Нажмите кнопку микрофона для подключения к входу микрофона
  2. Отпустите кнопку микрофона, чтобы отключить поток микрофона и воспроизвести MP3-ответ.
  3. Когда заканчивается MP3: вернитесь в режим ожидания и дождитесь нажатия новой кнопки, чтобы снова начать шаг 1.

Живая версия здесь: https://dyadstudios.com/playground/daysi/

Способ, которым я достиг этого, заключается в следующем:

var audioContext = (window.AudioContext) ? new AudioContext() : new window["webkitAudioContext"]();
var analyser = audioContext.createAnalyser();
analyser.fftSize = Math.pow(2, 9);  // 512
var sourceMic = undefined;  // Microphone stream source
var sourceMp3 = undefined;  // MP3 buffer source

// Browser requests mic access
window.navigator.mediaDevices.getUserMedia({audio: true}).then((stream) => {
    sourceMic = audioContext.createMediaStreamSource(stream)
})

// 1. Mic button pressed, start listening
listen() {
    audioContext.resume();

    // Connect mic to analyser
    if (sourceMic) {
        sourceMic.connect(analyser);
    }
}

// 2. Disconnect mic, play mp3
answer(mp3AudioBuffer) {
    if (sourceMic) {
        // Disconnect mic to prevent audio feedback
        sourceMic.disconnect();
    }

    // Play mp3
    sourceMp3 = audioContext.createBufferSource();
    sourceMp3.onended = mp3StreamEnded;
    sourceMp3.buffer = mp3AudioBuffer;
    sourceMp3.connect(analyser);
    sourceMp3.start(0);

    // Connect to speakers to hear MP3
    analyser.connect(audioContext.destination);
}

// 3. MP3 has ended
mp3StreamEnded() {
    sourceMp3.disconnect();

    // Disconnect speakers (prevents mic feedback)
    analyser.disconnect();
}

Он отлично работает на Firefox и Chrome, но OSX Safari 12.1 получает данные с микрофона только при первом нажатии кнопки. Каждый раз, когда я нажимаю кнопку микрофона на втором проходе, анализатор больше не получает данные с микрофона, но данные MP3 все еще работают. Кажется, что подключение, отключение и повторное подключение AudioNode микрофона к анализатору как-то ломает его. Я проверил, и Safari поддерживает AudioNode.connect(), а также AudioNode.disconnect(). Я знаю, что реализация WebAudio в Safari немного устарела, есть ли способ обойти эту проблему?

1 Ответ

1 голос
/ 29 октября 2019

В Safari действительно есть ошибка, из-за которой он отбрасывает сигнал, если MediaStreamAudioSourceNode отключается в течение некоторого времени. Вы можете избежать этого, просто не отключая его до тех пор, пока он вам может понадобиться снова. Вместо этого вы можете использовать GainNode для приглушения сигнала.

Вы можете сделать это, введя новую переменную для управления громкостью.

const sourceMicVolume = audioContext.createGain();

sourceMicVolume.gain.value = 0;

Затем вам нужно подключить все сразу, когда высоздание экземпляров sourceMic.

sourceMic = audioContext.createMediaStreamSource(stream);

sourceMic.connect(sourceMicVolume);
sourceMicVolume.connect(analyser);

Внутри ваших обработчиков событий вы бы тогда только устанавливали громкость усиления вместо (не) соединения узлов. Внутри функции listen() это будет выглядеть так:

if (sourceMic) {
    sourceMicVolume.gain.value = 1;
}

А внутри функции answer() это будет выглядеть так:

if (sourceMic) {
    sourceMicVolume.gain.value = 0;
}
...