我可以在不使用麦克风的情况下录制<audio>的输出吗?

时间:2017-02-20 04:35:27

标签: javascript html5 audio webrtc html5-audio

我有一个<audio>元素,我正在改变速度,开始/结束界限和音高。我想看看是否可以录制我在浏览器中听到的音频。但是,由于质量较差,我不想仅使用麦克风录音。

我可以在服务器端做同样的效果,但我不愿意,因为我基本上是用两种不同的技术复制相同的功能。

回应旗帜投票,因为它不清楚我要问的是什么&#34;,我会改写。

我在页面上播放了<audio>元素。我有一些javascript操纵播放速率,音量等。然后我希望我的浏览器记录音频,因为我听到它。这不是麦克风。我想创建一个尽可能接近播放的新音频文件。如果它是75%,那么新文件的容量将达到75%。

如果您认为不可能,那么这样说,那没关系。如果你想要更多澄清,那很好。我更喜欢如果人们没有给出解释而不进行投票和标记。

2 个答案:

答案 0 :(得分:4)

在支持浏览器时,您可以使用MediaElement.captureStream()方法和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>

答案 1 :(得分:2)

正如Kaiido在回答中提到的那样,captureStream()是一种做法。但是,Chrome和Firefox尚不完全支持。 MediaRecorder也不允许在录制期间更改曲目集,来自captureStream()的MediaStream可能具有这些(取决于应用程序) - 从而过早地结束录制。

如果您需要一种支持的方式从媒体元素录制仅音频,您可以使用MediaElementAudioSourceNode,管道到MediaStreamAudioDestinationNode,并管道{{ 1}}属于MediaRecorder的属性。

以下是您可以在包含现有音频元素的网页上使用的示例:

stream

请注意,如果没有正确的CORS设置,这两种方法都不适用于跨源音频源,因为WebAudio和录音都可以让应用程序检查音频数据。