動態

詳情 返回 返回

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

看到這裏的時候一定要理解並運行上文的《前端H5錄音實時幀回調-波形配置- Recorder.js》,這樣對Recorder有個概念。
1、通過onProcess回調可實現錄音的實時處理,onProcessbuffers參數內容為pcm數組(16位 LE小端模式 Little Endian),能直接流式的將數據進行上傳;
2、onProcess內的buffers參數為所有的PCM集合,如果是流式上傳我們只需要當前的分片即可,所以需要用到Recorder.SampleData方法來實時提取出pcm數據和轉換採樣率,在下面的例子中用send_chunk變量來標記。
3、如果直接使用pcm格式,初始化錄音對象時可以將type設置為"unknown",這樣用户更好回收(官網描述)
4、如果 type: 'unknown' 的話,結束錄音事件裏直接rec.close();就可以了,因為unknown的編碼格式不支持stop

<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";

//引入pcm格式支持文件
import "recorder-core/src/engine/pcm";

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

let wave: any; // 用於繪製波形
const recwave = ref(null); // 綁定到dom元素上
let rec: any; // Recorder實例
let send_chunk: any; // 上次分割點數據
let testSampleRate = 16000; // 採樣率

//重置環境,每次開始錄音時必須先調用此方法,清理環境
const RealTimeSendReset = () => {
  send_chunk = null;
};

// 打開錄音
const recOpen = () => {
  RealTimeSendReset();
  // 創建錄音對象
  rec = Recorder({
    type: "unknown", //這裏特意使用unknown格式,方便清理內存
    onProcess: (buffers: any, powerLevel: any, _: any, bufferSampleRate: any) => {
      // 所有的pcm數據queue,緩存採樣率,是否結束
      RealTimeSendTry(buffers, bufferSampleRate, false);
      if (wave) {
        wave.input(buffers[buffers.length - 1], powerLevel, bufferSampleRate);
      }
    }
  });
  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 = (buffers: any, bufferSampleRate: any, isClose: any) => {
  //提取出新的pcm數據
  let pcm = new Int16Array(0);
  if (buffers.length > 0) {
    //【關鍵代碼】借用SampleData函數進行數據的連續處理,採樣率轉換是順帶的,得到新的pcm數據
    // send_chunk為上次分割點
    let chunk = Recorder.SampleData(buffers, bufferSampleRate, testSampleRate, send_chunk);
    send_chunk = chunk; // 保存本次分割點,用於下次使用
    console.log("分片下標", chunk);
    pcm = chunk.data; //此時的pcm就是原始的音頻16位pcm數據(小端LE),直接保存即為16位pcm文件、加個wav頭即為wav文件、丟給mp3編碼器轉一下碼即為mp3文件
  }

  //沒有指定固定的幀大小,直接把pcm發送出去即可
  TransferUpload(pcm, isClose);
  return;
};

//=====數據傳輸函數==========
const TransferUpload = (pcmFrame: any, isClose: any) => {
  if (isClose && pcmFrame.length == 0) {
    // 這裏就是數據發送完成,錄音結束的位置,可以停止ws了
    // ws.send(arrayBuffer,true)
    return; //如果不需要處理最後一幀數據,直接return不做任何處理
  }

  let arrayBuffer = pcmFrame.buffer;
  console.log("pcm二進制", arrayBuffer);
  //可以實現
  //WebSocket send(arrayBuffer) ...
  //WebRTC send(arrayBuffer) ...
  //XMLHttpRequest send(arrayBuffer) ...

  //最後一次調用發送,此時的pcmFrame可以認為是最後一幀
  if (isClose) {
    console.log("最後一次調用", pcmFrame, pcmFrame.length);
    // 比如再發送一次socket
    // ws.send(arrayBuffer,false)
  }
};

// 開始錄音
const recStart = () => {
  if (!rec) return console.error("未打開錄音");
  rec.start();
  console.log("已開始錄音");
};
// 結束錄音
const recStop = () => {
  if (!rec) return console.error("未打開錄音");
  rec.close(); // 關閉錄音,釋放錄音資源
  rec = null;
  RealTimeSendTry([], 0, true); //最後一次發送
};
</script>

<style lang="scss" scoped></style>

參考文檔:
Recorder.js
【音頻流】【上傳】實時轉碼上傳-pcm固定幀大小

user avatar gushiio 頭像
點贊 1 用戶, 點贊了這篇動態!
點贊

Add a new 評論

Some HTML is okay.