10.WebRTC实现网页录音功能

一、概述

通过WebRTC,实现在页面上进行录音,并将录音结果转换为.wav格式进行播放

二、录音实现

  1. 检测是否有麦克风权限
navigator.mediaDevices.enumerateDevices().then(function(devices) {
        // 检测视频输入
        let video = devices.find((device) => {
            return device.kind === 'videoinput'
        })
        // 检测音频输入
        let audio = devices.find((device) => {
            return device.kind === 'audioinput'
        })
        // getUserMedia的参数
        let mediaConstraints = {
            video: !!video,
            audio: !!audio
        }
        let constraints = { video: video && mediaConstraints.video, audio: audio && mediaConstraints.audio }
        return navigator.mediaDevices.getUserMedia(constraints).then(mediaStream => {
            stream = mediaStream // stream 记录音频流,在停止录音等时使用
            // 开始录音...
            beginRecord(mediaStream )
        })
    })
  1. 调用getUserMedia方法,获取音频流,并开始录音
// 录音
function beginRecord(mediaStream) {
    let audioContext = new (window.AudioContext || window.webkitAudioContext)
    let mediaNode = audioContext.createMediaStreamSource(mediaStream)
    // 创建一个jsNode
    let jsNode = createJSNode(audioContext)
    // 需要连接扬声器消费到outputBuffer, process回调才能出发,且不给outputBuffer设置内容扬声器不会播出声音
    jsNode.connect(audioContext.destination)
    jsNode.onaudioprocess = (audioProcessingEvent) => {
        let audioBuffer = audioProcessingEvent.inputBuffer
        let leftChannelData = audioBuffer.getChannelData(0) // 左声道
        let rightChannelData = audioBuffer.getChannelData(1) // 右声道
        // 将音频数据存入dataList
        dataList.left.push(leftChannelData.slice(0))
        dataList.right.push(rightChannelData.slice(0))
    }
    // 把mediaNode连接到jsNode
    mediaNode.connect(jsNode)
}

以上步骤完成,便开始录音,并且将音频数据存入了dataList数组中。

到这一步,其实录音的工作已经完成了。下面的工作是将录音数据保存成特定格式(如.mp3),并插入到页面的audio元素中进行播放。

三、停止录音

停止录音需要做三个工作:

  1. 合并数据
  2. 创建指定格式的文件
  3. 录音播放

停止录音的总体方法为:

function stopRecord() {
    let leftData = mergeArray(dataList.left)
    let rightData = mergeArray(dataList.right)
    let allData = intervalLeftAndRight(leftData, rightData) // 合并数据
    let wavBuffer = createWavFile(allData) // 创建指定格式的数据
    playRecord(wavBuffer) // 播放录音
    
}

下面按照具体步骤实现。

  1. 合并数据
// 交叉合并左右声道的数据
function intervalLeftAndRight(left, right) {
    let totalLength = left.length + right.length
    let data = new Float32Array(totalLength)
    for(let i = 0; i < left.length; i++) {
        let k = i * 2
        data[k] = left[i]
        data[k + 1] = right[i]
    }
    return data
}

function mergeArray(list) {
    let length = list.length * list[0].length
    let data = new Float32Array(length)
    let offset = 0
    for(let i = 0; i < list.length; i++) {
        data.set(list[i], offset)
        offset += list[i].length
    }
    return data
}
  1. 创建指定格式的文件,这一块的代码是完全从网上找的资料,具体出处地址不记得了。此处是创建.wav文件
function createWavFile(audioData) {
    const WAV_HEAD_SIZE = 44
    let buffer = new ArrayBuffer(audioData.length * 2 + WAV_HEAD_SIZE)
    let view = new DataView(buffer)
    // 写入wav头部信息
    writeUTFBytes(view, 0, 'RIFF')
    view.setUint32(4, 44 + audioData.length * 2, true)
    writeUTFBytes(view, 8, 'WAVE')
    writeUTFBytes(view, 12, 'fmt ');
    view.setUint32(16, 16, true);
    view.setUint16(20, 1, true);
    view.setUint16(22, 2, true);
    view.setUint32(24, 44100, true);
    view.setUint32(28, 44100 * 2, true);
    view.setUint16(32, 2 * 2, true);
    view.setUint16(34, 16, true);
    writeUTFBytes(view, 36, 'data');
    view.setUint32(40, audioData.length * 2, true);

    // 写入wav头部,代码同上
    let length = audioData.length;
    let index = 44;
    let volume = 1;
    for (let i = 0; i < length; i++) {
        view.setInt16(index, audioData[i] * (0x7FFF * volume), true);
        index += 2;
    }
    return buffer;
}

function writeUTFBytes(view, offset, string) {
    var lng = string.length;
    for (var i = 0; i < lng; i++) { 
        view.setUint8(offset + i, string.charCodeAt(i));
    }
}
  1. 录音播放
function playRecord(arrayBuffer) {
    let blob = new Blob([new Uint8Array(arrayBuffer)])
    let blobUrl = URL.createObjectURL(blob); // 创建BlobURL
    document.querySelector('.audio-node').src = blobUrl // 插入到页面的音频播放组件
}

四、关闭录音功能

在停止录音的时候,浏览器的录音功能是需要手动关闭的,否则会在浏览器顶部出现录音的红色点点,下图这样的:

在这里插入图片描述

关闭录音功能的方法:

stream.getTracks().forEach(track => {
    if(track.readyState === 'live') {
        track.stop()
    }
})

以上,就是一个完整的web端录音功能的实现。

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值