Update PDAB

- Added standard debugger file for logging
- Added fault handler to see what happens if it faults
This commit is contained in:
Logan Cusano
2024-04-28 03:17:08 -04:00
parent fc6c114473
commit 098dfc9a10
3 changed files with 85 additions and 60 deletions

View File

@@ -6,10 +6,12 @@ import time
import pyaudio import pyaudio
import discord import discord
import numpy import numpy
from debugger import setup_logger
voice_connection = None voice_connection = None
LOGGER = logging.getLogger("Discord_Radio_Bot.NoiseGateV2") # Configure logging
logger = setup_logger('NoiseGatev2')
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences
@@ -30,19 +32,19 @@ class AudioStream:
if _input: if _input:
self.paInstance_kwargs['input_device_index'] = _input_device_index self.paInstance_kwargs['input_device_index'] = _input_device_index
else: else:
LOGGER.warning(f"[AudioStream.__init__]:\tInput was not enabled." logger.warning(f"[AudioStream.__init__]:\tInput was not enabled."
f" Reinitialize with '_input=True'") f" Reinitialize with '_input=True'")
if _output_device_index: if _output_device_index:
if _output: if _output:
self.paInstance_kwargs['output_device_index'] = _output_device_index self.paInstance_kwargs['output_device_index'] = _output_device_index
else: else:
LOGGER.warning(f"[AudioStream.__init__]:\tOutput was not enabled." logger.warning(f"[AudioStream.__init__]:\tOutput was not enabled."
f" Reinitialize with '_output=True'") f" Reinitialize with '_output=True'")
if _init_on_startup: if _init_on_startup:
# Init PyAudio instance # Init PyAudio instance
LOGGER.info("Creating PyAudio instance") logger.info("Creating PyAudio instance")
self.paInstance = pyaudio.PyAudio() self.paInstance = pyaudio.PyAudio()
# Define and initialize stream object if we have been passed a device ID (pyaudio.open) # Define and initialize stream object if we have been passed a device ID (pyaudio.open)
@@ -50,27 +52,30 @@ class AudioStream:
if _output_device_index or _input_device_index: if _output_device_index or _input_device_index:
if _init_on_startup: if _init_on_startup:
LOGGER.info("Init stream") logger.info("Init stream")
self.init_stream() self.init_stream()
def init_stream(self, _new_output_device_index: int = None, _new_input_device_index: int = None): def init_stream(self, _new_output_device_index: int = None, _new_input_device_index: int = None):
logger.info("Checking what device has been set if any")
# Check what device was asked to be changed (or set) # Check what device was asked to be changed (or set)
if _new_input_device_index: if _new_input_device_index:
if self.paInstance_kwargs['input']: if self.paInstance_kwargs['input']:
self.paInstance_kwargs['input_device_index'] = _new_input_device_index self.paInstance_kwargs['input_device_index'] = _new_input_device_index
else: else:
LOGGER.warning(f"[AudioStream.init_stream]:\tInput was not enabled when initialized." logger.warning(f"[AudioStream.init_stream]:\tInput was not enabled when initialized."
f" Reinitialize with '_input=True'") f" Reinitialize with '_input=True'")
if _new_output_device_index: if _new_output_device_index:
if self.paInstance_kwargs['output']: if self.paInstance_kwargs['output']:
self.paInstance_kwargs['output_device_index'] = _new_output_device_index self.paInstance_kwargs['output_device_index'] = _new_output_device_index
else: else:
LOGGER.warning(f"[AudioStream.init_stream]:\tOutput was not enabled when initialized." logger.warning(f"[AudioStream.init_stream]:\tOutput was not enabled when initialized."
f" Reinitialize with '_output=True'") f" Reinitialize with '_output=True'")
logger.info("Close the stream if it's open")
self.close_if_open() self.close_if_open()
logger.info("Open the audio stream")
# Open the stream # Open the stream
self.stream = self.paInstance.open(**self.paInstance_kwargs) self.stream = self.paInstance.open(**self.paInstance_kwargs)
@@ -80,10 +85,10 @@ class AudioStream:
if self.stream.is_active(): if self.stream.is_active():
self.stream.stop_stream() self.stream.stop_stream()
self.stream.close() self.stream.close()
LOGGER.debug(f"[ReopenStream.close_if_open]:\t Stream was open; It was closed.") logger.debug(f"[ReopenStream.close_if_open]:\t Stream was open; It was closed.")
def list_devices(self, _display_input_devices: bool = True, _display_output_devices: bool = True): def list_devices(self, _display_input_devices: bool = True, _display_output_devices: bool = True):
LOGGER.info('Getting a list of the devices connected') logger.info('Getting a list of the devices connected')
info = self.paInstance.get_host_api_info_by_index(0) info = self.paInstance.get_host_api_info_by_index(0)
numdevices = info.get('deviceCount') numdevices = info.get('deviceCount')
@@ -96,13 +101,13 @@ class AudioStream:
input_device = self.paInstance.get_device_info_by_host_api_device_index(0, i).get('name') input_device = self.paInstance.get_device_info_by_host_api_device_index(0, i).get('name')
devices['Input'][i] = input_device devices['Input'][i] = input_device
if _display_input_devices: if _display_input_devices:
LOGGER.debug(f"Input Device id {i} - {input_device}") logger.debug(f"Input Device id {i} - {input_device}")
if (self.paInstance.get_device_info_by_host_api_device_index(0, i).get('maxOutputChannels')) > 0: if (self.paInstance.get_device_info_by_host_api_device_index(0, i).get('maxOutputChannels')) > 0:
output_device = self.paInstance.get_device_info_by_host_api_device_index(0, i).get('name') output_device = self.paInstance.get_device_info_by_host_api_device_index(0, i).get('name')
devices['Output'][i] = output_device devices['Output'][i] = output_device
if _display_output_devices: if _display_output_devices:
LOGGER.debug(f"Output Device id {i} - {output_device}") logger.debug(f"Output Device id {i} - {output_device}")
return devices return devices
@@ -126,28 +131,31 @@ class NoiseGate(AudioStream):
def run(self) -> None: def run(self) -> None:
global voice_connection global voice_connection
# Start the audio stream # Start the audio stream
LOGGER.debug(f"Starting stream") logger.debug(f"Starting stream")
self.stream.start_stream() try:
# Start the stream to discord self.stream.start_stream()
self.core() # Start the stream to discord
self.core()
except Exception as e:
logger.error(err)
def core(self, error=None): def core(self, error=None):
if error: if error:
LOGGER.warning(error) logger.warning(error)
while not voice_connection.is_connected(): while not voice_connection.is_connected():
time.sleep(.2) time.sleep(.2)
if not voice_connection.is_playing(): if not voice_connection.is_playing():
LOGGER.debug(f"Playing stream to discord") logger.debug(f"Playing stream to discord")
voice_connection.play(self.NGStream, after=self.core) voice_connection.play(self.NGStream, after=self.core)
async def close(self): async def close(self):
LOGGER.debug(f"Closing") logger.debug(f"Closing")
await voice_connection.disconnect() await voice_connection.disconnect()
if self.stream.is_active: if self.stream.is_active:
self.stream.stop_stream() self.stream.stop_stream()
LOGGER.debug(f"Stopping stream") logger.debug(f"Stopping stream")
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences
@@ -169,9 +177,9 @@ class NoiseGateStream(discord.AudioSource):
if self.process_set_count % 10 == 0: if self.process_set_count % 10 == 0:
if buffer_decibel >= self.stream.THRESHOLD: if buffer_decibel >= self.stream.THRESHOLD:
LOGGER.debug(f"[Noisegate Open] {buffer_decibel} db") logger.debug(f"[Noisegate Open] {buffer_decibel} db")
else: else:
LOGGER.debug(f"[Noisegate Closed] {buffer_decibel} db") logger.debug(f"[Noisegate Closed] {buffer_decibel} db")
if buffer_decibel >= self.stream.THRESHOLD: if buffer_decibel >= self.stream.THRESHOLD:
self.NG_fadeout_count = self.NG_fadeout self.NG_fadeout_count = self.NG_fadeout
@@ -182,13 +190,13 @@ class NoiseGateStream(discord.AudioSource):
else: else:
if self.NG_fadeout_count > 0: if self.NG_fadeout_count > 0:
self.NG_fadeout_count -= 1 self.NG_fadeout_count -= 1
LOGGER.debug(f"Frames in fadeout remaining: {self.NG_fadeout_count}") logger.debug(f"Frames in fadeout remaining: {self.NG_fadeout_count}")
self.process_set_count += 1 self.process_set_count += 1
if curr_buffer: if curr_buffer:
return bytes(curr_buffer) return bytes(curr_buffer)
except OSError as e: except OSError as e:
LOGGER.warning(e) logger.warning(e)
pass pass
def audio_datalist_set_volume(self, datalist, volume): def audio_datalist_set_volume(self, datalist, volume):

28
debugger.py Normal file
View File

@@ -0,0 +1,28 @@
import logging
import os
running_dir = os.path.dirname(__file__)
# Ensure the directory exists
log_dir = f"{running_dir}/logs"
os.makedirs(log_dir, exist_ok=True)
def setup_logger(namespace):
# Create the file if it doesn't exist
log_file = f"{running_dir}/logs/pdab.log"
open(log_file, 'a').close()
# Configure logging
logFormatter = logging.Formatter("%(asctime)s [%(threadName)-16.16s] [%(levelname)-7.7s] - %(message)s", "%Y-%m-%d %H:%M:%S")
logger = logging.getLogger(namespace)
logger.setLevel(logging.INFO)
fileHandler = logging.FileHandler(log_file)
fileHandler.setFormatter(logFormatter)
logger.addHandler(fileHandler)
consoleHandler = logging.StreamHandler()
consoleHandler.setFormatter(logFormatter)
logger.addHandler(consoleHandler)
return logger

61
main.py
View File

@@ -1,6 +1,5 @@
# Python client file (client.py) # Python client file (client.py)
import argparse import argparse
import logging
import os import os
import platform import platform
import socketio import socketio
@@ -8,29 +7,11 @@ import asyncio
from discord import Intents, opus from discord import Intents, opus
from discord.ext import commands from discord.ext import commands
from NoiseGatev2 import NoiseGate from NoiseGatev2 import NoiseGate
from debugger import setup_logger, running_dir
import faulthandler
faulthandler.enable()
running_dir = os.path.dirname(__file__) logger = setup_logger('main')
# Ensure the directory exists
log_dir = f"{running_dir}/logs"
os.makedirs(log_dir, exist_ok=True)
# Create the file if it doesn't exist
log_file = f"{running_dir}/logs/pdab.log"
open(log_file, 'a').close()
# Configure logging
logFormatter = logging.Formatter("%(asctime)s [%(threadName)-12.12s] [%(levelname)-5.5s] %(message)s")
logger = logging.getLogger('main')
logger.setLevel(logging.INFO)
fileHandler = logging.FileHandler(log_file)
fileHandler.setFormatter(logFormatter)
logger.addHandler(fileHandler)
consoleHandler = logging.StreamHandler()
consoleHandler.setFormatter(logFormatter)
logger.addHandler(consoleHandler)
# Example usage # Example usage
logger.info("Logging initialized successfully.") logger.info("Logging initialized successfully.")
@@ -43,14 +24,19 @@ ng_threshold = None
### Core functions ### Core functions
def load_opus(): def load_opus():
logger.info(f"Running dir: '{running_dir}'")
processor = platform.machine() processor = platform.machine()
logger.info(f"Processor: {processor}") logger.info(f"Processor: {processor}")
logger.info(f'OS: {os.name}')
if os.name == 'nt': if os.name == 'nt':
opus_path = f'{running_dir}/opus/libopus_amd64.dll' if processor == "AMD64" else None opus_path = f'{running_dir}/opus/libopus_amd64.dll' if processor == "AMD64" else None
else: else:
opus_path = f'{running_dir}/opus/libopus_aarcch64.so' if processor == "aarch64" else f'{running_dir}/opus/libopus_armv7l.so' opus_path = f'{running_dir}/opus/libopus_aarcch64.so' if processor == "aarch64" else f'{running_dir}/opus/libopus_armv7l.so'
logger.debug(f"Opus path: '{opus_path}'")
logger.info(f"Opus path: '{opus_path}'")
if opus_path: if opus_path:
opus.load_opus(opus_path) opus.load_opus(opus_path)
logger.info(f"Loaded OPUS library from {opus_path}") logger.info(f"Loaded OPUS library from {opus_path}")
@@ -85,6 +71,7 @@ async def join_voice_channel(channel_id):
logging.error(e) logging.error(e)
logging.info('error encountered') logging.info('error encountered')
async def leave_voice_channel(guild_id): async def leave_voice_channel(guild_id):
guild = await client.fetch_guild(guild_id) guild = await client.fetch_guild(guild_id)
logger.info(f"Leaving voice channel in guild {guild}") logger.info(f"Leaving voice channel in guild {guild}")
@@ -198,19 +185,14 @@ async def on_ready():
logger.info("Loading OPUS library") logger.info("Loading OPUS library")
load_opus() load_opus()
if not opus.is_loaded(): logger.info(opus.is_loaded())
return
# Send update to socket server if opus.is_loaded():
try:
logger.info('Emitting to the server') logger.info('Emitting to the server')
await sio.emit('discord_ready', {'message': 'Discord bot is ready'}) await sio.emit('discord_ready', {'message': 'Discord bot is ready'})
except Exception as e:
logger.error(f"Error emitting to the server: {e}")
logger.info('Server not ready yet')
async def main(args): async def start_bot(args):
global client, device_id, ng_threshold global client, device_id, ng_threshold
# Connect to the WebSocket server # Connect to the WebSocket server
@@ -241,6 +223,13 @@ def parse_arguments():
if __name__ == "__main__": if __name__ == "__main__":
args = parse_arguments() try:
logger.info("Arguments: %s", args) args = parse_arguments()
asyncio.run(main(args)) logger.info("Arguments: %s", args)
# Create an event loop
loop = asyncio.get_event_loop()
# Run the start_bot function within the event loop
loop.run_until_complete(start_bot(args))
except Exception as e:
logger.error(e)
logger.warning("Exiting now...")