H5网页实现录音并转换为文字

H5网页实现录音并转换为文字

前言

     在上篇文章中实现了通过本地的音频文件来识别语音,下面我们对于这个Demo做进一步的扩展,直接通过网页录音并识别。
在这里插入图片描述

内容

     如下是Html部分的代码,主要用来设置录音机样式以及引用了 专门用来采集音频的JS文件(HZRecorder.js)

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
</head>
<body>
    <div>
        <audio controls autoplay></audio>
        <input onclick="startRecording()" type="button" value="录音" />
        <input onclick="stopRecording()" type="button" value="停止" />
        <input onclick="playRecording()" type="button" value="播放" />
        <input onclick="uploadAudio()" type="button" value="提交" />
    </div>

    <script type="text/javascript" src="HZRecorder.js"></script>


    <script>
        var recorder;
        var audio = document.querySelector('audio');
        function startRecording() {
            HZRecorder.get(function (rec) {
                recorder = rec;
                recorder.start();
            });
        }
        function stopRecording() {
            recorder.stop();
        }
        function playRecording() {
            recorder.play(audio);
        }
        function uploadAudio() {
            recorder.upload("Handler1.ashx", function (state, e) {
                switch (state) {
                    case 'uploading':
                        var percentComplete = Math.round(e.loaded * 100 / e.total) + '%';
                        break;
                    case 'ok':
                        alert("上传成功");
                        break;
                    case 'error':
                        alert("上传失败");
                        break;
                    case 'cancel':
                        alert("上传被取消");
                        break;
                }
            });
        }
    </script>
</body>
</html>

     这份JS音频采集代码来自网上参考很多方法被淘汰了,所以做了一定的修改和补充,现在可以根据采样率以及采样位数录制特定的音频文件。本篇将采集到的音频流转成了wav的格式。如下是完整的JS代码:

(function (window) {
    window.URL = window.URL || window.webkitURL;
    navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;

    var HZRecorder = function (stream, config) {
        config = config || {};
        config.sampleBits = config.sampleBits || 8;      // 采样数位
        config.sampleRate = config.sampleRate || (44100 / 6);   // 采样率
        var context = new (window.webkitAudioContext || window.AudioContext)();
        var audioInput = context.createMediaStreamSource(stream);
        var createScript = context.createScriptProcessor || context.createJavaScriptNode;
        var recorder = createScript.apply(context, [4096, 1, 1]);
        var audioData = {
            size: 0          // 录音文件长度
            , buffer: []     // 录音缓存
            , inputSampleRate: context.sampleRate    // 输入采样率
            , inputSampleBits: 16       // 输入采样数位 
            , outputSampleRate: config.sampleRate    // 输出采样率
            , oututSampleBits: config.sampleBits       // 输出采样数位 
            , input: function (data) {
                this.buffer.push(new Float32Array(data));
                this.size += data.length;
            }
            , compress: function () { 
                //合并
                var data = new Float32Array(this.size);
                var offset = 0;
                for (var i = 0; i < this.buffer.length; i++) {
                    data.set(this.buffer[i], offset);
                    offset += this.buffer[i].length;
                }
                //压缩
                var compression = parseInt(this.inputSampleRate / this.outputSampleRate);
                var length = data.length / compression;
                var result = new Float32Array(length);
                var index = 0, j = 0;
                while (index < length) {
                    result[index] = data[j];
                    j += compression;
                    index++;
                }
                return result;
            }
            , encodeWAV: function () {
                var sampleRate = Math.min(this.inputSampleRate, this.outputSampleRate);
                var sampleBits = Math.min(this.inputSampleBits, this.oututSampleBits);
                var bytes = this.compress();
                var dataLength = bytes.length * (sampleBits / 8);
                var buffer = new ArrayBuffer(44 + dataLength);
                var data = new DataView(buffer);

                var channelCount = 1; // 单声道
                var offset = 0;

                var writeString = function (str) {
                    for (var i = 0; i < str.length; i++) {
                        data.setUint8(offset + i, str.charCodeAt(i));
                    }
                }
                
                // 资源交换文件标识符 
                writeString('RIFF'); offset += 4;
                // 下个地址开始到文件尾总字节数,即文件大小-8 
                data.setUint32(offset, 36 + dataLength, true); offset += 4;
                // WAV文件标志
                writeString('WAVE'); offset += 4;
                // 波形格式标志 
                writeString('fmt '); offset += 4;
                // 过滤字节,一般为 0x10 = 16 
                data.setUint32(offset, 16, true); offset += 4;
                // 格式类别 (PCM形式采样数据) 
                data.setUint16(offset, 1, true); offset += 2;
                // 通道数 
                data.setUint16(offset, channelCount, true); offset += 2;
                // 采样率,每秒样本数,表示每个通道的播放速度 
                data.setUint32(offset, sampleRate, true); offset += 4;
                // 波形数据传输率 (每秒平均字节数) 单声道×每秒数据位数×每样本数据位/8 
                data.setUint32(offset, channelCount * sampleRate * (sampleBits / 8), true); offset += 4;
                // 快数据调整数 采样一次占用字节数 单声道×每样本的数据位数/8 
                data.setUint16(offset, channelCount * (sampleBits / 8), true); offset += 2;
                // 每样本数据位数 
                data.setUint16(offset, sampleBits, true); offset += 2;
                // 数据标识符 
                writeString('data'); offset += 4;
                // 采样数据总数,即数据总大小-44 
                data.setUint32(offset, dataLength, true); offset += 4;
                // 写入采样数据 
                if (sampleBits === 8) {
                    for (var i = 0; i < bytes.length; i++, offset++) {
                        var s = Math.max(-1, Math.min(1, bytes[i]));
                        var val = s < 0 ? s * 0x8000 : s * 0x7FFF;
                        val = parseInt(255 / (65535 / (val + 32768)));
                        data.setInt8(offset, val, true);
                    }
                } else {
                    for (var i = 0; i < bytes.length; i++, offset += 2) {
                        var s = Math.max(-1, Math.min(1, bytes[i]));
                        data.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
                    }
                }

                return new Blob([data], { type: 'audio/wav' });
            }
        };

        // 开始录音
        this.start = function () {
            audioInput.connect(recorder);
            recorder.connect(context.destination);
        }

        // 暂停
        this.stop = function () {
            recorder.disconnect();
        }

        // 获取音频文件
        this.getBlob = function () {
            this.stop();
            return audioData.encodeWAV();
        }

        // 播放
        this.play = function (audio) {
            audio.src = window.URL.createObjectURL(this.getBlob());
        }

        // 上传
        this.upload = function (url, callback) {
            var fd = new FormData();
            fd.append("audioData", this.getBlob());
            var xhr = new XMLHttpRequest();
            if (callback) {
                xhr.upload.addEventListener("progress", function (e) {
                    callback('uploading', e);
                }, false);
                xhr.addEventListener("load", function (e) {
                    callback('ok', e);
                }, false);
                xhr.addEventListener("error", function (e) {
                    callback('error', e);
                }, false);
                xhr.addEventListener("abort", function (e) {
                    callback('cancel', e);
                }, false);
            }
            xhr.open("POST", url);
            xhr.send(fd);
        }

        // 音频采集
        recorder.onaudioprocess = function (e) {
            audioData.input(e.inputBuffer.getChannelData(0));
        }

    };
    // 抛出异常
    HZRecorder.throwError = function (message) {
        alert(message);
        throw new function () { this.toString = function () { return message; } }
    }
    // 是否支持录音
    HZRecorder.canRecording = (navigator.getUserMedia != null);
    // 获取录音机
    HZRecorder.get = function (callback, config) {
        if (callback) {
            if (navigator.getUserMedia) {
                navigator.getUserMedia(
                    { audio: true } // 启用音频
                    , function (stream) {
                        var rec = new HZRecorder(stream, config);
                        callback(rec);
                    }
                    , function (error) {
                        switch (error.code || error.name) {
                            case 'PERMISSION_DENIED':
                            case 'PermissionDeniedError':
                                console.log('用户拒绝提供信息。');
                                break;
                            case 'NOT_SUPPORTED_ERROR':
                            case 'NotSupportedError':
                                console.log('浏览器不支持硬件设备。');
                                break;
                            case 'MANDATORY_UNSATISFIED_ERROR':
                            case 'MandatoryUnsatisfiedError':
                                console.log('无法发现指定的硬件设备。');
                                break;
                            default:
                                console.log('无法打开麦克风。异常信息:' + (error.code || error.name));
                                break;
                        }
                    });
            } else {
                console.log('当前浏览器不支持录音功能。');
                return;
            }
        }
    }
    window.HZRecorder = HZRecorder;
})(window);

小结

      H5页面添加了一个录音机,从录制暂停回放到语音识别一条龙服务有没有很贴心,荣幸与您分享~

  • 6
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论
要在原生的 H5实现录音和录视频,可以使用 MediaStream API 和 getUserMedia() 方法。这些 API 可以访问设备上的摄像头和麦克风,并将捕获的媒体流转换为可用于录制或播放的数据。 下面是一个简单的示例,演示如何使用 H5 实现录音并将其上传: ```html <!DOCTYPE html> <html> <head> <title>录音上传示例</title> </head> <body> <button id="record">开始录音</button> <button id="stop">停止录音</button> <button id="upload">上传录音</button> <audio id="audio" controls></audio> <script> let mediaRecorder; let chunks = []; const constraints = { audio: true }; const recordBtn = document.getElementById('record'); const stopBtn = document.getElementById('stop'); const uploadBtn = document.getElementById('upload'); const audio = document.getElementById('audio'); recordBtn.addEventListener('click', async () => { try { const stream = await navigator.mediaDevices.getUserMedia(constraints); mediaRecorder = new MediaRecorder(stream); mediaRecorder.addEventListener('dataavailable', e => { chunks.push(e.data); }); mediaRecorder.addEventListener('stop', () => { const blob = new Blob(chunks, { type: 'audio/mp3' }); chunks = []; audio.src = URL.createObjectURL(blob); }); mediaRecorder.start(); } catch (error) { console.error(error); } }); stopBtn.addEventListener('click', () => { mediaRecorder.stop(); }); uploadBtn.addEventListener('click', () => { const blob = new Blob(chunks, { type: 'audio/mp3' }); const formData = new FormData(); formData.append('file', blob, 'recording.mp3'); fetch('/upload', { method: 'POST', body: formData }).then(response => { console.log('录音上传成功!'); }).catch(error => { console.error('录音上传失败:', error); }); }); </script> </body> </html> ``` 在这个示例中,我们创建了三个按钮:开始录音、停止录音和上传录音。当用户单击“开始录音”按钮时,我们使用 getUserMedia() 方法获取麦克风的访问权限,并创建一个 MediaRecorder 对象来录制音频。每当 MediaRecorder 对象接收到新的音频数据时,我们将其存储在一个数组中。当用户单击“停止录音”按钮时,我们停止录制,并将存储的音频数据转换为 Blob 对象。最后,当用户单击“上传录音”按钮时,我们将 Blob 对象作为表单数据发送到服务器。 类似地,你可以用类似的方法来实现录制视频。只需要将 constraints 对象中的 audio 属性改为 video 即可。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

格林希尔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值