@@ -11,12 +11,13 @@ import {
1111 RoomOptions ,
1212} from 'livekit-client' ;
1313import { EventEmitter } from 'events' ;
14- import { useCallback , useEffect , useMemo , useRef , useState } from 'react' ;
14+ import { useCallback , useEffect , useMemo , useState } from 'react' ;
1515
16+ import { TokenSourceConfigurable , TokenSourceFixed , TokenSourceOptions } from '../TokenSource' ;
17+ import { useMaybeRoomContext } from '../context' ;
1618import { useAgent } from './useAgent' ;
17- import { log , TrackReference } from '@livekit/components-core' ;
19+ import { TrackReference } from '@livekit/components-core' ;
1820import { useLocalParticipant } from './useLocalParticipant' ;
19- import { roomOptionsStringifyReplacer } from '../utils' ;
2021
2122/** @public */
2223export enum SessionEvent {
@@ -124,96 +125,17 @@ export type UseSessionReturn = (
124125 SessionActions ;
125126
126127type UseSessionCommonOptions = {
128+ room ?: Room ;
129+
127130 /**
128131 * Amount of time in milliseonds the system will wait for an agent to join the room, before
129132 * transitioning to the "failure" state.
130133 */
131134 agentConnectTimeoutMilliseconds ?: number ;
132135} ;
133136
134- type UseSessionFixedOptions = UseSessionCommonOptions ; // & RoomOptionsTokenSourceFixed FIXME: add this!
135- type UseSessionConfigurableOptions = UseSessionCommonOptions & TokenSourceFetchOptions ; // & RoomOptionsTokenSourceConfigurable FIXME: replace this!
136-
137- /** Given two TokenSourceFetchOptions values, check to see if they are deep equal. */
138- function areTokenSourceFetchOptionsEqual (
139- a : TokenSourceFetchOptions ,
140- b : TokenSourceFetchOptions ,
141- ) {
142- for ( const key of Object . keys ( a ) as Array < keyof TokenSourceFetchOptions > ) {
143- switch ( key ) {
144- case 'roomName' :
145- case 'participantName' :
146- case 'participantIdentity' :
147- case 'participantMetadata' :
148- case 'participantAttributes' :
149- case 'agentName' :
150- case 'agentMetadata' :
151- if ( a [ key ] !== b [ key ] ) {
152- return false ;
153- }
154- break ;
155- default :
156- // ref: https://stackoverflow.com/a/58009992
157- const exhaustiveCheckedKey : never = key ;
158- throw new Error ( `Options key ${ exhaustiveCheckedKey } not being checked for equality!` ) ;
159- }
160- }
161-
162- return true ;
163- }
164-
165- function extractTokenSourceFetchOptionsFromObject <
166- Rest extends object ,
167- Input extends TokenSourceFetchOptions & Rest = TokenSourceFetchOptions & Rest ,
168- > ( input : Input ) : [ TokenSourceFetchOptions , Rest ] {
169- const output : Partial < Input > = { ...input } ;
170- const options : TokenSourceFetchOptions = { } ;
171-
172- for ( const key of Object . keys ( input ) as Array < keyof TokenSourceFetchOptions > ) {
173- switch ( key ) {
174- case 'roomName' :
175- case 'participantName' :
176- case 'participantIdentity' :
177- case 'participantMetadata' :
178- case 'agentName' :
179- case 'agentMetadata' :
180- options [ key ] = input [ key ] ;
181- delete output [ key ] ;
182- break ;
183-
184- case 'participantAttributes' :
185- options . participantAttributes = options . participantAttributes ?? { } ;
186- delete output . participantAttributes ;
187- break ;
188-
189- default :
190- // ref: https://stackoverflow.com/a/58009992
191- key satisfies never ;
192- break ;
193- }
194- }
195-
196- return [ options , output as Rest ] ;
197- }
198-
199- function areRoomOptionsEqual ( a : RoomOptions , b : RoomOptions ) {
200- const [ tokenSourceFetchOptionsA , restRoomOptionsA ] = extractTokenSourceFetchOptionsFromObject ( a ) ;
201- const [ tokenSourceFetchOptionsB , restRoomOptionsB ] = extractTokenSourceFetchOptionsFromObject ( b ) ;
202-
203- if ( ! areTokenSourceFetchOptionsEqual ( tokenSourceFetchOptionsA , tokenSourceFetchOptionsB ) ) {
204- return false ;
205- }
206-
207- // FIXME: do this in a better way maybe?
208- // I stole this existing approach from useLiveKitRoom
209- const restRoomOptionsAHash = JSON . stringify ( restRoomOptionsA , roomOptionsStringifyReplacer ) ;
210- const restRoomOptionsBHash = JSON . stringify ( restRoomOptionsB , roomOptionsStringifyReplacer ) ;
211- if ( restRoomOptionsAHash !== restRoomOptionsBHash ) {
212- return false ;
213- }
214-
215- return true ;
216- }
137+ type UseSessionConfigurableOptions = UseSessionCommonOptions & TokenSourceOptions ;
138+ type UseSessionFixedOptions = UseSessionCommonOptions ;
217139
218140/**
219141 * A Session represents a manages connection to a Room which can contain Agents.
@@ -231,40 +153,13 @@ export function useSession(
231153 tokenSource : TokenSourceConfigurable | TokenSourceFixed ,
232154 options : UseSessionConfigurableOptions | UseSessionFixedOptions = { } ,
233155) : UseSessionReturn {
234- const { agentConnectTimeoutMilliseconds, ...restOptions } = options ;
235-
236- const roomOptions : RoomOptions = useMemo ( ( ) => {
237- if ( tokenSource instanceof TokenSourceConfigurable ) {
238- return { tokenSource, ...restOptions } ; // as RoomOptionsTokenSourceConfigurable FIXME: add this!
239- } else if ( tokenSource instanceof TokenSourceFixed ) {
240- return { tokenSource, ...restOptions } ; // as RoomOptionsTokenSourceFixed FIXME: add this!
241- } else {
242- throw new Error ( 'Specified token source is neither fixed nor configurable - is this value valid?' ) ;
243- }
244- } , [ tokenSource , restOptions ] ) ;
245-
246- const [ sessionActive , setSessionActive ] = useState ( false ) ;
247-
248- const previousRoomOptions = useRef ( roomOptions ) ;
249- const previousRoomValue = useRef < Room | null > ( null ) ;
250- const room = useMemo ( ( ) => {
251- const roomOptionsEqual = areRoomOptionsEqual ( previousRoomOptions . current , roomOptions ) ;
252-
253- if ( previousRoomValue . current ) {
254- if ( ! roomOptionsEqual && sessionActive ) {
255- log . warn ( "Warning: useSession tokenSource / options parameters changed while session is active - this won't do anything. If you are intending to change room options, stop the session first with `session.stop()`." ) ;
256- return previousRoomValue . current ;
257- }
258- if ( roomOptionsEqual ) {
259- return previousRoomValue . current ;
260- }
261- }
156+ const { room : optionsRoom , agentConnectTimeoutMilliseconds, ...tokenSourceOptions } = options ;
262157
263- const room = new Room ( roomOptions ) ;
264- previousRoomValue . current = room ;
265- previousRoomOptions . current = roomOptions ;
266- return room ;
267- } , [ roomOptions ] ) ;
158+ const roomFromContext = useMaybeRoomContext ( ) ;
159+ const room = useMemo (
160+ ( ) => roomFromContext ?? optionsRoom ?? new Room ( ) ,
161+ [ roomFromContext , optionsRoom ] ,
162+ ) ;
268163
269164 const emitter = useMemo ( ( ) => new EventEmitter ( ) as TypedEventEmitter < SessionCallbacks > , [ ] ) ;
270165
@@ -476,16 +371,11 @@ export function useSession(
476371 const tokenSourceFetch = useCallback ( ( ) => {
477372 const isConfigurable = tokenSource instanceof TokenSourceConfigurable ;
478373 if ( isConfigurable ) {
479- return tokenSource . fetch ( restOptions ) ;
374+ return tokenSource . fetch ( tokenSourceOptions ) ;
480375 } else {
481376 return tokenSource . fetch ( ) ;
482377 }
483- } , [ tokenSource , restOptions ] ) ;
484-
485- const end = useCallback ( async ( ) => {
486- setSessionActive ( false ) ;
487- await room . disconnect ( ) ;
488- } , [ setSessionActive , room ] ) ;
378+ } , [ tokenSource ] ) ;
489379
490380 const start = useCallback (
491381 async ( connectOptions : SessionConnectOptions = { } ) => {
@@ -496,13 +386,14 @@ export function useSession(
496386
497387 await waitUntilDisconnected ( signal ) ;
498388
499- setSessionActive ( true ) ;
500- const onSignalAbort = ( ) => end ( ) ;
389+ const onSignalAbort = ( ) => {
390+ room . disconnect ( ) ;
391+ } ;
501392 signal ?. addEventListener ( 'abort' , onSignalAbort ) ;
502393
503394 await Promise . all ( [
504395 // FIXME: swap the below line in once the new `livekit-client` changes are published
505- // room.connect(),
396+ // room.connect(tokenSource, { tokenSourceOptions } ),
506397 tokenSourceFetch ( ) . then ( ( { serverUrl, participantToken } ) =>
507398 room . connect ( serverUrl , participantToken ) ,
508399 ) ,
@@ -522,18 +413,23 @@ export function useSession(
522413
523414 signal ?. removeEventListener ( 'abort' , onSignalAbort ) ;
524415 } ,
525- [ room , waitUntilDisconnected , tokenSourceFetch , waitUntilConnected , agent . waitUntilAvailable , end ] ,
416+ [ room , waitUntilDisconnected , tokenSourceFetch , waitUntilConnected , agent . waitUntilAvailable ] ,
526417 ) ;
527418
419+ const end = useCallback ( async ( ) => {
420+ await room . disconnect ( ) ;
421+ } , [ room ] ) ;
422+
528423 const prepareConnection = useCallback ( async ( ) => {
529424 const credentials = await tokenSourceFetch ( ) ;
530425 // FIXME: swap the below line in once the new `livekit-client` changes are published
531- // await room.prepareConnection(),
426+ // room.prepareConnection(tokenSource, { tokenSourceOptions } ),
532427 await room . prepareConnection ( credentials . serverUrl , credentials . participantToken ) ;
533428 } , [ tokenSourceFetch , room ] ) ;
534429 useEffect ( ( ) => {
535430 prepareConnection ( ) . catch ( ( err ) => {
536- log . warn ( 'Room.prepareConnection failed:' , err ) ;
431+ // FIXME: figure out a better logging solution?
432+ console . warn ( 'WARNING: Room.prepareConnection failed:' , err ) ;
537433 } ) ;
538434 } , [ prepareConnection ] ) ;
539435
0 commit comments