上一章地址: web音频流转发之音频源
下一张地址:web音频流转发之音视频直播
在这一章我说几个咱们须要用到的音频处理模块也就3个吧,包括咱们转发流是须要用到的核心模块。更多模块请看MDN,或者看HTML5音频API Web Audio也有一些中文讲解,但愿你们多多支持。javascript
AudioNode:是一个处理音频的通用模块, 好比一个音频源 (e.g. 一个 HTML <audio> or <video> 元素), 一个音频地址或者一个中间处理模块 (e.g. 一个过滤器如 BiquadFilterNode, 或一个音量控制器如 GainNode).一个AudioNode 既有输入也有输出。输入与输出都有必定数量的通道。只有一个输出而没有输入的 AudioNode 叫作音频源(MDN的解释)。下面我用简单的代码给你们解释下html
let audioCtx = new window.AudioContext, //频率及时间域分析器,声音可视化就用这个 analyser = audioCtx.createAnalyser(), //音量变动模块 gainNode = audioCtx.createGain(), //波形控制器模块 distortion = audioCtx.createWaveShaper(), //低频滤波器模块 biquadFilter = audioCtx.createBiquadFilter(), //建立源 source = audioCtx.createMediaStreamSource(stream); //经过connect方法从音频源链接到AudioNode处理模块,再链接到输出设备, //当咱们修改前面的模块时,就会影响到后面AudioNode,以及咱们最终听见的声音 source.connect(analyser); analyser.connect(distortion); distortion.connect(biquadFilter); biquadFilter.connect(convolver); convolver.connect(gainNode); gainNode.connect(audioCtx.destination);
下面我就分别讲解咱们须要用的几个apijava
下面简单说一下它的方法和属性,具体的使用在后面的demo中,说实话这些属性我也不知道有有什么用,可是咱们能经过方法取到咱们须要的数据,作音频可视化。analyser中的数据会根据数据的不一样会不停的变换,全部咱们须要用requestAnimationFrame函数,反复获取里面的数据,而后进行绘图。web
let analyser = audioCtx.createAnalyser(); //频域的FFT大小,默认是2048 analyser.fftSize; //fftSize的一半 analyser.frequencyBinCount; //快速傅立叶变化的最大范围的双精度浮点数 analyser.maxDecibels; //最后一个分析帧的平均常数 analyser.smoothingTimeConstant; //将当前频域数据拷贝进Float32Array数组 analyser.getFloatFrequencyData() //将当前频域数据拷贝进Uint8Array数组 analyser.getByteFrequencyData() 将当前波形,或者时域数据拷贝进Float32Array数组 analyser.getFloatTimeDomainData() //将当前波形,或者时域数据拷贝进 Uint8Array数组 analyser.getByteTimeDomainData()
这个简单到极点。。。canvas
let gainNode = audioCtx.createGain(); //修改value的大小,改变输出大小,默认是1,0表示静音 gainNode.gain.value = 1
缓冲区音频处理模块,这个是咱们作直播的核心模块,没有这个模块就作不到音频流的转发,音频数据的延迟在除开网络的影响下,这个模块也占一部分,固然要看本身的配置。AudioBuffer介绍segmentfault
/* 第一个参数表示每一帧缓存的数据大小,能够是256, 512, 1024, 2048, 4096, 8192, 16384, 值越小一帧的数据就越小,声音就越短,onaudioprocess 触发就越频繁。 4096的数据大小大概是0.085s,就是说每过0.085s就触发一次onaudioprocess, 若是我要把这一帧的数据发送到其余地方,那这个延迟最少就是0.085s, 固然还有考虑发送过去的电脑处理能力,通常1024以上的数字,若是有变态需求的256也是能够考虑的 第二,三个参数表示输入帧,和输出帧的通道数。这里表示2通道的输入和输出,固然我也能够采集1,4,5等通道 */ let recorder = audioCtx.createScriptProcessor(4096, 2, 2); /* 缓存区触发事件,链接了createScriptProcessor这个AudioNode就须要在onaudioprocess中, 把输入帧的数据,链接到输出帧,扬声器才有声音 */ recorder.onaudioprocess = function(e){ let inputBuffer = e.inputBuffer, //输入帧数据,AudioBuffer类型 outputBuffer = e.outputBuffer; //输出帧数据, AudioBuffer类型 //第一种方式 //将inputBuffer第0个通道的数据,复制到outputBuffer的第0个通道,偏移0个字节 outputBuffer.copyToChannel(inputBuffer.getChannelData(0), 0, 0); //将inputBuffer第1个通道的数据,复制到outputBuffer的第1个通道,偏移0个字节 outputBuffer.copyToChannel(inputBuffer.getChannelData(1), 1, 0); //第二中方式用循环 for (var channel = 0; channel < outputBuffer.numberOfChannels; channel++) { let inputData = inputBuffer.getChannelData(channel), outputData = outputBuffer.getChannelData(channel); for (var sample = 0; sample < inputBuffer.length; sample++) { outputData[sample] = inputData[sample]; } } }
下面我用input=file选择一个本地音乐举个栗子,采用哪一种音频看本身哟api
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title></title> <link rel="stylesheet" href=""> </head> <body> <canvas width="500px" height="500px"> </canvas> <input type="file" name="" value="" placeholder=""> <button type="button" class="add">音量+</button> <button type="button" class="lost">音量-</button> </body> <script type="text/javascript" charset="utf-8"> let fileInput = document.querySelector('input'), add = document.querySelector('.add'), //音量+ lost = document.querySelector('.lost'), //音量- audioCtx = new window.AudioContext, //建立环境 analyser = audioCtx.createAnalyser(), //analyser分析器 gainNode = audioCtx.createGain(), //控制音量大小 recorder = audioCtx.createScriptProcessor(4096, 2, 2), //缓冲区音频处理模块 canvas = document.querySelector('canvas'), canvasCtx = canvas.getContext('2d'); fileInput.onchange = function(ev){ let file = ev.target.files[0], fr = new FileReader(); fr.readAsArrayBuffer(file); fr.onload = function(data){ let result = data.target.result; //解码ArrayBuffer audioCtx.decodeAudioData(result, getBuffer); }; }; //修改音量大小 add.onclick = function(){ gainNode.gain.value += 0.1; }; lost.onclick = function(){ gainNode.gain.value -= 0.1; } function getBuffer(audioBuffer){ //建立对象,用过AudioBuffer对象来播放音频数据 let source = audioCtx.createBufferSource(); source.buffer = audioBuffer; //将source与analyser分析器链接 source.connect(analyser); //将analyser与gainNode分析器链接 analyser.connect(gainNode); //音量控制器与输出设备连接 gainNode.connect(recorder); recorder.connect(audioCtx.destination); //播放 source.start(0); draw(analyser); //音频采集 recorder.onaudioprocess = function (e) { /*输入流,必需要连接到输出流,audioCtx.destination才能有输出*/ let inputBuffer = e.inputBuffer, outputBuffer = e.outputBuffer; outputBuffer.copyToChannel(inputBuffer.getChannelData(0), 0, 0); outputBuffer.copyToChannel(inputBuffer.getChannelData(1), 1, 0); }; } let WIDTH = 500, HEIGHT = 500; //绘制波形图 function draw() { requestAnimationFrame(draw); //保存频率数据 let dataArray = new Uint8Array(analyser.fftSize), bufferLength = analyser.fftSize; //获取频域的输出信息 analyser.getByteTimeDomainData(dataArray); canvasCtx.fillStyle = 'rgb(200, 200, 200)'; canvasCtx.fillRect(0, 0, 500, 500); canvasCtx.lineWidth = 2; canvasCtx.strokeStyle = 'rgb(0, 0, 0)'; canvasCtx.beginPath(); var sliceWidth = WIDTH * 1.0 / bufferLength; var x = 0; for(var i = 0; i < bufferLength; i++) { var v = dataArray[i] / 128.0; var y = v * HEIGHT/2; if(i === 0) { canvasCtx.moveTo(x, y); } else { canvasCtx.lineTo(x, y); } x += sliceWidth; } canvasCtx.lineTo(canvas.width, canvas.height/2); canvasCtx.stroke(); }; </script> </html>
基本上咱们要用到的api都介绍完了,我想你们应该知道如何作音频转发了吧。下面一章就开始介绍音频流的转发了。
HTML5音频API Web Audio这一篇文章仍是能够看看的。
但愿你们多多支持,收藏点赞呀数组