buffer audio from TTS service before pushing frames

This commit is contained in:
Aleix Conchillo Flaqué
2025-06-08 18:31:54 -07:00
parent abdce063f1
commit 901dd041f0
10 changed files with 33 additions and 17 deletions

View File

@@ -253,7 +253,8 @@ class AWSPollyTTSService(TTSService):
yield TTSStartedFrame()
CHUNK_SIZE = 1024
CHUNK_SIZE = self.chunk_size
for i in range(0, len(audio_data), CHUNK_SIZE):
chunk = audio_data[i : i + CHUNK_SIZE]
if len(chunk) > 0:

View File

@@ -362,8 +362,8 @@ class GoogleHttpTTSService(TTSService):
# Skip the first 44 bytes to remove the WAV header
audio_content = response.audio_content[44:]
# Read and yield audio data in chunks
CHUNK_SIZE = 1024
CHUNK_SIZE = self.chunk_size
for i in range(0, len(audio_content), CHUNK_SIZE):
chunk = audio_content[i : i + CHUNK_SIZE]
if not chunk:
@@ -505,9 +505,10 @@ class GoogleTTSService(TTSService):
yield TTSStartedFrame()
audio_buffer = b""
CHUNK_SIZE = 1024
first_chunk_for_ttfb = False
CHUNK_SIZE = self.chunk_size
async for response in streaming_responses:
chunk = response.audio_content
if not chunk:

View File

@@ -227,7 +227,8 @@ class MiniMaxHttpTTSService(TTSService):
# Process the streaming response
buffer = bytearray()
CHUNK_SIZE = 1024
CHUNK_SIZE = self.chunk_size
async for chunk in response.content.iter_chunked(CHUNK_SIZE):
if not chunk:
@@ -279,10 +280,8 @@ class MiniMaxHttpTTSService(TTSService):
await self.stop_ttfb_metrics()
yield TTSAudioRawFrame(
audio=audio_chunk,
sample_rate=self._settings["audio_setting"][
"sample_rate"
],
num_channels=self._settings["audio_setting"]["channel"],
sample_rate=self.sample_rate,
num_channels=1,
)
except ValueError as e:
logger.error(f"Error converting hex to binary: {e}")

View File

@@ -125,7 +125,7 @@ class OpenAITTSService(TTSService):
await self.start_tts_usage_metrics(text)
CHUNK_SIZE = 1024
CHUNK_SIZE = self.chunk_size
yield TTSStartedFrame()
async for chunk in r.iter_bytes(CHUNK_SIZE):

View File

@@ -85,8 +85,7 @@ class PiperTTSService(TTSService):
await self.start_tts_usage_metrics(text)
# Process the streaming response
CHUNK_SIZE = 1024
CHUNK_SIZE = self.chunk_size
yield TTSStartedFrame()
async for chunk in response.content.iter_chunked(CHUNK_SIZE):

View File

@@ -430,8 +430,7 @@ class RimeHttpTTSService(TTSService):
yield TTSStartedFrame()
# Process the streaming response
CHUNK_SIZE = 1024
CHUNK_SIZE = self.chunk_size
async for chunk in response.content.iter_chunked(CHUNK_SIZE):
if need_to_strip_wav_header and chunk.startswith(b"RIFF"):

View File

@@ -106,6 +106,19 @@ class TTSService(AIService):
def sample_rate(self) -> int:
return self._sample_rate
@property
def chunk_size(self) -> int:
"""This property indicates how much audio we download (from TTS services
that require chunking) before we start pushing the first audio
frame. This will make sure we download the rest of the audio while audio
is being played without causing audio glitches (specially at the
beginning). Of course, this will also depend on how fast the TTS service
generates bytes.
"""
CHUNK_SECONDS = 0.5
return int(self.sample_rate * CHUNK_SECONDS * 2) # 2 bytes/sample
async def set_model(self, model: str):
self.set_model_name(model)

View File

@@ -152,7 +152,7 @@ class XTTSService(TTSService):
yield TTSStartedFrame()
CHUNK_SIZE = 1024
CHUNK_SIZE = self.chunk_size
buffer = bytearray()
async for chunk in r.content.iter_chunked(CHUNK_SIZE):