BaseOutputTransport: send silence when EndFrame is received

This commit is contained in:
Aleix Conchillo Flaqué
2025-11-06 11:16:34 -08:00
parent 8c34e1efba
commit 4c8c44ecc3
3 changed files with 20 additions and 0 deletions

View File

@@ -9,6 +9,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Added `TransportParams.audio_out_silence_secs`, which specifies how many
seconds of silence to output when an `EndFrame` reaches the output
transport. This can help ensure that all audio data is fully delivered to
clients.
- Added new `FrameProcessor.broadcast_frame()` method. This will push two
instances of a given frame class, one upstream and the other downstream.

View File

@@ -729,11 +729,24 @@ class BaseOutputTransport(FrameProcessor):
else:
return without_mixer(BOT_VAD_STOP_SECS)
async def _send_silence(self, secs: int):
if secs <= 0:
return
sample_width = 2
silence = b"\x00" * self.sample_rate * sample_width * secs
silence_frame = OutputAudioRawFrame(
audio=silence, sample_rate=self.sample_rate, num_channels=1
)
await self._transport.write_audio_frame(silence_frame)
async def _audio_task_handler(self):
"""Main audio processing task handler."""
async for frame in self._next_frame():
# No need to push EndFrame, it's pushed from process_frame().
if isinstance(frame, EndFrame):
# Send some final silence so words don't cut out.
await self._send_silence(self._params.audio_out_end_silence_secs)
break
# Handle frame.

View File

@@ -83,6 +83,7 @@ class TransportParams(BaseModel):
audio_out_10ms_chunks: Number of 10ms chunks to buffer for output.
audio_out_mixer: Audio mixer instance or destination mapping.
audio_out_destinations: List of audio output destination identifiers.
audio_out_end_silence_secs: How much silence to send after an EndFrame (0 for no silence).
audio_in_enabled: Enable audio input streaming.
audio_in_sample_rate: Input audio sample rate in Hz.
audio_in_channels: Number of input audio channels.
@@ -131,6 +132,7 @@ class TransportParams(BaseModel):
audio_out_10ms_chunks: int = 4
audio_out_mixer: Optional[BaseAudioMixer | Mapping[Optional[str], BaseAudioMixer]] = None
audio_out_destinations: List[str] = Field(default_factory=list)
audio_out_end_silence_secs: int = 2
audio_in_enabled: bool = False
audio_in_sample_rate: Optional[int] = None
audio_in_channels: int = 1