You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用JavaScript无需Speech Recognition API检测用户说话起止时间?

基于Web Audio API的语音起止时间检测实现

本方案不使用兼容性较差的Speech Recognition API,仅依赖跨浏览器支持度更高的Web Audio API实现说话起始、结束时间检测,无需调用云端接口,所有计算均在本地完成。

核心实现逻辑

  • 调用getUserMedia申请用户麦克风权限,获取音频输入流
  • 通过AnalyserNode实时获取音频时域数据,计算当前音量值
  • 设定音量阈值和静默判定时长:音量超过阈值时标记为说话开始,音量持续低于阈值达到预设时长时标记为说话结束

完整代码实现

class SpeechTimeDetector {
  constructor(options = {}) {
    // 可调参数
    this.volumeThreshold = options.volumeThreshold || 0.15; // 音量阈值
    this.silenceDuration = options.silenceDuration || 500; // 静默判定时长(ms)
    this.pollingInterval = options.pollingInterval || 20; // 检测轮询间隔(ms)
    
    // 状态变量
    this.isSpeaking = false;
    this.speechStartTime = null;
    this.speechEndTime = null;
    this.silenceTimer = null;
    
    // 音频相关实例
    this.audioContext = null;
    this.analyser = null;
    this.mediaStreamSource = null;
    this.dataArray = null;
  }

  // 初始化,需要在用户交互事件(如click)中调用,避免浏览器限制AudioContext自动启动
  async init() {
    try {
      // 请求麦克风权限
      const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
      
      // 初始化音频上下文
      this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
      this.analyser = this.audioContext.createAnalyser();
      this.analyser.fftSize = 2048;
      
      // 连接音频流
      this.mediaStreamSource = this.audioContext.createMediaStreamSource(stream);
      this.mediaStreamSource.connect(this.analyser);
      
      this.dataArray = new Uint8Array(this.analyser.fftSize);
      this._startDetect();
      return true;
    } catch (err) {
      console.error('初始化失败:', err);
      throw err;
    }
  }

  // 计算当前音量
  _getCurrentVolume() {
    this.analyser.getByteTimeDomainData(this.dataArray);
    let sum = 0;
    for (let i = 0; i < this.dataArray.length; i++) {
      const normalized = (this.dataArray[i] - 128) / 128; // 归一化到[-1,1]
      sum += normalized * normalized;
    }
    return Math.sqrt(sum / this.dataArray.length); // 返回均方根值作为音量
  }

  // 开始检测
  _startDetect() {
    setInterval(() => {
      const currentVolume = this._getCurrentVolume();
      
      if (currentVolume > this.volumeThreshold) {
        // 音量超过阈值
        if (this.silenceTimer) {
          clearTimeout(this.silenceTimer);
          this.silenceTimer = null;
        }
        
        if (!this.isSpeaking) {
          // 说话开始
          this.isSpeaking = true;
          this.speechStartTime = Date.now();
          console.log('说话开始:', new Date(this.speechStartTime));
          // 这里可以自定义说话开始的回调逻辑
        }
      } else {
        // 音量低于阈值
        if (this.isSpeaking && !this.silenceTimer) {
          this.silenceTimer = setTimeout(() => {
            // 静默达到设定时长,说话结束
            this.isSpeaking = false;
            this.speechEndTime = Date.now();
            console.log('说话结束:', new Date(this.speechEndTime));
            console.log('说话时长:', this.speechEndTime - this.speechStartTime, 'ms');
            // 这里可以自定义说话结束的回调逻辑
          }, this.silenceDuration);
        }
      }
    }, this.pollingInterval);
  }

  // 销毁实例,释放资源
  destroy() {
    if (this.mediaStreamSource) this.mediaStreamSource.disconnect();
    if (this.audioContext) this.audioContext.close();
    this.isSpeaking = false;
  }
}

// 使用示例,需要绑定到用户交互事件,比如按钮点击
// document.querySelector('#startBtn').addEventListener('click', async () => {
//   const detector = new SpeechTimeDetector({
//     volumeThreshold: 0.18,
//     silenceDuration: 600
//   });
//   await detector.init();
// })

参数调整说明

  • volumeThreshold:音量判定阈值,范围0-1,安静环境建议设置为0.1-0.2,嘈杂环境可适当提高
  • silenceDuration:静默判定时长,单位ms,对话场景建议设置为300-800ms,避免说话停顿被误判为结束
  • pollingInterval:检测轮询间隔,单位ms,建议设置为10-50ms,数值越小检测灵敏度越高,性能消耗也越大

兼容性说明

本方案依赖的Web Audio API支持Chrome 35+、Firefox 43+、Safari 14.1+、Edge 79+,全球用户覆盖率超过95%,远高于Speech Recognition API的兼容性。


内容的提问来源于stack exchange,提问作者Витязи Team

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.09 15:54:00