Skip to content

refactor: RtcCore struct refactoring - #11

Merged
dangusev merged 15 commits into
mainfrom
refactor/rtc-core-refactoring
Sep 25, 2026
Merged

dangusev merged 15 commits into
mainfrom
refactor/rtc-core-refactoring

Conversation

@dangusev

Copy link
Copy Markdown
Collaborator
  • move tests out of rtc/mod.rs, drop redundant tests

@dangusev
dangusev marked this pull request as draft September 23, 2026 14:55
The new names match JS `CallState.participants` and the public `RtcCore::participants()`.
Coordinator and SFU background tasks checked the generation only at some points. The coordinator event reader and the SFU event loop waited for the next message, and the SFU ping loop had no generation exit. A cancelled generation could keep its sockets open.
`leave` and the join error paths cleared shared fields without a generation check.
A join that started while `leave` waited on the network lost its participants, capabilities, reconnect claim, coordinator connection and user token.
The error path of a cancelled join could also stop the coordinator of the next join.

`leave` now clears these fields only when its generation is still current. `stop_coordinator_events` takes a generation and does nothing when it is stale.
Both hold the `lifecycle` lock while they check and clear, in the same order as `apply_join_call_state_if_current`.
During a migration, the old and the new SFU connection share one generation, so events from the old SFU passed the generation check.

A connection with reconnect disabled now ignores `SubscriberOffer`, `IceTrickle`, `ChangePublishOptions`, `ChangePublishQuality` and `IceRestart`.
Зarticipant, track, grant and pin events, errors and `ParticipantMigrationComplete` still apply from the old SFU.
- Rename `FailureCaps` to `FailureLimits`.
- Rename the `RtcCore` field `caps` to `failure_limits`.

`FailureLimits` is public in `rtc::reconnect`, so this breaks code that names the old type.
No behavior change.
A reconnect task of a previous join could run after the next join had started.
It counted an ICE failure for the new join, so the first real ICE failure of the new join reached the limit and left the call.
`reload_user_token` stored the loaded token without a generation check.
If the generation changed in the same poll in which the load finished, the token of a previous join replaced the token of the new join.
Add tests for behavior that had no direct coverage:
  - `while_generation` cancels work that ends after its generation changed, and never starts work for a stale generation.
  - Concurrent reconnect claims for one generation have one winner.
  - A second migration waiter for a generation is rejected. A waiter of a new generation replaces the old one.
  - The user request query needs the coordinator connection of the current generation, a connection id and a user id.
  Add tests for behavior that had no direct coverage:
  - `while_generation` cancels work that ends after its generation
    changed, and never starts work for a stale generation.
  - Concurrent reconnect claims for one generation have one winner.
  - A second migration waiter for a generation is rejected. A waiter of
    a new generation replaces the old one.
  - The user request query needs the coordinator connection of the
    current generation, a connection id and a user id.
  - A join attempt stores the coordinator's stats options, and the
    session id is the one the SFU got in the join request.
  - Only the stored connection of the current generation is current.
- Remove `CallingState::Offline`. The SDK never set it. JS sets it only from a browser network monitor, and this SDK has no such source.
- Remove the private `started` field of `RtcCore`. It was written on join and never read.
`LocalTrack::Video` accepts any `TrackType`.
A video track with the type `Unspecified` or `Audio` passed the join and capability checks, and failed later in codec selection or reached the SFU with a wrong type.
`set_track_muted(Unspecified, …)` returned `Ok` or a misleading `PermissionDenied` for `send-video`.

`publish` now rejects a video track whose type is not `Video` or `ScreenShare`, before any other check.
`set_track_muted` rejects `Unspecified`. Both return `IllegalState`.
The live restore-failure test covered only REJOIN, and it checked only that the fault point was reached and that the call ended `Joined`.
A reconnect that ignored the restore error also passed it.
@dangusev

Copy link
Copy Markdown
Collaborator Author

Also closes #5

webrtc-rs rejects an ICE restart while the ICE agent gathers candidates.
A FAST reconnect soon after a publish or an ICE restart failed with a negotiation error, and each failure counted toward the negotiation limit. Three failures left the call.

`restart_ice` now tries the restart again every 50 ms while webrtc-rs reports that it is gathering, for up to 10 s. At the limit it returns `RtcError::Timeout`, which does not count as a negotiation failure.

`SfuTimeoutError` no longer says "sfu" in its message, because it also reports client deadlines that are not for the SFU.
@dangusev
dangusev marked this pull request as ready for review September 25, 2026 10:34
@dangusev

Copy link
Copy Markdown
Collaborator Author

bugbot run

@cursor

cursor Bot commented Sep 25, 2026

Copy link
Copy Markdown

Skipping Bugbot: Bugbot is disabled for this repository. Visit the Bugbot dashboard to update your settings.

@dangusev
dangusev merged commit 3ec7a54 into main Sep 25, 2026
5 checks passed
@dangusev
dangusev deleted the refactor/rtc-core-refactoring branch September 25, 2026 12:23
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.

2 participants