@@ -700,7 +700,7 @@ def unpack_audio(self, data):
700
700
701
701
self .decoder .decode (data )
702
702
703
- def start_recording (self , sink , callback , * args ):
703
+ def start_recording (self , sink , callback , * args , sync_start : bool = False ):
704
704
"""The bot will begin recording audio from the current voice channel it is in.
705
705
This function uses a thread so the current code line will not be stopped.
706
706
Must be in a voice channel to use.
@@ -716,6 +716,9 @@ def start_recording(self, sink, callback, *args):
716
716
A function which is called after the bot has stopped recording.
717
717
*args:
718
718
Args which will be passed to the callback function.
719
+ sync_start: :class:`bool`
720
+ If True, the recordings of subsequent users will start with silence.
721
+ This is useful for recording audio just as it was heard.
719
722
720
723
Raises
721
724
------
@@ -738,6 +741,7 @@ def start_recording(self, sink, callback, *args):
738
741
self .decoder = opus .DecodeManager (self )
739
742
self .decoder .start ()
740
743
self .recording = True
744
+ self .sync_start = sync_start
741
745
self .sink = sink
742
746
sink .init (self )
743
747
@@ -796,8 +800,9 @@ def recv_audio(self, sink, callback, *args):
796
800
# it by user, handles pcm files and
797
801
# silence that should be added.
798
802
799
- self .user_timestamps = {}
803
+ self .user_timestamps : dict [ int , tuple [ int , float ]] = {}
800
804
self .starting_time = time .perf_counter ()
805
+ self .first_packet_timestamp : float
801
806
while self .recording :
802
807
ready , _ , err = select .select ([self .socket ], [], [self .socket ], 0.01 )
803
808
if not ready :
@@ -815,27 +820,46 @@ def recv_audio(self, sink, callback, *args):
815
820
816
821
self .stopping_time = time .perf_counter ()
817
822
self .sink .cleanup ()
818
- callback = asyncio .run_coroutine_threadsafe (
819
- callback (self .sink , * args ), self .loop
820
- )
823
+ callback = asyncio .run_coroutine_threadsafe (callback (sink , * args ), self .loop )
821
824
result = callback .result ()
822
825
823
826
if result is not None :
824
827
print (result )
825
828
826
- def recv_decoded_audio (self , data ):
827
- if data .ssrc not in self .user_timestamps :
828
- self .user_timestamps .update ({data .ssrc : data .timestamp })
829
- # Add silence when they were not being recorded.
830
- silence = 0
831
- else :
832
- silence = data .timestamp - self .user_timestamps [data .ssrc ] - 960
833
- self .user_timestamps [data .ssrc ] = data .timestamp
829
+ def recv_decoded_audio (self , data : RawData ):
830
+ # Add silence when they were not being recorded.
831
+ if data .ssrc not in self .user_timestamps : # First packet from user
832
+ if (
833
+ not self .user_timestamps or not self .sync_start
834
+ ): # First packet from anyone
835
+ self .first_packet_timestamp = data .receive_time
836
+ silence = 0
837
+
838
+ else : # Previously received a packet from someone else
839
+ silence = (
840
+ (data .receive_time - self .first_packet_timestamp ) * 48000
841
+ ) - 960
842
+
843
+ else : # Previously received a packet from user
844
+ dRT = (
845
+ data .receive_time - self .user_timestamps [data .ssrc ][1 ]
846
+ ) * 48000 # delta receive time
847
+ dT = data .timestamp - self .user_timestamps [data .ssrc ][0 ] # delta timestamp
848
+ diff = abs (100 - dT * 100 / dRT )
849
+ if (
850
+ diff > 60 and dT != 960
851
+ ): # If the difference in change is more than 60% threshold
852
+ silence = dRT - 960
853
+ else :
854
+ silence = dT - 960
855
+
856
+ self .user_timestamps .update ({data .ssrc : (data .timestamp , data .receive_time )})
834
857
835
858
data .decoded_data = (
836
- struct .pack ("<h" , 0 ) * silence * opus ._OpusStruct .CHANNELS
859
+ struct .pack ("<h" , 0 ) * max ( 0 , int ( silence )) * opus ._OpusStruct .CHANNELS
837
860
+ data .decoded_data
838
861
)
862
+
839
863
while data .ssrc not in self .ws .ssrc_map :
840
864
time .sleep (0.05 )
841
865
self .sink .write (data .decoded_data , self .ws .ssrc_map [data .ssrc ]["user_id" ])
0 commit comments