Fix/connect ps data channel after default data channel connected#4798
Fix/connect ps data channel after default data channel connected#4798JudyZhuHz merged 20 commits intowebex:nextfrom
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 351fb9599a
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| await new Promise<void>((resolve) => { | ||
| const onDefaultSessionConnected = () => { | ||
| // @ts-ignore - Fix type | ||
| this.webex.internal.llm.off('online', onDefaultSessionConnected); | ||
| resolve(); |
There was a problem hiding this comment.
Re-check practice state after waiting for default online
This code computes isPracticeSession/URLs before the await and then proceeds to registerAndConnect after the wait without re-validating state. If the panelist leaves or is demoted while the default LLM session is still offline, cleanupPSDataChannel() can run, but this suspended call will later resume on 'online' and reconnect the practice-session channel with stale meeting data, re-attaching relay listeners unexpectedly. Re-evaluate meeting/practice eligibility after the wait (or cancel pending waiters during cleanup) before connecting.
Useful? React with 👍 / 👎.
|
This pull request is automatically being deployed by Amplify Hosting (learn more). |
…to fix/connect_ps_after_default
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b212b5c8cf
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| this.updatePSDataChannel(); | ||
| }; | ||
| // @ts-ignore - Fix type | ||
| this.webex.internal.llm.on('online', onDefaultSessionConnected); |
There was a problem hiding this comment.
Deduplicate deferred online listener before scheduling reconnect
When updatePSDataChannel() runs while the default LLM session is offline, this line adds a new 'online' listener every time with no guard for an existing pending waiter. In practice, role/locus updates can invoke updatePSDataChannel() multiple times before default comes online, so all queued handlers fire and each re-enters updatePSDataChannel(), causing concurrent registerAndConnect/cleanup flows for the same practice-session ID; this can race and leave the practice-session connection state inconsistent or trigger unexpected disconnect/reconnect behavior. Track a single pending listener (or use a one-shot registration with cancellation in cleanup) instead of registering unbounded handlers.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 08cb77f62f
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
|
||
| // Ensure the default session data channel is connected before connecting the practice session | ||
| // @ts-ignore - Fix type | ||
| if (!this.webex.internal.llm.isConnected()) { |
There was a problem hiding this comment.
Avoid missing default-session online transition
updatePSDataChannel() checks llm.isConnected() before subscribing to 'online', which introduces a check-then-subscribe race: if the default session comes online between the check and llm.on('online', ...), Mercury’s one-time 'online' emission is already gone (it is emitted via trigger in internal-plugin-mercury/src/mercury.js and not replayed), so this call returns and never retries the practice-session connect. In that window, panelists can stay disconnected from the practice-session channel until an unrelated later update happens to call updatePSDataChannel() again.
Useful? React with 👍 / 👎.
|
@codex review |
|
Codex Review: Didn't find any major issues. Already looking forward to the next diff. ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback". |
…default # Conflicts: # packages/@webex/plugin-meetings/test/unit/spec/webinar/index.ts
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 45f0c5a841
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| const datachannelToken = this.webex.internal.llm.getDatachannelToken( | ||
| DataChannelTokenType.Default | ||
| ); |
There was a problem hiding this comment.
Restore locus-token fallback for default LLM session
updateLLMConnection() now reads the default token only from llm.getDatachannelToken(...) and no longer falls back to this.locusInfo.self.datachannelToken, so any locus-driven reconnect path that runs before/without saveDataChannelToken(join) leaves datachannelToken undefined even when Locus already has a valid token. In token-auth mode this makes registerAndConnect() send no Data-Channel-Auth-Token header, causing default-session data-channel connect failures for flows like lobby admission or early meeting-info updates.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Before saveDataChannelToken() called, the isJoined will be false, so we will not call registerAndConnect() actually
| const practiceSessionDatachannelToken = this.webex.internal.llm.getDatachannelToken( | ||
| DataChannelTokenType.PracticeSession | ||
| ); |
There was a problem hiding this comment.
Recover practice-session token from locus when cache is empty
updatePSDataChannel() now sources the practice-session token only from llm.getDatachannelToken(...) and removed the previous fallback to meeting.locusInfo.self.practiceSessionDatachannelToken. If the practice-session token is first delivered by a later locus update (or cache was cleared), this code attempts registerAndConnect() with undefined, so in JWT-token mode the practice-session channel is opened without auth header and fails to connect even though Locus has the token.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Same as above comment
…default # Conflicts: # docs/samples/meetings.min.js
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7100da0354
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| const practiceSessionDatachannelToken = this.webex.internal.llm.getDatachannelToken( | ||
| DataChannelTokenType.PracticeSession | ||
| ); |
There was a problem hiding this comment.
Restore token fallback before PS reconnect
After a panelist is demoted, cleanupPSDataChannel() disconnects the practice-session LLM connection, and that path clears the cached practice token in LLM; on a later promotion in the same meeting, this code now reads only getDatachannelToken(...) and no longer falls back to meeting.locusInfo.self.practiceSessionDatachannelToken, so registerAndConnect() is called with undefined. In token-auth mode this sends no Data-Channel-Auth-Token header and can block practice-session reconnection until a full rejoin/refresh repopulates the cache. Fresh evidence versus earlier discussion: this failure is reproducible even after join succeeds, because demotion cleanup itself empties the token cache before the next promotion.
Useful? React with 👍 / 👎.
This reverts commit 6ff96db.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4e2386afe1
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| const datachannelToken = this.webex.internal.llm.getDatachannelToken( | ||
| DataChannelTokenType.Default | ||
| ); |
There was a problem hiding this comment.
Restore locus-token fallback when default cache is empty
updateLLMConnection() now reads only llm.getDatachannelToken(DataChannelTokenType.Default) and no longer falls back to locusInfo.self.datachannelToken, so when the cache is empty it calls registerAndConnect(..., undefined). This is reachable after lobby flows: SELF_ADMITTED_GUEST re-invokes updateLLMConnection() but that path does not call saveDataChannelToken(), so in token-auth mode the request is sent without Data-Channel-Auth-Token even though locus already has a valid token. Fresh evidence vs the earlier thread is this post-admission call path, where isJoined() is true and the cache can still be unset.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2212f6fe66
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| this.disconnect(options, sessionId).then(() => { | ||
| // Clean up sessions data | ||
| this.connections.delete(sessionId); | ||
| this.datachannelTokens[sessionId] = undefined; | ||
| }); |
There was a problem hiding this comment.
Clear token cache when disconnecting a meeting session
disconnectLLM() no longer clears the cached data-channel token, which leaves stale auth state in the shared LLM service after teardown-only paths. In the code path I checked (MeetingUtil.cleanUp() -> cleanupLLMConneciton()), cleanup can run without clearMeetingData(), so the old meeting token remains cached; because updateLLMConnection() now reads only the LLM cache, a later meeting can send the previous meeting’s Data-Channel-Auth-Token and fail token-auth connection until a fresh token is explicitly saved.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
In my test, clearMeetingData will be always called when leave meeting
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7fb7706018
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| this.disconnect(options, sessionId).then(() => { | ||
| // Clean up sessions data | ||
| this.connections.delete(sessionId); | ||
| this.datachannelTokens[sessionId] = undefined; | ||
| }); |
There was a problem hiding this comment.
Reset cached token when disconnecting a session
disconnectLLM() now removes only the connection record and leaves datachannelTokens intact, which leaks auth state across teardown-only flows. Fresh evidence versus the earlier thread: there are cleanup paths that do not run clearMeetingData()—Meeting#index#setUpLocusInfoMeetingListener (the shouldLeave === false branch) and Meetings#destroy both call MeetingUtil.cleanUp() directly—so the stale token persists after meeting destruction. Because this commit also switched updateLLMConnection()/updatePSDataChannel() to rely on cached LLM tokens, later reconnects can send an old meeting token and fail data-channel auth.
Useful? React with 👍 / 👎.
| if (this.config.enableAutomaticLLM) { | ||
| // @ts-ignore | ||
| this.webex.internal.llm.on('online', this.handleLLMOnline); | ||
| this.saveDataChannelToken(join); |
There was a problem hiding this comment.
I'm wondering if this call maybe should be done earlier in line 6154. I'm not entirely sure what is the meaning of enableAutomaticLLM config flag, if it is false, can you still have an LLM connection and might need the token? I see there are places where updateLLMConnection() is called without the check for enableAutomaticLLM config flag....
There was a problem hiding this comment.
I suppose enableAutomaticLLM should always be true in webex meeting? But I agree do it earlier will be safer.
| * @param {Object} join - The parsed join response (from MeetingUtil.parseLocusJoin) | ||
| * @returns {void} | ||
| */ | ||
| saveDataChannelToken(join: any): void { |
There was a problem hiding this comment.
would be nice to use the LocusDTO type here, because we know that join.locus will be of that type, right? and we could also add the 2 tokens to self type, not sure if we have self type declared already, I think I've added it here: https://github.com/webex/webex-js-sdk/pull/4742/changes#diff-10d3bc06a1bbd80411c0671b115c896747942db210526c4771457e083783d5e7R41 - it's just that it's a draft PR that I stopped working on, because probably the change wasn't needed, but we could still take the type from that PR.
There was a problem hiding this comment.
We have to save the tokens into llm lib anyway, because there is a refresh logic that client need to call fetch api to get a new token, the new token will be saved in llm to replace the old one.
| const datachannelToken = join?.locus?.self?.datachannelToken; | ||
| const practiceSessionDatachannelToken = join?.locus?.self?.practiceSessionDatachannelToken; | ||
|
|
||
| if (datachannelToken) { |
There was a problem hiding this comment.
saveDataChannelToken() is only called on join response. Is it not possible for Locus to revoke or to change any of the data channel tokens later after join?
marcin-bazyl
left a comment
There was a problem hiding this comment.
approving as my comments are not blocking and can be addressed in subsequent PRs
…to fix/connect_ps_after_default
Thank you for your contribution! |

COMPLETES #< INSERT LINK TO ISSUE >
This pull request addresses
When panelist join a webinar in which practice session is running, panelist call voicea.announce() earlier than cantina set up voicea event listener, so cantina cannot get the announcement response.
Sometime when leave webinar, "this.transcription" in meeting/index will be undefined so skipps the cleanup work of voicea plugin and make the announce status is not "idle" which block the next announce() if join again.
Data channel tokens only be present in join response and will be removed in later locus message.
by making the following changes
Make sure default data channel connecrted, then connect PS data channel.
Remove the condition "if(this.transcription)" to cleanup voicea anyway.
Save data channel tokens in join response for later usage.
Change Type
The following scenarios were tested
Web client panelist join 5k Webinar in which PS already started, check whether it can get caption language list.
Web client leave webinar and join agian, check whether it can get caption language list.
The GAI Coding Policy And Copyright Annotation Best Practices
I certified that
Make sure to have followed the contributing guidelines before submitting.