javascript - 如何不点击切换 Web 音频源节点?
问题描述
我正在尝试为特定的 Web 应用程序编写一个小型音频库,以解决需要较长加载时间的 Web 音频缓冲区源的问题,我正在尝试使用缓冲区源切换 HTML5 音频源(通过 MediaElementSourceNode)一次缓冲源已准备好播放。对于 20 分钟的曲目,Web Audio 的 Buffer Source 大约需要 5 秒才能解码并开始播放。
在 Web 音频中使用 PanNode 需要使用 MediaElementSourceNode
首先,我认为这是一个 JS 主线程延迟问题,它正在抛出“开始时间”。我想我可以通过确保禁用 MediaElementSource 和启用 BufferSourceNode 的代码尽可能接近执行来解决。
然后,虽然它必须是 HTML 在启动时有一个小的延迟,导致记录的 startTime 关闭,但为了解决这个问题,我使用了一个事件处理程序来监听“播放”。
我四处搜索,发现 Gapless 5 显然没有问题,查看它的源代码,我无法发现它是如何无缝切换源的
play(offset) {
this.createNodes();
this.connectNodes();
//if webAudio's buffer source is not ready, starting playing with HTML5
if (!this.audioClip.isWebAudioReady() &&
this.audioClip.playType > 0) {
this.playHTML5();
}
//returns true if buffer != null
if (!this.audioClip.isWebAudioReady()) {
this.audioClip.addDecodeListener(this.play.bind(this));
}
if (this.audioClip.isWebAudioReady()) {
this.playBufferSource();
}
playHTML5() {
var context = AudioManager.context();
if (this.audioClip.isHTML5Ready()) {
this.createHTMLSourceNode();
console.log("playing HTML5");
this.mediaElementSourceNode.connect(this.gainNode);
this.mediaElementSourceNode.source.play();
this.startTime = context.currentTime;
}
else {
console.log('not ready yet');
this.audioClip.addLoadListener(this.playHTML5.bind(this));
}
}
playBufferSource() {
var context = AudioManager.context();
var offset = context.currentTime - this.startTime;
if (!this.bufferSourceNode) {
this.createBufferSourceNode();
}
this.bufferSourceNode.connect(this.gainNode);
//hoplessly attempt to make up for Thread latencey
offset = context.currentTime - this.startTime;
if (this.audioClip.playType > 0) {
this.mediaElementSourceNode.disconnect();
this.mediaElementSourceNode = null;
}
if (this.audioClip.playType == 0) {
offset = 0;
this.bufferSourceNode.start(0, offset);
}
else {
offset = context.currentTime - this.startTime;
this.bufferSourceNode.start(0, offset);
}
// console.log("starting web audio at" + offset);
}
createBufferSourceNode() {
var context = AudioManager.context();
if (!this.audioClip.webAudioReady) {
console.log('Web Audio not ready!, Sometihng went wrong!');
return;
}
var buffer = this.audioClip.buffer;
this.bufferSourceNode = context.createBufferSource();
//When using anything other than Buffer,
//we want to disable pitching.
if (this.audioClip.playType == NS.PlayTypes.Buffer) {
this.bufferSourceNode.playbackRate.setValueAtTime(this._pitch,
context.currentTime);
}
this.bufferSourceNode.buffer = buffer;
}
createHTMLSourceNode() {
var context = AudioManager.context();
var HTMLAudio = this.audioClip.mediaElement.cloneNode(false);
//HTMLAudio.addEventListener('ended', onHTML5Ended.bind(this), false);
HTMLAudio.addEventListener('play', this.onHTML5Play.bind(this), false);
var sourceNode = context.createMediaElementSource(HTMLAudio);
sourceNode.source = HTMLAudio;
this.mediaElementSourceNode = sourceNode;
}
/**
*
*/
onHTML5Play() {
this.startTime = AudioManager.context().currentTime;
console.log("HTML5 started playing");
}
由于我在尽可能靠近第一个源的时间启动第二个源,如果波形排列得足够近,从技术上讲,我应该听不到任何咔嗒声,但产生的咔嗒声非常可听,有时可以听到 2 次咔嗒声。
解决方案
推荐阅读
- c++ - for循环内的while循环
- django - Django 需要可选表单字段错误
- amp-html - 使用亚马逊和特定产品配置 amp-ad
- c# - 在网格 C# 中显示完整的日期
- ios - Uber API 编译错误
- python - Numpy:填充数组以向量化嵌套求和
- javascript - 如何使用 GTM 自定义 javascript 变量为单击事件上的按钮分配字符串值
- time-complexity - Fn = omega(2^cn) 的最大 c 是多少?
- android - 如何解决问题“二进制 XML 文件第 11 行:二进制 XML 文件第 11 行:膨胀类 com.evrencoskun.tableview.TableView 时出错”
- c++ - C++ Do/While 循环和 If/Else:骰子游戏——第 75 行错误:预期在“Cout”之前出现“While”——如何解决这个问题?