@@ -345,6 +345,119 @@ export const useAgentTimeoutIdStore = (): {
345345
346346type SessionStub = Pick < UseSessionReturn , 'connectionState' | 'room' | 'internal' > ;
347347
348+ /** Internal hook used by useAgent which generates a function that when called, will return a
349+ * promise which resolves when agent.isAvailable is enabled. */
350+ function useAgentWaitUntilDerivedStates (
351+ emitter : TypedEventEmitter < AgentCallbacks > ,
352+ state : AgentState ,
353+ ) {
354+ const stateRef = React . useRef ( state ) ;
355+ React . useEffect ( ( ) => {
356+ stateRef . current = state ;
357+ } , [ state ] ) ;
358+
359+ const waitUntilConnected = React . useCallback (
360+ async ( signal ?: AbortSignal ) => {
361+ const { isConnected } = generateDerivedStateValues ( stateRef . current ) ;
362+ if ( isConnected ) {
363+ return ;
364+ }
365+
366+ return new Promise < void > ( ( resolve , reject ) => {
367+ const stateChangedHandler = ( state : AgentState ) => {
368+ const { isConnected } = generateDerivedStateValues ( state ) ;
369+ if ( ! isConnected ) {
370+ return ;
371+ }
372+ cleanup ( ) ;
373+ resolve ( ) ;
374+ } ;
375+ const abortHandler = ( ) => {
376+ cleanup ( ) ;
377+ reject ( new Error ( 'useAgent(/* ... */).waitUntilConnected - signal aborted' ) ) ;
378+ } ;
379+
380+ const cleanup = ( ) => {
381+ emitter . off ( AgentEvent . StateChanged , stateChangedHandler ) ;
382+ signal ?. removeEventListener ( 'abort' , abortHandler ) ;
383+ } ;
384+
385+ emitter . on ( AgentEvent . StateChanged , stateChangedHandler ) ;
386+ signal ?. addEventListener ( 'abort' , abortHandler ) ;
387+ } ) ;
388+ } ,
389+ [ emitter ] ,
390+ ) ;
391+
392+ const waitUntilCouldBeListening = React . useCallback (
393+ async ( signal ?: AbortSignal ) => {
394+ const { canListen } = generateDerivedStateValues ( stateRef . current ) ;
395+ if ( canListen ) {
396+ return ;
397+ }
398+
399+ return new Promise < void > ( ( resolve , reject ) => {
400+ const stateChangedHandler = ( state : AgentState ) => {
401+ const { canListen } = generateDerivedStateValues ( state ) ;
402+ if ( ! canListen ) {
403+ return ;
404+ }
405+ cleanup ( ) ;
406+ resolve ( ) ;
407+ } ;
408+ const abortHandler = ( ) => {
409+ cleanup ( ) ;
410+ reject ( new Error ( 'useAgent(/* ... */).waitUntilCouldBeListening - signal aborted' ) ) ;
411+ } ;
412+
413+ const cleanup = ( ) => {
414+ emitter . off ( AgentEvent . StateChanged , stateChangedHandler ) ;
415+ signal ?. removeEventListener ( 'abort' , abortHandler ) ;
416+ } ;
417+
418+ emitter . on ( AgentEvent . StateChanged , stateChangedHandler ) ;
419+ signal ?. addEventListener ( 'abort' , abortHandler ) ;
420+ } ) ;
421+ } ,
422+ [ emitter ] ,
423+ ) ;
424+
425+ const waitUntilFinished = React . useCallback (
426+ async ( signal ?: AbortSignal ) => {
427+ const { isFinished } = generateDerivedStateValues ( stateRef . current ) ;
428+ if ( isFinished ) {
429+ return ;
430+ }
431+
432+ return new Promise < void > ( ( resolve , reject ) => {
433+ const stateChangedHandler = ( state : AgentState ) => {
434+ const { isFinished } = generateDerivedStateValues ( state ) ;
435+ if ( ! isFinished ) {
436+ return ;
437+ }
438+ cleanup ( ) ;
439+ resolve ( ) ;
440+ } ;
441+ const abortHandler = ( ) => {
442+ cleanup ( ) ;
443+ reject ( new Error ( 'useAgent(/* ... */).waitUntilFinished - signal aborted' ) ) ;
444+ } ;
445+
446+ const cleanup = ( ) => {
447+ emitter . off ( AgentEvent . StateChanged , stateChangedHandler ) ;
448+ signal ?. removeEventListener ( 'abort' , abortHandler ) ;
449+ } ;
450+
451+ emitter . on ( AgentEvent . StateChanged , stateChangedHandler ) ;
452+ signal ?. addEventListener ( 'abort' , abortHandler ) ;
453+ } ) ;
454+ } ,
455+ [ emitter ] ,
456+ ) ;
457+
458+ return { waitUntilConnected, waitUntilCouldBeListening, waitUntilFinished } ;
459+ }
460+
348461/**
349462 * useAgent encapculates all agent state, normalizing some quirks around how LiveKit Agents work.
350463 * @public
@@ -675,104 +788,8 @@ export function useAgent(session?: SessionStub): UseAgentReturn {
675788 }
676789 } , [ agentParticipantAttributes , emitter , agentParticipant , state , videoTrack , audioTrack ] ) ;
677790
678- const waitUntilConnected = React . useCallback (
679- async ( signal ?: AbortSignal ) => {
680- const { isConnected } = generateDerivedStateValues ( state ) ;
681- if ( isConnected ) {
682- return ;
683- }
684-
685- return new Promise < void > ( ( resolve , reject ) => {
686- const stateChangedHandler = ( state : AgentState ) => {
687- const { isConnected } = generateDerivedStateValues ( state ) ;
688- if ( ! isConnected ) {
689- return ;
690- }
691- cleanup ( ) ;
692- resolve ( ) ;
693- } ;
694- const abortHandler = ( ) => {
695- cleanup ( ) ;
696- reject ( new Error ( 'useAgent.waitUntilConnected - signal aborted' ) ) ;
697- } ;
698-
699- const cleanup = ( ) => {
700- emitter . off ( AgentEvent . StateChanged , stateChangedHandler ) ;
701- signal ?. removeEventListener ( 'abort' , abortHandler ) ;
702- } ;
703-
704- emitter . on ( AgentEvent . StateChanged , stateChangedHandler ) ;
705- signal ?. addEventListener ( 'abort' , abortHandler ) ;
706- } ) ;
707- } ,
708- [ state , emitter ] ,
709- ) ;
710-
711- const waitUntilCouldBeListening = React . useCallback (
712- async ( signal ?: AbortSignal ) => {
713- const { canListen } = generateDerivedStateValues ( state ) ;
714- if ( canListen ) {
715- return ;
716- }
717-
718- return new Promise < void > ( ( resolve , reject ) => {
719- const stateChangedHandler = ( state : AgentState ) => {
720- const { canListen } = generateDerivedStateValues ( state ) ;
721- if ( ! canListen ) {
722- return ;
723- }
724- cleanup ( ) ;
725- resolve ( ) ;
726- } ;
727- const abortHandler = ( ) => {
728- cleanup ( ) ;
729- reject ( new Error ( 'useAgent.waitUntilCouldBeListening - signal aborted' ) ) ;
730- } ;
731-
732- const cleanup = ( ) => {
733- emitter . off ( AgentEvent . StateChanged , stateChangedHandler ) ;
734- signal ?. removeEventListener ( 'abort' , abortHandler ) ;
735- } ;
736-
737- emitter . on ( AgentEvent . StateChanged , stateChangedHandler ) ;
738- signal ?. addEventListener ( 'abort' , abortHandler ) ;
739- } ) ;
740- } ,
741- [ state , emitter ] ,
742- ) ;
743-
744- const waitUntilFinished = React . useCallback (
745- async ( signal ?: AbortSignal ) => {
746- const { isFinished } = generateDerivedStateValues ( state ) ;
747- if ( isFinished ) {
748- return ;
749- }
750-
751- return new Promise < void > ( ( resolve , reject ) => {
752- const stateChangedHandler = ( state : AgentState ) => {
753- const { isFinished } = generateDerivedStateValues ( state ) ;
754- if ( ! isFinished ) {
755- return ;
756- }
757- cleanup ( ) ;
758- resolve ( ) ;
759- } ;
760- const abortHandler = ( ) => {
761- cleanup ( ) ;
762- reject ( new Error ( 'useAgent.waitUntilFinished - signal aborted' ) ) ;
763- } ;
764-
765- const cleanup = ( ) => {
766- emitter . off ( AgentEvent . StateChanged , stateChangedHandler ) ;
767- signal ?. removeEventListener ( 'abort' , abortHandler ) ;
768- } ;
769-
770- emitter . on ( AgentEvent . StateChanged , stateChangedHandler ) ;
771- signal ?. addEventListener ( 'abort' , abortHandler ) ;
772- } ) ;
773- } ,
774- [ state , emitter ] ,
775- ) ;
791+ const { waitUntilConnected, waitUntilCouldBeListening, waitUntilFinished } =
792+ useAgentWaitUntilDerivedStates ( emitter , state ) ;
776793
777794 const waitUntilCamera = React . useCallback (
778795 ( signal ?: AbortSignal ) => {
@@ -786,7 +803,7 @@ export function useAgent(session?: SessionStub): UseAgentReturn {
786803 } ;
787804 const abortHandler = ( ) => {
788805 cleanup ( ) ;
789- reject ( new Error ( 'useAgent.waitUntilCamera - signal aborted' ) ) ;
806+ reject ( new Error ( 'useAgent(/* ... */) .waitUntilCamera - signal aborted' ) ) ;
790807 } ;
791808
792809 const cleanup = ( ) => {
@@ -813,7 +830,7 @@ export function useAgent(session?: SessionStub): UseAgentReturn {
813830 } ;
814831 const abortHandler = ( ) => {
815832 cleanup ( ) ;
816- reject ( new Error ( 'useAgent.waitUntilMicrophone - signal aborted' ) ) ;
833+ reject ( new Error ( 'useAgent(/* ... */) .waitUntilMicrophone - signal aborted' ) ) ;
817834 } ;
818835
819836 const cleanup = ( ) => {
0 commit comments