11import audioop
2+ import shutil
23import subprocess # noqa: S404
34import threading
45import time
1314 "AudioVolume" ,
1415)
1516
17+ from interactions .client .const import get_logger
18+ from interactions .api .voice .opus import Encoder
19+ from interactions .client .utils import FastJson
20+
1621
1722class AudioBuffer :
1823 def __init__ (self ) -> None :
@@ -62,6 +67,8 @@ class BaseAudio(ABC):
6267 """Does this audio data need encoding with opus?"""
6368 bitrate : Optional [int ]
6469 """Optionally specify a specific bitrate to encode this audio data with"""
70+ encoder : Optional [Encoder ]
71+ """The encoder to use for this audio data"""
6572
6673 def __del__ (self ) -> None :
6774 self .cleanup ()
@@ -135,10 +142,40 @@ def audio_complete(self) -> bool:
135142 return False
136143 return True
137144
138- def _create_process (self , * , block : bool = True ) -> None :
145+ def _create_process (self , * , block : bool = True , probe : bool = True ) -> None :
139146 before = (
140147 self .ffmpeg_before_args if isinstance (self .ffmpeg_before_args , list ) else self .ffmpeg_before_args .split ()
141148 )
149+
150+ config = {
151+ "sample_rate" : 48000 ,
152+ "bitrate" : None ,
153+ }
154+
155+ if shutil .which ("ffprobe" ) is not None and probe :
156+ ffprobe_cmd = [
157+ "ffprobe" ,
158+ "-loglevel" ,
159+ "quiet" ,
160+ "-print_format" ,
161+ "json" ,
162+ "-show_streams" ,
163+ "-select_streams" ,
164+ "a:0" ,
165+ self .source ,
166+ ]
167+ raw_output = subprocess .check_output (ffprobe_cmd , stderr = subprocess .DEVNULL )
168+ output = FastJson .loads (raw_output )
169+
170+ config ["sample_rate" ] = int (output ["streams" ][0 ]["sample_rate" ])
171+ config ["bitrate" ] = int (output ["streams" ][0 ]["bit_rate" ])
172+
173+ get_logger ().debug (f"Detected audio data for { self .source } - { config } " )
174+
175+ if getattr (self , "bitrate" , None ) is None and self .encoder :
176+ self .bitrate = int (config ["bitrate" ] / 1024 )
177+ self .encoder .set_bitrate (self .bitrate )
178+
142179 after = self .ffmpeg_args if isinstance (self .ffmpeg_args , list ) else self .ffmpeg_args .split ()
143180 cmd = [
144181 "ffmpeg" ,
@@ -147,7 +184,7 @@ def _create_process(self, *, block: bool = True) -> None:
147184 "-f" ,
148185 "s16le" ,
149186 "-ar" ,
150- "48000" ,
187+ str ( config [ "sample_rate" ]) ,
151188 "-ac" ,
152189 "2" ,
153190 "-loglevel" ,
0 commit comments