Skip to content

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

Closed
wants to merge 0 commits into from

Conversation

cpettet
Copy link
Contributor

@cpettet cpettet commented Apr 1, 2025

What is this PR doing?

Refactoring session context (eventually).

How should this be manually tested?

  • TBD

What are the relevant tickets?

A maintainer will add this ticket number.

Resolves VIDCS-3442

Checklist

[✅] Branch is based on develop (not main).
[ ] 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?

@cpettet cpettet added skip-ci Skip CI do-not-review Do not review labels Apr 1, 2025
Comment on lines 110 to 116
useEffect(() => {
session?.on('signal', emojiHandler);

return () => {
session?.off('signal', emojiHandler);
};
}, [emojiHandler, session]);
Copy link
Contributor Author

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.

Comment on lines 55 to 56
changedStream: null | ChangedStreamType;
connections: null | Connection[];
Copy link
Contributor Author

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
Copy link
Contributor Author

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.

Copy link
Contributor

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 🙏

Comment on lines 251 to 268
/**
* 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
)
);
Copy link
Contributor Author

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.

Comment on lines 292 to 356
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);
}
};
Copy link
Contributor Author

@cpettet cpettet Apr 4, 2025

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.

Comment on lines 404 to 415
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);
}
});
});
Copy link
Contributor Author

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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this error though?

Copy link
Contributor Author

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

@cpettet cpettet force-pushed the cpettet/vidcs-3442-refactor-session-context branch from 23694b0 to 89d7cd6 Compare April 15, 2025 20:59
Copy link
Contributor

@maikthomas maikthomas left a 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 🙌

Comment on lines 404 to 415
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);
}
});
});
Copy link
Contributor

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
Copy link
Contributor

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 🙏

@cpettet cpettet closed this Apr 30, 2025
@cpettet cpettet force-pushed the cpettet/vidcs-3442-refactor-session-context branch from 177d926 to b575d9d Compare April 30, 2025 20:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
do-not-review Do not review skip-ci Skip CI
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants