diff --git a/app/internal/bot_manager.py b/app/internal/bot_manager.py index e860264..7545ed6 100644 --- a/app/internal/bot_manager.py +++ b/app/internal/bot_manager.py @@ -4,7 +4,7 @@ import os from discord import VoiceClient, VoiceChannel, opus, Activity, ActivityType, Intents from discord.ext import commands from typing import Optional, Dict -from internal.NoiseGatev2 import AudioTransmitter +from internal.NoiseGatev2 import AudioStreamManager, NoiseGateSource from internal.logger import create_logger LOGGER = create_logger(__name__) @@ -105,40 +105,23 @@ class DiscordBotManager: try: self._voice_ready_event.clear() voice_client = await channel.connect(timeout=60.0, reconnect=True) - LOGGER.debug("Voice client connecting...") - await asyncio.wait_for(self._voice_ready_event.wait(), timeout=15.0) - LOGGER.info("Bot voice connection is ready.") - LOGGER.info(f"Checking opus status before transmitter init: {opus.is_loaded()}") - - try: - encoder = opus.OpusEncoder() - LOGGER.info(f"Manually created OpusEncoder successfully: {encoder}") - except Exception as e: - LOGGER.error(f"MANUAL ENCODER CREATION FAILED: {e}", exc_info=True) - - # Create and start the new AudioTransmitter - transmitter = AudioTransmitter( - voice_client=voice_client, - noise_gate_threshold=ng_threshold, - loop=self.loop, - input_device_index=device_id - ) + # Create a single audio manager for this connection + audio_manager = AudioStreamManager(input_device_index=device_id) - # Start the transmitter's main loop as a background task - transmitter_task = self.loop.create_task(transmitter.start()) + # Create the noise-gated audio source + audio_source = NoiseGateSource(audio_manager.get_stream(), threshold=ng_threshold) + + # Play the source + voice_client.play(audio_source, after=lambda e: print(f'Player error: {e}') if e else None) self.voice_connections[guild_id] = { "client": voice_client, - "transmitter": transmitter, - "task": transmitter_task + "audio_manager": audio_manager } - LOGGER.info(f"Joined guild {guild_id} and audio transmitter is running.") + LOGGER.info(f"Joined guild {guild_id} and started audio stream.") - except asyncio.TimeoutError: - LOGGER.error(f"Timeout waiting for bot to join voice channel {channel_id}.") - raise RuntimeError("Bot failed to confirm voice connection within timeout.") except Exception as e: LOGGER.error(f"Failed to connect to voice channel: {e}", exc_info=True) raise @@ -149,18 +132,15 @@ class DiscordBotManager: connection_info = self.voice_connections.get(guild_id) if not connection_info: raise RuntimeError("Not connected to the specified guild's voice channel.") - # Stop the transmitter task and clean up its resources - transmitter = connection_info.get("transmitter") - task = connection_info.get("task") - if transmitter: - LOGGER.info(f"Stopping audio transmitter for guild {guild_id}.") - await transmitter.stop() - if task and not task.done(): - task.cancel() - voice_client = connection_info.get("client") if voice_client and voice_client.is_connected(): + voice_client.stop() await voice_client.disconnect() + + # Terminate the audio manager to release PyAudio resources + audio_manager = connection_info.get("audio_manager") + if audio_manager: + audio_manager.terminate() del self.voice_connections[guild_id] LOGGER.info(f"Left guild {guild_id} voice channel.")