transport(websockets): fix initial busy loop when using audio mixers

This commit is contained in:
Aleix Conchillo Flaqué
2024-12-04 15:15:43 -08:00
parent e0f7a8a9f4
commit 0935d773f5
3 changed files with 32 additions and 14 deletions

View File

@@ -61,6 +61,9 @@ async def on_audio_data(processor, audio, sample_rate, num_channels):
### Fixed ### Fixed
- Fixed an issue in `WebsocketServerTransport` and `FastAPIWebsocketTransport`
that would cause a busy loop when using audio mixer.
- Fixed a `DailyTransport` and `LiveKitTransport` issue where connections were - Fixed a `DailyTransport` and `LiveKitTransport` issue where connections were
being closed in the input transport prematurely. This was causing frames being closed in the input transport prematurely. This was causing frames
queued inside the pipeline being discarded. queued inside the pipeline being discarded.

View File

@@ -105,6 +105,11 @@ class FastAPIWebsocketOutputTransport(BaseOutputTransport):
self._next_send_time = 0 self._next_send_time = 0
async def write_raw_audio_frames(self, frames: bytes): async def write_raw_audio_frames(self, frames: bytes):
if self._websocket.client_state != WebSocketState.CONNECTED:
# Simulate audio playback with a sleep.
await self._write_audio_sleep()
return
frame = AudioRawFrame( frame = AudioRawFrame(
audio=frames, audio=frames,
sample_rate=self._params.audio_out_sample_rate, sample_rate=self._params.audio_out_sample_rate,
@@ -125,10 +130,21 @@ class FastAPIWebsocketOutputTransport(BaseOutputTransport):
) )
frame = wav_frame frame = wav_frame
payload = self._params.serializer.serialize(frame)
if payload:
await self._websocket.send_text(payload)
self._websocket_audio_buffer = bytes()
# Simulate audio playback with a sleep.
await self._write_audio_sleep()
async def _write_frame(self, frame: Frame):
payload = self._params.serializer.serialize(frame) payload = self._params.serializer.serialize(frame)
if payload and self._websocket.client_state == WebSocketState.CONNECTED: if payload and self._websocket.client_state == WebSocketState.CONNECTED:
await self._websocket.send_text(payload) await self._websocket.send_text(payload)
async def _write_audio_sleep(self):
# Simulate a clock. # Simulate a clock.
current_time = time.monotonic() current_time = time.monotonic()
sleep_duration = max(0, self._next_send_time - current_time) sleep_duration = max(0, self._next_send_time - current_time)
@@ -138,13 +154,6 @@ class FastAPIWebsocketOutputTransport(BaseOutputTransport):
else: else:
self._next_send_time += self._send_interval self._next_send_time += self._send_interval
self._websocket_audio_buffer = bytes()
async def _write_frame(self, frame: Frame):
payload = self._params.serializer.serialize(frame)
if payload and self._websocket.client_state == WebSocketState.CONNECTED:
await self._websocket.send_text(payload)
class FastAPIWebsocketTransport(BaseTransport): class FastAPIWebsocketTransport(BaseTransport):
def __init__( def __init__(

View File

@@ -153,6 +153,8 @@ class WebsocketServerOutputTransport(BaseOutputTransport):
async def write_raw_audio_frames(self, frames: bytes): async def write_raw_audio_frames(self, frames: bytes):
if not self._websocket: if not self._websocket:
# Simulate audio playback with a sleep.
await self._write_audio_sleep()
return return
frame = AudioRawFrame( frame = AudioRawFrame(
@@ -179,6 +181,17 @@ class WebsocketServerOutputTransport(BaseOutputTransport):
if proto: if proto:
await self._websocket.send(proto) await self._websocket.send(proto)
self._websocket_audio_buffer = bytes()
# Simulate audio playback with a sleep.
await self._write_audio_sleep()
async def _write_frame(self, frame: Frame):
payload = self._params.serializer.serialize(frame)
if payload and self._websocket:
await self._websocket.send(payload)
async def _write_audio_sleep(self):
# Simulate a clock. # Simulate a clock.
current_time = time.monotonic() current_time = time.monotonic()
sleep_duration = max(0, self._next_send_time - current_time) sleep_duration = max(0, self._next_send_time - current_time)
@@ -188,13 +201,6 @@ class WebsocketServerOutputTransport(BaseOutputTransport):
else: else:
self._next_send_time += self._send_interval self._next_send_time += self._send_interval
self._websocket_audio_buffer = bytes()
async def _write_frame(self, frame: Frame):
payload = self._params.serializer.serialize(frame)
if payload and self._websocket:
await self._websocket.send(payload)
class WebsocketServerTransport(BaseTransport): class WebsocketServerTransport(BaseTransport):
def __init__( def __init__(