HTML5声音录制和播放功能的实现

本文通过实例代码给大家介绍了HTML5声音录制/播放功能,非常不错,具有参考借鉴价值,需要的朋友跟随脚本之家小编一起学习吧

html代码:

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>火星黑洞</title>
    </head>
    <body>
        <p>
            <audio 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="提交" />
            <br />
            <p id="recordingslist"></p>
        </p>
        <script type="text/javascript" src="js/HZRecorder.js"></script>
        <script>
            var recorder;
            var audio = document.querySelector('audio');
            function startRecording() {
                HZRecorder.get(function(rec) {
                    recorder = rec;
                    recorder.start();
                }, {
                    sampleBits: 16,
                    sampleRate: 16000
                });
            }
            function stopRecording() {
                recorder.stop();
                var blob = recorder.getBlob();
                var url = URL.createObjectURL(blob);
                var p = document.createElement('p');
                var au = document.createElement('audio');
                var hf = document.createElement('a');
                au.controls = true;
                au.src = url;
                hf.href = url;
                hf.download = new Date().toISOString() + '.wav';
                hf.innerHTML = hf.download;
                p.appendChild(au);
                p.appendChild(hf);
                recordingslist.appendChild(p);
            }
            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(e.target.responseText);
                            alert("上传成功");
                            break;
                        case 'error':
                            alert("上传失败");
                            break;
                        case 'cancel':
                            alert("上传被取消");
                            break;
                    }
                });
            }
        </script>
    </body>
</html>

HZRecorder.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      //采样数位 8, 16
        config.sampleRate = config.sampleRate || (44100 / 6);   //采样率(1/6 44100)
        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 mp3ReceiveSuccess, currentErrorCallback;
        var audioData = {
            size: 0          //录音文件长度
            , buffer: []     //录音缓存
            , inputSampleRate: context.sampleRate    //输入采样率
            , inputSampleBits: 16       //输入采样数位 8, 16
            , outputSampleRate: config.sampleRate    //输出采样率
            , oututSampleBits: config.sampleBits       //输出采样数位 8, 16
            , 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));
            //record(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':
                                HZRecorder.throwError('用户拒绝提供信息。');
                                break;
                            case 'NOT_SUPPORTED_ERROR':
                            case 'NotSupportedError':
                                HZRecorder.throwError('浏览器不支持硬件设备。');
                                break;
                            case 'MANDATORY_UNSATISFIED_ERROR':
                            case 'MandatoryUnsatisfiedError':
                                HZRecorder.throwError('无法发现指定的硬件设备。');
                                break;
                            default:
                                HZRecorder.throwError('无法打开麦克风。异常信息:' + (error.code || error.name));
                                break;
                        }
                    });
            } else {
                HZRecorder.throwErr('当前浏览器不支持录音功能。'); return;
            }
        }
    }
    window.HZRecorder = HZRecorder;
})(window);

以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注编程之家!

相关推荐:

如何解决HTML5 虚拟键盘出现挡住输入框的问题

关于HTML5和CSS3实现机器猫的代码

以上就是HTML5声音录制和播放功能的实现的详细内容,更多请关注编程之家其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


HTML5和CSS3实现3D展示商品信息的代码
利用HTML5中的Canvas绘制笑脸的代码
Html5剪切板功能的实现
如何通过HTML5触摸事件实现移动端简易进度条
Html5移动端获奖无缝滚动动画实现
关于HTML5和CSS3实现机器猫的代码
HTML5使用DOM进行自定义控制
使用HTML5 Canvas绘制阴影效果的方法
使用PHP和HTML5 FormData实现无刷新文件上传
如何解决HTML5 虚拟键盘出现挡住输入框的问题
HTML5中div和section以及article的区别分析
html5和CSS 实现禁止IOS长按复制粘贴功能
html5 touch事件实现触屏页面上下滑动
canvas 模拟实现电子彩票刮刮乐的代码
HTML5 Plus 实现手机APP拍照或相册选择图片上传的功能
Android自定义环形LoadingView效果
HTML5 canvas绘制五角星的方法
html5使用html2canvas实现浏览器截图
使用Canvas处理图片的方法介绍
利用Canvas模仿百度贴吧客户端loading小球的方法