Skip to content

Commit 77fe4d2

Browse files
committed
feat: support ffprobe in audio
1 parent 04038ec commit 77fe4d2

File tree

2 files changed

+40
-2
lines changed

2 files changed

+40
-2
lines changed

interactions/api/voice/audio.py

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import audioop
2+
import shutil
23
import subprocess # noqa: S404
34
import threading
45
import time
@@ -13,6 +14,10 @@
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

1722
class 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",

interactions/api/voice/player.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ def run(self) -> None:
9494
# noinspection PyProtectedMember
9595
self.current_audio.volume = self.state._volume
9696

97+
self.current_audio.encoder = self._encoder
9798
self._encoder.set_bitrate(getattr(self.current_audio, "bitrate", self.state.channel.bitrate))
9899

99100
self._stopped.clear()

0 commit comments

Comments
 (0)