-
Notifications
You must be signed in to change notification settings - Fork 247
fix: prevent mute cycling when restarting tracks during unmute #1793
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
🦋 Changeset detectedLatest commit: 83f3f62 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
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 |
📝 WalkthroughWalkthroughPropagates a new optional Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
📜 Recent review detailsConfiguration used: Organization UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (4)
🚧 Files skipped from review as they are similar to previous changes (1)
🧰 Additional context used🧬 Code graph analysis (2)src/room/track/LocalVideoTrack.ts (3)
src/room/track/LocalAudioTrack.ts (3)
🔇 Additional comments (7)
✏️ Tip: You can disable this entire section by setting Comment |
There was a problem hiding this 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
🤖 Fix all issues with AI agents
In `@src/room/track/LocalAudioTrack.ts`:
- Around line 109-110: The method signature for LocalAudioTrack.restart is not
formatted to match Prettier; re-run the project's Prettier auto-fixer or
manually reformat the signature of the restart method (protected async
restart(constraints?: MediaTrackConstraints, targetEnabled?: boolean):
Promise<typeof this>) to match the repository's style (e.g., adjust spacing or
break parameters onto separate lines) and ensure the body (including the
super.restart call) remains unchanged so the CI Prettier check passes.
In `@src/room/track/LocalTrack.ts`:
- Line 148: Reformat the LocalTrack class method signature setMediaStreamTrack
so it matches the project's Prettier rules: break the parameter list onto
multiple lines (one parameter per line) and ensure consistent spacing around the
commas and optional parameter markers (e.g., force?: boolean, targetEnabled?:
boolean) and the opening brace; update the signature of private async
setMediaStreamTrack(newTrack: MediaStreamTrack, force?: boolean, targetEnabled?:
boolean) accordingly so the line no longer violates Prettier.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/room/track/LocalAudioTrack.tssrc/room/track/LocalTrack.tssrc/room/track/LocalVideoTrack.ts
🧰 Additional context used
🧬 Code graph analysis (1)
src/room/track/LocalVideoTrack.ts (3)
src/room/track/options.ts (1)
VideoCaptureOptions(169-192)src/room/track/LocalTrack.ts (1)
constraints(38-40)src/room/track/utils.ts (1)
constraintsForOptions(64-103)
🪛 ESLint
src/room/track/LocalAudioTrack.ts
[error] 109-109: Replace constraints?:·MediaTrackConstraints,·targetEnabled?:·boolean with ⏎····constraints?:·MediaTrackConstraints,⏎····targetEnabled?:·boolean,⏎··
(prettier/prettier)
src/room/track/LocalTrack.ts
[error] 148-148: Replace newTrack:·MediaStreamTrack,·force?:·boolean,·targetEnabled?:·boolean with ⏎····newTrack:·MediaStreamTrack,⏎····force?:·boolean,⏎····targetEnabled?:·boolean,⏎··
(prettier/prettier)
🪛 GitHub Actions: Test
src/room/track/LocalAudioTrack.ts
[error] 109-109: prettier/prettier formatting issue in LocalAudioTrack.ts: Replace 'constraints?: MediaTrackConstraints, targetEnabled?: boolean' with proper formatting.
🪛 GitHub Check: test
src/room/track/LocalAudioTrack.ts
[failure] 109-109:
Replace constraints?:·MediaTrackConstraints,·targetEnabled?:·boolean with ⏎····constraints?:·MediaTrackConstraints,⏎····targetEnabled?:·boolean,⏎··
src/room/track/LocalTrack.ts
[failure] 148-148:
Replace newTrack:·MediaStreamTrack,·force?:·boolean,·targetEnabled?:·boolean with ⏎····newTrack:·MediaStreamTrack,⏎····force?:·boolean,⏎····targetEnabled?:·boolean,⏎··
🔇 Additional comments (6)
src/room/track/LocalTrack.ts (2)
204-206: Enabled state now deterministic during restart.Using
targetEnabledavoids transient mute cycling in the unmute-restart path.
324-367: Restart path cleanly propagates targetEnabled.The forwarding into
setMediaStreamTrackkeeps restart behavior consistent with the new unmute flow.src/room/track/LocalAudioTrack.ts (2)
77-89: Reacquire on unmute now forces enabled state.Passing
trueavoids the mute-cycle regression during track restart.
98-107: Restart propagation looks good.The new optional
targetEnabledcleanly flows into the base restart.src/room/track/LocalVideoTrack.ts (2)
161-172: Unmute now restarts with explicit enabled state.This mirrors the audio fix and should avoid the mute-cycle during camera reacquisition.
249-268: Restart now refreshes simulcast tracks appropriately.Cloning and replacing simulcast tracks after restart keeps encodings in sync with the new MediaStreamTrack.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
6535184 to
f62a223
Compare
When unmuting audio/video tracks that require reacquisition (e.g., due to stopOnMute, ended track state, or device changes), the track restart would cause a mute cycle (enabled=false then immediately enabled=true). This happened because: 1. restartTrack() creates a new MediaStreamTrack 2. setMediaStreamTrack() syncs enabled state with !this.isMuted 3. But isMuted is still true at this point (super.unmute() hasn't run yet) 4. So the new track starts with enabled=false 5. Then super.unmute() sets enabled=true On iOS, this causes audible mute/unmute sounds for the microphone and can trigger system callbacks multiple times as the system detects the rapid enabled state changes. The fix adds a targetEnabled parameter that flows through: - unmute() -> restartTrack(undefined, true) - restartTrack() -> restart(constraints, targetEnabled) - restart() -> setMediaStreamTrack(newTrack, false, targetEnabled) When targetEnabled is provided, setMediaStreamTrack uses it instead of deriving the enabled state from isMuted, ensuring the new track starts with the correct enabled state.
f62a223 to
83f3f62
Compare
|
@xianshijing-lk could you please review this PR? |
davidliu
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, @lukasIO is there anything here that could affect web? Should be an isolated change.
When unmuting audio/video tracks that require reacquisition (e.g., due to
stopOnMute, ended track state, or device changes), the track restart would
cause a mute cycle (enabled=false then immediately enabled=true).
This happened because:
On iOS, this causes audible mute/unmute sounds for the microphone and can
trigger system callbacks multiple times as the system detects the rapid
enabled state changes.
The fix adds a targetEnabled parameter that flows through:
When targetEnabled is provided, setMediaStreamTrack uses it instead of
deriving the enabled state from isMuted, ensuring the new track starts
with the correct enabled state.
Related issues
This partially addresses the above issues but does not fix the possibly unnecessary restarts caused by device ID mismatches.
Test plan
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.