AudioNode.disconnect() 后跟 .connect() 在 Safari 中不起作用
AudioNode.disconnect() followed by .connect() not working in Safari
我构建了一个语音助手演示,它获取麦克风数据,将其传递给分析器,然后使用 .getByteFrequencyData()
显示视觉效果。它的工作原理如下:
- 按麦克风按钮连接到麦克风输入
- 释放麦克风按钮断开麦克风流,并播放响应的 MP3。
- 当MP3结束时:return进入待机状态,等待按下新的按钮再次开始步骤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()
as well as AudioNode.disconnect()
。我知道 Safari 的 WebAudio 实现有点过时,是否有解决此问题的解决方法?
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;
}
我构建了一个语音助手演示,它获取麦克风数据,将其传递给分析器,然后使用 .getByteFrequencyData()
显示视觉效果。它的工作原理如下:
- 按麦克风按钮连接到麦克风输入
- 释放麦克风按钮断开麦克风流,并播放响应的 MP3。
- 当MP3结束时:return进入待机状态,等待按下新的按钮再次开始步骤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()
as well as AudioNode.disconnect()
。我知道 Safari 的 WebAudio 实现有点过时,是否有解决此问题的解决方法?
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;
}