前端和用户直接相关,所以实现录音功能是很常见的需求。如何实现配音功能,网上一搜全是老掉牙方法。作为一个热爱新技术,喜欢与时俱进的前端仔,我实在看不下去了,就写了这篇文章教大家如何用新方法实现录音功能。
废话不多说,直接上代码(非常简单易懂,而且我封装好了):
1 function Recorder(stream, mimeType) { 2 const mediaRecorder = new MediaRecorder(stream); 3 let chunks = []; 4 let blob 5 mediaRecorder.ondataavailable = function (e) { 6 chunks.push(e.data); 7 } 8 mediaRecorder.onstop = function () { 9 blob = new Blob(chunks, { 'type': mimeType }); 10 chunks = []; 11 } 12 13 // 开始录音方法: 14 this.start = function () { 15 mediaRecorder.start(); 16 } 17 18 // 结束录音方法: 19 this.stop = function () { 20 mediaRecorder.stop(); 21 } 22 23 // 获取录音的音频文件 24 this.getFile = function () { 25 return blob 26 } 27 } 28 29 export default function getRecorder(mimeType = "audio/ogg; codecs=opus") { 30 if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) { 31 return Promise.reject(new Error('当前浏览器不支持录音功能。')); 32 } 33 return navigator.mediaDevices.getUserMedia({ audio: true }).then(function (stream) { 34 return new Recorder(stream, mimeType) 35 }) 36 }
36行代码全部搞定,而且支持各种文件类型。
再看看网上搜到的祖传方法,代码过多,慎点:
(因为代码过多,我将其分成了三个文件,这里只展示主文件,过于底层的两个就不展示了,因为没有必要教大家如何用老方法实现录音,这里只是为了对比网上搜的老方法有多糟糕。
声明一下,这里没有看不起老方法的意思,在那个年代能够以这样的方式实现录音的肯定是大神。
不过现在确实都2021年了,祖传方法还这么流行,这是国内IT博客互相无脑抄袭的风气造成的。)
1 import encodeWAV from './utiles/encodeWAV' // 负责将音频数据编码成mav格式的文件,共64行。代码过于底层,这里不展示! 2 import audioTransform from './utiles/audioTransform' // 输入音频的声道,采样率,比特率和输出要求不一致时,负责做转换的。共52行。代码过于底层,这里不展示! 3 const channelCount = 1; 4 const sampleBits = 16 5 var HZRecorder = function (stream) { 6 const outConf = { channelCount, sampleBits } 7 const inConf = { channelCount, sampleBits }; 8 9 var context = new AudioContext(); 10 var audioInput = context.createMediaStreamSource(stream); 11 outConf.sampleRate = inConf.sampleRate = context.sampleRate 12 13 var jsProcessor = context.createScriptProcessor(0, inConf.channelCount, outConf.channelCount); //输入声道和输出声道 14 //定义数据 15 var audioData = { 16 size: 0, //录音文件长度 17 buffer: [], //录音缓存 18 input: function (data) { 19 this.buffer.push(new Float32Array(data)); 20 this.size += data.length; 21 }, 22 encode: function () { 23 let inputSampleArr = new Float32Array(this.size), offset = 0; 24 for (let i = 0; i < this.buffer.length; i++) { 25 inputSampleArr.set(this.buffer[i], offset); 26 offset += this.buffer[i].length; 27 } 28 let res = audioTransform(inputSampleArr, inConf, outConf) 29 return encodeWAV(res.sampleArr, res.sampleRate, res.sampleBits, res.channelCount) 30 }, 31 clear: function () { 32 this.size = 0; 33 this.buffer = [] 34 } 35 }; 36 37 //开始录音 38 this.start = function () { 39 audioData.clear() 40 audioInput.connect(jsProcessor); 41 jsProcessor.connect(context.destination); 42 } 43 44 //停止 45 this.stop = function () { 46 audioInput.disconnect() 47 jsProcessor.disconnect(); 48 } 49 50 //获取音频文件 51 this.getBlob = function () { 52 this.stop() 53 return audioData.encode(); 54 } 55 56 //音频采集 57 jsProcessor.onaudioprocess = function (e) { 58 /** 59 * @type {Float32Array} 60 */ 61 let data = e.inputBuffer.getChannelData(0) 62 audioData.input(data); 63 } 64 }; 65 66 //获取录音机 67 export default function getRecorder() { 68 if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) { 69 return Promise.reject(new Error('当前浏览器不支持录音功能。')); 70 } 71 //获取计算机的设备:录音设备 72 return navigator.mediaDevices.getUserMedia({ 73 audio: { sampleSize: sampleBits, channelCount: 1 } 74 }).then(stream => { 75 return new HZRecorder(stream); 76 }); 77 };
老方法,涉及过多的底层。文件类型只支持wav,扩展不便。