Compare commits

...

4 Commits

Author SHA1 Message Date
Filipi Fuchter
37d15588b8 Starting the base output transport only after starting the small webrtc transport. 2025-05-05 17:12:31 -03:00
Filipi Fuchter
d2bf8321a0 Mentioning the fix in the changelog. 2025-05-05 07:03:08 -03:00
Filipi Fuchter
781df7ac77 Merge branch 'main' into fixing_sound_mixer 2025-05-05 06:58:02 -03:00
Filipi Fuchter
1d69a92ea1 Adding real-time throttling to the audio mixer. 2025-05-05 06:55:34 -03:00
3 changed files with 19 additions and 1 deletions

View File

@@ -5,6 +5,15 @@ All notable changes to **Pipecat** will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Fixed
- Added real-time throttling to the `BaseOutputTransport` when using audio mixer
to ensure audio frames (including silence) are emitted at the correct intervals.
This prevents unnecessary CPU usage and avoids flooding the output with silent
frames when no new audio is available.
## [0.0.66] - 2025-05-02
### Added

View File

@@ -435,6 +435,9 @@ class BaseOutputTransport(FrameProcessor):
async def with_mixer(vad_stop_secs: float) -> AsyncGenerator[Frame, None]:
last_frame_time = 0
silence = b"\x00" * self._audio_chunk_size
# chunk duration in seconds
chunk_duration = (10 * self._params.audio_out_10ms_chunks) / 1000.0
next_frame_time = time.time()
while True:
try:
frame = self._audio_queue.get_nowait()
@@ -454,6 +457,11 @@ class BaseOutputTransport(FrameProcessor):
num_channels=self._params.audio_out_channels,
)
yield frame
# Throttle frame generation to maintain real-time pacing and avoid flooding with silence
wait = next_frame_time - time.time()
if wait > 0:
await asyncio.sleep(wait)
next_frame_time += chunk_duration
if self._mixer:
return with_mixer(BOT_VAD_STOP_SECS)

View File

@@ -484,9 +484,10 @@ class SmallWebRTCOutputTransport(BaseOutputTransport):
self._params = params
async def start(self, frame: StartFrame):
await super().start(frame)
await self._client.setup(self._params, frame)
await self._client.connect()
# Parent start.
await super().start(frame)
async def stop(self, frame: EndFrame):
await super().stop(frame)