Open
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates local publishing so camera+microphone and screenshare A/V tracks can be grouped into shared MediaStreams (so the SDP msid groups them), enabling the remote side to treat related tracks as coming from the same source.
Changes:
- Extend
WebRTCEndpoint.addTrackto accept an optionalMediaStream, and emitlocalTrackAddedwith that shared stream. - Introduce
LocalStreamints-clientand use it inFishjamClient.addTrackto group camera/mic and screenshare tracks into two stable shared streams. - Adjust local track replacement stream-mutation behavior to remove only the replaced track (instead of clearing the whole stream).
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| packages/webrtc-client/src/webRTCEndpoint.ts | Allows passing a shared MediaStream into addTrack for msid grouping. |
| packages/webrtc-client/src/tracks/LocalTrack.ts | Changes how replaceTrack updates the associated stream’s track list. |
| packages/ts-client/src/index.ts | Exports the new LocalStream utility. |
| packages/ts-client/src/LocalStream.ts | Adds a helper to manage a shared stream with at most one audio + one video track. |
| packages/ts-client/src/FishjamClient.ts | Uses shared LocalStreams for camera/mic and screenshare when publishing tracks. |
Comments suppressed due to low confidence (2)
packages/webrtc-client/src/tracks/LocalTrack.ts:161
replaceTrackmutates the sharedMediaStream(removingoldTrack/ addingnewTrack) before callingRTCRtpSender.replaceTrack. IfreplaceTrackthrows, the catch block restorestrackContext.trackbut does not restore the stream’s track list, leaving the stream out of sync with the actual sender/track state. This can break subsequent operations and, with shared streams, can desync A/V grouping. Consider either updating the stream only aftersender.replaceTracksucceeds, or performing a full rollback in the catch (removenewTrackfrom the stream and re-addoldTrackwhen present).
if (oldTrack) {
stream?.removeTrack(oldTrack);
}
if (newTrack) {
stream?.addTrack(newTrack);
}
const action = getActionType(this.trackContext.track, newTrack);
this.trackContext.track = newTrack;
this.mediaStreamTrackId = newTrack?.id ?? null;
if (action === 'mute' || action === 'unmute') {
emitMutableEvents(action, webrtc, trackId);
}
try {
await this.sender.replaceTrack(newTrack);
} catch (_error) {
// rollback: emit opposite events and revert internal state
if (action === 'mute') {
emitMutableEvents('unmute', webrtc, trackId);
} else if (action === 'unmute') {
emitMutableEvents('mute', webrtc, trackId);
}
this.trackContext.track = oldTrack;
this.mediaStreamTrackId = oldTrack?.id ?? null;
}
packages/ts-client/src/FishjamClient.ts:429
- The
localTrackStreamMapis used to find aMediaStreamTrackwhen handlinglocalTrackRemoved(since the event only containstrackId). After alocalTrackReplaced, this map is not updated, so a laterlocalTrackRemovedwill attempt to remove the old track fromlocalCameraStream/localScreenShareStream, leaving the current track in the shared stream. Update the map in thelocalTrackReplacedhandler (set toevent.trackor delete whenevent.trackis null) so stream cleanup stays correct after replacements.
this.webrtc?.on('localTrackRemoved', (event) => {
const track = this.localTrackStreamMap.get(event.trackId);
if (track) {
this.localCameraStream.removeTrack(track);
this.localScreenShareStream.removeTrack(track);
this.localTrackStreamMap.delete(event.trackId);
}
this.emit('localTrackRemoved', event);
});
this.webrtc?.on('localTrackReplaced', (event) => {
this.emit('localTrackReplaced', event);
});
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Gawor270
reviewed
Mar 24, 2026
Gawor270
approved these changes
Mar 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Camera + mic and screenshare are now grouped into media streams. They are now placed into groups in the sdp (msid is set)
Motivation and Context
Why is this change required? What problem does it solve? If it fixes an open
issue, please link to the issue here.
Documentation impact
Types of changes
not work as expected)