我正在开发一个Elecron应用程序(JavaScript)来实现音频可视化。有一个Playlist()
示例,它接收用户想要播放的音频文件路径。当第一个音频播放完后,它会播放下一个。到目前为止一切都很好。这个应用程序进行了大量的计算工作,从每个通道提取音频特征,重新渲染画布和动画情节。它做得很漂亮。
问题是:每次应用播放下一个文件时,速度就越慢,就好像之前的所有音频数据都还在某个地方一样。我在文档中找到了AudioContext()
中的close()
方法:
AudioContext接口的close()方法关闭音频上下文,释放它使用的任何系统音频资源。
AudioContext现在可以显式关闭,从而释放与AudioContext相关得所有硬件资源.如果没有此功能,开发人员必须依靠AudioContext得垃圾回收来释放硬件资源.
我还发现了关闭和重新启动音频上下文的示例:
https://github.com/mdn/webaudio-examples/blob/master/audiocontext-states/index.html
https://mdn.github.io/webaudio-examples/audiocontext-states/
问题是我使用的是audioContext.createMediaElementSource(HTMLelementID)
,它不允许我像示例中那样重新启动所有节点。代表我之前所做操作的简化代码是:
class Audio() {
constructor(audioElementID, playlistObj) {
this.audioContext = new AudioContext();
this.audioElement = document.getElementById(audioElementID);
this.track = this.audioContext.createMediaElementSource(this.audioElement);
this.gainNode = this.audioContext.createGain();
this.track.connect(this.gainNode);
this.gainNode.connect(this.audioContext.destination);
this.audioElement.addEventListener('ended', () => {
playlistObj.playnextTrack() // changes the src from the html element (audioElementID) and sets this.audioElement.currentTime to 0
}
}
// everything is a property here for debugging reasons
}
const audio = new Audio('audioID', playlist);
// playlist defined somewhere else
为了实现close()
方法,我必须更改(与示例完全相同,一个重新创建所有内容的函数):
class Audio() {
constructor(audioElementID, playlistObj) {
this.createAudioContext = () => {
this.audioContext = new AudioContext();
this.audioElement = document.getElementById(audioElementID);
this.track = this.audioContext.createMediaElementSource(this.audioElement);
this.gainNode = this.audioContext.createGain();
this.track.connect(this.gainNode);
this.gainNode.connect(this.audioContext.destination);
this.audioElement.addEventListener('ended', () => {
playlistObj.playNextTrack() // changes the src from the html element (audioElementID) and sets this.audioElement.currentTime to 0
}
}
this.createAudioContext();
}
}
在playlist.playNextTrack()
中,我暂停audioElement,调用audio.audioContext.close()
,等待它(这是一个承诺),调用audio.createAudioContext()
重新创建所有内容并播放。
“无法在'BaseAudioContext'上执行'createMediaElementSource':HTMLMediaElement先前已连接到位于音频的其他MediaElementSourceNode。createAudioContext”
在本示例中,音频源只是随机振荡器,而不是mp3音频文件。
我真的被困在这里了。不知道该怎么办。我甚至不确定AudioContext()
是否真的在导致这个性能问题之前保存了所有音频文件的数据。如果是这样的话,如何将HTMLMediaElement
重新连接到audio.createAudioContext()
创建的新节点?我已经尝试了audio.track.disconnect()
,但它不起作用(因为这里我把track
和gainNode
断开了连接,所以不应该这样做)。而且audioElement
没有disconnect()
方法,因为它只是一个html元素。
你知道吗?
最新消息:
我忽略了重新创建音频上下文的问题,删除并重新创建html元素。但问题仍然存在:播放的新音频文件越多,应用程序的运行速度就越慢。现在更准确地说:创建的新AudioContext()越多,速度就越慢(即使我关闭了前一个)。
1条答案
按热度按时间vnjpjtjt1#
我真的被困在这里了。不知道该怎么办。我甚至不确定AudioContext()是否真的在导致这个性能问题之前保存了所有音频文件的数据。
不,这不太可能。AudioContext设置了采样率、输出目标和图形等内容。仅此而已。
AudioContext接口的close()方法关闭音频上下文,释放它使用的任何系统音频资源。
您误解了这一点的含义。那些“系统音频资源”是声音设备。当AudioContext运行时,会请求一个音频设备。这在低功率环境中特别有意义,如移动的设备。另一个例子是蓝牙。如果AudioContext保持运行,您的蓝牙耳机可能会保持打开状态。如果允许关闭AudioContext,则蓝牙耳机可以进入睡眠。
如果是这样,我如何将HTMLMediaElement重新连接到audio.createAudioContext()创建的新节点?
你不需要。如果API支持这一点就好了,但似乎没有。只需创建一个新的HTMLMediaElement。
你应该做的是正确地分析你的应用程序,找出速度变慢的地方。使用你的开发人员工具。虽然只是开始注解掉正在运行的部分可能会更快。我们当然不能告诉你问题在哪里,特别是从你所显示的代码。