BaseOutputTransport: send silence when EndFrame is received
This commit is contained in:
@@ -9,6 +9,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
### Added
|
### 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
|
- Added new `FrameProcessor.broadcast_frame()` method. This will push two
|
||||||
instances of a given frame class, one upstream and the other downstream.
|
instances of a given frame class, one upstream and the other downstream.
|
||||||
|
|
||||||
|
|||||||
@@ -729,11 +729,24 @@ class BaseOutputTransport(FrameProcessor):
|
|||||||
else:
|
else:
|
||||||
return without_mixer(BOT_VAD_STOP_SECS)
|
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):
|
async def _audio_task_handler(self):
|
||||||
"""Main audio processing task handler."""
|
"""Main audio processing task handler."""
|
||||||
async for frame in self._next_frame():
|
async for frame in self._next_frame():
|
||||||
# No need to push EndFrame, it's pushed from process_frame().
|
# No need to push EndFrame, it's pushed from process_frame().
|
||||||
if isinstance(frame, EndFrame):
|
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
|
break
|
||||||
|
|
||||||
# Handle frame.
|
# Handle frame.
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ class TransportParams(BaseModel):
|
|||||||
audio_out_10ms_chunks: Number of 10ms chunks to buffer for output.
|
audio_out_10ms_chunks: Number of 10ms chunks to buffer for output.
|
||||||
audio_out_mixer: Audio mixer instance or destination mapping.
|
audio_out_mixer: Audio mixer instance or destination mapping.
|
||||||
audio_out_destinations: List of audio output destination identifiers.
|
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_enabled: Enable audio input streaming.
|
||||||
audio_in_sample_rate: Input audio sample rate in Hz.
|
audio_in_sample_rate: Input audio sample rate in Hz.
|
||||||
audio_in_channels: Number of input audio channels.
|
audio_in_channels: Number of input audio channels.
|
||||||
@@ -131,6 +132,7 @@ class TransportParams(BaseModel):
|
|||||||
audio_out_10ms_chunks: int = 4
|
audio_out_10ms_chunks: int = 4
|
||||||
audio_out_mixer: Optional[BaseAudioMixer | Mapping[Optional[str], BaseAudioMixer]] = None
|
audio_out_mixer: Optional[BaseAudioMixer | Mapping[Optional[str], BaseAudioMixer]] = None
|
||||||
audio_out_destinations: List[str] = Field(default_factory=list)
|
audio_out_destinations: List[str] = Field(default_factory=list)
|
||||||
|
audio_out_end_silence_secs: int = 2
|
||||||
audio_in_enabled: bool = False
|
audio_in_enabled: bool = False
|
||||||
audio_in_sample_rate: Optional[int] = None
|
audio_in_sample_rate: Optional[int] = None
|
||||||
audio_in_channels: int = 1
|
audio_in_channels: int = 1
|
||||||
|
|||||||
Reference in New Issue
Block a user