動態

詳情 返回 返回

PC瀏覽器端-MP3錄音+實時幀回調+流式上傳-Recorderjs - 動態 詳情

看到這裏的時候一定要理解並運行上文的《前端recorder-core實時錄音並繪製波形,blob常規數據格式》,這樣對Recorder有個概念。
在創建錄音對象的時候有一個takeoffEncodeChunk回調,該回調為實時編碼環境,會接管編碼器輸出。
當編碼器實時編碼出一塊有效的二進制音頻數據時實時回調此方法,也就是説每次獲取到有效的二進制音頻數據takeoffEncodeChunk都會回調一次,返回二進制的Uint8Array,就是編碼出來的音頻數據片段(chunkBytes),所有的chunkBytes拼接在一起即為完整音頻。

  // 創建錄音對象
  rec = Recorder({
    type: "mp3", // 格式
    sampleRate: 16000, // 錄音的採樣率
    bitRate: 16, // 比特率
    onProcess: (buffers: any, powerLevel: any, _: any, bufferSampleRate: any) => {
      if (wave) {
        wave.input(buffers[buffers.length - 1], powerLevel, bufferSampleRate);
      }
    },
    takeoffEncodeChunk: (chunkBytes: any) => {
      //【關鍵代碼】接管實時轉碼,推入實時處理
      console.log("接管實時轉碼,推入實時處理", chunkBytes);
    }
  });

使用takeoffEncodeChunk後需要注意,這個模式是流式輸出的,Recorder不會自動保存每一次的片段數據,需要我們自行實時保存錄音文件數據,因此Recorder.stop停止時返回的blob的長度將為0字節。
完整代碼,vue3+ts+arco.design,複製到項目中可這直接運行

<template>
  <div class="snow-page">
    <div class="snow-inner">
      <a-space direction="vertical" fill>
        <!-- 波形繪製區域 -->
        <div style="display: inline-block; vertical-align: bottom; border: 1px solid #cccccc">
          <div style="width: 300px; height: 100px" ref="recwave"></div>
        </div>
        <a-space>
          <a-button type="primary" @click="recOpen">打開錄音權限</a-button>
          <a-button type="primary" @click="recStart">開始錄音</a-button>
          <a-button @click="recStop">結束錄音</a-button>
        </a-space>
      </a-space>
    </div>
  </div>
</template>

<script setup lang="ts">
//必須引入的核心
import Recorder from "recorder-core";

//引入mp3格式支持文件;如果需要多個格式支持,把這些格式的編碼引擎js文件放到後面統統引入進來即可
import "recorder-core/src/engine/mp3";
import "recorder-core/src/engine/mp3-engine";
//錄製wav格式的用這一句就行
import "recorder-core/src/engine/wav";

//可選的插件支持項,這個是波形可視化插件
import "recorder-core/src/extensions/waveview";
//ts import 提示:npm包內已自帶了.d.ts聲明文件(不過是any類型)

let rec: any;
let recBlob: any;
let wave: any;
const recwave = ref(null);
// 打開錄音
const recOpen = () => {
  // 創建錄音對象
  rec = Recorder({
    type: "mp3", // 格式
    sampleRate: 16000, // 錄音的採樣率
    bitRate: 16, // 比特率
    onProcess: (buffers: any, powerLevel: any, _: any, bufferSampleRate: any) => {
      if (wave) {
        wave.input(buffers[buffers.length - 1], powerLevel, bufferSampleRate);
      }
    },
    takeoffEncodeChunk: (chunkBytes: any) => {
      RealTimeSendTry(chunkBytes, false);
    }
  });
  if (!rec) {
    alert("當前瀏覽器不支持錄音功能!");
    return;
  }
  // 打開錄音,獲得權限
  rec.open(
    () => {
      console.log("錄音已打開");
      if (recwave.value) {
        // 創建音頻可視化圖形繪製對象
        wave = Recorder.WaveView({ elem: recwave.value });
      }
    },
    (msg: any, isUserNotAllow: any) => {
      // 用户拒絕了錄音權限,或者瀏覽器不支持錄音
      console.log((isUserNotAllow ? "UserNotAllow," : "") + "無法錄音:" + msg);
    }
  );
};

const RealTimeSendTry = (chunkBytes: any, isClose: any) => {
  //沒有指定固定的幀大小,直接把chunkBytes發送出去即可
  if (chunkBytes.length > 0) {
    //*********發送方式二:直接ArrayBuffer二進制發送***************
    let arrayBuffer = chunkBytes.buffer;
    console.log("二進制發送", chunkBytes, arrayBuffer);
    //可以實現
    //WebSocket send(arrayBuffer) ...
    //WebRTC send(arrayBuffer) ...
    //XMLHttpRequest send(arrayBuffer) ...
  }

  //最後一次調用發送,注意此時的frameBytes不一定有數據,可能長度為0
  //請勿假設調用了rec.stop之後的takeoffEncodeChunk一定有回調並且是最後一幀,因為可能會回調 0-2 幀
  //請以isClose為準,isClose的當前幀或者前一幀,只要是有數據的就是最後一幀;因此如果需要獲得最後一幀數據,可延遲一幀的發送,isClose時取當前幀或延遲的這幀作為最後一幀
  if (isClose) {
    // 可做關閉邏輯處理
    console.log("最後一幀", chunkBytes, chunkBytes.length);
  }
};

// 開始錄音
const recStart = () => {
  if (!rec) return console.error("未打開錄音");
  rec.start();
  console.log("已開始錄音");
};
// 結束錄音
const recStop = () => {
  if (!rec) return console.error("未打開錄音");
  rec.stop(
    (blob: any, duration: any) => {
      recBlob = blob;
      const localUrl = (window.URL || webkitURL).createObjectURL(blob);
      console.log("結束錄音", blob, localUrl, "時長:" + duration + "ms");
      rec.close(); // 關閉錄音,釋放錄音資源
      rec = null;
      RealTimeSendTry(new Uint8Array(0), true); //最後一次發送
    },
    (err: any) => {
      console.error("結束錄音出錯:" + err);
      rec.close(); //關閉錄音,釋放錄音資源
      rec = null;
    }
  );
};
</script>

Add a new 評論

Some HTML is okay.