diff --git a/src/components/VideoProvider/useLocalTracks/useLocalTracks.test.tsx b/src/components/VideoProvider/useLocalTracks/useLocalTracks.test.tsx index ae1fd8267..9555f9eee 100644 --- a/src/components/VideoProvider/useLocalTracks/useLocalTracks.test.tsx +++ b/src/components/VideoProvider/useLocalTracks/useLocalTracks.test.tsx @@ -123,6 +123,42 @@ describe('the useLocalTracks hook', () => { }); }); + it('should set isAcquiringLocalTracks to true while acquiring tracks', async () => { + const { result, waitForNextUpdate } = renderHook(useLocalTracks); + + expect(result.current.isAcquiringLocalTracks).toBe(false); + + act(() => { + result.current.getAudioAndVideoTracks(); + }); + + expect(result.current.isAcquiringLocalTracks).toBe(true); + + await act(async () => { + await waitForNextUpdate(); + }); + + expect(result.current.isAcquiringLocalTracks).toBe(false); + }); + + it('should ignore calls to getAudioAndVideoTracks while isAcquiringLocalTracks is true', async () => { + const { result, waitForNextUpdate } = renderHook(useLocalTracks); + + act(() => { + expect(result.current.isAcquiringLocalTracks).toBe(false); + result.current.getAudioAndVideoTracks(); // This call is not ignored + }); + + expect(result.current.isAcquiringLocalTracks).toBe(true); + result.current.getAudioAndVideoTracks(); // This call is ignored + + await act(async () => { + await waitForNextUpdate(); + }); + + expect(Video.createLocalTracks).toHaveBeenCalledTimes(1); + }); + it('should not create any tracks when no input devices are present', async () => { mockUseAudioInputDevices.mockImplementation(() => []); mockUseVideoInputDevices.mockImplementation(() => []); diff --git a/src/components/VideoProvider/useLocalTracks/useLocalTracks.ts b/src/components/VideoProvider/useLocalTracks/useLocalTracks.ts index b93052f5e..fc70580bd 100644 --- a/src/components/VideoProvider/useLocalTracks/useLocalTracks.ts +++ b/src/components/VideoProvider/useLocalTracks/useLocalTracks.ts @@ -49,7 +49,7 @@ export default function useLocalTracks() { const getAudioAndVideoTracks = useCallback(() => { if (!hasAudio && !hasVideo) return Promise.resolve(); - if (audioTrack || videoTrack) return Promise.resolve(); + if (isAcquiringLocalTracks || audioTrack || videoTrack) return Promise.resolve(); setIsAcquiringLocalTracks(true); @@ -84,7 +84,7 @@ export default function useLocalTracks() { } }) .finally(() => setIsAcquiringLocalTracks(false)); - }, [hasAudio, hasVideo, audioTrack, videoTrack, localAudioDevices, localVideoDevices]); + }, [hasAudio, hasVideo, audioTrack, videoTrack, localAudioDevices, localVideoDevices, isAcquiringLocalTracks]); const localTracks = [audioTrack, videoTrack].filter(track => track !== undefined) as ( | LocalAudioTrack