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

Android默认Speech Recognizer录音延迟计算精度问题求助

解决Android Speech Recognizer录音延迟计算不准确的问题

问题根源

你当前的计算方式是用识别结果返回的时间减去录制启动时间,这个差值包含了语音上传、云端识别、结果回传的全部耗时,完全不是用户说出关键词的真实时间点,所以必然出现偏差(比如第1秒说话,结果返回时已经过了2秒,就会显示2秒延迟)。

解决方案核心逻辑

要准确计算延迟,必须捕获用户说出关键词的起始时刻,而不是依赖识别回调的时间。我们可以通过本地音频监听,检测语音音量峰值的时间点,再结合识别结果验证关键词,最终计算真实延迟。

具体实现步骤

1. 添加录音权限

在AndroidManifest.xml中添加:

<uses-permission android:name="android.permission.RECORD_AUDIO" />

注意Android 6.0+以上需要动态申请权限。

2. 实现本地音频监听(检测语音起始时间)

添加音频监听工具方法,记录用户开始说话的时间点:

private AudioRecord audioRecord;
private boolean isListening = false;
private long speechStartTime = 0;

private void startAudioMonitoring() {
    int sampleRate = 44100;
    int channelConfig = AudioFormat.CHANNEL_IN_MONO;
    int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
    int bufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat);

    audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRate, channelConfig, audioFormat, bufferSize);
    audioRecord.startRecording();

    isListening = true;
    new Thread(() -> {
        short[] buffer = new short[bufferSize];
        // 音量阈值,根据实际环境调整,避免噪音误触发
        final int VOLUME_THRESHOLD = 2000;

        while (isListening) {
            int read = audioRecord.read(buffer, 0, bufferSize);
            if (read > 0) {
                int volume = calculateVolume(buffer, read);
                // 首次检测到超过阈值的音量,记录语音起始时间
                if (volume > VOLUME_THRESHOLD && speechStartTime == 0) {
                    speechStartTime = System.nanoTime();
                }
            }
        }
        audioRecord.stop();
        audioRecord.release();
    }).start();
}

// 计算当前音频帧的音量(均方根值)
private int calculateVolume(short[] buffer, int length) {
    long sum = 0;
    for (int i = 0; i < length; i++) {
        sum += (long) buffer[i] * buffer[i];
    }
    double rms = Math.sqrt(sum / (double) length);
    return (int) (rms * 10);
}

3. 修改录制启动逻辑

在按下录制按钮时,初始化时间戳并启动音频监听:

private long startTime;

public void onRecordButtonClick(View view) {
    progressBar.setVisibility(View.VISIBLE);
    // 重置时间戳
    startTime = System.nanoTime();
    speechStartTime = 0;
    // 启动本地音频监听
    startAudioMonitoring();

    // 启动Android Speech Recognizer
    Intent recognizerIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
    recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
    recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault());
    speechRecognizer.startListening(recognizerIntent);
}

4. 修改结果回调逻辑

在onResults中使用检测到的语音起始时间计算延迟:

@Override
public void onResults(Bundle results) {
    progressBar.setVisibility(View.GONE);
    // 停止音频监听线程
    isListening = false;

    ArrayList<String> matches = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);

    if (matches != null && !matches.isEmpty()) {
        String transcript = matches.get(0);
        textSTT.setText(transcript);

        if (transcript.contains(keyword)) {
            if (speechStartTime != 0) {
                long delay = speechStartTime - startTime;
                double delayInSeconds = delay / 1_000_000_000.0;
                double roundedDelay = roundToTwoDecimalPlaces(delayInSeconds);

                delayResult.setText(String.format("Delay: %.2f seconds\nTranscription result: %s", roundedDelay, transcript));
            } else {
                delayResult.setText("无法检测到语音起始时间");
            }
        } else {
            delayResult.setText("未识别到关键词");
        }
    } else {
        delayResult.setText("无语音识别结果");
    }
}

5. 错误回调处理

在onError中停止音频监听,避免资源泄漏:

@Override
public void onError(int errorCode) {
    progressBar.setVisibility(View.GONE);
    isListening = false;
    // 根据错误码添加对应提示
    String errorMsg = switch (errorCode) {
        case SpeechRecognizer.ERROR_NO_MATCH -> "未匹配到语音";
        case SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS -> "缺少录音权限";
        default -> "语音识别出错:" + errorCode;
    };
    delayResult.setText(errorMsg);
}

优化建议

  • 调整音量阈值:根据测试环境的噪音水平,修改VOLUME_THRESHOLD的值,避免误触发或漏检测。
  • 连续帧验证:可以改为连续3-5帧都超过阈值才判定为语音开始,提升检测准确性。
  • 本地识别优先:部分Android机型支持本地语音识别(比如Google Pixel系列),可以尝试配置识别参数优先使用本地模型,减少云端延迟对流程的干扰。

内容的提问来源于stack exchange,提问作者Sir Arhm

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 18:15:13