Allow defining whether to insert silence in the output transport.
This commit is contained in:
@@ -84,6 +84,8 @@ class TransportParams(BaseModel):
|
|||||||
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_out_end_silence_secs: How much silence to send after an EndFrame (0 for no silence).
|
||||||
|
audio_out_insert_silence: Insert silence frames when the audio output queue is empty.
|
||||||
|
When False, the transport will wait for audio data instead of inserting 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.
|
||||||
@@ -144,6 +146,7 @@ class TransportParams(BaseModel):
|
|||||||
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_out_end_silence_secs: int = 2
|
||||||
|
audio_out_insert_silence: bool = True
|
||||||
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
|
||||||
|
|||||||
@@ -79,14 +79,17 @@ class RawAudioTrack(AudioStreamTrack):
|
|||||||
supporting queued audio data with proper synchronization.
|
supporting queued audio data with proper synchronization.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, sample_rate):
|
def __init__(self, sample_rate: int, insert_silence: bool = True):
|
||||||
"""Initialize the raw audio track.
|
"""Initialize the raw audio track.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
sample_rate: The audio sample rate in Hz.
|
sample_rate: The audio sample rate in Hz.
|
||||||
|
insert_silence: If True, emit silence when the queue is empty. If False,
|
||||||
|
wait until audio data is available.
|
||||||
"""
|
"""
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self._sample_rate = sample_rate
|
self._sample_rate = sample_rate
|
||||||
|
self._insert_silence = insert_silence
|
||||||
self._samples_per_10ms = sample_rate * 10 // 1000
|
self._samples_per_10ms = sample_rate * 10 // 1000
|
||||||
self._bytes_per_10ms = self._samples_per_10ms * 2 # 16-bit (2 bytes per sample)
|
self._bytes_per_10ms = self._samples_per_10ms * 2 # 16-bit (2 bytes per sample)
|
||||||
self._timestamp = 0
|
self._timestamp = 0
|
||||||
@@ -131,12 +134,19 @@ class RawAudioTrack(AudioStreamTrack):
|
|||||||
if wait > 0:
|
if wait > 0:
|
||||||
await asyncio.sleep(wait)
|
await asyncio.sleep(wait)
|
||||||
|
|
||||||
if self._chunk_queue:
|
if not self._chunk_queue:
|
||||||
|
if self._insert_silence:
|
||||||
|
chunk = bytes(self._bytes_per_10ms)
|
||||||
|
else:
|
||||||
|
while not self._chunk_queue:
|
||||||
|
await asyncio.sleep(0.005)
|
||||||
chunk, future = self._chunk_queue.popleft()
|
chunk, future = self._chunk_queue.popleft()
|
||||||
if future and not future.done():
|
if future and not future.done():
|
||||||
future.set_result(True)
|
future.set_result(True)
|
||||||
else:
|
else:
|
||||||
chunk = bytes(self._bytes_per_10ms) # silence
|
chunk, future = self._chunk_queue.popleft()
|
||||||
|
if future and not future.done():
|
||||||
|
future.set_result(True)
|
||||||
|
|
||||||
# Convert the byte data to an ndarray of int16 samples
|
# Convert the byte data to an ndarray of int16 samples
|
||||||
samples = np.frombuffer(chunk, dtype=np.int16)
|
samples = np.frombuffer(chunk, dtype=np.int16)
|
||||||
@@ -484,7 +494,10 @@ class SmallWebRTCClient:
|
|||||||
self._video_input_track = self._webrtc_connection.video_input_track()
|
self._video_input_track = self._webrtc_connection.video_input_track()
|
||||||
self._screen_video_track = self._webrtc_connection.screen_video_input_track()
|
self._screen_video_track = self._webrtc_connection.screen_video_input_track()
|
||||||
if self._params.audio_out_enabled:
|
if self._params.audio_out_enabled:
|
||||||
self._audio_output_track = RawAudioTrack(sample_rate=self._out_sample_rate)
|
self._audio_output_track = RawAudioTrack(
|
||||||
|
sample_rate=self._out_sample_rate,
|
||||||
|
insert_silence=self._params.audio_out_insert_silence,
|
||||||
|
)
|
||||||
self._webrtc_connection.replace_audio_track(self._audio_output_track)
|
self._webrtc_connection.replace_audio_track(self._audio_output_track)
|
||||||
|
|
||||||
if self._params.video_out_enabled:
|
if self._params.video_out_enabled:
|
||||||
|
|||||||
Reference in New Issue
Block a user