久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

js實(shí)現(xiàn)mp3錄音通過websocket實(shí)時傳送+簡易波形圖

 頭號碼甲 2021-10-14

在分享之前先貼上借鑒的大佬們的博客,感謝這些巨人,,關(guān)于錄音:https://blog.csdn.net/sweetsuzyhyf/article/details/50469881 

 
廢話:想不到我的第一篇博客是關(guān)于前端,作為一名后端的小菜,,前端方面肯定還有很多不足之處,,如果文章有任何問題歡迎指正。感謝大家,。好了,!廢話不多說下面講一下需求。
需求:公司要求實(shí)現(xiàn)web端的錄音并通過websocket實(shí)時上傳至java后臺,,而且能通過vlc實(shí)時播放,,簡單一點(diǎn)講就是我用網(wǎng)頁在那一邊講話,一個大喇叭就能實(shí)時把我的話播出去,,這樣是不是通俗易懂呀,,而且呢公司要求用mp3格式。當(dāng)然啦,!為了知道自己在講話需要一個波形圖,,這里主要實(shí)現(xiàn)前半部分功能,后半部分臣妾也做不到呀,!后半部分的vlc播放呢如果大家想知道,,可以留言,屆時可以給大家指條明路
 
前端實(shí)現(xiàn):
引入:<script type="text/javascript" src="/js/recorder/recordmp3.js"></script>
這個跟大佬的js有點(diǎn)不一樣,,我在里面加了一點(diǎn)東西,,而且在這個js里面引入了兩個另外的js,lame.min.js和worker-realtime.js,,這倆在大佬的代碼里有
2020-08-12補(bǔ)充:由于大佬們的博客不見了,,現(xiàn)在補(bǔ)充上兩個js文件worker-realtime.js,lame.min.js
2020-12-25補(bǔ)充:啊啊??!找到了大佬的項(xiàng)目關(guān)于實(shí)時推流啥的,感覺就是啥都行啊,,在此分享https://github.com/xiangyuecn/Recorder,,超級好用,值得學(xué)習(xí)
頁面:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www./TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www./1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=gb2312"/>
    <title>測試</title>
</head>
<body>
<button id="intercomBegin">開始對講</button>
<button id="intercomEnd">關(guān)閉對講</button>
<canvas id="casvased" style="width: 400px;height: 100px"></canvas>
</body>
<script type="text/javascript" src="/js/jquery-3.3.1.js"></script>
<script type="text/javascript" src="/js/recorder/recordmp3.js"></script>
<script type="text/javascript">
    var begin = document.getElementById('intercomBegin');
    var end = document.getElementById('intercomEnd');

    var canvas = document.getElementById("casvased");
    var canvasCtx = canvas.getContext("2d");

    var ws = null; //實(shí)現(xiàn)WebSocket

    var recorder;

    /*
    * WebSocket
    */
    function useWebSocket() {
        ws = new WebSocket("ws://127.0.0.1:8089/send/voice");
        ws.binaryType = 'arraybuffer'; //傳輸?shù)氖?ArrayBuffer 類型的數(shù)據(jù)
        ws.onopen = function () {
            console.log('握手成功');
            if (ws.readyState == 1) { //ws進(jìn)入連接狀態(tài),,則每隔500毫秒發(fā)送一包數(shù)據(jù)
                recorder.start();
            }
        };

        ws.onmessage = function (msg) {
            console.info(msg)
        }

        ws.onerror = function (err) {
            console.info(err)
        }
    }

    /*
    * 開始對講
    */
    begin.onclick = function () {
        recorder = new MP3Recorder({
            debug: true,
            funOk: function () {
                console.log('點(diǎn)擊錄制,,開始錄音! ');
            },
            funCancel: function (msg) {
                console.log(msg);
                recorder = null;
            }
        });
    }

    /*
    * 關(guān)閉對講
    */
    end.onclick = function () {
        if (ws) {
            ws.close();
            recorder.stop();
            console.log('關(guān)閉對講以及WebSocket');
        }
    }

    var sendData = function() { //對以獲取的數(shù)據(jù)進(jìn)行處理(分包)
        var reader = new FileReader();
        reader.onload = e => {
            var outbuffer = e.target.result;
            var arr = new Int8Array(outbuffer);
            if (arr.length > 0) {
                var tmparr = new Int8Array(1024);
                var j = 0;
                for (var i = 0; i < arr.byteLength; i++) {
                    tmparr[j++] = arr[i];
                    if (((i + 1) % 1024) == 0) {
                        ws.send(tmparr);
                        if (arr.byteLength - i - 1 >= 1024) {
                            tmparr = new Int8Array(1024);
                        } else {
                            tmparr = new Int8Array(arr.byteLength - i - 1);
                        }
                        j = 0;
                    }
                    if ((i + 1 == arr.byteLength) && ((i + 1) % 1024) != 0) {
                        ws.send(tmparr);
                    }
                }
            }
        };
        recorder.getMp3Blob(function (blob) {
            reader.readAsArrayBuffer(blob);//這里拿到mp3格式的音頻流寫入到reader中
})
  }; </script> </html>

recordmp3.js

(function (exports) {

    var MP3Recorder = function (config) {

        var recorder = this;
        config = config || {};
        config.sampleRate = config.sampleRate || 44100;
        config.bitRate = config.bitRate || 128;

        navigator.getUserMedia = navigator.getUserMedia ||
            navigator.webkitGetUserMedia ||
            navigator.mozGetUserMedia ||
            navigator.msGetUserMedia;

        if (navigator.getUserMedia) {
            navigator.getUserMedia({
                    audio: true
                },
                function (stream) {
                    var context = new AudioContext(),
                        microphone = context.createMediaStreamSource(stream),
                        processor = context.createScriptProcessor(16384, 1, 1),//bufferSize大小,,輸入channel數(shù),,輸出channel數(shù)
                        mp3ReceiveSuccess, currentErrorCallback;

                    var height = 100;
                    var width = 400;

                    const analyser = context.createAnalyser()
                    analyser.fftSize = 1024
                    //連接到音頻源
                    microphone.connect(analyser);
                    analyser.connect(context.destination);

                    const bufferLength = analyser.frequencyBinCount // 返回的是 analyser的fftsize的一半
                    const dataArray = new Uint8Array(bufferLength);

                    function draw() {
                        canvasCtx.clearRect(0, 0, width, height); //清除畫布
                        analyser.getByteFrequencyData(dataArray); // 將當(dāng)前頻率數(shù)據(jù)復(fù)制到傳入其中的Uint8Array
                        const requestAnimFrame = window.requestAnimationFrame(draw) || window.webkitRequestAnimationFrame(draw);
                        canvasCtx.fillStyle = '#000130';
                        canvasCtx.fillRect(0, 0, width, height);
                        let barWidth = (width / bufferLength) * 2;
                        let barHeight;
                        let x = 0;
                        let c = 2
                        for (let i = 0; i < bufferLength; i++) {
                            barHeight = c+(dataArray[i]/400)*height;
                            canvasCtx.fillStyle = 'rgb(0, 255, 30)';
                            canvasCtx.fillRect(x, height / 2 - barHeight / 2, barWidth, barHeight);
                            x += barWidth + 1;
                        }
                    }

                    draw();

                    useWebSocket();
                    config.sampleRate = context.sampleRate;
                    processor.onaudioprocess = function (event) {
                        //邊錄音邊轉(zhuǎn)換
                        var array = event.inputBuffer.getChannelData(0);
                        realTimeWorker.postMessage({cmd: 'encode', buf: array});
                        sendData();
                    };

                    var realTimeWorker = new Worker('/js/recorder/worker-realtime.js');
                    realTimeWorker.onmessage = function (e) {
                        switch (e.data.cmd) {
                            case 'init':
                                log('初始化成功');
                                if (config.funOk) {
                                    config.funOk();
                                }
                                break;
                            case 'end':
                                log('MP3大?。?, e.data.buf.length);
                                if (mp3ReceiveSuccess) {
                                    mp3ReceiveSuccess(new Blob(e.data.buf, {type: 'audio/mp3'}));
                                }
                                break;
                            case 'error':
                                log('錯誤信息:' + e.data.error);
                                if (currentErrorCallback) {
                                    currentErrorCallback(e.data.error);
                                }
                                break;
                            default:
                                log('未知信息:', e.data);
                        }
                    };

                    recorder.getMp3Blob = function (onSuccess, onError) {
                        currentErrorCallback = onError;
                        mp3ReceiveSuccess = onSuccess;
                        realTimeWorker.postMessage({cmd: 'finish'});
                    };

                    recorder.start = function () {
                        if (processor && microphone) {
                            microphone.connect(processor);
                            processor.connect(context.destination);
                            log('開始錄音');
                        }
                    }

                    recorder.stop = function () {
                        if (processor && microphone) {
                            microphone.disconnect();
                            processor.disconnect();
                            log('錄音結(jié)束');
                        }
                    }

                    realTimeWorker.postMessage({
                        cmd: 'init',
                        config: {
                            sampleRate: config.sampleRate,
                            bitRate: config.bitRate
                        }
                    });
                },
                function (error) {
                    var msg;
                    switch (error.code || error.name) {
                        case 'PERMISSION_DENIED':
                        case 'PermissionDeniedError':
                            msg = '用戶拒絕訪問麥客風(fēng)';
                            break;
                        case 'NOT_SUPPORTED_ERROR':
                        case 'NotSupportedError':
                            msg = '瀏覽器不支持麥客風(fēng)';
                            break;
                        case 'MANDATORY_UNSATISFIED_ERROR':
                        case 'MandatoryUnsatisfiedError':
                            msg = '找不到麥客風(fēng)設(shè)備';
                            break;
                        default:
                            msg = '無法打開麥克風(fēng),異常信息:' + (error.code || error.name);
                            break;
                    }
                    if (config.funCancel) {
                        config.funCancel(msg);
                    }
                });
        } else {
            if (config.funCancel) {
                config.funCancel('當(dāng)前瀏覽器不支持錄音功能');
            }
        }

        function log(str) {
            if (config.debug) {
                console.log(str);
            }
        }
    }

    exports.MP3Recorder = MP3Recorder;

})(window);

后端websocket:

這里實(shí)現(xiàn)的是保存為mp3文件

package com.jetosend.common.socket;

import com.jetosend.common.utils.Utils;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.*;
import java.nio.ByteBuffer;
import java.util.Hashtable;
import java.util.Map;

@ServerEndpoint("/send/{key}")
@Component
public class ServerSocket {

    private static final Map<String, Session> connections = new Hashtable<>();
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

    /***
     * @Description:打開連接
     * @Param: [id, 保存對方平臺的資源編碼
     * session]
     * @Return: void
     * @Author: Liting
     * @Date: 2019-10-10 09:22
     */
    @OnOpen
    public void onOpen(@PathParam("key") String id, Session session) {
        System.out.println(id + "連上了");
        connections.put(id, session);
    }

    /**
     * 接收消息
     */
    @OnMessage
    public void onMessage(@PathParam("key") String id, InputStream inputStream) {
        System.out.println("來自" + id);
        try {
            int rc = 0;
            byte[] buff = new byte[100];
            while ((rc = inputStream.read(buff, 0, 100)) > 0) {
                byteArrayOutputStream.write(buff, 0, rc);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 異常處理
     *
     * @param throwable
     */
    @OnError
    public void onError(Throwable throwable) {
        throwable.printStackTrace();
        //TODO 日志打印異常
    }

    /**
     * 關(guān)閉連接
     */
    @OnClose
    public void onClose(@PathParam("key") String id) {
        System.out.println(id + "斷開");
        BufferedOutputStream bos = null;
        FileOutputStream fos = null;
        File file = null;
        try {
            file = new File("D:\\testtest.mp3");

            //輸出流
            fos = new FileOutputStream(file);

            //緩沖流
            bos = new BufferedOutputStream(fos);

            //將字節(jié)數(shù)組寫出
            bos.write(byteArrayOutputStream.toByteArray());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        connections.remove(id);
    }

實(shí)現(xiàn)效果:

 

好了,,到這里就是全部了,,如有疑問可以留言

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn),。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多