录音的类 复制即用 解决录音文件渲染没显示总时长问题

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta name="apple-mobile-web-capable" content="yes">
    <title>WEB录音机</title>

</head>

<body>
<button onclick="test66.record()">开始录音</button>
<button onclick="test66.stopRecord()">停止录音</button>
<button onclick="test66.bofangRecord()">播放录音</button>
<button onclick="test66.recordClose()">关闭录音</button>
<audio class="audio-node" controls autoplay></audio>
</body>
<script type="text/javascript">
    const recordObj = class record {


        constructor() {
            console.log('new了')
            this.recordData = {
                mediaStream: null,
                mediaNode: null,
                jsNode: null
            };
            this.leftDataList = [];
            this.rightDataList = [];
            console.log(this.recordData, 'this.recordData', this.leftDataList, 'this.leftDataList', this.rightDataList, 'this.rightDataList')

        }
        record() {

            // console.log(this.recordData, 'this.recordData', this.leftDataList, 'this.leftDataList', this.rightDataList, 'this.rightDataList')
            window.navigator.mediaDevices.getUserMedia({
                audio: {
                    sampleRate: 44100, // 采样率
                    channelCount: 2,   // 声道
                    volume: 2.0        // 音量
                }
            }).then(mediaStream => {
                console.log(mediaStream);// 这里可以拿到mediaStream
                this.recordData.mediaStream = mediaStream
                this.beginRecord(this.recordData.mediaStream);
            }).catch(err => {
                // 如果用户电脑没有麦克风设备或者用户拒绝了,或者连接出问题了等
                // 这里都会抛异常,并且通过err.name可以知道是哪种类型的错误
                console.error(err);
            });
        }

        beginRecord(mediaStream) {
            let audioContext = new (window.AudioContext || window.webkitAudioContext);
            let mediaNode = audioContext.createMediaStreamSource(mediaStream);
            console.log(mediaNode)
            this.recordData.mediaNode = mediaNode
            // 这里connect之后就会自动播放了
            // mediaNode.connect(audioContext.destination);	//直接把录的音直接播放出来
            // 创建一个jsNode
            let jsNode = this.createJSNode(audioContext);
            this.recordData.jsNode = jsNode
            console.log(this.leftDataList,'this.leftDataList   beginRecord')
            // 需要连到扬声器消费掉outputBuffer,process回调才能触发
            // 并且由于不给outputBuffer设置内容,所以扬声器不会播放出声音
            jsNode.connect(audioContext.destination);
            jsNode.onaudioprocess = (event) => {
                this.onAudioProcess(event);
            }
            // 把mediaNode连接到jsNode
            mediaNode.connect(jsNode);
        }

        createJSNode(audioContext) {
            const BUFFER_SIZE = 4096;	//4096
            const INPUT_CHANNEL_COUNT = 2;
            const OUTPUT_CHANNEL_COUNT = 2;
            // createJavaScriptNode已被废弃
            let creator = audioContext.createScriptProcessor || audioContext.createJavaScriptNode;
            creator = creator.bind(audioContext);
            return creator(BUFFER_SIZE,
                INPUT_CHANNEL_COUNT, OUTPUT_CHANNEL_COUNT);
        }




        onAudioProcess(event) {
            // console.log(event.inputBuffer);
            let audioBuffer = event.inputBuffer;
            let leftChannelData = audioBuffer.getChannelData(0),
                rightChannelData = audioBuffer.getChannelData(1);
            console.log(leftChannelData, rightChannelData,this.leftDataList,'this.leftDataList');
            // 需要克隆一下
            this.leftDataList.push(leftChannelData.slice(0));
            this.rightDataList.push(rightChannelData.slice(0));
        }

        bofangRecord() {
            // 播放录音
            let leftData = this.mergeArray(this.leftDataList),
                rightData = this.mergeArray(this.rightDataList);
            if (leftData == null || leftData == null) {
                alert("请先录音再播放");
                return;
            }
            let allData = this.interleaveLeftAndRight(leftData, rightData);
            let wavBuffer = this.createWavFile(allData);
            this.playRecord(wavBuffer);
        }

        playRecord(arrayBuffer) {
            let blob = new Blob([new Uint8Array(arrayBuffer)]);
            let blobUrl = URL.createObjectURL(blob);
            document.querySelector('.audio-node').src = blobUrl;
            // 增加了下载功能
            const aLink = document.createElement('a')
            aLink.href = blobUrl
            // 文件名字
            aLink.download = '测试数据.mp3'
            document.body.appendChild(aLink)
            aLink.click()
            aLink.remove();
        }

        stopRecord() {
            // 停止录音
            this.recordData.mediaNode.disconnect();
            this.recordData.jsNode.disconnect();
            console.log("已停止录音")
            // console.log(this.leftDataList, this.rightDataList);
        }

        recordClose() {
            if (this.recordData.mediaStream == null || this.recordData.mediaStream.getAudioTracks() == null || this.recordData.mediaStream.getAudioTracks().length == 0) {
                return;
            }
            // 停止语音
            this.recordData.mediaStream.getAudioTracks()[0].stop();
            console.log("已停止语音")
        }

        mergeArray(list) {
            if (list == null || list.length == 0 || list[0] == null || list[0].length == 0) {
                return null;
            }
            let length = list.length * list[0].length;
            let data = new Float32Array(length),
                offset = 0;
            for (let i = 0; i < list.length; i++) {
                data.set(list[i], offset);
                offset += list[i].length;
            }
            return data;
        }

        interleaveLeftAndRight(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;
        }

        createWavFile(audioData) {// audioData是合并后的数据
            const WAV_HEAD_SIZE = 44;
            let buffer = new ArrayBuffer(audioData.length * 2 + WAV_HEAD_SIZE),
                // 需要用一个view来操控buffer
                view = new DataView(buffer);
            // 写入wav头部信息
            // RIFF chunk descriptor/identifier
            this.writeUTFBytes(view, 0, 'RIFF');
            // RIFF chunk length
            view.setUint32(4, 44 + audioData.length * 2, true);
            // RIFF type
            this.writeUTFBytes(view, 8, 'WAVE');
            // format chunk identifier
            // FMT sub-chunk
            this.writeUTFBytes(view, 12, 'fmt ');
            // format chunk length
            view.setUint32(16, 16, true);
            // sample format (raw)
            view.setUint16(20, 1, true);
            // stereo (2 channels)
            view.setUint16(22, 2, true);
            // sample rate
            view.setUint32(24, 44100, true);
            // byte rate (sample rate * block align)
            view.setUint32(28, 44100 * 2, true);
            // block align (channel count * bytes per sample)
            view.setUint16(32, 2 * 2, true);
            // bits per sample
            view.setUint16(34, 16, true);
            // data sub-chunk
            // data chunk identifier
            this.writeUTFBytes(view, 36, 'data');
            // data chunk length
            view.setUint32(40, audioData.length * 2, true);
            // 写入wav头部,代码同上
            // 写入PCM数据
            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;
        }

        writeUTFBytes(view, offset, string) {
            var lng = string.length;
            for (var i = 0; i < lng; i++) {
                view.setUint8(offset + i, string.charCodeAt(i));
            }
        }
    }

const test66= new recordObj()
</script>

</html>

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值