From 7a78b786a42d4e546b8f42a743abe69d881198be Mon Sep 17 00:00:00 2001 From: Ronald Claveau Date: Sun, 8 Jun 2025 19:06:15 +0200 Subject: [PATCH 1/2] fix: manage silence for new SSRC with existing user_id --- discord/voice_client.py | 55 +++++++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/discord/voice_client.py b/discord/voice_client.py index 75902ecbe2..08c3ea17aa 100644 --- a/discord/voice_client.py +++ b/discord/voice_client.py @@ -265,6 +265,7 @@ def __init__(self, client: Client, channel: abc.Connectable): self.sink = None self.starting_time = None self.stopping_time = None + self.temp_queued_data: dict[int, list] = {} warn_nacl = not has_nacl supported_modes: tuple[SupportedModes, ...] = ( @@ -845,7 +846,7 @@ def recv_audio(self, sink, callback, *args): # it by user, handles pcm files and # silence that should be added. - self.user_timestamps: dict[int, tuple[int, float]] = {} + self.user_timestamps: dict[int, tuple[int, int, float]] = {} self.starting_time = time.perf_counter() self.first_packet_timestamp: float while self.recording: @@ -873,7 +874,25 @@ def recv_audio(self, sink, callback, *args): def recv_decoded_audio(self, data: RawData): # Add silence when they were not being recorded. - if data.ssrc not in self.user_timestamps: # First packet from user + data.user_id = self.ws.ssrc_map.get(data.ssrc, {}).get("user_id") + + if data.user_id is None: + _log.debug(f"DEBUG: received packet with SSRC {data.ssrc} not linked to a user_id." + f"Queueing for later processing.") + self.temp_queued_data.setdefault(data.ssrc, []).append(data) + return + elif data.ssrc in self.temp_queued_data: + _log.debug('DEBUG: We got %d packet(s) in queue for SSRC %d', + len(self.temp_queued_data[data.ssrc]), data.ssrc) + queued_packets = self.temp_queued_data.pop(data.ssrc) + for q_packet in queued_packets: + q_packet.user_id = data.user_id + self._process_audio_packet(q_packet) + + self._process_audio_packet(data) + + def _process_audio_packet(self, data: RawData): + if data.user_id not in self.user_timestamps: # First packet from user if ( not self.user_timestamps or not self.sync_start ): # First packet from anyone @@ -886,19 +905,29 @@ def recv_decoded_audio(self, data: RawData): ) - 960 else: # Previously received a packet from user - dRT = ( - data.receive_time - self.user_timestamps[data.ssrc][1] - ) * 48000 # delta receive time - dT = data.timestamp - self.user_timestamps[data.ssrc][0] # delta timestamp - diff = abs(100 - dT * 100 / dRT) - if ( - diff > 60 and dT != 960 - ): # If the difference in change is more than 60% threshold - silence = dRT - 960 + prev_ssrc = self.user_timestamps[data.user_id][0] + prev_timestamp = self.user_timestamps[data.user_id][1] + prev_receive_time = self.user_timestamps[data.user_id][2] + + if data.ssrc != prev_ssrc: + _log.info(f"Received audio data from USER_ID {data.user_id} with a previous SSRC {prev_ssrc} and new " + f"SSRC {data.ssrc}.") + dRT = (data.receive_time - prev_receive_time) * 1000 + silence = max(0, int(dRT / (1000 / 48000))) - 960 else: - silence = dT - 960 + dRT = ( + data.receive_time - prev_receive_time + ) * 48000 # delta receive time + dT = data.timestamp - prev_timestamp # delta timestamp + diff = abs(100 - dT * 100 / dRT) + if ( + diff > 60 and dT != 960 + ): # If the difference in change is more than 60% threshold + silence = dRT - 960 + else: + silence = dT - 960 - self.user_timestamps.update({data.ssrc: (data.timestamp, data.receive_time)}) + self.user_timestamps.update({data.user_id: (data.ssrc, data.timestamp, data.receive_time)}) data.decoded_data = ( struct.pack(" Date: Sun, 8 Jun 2025 17:30:53 +0000 Subject: [PATCH 2/2] style(pre-commit): auto fixes from pre-commit.com hooks --- discord/voice_client.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/discord/voice_client.py b/discord/voice_client.py index 08c3ea17aa..7bbd65dbdb 100644 --- a/discord/voice_client.py +++ b/discord/voice_client.py @@ -877,13 +877,18 @@ def recv_decoded_audio(self, data: RawData): data.user_id = self.ws.ssrc_map.get(data.ssrc, {}).get("user_id") if data.user_id is None: - _log.debug(f"DEBUG: received packet with SSRC {data.ssrc} not linked to a user_id." - f"Queueing for later processing.") + _log.debug( + f"DEBUG: received packet with SSRC {data.ssrc} not linked to a user_id." + f"Queueing for later processing." + ) self.temp_queued_data.setdefault(data.ssrc, []).append(data) return elif data.ssrc in self.temp_queued_data: - _log.debug('DEBUG: We got %d packet(s) in queue for SSRC %d', - len(self.temp_queued_data[data.ssrc]), data.ssrc) + _log.debug( + "DEBUG: We got %d packet(s) in queue for SSRC %d", + len(self.temp_queued_data[data.ssrc]), + data.ssrc, + ) queued_packets = self.temp_queued_data.pop(data.ssrc) for q_packet in queued_packets: q_packet.user_id = data.user_id @@ -910,8 +915,10 @@ def _process_audio_packet(self, data: RawData): prev_receive_time = self.user_timestamps[data.user_id][2] if data.ssrc != prev_ssrc: - _log.info(f"Received audio data from USER_ID {data.user_id} with a previous SSRC {prev_ssrc} and new " - f"SSRC {data.ssrc}.") + _log.info( + f"Received audio data from USER_ID {data.user_id} with a previous SSRC {prev_ssrc} and new " + f"SSRC {data.ssrc}." + ) dRT = (data.receive_time - prev_receive_time) * 1000 silence = max(0, int(dRT / (1000 / 48000))) - 960 else: @@ -927,7 +934,9 @@ def _process_audio_packet(self, data: RawData): else: silence = dT - 960 - self.user_timestamps.update({data.user_id: (data.ssrc, data.timestamp, data.receive_time)}) + self.user_timestamps.update( + {data.user_id: (data.ssrc, data.timestamp, data.receive_time)} + ) data.decoded_data = ( struct.pack("