我可以在不使用麦克风的情况下录制 <audio> 的输出吗?
Can I record the output of an <audio> without use of the microphone?
我有一个 <audio>
元素,我正在改变速度、start/end 边界和间距。我想看看是否可以录制我在浏览器中听到的音频。但是我不想只用麦克风录音,因为质量较低。
我可以在服务器端实现相同的效果,但我宁愿不这样做,因为我基本上是用两种不同的技术来复制相同的功能。
为了回应旗帜投票,因为它是 "unclear what I'm asking",我会重新措辞。
我有一个 <audio>
元素在页面上播放。我有一些 javascript 操纵播放速率、音量等。然后我希望我的 浏览器 录制我听到的音频 .这不是麦克风。我想创建一个尽可能接近正在播放的音频文件。如果音量为 75%,则新文件的音量将为 75%。
在支持的浏览器中,您可以使用MediaElement.captureStream()
method along with the MediaRecorder API。
但请注意,这些技术仍在积极开发中,当前的实施仍然充满错误。
例如,对于您的情况,如果您在录制时更改其音量,当前稳定的 FF 将停止原始媒体音频的渲染......我没有时间搜索关于它的错误报告,但无论如何,这只是一个您会发现的许多错误中的一个。
// here we will save all the chunks of our record
const chunks = [];
// wait for the original media is ready
audio.oncanplay = function() {
audio.volume = 0.5; // just for your example
// FF still does prefix this unstable method
var stream = audio.captureStream ? audio.captureStream() : audio.mozCaptureStream();
// create a MediaRecorder from our stream
var rec = new MediaRecorder(stream);
// every time we've got a bit of data, store it
rec.ondataavailable = e => chunks.push(e.data);
// once everything is done
rec.onstop = e => {
audio.pause();
// concatenate our chunks into one file
let final = new Blob(chunks);
let a = new Audio(URL.createObjectURL(final));
a.controls = true;
document.body.append(a);
};
rec.start();
// record for 6 seconds
setTimeout(() => rec.stop(), 6000);
// for demo, change volume at half-time
setTimeout(() => audio.volume = 1, 3000);
};
// FF will "taint" the stream, even if the media is served with correct CORS...
fetch("https://dl.dropboxusercontent.com/s/8c9m92u1euqnkaz/GershwinWhiteman-RhapsodyInBluePart1.mp3").then(resp => resp.blob()).then(b => audio.src = URL.createObjectURL(b));
<audio id="audio" autoplay controls></audio>
对于旧版浏览器,您可以使用 WebAudio API 的 createMediaElementSource
方法,通过 API.
传递您的音频元素媒体
从那里,您将能够将原始 PCM 数据提取到 arrayBuffers 并将其保存。
在下面的演示中,我将使用 recorder.js
库,它极大地帮助 提取 + 保存到 wav 过程。
audio.oncanplay = function(){
var audioCtx = new AudioContext();
var source = audioCtx.createMediaElementSource(audio);
var gainNode = audioCtx.createGain();
gainNode.gain.value = 0.5;
source.connect(gainNode);
gainNode.connect(audioCtx.destination);
var rec = new Recorder(gainNode);
rec.record();
setTimeout(function(){
gainNode.gain.value = 1;
}, 3000);
setTimeout(function(){
rec.stop()
audio.pause();
rec.exportWAV(function(blob){
var a = new Audio(URL.createObjectURL(blob));
a.controls = true;
document.body.appendChild(a);
});
}, 6000);
};
<script src="https://rawgit.com/mattdiamond/Recorderjs/master/dist/recorder.js"></script>
<audio id="audio" crossOrigin="anonymous" controls src="https://dl.dropboxusercontent.com/s/8c9m92u1euqnkaz/GershwinWhiteman-RhapsodyInBluePart1.mp3" autoplay></audio>
正如 Kaiido 在他的回答中提到的那样,captureStream()
是一种实现方式。但是,Chrome 和 Firefox 还没有完全支持它。 MediaRecorder 也不允许在录制过程中更改轨道集,来自 captureStream()
的 MediaStream 可能有这些(取决于应用程序)- 从而提前结束录制。
如果您需要一种受支持的方式从媒体元素录制 仅音频 ,您可以使用 MediaElementAudioSourceNode
,将其通过管道传输到 MediaStreamAudioDestinationNode
,并将其 stream
属性通过管道传输到 MediaRecorder。
这是一个您可以在具有现有音频元素的页面上使用的示例:
const a = document.getElementsByTagName("audio")[0];
const ac = new AudioContext();
const source = ac.createMediaElementSource(a);
// The media element source stops audio playout of the audio element.
// Hook it up to speakers again.
source.connect(ac.destination);
// Hook up the audio element to a MediaStream.
const dest = ac.createMediaStreamDestination();
source.connect(dest);
// Record 10s of audio with MediaRecorder.
const recorder = new MediaRecorder(dest.stream);
recorder.start();
recorder.ondataavailable = ev => {
console.info("Finished recording. Got blob:", ev.data);
a.src = URL.createObjectURL(ev.data);
a.play();
};
setTimeout(() => recorder.stop(), 10 * 1000);
请注意,如果没有适当的 CORS 设置,这两种方法都不适用于 cross-origin 音频源,因为 WebAudio 和录音都可以让应用程序检查音频数据。
我有一个 <audio>
元素,我正在改变速度、start/end 边界和间距。我想看看是否可以录制我在浏览器中听到的音频。但是我不想只用麦克风录音,因为质量较低。
我可以在服务器端实现相同的效果,但我宁愿不这样做,因为我基本上是用两种不同的技术来复制相同的功能。
为了回应旗帜投票,因为它是 "unclear what I'm asking",我会重新措辞。
我有一个 <audio>
元素在页面上播放。我有一些 javascript 操纵播放速率、音量等。然后我希望我的 浏览器 录制我听到的音频 .这不是麦克风。我想创建一个尽可能接近正在播放的音频文件。如果音量为 75%,则新文件的音量将为 75%。
在支持的浏览器中,您可以使用MediaElement.captureStream()
method along with the MediaRecorder API。
但请注意,这些技术仍在积极开发中,当前的实施仍然充满错误。
例如,对于您的情况,如果您在录制时更改其音量,当前稳定的 FF 将停止原始媒体音频的渲染......我没有时间搜索关于它的错误报告,但无论如何,这只是一个您会发现的许多错误中的一个。
// here we will save all the chunks of our record
const chunks = [];
// wait for the original media is ready
audio.oncanplay = function() {
audio.volume = 0.5; // just for your example
// FF still does prefix this unstable method
var stream = audio.captureStream ? audio.captureStream() : audio.mozCaptureStream();
// create a MediaRecorder from our stream
var rec = new MediaRecorder(stream);
// every time we've got a bit of data, store it
rec.ondataavailable = e => chunks.push(e.data);
// once everything is done
rec.onstop = e => {
audio.pause();
// concatenate our chunks into one file
let final = new Blob(chunks);
let a = new Audio(URL.createObjectURL(final));
a.controls = true;
document.body.append(a);
};
rec.start();
// record for 6 seconds
setTimeout(() => rec.stop(), 6000);
// for demo, change volume at half-time
setTimeout(() => audio.volume = 1, 3000);
};
// FF will "taint" the stream, even if the media is served with correct CORS...
fetch("https://dl.dropboxusercontent.com/s/8c9m92u1euqnkaz/GershwinWhiteman-RhapsodyInBluePart1.mp3").then(resp => resp.blob()).then(b => audio.src = URL.createObjectURL(b));
<audio id="audio" autoplay controls></audio>
对于旧版浏览器,您可以使用 WebAudio API 的 createMediaElementSource
方法,通过 API.
传递您的音频元素媒体
从那里,您将能够将原始 PCM 数据提取到 arrayBuffers 并将其保存。
在下面的演示中,我将使用 recorder.js
库,它极大地帮助 提取 + 保存到 wav 过程。
audio.oncanplay = function(){
var audioCtx = new AudioContext();
var source = audioCtx.createMediaElementSource(audio);
var gainNode = audioCtx.createGain();
gainNode.gain.value = 0.5;
source.connect(gainNode);
gainNode.connect(audioCtx.destination);
var rec = new Recorder(gainNode);
rec.record();
setTimeout(function(){
gainNode.gain.value = 1;
}, 3000);
setTimeout(function(){
rec.stop()
audio.pause();
rec.exportWAV(function(blob){
var a = new Audio(URL.createObjectURL(blob));
a.controls = true;
document.body.appendChild(a);
});
}, 6000);
};
<script src="https://rawgit.com/mattdiamond/Recorderjs/master/dist/recorder.js"></script>
<audio id="audio" crossOrigin="anonymous" controls src="https://dl.dropboxusercontent.com/s/8c9m92u1euqnkaz/GershwinWhiteman-RhapsodyInBluePart1.mp3" autoplay></audio>
正如 Kaiido 在他的回答中提到的那样,captureStream()
是一种实现方式。但是,Chrome 和 Firefox 还没有完全支持它。 MediaRecorder 也不允许在录制过程中更改轨道集,来自 captureStream()
的 MediaStream 可能有这些(取决于应用程序)- 从而提前结束录制。
如果您需要一种受支持的方式从媒体元素录制 仅音频 ,您可以使用 MediaElementAudioSourceNode
,将其通过管道传输到 MediaStreamAudioDestinationNode
,并将其 stream
属性通过管道传输到 MediaRecorder。
这是一个您可以在具有现有音频元素的页面上使用的示例:
const a = document.getElementsByTagName("audio")[0];
const ac = new AudioContext();
const source = ac.createMediaElementSource(a);
// The media element source stops audio playout of the audio element.
// Hook it up to speakers again.
source.connect(ac.destination);
// Hook up the audio element to a MediaStream.
const dest = ac.createMediaStreamDestination();
source.connect(dest);
// Record 10s of audio with MediaRecorder.
const recorder = new MediaRecorder(dest.stream);
recorder.start();
recorder.ondataavailable = ev => {
console.info("Finished recording. Got blob:", ev.data);
a.src = URL.createObjectURL(ev.data);
a.play();
};
setTimeout(() => recorder.stop(), 10 * 1000);
请注意,如果没有适当的 CORS 设置,这两种方法都不适用于 cross-origin 音频源,因为 WebAudio 和录音都可以让应用程序检查音频数据。