| """ | |
| 音频捕获模块门面。 | |
| 根据配置选择并管理具体的音频捕获策略。 | |
| """ | |
| from multiprocessing import Queue | |
| from voice_dialogue.utils.logger import logger | |
| from .aec_capture import AecCapture | |
| from .pyaudio_capture import PyAudioCapture | |
| class AudioCapture: | |
| """ | |
| 音频捕获器门面 (Facade)。 | |
| 根据配置选择并管理具体的音频捕获策略(PyAudio 或 AEC)。 | |
| 为上层应用提供统一的、简化的音频捕获接口。 | |
| 它不是一个线程,而是线程安全策略的管理者。 | |
| """ | |
| def __init__( | |
| self, | |
| audio_frames_queue: Queue, | |
| enable_echo_cancellation: bool = True, | |
| ): | |
| """ | |
| 初始化音频捕获器。 | |
| Args: | |
| audio_frames_queue (Queue): 用于存放捕获的音频帧的队列。 | |
| enable_echo_cancellation (bool): 是否启用回声消除功能。 | |
| 若为 True,则使用 AEC 原生库; | |
| 否则,使用 PyAudio。 | |
| """ | |
| self._strategy = None | |
| try: | |
| if enable_echo_cancellation: | |
| self._strategy = AecCapture(audio_frames_queue=audio_frames_queue) | |
| else: | |
| self._strategy = PyAudioCapture(audio_frames_queue=audio_frames_queue) | |
| logger.info(f"音频捕获策略已选择: {self._strategy.__class__.__name__}") | |
| except Exception as e: | |
| logger.error( | |
| f"初始化 {AecCapture.__name__ if enable_echo_cancellation else PyAudioCapture.__name__} 失败: {e}, 将回退到 PyAudio。") | |
| # 只有在尝试 AEC 失败时才回退 | |
| if not isinstance(self._strategy, PyAudioCapture): | |
| self._strategy = PyAudioCapture(audio_frames_queue=audio_frames_queue) | |
| logger.info(f"已回退到音频捕获策略: {self._strategy.__class__.__name__}") | |
| def start(self): | |
| """启动音频捕获线程。""" | |
| self._strategy.start() | |
| def stop(self): | |
| """停止音频捕获线程。""" | |
| self._strategy.exit() | |
| def pause(self): | |
| """暂停音频捕获。""" | |
| self._strategy.pause() | |
| def resume(self): | |
| """恢复音频捕获。""" | |
| self._strategy.resume() | |
| def is_paused(self) -> bool: | |
| """检查捕获器是否已暂停。""" | |
| return self._strategy.is_paused | |
| def is_ready(self) -> bool: | |
| """检查捕获线程是否已准备就绪。""" | |
| return self._strategy.is_ready | |
| def is_alive(self): | |
| return self._strategy.is_alive() | |