我一直在尝试使用createMediaElementSource将音频元素连接到web音频api并让它工作但我需要做的一件事是改变音频标签的播放速率,我无法让它工作.
如果您尝试运行下面的代码,您将看到它一直有效,直到您取消注释我们设置播放速率的行.当这一行在音频中被静音.
我知道我可以使用source.playbackRate.value在AudioBufferSourceNode上设置播放速率,但这不是我想要做的,我需要在使用createMediaElementSource连接到web音频api时设置音频元素的播放速率所以我没有任何AudioBufferSourceNode.
有人设法做到了吗?
var _source,
_audio,
_context,
_gainNode;
_context = new webkitAudioContext();
function play(url) {
if (_audio) {
_audio.pause();
}
_audio = new Audio(url);
//_audio.playbackRate = 0.6;
setTimeout(function() {
if (!_gainNode) {
_gainNode = _context.createGainNode();
_gainNode.gain.value = 0.1;
_gainNode.connect(_context.destination);
}
_source = _context.createMediaElementSource(_audio);
_source.connect(_gainNode);
_audio.play();
}, 0);
}
play("http://geo-samples.beatport.com/items/volumes/volume2/items/3000000/200000/40000/9000/400/60/3249465.LOFI.mp3");
setTimeout(function () {
_audio.pause();
}, 4000);
Run Code Online (Sandbox Code Playgroud) 我使用Web Audio API编写了一个简单的Web应用程序,但我注意到当我noteOn(0)向给定的源发出命令,然后是a noteOff(0),然后最后通过另一个noteOn(0)命令时,声音将打开,关闭(如预期的那样) )但是然后不会打开第三个命令.
有什么我做错了吗?就这么简单,我可以向你展示代码,但我觉得它是多余的.也许我需要在缓冲区之后重新分配缓冲区noteOff,但是我无法想象它是如何被使用的.
我对ScriptProcessorNode的onaudioprocess特别感兴趣(直到最近才称为JavaScriptNode).它是一个事件监听器,定期调用它进行音频处理.它是在单独的线程中运行的吗?
我想将数据提供给循环缓冲区并在此回调之外处理它,这样我就不会占用CPU了.我可以使用Web worker进行异步处理,但是AFAIK在不同线程的情况下我需要不同的环形缓冲区实现.
有没有办法测试这个?
我一直在玩Web Audio API并使用笔记本电脑的麦克风作为输入源.当我听到输入时,我可以听到很多白噪声; 如何创建滤镜以降低噪音,使声音更清晰?是否有任何库为这种情况提供预先编写的噪声滤波器?
每次解码音频文件时,Chrome选项卡的内存使用量都会增加约100 MB(对于典型大小的MP3文件).
OfflineAudioContext.decodeAudioData相反,行为有很大不同:它在解码文件后释放内存.
为什么"在线"会AudioContext保留所有这些内存?
我正在尝试实现可以在任何给定时刻重新启动的音量包络,即使它已经处于参数运动的中间但我无法弄清楚如何在没有点击结果音频的情况下这样做(这似乎是关于它们何时发生,有些不规则).
这甚至可能吗?我看到AudioParam.cancelScheduledValues() "取消对AudioParam的所有预定的未来更改",但我不确定当前正在进行的更改会发生什么.
这是我用来启动/重启音量信封的代码.
var now = context.currentTime;
var currentVol = gain.gain.value;
gain.gain.cancelScheduledValues(now);
gain.gain.setValueAtTime(currentVol, now);
gain.gain.exponentialRampToValueAtTime(1, now + volAttack);
gain.gain.exponentialRampToValueAtTime(0.000001, now + volAttack + volDecay);
Run Code Online (Sandbox Code Playgroud) 我已经成功地在React中实例化了一个简单的AudioWorklet,并希望像谷歌的例子那样启动一个简单的振荡器.为了测试运行它,我正在渲染一个按钮,其onClick事件调用以下内容:
SRC/App.jsx:
userGesture(){
//create a new AudioContext
this.context = new AudioContext();
//Add our Processor module to the AudioWorklet
this.context.audioWorklet.addModule('worklet/processor.js').then(() => {
//Create an oscillator and run it through the processor
let oscillator = new OscillatorNode(this.context);
let bypasser = new MyWorkletNode(this.context, 'my-worklet-processor');
//Connect to the context's destination and start
oscillator.connect(bypasser).connect(this.context.destination);
oscillator.start();
})
.catch((e => console.log(e)))
}
Run Code Online (Sandbox Code Playgroud)
问题是,每次单击时,addModule方法都会返回以下错误:
DOMException: The user aborted a request.
Run Code Online (Sandbox Code Playgroud)
我在Ubuntu v16.0.4上运行Chrome v66.
SRC/worklet/worklet-的node.js:
export default class MyWorkletNode extends window.AudioWorkletNode {
constructor(context) {
super(context, 'my-worklet-processor');
}
}
Run Code Online (Sandbox Code Playgroud)
SRC/worklet/processor.js …
背景
我正在编写一个服务来以块的形式提供静态音频文件,以支持带宽较低的用户的流畅体验。一旦文件完全流式传输(块序列是线性的,用户将无法“跳转”范围),我想将文件保存到本地缓存中(使用 localforage,但这不是这个问题的一部分)到稍后从那里加载缓存文件并节省带宽。
问题
根据我目前的知识/代码/工具状态,只能执行以下操作之一:
A) 使用HTMLAudioElement流式传输音频
const audio = new Audio()
audio.src = url
audio.preload = 'auto'
audio.load()
Run Code Online (Sandbox Code Playgroud)
HTML5 音频在内部处理部分响应,本身工作正常,但一旦完全加载,我就无法访问底层缓冲区来保存文件。因此,如果不单独下载(在另一个请求中),我将无法在本地缓存文件。
B) 下载/获取整个文件,然后播放
fetch(url, options) // set content header to array buffer
.then((response) => {
var blob = new Blob([response.value], { type: 'audio/mp3' })
var url = window.URL.createObjectURL(blob)
const audio = new Audio()
audio.src = url
audio.play()
})
Run Code Online (Sandbox Code Playgroud)
这使我可以访问数据,以便我可以缓存它以供离线重用。但是我放弃了流媒体选项,这使得几乎不可能在没有长时间等待的情况下播放更大的文件。
C) 使用自定义加载器并使用 WebAudio API 播放每个块
由于 A 和 B 不够用,我编写了一个自定义 loader,它加载块(工作正常),并使用当前块(作为 ArrayBuffer)作为数据分派事件。它还在结束时调度另一个事件,该事件返回所有块,因此我可以从中创建一个 blob:
const chunkSize …Run Code Online (Sandbox Code Playgroud) 使用 Web Audio API 创建音频缓冲区时,有一些由 decodeAudioData 方法创建的缓冲区,它们驻留在内存中,显然无法通过 JavaScript 访问。它们似乎在浏览器选项卡的整个生命周期中都存在,并且永远不会被垃圾收集。
我知道这些缓冲区与主线程分开并设置在另一个线程上以进行异步解码。我也知道 API 规范说 decodeAudioData 不应该被允许对同一个输入缓冲区解码两次,我认为这就是为什么保留解码缓冲区和/或编码输入缓冲区的副本的原因。但是,在 Chromecast 等内存有限的设备上,这会导致大量内存积累和 Chromecast 崩溃。
在我的示例代码中,我使用 Ajax 获取 mp3,然后将 arraybuffer 传递给 decodeAudioData 函数。通常在该函数中有一个 onsuccess 回调,它可以将解码的 AudioBuffer 作为参数。但是在我的代码中,我什至没有将其传入。因此,在解码后我也不会对解码的缓冲区执行任何操作。它没有在我的代码中的任何地方引用。它完全留在本机代码中。但是,每次调用此函数都会增加内存分配,并且永远不会释放。例如,在 Firefox 中,about:memory 会显示 Tab 生命周期内的音频缓冲区。非引用应该足以让垃圾收集器摆脱这些缓冲区。
我的主要问题是,是否有任何对这些解码音频缓冲区的引用,比如在 audiocontext 对象中,或者我可以尝试从内存中删除它们的其他地方?或者有没有其他方法可以使这些存储的和无法访问的缓冲区消失?
我的问题与目前关于 decodeAudioData 的所有其他问题都不同,因为我表明即使没有用户存储任何引用,甚至没有使用返回的解码音频缓冲区,也会发生内存泄漏。
function loadBuffer() {
// create an audio context
var context = new (window.AudioContext || window.webkitAudioContext)();
// fetch mp3 as an arraybuffer async
var url = "beep.mp3";
var request = new XMLHttpRequest(); …Run Code Online (Sandbox Code Playgroud) 我们在会议室录音,在那里我们有多个演讲者对话。每个扬声器都有一个个人麦克风,每个麦克风的语音都被记录为一个单独的通道(单独的音频文件)。
我们的目标是允许用户一次播放所有音频(频道)。我们可能有多达 12 个单独的文件。此外,我们需要用户能够控制每个流的音量(因此仅在后端合并文件不是解决方案)。
我们可以用什么来实现这一目标?一次播放它们的幼稚解决方案可能行不通,因此我们想知道现代 html5 API 是否解决了这种挑战。
--- 更新以回答@Amdadan 的评论 ---
为什么不?你试了吗?如果您正在流式传输它们,您是否担心连接吞吐量?您是否担心 API 限制?
是的,我们试过了。1)当我们对所有文件调用“播放”时 - 它不会在同一时刻开始(它开始加载所有文件,一个加载速度更快,一个加载速度更慢,等等)。2)当它已经在播放并且文件到达“缓冲”时间结束时 - 它也会停止而其他人继续播放。
我们尝试使用事件来处理这些情况,但我们没有成功——有很多情况需要处理。
如果您在玩之前将它们全部加载,您是否担心尺寸?
是的我们是。文件可能有几个小时的长度——它不能全部被缓冲。
如果您正在流式传输它们,您是否担心连接吞吐量?您是否担心 API 限制?
不,我们使用连接到 s3 的 CloudFront - 吞吐量还可以,并且没有特定限制
提前谢谢你, - 杰克
web-audio-api ×10
javascript ×7
html5-audio ×4
html5 ×2
html ×1
reactjs ×1
streaming ×1
webrtc ×1