Skip to content
This repository has been archived by the owner on Mar 13, 2023. It is now read-only.

feat: Allow audio pre-buffering #570

Merged
merged 3 commits into from
Jul 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 25 additions & 3 deletions naff/api/voice/audio.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ def audio_complete(self) -> bool:
return False
return True

def _create_process(self) -> None:
def _create_process(self, *, block: bool = True) -> None:
before = (
self.ffmpeg_before_args if isinstance(self.ffmpeg_before_args, list) else self.ffmpeg_before_args.split()
)
Expand Down Expand Up @@ -162,8 +162,9 @@ def _create_process(self) -> None:
)
self.read_ahead_task.start()

# block until some data is in the buffer
self.buffer.initialised.wait()
if block:
# block until some data is in the buffer
self.buffer.initialised.wait()

def _read_ahead(self) -> None:
while self.process:
Expand All @@ -181,6 +182,24 @@ def _read_ahead(self) -> None:
self.buffer.initialised.set()
time.sleep(0.1)

def pre_buffer(self, duration: None | float = None) -> None:
"""
Start pre-buffering the audio.

Args:
duration: The duration of audio to pre-buffer.
"""
if duration:
self.buffer_seconds = duration

if self.process and self.process.poll() is None:
raise RuntimeError("Cannot pre-buffer an already running process")
# sanity value enforcement to prevent audio weirdness
self.buffer = AudioBuffer()
self.buffer.initialised.clear()

self._create_process(block=False)

def read(self, frame_size: int) -> bytes:
"""
Reads frame_size bytes of audio from the buffer.
Expand All @@ -190,6 +209,9 @@ def read(self, frame_size: int) -> bytes:
"""
if not self.process:
self._create_process()
if not self.buffer.initialised.is_set():
# we cannot start playing until the buffer is initialised
self.buffer.initialised.wait()

data = self.buffer.read(frame_size)

Expand Down
5 changes: 1 addition & 4 deletions naff/api/voice/player.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,7 @@ def play(self) -> None:
"""Start playing."""
self._stop_event.clear()
self._resume.set()
try:
self.start()
finally:
self.current_audio.cleanup()
self.start()

def run(self) -> None:
"""The main player loop to send audio to the voice websocket."""
Expand Down