-
Notifications
You must be signed in to change notification settings - Fork 7
VIDCS-3442: Refactor session context #140
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
frontend/src/hooks/useEmoji.tsx
Outdated
useEffect(() => { | ||
session?.on('signal', emojiHandler); | ||
|
||
return () => { | ||
session?.off('signal', emojiHandler); | ||
}; | ||
}, [emojiHandler, session]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We handle this in the session context. Removing this silences the event listener console warning.
changedStream: null | ChangedStreamType; | ||
connections: null | Connection[]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These two weren't used anywhere.
@@ -146,7 +118,8 @@ const MAX_PIN_COUNT = isMobile() ? MAX_PIN_COUNT_MOBILE : MAX_PIN_COUNT_DESKTOP; | |||
* @returns {SessionContextType} a context provider for a publisher preview | |||
*/ | |||
const SessionProvider = ({ children }: SessionProviderProps): ReactElement => { | |||
const session = useRef<Session | null>(null); | |||
const [, forceUpdate] = useState<boolean>(false); // NOSONAR |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Takes the place of the setChangedStream
state function. Without a re-render during a stream change, we don't get visual indicators for a subscriber muting themselves or the initials being displayed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be good to add this context somewhere 🙏
/** | ||
* Handles the creation of a new connection. Adding it to the connection array | ||
* @param {ConnectionEventType} e - The connection event object. | ||
*/ | ||
const handleConnectionCreated = (e: ConnectionEventType) => { | ||
setConnections((prevConnections) => [...prevConnections, e.connection]); | ||
}; | ||
|
||
/** | ||
* Handles the destruction of a connection. Removing it from the connections array | ||
* @param {ConnectionEventType} e - The connection event object. | ||
*/ | ||
const handleConnectionDestroyed = (e: ConnectionEventType) => { | ||
setConnections((prevConnections) => | ||
[...prevConnections].filter( | ||
(connection) => connection.connectionId !== e.connection.connectionId | ||
) | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These two weren't used at all. It may have been leftovers from our call data function from the beginning.
const subscribe = useCallback( | ||
async (stream: Stream, localSession: Session, options: SubscriberProperties = {}) => { | ||
const { streamId } = stream; | ||
if (localSession) { | ||
const finalOptions: SubscriberProperties = { | ||
...options, | ||
insertMode: 'append', | ||
width: '100%', | ||
height: '100%', | ||
preferredResolution: 'auto', | ||
style: { | ||
buttonDisplayMode: 'off', | ||
nameDisplayMode: 'on', | ||
}, | ||
insertDefaultUI: false, | ||
}; | ||
const isScreenshare = stream.videoType === 'screen'; | ||
const subscriber = localSession.subscribe(stream, undefined, finalOptions); | ||
subscriber.on('videoElementCreated', (event: VideoElementCreatedEvent) => { | ||
const { element } = event; | ||
const subscriberWrapper: SubscriberWrapper = { | ||
element, | ||
subscriber, | ||
isScreenshare, | ||
isPinned: false, | ||
// subscriber.id is refers to the targetElement id and will be undefined when insertDefaultUI is false so we use streamId to track our subscriber | ||
id: streamId, | ||
}; | ||
// prepend new subscriber to beginning of array so that is is visible on joining | ||
setSubscriberWrappers((previousSubscriberWrappers) => | ||
[subscriberWrapper, ...previousSubscriberWrappers].sort( | ||
sortByDisplayPriority(activeSpeakerIdRef.current) | ||
) | ||
); | ||
}); | ||
|
||
subscriber.on('destroyed', () => { | ||
activeSpeakerTracker.current.onSubscriberDestroyed(streamId); | ||
const isNotDestroyedStreamId = ({ id }: { id: string }) => streamId !== id; | ||
setSubscriberWrappers((prevSubscriberWrappers) => | ||
prevSubscriberWrappers.filter(isNotDestroyedStreamId) | ||
); | ||
}); | ||
|
||
// Create moving average tracker and add handler for subscriber audioLevelUpdated event emitted periodically with subscriber audio volume | ||
// See for reference: https://developer.vonage.com/en/video/guides/ui-customization/general-customization#adjusting-user-interface-based-on-audio-levels | ||
const getMovingAverageAudioLevel = createMovingAvgAudioLevelTracker(); | ||
subscriber.on('audioLevelUpdated', ({ audioLevel }) => { | ||
const { logMovingAvg } = getMovingAverageAudioLevel(audioLevel); | ||
activeSpeakerTracker.current.onSubscriberAudioLevelUpdated({ | ||
subscriberId: streamId, | ||
movingAvg: logMovingAvg, | ||
}); | ||
}); | ||
} | ||
}, | ||
[] | ||
); | ||
|
||
// handle the subscription (Receiving media from remote parties) | ||
const handleStreamCreated = (e: StreamCreatedEvent) => { | ||
if (session.current) { | ||
subscribe(e.stream, session.current); | ||
} | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most of this was moved to the VonageVideoClient
class. Some are bespoke handlers in this file, see below.
await new Promise<string | undefined>((resolve, reject) => { | ||
session.current?.connect(token, (err?: OTError) => { | ||
if (err) { | ||
// We ignore the following lint warning because we are rejecting with an OTError object. | ||
reject(err); // NOSONAR | ||
} else { | ||
setConnected(true); | ||
logOnConnect(apiKey, sessionId, session.current?.connection?.connectionId); | ||
resolve(session.current?.sessionId); | ||
} | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved to VonageVideoClient
file. We set connected
state if we successfully connect, below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can this error though?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep! The session.current.connect(credential);
call can throw if there's an issue calling Session.connect
23694b0
to
89d7cd6
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good so far, good to separate all the nitty gritty logic around the SDK away from some of the react stuff by adding this more simple interface 🙌
await new Promise<string | undefined>((resolve, reject) => { | ||
session.current?.connect(token, (err?: OTError) => { | ||
if (err) { | ||
// We ignore the following lint warning because we are rejecting with an OTError object. | ||
reject(err); // NOSONAR | ||
} else { | ||
setConnected(true); | ||
logOnConnect(apiKey, sessionId, session.current?.connection?.connectionId); | ||
resolve(session.current?.sessionId); | ||
} | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can this error though?
@@ -146,7 +118,8 @@ const MAX_PIN_COUNT = isMobile() ? MAX_PIN_COUNT_MOBILE : MAX_PIN_COUNT_DESKTOP; | |||
* @returns {SessionContextType} a context provider for a publisher preview | |||
*/ | |||
const SessionProvider = ({ children }: SessionProviderProps): ReactElement => { | |||
const session = useRef<Session | null>(null); | |||
const [, forceUpdate] = useState<boolean>(false); // NOSONAR |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be good to add this context somewhere 🙏
177d926
to
b575d9d
Compare
What is this PR doing?
Refactoring session context (eventually).
How should this be manually tested?
What are the relevant tickets?
A maintainer will add this ticket number.
Resolves VIDCS-3442
Checklist
[✅] Branch is based on
develop
(notmain
).[ ] Resolves a
Known Issue
.[ ] If yes, did you remove the item from the
docs/KNOWN_ISSUES.md
?[ ] Resolves an item reported in
Issues
.If yes, which issue? Issue Number?