基于webrtcvad的类Siri语音录制:WAV文件无声音问题排查
问题原因
你的代码核心问题在于音频数据类型不匹配:
sounddevice.RawInputStream输出的indata是numpy.ndarray对象,但webrtcvad.is_speech需要传入原始字节流(bytes);同时你将numpy数组直接存入self.frames,后续用b''.join(self.frames)拼接时无法得到正确的音频字节数据,最终导致保存的WAV文件无声。
修复方案
需要将RawInputStream输出的numpy数组转换为bytes后再传入VAD处理,同时确保self.frames存储的是字节数据。修改后的完整代码如下:
import numpy as np import sounddevice as sd from scipy.io.wavfile import write import webrtcvad import threading class VoiceActivityDetector: def __init__(self, frame_duration_ms=30, padding_duration_ms=300, vad_aggressiveness=3): self.vad = webrtcvad.Vad(vad_aggressiveness) self.frame_duration_ms = frame_duration_ms self.padding_duration_ms = padding_duration_ms self.original_num_padding_frames = padding_duration_ms // frame_duration_ms self.num_padding_frames = self.original_num_padding_frames self.frames = [] self.triggered = False self.has_spoken = False def process_frame(self, frame_bytes): # frame_bytes 是bytes类型,符合webrtcvad要求 is_speech = self.vad.is_speech(frame_bytes, 16000) if not self.triggered: self.frames.append(frame_bytes) if is_speech: self.triggered = True self.has_spoken = True # 保留触发前的最后N帧,确保语音开头完整 self.frames = self.frames[-self.original_num_padding_frames:] print("speech detected") else: self.frames.append(frame_bytes) if not is_speech and self.has_spoken: self.num_padding_frames -= 1 print(f'Silence countdown: {self.num_padding_frames}') if self.num_padding_frames == 0: print('silence detected...') return False # 停止录制 elif is_speech: self.num_padding_frames = self.original_num_padding_frames return True def record(self, fs=16000): self.stop_recording = threading.Event() def callback(indata, frames, time, status): if status: print(status) # 将numpy数组转换为bytes,这是关键修复点 frame_bytes = indata.tobytes() if not self.process_frame(frame_bytes): self.stop_recording.set() blocksize = int(fs * self.frame_duration_ms / 1000) with sd.RawInputStream( samplerate=fs, blocksize=blocksize, channels=1, dtype='int16', callback=callback ): while not self.stop_recording.is_set(): sd.sleep(100) # 将拼接后的字节转换为numpy int16数组 recording = np.frombuffer(b''.join(self.frames), dtype=np.int16) return recording, fs def get_user_response(): vad = VoiceActivityDetector() print("Please start speaking, when finished, pause and the recording will end...") recording, fs = vad.record() print('Saving the recording...') output_filename = "temporary.wav" write(output_filename, fs, recording) print(f"Recording saved as {output_filename}") if __name__ == "__main__": get_user_response()
关键修改点
- 在
callback函数中添加frame_bytes = indata.tobytes(),将numpy数组转换为符合VAD要求的字节流 - 确保
process_frame接收和存储的都是bytes类型数据,后续拼接和转换为numpy数组的逻辑才能正常工作
内容的提问来源于stack exchange,提问作者helpme
相关产品推荐
相关产品推荐

