Skip to content

Conversation

@pierre-lehnen-rc
Copy link
Contributor

@pierre-lehnen-rc pierre-lehnen-rc commented Oct 29, 2025

Proposed changes (including videos or screenshots)

Issue(s)

VGA-56

Steps to test or reproduce

Further comments

Summary by CodeRabbit

  • Bug Fixes

    • Prevented a race that could cause WebRTC negotiation to fail when both participants renegotiated simultaneously, improving call reliability.
  • New Features

    • Centralized negotiation manager for more reliable offer/answer flow and smoother renegotiation.
    • New SDP exchange APIs, explicit local/remote description handling, ICE-gathering wait, and an isStable status for better call stability and observability.
  • Chores

    • Bumped media-related package versions.

@dionisio-bot
Copy link
Contributor

dionisio-bot bot commented Oct 29, 2025

Looks like this PR is not ready to merge, because of the following issues:

  • This PR is targeting the wrong base branch. It should target 7.13.0, but it targets 7.12.0

Please fix the issues and try again

If you have any trouble, please check the PR guidelines

@changeset-bot
Copy link

changeset-bot bot commented Oct 29, 2025

🦋 Changeset detected

Latest commit: d46b081

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 42 packages
Name Type
@rocket.chat/media-signaling Minor
@rocket.chat/media-calls Minor
@rocket.chat/meteor Patch
@rocket.chat/core-services Patch
@rocket.chat/ddp-client Patch
@rocket.chat/ui-voip Patch
@rocket.chat/account-service Patch
@rocket.chat/authorization-service Patch
@rocket.chat/ddp-streamer Patch
@rocket.chat/omnichannel-transcript Patch
@rocket.chat/presence-service Patch
@rocket.chat/queue-worker Patch
@rocket.chat/stream-hub-service Patch
@rocket.chat/federation-matrix Patch
@rocket.chat/network-broker Patch
@rocket.chat/omni-core-ee Patch
@rocket.chat/omnichannel-services Patch
@rocket.chat/presence Patch
rocketchat-services Patch
@rocket.chat/livechat Patch
@rocket.chat/mock-providers Patch
@rocket.chat/ui-contexts Patch
@rocket.chat/uikit-playground Patch
@rocket.chat/fuselage-ui-kit Patch
@rocket.chat/gazzodown Patch
@rocket.chat/ui-avatar Patch
@rocket.chat/ui-client Patch
@rocket.chat/ui-video-conf Patch
@rocket.chat/web-ui-registration Patch
@rocket.chat/core-typings Patch
@rocket.chat/rest-typings Patch
@rocket.chat/api-client Patch
@rocket.chat/apps Patch
@rocket.chat/cron Patch
@rocket.chat/freeswitch Patch
@rocket.chat/http-router Patch
@rocket.chat/model-typings Patch
@rocket.chat/license Patch
@rocket.chat/pdf-worker Patch
@rocket.chat/models Patch
@rocket.chat/instance-status Patch
@rocket.chat/omni-core Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 29, 2025

Warning

Rate limit exceeded

@pierre-lehnen-rc has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 11 minutes and 39 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 056357b and d46b081.

📒 Files selected for processing (1)
  • packages/media-signaling/src/lib/NegotiationManager.ts (1 hunks)

Walkthrough

Introduces a Negotiation and NegotiationManager to centralize WebRTC renegotiation, refactors IWebRTCProcessor/Processor APIs and SDP/ICE flows, removes four client-state variants and schema values, updates Call and CallSignalProcessor to use the manager, and bumps package versions with a changelog entry.

Changes

Cohort / File(s) Summary
Version & Changelog
/.changeset/six-adults-lie.md
Bumps minor versions for @rocket.chat/media-signaling and @rocket.chat/media-calls; adds changelog entry fixing simultaneous renegotiation failure.
Client State Types
packages/media-signaling/src/definition/client.ts
Removes has-offer, has-answer, has-new-offer, has-new-answer variants from ClientState.
Local-state Signal Schema
packages/media-signaling/src/definition/signals/client/local-state.ts
Removes the four offer/answer enum variants from clientMediaSignalLocalStateSchema.clientState.
Service Processor Types
packages/media-signaling/src/definition/services/IServiceProcessor.ts, packages/media-signaling/src/definition/services/index.ts
Makes IServiceProcessor generic over ServiceUniqueEvents; removes negotiationNeeded from ServiceProcessorEvents; exports negotiation module.
Negotiation Types
packages/media-signaling/src/definition/services/negotiation.ts
Adds NegotiationManagerEvents, NegotiationManagerConfig, NegotiationEvents, NegotiationData, and INegotiationCompatibleMediaCall.
IWebRTCProcessor API
packages/media-signaling/src/definition/services/webrtc/IWebRTCProcessor.ts
Adds WebRTCUniqueEvents with negotiationNeeded; changes event typing; changes createOffer/createAnswer to return RTCSessionDescriptionInit; removes startNewNegotiation/setRemoteAnswer; adds setLocalDescription, setRemoteDescription, waitForIceGathering, getLocalDescription.
Call refactor
packages/media-signaling/src/lib/Call.ts
Replaces per-negotiation fields with a NegotiationManager; delegates SDP/offer/answer handling to it and wires its events into the call.
New NegotiationManager
packages/media-signaling/src/lib/NegotiationManager.ts
Adds NegotiationManager coordinating negotiation queueing, politeness/sequence handling, lifecycle, and public APIs: addNegotiation, setRemoteDescription, processNegotiations, setWebRTCProcessor, and currentNegotiationId getter.
Negotiation Coordinator
packages/media-signaling/src/lib/services/webrtc/Negotiation.ts
Adds Negotiation and WebRTCNegotiation classes for negotiation lifecycle, SDP creation/application, ICE handling, events, and error handling.
WebRTC Processor refactor
packages/media-signaling/src/lib/services/webrtc/Processor.ts
Centralizes initialization and ICE gathering, replaces legacy flags and flows with initialization/gathering flow, exposes setLocalDescription/setRemoteDescription, createOffer/createAnswer now return RTCSessionDescriptionInit, adds isStable() and revised ICE handling.
CallSignalProcessor logic
ee/packages/media-calls/src/internal/agents/CallSignalProcessor.ts
Adds unsigned-client early exit; expands processNegotiationNeeded with politeness/sequence branching and a startNewNegotiation helper to initiate fresh negotiations.

Sequence Diagram(s)

sequenceDiagram
    actor Caller
    actor Callee
    participant NM as NegotiationManager
    participant N as Negotiation
    participant WP as WebRTCProcessor

    Note over Caller,Callee: Two simultaneous renegotiations

    Caller ->> NM: addNegotiation(id-A, remoteOffer?)
    Callee ->> NM: addNegotiation(id-B, remoteOffer?)
    NM ->> NM: enqueue & decide order (sequence, politeness)

    rect rgb(230,245,235)
      NM ->> N: process(selected negotiation)
      N ->> WP: createOffer() / createAnswer()
      WP -->> N: RTCSessionDescriptionInit
      N ->> WP: setLocalDescription(sdp)
      N ->> WP: waitForIceGathering()
      N ->> NM: emit local-sdp (deliver)
    end

    Note over NM: Other negotiation deferred, retried, or started based on politeness/sequence
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Focus review on:
    • packages/media-signaling/src/lib/NegotiationManager.ts — queuing, politeness/sequence correctness, concurrency edges.
    • packages/media-signaling/src/lib/services/webrtc/Processor.ts — initialization gating, ICE gathering, SDP set/get flows.
    • ee/packages/media-calls/src/internal/agents/CallSignalProcessor.ts — politeness branches and race handling.

Possibly related PRs

Suggested reviewers

  • KevLehman
  • tassoevan

Poem

🐰 I hopped where offers tangled in air,
I queued the dances with courteous care,
Polite or impolite, each step set right,
SDP and ICE now waltz through the night,
Hop—no more collisions, all signals bright.

Pre-merge checks and finishing touches

✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: weak glare protection on webrtc renegotiations' accurately describes the main change: implementing server-side glare protection to handle simultaneous WebRTC renegotiations.
Linked Issues check ✅ Passed The PR implements server-side glare protection for WebRTC renegotiations through NegotiationManager with sequencing and politeness-based logic VGA-56, and adds CallSignalProcessor guards to prevent simultaneous negotiations.
Out of Scope Changes check ✅ Passed All changes are scoped to WebRTC negotiation handling. Type definitions (ClientState, IServiceProcessor, IWebRTCProcessor) and implementations (NegotiationManager, Negotiation, Processor) directly support the glare protection objective.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@codecov
Copy link

codecov bot commented Oct 29, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 67.82%. Comparing base (688786a) to head (d46b081).
⚠️ Report is 1 commits behind head on feat/voip-sync-audio-direction.

Additional details and impacted files

Impacted file tree graph

@@                        Coverage Diff                         @@
##           feat/voip-sync-audio-direction   #37335      +/-   ##
==================================================================
+ Coverage                           67.62%   67.82%   +0.19%     
==================================================================
  Files                                3345     3345              
  Lines                              113837   114470     +633     
  Branches                            20666    20725      +59     
==================================================================
+ Hits                                76985    77637     +652     
+ Misses                              34163    34150      -13     
+ Partials                             2689     2683       -6     
Flag Coverage Δ
e2e 57.52% <ø> (+0.03%) ⬆️
unit 71.85% <ø> (+0.28%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out 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.

@pierre-lehnen-rc pierre-lehnen-rc force-pushed the fix/voip-weak-glare-protection branch from 73115f4 to 0adee6c Compare October 29, 2025 17:28
@pierre-lehnen-rc pierre-lehnen-rc marked this pull request as ready for review November 3, 2025 21:49
@pierre-lehnen-rc pierre-lehnen-rc changed the title fix: (wip) weak glare protection on webrtc renegotiations fix: weak glare protection on webrtc renegotiations Nov 3, 2025
@pierre-lehnen-rc pierre-lehnen-rc added this to the 7.13.0 milestone Nov 3, 2025
@pierre-lehnen-rc pierre-lehnen-rc added the stat: QA assured Means it has been tested and approved by a company insider label Nov 3, 2025
@dionisio-bot dionisio-bot bot added the stat: ready to merge PR tested and approved waiting for merge label Nov 3, 2025
Copy link
Contributor

@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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 688786a and dd30d3b.

📒 Files selected for processing (12)
  • .changeset/six-adults-lie.md (1 hunks)
  • ee/packages/media-calls/src/internal/agents/CallSignalProcessor.ts (1 hunks)
  • packages/media-signaling/src/definition/client.ts (0 hunks)
  • packages/media-signaling/src/definition/services/IServiceProcessor.ts (1 hunks)
  • packages/media-signaling/src/definition/services/index.ts (1 hunks)
  • packages/media-signaling/src/definition/services/negotiation.ts (1 hunks)
  • packages/media-signaling/src/definition/services/webrtc/IWebRTCProcessor.ts (2 hunks)
  • packages/media-signaling/src/definition/signals/client/local-state.ts (1 hunks)
  • packages/media-signaling/src/lib/Call.ts (13 hunks)
  • packages/media-signaling/src/lib/NegotiationManager.ts (1 hunks)
  • packages/media-signaling/src/lib/services/webrtc/Negotiation.ts (1 hunks)
  • packages/media-signaling/src/lib/services/webrtc/Processor.ts (11 hunks)
💤 Files with no reviewable changes (1)
  • packages/media-signaling/src/definition/client.ts
🧰 Additional context used
🧬 Code graph analysis (7)
packages/media-signaling/src/definition/services/negotiation.ts (2)
packages/media-signaling/src/definition/logger.ts (1)
  • IMediaSignalLogger (1-6)
packages/media-signaling/src/definition/call/IClientMediaCall.ts (1)
  • IClientMediaCall (67-101)
packages/media-signaling/src/lib/services/webrtc/Processor.ts (1)
packages/media-signaling/src/definition/services/webrtc/IWebRTCProcessor.ts (1)
  • WebRTCInternalStateMap (7-13)
packages/media-signaling/src/lib/Call.ts (1)
packages/media-signaling/src/lib/NegotiationManager.ts (1)
  • NegotiationManager (6-287)
ee/packages/media-calls/src/internal/agents/CallSignalProcessor.ts (2)
ee/packages/media-calls/src/logger.ts (1)
  • logger (3-3)
packages/models/src/index.ts (1)
  • MediaCallNegotiations (186-186)
packages/media-signaling/src/definition/services/webrtc/IWebRTCProcessor.ts (1)
packages/media-signaling/src/definition/services/IServiceProcessor.ts (1)
  • ServiceProcessorEvents (14-17)
packages/media-signaling/src/lib/NegotiationManager.ts (3)
packages/media-signaling/src/definition/services/negotiation.ts (3)
  • NegotiationManagerEvents (4-8)
  • INegotiationCompatibleMediaCall (28-30)
  • NegotiationManagerConfig (10-12)
packages/media-signaling/src/lib/services/webrtc/Negotiation.ts (1)
  • Negotiation (5-163)
packages/media-signaling/src/definition/services/webrtc/IWebRTCProcessor.ts (1)
  • IWebRTCProcessor (21-45)
packages/media-signaling/src/lib/services/webrtc/Negotiation.ts (3)
packages/media-signaling/src/definition/services/negotiation.ts (2)
  • NegotiationEvents (14-18)
  • NegotiationData (20-26)
packages/media-signaling/src/definition/services/webrtc/IWebRTCProcessor.ts (1)
  • IWebRTCProcessor (21-45)
packages/media-signaling/src/definition/logger.ts (1)
  • IMediaSignalLogger (1-6)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: 📦 Build Packages
  • GitHub Check: CodeQL-Build
  • GitHub Check: CodeQL-Build

Copy link
Contributor

@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: 4

♻️ Duplicate comments (1)
packages/media-signaling/src/definition/services/IServiceProcessor.ts (1)

19-23: Add type constraint to ServiceUniqueEvents generic parameter.

The previous review comment suggested adding a type constraint to ensure ServiceUniqueEvents can only be extended with compatible event types. Without the constraint, callers could pass invalid types that aren't compatible with the Emitter intersection.

Apply this diff to add the missing constraint:

 export interface IServiceProcessor<
 	ServiceStateMap extends DefaultServiceStateMap = DefaultServiceStateMap,
-	ServiceUniqueEvents = Record<never, never>,
+	ServiceUniqueEvents extends Record<string, unknown> = Record<never, never>,
 > {
 	emitter: Emitter<ServiceProcessorEvents<ServiceStateMap> & ServiceUniqueEvents>;
🧹 Nitpick comments (1)
packages/media-signaling/src/lib/NegotiationManager.ts (1)

34-49: Consider consistent initialization for negotiation ID tracking.

Lines 45-46 initialize highestNegotiationId to null and highestKnownNegotiationId to an empty string. This mixed approach (null vs empty string) could lead to confusion. Consider using a consistent initialization pattern (e.g., both null) unless the semantic difference is intentional and documented.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between dd30d3b and c0371bd.

📒 Files selected for processing (3)
  • packages/media-signaling/src/definition/services/IServiceProcessor.ts (1 hunks)
  • packages/media-signaling/src/definition/services/webrtc/IWebRTCProcessor.ts (2 hunks)
  • packages/media-signaling/src/lib/NegotiationManager.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
packages/media-signaling/src/lib/NegotiationManager.ts (3)
packages/media-signaling/src/definition/services/negotiation.ts (3)
  • NegotiationManagerEvents (4-8)
  • INegotiationCompatibleMediaCall (28-30)
  • NegotiationManagerConfig (10-12)
packages/media-signaling/src/lib/services/webrtc/Negotiation.ts (1)
  • Negotiation (5-163)
packages/media-signaling/src/definition/services/webrtc/IWebRTCProcessor.ts (1)
  • IWebRTCProcessor (21-45)
packages/media-signaling/src/definition/services/webrtc/IWebRTCProcessor.ts (1)
packages/media-signaling/src/definition/services/IServiceProcessor.ts (2)
  • ServiceProcessorEvents (14-17)
  • IServiceProcessor (19-26)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: 📦 Build Packages
  • GitHub Check: CodeQL-Build
  • GitHub Check: CodeQL-Build
🔇 Additional comments (5)
packages/media-signaling/src/lib/NegotiationManager.ts (3)

51-90: LGTM: Negotiation queuing logic implements glare protection.

The method correctly handles duplicate negotiations, validates offer types, and implements the glare protection strategy by skipping negotiations with stale sequences. Line 65's assumption that negotiations arrive in order when negotiationSequence is not provided is reasonable for the use case.


120-144: LGTM: Processor setup and negotiation processing loop.

The WebRTC processor setup correctly wires event listeners, and the processNegotiations method implements a clean state machine pattern with appropriate guards.


256-264: Fix typos in comments.

Lines 257 and 262: "fullfil" should be "fulfill".

Apply this diff:

 	protected isFulfillingNegotiationQueued(): boolean {
-		// If we're a polite client, then any queued negotiation is enough to fullfil our negotiation needs
+		// If we're a polite client, then any queued negotiation is enough to fulfill our negotiation needs
 		if (this.isPoliteClient()) {
 			return this.highestSequence > this.highestProcessedSequence;
 		}
 
 		// If there's an impolite negotiation queued, that's good enough for any client

Likely an incorrect or invalid review comment.

packages/media-signaling/src/definition/services/webrtc/IWebRTCProcessor.ts (2)

15-19: LGTM: WebRTC-specific event types properly extend service processor events.

The new WebRTCUniqueEvents type correctly defines the negotiationNeeded event, and the intersection pattern with ServiceProcessorEvents aligns with the generic extension mechanism introduced in IServiceProcessor.


21-37: LGTM: API simplification and negotiation-supporting methods.

The interface changes correctly:

  • Extend IServiceProcessor with WebRTCUniqueEvents to expose the negotiationNeeded event
  • Simplify createOffer and createAnswer return types by removing wrapper objects
  • Add essential methods (setLocalDescription, setRemoteDescription, waitForIceGathering, getLocalDescription) that the NegotiationManager requires for coordinating SDP exchanges

Copy link
Contributor

@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: 3

🧹 Nitpick comments (2)
packages/media-signaling/src/lib/NegotiationManager.ts (2)

109-115: Consider adding descriptive message to error log.

The error logging at line 112 now correctly uses structured logging (fixed from past review). For improved debugging, consider including a descriptive message and the negotiation ID.

Apply this diff:

 		try {
 			return this.currentNegotiation.setRemoteAnswer(remoteDescription);
 		} catch (e) {
-			this.config.logger?.error(e);
+			this.config.logger?.error('Failed to set remote answer', e, { negotiationId });
 			this.currentNegotiation = null;
 			this.emitter.emit('error', { errorCode: 'failed-to-set-remote-answer', negotiationId });
 		}

223-229: Consider adding descriptive message to error log.

The error logging at line 226 now correctly uses structured logging (fixed from past review). For improved debugging, consider including a descriptive message.

Apply this diff:

 		try {
 			return negotiation.process(this.webrtcProcessor);
 		} catch (e) {
-			this.config.logger?.error(e);
+			this.config.logger?.error('Failed to process negotiation', e, { negotiationId: negotiation.negotiationId });
 			this.currentNegotiation = null;
 			this.emitter.emit('error', { errorCode: 'failed-to-process-negotiation', negotiationId: negotiation.negotiationId });
 		}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c0371bd and b723e67.

📒 Files selected for processing (1)
  • packages/media-signaling/src/lib/NegotiationManager.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-06T20:32:23.658Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 37152
File: packages/apps-engine/tests/test-data/utilities.ts:557-573
Timestamp: 2025-10-06T20:32:23.658Z
Learning: In packages/apps-engine/tests/test-data/utilities.ts, the field name `isSubscripbedViaBundle` in the `IMarketplaceSubscriptionInfo` type should not be flagged as a typo, as it may match the upstream API's field name.

Applied to files:

  • packages/media-signaling/src/lib/NegotiationManager.ts
🧬 Code graph analysis (1)
packages/media-signaling/src/lib/NegotiationManager.ts (3)
packages/media-signaling/src/definition/services/negotiation.ts (3)
  • NegotiationManagerEvents (4-8)
  • INegotiationCompatibleMediaCall (28-30)
  • NegotiationManagerConfig (10-12)
packages/media-signaling/src/lib/services/webrtc/Negotiation.ts (1)
  • Negotiation (5-163)
packages/media-signaling/src/definition/services/webrtc/IWebRTCProcessor.ts (1)
  • IWebRTCProcessor (21-45)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: 📦 Build Packages
  • GitHub Check: CodeQL-Build
  • GitHub Check: CodeQL-Build
🔇 Additional comments (1)
packages/media-signaling/src/lib/NegotiationManager.ts (1)

294-296: Good use of abstract class for type safety.

The WebRTCNegotiationManager abstract class effectively narrows the webrtcProcessor type from nullable to required, enabling type-safe assertions in methods like processNegotiation (line 196) and isConfigured (line 232).

Copy link
Contributor

@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: 0

🧹 Nitpick comments (4)
packages/media-signaling/src/lib/NegotiationManager.ts (4)

26-26: Remove unused field inputTrackAvailable.

The inputTrackAvailable field is initialized in the constructor (line 44) but is never read or updated anywhere in the class. The actual input track availability is checked via this.call.hasInputTrack() at line 244.

Apply this diff to remove the unused field:

-	protected inputTrackAvailable: boolean;
-
 	/** id of the newest negotiation that has reached the processing state */

And remove from the constructor:

 		this.webrtcProcessor = null;
-		this.inputTrackAvailable = false;
 		this.highestNegotiationId = null;

196-230: Consider adding cleanup for completed negotiations.

The negotiation map grows indefinitely as new negotiations are added (line 155), but completed negotiations are never removed. This could lead to memory accumulation over long-lived calls with many renegotiations. Additionally, event listeners attached to each negotiation (lines 203, 213, 218) remain in memory even after the negotiation completes.

Consider adding cleanup logic to remove old negotiations from the map:

negotiation.emitter.on('ended', () => {
	if (this.currentNegotiation !== negotiation) {
		return;
	}

	this.config.logger?.debug('NegotiationManager.processNegotiation.ended');
	this.currentNegotiation = null;
	
	// Clean up old negotiations that have been processed and ended
	for (const [id, neg] of this.negotiations.entries()) {
		if (neg.ended && neg.sequence < this.highestProcessedSequence) {
			this.negotiations.delete(id);
		}
	}
	
	void this.processNegotiations();
});

Alternatively, implement a periodic cleanup or limit the map size based on a retention policy.


252-260: Consider using consistent spelling.

The comment uses "fulfil" (British spelling), while line 178 uses "fulfilled" (American spelling). For consistency across the codebase, consider standardizing on one variant.

Apply this diff for consistency:

-	// If we're a polite client, then any queued negotiation is enough to fulfil our negotiation needs
+	// If we're a polite client, then any queued negotiation is enough to fulfill our negotiation needs
 	if (this.isPoliteClient()) {

294-296: Unconventional type narrowing pattern.

The WebRTCNegotiationManager abstract class is used purely for type narrowing through the isConfigured() type guard (line 232) rather than actual inheritance. While this works correctly, it's an unconventional pattern. Consider adding a comment explaining this design choice to aid future maintainers.

Add a clarifying comment:

+/**
+ * Type-narrowing helper: asserts that webrtcProcessor is non-null.
+ * Used by isConfigured() type guard to enable safe access to processor methods.
+ */
 abstract class WebRTCNegotiationManager extends NegotiationManager {
 	protected abstract webrtcProcessor: IWebRTCProcessor;
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b723e67 and 056357b.

📒 Files selected for processing (1)
  • packages/media-signaling/src/lib/NegotiationManager.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-06T20:32:23.658Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 37152
File: packages/apps-engine/tests/test-data/utilities.ts:557-573
Timestamp: 2025-10-06T20:32:23.658Z
Learning: In packages/apps-engine/tests/test-data/utilities.ts, the field name `isSubscripbedViaBundle` in the `IMarketplaceSubscriptionInfo` type should not be flagged as a typo, as it may match the upstream API's field name.

Applied to files:

  • packages/media-signaling/src/lib/NegotiationManager.ts
🧬 Code graph analysis (1)
packages/media-signaling/src/lib/NegotiationManager.ts (3)
packages/media-signaling/src/definition/services/negotiation.ts (3)
  • NegotiationManagerEvents (4-8)
  • INegotiationCompatibleMediaCall (28-30)
  • NegotiationManagerConfig (10-12)
packages/media-signaling/src/lib/services/webrtc/Negotiation.ts (1)
  • Negotiation (5-163)
packages/media-signaling/src/definition/services/webrtc/IWebRTCProcessor.ts (1)
  • IWebRTCProcessor (21-45)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: 📦 Build Packages
  • GitHub Check: CodeQL-Build
  • GitHub Check: CodeQL-Build
🔇 Additional comments (12)
packages/media-signaling/src/lib/NegotiationManager.ts (12)

1-11: LGTM!

The imports and the currentNegotiationId getter are implemented correctly, with proper fallback logic for when no negotiation is actively being processed.


34-49: LGTM!

Constructor properly initializes all state fields, with nullable fields set to null and numeric sequences set to 0.


51-90: LGTM!

The negotiation addition logic correctly implements the polite/impolite negotiation pattern for glare protection. The XOR logic at line 70 properly determines whether a negotiation originates from the polite peer (callee), and negotiations with outdated sequences are correctly skipped.


92-116: LGTM!

The remote description handling correctly routes offers to addNegotiation and validates that answers correspond to the current negotiation. Error handling uses structured logging appropriately.


118-124: Verify single processor initialization or add cleanup.

If setWebRTCProcessor is called multiple times with different processors, the old event listeners will remain attached to the previous processor, potentially causing memory leaks.

If the processor can change during the lifecycle, consider removing old listeners before attaching new ones:

 public setWebRTCProcessor(webrtcProcessor: IWebRTCProcessor) {
 	this.config.logger?.debug('NegotiationManager.setWebRTCProcessor');
+	// Clean up old listeners if processor is being replaced
+	if (this.webrtcProcessor) {
+		this.webrtcProcessor.emitter.off('internalError', this.onWebRTCInternalError);
+		this.webrtcProcessor.emitter.off('negotiationNeeded', this.onWebRTCNegotiationNeeded);
+	}
+	
 	this.webrtcProcessor = webrtcProcessor;

 	this.webrtcProcessor.emitter.on('internalError', (event) => this.onWebRTCInternalError(event));
 	this.webrtcProcessor.emitter.on('negotiationNeeded', () => this.onWebRTCNegotiationNeeded());
 }

Otherwise, verify and document that this method is only called once during initialization.


126-142: LGTM!

The processing logic correctly gates on configuration state and ensures only one negotiation is processed at a time.


144-146: LGTM!

The polite client determination correctly maps the callee role to polite behavior in the perfect negotiation pattern.


148-169: LGTM!

The queue management correctly tracks sequence numbers and implements the glare protection logic where impolite negotiations preempt polite ones.


171-194: LGTM!

The queue selection logic correctly prioritizes negotiations according to the perfect negotiation pattern, ensuring impolite negotiations preempt conflicting polite ones.


232-250: LGTM!

The configuration check correctly gates negotiation processing on call state, processor availability, and input track readiness, with proper type narrowing.


262-280: LGTM!

The negotiation-needed handler correctly prevents redundant renegotiation requests by checking if a fulfilling negotiation is already queued.


282-291: LGTM!

The internal error handler correctly propagates WebRTC processor errors with proper context (negotiation ID when available).

@tassoevan tassoevan merged commit 7367c89 into feat/voip-sync-audio-direction Nov 5, 2025
48 checks passed
@tassoevan tassoevan deleted the fix/voip-weak-glare-protection branch November 5, 2025 00:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stat: QA assured Means it has been tested and approved by a company insider stat: ready to merge PR tested and approved waiting for merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants