Vue3 实现麦克风实时音量检测

文章目录

    • 1 前言
    • 2 功能实现
      • 2.1 新建 vumeter.js
      • 2.2 新建 useVolume.ts
      • 2.3 新增音量检测展示容器

1 前言

本文基于 Vue3 + TypeScript 实现实时音量检测,其他语言可修改相应写法
在这里插入图片描述

2 功能实现

2.1 新建 vumeter.js

在 public/static 目录下新建 vumeter.js

const SMOOTHING_FACTOR = 0.8;
registerProcessor(
  'vumeter',
  class extends AudioWorkletProcessor {
    _volume;
    _updateIntervalInMS;
    _nextUpdateFrame;
    _currentTime;

    constructor() {
      super();
      this._volume = 0;
      this._updateIntervalInMS = 25;
      this._nextUpdateFrame = this._updateIntervalInMS;
      this._currentTime = 0;
      this.port.onmessage = (event) => {
        if (event.data.updateIntervalInMS) {
          this._updateIntervalInMS = event.data.updateIntervalInMS;
        }
      };
    }

    get intervalInFrames() {
      return (this._updateIntervalInMS / 1000) * sampleRate;
    }

    process(inputs) {
      const input = inputs[0];
      if (input.length > 0) {
        const samples = input[0];
        let sum = 0;
        let rms = 0;
        for (let i = 0; i < samples.length; i += 1) {
          sum += samples[i] * samples[i];
        }
        rms = Math.sqrt(sum / samples.length);
        this._volume = Math.max(rms, this._volume * SMOOTHING_FACTOR);
        this._nextUpdateFrame -= samples.length;
        if (0 > this._nextUpdateFrame) {
          this._nextUpdateFrame += this.intervalInFrames;
          if (!this._currentTime || 0.125 < currentTime - this._currentTime) {
            this._currentTime = currentTime;
            this.port.postMessage({ volume: this._volume });
          }
        }
      }

      return true;
    }
  },
);

2.2 新建 useVolume.ts

在 src/hooks 目录下新建 vumeter.js

const volume = ref(0)
let audioContext: AudioContext
let node: AudioWorkletNode
let stream: MediaStream | null = null
let source: MediaStreamAudioSourceNode | null = null

const getStaticPath = (path: string) => `${import.meta.env.VITE_PUBLIC_PATH}static/${path}`

const init = async () => {
  audioContext = new AudioContext()
  await audioContext.audioWorklet.addModule(getStaticPath('vumeter.js'))
  node = new AudioWorkletNode(audioContext, 'vumeter')
  node.port.onmessage = (event) => {
    if (event.data.volume) {
      volume.value = Math.round(event.data.volume * 200)
    }
  }
}

const disconnectAudioContext = () => {
  stream?.getTracks().forEach((track) => track.stop()) // 取消麦克风占用
  source?.disconnect() // 取消 onmessage 监听
  stream = null
  source = null
  volume.value = 0
}

const connectAudioContext = async () => {
  if (!audioContext) await init()
  navigator.mediaDevices.getUserMedia({ audio: true, video: false }).then(async (mediaStream) => {
    stream = mediaStream
    source = audioContext.createMediaStreamSource(stream)
    source.connect(node)
  })
}

export default function () {
  return {
    volume,
    connectAudioContext,
    disconnectAudioContext
  }
}

2.3 新增音量检测展示容器






你可能感兴趣的:(Vue3,JavaScript,javascript,开发语言,ecmascript)