diff --git a/src/hooks/useWebAvatar.tsx b/src/hooks/useWebAvatar.tsx index 04f1833..13775a7 100644 --- a/src/hooks/useWebAvatar.tsx +++ b/src/hooks/useWebAvatar.tsx @@ -1,4 +1,4 @@ -import { RoomEvent, Track } from 'livekit-client'; +import { ConnectionState, RoomEvent, Track } from 'livekit-client'; import { useEffect, useRef, useState } from 'react'; import type { RemoteTrack } from 'livekit-client'; @@ -17,12 +17,16 @@ export function useWebAvatar() { } function handleTrackSubscribed(track: RemoteTrack) { - if (track.kind === Track.Kind.Video) { + if ( + track.kind === Track.Kind.Video && + !track.attachedElements.includes(videoRef.current!) + ) { track.attach(videoRef.current!); } else if ( audioRef && track.kind === Track.Kind.Audio && - room?.canPlaybackAudio + room?.canPlaybackAudio && + !track.attachedElements.includes(audioRef.current!) ) { track.attach(audioRef.current!); } @@ -39,14 +43,29 @@ export function useWebAvatar() { room .on(RoomEvent.TrackSubscribed, handleTrackSubscribed) .on(RoomEvent.TrackUnsubscribed, handleTrackUnsubscribed) - .on(RoomEvent.AudioPlaybackStatusChanged, handleAudioPlaybackStatusChanged) + .on( + RoomEvent.AudioPlaybackStatusChanged, + handleAudioPlaybackStatusChanged, + ); + + if (room.state === ConnectionState.Connected) { + // support for instances created AFTER "connect" by making sure the new video and audio elements are attached + room.remoteParticipants.forEach((participant) => { + participant.trackPublications.forEach(({ track }) => { + handleTrackSubscribed(track!); + }); + }); + } return () => { room .off(RoomEvent.TrackSubscribed, handleTrackSubscribed) .off(RoomEvent.TrackUnsubscribed, handleTrackUnsubscribed) - .off(RoomEvent.AudioPlaybackStatusChanged, handleAudioPlaybackStatusChanged); - } + .off( + RoomEvent.AudioPlaybackStatusChanged, + handleAudioPlaybackStatusChanged, + ); + }; }, [room]); return { ...avatar, videoRef, audioRef, canPlaybackAudio };