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

Android端TTS发声时检测他人说话的FFT实现方案咨询

基于FFT的TTS发声时人声检测方案可行性与优化

你的思路是可行的,但落地需要解决几个核心问题:回声消除、特征提取逻辑优化、实时处理流程设计,下面针对你的疑问和现有代码逐一说明:

现有代码的问题

你直接对JTransforms输出的FFT复数数组(实部+虚部交替存储)计算余弦相似度,这个逻辑存在明显缺陷:

  • FFT的相位信息对语音的"身份区分"意义不大,TTS播放的声音经过空气传播、回声反射后相位会偏移,但本质还是同一个声音,直接用实虚部计算会导致相似度骤降,误判为他人说话。
  • 没有分帧处理:语音是时变信号,整段音频的FFT对比没有实际意义,必须按帧(比如20ms/帧)提取特征后再做对比。

可行的实现步骤

1. 必须先做回声消除

手机麦克风会同时录到TTS的播放声(回声)和周围人声,不消除回声的话,你的对比逻辑会把自己的TTS当成"他人声音",或者根本无法区分两者:

  • Android原生可以通过AudioManager开启声学回声消除(AEC),配置AudioRecord时指定单声道、PCM16位的音频参数。
  • 更可靠的方案是使用WebRTC的AudioProcessing模块,它的回声消除算法针对移动设备做过优化,能有效滤除TTS的播放回声。

2. 特征提取优化

放弃直接用FFT复数数组,改用幅度谱或**MFCC(梅尔频率倒谱系数)**作为对比特征:

  • 幅度谱:将FFT的复数转换成模长(sqrt(实部²+虚部²)),保留频谱的能量分布信息,忽略对语音区分无用的相位。
  • MFCC:专门针对语音设计的特征,能提取到语音的关键频谱特性,比原始FFT更能区分TTS和真人声。

3. 实时对比流程

  1. 预存TTS特征:在播放TTS前,先对TTS的原始音频数据分帧、加窗、做FFT,提取幅度谱/MFCC特征并保存。
  2. 实时录制与处理:用AudioRecord实时录制周围声音,每帧执行同样的特征提取操作。
  3. 相似度判断:计算实时帧特征与TTS预存特征的余弦相似度,若相似度低于设定阈值(比如0.6),则判定为他人说话,触发对应事件。

优化后的相似度计算代码

针对幅度谱的余弦相似度计算逻辑:

// 将FFT复数数组转换为幅度谱数组
private fun fftComplexToMagnitude(fftComplex: DoubleArray): DoubleArray {
    val magnitude = DoubleArray(fftComplex.size / 2)
    var i = 0
    while (i < fftComplex.size) {
        val real = fftComplex[i]
        val imag = fftComplex[i + 1]
        magnitude[i / 2] = Math.sqrt(real * real + imag * imag)
        i += 2
    }
    return magnitude
}

// 计算幅度谱的余弦相似度
private fun calculateCosineSimilarity(mag1: DoubleArray, mag2: DoubleArray): Double {
    if (mag1.size != mag2.size) return 0.0
    
    var dotProduct = 0.0
    var norm1 = 0.0
    var norm2 = 0.0
    
    for (i in mag1.indices) {
        dotProduct += mag1[i] * mag2[i]
        norm1 += mag1[i] * mag1[i]
        norm2 += mag2[i] * mag2[i]
    }
    
    val denominator = Math.sqrt(norm1) * Math.sqrt(norm2)
    return if (denominator == 0.0) 0.0 else dotProduct / denominator
}

额外注意事项

  • 分帧加窗:每帧音频长度建议设为20ms,加汉明窗减少频谱泄漏。
  • FFT数组大小:尽量使用2的幂次(如1024、2048),提升FFT计算效率。
  • 阈值调优:实际测试时根据回声消除效果调整相似度阈值,确保TTS回声的相似度在0.8以上,他人说话时低于0.6。
  • 线程处理:所有音频处理逻辑要放在子线程,避免阻塞UI线程。

内容的提问来源于stack exchange,提问作者叶辰哲

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 09:35:34