Module agents.avatar.avatar_synchronizer
Classes
class AvatarSynchronizer (audio_track: CustomAudioTrack, video_track: CustomVideoTrack, video_fps: float)-
Expand source code
class AvatarSynchronizer: """ Paces audio and video frames into their respective custom tracks so that audio and video stay in sync at the configured FPS. """ def __init__( self, audio_track: CustomAudioTrack, video_track: CustomVideoTrack, video_fps: float, ): self._audio_track = audio_track self._video_track = video_track self._video_fps = video_fps self._frame_interval = 1.0 / video_fps self._last_frame_time = 0.0 self._start_time = 0.0 async def push(self, frame: Union[AudioFrame, VideoFrame, AudioSegmentEnd]) -> None: if not self._start_time: self._start_time = time.monotonic() if isinstance(frame, AudioFrame): await self._audio_track.put_frame(frame) elif isinstance(frame, VideoFrame): now = time.monotonic() elapsed = now - self._last_frame_time if elapsed < self._frame_interval: await asyncio.sleep(self._frame_interval - elapsed) await self._video_track.put_frame(frame) self._last_frame_time = time.monotonic() async def aclose(self) -> None: passPaces audio and video frames into their respective custom tracks so that audio and video stay in sync at the configured FPS.
Methods
async def aclose(self) ‑> None-
Expand source code
async def aclose(self) -> None: pass async def push(self, frame: Union[AudioFrame, VideoFrame, AudioSegmentEnd]) ‑> None-
Expand source code
async def push(self, frame: Union[AudioFrame, VideoFrame, AudioSegmentEnd]) -> None: if not self._start_time: self._start_time = time.monotonic() if isinstance(frame, AudioFrame): await self._audio_track.put_frame(frame) elif isinstance(frame, VideoFrame): now = time.monotonic() elapsed = now - self._last_frame_time if elapsed < self._frame_interval: await asyncio.sleep(self._frame_interval - elapsed) await self._video_track.put_frame(frame) self._last_frame_time = time.monotonic()