Tutorial: 音量大小检测

音量大小检测

本文主要介绍如何做音量大小的判定。 音量大小的判定主要应用在:

  • 检查麦克风的通话质量
  • 获取音视频通话中用户的说话音量

实现方法

通过调用 getAudioLevel() 方法获取当前音量大小。

setInterval(() => {
  const volume = stream.getAudioLevel();
  if (volume > 0.1) {
    console.log(`${stream.getUserId()} is speaking`);
  }
}, 1000);

如果需要在页面中渲染用户音量大小,建议使用 requestAnimationFrame 替换 setInterval 进行性能优化

// 设置AnimationFrame
function setAnimationFrame(render) {
  // 计时器
  let timer = {};
  function animeLoop() {
    render();
    timer.id = requestAnimationFrame(animeLoop);
  }
  animeLoop();
  return timer;
}

// 清除AnimationFrame
function clearAnimationFrame(timer) {
  cancelAnimationFrame(timer.id);
}

最佳实践

以下提供两种页面中渲染用户音量的实践方案,接入者可根据业务场景选择合适的方案:

方案一用更简便的逻辑实现监听和取消监听用户音量功能,优先推荐给接入方使用
方案二更加详细的梳理了监听音量和取消监听音量的时机,供接入方参考

方案一

第一步:创建远端流数组 remoteStreamList

let remoteStreamList = [];

client.on('stream-subscribed', { stream: remoteStream } => {
  remoteStreamList.push(remoteStream);
})

client.on('stream-removed', { stream: remoteStream } => {
  remoteStreamList = remoteStreamList.filter(stream => {
    return stream.getId() !== remoteStream.getId();
  });
})

第二步:封装开始获取音量 startGetAudioLevel 和停止获取音量 stopGetAudioLevel 的方法

// 开始获取流音量
let getAudioLevelTimer = -1;
function startGetAudioLevel() {
  getAudioLevelTimer = setAnimationFrame(() => {
    if (localStream) {
      const level = localStream.getAudioLevel();
      if (level >= 0.1) {
        console.warn(`user ${localStream.getUserId()} is speaking, volume: ${level}`);
        // 在页面中渲染用户音量大小
      }
    }
    
    remoteStreamList.forEach(stream => {
      const level = stream.getAudioLevel();
      if (level >= 0.1) {
        console.warn(`user ${stream.getUserId()} is speaking, volume: ${level}`);
        // 在页面中渲染用户音量大小
      }
    });
  });
}

// 停止获取流音量
function stopGetAudioLevel() {
  if (getAudioLevelTimer !== -1) {
    clearAnimationFrame(getAudioLevelTimer);
    getAudioLevelTimer = -1;
  }
}

第三步:在本地用户进房和退房时执行 startGetAudioLevelstopGetAudioLevel 方法

开始获取所有流音量:本地用户执行 client.join 之后开始获取所有流的音量

client.join();
startGetAudioLevel();

停止获取所有流音量:本地用户执行 client.leave 之后停止获取所有流的音量

client.leave();
stopGetAudioLevel();

方案二

第一步:封装开始获取音量 startGetAudioLevel 和停止获取音量 stopGetAudioLevel 的方法

const audioLevelTimerMap = new Map();

// 开始获取指定流音量
function startGetAudioLevel(stream) {
  let timer = setAnimationFrame(() => {
    const volume = stream.getAudioLevel();
    if (volume > 0.1) {
      console.log(`user ${stream.getUserId()} is speaking, volume: ${volume}`);
      // 在页面中渲染用户音量大小
    }
  });
  audioLevelTimerMap.set(stream.getId(), timer);
}

// 停止获取指定流音量
function stopGetAudioLevel(stream) {
  let timer = audioLevelTimerMap.get(stream.getId());
  clearAnimationFrame(timer);
}

// 停止获取所有流的音量
function clearGetAudioLevelTimer() {
  audioLevelTimerMap.forEach(audioLevelTimer => {
    audioLevelTimer && clearAnimationFrame(audioLevelTimer);
  });
  audioLevelTimerMap.clear();
}

第二步:分别执行本地流和远端流的 startGetAudioLevelstopGetAudioLevel 方法

开始获取本地流音量:本地用户执行 client.publish 之后开始获取本地音量

client.publish(localStream);
startGetAudioLevel(localStream);

停止获取本地流音量:本地用户执行 client.unpublish 之后停止获取本地音量

client.unpublish(localStream);
stopGetAudioLevel(localStream);

开始获取远端流音量:监听到远端流 stream-subscribed 事件时开始获取远端流音量

client.on('stream-subscribed', { stream: remoteStream } => {
  startGetAudioLevel(remoteStream);
})

停止获取远端流音量:监听到远端流 stream-removed事件时停止获取远端流音量

client.on('stream-removed', { stream: remoteStream } => {
  stopGetAudioLevel(remoteStream);
})

停止获取所有流音量:本地用户执行 client.leave 之后停止获取所有流的音量

client.leave();
clearGetAudioLevelTimer();