Skip to content

[MM-68559][MM-68560][MM-68562] Browser screen share with audio publish, subscribe, and end detection#1179

Merged
M-ZubairAhmed merged 14 commits into
v2from
mm_68559_68560_68562
May 18, 2026
Merged

[MM-68559][MM-68560][MM-68562] Browser screen share with audio publish, subscribe, and end detection#1179
M-ZubairAhmed merged 14 commits into
v2from
mm_68559_68560_68562

Conversation

@M-ZubairAhmed
Copy link
Copy Markdown
Member

@M-ZubairAhmed M-ZubairAhmed commented May 14, 2026

Summary

This pull request includes several improvements and refactors related to screen sharing events and state management in the call/recording components and their tests. The main changes focus on consolidating screen sharing action handling, updating event usage for consistency, and improving test mocks.

Ticket Link

https://mattermost.atlassian.net/browse/MM-68562
https://mattermost.atlassian.net/browse/MM-68560
https://mattermost.atlassian.net/browse/MM-68559

Screenshots

Release Note


Implement logic to remove entries from the hosts and didRingForCalls states when a call ends, ensuring proper state management for active calls.
@M-ZubairAhmed M-ZubairAhmed changed the base branch from main to v2 May 14, 2026 01:33
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented May 14, 2026

Codecov Report

❌ Patch coverage is 64.55696% with 56 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (v2@86092cd). Learn more about missing BASE report.

Files with missing lines Patch % Lines
webapp/src/state/screen_sharing_ids/reducer.ts 12.00% 21 Missing and 1 partial ⚠️
webapp/src/clients/call/call_client.ts 88.65% 5 Missing and 6 partials ⚠️
webapp/src/reducers.ts 36.36% 7 Missing ⚠️
webapp/src/actions.ts 0.00% 4 Missing ⚠️
webapp/src/clients/calls/index.ts 0.00% 3 Missing ⚠️
webapp/src/clients/websocket/index.ts 0.00% 2 Missing ⚠️
webapp/src/components/call_widget/component.tsx 0.00% 2 Missing ⚠️
webapp/src/selectors.ts 66.66% 1 Missing and 1 partial ⚠️
webapp/src/websocket_handlers.ts 0.00% 2 Missing ⚠️
webapp/src/components/expanded_view/component.tsx 0.00% 1 Missing ⚠️
Additional details and impacted files
@@          Coverage Diff          @@
##             v2    #1179   +/-   ##
=====================================
  Coverage      ?   26.93%           
=====================================
  Files         ?      245           
  Lines         ?    13170           
  Branches      ?     1680           
=====================================
  Hits          ?     3547           
  Misses        ?     9273           
  Partials      ?      350           
Files with missing lines Coverage Δ
webapp/src/action_types.ts 100.00% <ø> (ø)
webapp/src/clients/call/constants.ts 100.00% <ø> (ø)
...app/src/components/expanded_view/call_settings.tsx 0.00% <ø> (ø)
...ebapp/src/state/screen_sharing_ids/action_types.ts 100.00% <100.00%> (ø)
webapp/src/state/screen_sharing_ids/actions.ts 100.00% <100.00%> (ø)
webapp/src/state/session/actions.ts 72.72% <ø> (ø)
webapp/src/state/session/reducer.ts 7.50% <100.00%> (ø)
webapp/src/components/expanded_view/component.tsx 0.00% <0.00%> (ø)
webapp/src/clients/websocket/index.ts 81.08% <0.00%> (ø)
webapp/src/components/call_widget/component.tsx 0.00% <0.00%> (ø)
... and 7 more
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@M-ZubairAhmed M-ZubairAhmed marked this pull request as ready for review May 15, 2026 04:41
- Added support for screen sharing events, including handling of remote and local screen streams.
- Updated action types and reducers to manage screen sharing state more effectively.
- Refactored websocket handlers to dispatch screen sharing actions.
- Cleaned up unused code and improved type definitions for better maintainability.
- Renamed reducer imports for consistency and clarity.
- Removed obsolete reducer files for screen sharing IDs and session management, streamlining the codebase.
- Ensured proper state management by consolidating reducer logic.
Comment thread webapp/src/actions.ts Outdated
session_id: call.screen_sharing_session_id,
},
});
actions.push(userScreenShared(channelID, call.screen_sharing_session_id, call.owner_id));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think the last argument should be the user ID of the user sharing screen. So maybe:

  const sharer = call.screen_sharing_session_id
      ? call.sessions.find((s) => s.session_id === call.screen_sharing_session_id)
      : undefined;
  actions.push(userScreenShared(channelID, call.screen_sharing_session_id, sharer?.user_id ?? ''));

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

added

@@ -0,0 +1,3 @@
// Copyright (c) 2020-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I presume you plan to put something here, or maybe using these four files are following convention?

Comment thread webapp/src/clients/call/call_client.ts Outdated

logDebug(`CallClient: remote track published from ${userID}`, remoteTrackPublication);
if (remoteTrackPublication.source === Track.Source.ScreenShare || remoteTrackPublication.source === Track.Source.ScreenShareAudio) {
// Screen-share publications do not carry stream state before subscription. We wait for TrackSubscribed,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Missing second comment line?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

added comment

logDebug('CallClient.shareScreen: another participant is already sharing, skipping');
return null;
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What about if this client is already sharing?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

handled the case

const {userID, sessionID} = this.parseUserIdAndSessionIdFromIdentity(localParticipant);
this.emit(CALL_EVENT.LOCAL_SCREEN_STREAM, screenShareStream, sessionID, userID);
logDebug(`CallClient: local screen share stream published for user ${userID}`, localTrackPublication);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

When sharing with audio, this will emit LOCAL_SCREEN_STREAM twice, once when screen video is published, and once when screen audio track is published. This second emission will hold both screen video and audio tracks. So this looks OK, but it's complicated, maybe add a comment?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

added


const emptyState: State = {};

export const reducer: Reducer<State, Actions> = (initialState = emptyState, action) : State => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

claude seems to think that "initialState" is a poor choice of variable name, and prefers "state". I leave it to you to decide.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

yup renamed

Copy link
Copy Markdown
Contributor

@bgardner8008 bgardner8008 left a comment

Choose a reason for hiding this comment

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

Looks great, thanks. I think there is only one thing that needs fixing, passing the screen sharer ID. Rest are just comments.

…eliably by checking the session list, ensuring accurate state management during call reconnections.
…is already sharing, improving efficiency and user experience.
…g teardown before notifying the server, improving state consistency.
- Updated unshareScreen to return early without sending a WebSocket message when not connected.
- Added error handling to emit an ERROR event if setScreenShareEnabled rejects.
- Improved shareScreen to return the existing stream if already sharing and adjusted systemAudio handling based on the withAudio parameter.
@M-ZubairAhmed
Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 17, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 17, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: dc1884bc-94c1-4661-8fe8-e725cb0f7bb2

📥 Commits

Reviewing files that changed from the base of the PR and between 2acf556 and 882bcde.

📒 Files selected for processing (2)
  • webapp/src/actions.ts
  • webapp/src/state/screen_sharing_ids/reducer.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • webapp/src/actions.ts
  • webapp/src/state/screen_sharing_ids/reducer.ts

📝 Walkthrough

Walkthrough

Adds full screen-sharing: CallClient implements share/unshare and stream composition with LiveKit; new Redux slice tracks per-channel sharer; CALL_EVENT constants standardize screen-stream events; components and websocket handlers wired to new actions; comprehensive tests and small config updates.

Changes

Screen-Sharing Implementation

Layer / File(s) Summary
Redux root state typing and session action/reducer refactoring
webapp/src/state/session/actions.ts, webapp/src/state/session/reducer.ts, webapp/src/state/session/selectors.ts, webapp/src/reducers.ts, webapp/src/selectors.ts
Session action creators export named type aliases; session reducer renamed to reducer with typed Channel['id']/UserSessionState['session_id'] keys; root reducer extracted as rootReducer with initialRootState and RootState exports; plugin-state helpers use computed key and typed fallback.
Screen-sharing state slice definition
webapp/src/state/screen_sharing_ids/action_types.ts, webapp/src/state/screen_sharing_ids/actions.ts, webapp/src/state/screen_sharing_ids/reducer.ts, webapp/src/state/screen_sharing_ids/selector.ts, webapp/src/action_types.ts, webapp/src/actions.ts
New Redux slice tracks channel → sharing session_id with USER_SCREEN_ON/USER_SCREEN_OFF action types, userScreenShared/userScreenUnshared creators, reducer upserting/clearing sharer, and hydration via loadCallState dispatch; global action types updated.
CALL_EVENT constants for screen-stream events
webapp/src/clients/call/constants.ts
Added LOCAL_SCREEN_STREAM, LOCAL_SCREEN_STREAM_OFF, REMOTE_SCREEN_STREAM, REMOTE_SCREEN_STREAM_OFF.
CallClient screen-sharing implementation
webapp/src/clients/call/call_client.ts
Adds shareScreen()/unshareScreen(), getLocalScreenStream(), updates getRemoteScreenStream(), composes screen video+audio, wires LiveKit track publish/subscribe/unpublish handlers to emit screen/voice events, and signals server via WebSocket client.
CallClient screen-sharing test suite
webapp/src/clients/call/call_client.test.ts
Enhanced mocks (MediaStream, LiveKit, WebSocket) and extensive tests for local/remote screen publish/unpublish, audio merging, onended teardown, signals (screen_on/screen_off), and error/edge cases.
WebSocket screen-sharing signaling and action dispatch
webapp/src/clients/websocket/index.ts, webapp/src/websocket_handlers.ts
WebSocketClient adds sendScreenOn(payload) and sendScreenOff(); websocket handlers now dispatch userScreenShared/userScreenUnshared action creators.
Event name standardization across components
standalone/src/recording/components/recording_view/index.tsx, webapp/src/clients/calls/index.ts, webapp/src/components/call_widget/component.tsx, webapp/src/components/expanded_view/component.tsx, webapp/src/components/expanded_view/call_settings.tsx
Replaced string event names with CALL_EVENT constants for remote/local screen and voice streams; removed initial getVideoDevices() initialization and a debug log.
Configuration and documentation
.gitignore
Ignore local Claude Code files HANDOFF.local.md and PLAN.local.md.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main feature: browser screen sharing with audio, publish/subscribe functionality, and end detection.
Description check ✅ Passed The description is related to the changeset, mentioning screen sharing events, state management improvements, and test refactors that align with the code changes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch mm_68559_68560_68562

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@webapp/src/actions.ts`:
- Around line 594-595: Guard the unconditional dispatch of userScreenShared
inside loadCallState: check that call.screen_sharing_session_id is truthy and
that call.sessions contains a matching session with a non-empty user_id (the
screenSharer found by call.sessions.find where session.session_id ===
call.screen_sharing_session_id). Only push actions.push(userScreenShared(...))
when both the session exists and screenSharer.user_id is present; otherwise skip
emitting the "screen on" action to avoid dispatching with empty IDs.

In `@webapp/src/state/screen_sharing_ids/reducer.ts`:
- Around line 40-43: The reducer currently sets the "not sharing" state by
assigning an empty-string sentinel with [action.data.channelID]: '' (using
initialState), which leaves stale keys; instead remove the channel key entirely:
in the reducer (the function handling this action that references initialState
and action.data.channelID) build a new state object that omits the channel key
(e.g., spread the existing state into newState and delete
newState[action.data.channelID] or use object destructuring to omit the key) and
return that new object; make the same change in the other branch that currently
uses an empty string (the block around the lines referenced as 58-61) so both
branches delete the channel key rather than set it to ''.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b888a420-b6bf-4bf4-88f8-78330359b08a

📥 Commits

Reviewing files that changed from the base of the PR and between 86092cd and 2acf556.

📒 Files selected for processing (22)
  • .gitignore
  • standalone/src/recording/components/recording_view/index.tsx
  • webapp/src/action_types.ts
  • webapp/src/actions.ts
  • webapp/src/clients/call/call_client.test.ts
  • webapp/src/clients/call/call_client.ts
  • webapp/src/clients/call/constants.ts
  • webapp/src/clients/calls/index.ts
  • webapp/src/clients/websocket/index.ts
  • webapp/src/components/call_widget/component.tsx
  • webapp/src/components/expanded_view/call_settings.tsx
  • webapp/src/components/expanded_view/component.tsx
  • webapp/src/reducers.ts
  • webapp/src/selectors.ts
  • webapp/src/state/screen_sharing_ids/action_types.ts
  • webapp/src/state/screen_sharing_ids/actions.ts
  • webapp/src/state/screen_sharing_ids/reducer.ts
  • webapp/src/state/screen_sharing_ids/selector.ts
  • webapp/src/state/session/actions.ts
  • webapp/src/state/session/reducer.ts
  • webapp/src/state/session/selectors.ts
  • webapp/src/websocket_handlers.ts
💤 Files with no reviewable changes (2)
  • webapp/src/action_types.ts
  • webapp/src/components/expanded_view/call_settings.tsx

Comment thread webapp/src/actions.ts Outdated
Comment thread webapp/src/state/screen_sharing_ids/reducer.ts Outdated
… only if screen sharing session ID and user ID are present, enhancing state management.

- Simplified reducer logic to delete channelID from state instead of setting it to an empty string, improving state clarity.
@M-ZubairAhmed
Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 18, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@M-ZubairAhmed M-ZubairAhmed merged commit 51411bc into v2 May 18, 2026
19 checks passed
@M-ZubairAhmed M-ZubairAhmed deleted the mm_68559_68560_68562 branch May 18, 2026 07:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants