HTML5录制音频到文件

blmhpbnm  于 2023-10-14  发布在  HTML5
关注(0)|答案(9)|浏览(302)

我最终想做的是从用户的麦克风记录,并在他们完成后将文件上传到服务器。到目前为止,我已经成功地使用以下代码创建了一个元素的流:

  1. var audio = document.getElementById("audio_preview");
  2. navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
  3. navigator.getUserMedia({video: false, audio: true}, function(stream) {
  4. audio.src = window.URL.createObjectURL(stream);
  5. }, onRecordFail);
  6. var onRecordFail = function (e) {
  7. console.log(e);
  8. }

我如何从这一点,记录到一个文件?

wf82jlnq

wf82jlnq1#

有一个相当完整的录音演示可在:http://webaudiodemos.appspot.com/AudioRecorder/index.html
它允许您在浏览器中录制音频,然后为您提供导出和下载录制内容的选项。
您可以查看该页面的源代码以找到指向JavaScript的链接,但总结一下,有一个Recorder对象,它包含一个exportWAV方法和一个forceDownload方法。

ssm49v7z

ssm49v7z2#

下面显示的代码版权归Matt Diamond所有,可在MIT许可下使用。原始文件在这里:

保存此文件并使用

  1. (function(window){
  2. var WORKER_PATH = 'recorderWorker.js';
  3. var Recorder = function(source, cfg){
  4. var config = cfg || {};
  5. var bufferLen = config.bufferLen || 4096;
  6. this.context = source.context;
  7. this.node = this.context.createScriptProcessor(bufferLen, 2, 2);
  8. var worker = new Worker(config.workerPath || WORKER_PATH);
  9. worker.postMessage({
  10. command: 'init',
  11. config: {
  12. sampleRate: this.context.sampleRate
  13. }
  14. });
  15. var recording = false,
  16. currCallback;
  17. this.node.onaudioprocess = function(e){
  18. if (!recording) return;
  19. worker.postMessage({
  20. command: 'record',
  21. buffer: [
  22. e.inputBuffer.getChannelData(0),
  23. e.inputBuffer.getChannelData(1)
  24. ]
  25. });
  26. }
  27. this.configure = function(cfg){
  28. for (var prop in cfg){
  29. if (cfg.hasOwnProperty(prop)){
  30. config[prop] = cfg[prop];
  31. }
  32. }
  33. }
  34. this.record = function(){
  35. recording = true;
  36. }
  37. this.stop = function(){
  38. recording = false;
  39. }
  40. this.clear = function(){
  41. worker.postMessage({ command: 'clear' });
  42. }
  43. this.getBuffer = function(cb) {
  44. currCallback = cb || config.callback;
  45. worker.postMessage({ command: 'getBuffer' })
  46. }
  47. this.exportWAV = function(cb, type){
  48. currCallback = cb || config.callback;
  49. type = type || config.type || 'audio/wav';
  50. if (!currCallback) throw new Error('Callback not set');
  51. worker.postMessage({
  52. command: 'exportWAV',
  53. type: type
  54. });
  55. }
  56. worker.onmessage = function(e){
  57. var blob = e.data;
  58. currCallback(blob);
  59. }
  60. source.connect(this.node);
  61. this.node.connect(this.context.destination); //this should not be necessary
  62. };
  63. Recorder.forceDownload = function(blob, filename){
  64. var url = (window.URL || window.webkitURL).createObjectURL(blob);
  65. var link = window.document.createElement('a');
  66. link.href = url;
  67. link.download = filename || 'output.wav';
  68. var click = document.createEvent("Event");
  69. click.initEvent("click", true, true);
  70. link.dispatchEvent(click);
  71. }
  72. window.Recorder = Recorder;
  73. })(window);
  74. //ADDITIONAL JS recorderWorker.js
  75. var recLength = 0,
  76. recBuffersL = [],
  77. recBuffersR = [],
  78. sampleRate;
  79. this.onmessage = function(e){
  80. switch(e.data.command){
  81. case 'init':
  82. init(e.data.config);
  83. break;
  84. case 'record':
  85. record(e.data.buffer);
  86. break;
  87. case 'exportWAV':
  88. exportWAV(e.data.type);
  89. break;
  90. case 'getBuffer':
  91. getBuffer();
  92. break;
  93. case 'clear':
  94. clear();
  95. break;
  96. }
  97. };
  98. function init(config){
  99. sampleRate = config.sampleRate;
  100. }
  101. function record(inputBuffer){
  102. recBuffersL.push(inputBuffer[0]);
  103. recBuffersR.push(inputBuffer[1]);
  104. recLength += inputBuffer[0].length;
  105. }
  106. function exportWAV(type){
  107. var bufferL = mergeBuffers(recBuffersL, recLength);
  108. var bufferR = mergeBuffers(recBuffersR, recLength);
  109. var interleaved = interleave(bufferL, bufferR);
  110. var dataview = encodeWAV(interleaved);
  111. var audioBlob = new Blob([dataview], { type: type });
  112. this.postMessage(audioBlob);
  113. }
  114. function getBuffer() {
  115. var buffers = [];
  116. buffers.push( mergeBuffers(recBuffersL, recLength) );
  117. buffers.push( mergeBuffers(recBuffersR, recLength) );
  118. this.postMessage(buffers);
  119. }
  120. function clear(){
  121. recLength = 0;
  122. recBuffersL = [];
  123. recBuffersR = [];
  124. }
  125. function mergeBuffers(recBuffers, recLength){
  126. var result = new Float32Array(recLength);
  127. var offset = 0;
  128. for (var i = 0; i < recBuffers.length; i++){
  129. result.set(recBuffers[i], offset);
  130. offset += recBuffers[i].length;
  131. }
  132. return result;
  133. }
  134. function interleave(inputL, inputR){
  135. var length = inputL.length + inputR.length;
  136. var result = new Float32Array(length);
  137. var index = 0,
  138. inputIndex = 0;
  139. while (index < length){
  140. result[index++] = inputL[inputIndex];
  141. result[index++] = inputR[inputIndex];
  142. inputIndex++;
  143. }
  144. return result;
  145. }
  146. function floatTo16BitPCM(output, offset, input){
  147. for (var i = 0; i < input.length; i++, offset+=2){
  148. var s = Math.max(-1, Math.min(1, input[i]));
  149. output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
  150. }
  151. }
  152. function writeString(view, offset, string){
  153. for (var i = 0; i < string.length; i++){
  154. view.setUint8(offset + i, string.charCodeAt(i));
  155. }
  156. }
  157. function encodeWAV(samples){
  158. var buffer = new ArrayBuffer(44 + samples.length * 2);
  159. var view = new DataView(buffer);
  160. /* RIFF identifier */
  161. writeString(view, 0, 'RIFF');
  162. /* file length */
  163. view.setUint32(4, 32 + samples.length * 2, true);
  164. /* RIFF type */
  165. writeString(view, 8, 'WAVE');
  166. /* format chunk identifier */
  167. writeString(view, 12, 'fmt ');
  168. /* format chunk length */
  169. view.setUint32(16, 16, true);
  170. /* sample format (raw) */
  171. view.setUint16(20, 1, true);
  172. /* channel count */
  173. view.setUint16(22, 2, true);
  174. /* sample rate */
  175. view.setUint32(24, sampleRate, true);
  176. /* byte rate (sample rate * block align) */
  177. view.setUint32(28, sampleRate * 4, true);
  178. /* block align (channel count * bytes per sample) */
  179. view.setUint16(32, 4, true);
  180. /* bits per sample */
  181. view.setUint16(34, 16, true);
  182. /* data chunk identifier */
  183. writeString(view, 36, 'data');
  184. /* data chunk length */
  185. view.setUint32(40, samples.length * 2, true);
  186. floatTo16BitPCM(view, 44, samples);
  187. return view;
  188. }
  1. <html>
  2. <body>
  3. <audio controls autoplay></audio>
  4. <script type="text/javascript" src="recorder.js"> </script>
  5. <fieldset><legend>RECORD AUDIO</legend>
  6. <input onclick="startRecording()" type="button" value="start recording" />
  7. <input onclick="stopRecording()" type="button" value="stop recording and play" />
  8. </fieldset>
  9. <script>
  10. var onFail = function(e) {
  11. console.log('Rejected!', e);
  12. };
  13. var onSuccess = function(s) {
  14. var context = new webkitAudioContext();
  15. var mediaStreamSource = context.createMediaStreamSource(s);
  16. recorder = new Recorder(mediaStreamSource);
  17. recorder.record();
  18. // audio loopback
  19. // mediaStreamSource.connect(context.destination);
  20. }
  21. window.URL = window.URL || window.webkitURL;
  22. navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
  23. var recorder;
  24. var audio = document.querySelector('audio');
  25. function startRecording() {
  26. if (navigator.getUserMedia) {
  27. navigator.getUserMedia({audio: true}, onSuccess, onFail);
  28. } else {
  29. console.log('navigator.getUserMedia not present');
  30. }
  31. }
  32. function stopRecording() {
  33. recorder.stop();
  34. recorder.exportWAV(function(s) {
  35. audio.src = window.URL.createObjectURL(s);
  36. });
  37. }
  38. </script>
  39. </body>
  40. </html>
展开查看全部
mi7gmzs6

mi7gmzs63#

更新现在Chrome也支持v47的MediaRecorder API。同样的事情要做的是使用它(猜测本机记录方法肯定会比变通方法更快),API真的很容易使用,你会发现关于如何为服务器上传一个blob的答案。

Demo-可以在Chrome和Firefox中工作,故意忽略了将blob推送到服务器.
Code Source
目前,有三种方法可以做到这一点:
1.作为wav [所有代码客户端,未压缩录制],可以查看--> Recorderjs。问题:文件太大,需要更多的上传带宽。
1.作为mp3 [所有代码客户端,压缩记录],可以查看--> mp3Recorder.问题:就我个人而言,我觉得质量不好,也有这个许可证的问题。
1.作为ogg [客户端+服务器端(node.js)代码,压缩录制,无限小时录制而不崩溃浏览器],你可以查看--> recordOpus,要么只客户端录制,要么客户端-服务器捆绑,选择是你的。
ogg记录示例(仅限firefox):

  1. var mediaRecorder = new MediaRecorder(stream);
  2. mediaRecorder.start(); // to start recording.
  3. ...
  4. mediaRecorder.stop(); // to stop recording.
  5. mediaRecorder.ondataavailable = function(e) {
  6. // do something with the data.
  7. }

Fiddle Demo用于ogg记录。

展开查看全部
goqiplq2

goqiplq24#

这是一个简单的JavaScript录音机和编辑器。你可以试试。
https://www.danieldemmel.me/JSSoundRecorder/
可以从这里下载**
https://github.com/daaain/JSSoundRecorder

olhwl3o2

olhwl3o25#

这个问题很老,许多答案在当前版本的浏览器中不受支持。我尝试使用简单的htmlcssjs创建音频记录器。我进一步在electron中使用相同的代码来制作一个跨平台应用程序。

  1. <html>
  2. <head>
  3. <title>Recorder App</title>
  4. </head>
  5. <h2>Recorder App</h2>
  6. <p>
  7. <button type="button" id="record">Record</button>
  8. <button type="button" id="stopRecord" disabled>Stop</button>
  9. </p>
  10. <p>
  11. <audio id="recordedAudio"></audio>
  12. </p>
  13. <script>
  14. navigator.mediaDevices.getUserMedia({audio:true})
  15. .then(stream => {handlerFunction(stream)})
  16. function handlerFunction(stream) {
  17. rec = new MediaRecorder(stream);
  18. rec.ondataavailable = e => {
  19. audioChunks.push(e.data);
  20. if (rec.state == "inactive"){
  21. let blob = new Blob(audioChunks,{type:'audio/mp3'});
  22. recordedAudio.src = URL.createObjectURL(blob);
  23. recordedAudio.controls=true;
  24. recordedAudio.autoplay=true;
  25. sendData(blob)
  26. }
  27. }
  28. }
  29. function sendData(data) {}
  30. record.onclick = e => {
  31. record.disabled = true;
  32. record.style.backgroundColor = "blue"
  33. stopRecord.disabled=false;
  34. audioChunks = [];
  35. rec.start();
  36. }
  37. stopRecord.onclick = e => {
  38. record.disabled = false;
  39. stop.disabled=true;
  40. record.style.backgroundColor = "red"
  41. rec.stop();
  42. }
  43. </script>
  44. </html>

上面的代码可以在Windows 10、Mac、Linux中运行,当然,也可以在谷歌Chrome和火狐上运行。

展开查看全部
6kkfgxo0

6kkfgxo06#

您可以使用GitHub中的Recordmp3js来实现您的要求。您可以从用户的麦克风录制,然后将文件作为mp3。最后上传到你的服务器。
我在我的demo中使用了这个。已经有一个示例与源代码由作者在这个位置:https://github.com/Audior/Recordmp3js
demo在这里:http://audior.ec/recordmp3js/
但目前仅适用于Chrome和Firefox。
似乎工作得很好,很简单。希望这对你有帮助。

q1qsirdb

q1qsirdb7#

这里有一个gitHub项目可以做到这一点。
它以mp3格式记录浏览器中的音频,并自动将其保存到Web服务器。https://github.com/Audior/Recordmp3js
您还可以查看实现的详细说明:http://audior.ec/blog/recording-mp3-using-only-html5-and-javascript-recordmp3-js/

7ivaypg9

7ivaypg98#

实时流式传输音频,无需等待录制结束:https://github.com/noamtcohen/AudioStreamer
这将传输PCM数据,但您可以修改代码以传输mp3或Speex

oug3syen

oug3syen9#

如果你只需要wav文件格式,你可以使用这个npm包,不需要做任何修改。https://www.npmjs.com/package/extendable-media-recorder

  1. import { MediaRecorder, register } from 'extendable-media-recorder';
  2. import { connect } from 'extendable-media-recorder-wav-encoder';
  3. await register(await connect());
  4. const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
  5. const mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/wav' });

相关问题