7

前言

web音频流转发之音视频直播
web音频流转发之AudioNode
app能直播,web为什么不可以?看完本系列文章,你就能做一个直播,真正的直播,包括音频流的转发,这也是我最近查看web audio api发现有相关api能实现音频流的转发,所有打算分享系列文章供大家交流,如有不对之处请指正。看完本系列文章能完成一个web直播,当然包括视频流。当然webrtc也能实现web直播,但是实现原理有所差别。文章也很简单就是对web audio api的灵活使用。

兼容性

兼容性是有必要看下,顺便看一下ie,和安卓Android Browse的兼容性,然而我想说我的荣耀8 安卓6.0 还是嵌套的chrome 37你们信吗?到底是作为一个渐渐增强的功能,还是作为一个装逼技能就看大家的使用啦!
图片描述

概述

一个简单而典型的web audio流程如下:
1.创建音频上下文
2.在音频上下文里创建源 — 例如 <audio>, 振荡器, 流
3.创建效果节点,例如混响、双二阶滤波器、平移、压缩
4.为音频选择一个目地,例如你的系统扬声器
5.连接源到效果器,对目的地进行效果输出
图片描述
这段话引用自MDN,这一章我主要讲解inputs中的3个api。

createMediaElementSource

下面是一个简单到极点的例子,完成了从audio获取音频源,然后输出到你的扬声器设备。
这个方法我们在直播中做用不到。

//创建音频上下文
let audioCtx = new (window.AudioContext || window.webkitAudioContext)(),
    //获取audio节点
    myAudio = document.querySelector('audio'),
    //创建音频源
    source = audioCtx.createMediaElementSource(myAudio),
    //将音频源直接连接到输出设备
    source.connect(audioCtx.destination);

createMediaStreamSource

这个方法介绍的是用navigator.mediaDevices.getUserMedia(navigator.getUserMedia已经废弃)获取到的音频流作为音频流。在直播时我们会采用此方法作为,音频流的采集方法;当然在这里我们也会获取到我们需要的视频流数据

 //简单兼容
 let getUserMedia = navigator.mediaDevices.getUserMedia || navigator.getUserMedia;
 //获取麦克风,摄像头权限
 getUserMedia({audio: true, video: true}).then(stream => {
    let audioCtx = new AudioContext(),
        //以流媒体作为音频源
        source = audioCtx.createMediaStreamSource(stream);
        //将音频源直接连接到输出设备
        source.connect(audioCtx.destination);
    });

createBufferSource

这个方法相对前面两个稍微复杂一点点。createBufferSource是由存储器中的音频数据组成的音频源,它通过AudioBuffer来进行存储,解释一下:它是通过一个固定的音频数据的二进制作为音频源,比如一首歌的二进制数据。

  let audioCtx = new (window.AudioContext || window.webkitAudioContext)(),  
  source = audioCtx.createBufferSource();
  //myArrayBuffer是一个AudioBuffer
  source.buffer = myArrayBuffer;
  source.loop = true; //循环播放
  source.connect(audioCtx.destination);
  source.start(); //开始播放音频源

下面讲讲myArrayBuffer的几种来源方式

//1.通过input=file 获取的音频文件
let fileInput = document.querySelector('input'),
    audioCtx = new (window.AudioContext || window.webkitAudioContext)();
    fileInput.onchange = function(ev){
        let file = ev.target.files[0],
        fr = new FileReader();
        fr.readAsArrayBuffer(file);
        fr.onload = function(data){
            //result是一个arraybuffer类型二进制数据
            let result = data.target.result;
            //解析数据
            analyticBuffer(result);
        };
    };
//2.通过XHR获取音频数据(注意需要返回arraybuffer类型)
  let request = new XMLHttpRequest();
  request.open('GET', 'xxx.mp3', true);
  //指定文件返回数据类型
  request.responseType = 'arraybuffer'; 
  //请求成功时执行
  request.onload = function() {
    //这是一个arraybuffer
    var buffer = request.response;
    //解析数据
    analyticBuffer(buffer )
  }
  request.send();

  //解析二进制数据
  function analyticBuffer(buffer){
    //将ArrayBuffer异步转换为一个AudioBuffer类型
    audioCtx.decodeAudioData(buffer, (myArrayBuffer) => {
          let source  = audioCtx.createBufferSource();
            source.buffer = myArrayBuffer;
            source.connect(audioCtx.destination);
            source.start();
    });
   }
//3.自己创造一个AudioBuffer
    //采样率sample/s
let sampleRate = audioCtx.sampleRate, 
    //帧数,音频时间 = frameCount / sampleRate
    frameCount = audioCtx.sampleRate * 2.0, 
    //创建一个两通道的音频数据,这是一个没有声音的音频数据
    myArrayBuffer = audioCtx.createBuffer(2, frameCount , sampleRate);
    //随机填充白噪音
        //两个通道循环2次
    for (var channel = 0; channel < 2; channel++) {
        //获取每个通道的array数据
        var nowBuffering = myArrayBuffer.getChannelData(channel);
        for (let i = 0; i < frameCount; i++) {
          //对每一帧填充数据
          nowBuffering[i] = Math.random() * 2 - 1;
        }
  }

AudioBuffer的属性和方法

AudioBuffer的方法在我们直播的时候需要用到,在后面的AudioNode(音频处理模块)中也会出现AudioBuffer数据,我们需要它是获取和传输数据

 let myArrayBuffer = audioCtx.createBuffer(2, 4096, sampleRate);
    myArrayBuffer.sampleRate //采样数
    myArrayBuffer.length //采样帧率 也就是4096
    myArrayBuffer.duration //时长
    myArrayBuffer.numberOfChannels //通道数
    //返回x通道的Float32Array类型的数据,x表示是哪个通道0或1
    myArrayBuffer.getChannelData(x) 
    //将myArrayBuffer第x通道的数据复制到anotherArray中,y表示数据复制开始的偏移量
    let anotherArray = new Float32Array;
    myArrayBuffer.copyFromChannel(anotherArray,x,y);
    //将anotherArray数据复制到myArrayBuffer的X通道中,y偏移量
    let anotherArray = new Float32Array;
    myArrayBuffer.copyToChannel(anotherArray,x,y);
    //关于copyToChannel,copyFromChannel,getChannelData在下一章看见例子就明白了

结束语

这一章大概就说到这么多吧,都是一些简单的api使用,下一章结合以后例子讲解部分AudioNode。


嘻倪孢
342 声望24 粉丝

快乐就好!