Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 44 additions & 9 deletions packages/@webex/plugin-meetings/src/meeting/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,7 @@ export default class Meeting extends StatelessWebexPlugin {
allowMediaInLobby: boolean;
localShareInstanceId: string;
remoteShareInstanceId: string;
acceptedContentHandoffPreviousShare: any;
shareCAEventSentStatus: {
transmitStart: boolean;
transmitStop: boolean;
Expand Down Expand Up @@ -1521,6 +1522,7 @@ export default class Meeting extends StatelessWebexPlugin {
* @memberof Meeting
*/
this.remoteShareInstanceId = null;
this.acceptedContentHandoffPreviousShare = null;

/**
* Status used for ensuring we do not oversend metrics
Expand Down Expand Up @@ -3206,20 +3208,50 @@ export default class Meeting extends StatelessWebexPlugin {
newShareStatus = SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE;
}
}
// or if content share is either released or null and whiteboard share is either released or null, no one is sharing
// Preserve active content sharing while another participant's content floor is only ACCEPTED.
// The final GRANTED update must still see the previous active share status so steal handling
// can unpublish local streams or update the remote presenter without emitting a stop event.
else if (
((previousContentShare && contentShare.disposition === FLOOR_ACTION.RELEASED) ||
contentShare.disposition === null) &&
((previousWhiteboardShare && whiteboardShare.disposition === FLOOR_ACTION.RELEASED) ||
whiteboardShare.disposition === null)
(this.shareStatus === SHARE_STATUS.LOCAL_SHARE_ACTIVE ||
this.shareStatus === SHARE_STATUS.REMOTE_SHARE_ACTIVE) &&
previousContentShare?.disposition === FLOOR_ACTION.GRANTED &&
contentShare.disposition === FLOOR_ACTION.ACCEPTED
Comment on lines 3214 to +3218

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve only real content shares on ACCEPTED

When a webinar attendee or guest is viewing a whiteboard, the earlier whiteboard branch stores it as REMOTE_SHARE_ACTIVE; if that whiteboard is then RELEASED while the next content floor is only ACCEPTED, this new preservation branch treats the whiteboard-backed remote state as an active content share. In that context the listener skips the transition to NO_SHARE and the accepted-event path below is also suppressed, so the stale whiteboard/remote state remains until the final GRANTED update instead of stopping the released whiteboard as intended. Please gate this preservation on the previous/current content floor actually representing an active content share, not just on the shared REMOTE_SHARE_ACTIVE status.

Useful? React with 👍 / 👎.

Comment on lines +3217 to +3218

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve handoff state across repeated ACCEPTED deltas

When Locus sends more than one intermediate ACCEPTED update for the same content handoff, the first one preserves the active share, but the next delta has previous.content.disposition === ACCEPTED, so this condition fails and the default branch changes shareStatus to NO_SHARE. A later GRANTED update then again misses the local-unpublish/remote-steal paths that this patch is trying to protect. Consider also preserving while acceptedContentHandoffPreviousShare is already set and the current floor is still ACCEPTED.

Useful? React with 👍 / 👎.

) {
this.acceptedContentHandoffPreviousShare = previousContentShare;
newShareStatus = this.shareStatus;
}
// Otherwise, neither content nor whiteboard floor is GRANTED (covers
// RELEASED, null, and intermediate dispositions such as ACCEPTED), so no
// one is currently sharing. Active content shares are preserved above until
// another participant receives the final GRANTED floor update.
else {
newShareStatus = SHARE_STATUS.NO_SHARE;
Comment on lines +3227 to 3228

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve local state until remote grant

When a local content share is active and Locus sends an intermediate ACCEPTED update for another participant before the final GRANTED, this default branch changes shareStatus to NO_SHARE. The subsequent GRANTED update then starts remote sharing with oldShareStatus === NO_SHARE, so the existing steal-handling path that calls unpublishStreams() only when oldShareStatus === LOCAL_SHARE_ACTIVE is skipped; the local share tracks can remain published after a remote participant takes the floor. This branch should avoid clearing a local active content share on an intermediate accepted handoff, or otherwise preserve enough state to unpublish on the final remote grant.

Useful? React with 👍 / 👎.

}

LoggerProxy.logger.info(
`Meeting:index#setUpLocusInfoMediaInactiveListener --> this.shareStatus=${this.shareStatus} newShareStatus=${newShareStatus}`
);

let mediaSharesUpdatePayload = payload;

if (
this.acceptedContentHandoffPreviousShare &&
contentShare.disposition === FLOOR_ACTION.GRANTED &&
payload.previous?.content?.disposition === FLOOR_ACTION.ACCEPTED
) {
mediaSharesUpdatePayload = {
...payload,
previous: {
...payload.previous,
content: this.acceptedContentHandoffPreviousShare,
},
};
}

if (contentShare.disposition !== FLOOR_ACTION.ACCEPTED) {
this.acceptedContentHandoffPreviousShare = null;
}

if (newShareStatus !== this.shareStatus) {
const oldShareStatus = this.shareStatus;

Expand Down Expand Up @@ -3393,8 +3425,11 @@ export default class Meeting extends StatelessWebexPlugin {
break;
}

this.members.locusMediaSharesUpdate(payload);
} else if (newShareStatus === SHARE_STATUS.REMOTE_SHARE_ACTIVE) {
this.members.locusMediaSharesUpdate(mediaSharesUpdatePayload);
} else if (
newShareStatus === SHARE_STATUS.REMOTE_SHARE_ACTIVE &&
contentShare.disposition !== FLOOR_ACTION.ACCEPTED
) {
Comment on lines +3429 to +3432

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve previous presenter for member updates

When a content handoff goes through ACCEPTED, this branch now suppresses locusMediaSharesUpdate until the final GRANTED update, but that final payload has previous.content.disposition === ACCEPTED for the new presenter, not the old granted presenter. In local/remote A -> B handoffs, Members.locusMediaSharesUpdate therefore never sees the old A as a granted previous share and never emits endedSharingId or clears A's isContentSharing, leaving the old presenter marked as sharing after B is granted. The accepted handoff path needs to preserve/pass the old granted presenter to the members update, not just the meeting share status.

Useful? React with 👍 / 👎.

// if we got here, then some remote participant has stolen
// the presentation from another remote participant
this.remoteShareInstanceId = contentShare.shareInstanceId;
Expand All @@ -3416,7 +3451,7 @@ export default class Meeting extends StatelessWebexPlugin {
resourceType: contentShare.resourceType,
}
);
this.members.locusMediaSharesUpdate(payload);
this.members.locusMediaSharesUpdate(mediaSharesUpdatePayload);
} else if (newShareStatus === SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE) {
// if we got here, then some remote participant has stolen
// the presentation from another remote participant
Expand All @@ -3442,7 +3477,7 @@ export default class Meeting extends StatelessWebexPlugin {
meetingId: this.id,
},
});
this.members.locusMediaSharesUpdate(payload);
this.members.locusMediaSharesUpdate(mediaSharesUpdatePayload);
}
});
}
Expand Down
Loading
Loading