From e40191f0a15c3ce3a9fad093a88fef42b587761e Mon Sep 17 00:00:00 2001 From: Nikhil dangi Date: Thu, 26 Mar 2026 19:35:49 +0530 Subject: [PATCH] Upgrade audio writing --- bot/audio_recorder.py | 57 +++++++++++++++++++++++++++++++------------ bot/main.py | 21 +++++++++++----- 2 files changed, 57 insertions(+), 21 deletions(-) diff --git a/bot/audio_recorder.py b/bot/audio_recorder.py index 459ab7a..9e0ae28 100644 --- a/bot/audio_recorder.py +++ b/bot/audio_recorder.py @@ -5,6 +5,7 @@ from pathlib import Path from typing import Dict, Optional import logging +import queue logger = logging.getLogger(__name__) @@ -20,6 +21,12 @@ def __init__(self, meeting_id: str, output_dir: str = "recordings"): self.sample_rate = 48000 self.channels = 2 self.sample_width = 2 + self._queue = queue.Queue() + self._running = True + + # Start background worker thread + self._thread = threading.Thread(target=self._worker, daemon=True) + self._thread.start() logger.info(f"AudioSink initialized for meeting {meeting_id}") @@ -27,18 +34,8 @@ def write(self, user, data): if not data: return - with self._lock: - user_id = user.id if hasattr(user, 'id') else user - - if user_id not in self._user_writers: - username = user.name if hasattr(user, 'name') else f"user_{user_id}" - self._init_user_writer(user_id, username) - - try: - writer = self._user_writers[user_id] - writer.writeframes(data) - except Exception as e: - logger.error(f"Error writing audio for user {user_id}: {e}") + user_id = user.id if hasattr(user, 'id') else user + self._queue.put((user_id, user, data)) def _init_user_writer(self, user_id: int, username: str): safe_username = "".join(c for c in username if c.isalnum() or c in (' ', '-', '_')) @@ -56,17 +53,47 @@ def _init_user_writer(self, user_id: int, username: str): except Exception as e: logger.error(f"Failed to create audio file for user {user_id}: {e}") + def _worker(self): + while self._running: + try: + item = self._queue.get() + + if item is None: + break + + user_id, user, data = item + + # Get or create writer (LOCK ONLY FOR THIS PART) + with self._lock: + if user_id not in self._user_writers: + username = user.name if hasattr(user, 'name') else f"user_{user_id}" + self._init_user_writer(user_id, username) + + writer = self._user_writers.get(user_id) + + # WRITE OUTSIDE LOCK (IMPORTANT) + if writer: + writer.writeframes(data) + + except Exception as e: + logger.error(f"Worker error: {e}") + def cleanup(self): + logger.info(f"Cleaning up audio sink for meeting {self.meeting_id}") + + # Stop worker thread first + self._running = False + self._queue.put(None) + self._thread.join() + with self._lock: - logger.info(f"Cleaning up audio sink for meeting {self.meeting_id}") - for user_id, writer in self._user_writers.items(): try: writer.close() logger.info(f"Closed audio file for user {user_id}") except Exception as e: logger.error(f"Error closing audio file for user {user_id}: {e}") - + self._user_writers.clear() def get_recording_info(self) -> dict: diff --git a/bot/main.py b/bot/main.py index d34dedc..ff971e6 100644 --- a/bot/main.py +++ b/bot/main.py @@ -1,3 +1,8 @@ +import ssl +import certifi +import aiohttp +from discord.ext import commands + import discord from discord import app_commands from discord.ext import commands @@ -348,28 +353,32 @@ async def end_meeting(interaction: discord.Interaction): ) -def main(): +async def main(): token = os.getenv("DISCORD_BOT_TOKEN") if not token: logger.error("DISCORD_BOT_TOKEN not found in environment variables") - logger.error("Please create a .env file with your bot token") sys.exit(1) Path("recordings").mkdir(exist_ok=True) + ssl_context = ssl.create_default_context(cafile=certifi.where()) + connector = aiohttp.TCPConnector(ssl=ssl_context) + try: logger.info("Starting bot...") - bot.run(token, log_handler=None) + + async with aiohttp.ClientSession(connector=connector) as session: + bot.http._HTTPClient__session = session # 🔥 inject SSL session + await bot.start(token) + except discord.LoginFailure: logger.error("Invalid bot token") - sys.exit(1) except KeyboardInterrupt: logger.info("Bot stopped by user") except Exception as e: logger.error(f"Fatal error: {e}", exc_info=True) - sys.exit(1) if __name__ == "__main__": - main() + asyncio.run(main())