笔记

万物寻其根,通其堵,便能解其困。
  博客园  :: 新随笔  :: 管理

h5录音 笔记

Posted on 2024-07-17 11:12  草妖  阅读(4)  评论(0)    收藏  举报

笔记参照来源,建议跳转查看更加详细详情:前端实现在浏览器网页中录音 - 浅笑· - 博客园 (cnblogs.com)

record.html

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>H5录音组件收录</title>
    <link rel="stylesheet" type="text/css" href="./PlugIn/tipsDialogTypeG/tipsDialogTypeG.css">
    <style type="text/css">
        html, body, #paperFrame {
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
            overflow: hidden;
        }
        .header-area {
            width: 100%;
            height: 50px;
        }
        .header-area-title {
            width: calc(100% - 150px);
            height: 50px;
            line-height: 50px;
            text-align: left;
            padding-left: 10px;
            float: left;
            font-weight: bold;
            font-size: 20px;
        }
        .header-area-close {
            width: 30px;
            height: 50px;
            float: right;
            margin-right: 10px;
            background-image: url("./Images/关闭1.png");
            background-repeat: no-repeat;
            background-position: right 13px;
        }
        .header-area-close:hover {
            background-image: url("./Images/关闭1【经过】.png");
            cursor: pointer;
        }
        .setting-info-area{
            width: 100%;
            height: 50px;
            overflow: hidden;
        }
        .setting-btn{
            padding: 0 15px;
            height: 30px;
            line-height: 30px;
            float: left;
            margin-left: 15px;
            background-color: #409eff;
            color: white;
            border-radius: 5px;
        }
        .setting-btn:hover{
            cursor: pointer;
        }
    </style>
</head>
<body>
    <div id="paperFrame">
        <div class="header-area">
            <div class="header-area-title">H5录音组件收录</div>
            <div class="header-area-close" @click="testCloseFrame"></div>
        </div>
        <div class="setting-info-area">
            <div class="setting-btn recoding-btn" @click="recodingBtn">录音</div>
            <div class="setting-btn recoded-btn" @click="recodedBtn">结束</div>
            <div class="setting-btn upload-btn" @click="uploadBtn">上传</div>
        </div>
        <audio v-if="audioUrl" controls :src="audioUrl"></audio>
    </div>
    <script type="text/javascript" src="./JS/jquery-1.12.4.min.js"></script>
    <script type="text/javascript" src="./JS/vue.2.5.17.min.js"></script>
    <script type="text/javascript" src="./JS/vuescroll.js"></script>
    <script type="text/javascript" src="./PlugIn/tipsDialogTypeG/tipsDialogTypeG.js"></script>
    <script type="text/javascript">
        var paperFrame = new Vue({
            el: "#paperFrame",
            data: {
                constraints:{audio: true},
                mediaRecorder:null,
                recodChunks:[],
                audioUrl:null,
                audioFile:null,
            },
            methods: {
                // 上传
                uploadBtn:function (){
                    if(this.audioFile==null){
                        return;
                    }
                    /* 通过节点获取文件
                    var files = $('.div-cls')[0].files;
                    var uploadFiles = new FormData();
                    uploadFiles.append('uploadFiles', files);
                    */
                    //上传文件
                    var uploadFiles = new FormData();
                    uploadFiles.append('uploadFiles', this.audioFile);
                    $.ajax({
                        method: 'POST',
                        url: 'http://127.0.0.1:8080/api/Resource/upLoadFiles',
                        data: uploadFiles,
                        processData: false,
                        contentType: false,
                        success: function (res) {
                            console.log("上传文件成功!!!");
                            console.log(res);
                        },
                        error: function(jqXHR, textStatus, errorThrown) {
                            console.log("上传文件失败!!!");
                            console.log(textStatus,errorThrown);
                        }
                    })
                },
                // 结束
                recodedBtn:function (){
                    var _this=this;
                    try{
                        _this.mediaRecorder.stop();
                        console.log(_this.recodChunks)
                        _this.mediaRecorder.onstop = e => {
                            /** 文本
                             * // 假设你已经有了一个Blob对象
                             * const blob = new Blob(["Hello, world!"], { type: "text/plain" });
                             *
                             * // 创建File对象
                             * const file = new File([blob], "hello-world.txt", {
                             *   lastModified: new Date().getTime(),
                             *   type: blob.type
                             * });
                             * */
                            // 音频
                            var blob = new Blob(_this.recodChunks, {type: "audio/ogg; codecs=opus"});
                            // 合成音频文件
                            _this.audioFile=new File([blob], "1.mp3", {
                                lastModified: new Date().getTime(),
                                type: blob.type
                            });
                            // 合成音频路径
                            _this.audioUrl = window.URL.createObjectURL(blob);
                        };
                        console.log("录音结束");
                        tipsDialogGcomponent.dialogShow({
                            type: 3,
                            content: "录音结束",
                            timeOut: 3000
                        });
                    }catch (e){
                        tipsDialogGcomponent.dialogShow({
                            type: 1,
                            content: e,
                            timeOut: 3000
                        });
                    }
                },
                // 录音
                recodingBtn:function (){
                    try{
                        this.mediaRecorder.start();
                        var _this=this;
                        _this.recodChunks = [];
                        this.mediaRecorder.ondataavailable = function (e) {
                            _this.recodChunks.push(e.data);
                        };
                        this.mediaRecorder.onerror = (event) => {
                            // 当发生错误时调用
                            // 错误信息可以通过 event.error 获取
                            console.log(event);
                            console.log(event.error);
                        };
                        console.log("录音中...");
                    }catch (e) {
                        tipsDialogGcomponent.dialogShow({
                            type: 1,
                            content: e,
                            timeOut: 3000
                        });
                    }
                },
                // 关闭窗体
                testCloseFrame: function () {
                    try{
                        window.controllers.closeFrame(1);
                    }catch (e) {
                        tipsDialogGcomponent.dialogShow({
                            type: 1,
                            content: e,
                            timeOut: 3000
                        });
                    }
                },
            },
            created: function () {
            },
            //el挂载完后调用
            mounted: function () {
                var _this=this;
                try{
                    navigator.mediaDevices.ondevicechange = () => {
                        console.log('设备发生变化');
                        tipsDialogGcomponent.dialogShow({
                            type: 3,
                            content: "设备发生变化!!!",
                            timeOut: 3000
                        });
                    };
                    navigator.mediaDevices.enumerateDevices().then(devices => {
                        const audioInputs = devices.filter(device => device.kind === 'audioinput');
                        console.log("当前可用的麦克风设备:");
                        for(let device of audioInputs) {
                            console.log(device);
                            console.log(device.label+"=>"+device.deviceId);
                        }
                        if(audioInputs.length==0){
                            console.log("没有可用的设备!");
                        }else{
                            console.log("检测麦克风已接入。");
                        }
                    });
                    navigator.mediaDevices.getUserMedia(_this.constraints).then(
                        stream => {
                            _this.mediaRecorder = new MediaRecorder(stream);
                            /**
                             * // 设置输出格式为音频
                             * mediaRecorder.mimeType = 'audio/webm';
                             * // 设置音频比特率为128kbps
                             * mediaRecorder.audioBitsPerSecond = 128000;
                             * */
                            _this.recodChunks = [];
                            tipsDialogGcomponent.dialogShow({
                                type: 3,
                                content: "授权成功!",
                                timeOut: 3000
                            });

                            /** 未验证 来源:https://zhuanlan.zhihu.com/p/26536898?from_voters_page=true */
                            var audioContext = window.AudioContext || window.webkitAudioContext;
                            var context = new audioContext(); //创建一个管理、播放声音的对象
                            var liveSource = context.createMediaStreamSource(stream); //将麦克风的声音输入这个对象
                            var levelChecker = context.createScriptProcessor(4096,1,1); //创建一个音频分析对象,采样的缓冲区大小为4096,输入和输出都是单声道
                            liveSource.connect(levelChecker); //将该分析对象与麦克风音频进行连接
                            levelChecker.connect(context.destination); // 此举无甚效果,仅仅是因为解决 Chrome 自身的 bug

                            levelChecker.onaudioprocess = function(e) {
                                //开始处理音频
                                var buffer = e.inputBuffer.getChannelData(0); //获得缓冲区的输入音频,转换为包含了PCM通道数据的32位浮点数组
                                //创建变量并迭代来获取最大的音量值
                                var maxVal = 0;
                                for (var i = 0; i < buffer.length; i++) {
                                    if (maxVal < buffer[i]) {
                                        maxVal = buffer[i];
                                    }
                                }
                                //显示音量值
                                console.log("您的音量值:"+Math.round(maxVal*100));
                                if(maxVal>.5){
                                    console.log("您的声音太响了!!");
                                    //当音量值大于0.5时,显示“声音太响”字样,并断开音频连接
                                    console.log("您的声音太响了!!");
                                    liveSource.disconnect(levelChecker);
                                }
                            };
                        },
                        () => {
                            console.error("授权失败!");
                            tipsDialogGcomponent.dialogShow({
                                type: 3,
                                content: "授权失败!",
                                timeOut: 3000
                            });
                        }
                    );
                }catch (e) {
                    tipsDialogGcomponent.dialogShow({
                        type: 1,
                        content: e,
                        timeOut: 3000
                    });
                }
                /** 原始数据,来源:https://www.cnblogs.com/qianxiaox/p/14973950.html
                 * 也可以参照:https://imangodoc.com/K4VjVUvb.html
                if (navigator.mediaDevices.getUserMedia) {
                    const constraints = {audio: true};
                    navigator.mediaDevices.getUserMedia(constraints).then(
                        stream => {
                            console.log("授权成功!");
                            const recordBtn = document.querySelector(".record-btn");
                            const mediaRecorder = new MediaRecorder(stream);
                            var chunks = [];
                            recordBtn.onclick = () => {
                                if (mediaRecorder.state === "recording") {
                                    mediaRecorder.stop();
                                    console.log(chunks)
                                    mediaRecorder.onstop = e => {
                                        var blob = new Blob(chunks, {type: "audio/ogg; codecs=opus"});
                                        chunks = [];
                                        var audioURL = window.URL.createObjectURL(blob);
                                        const audioSrc = document.querySelector(".audio-player");
                                        audioSrc.src = audioURL;
                                    };
                                    recordBtn.textContent = "record";
                                    console.log("录音结束");
                                } else {
                                    mediaRecorder.start();
                                    mediaRecorder.ondataavailable = function (e) {
                                        chunks.push(e.data);
                                    };
                                    console.log(chunks)
                                    console.log("录音中...");
                                    recordBtn.textContent = "stop";
                                }
                                console.log("录音器状态:", mediaRecorder.state);
                            };

                        },
                        () => {
                            console.error("授权失败!");
                        }
                    );
                } else {
                    console.error("浏览器不支持 getUserMedia");
                }
                */
            }
        });
    </script>
</body>
</html>

 

 

 

后台接收

@RequestMapping(value = "/upLoadFiles", method = RequestMethod.POST)public String upLoadFiles(HttpServletRequest req, MultipartFile[] uploadFiles) {
        ApiResponseV1<List<String>> _data = new ApiResponseV1<>();
        try {
            ***
        } catch (Exception err) {
            ***
        }
        return ***;
    }

 

待续。。。