WIP: implement-discord-module #4
@@ -64,7 +64,11 @@ class UDPAudioSource(discord.AudioSource):
|
||||
|
||||
def cleanup(self):
|
||||
if self.ffmpeg_process:
|
||||
self.ffmpeg_process.kill()
|
||||
try:
|
||||
self.ffmpeg_process.stdin.close()
|
||||
self.ffmpeg_process.terminate()
|
||||
except:
|
||||
pass
|
||||
|
||||
class DiscordRadioBot(discord.Client):
|
||||
"""
|
||||
@@ -103,17 +107,18 @@ class DiscordRadioBot(discord.Client):
|
||||
Runs in a background thread. Listens for UDP packets from OP25.
|
||||
"""
|
||||
self.udp_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
# Bind to 0.0.0.0 to ensure we catch traffic from any interface (Docker/Localhost)
|
||||
# Bind to all interfaces to ensure we catch the OP25 stream
|
||||
self.udp_sock.bind(('0.0.0.0', self.listen_port))
|
||||
self.udp_sock.settimeout(1.0)
|
||||
|
||||
LOGGER.info(f"UDP Audio Bridge listening on 0.0.0.0:{self.listen_port}")
|
||||
LOGGER.info(f"Forwarding audio to: {self.forward_ports}")
|
||||
|
||||
forward_socks = []
|
||||
# Create sockets for each forward port
|
||||
forward_targets = []
|
||||
for port in self.forward_ports:
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
forward_socks.append((s, port))
|
||||
forward_targets.append((s, port))
|
||||
|
||||
self.running = True
|
||||
while self.running:
|
||||
@@ -121,21 +126,23 @@ class DiscordRadioBot(discord.Client):
|
||||
data, addr = self.udp_sock.recvfrom(4096)
|
||||
self.packets_received += 1
|
||||
|
||||
# 1. Forward to Liquidsoap/Other tools
|
||||
for sock, port in forward_socks:
|
||||
# Send to localhost (where Liquidsoap should be listening)
|
||||
# 1. Forward to Liquidsoap/audio.py
|
||||
for sock, port in forward_targets:
|
||||
try:
|
||||
sock.sendto(data, ('127.0.0.1', port))
|
||||
self.packets_forwarded += 1
|
||||
except Exception as fe:
|
||||
# Log forwarding errors only once per 5 seconds to avoid spam
|
||||
if self.packets_forwarded % 100 == 0:
|
||||
LOGGER.error(f"Forward error to port {port}: {fe}")
|
||||
|
||||
# 2. Add to Discord Buffer
|
||||
self.audio_buffer.extend(data)
|
||||
|
||||
# Periodic Debug Logging (Every 5 seconds, only if active)
|
||||
if time.time() - self.last_log_time > 5:
|
||||
# Periodic Stats Logging
|
||||
if time.time() - self.last_log_time > 10:
|
||||
if self.packets_received > 0:
|
||||
LOGGER.info(f"UDP Stats [5s]: Rx {self.packets_received} pkts | Tx {self.packets_forwarded} pkts | Buffer: {len(self.audio_buffer)} bytes")
|
||||
|
||||
# Reset counters
|
||||
LOGGER.info(f"Discord Audio Bridge Stats: Received {self.packets_received} packets, Forwarded {self.packets_forwarded}")
|
||||
self.packets_received = 0
|
||||
self.packets_forwarded = 0
|
||||
self.last_log_time = time.time()
|
||||
@@ -208,10 +215,8 @@ class DiscordRadioBot(discord.Client):
|
||||
This turns the green ring ON.
|
||||
"""
|
||||
if self.voice_client and not self.voice_client.is_playing():
|
||||
# clear buffer slightly to ensure we aren't playing old data
|
||||
# but keep a little to prevent jitter
|
||||
# self.audio_buffer.clear()
|
||||
|
||||
# Clear old audio so we don't start with a delay
|
||||
self.audio_buffer.clear()
|
||||
source = UDPAudioSource(self.audio_buffer)
|
||||
self.voice_client.play(source)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user