""" 音频管理器模块 负责管理音频输入输出设备 """ import time from typing import Dict, Any, List, Optional import threading class AudioManager: """ 音频管理器 负责管理音频输入输出设备 """ def __init__(self, plugin): """ 初始化音频管理器 Args: plugin: 语音控制插件实例 """ self.plugin = plugin self.enabled = False self.initialized = False # 音频设备列表 self.audio_devices = { 'input': {}, 'output': {} } # 当前设备配置 self.current_devices = { 'input': None, 'output': None } # 音频流管理 self.audio_streams = { 'input': None, 'output': None } # 音频配置 self.audio_config = { 'sample_rate': 16000, 'channels': 1, 'format': 'int16', 'input_buffer_size': 1024, 'output_buffer_size': 1024, 'latency': 'low', 'enable_echo_cancellation': True, 'enable_noise_reduction': True, 'enable_auto_gain': True } # 音频状态 self.audio_state = { 'input_level': 0.0, 'output_level': 0.0, 'is_recording': False, 'is_playing': False, 'last_input_time': 0.0, 'last_output_time': 0.0 } # 设备统计 self.device_stats = { 'devices_found': 0, 'input_devices': 0, 'output_devices': 0, 'devices_connected': 0, 'devices_disconnected': 0, 'data_transferred': 0 } # 线程管理 self.monitor_thread = None self.running = False # 回调函数 self.audio_callbacks = { 'device_connected': [], 'device_disconnected': [], 'input_level_changed': [], 'output_level_changed': [], 'recording_started': [], 'recording_stopped': [], 'playback_started': [], 'playback_stopped': [] } # 时间戳记录 self.last_device_scan = 0.0 self.last_level_update = 0.0 print("✓ 音频管理器已创建") def initialize(self) -> bool: """ 初始化音频管理器 Returns: 是否初始化成功 """ try: # 扫描音频设备 self._scan_audio_devices() # 初始化默认设备 self._initialize_default_devices() self.initialized = True print("✓ 音频管理器初始化完成") return True except Exception as e: print(f"✗ 音频管理器初始化失败: {e}") import traceback traceback.print_exc() return False def enable(self) -> bool: """ 启用音频管理器 Returns: 是否启用成功 """ try: if not self.initialized: print("✗ 音频管理器未初始化") return False self.enabled = True self.running = True # 启动监控线程 self.monitor_thread = threading.Thread(target=self._monitor_loop, daemon=True) self.monitor_thread.start() print("✓ 音频管理器已启用") return True except Exception as e: print(f"✗ 音频管理器启用失败: {e}") import traceback traceback.print_exc() return False def disable(self): """禁用音频管理器""" try: self.enabled = False self.running = False # 等待监控线程结束 if self.monitor_thread and self.monitor_thread.is_alive(): self.monitor_thread.join(timeout=2.0) # 关闭所有音频流 self._close_all_streams() print("✓ 音频管理器已禁用") except Exception as e: print(f"✗ 音频管理器禁用失败: {e}") import traceback traceback.print_exc() def finalize(self): """清理音频管理器资源""" try: self.disable() self.audio_callbacks.clear() self.audio_devices.clear() self.initialized = False print("✓ 音频管理器资源已清理") except Exception as e: print(f"✗ 音频管理器资源清理失败: {e}") import traceback traceback.print_exc() def update(self, dt: float): """ 更新音频管理器状态 Args: dt: 时间增量 """ try: if not self.enabled: return current_time = time.time() # 定期扫描设备 if current_time - self.last_device_scan > 5.0: # 每5秒扫描一次 self._scan_audio_devices() self.last_device_scan = current_time self.last_level_update = current_time except Exception as e: print(f"✗ 音频管理器更新失败: {e}") import traceback traceback.print_exc() def _scan_audio_devices(self): """扫描音频设备""" try: # 模拟设备扫描 # 在实际实现中,这里会调用平台特定的API来发现音频设备 # 模拟输入设备 input_devices = { 0: { 'id': 0, 'name': '系统默认麦克风', 'type': 'input', 'channels': 1, 'sample_rates': [16000, 44100, 48000], 'is_default': True, 'connected': True }, 1: { 'id': 1, 'name': 'USB 麦克风', 'type': 'input', 'channels': 2, 'sample_rates': [16000, 44100, 48000], 'is_default': False, 'connected': True }, 2: { 'id': 2, 'name': '蓝牙耳机麦克风', 'type': 'input', 'channels': 1, 'sample_rates': [16000, 44100], 'is_default': False, 'connected': True } } # 模拟输出设备 output_devices = { 0: { 'id': 0, 'name': '系统默认扬声器', 'type': 'output', 'channels': 2, 'sample_rates': [16000, 44100, 48000], 'is_default': True, 'connected': True }, 1: { 'id': 1, 'name': 'USB 音响', 'type': 'output', 'channels': 2, 'sample_rates': [16000, 44100, 48000, 96000], 'is_default': False, 'connected': True }, 2: { 'id': 2, 'name': '蓝牙耳机', 'type': 'output', 'channels': 2, 'sample_rates': [16000, 44100], 'is_default': False, 'connected': True } } # 更新设备列表 self.audio_devices['input'] = input_devices self.audio_devices['output'] = output_devices # 更新统计信息 self.device_stats['devices_found'] = len(input_devices) + len(output_devices) self.device_stats['input_devices'] = len(input_devices) self.device_stats['output_devices'] = len(output_devices) print(f"✓ 音频设备扫描完成: {len(input_devices)}个输入设备, {len(output_devices)}个输出设备") except Exception as e: print(f"✗ 音频设备扫描失败: {e}") def _initialize_default_devices(self): """初始化默认设备""" try: # 查找默认输入设备 for device_id, device_info in self.audio_devices['input'].items(): if device_info.get('is_default', False): self.current_devices['input'] = device_id break # 查找默认输出设备 for device_id, device_info in self.audio_devices['output'].items(): if device_info.get('is_default', False): self.current_devices['output'] = device_id break print("✓ 默认音频设备初始化完成") except Exception as e: print(f"✗ 默认音频设备初始化失败: {e}") def _monitor_loop(self): """监控循环线程""" try: monitor_interval = 0.1 # 100ms while self.running: if self.enabled: self._update_audio_levels() self._check_device_status() time.sleep(monitor_interval) except Exception as e: print(f"✗ 音频监控循环失败: {e}") def _update_audio_levels(self): """更新音频级别""" try: current_time = time.time() # 模拟输入级别更新 if self.audio_state['is_recording']: import random new_input_level = random.uniform(0.0, 1.0) if abs(new_input_level - self.audio_state['input_level']) > 0.01: self.audio_state['input_level'] = new_input_level self._trigger_audio_callback('input_level_changed', { 'level': new_input_level, 'timestamp': current_time }) # 模拟输出级别更新 if self.audio_state['is_playing']: import random new_output_level = random.uniform(0.0, 1.0) if abs(new_output_level - self.audio_state['output_level']) > 0.01: self.audio_state['output_level'] = new_output_level self._trigger_audio_callback('output_level_changed', { 'level': new_output_level, 'timestamp': current_time }) self.last_level_update = current_time except Exception as e: print(f"✗ 音频级别更新失败: {e}") def _check_device_status(self): """检查设备状态""" try: # 在实际实现中,这里会检查设备连接状态 # 目前只是模拟 pass except Exception as e: print(f"✗ 设备状态检查失败: {e}") def _close_all_streams(self): """关闭所有音频流""" try: self.audio_streams['input'] = None self.audio_streams['output'] = None print("✓ 所有音频流已关闭") except Exception as e: print(f"✗ 音频流关闭失败: {e}") def get_input_devices(self) -> Dict[int, Dict[str, Any]]: """ 获取输入设备列表 Returns: 输入设备字典 """ return self.audio_devices['input'].copy() def get_output_devices(self) -> Dict[int, Dict[str, Any]]: """ 获取输出设备列表 Returns: 输出设备字典 """ return self.audio_devices['output'].copy() def get_all_devices(self) -> Dict[str, Dict[int, Dict[str, Any]]]: """ 获取所有设备列表 Returns: 所有设备字典 """ return { 'input': self.audio_devices['input'].copy(), 'output': self.audio_devices['output'].copy() } def set_input_device(self, device_id: int) -> bool: """ 设置输入设备 Args: device_id: 设备ID Returns: 是否设置成功 """ try: if device_id in self.audio_devices['input']: old_device = self.current_devices['input'] self.current_devices['input'] = device_id print(f"✓ 输入设备已设置: {self.audio_devices['input'][device_id]['name']}") # 触发设备变更回调 self._trigger_audio_callback('device_connected', { 'device_type': 'input', 'device_id': device_id, 'device_name': self.audio_devices['input'][device_id]['name'], 'old_device_id': old_device }) return True else: print(f"✗ 输入设备不存在: ID {device_id}") return False except Exception as e: print(f"✗ 输入设备设置失败: {e}") return False def set_output_device(self, device_id: int) -> bool: """ 设置输出设备 Args: device_id: 设备ID Returns: 是否设置成功 """ try: if device_id in self.audio_devices['output']: old_device = self.current_devices['output'] self.current_devices['output'] = device_id print(f"✓ 输出设备已设置: {self.audio_devices['output'][device_id]['name']}") # 触发设备变更回调 self._trigger_audio_callback('device_connected', { 'device_type': 'output', 'device_id': device_id, 'device_name': self.audio_devices['output'][device_id]['name'], 'old_device_id': old_device }) return True else: print(f"✗ 输出设备不存在: ID {device_id}") return False except Exception as e: print(f"✗ 输出设备设置失败: {e}") return False def get_current_input_device(self) -> Optional[Dict[str, Any]]: """ 获取当前输入设备 Returns: 当前输入设备信息或None """ try: device_id = self.current_devices['input'] if device_id is not None and device_id in self.audio_devices['input']: return self.audio_devices['input'][device_id] return None except Exception as e: print(f"✗ 当前输入设备获取失败: {e}") return None def get_current_output_device(self) -> Optional[Dict[str, Any]]: """ 获取当前输出设备 Returns: 当前输出设备信息或None """ try: device_id = self.current_devices['output'] if device_id is not None and device_id in self.audio_devices['output']: return self.audio_devices['output'][device_id] return None except Exception as e: print(f"✗ 当前输出设备获取失败: {e}") return None def start_recording(self) -> bool: """ 开始录音 Returns: 是否开始成功 """ try: if not self.enabled: print("✗ 音频管理器未启用") return False # 模拟开始录音 self.audio_state['is_recording'] = True self.audio_state['last_input_time'] = time.time() # 触发录音开始回调 self._trigger_audio_callback('recording_started', { 'device_id': self.current_devices['input'], 'timestamp': time.time() }) print("✓ 录音已开始") return True except Exception as e: print(f"✗ 录音开始失败: {e}") return False def stop_recording(self) -> bool: """ 停止录音 Returns: 是否停止成功 """ try: self.audio_state['is_recording'] = False # 触发录音停止回调 self._trigger_audio_callback('recording_stopped', { 'device_id': self.current_devices['input'], 'timestamp': time.time() }) print("✓ 录音已停止") return True except Exception as e: print(f"✗ 录音停止失败: {e}") return False def start_playback(self) -> bool: """ 开始播放 Returns: 是否开始成功 """ try: if not self.enabled: print("✗ 音频管理器未启用") return False # 模拟开始播放 self.audio_state['is_playing'] = True self.audio_state['last_output_time'] = time.time() # 触发播放开始回调 self._trigger_audio_callback('playback_started', { 'device_id': self.current_devices['output'], 'timestamp': time.time() }) print("✓ 播放已开始") return True except Exception as e: print(f"✗ 播放开始失败: {e}") return False def stop_playback(self) -> bool: """ 停止播放 Returns: 是否停止成功 """ try: self.audio_state['is_playing'] = False # 触发播放停止回调 self._trigger_audio_callback('playback_stopped', { 'device_id': self.current_devices['output'], 'timestamp': time.time() }) print("✓ 播放已停止") return True except Exception as e: print(f"✗ 播放停止失败: {e}") return False def get_audio_level(self, stream_type: str) -> float: """ 获取音频级别 Args: stream_type: 流类型('input'或'output') Returns: 音频级别(0.0-1.0) """ try: if stream_type == 'input': return self.audio_state['input_level'] elif stream_type == 'output': return self.audio_state['output_level'] else: print(f"✗ 无效的流类型: {stream_type}") return 0.0 except Exception as e: print(f"✗ 音频级别获取失败: {e}") return 0.0 def set_audio_config(self, config: Dict[str, Any]) -> bool: """ 设置音频配置 Args: config: 配置字典 Returns: 是否设置成功 """ try: self.audio_config.update(config) print(f"✓ 音频配置已更新: {self.audio_config}") return True except Exception as e: print(f"✗ 音频配置设置失败: {e}") return False def get_audio_config(self) -> Dict[str, Any]: """ 获取音频配置 Returns: 配置字典 """ return self.audio_config.copy() def is_recording(self) -> bool: """ 检查是否正在录音 Returns: 是否正在录音 """ return self.audio_state['is_recording'] def is_playing(self) -> bool: """ 检查是否正在播放 Returns: 是否正在播放 """ return self.audio_state['is_playing'] def _trigger_audio_callback(self, callback_type: str, data: Dict[str, Any]): """ 触发音频回调 Args: callback_type: 回调类型 data: 回调数据 """ try: if callback_type in self.audio_callbacks: for callback in self.audio_callbacks[callback_type]: try: callback(data) except Exception as e: print(f"✗ 音频回调执行失败: {e}") except Exception as e: print(f"✗ 音频回调触发失败: {e}") def register_audio_callback(self, callback_type: str, callback: callable): """ 注册音频回调 Args: callback_type: 回调类型 callback: 回调函数 """ try: if callback_type in self.audio_callbacks: self.audio_callbacks[callback_type].append(callback) print(f"✓ 音频回调已注册: {callback_type}") else: print(f"✗ 无效的回调类型: {callback_type}") except Exception as e: print(f"✗ 音频回调注册失败: {e}") def unregister_audio_callback(self, callback_type: str, callback: callable): """ 注销音频回调 Args: callback_type: 回调类型 callback: 回调函数 """ try: if callback_type in self.audio_callbacks: if callback in self.audio_callbacks[callback_type]: self.audio_callbacks[callback_type].remove(callback) print(f"✓ 音频回调已注销: {callback_type}") except Exception as e: print(f"✗ 音频回调注销失败: {e}") def get_device_stats(self) -> Dict[str, int]: """ 获取设备统计信息 Returns: 统计信息字典 """ return self.device_stats.copy() def reset_device_stats(self): """重置设备统计信息""" try: self.device_stats = { 'devices_found': 0, 'input_devices': 0, 'output_devices': 0, 'devices_connected': 0, 'devices_disconnected': 0, 'data_transferred': 0 } print("✓ 音频管理器统计信息已重置") except Exception as e: print(f"✗ 音频管理器统计信息重置失败: {e}")