欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時間:2020年06月12日 08:52:08   作者:麥葉  
這篇文章主要介紹了js實現(xiàn)mp3錄音通過websocket實時傳送+簡易波形圖效果,本文通過實例代碼給大家介紹的非常詳細(xì)對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下

波形圖:http://www.dbjr.com.cn/article/188545.htm

廢話:想不到我的第一篇博客是關(guān)于前端,作為一名后端的小菜,前端方面肯定還有很多不足之處,如果文章有任何問題歡迎指正。感謝大家。好了!廢話不多說下面講一下需求。

需求:公司要求實現(xiàn)web端的錄音并通過websocket實時上傳至java后臺,而且能通過vlc實時播放,簡單一點講就是我用網(wǎng)頁在那一邊講話,一個大喇叭就能實時把我的話播出去,這樣是不是通俗易懂呀,而且呢公司要求用mp3格式。當(dāng)然啦!為了知道自己在講話需要一個波形圖,這里主要實現(xiàn)前半部分功能,后半部分臣妾也做不到呀!后半部分的vlc播放呢如果大家想知道,可以留言,屆時可以給大家指條明路

前端實現(xiàn):

引入:

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

這個跟大佬的js有點不一樣,我在里面加了一點東西,而且在這個js里面引入了兩個另外的js,lame.min.js和worker-realtime.js,這倆在大佬的代碼里有

頁面:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/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; //實現(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('點擊錄制,開始錄音! ');
   },
   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:
這里實現(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);
 }

實現(xiàn)效果:

 

總結(jié)

到此這篇關(guān)于js實現(xiàn)mp3錄音通過websocket實時傳送+簡易波形圖效果的文章就介紹到這了,更多相關(guān)js實現(xiàn)mp3錄音內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JavaScript插件化開發(fā)教程 (三)

    JavaScript插件化開發(fā)教程 (三)

    前面我們學(xué)習(xí)了jQuery的方式開發(fā)插件,講訴的都是些基礎(chǔ)的理論知識,今天開始,我們就來實戰(zhàn)一下,學(xué)習(xí)開發(fā)自己的插件庫。
    2015-01-01
  • 在新窗口打開超鏈接的方法小結(jié)

    在新窗口打開超鏈接的方法小結(jié)

    有時候我們想讓用戶在新窗口打開網(wǎng)站,因為默認(rèn)當(dāng)前窗口打開,很多情況下,用戶并不喜歡
    2013-04-04
  • 基于JS實現(xiàn)Android,iOS一個手勢動畫效果

    基于JS實現(xiàn)Android,iOS一個手勢動畫效果

    這篇文章主要介紹了基于JS實現(xiàn)Android,iOS一個手勢動畫效果 的相關(guān)資料,需要的朋友可以參考下
    2016-04-04
  • BootStrap模態(tài)框不垂直居中的解決方法

    BootStrap模態(tài)框不垂直居中的解決方法

    這篇文章主要為大家詳細(xì)介紹了BootStrap模態(tài)框不垂直居中的解決方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • 我也種棵OO樹JXTree[js+css+xml]

    我也種棵OO樹JXTree[js+css+xml]

    我也種棵OO樹JXTree[js+css+xml]...
    2007-04-04
  • 對TypeScript庫進(jìn)行單元測試的方法

    對TypeScript庫進(jìn)行單元測試的方法

    這篇文章主要介紹了對TypeScript庫進(jìn)行單元測試的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07
  • css如何讓浮動元素水平居中

    css如何讓浮動元素水平居中

    css中對于定寬的非浮動元素用margin:0 auto進(jìn)行水平居中,對于不定寬的浮動元素也有一個常用技巧,這篇文章就給大家介紹下css如何讓浮動元素水平居中,需要的朋友可以來學(xué)習(xí)下
    2015-08-08
  • JavaScript中的

    JavaScript中的"=、==、==="區(qū)別講解

    今天小編就為大家分享一篇關(guān)于JavaScript中的"=、==、==="區(qū)別講解,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • 微信小程序彈窗禁止頁面滾動的實現(xiàn)代碼

    微信小程序彈窗禁止頁面滾動的實現(xiàn)代碼

    這篇文章主要介紹了微信小程序彈窗禁止頁面滾動的實現(xiàn)代碼,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-12-12
  • JS截取字符串常用方法詳細(xì)整理

    JS截取字符串常用方法詳細(xì)整理

    截取字符串的使用比較廣泛,有很多中方法,本文粗略的整理了一些,感興趣的額朋友可以才參考下
    2013-10-10

最新評論