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

Python无损耗连续录音求助:解决sd.wait()耗时导致的音频丢失

实时语音转文字项目的音频录制丢失问题解决

问题描述

我正在开发一个实时语音转文字项目,需要连续录制音频:每5秒录制一段,每次将最后2段(共10秒)写入文件。但Python脚本中sd.wait()耗时约5.06秒,导致音频丢失。通过时间戳排查确认,仅sd.wait()这一行占用额外时间。

原代码

import sounddevice as sd
import numpy as np
from scipy.io.wavfile import write
from pydub import AudioSegment
import time as t
import os


seconds = 5
fs = 44100
recordsMaxLength = 2


def record_audio(seconds=seconds, fs=fs, recordsMaxLength=recordsMaxLength):
    audioIndex = 0
    current_time = 0
    records = []
    output_dir = "records"
    concatedRecords = None
    os.makedirs(output_dir, exist_ok=True)

    try:
        for i in range(3):
            print("time between starts:", t.time()-current_time)
            record = sd.rec(int(seconds * fs), samplerate=fs, channels=2, dtype='int16')
            current_time = t.time()
            sd.wait()
            print("time: ", t.time() - current_time)
            current_time = t.time()
            if len(records) < recordsMaxLength:
                records.append(record)
            else:
                for i in range(recordsMaxLength - 1):
                    records[i] = records[i + 1]
                records[recordsMaxLength - 1] = record

            if len(records) > 1:
                concatedRecords = np.concatenate(records)

            audioIndex += 1
    except KeyboardInterrupt:
        pass

    # If there are no records, there's nothing to save
    if concatedRecords is not None:
        # Convert numpy array to pydub AudioSegment
        audio_segment = AudioSegment(
            data=concatedRecords.tobytes(),
            sample_width=concatedRecords.dtype.itemsize,
            frame_rate=fs,
            channels=2
        )

        # Export the AudioSegment as an MP3 file
        output_path = os.path.join(output_dir, "records.mp3")
        audio_segment.export(output_path, format="mp3")
        print(f"Saved recording as {output_path}")
    else:
        print("No audio recorded to save.")

解决方案

核心问题分析

sd.wait()会阻塞主线程直到当前录制完成,但实际录制时长略超过设定的5秒,导致下一次录制启动延迟,出现音频间隙。要实现无间隙连续录制,需改用非阻塞录制+回调函数的方式,避免主线程被阻塞。

改进后代码

import sounddevice as sd
import numpy as np
from pydub import AudioSegment
import os
import sys

seconds = 5
fs = 44100
records_max_length = 2
records = []
output_dir = "records"
os.makedirs(output_dir, exist_ok=True)

def callback(indata, frames, time, status):
    """音频录制回调函数,实时处理录制数据"""
    global records
    if status:
        print(status, file=sys.stderr)
    # 保存当前录制的片段
    records.append(indata.copy())
    # 仅保留最近的2段音频
    if len(records) > records_max_length:
        records.pop(0)
    # 当凑齐2段时,合并并写入文件
    if len(records) == records_max_length:
        concated_records = np.concatenate(records)
        audio_segment = AudioSegment(
            data=concated_records.tobytes(),
            sample_width=concated_records.dtype.itemsize,
            frame_rate=fs,
            channels=2
        )
        output_path = os.path.join(output_dir, "latest_records.mp3")
        audio_segment.export(output_path, format="mp3")
        print(f"已更新录制文件: {output_path}")

def start_continuous_recording():
    # 启动非阻塞连续录制,每5秒触发一次回调
    with sd.InputStream(samplerate=fs, channels=2, dtype='int16',
                       blocksize=int(seconds * fs), callback=callback):
        print("开始连续录制,按Ctrl+C停止...")
        while True:
            pass

if __name__ == "__main__":
    try:
        start_continuous_recording()
    except KeyboardInterrupt:
        print("\n录制已停止")

关键改进点

  • 采用sd.InputStream的回调机制,非阻塞录制,彻底避免sd.wait()的阻塞延迟
  • 回调函数实时处理音频片段,自动维护最近2段数据,无需手动控制录制循环
  • 每次凑齐2段音频后立即写入文件,保证实时性
  • 主线程仅保持运行状态,不参与录制阻塞,确保音频录制无间隙

内容的提问来源于stack exchange,提问作者Haluk Umut Berkut

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 13:55:22