Skip to content

feat(llc): handle isPinned in joinParticipant event#1220

Merged
Brazol merged 3 commits intomainfrom
feat/participant-join-pinned
Apr 23, 2026
Merged

feat(llc): handle isPinned in joinParticipant event#1220
Brazol merged 3 commits intomainfrom
feat/participant-join-pinned

Conversation

@Brazol
Copy link
Copy Markdown
Contributor

@Brazol Brazol commented Apr 22, 2026

Summary by CodeRabbit

  • New Features

    • Participants can now be automatically pinned when joining if the server marks them pinned; pins include non-local pin metadata (with timestamp).
  • Deprecations

    • The custom field on CallParticipantState is deprecated — use customData instead.
  • Documentation

    • Changelog updated to describe the new join-time pinning behavior.

@Brazol Brazol requested a review from a team as a code owner April 22, 2026 14:52
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 22, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e0ba8122-8a1d-455a-8248-a2c6e102c924

📥 Commits

Reviewing files that changed from the base of the PR and between 1afc770 and ff21d2d.

📒 Files selected for processing (2)
  • packages/stream_video/CHANGELOG.md
  • packages/stream_video/lib/src/call/call_events.dart
✅ Files skipped from review due to trivial changes (1)
  • packages/stream_video/CHANGELOG.md

📝 Walkthrough

Walkthrough

Adds server-driven participant pinning support: protobuf schemas extended (participantJoined.isPinned, negotiationId fields), mappers and events carry isPinned, call-state initialization applies non-local pin when isPinned is true, and a changelog entry documents the feature.

Changes

Cohort / File(s) Summary
Protobuf: SFU events
packages/stream_video/lib/protobuf/video/sfu/event/events.pb.dart, packages/stream_video/lib/protobuf/video/sfu/event/events.pbjson.dart
Added isPinned (bool, tag 3) to ParticipantJoined with accessors and JSON descriptor updates; added negotiationId (int, tag 3) to SubscriberOffer.
Protobuf: Signal RPC
packages/stream_video/lib/protobuf/video/sfu/signal_rpc/signal.pb.dart, packages/stream_video/lib/protobuf/video/sfu/signal_rpc/signal.pbjson.dart
Added negotiationId (int32/unsigned, tag 4) to SendAnswerRequest with constructor param and accessors; updated JSON descriptor.
SFU domain & mapping
packages/stream_video/lib/src/sfu/data/events/sfu_events.dart, packages/stream_video/lib/src/sfu/data/events/sfu_event_mapper_extensions.dart
Added isPinned field to SfuParticipantJoinedEvent (default false) and mapped protobuf participantJoined.isPinned through to the domain event.
Call event mapping & state
packages/stream_video/lib/src/call/call_events.dart, packages/stream_video/lib/src/call/state/mixins/state_sfu_mixin.dart
When a participant joins with isPinned == true, initialize their CallParticipantState.pin with a non-local CallParticipantPin(pinnedAt: DateTime.now()); otherwise behavior unchanged.
Models
packages/stream_video/lib/src/models/call_participant_state.dart
Marked constructor parameter custom as deprecated (@Deprecated('Use customData instead')) in public and internal constructors.
Docs
packages/stream_video/CHANGELOG.md
Added changelog entry describing automatic pinning when SFU ParticipantJoined carries isPinned: true.

Sequence Diagram(s)

sequenceDiagram
    participant SFU as SFU Server
    participant Mapper as Event Mapper
    participant Domain as Call Events
    participant StateMgr as State Manager
    participant Store as Call State

    SFU->>Mapper: ParticipantJoined(isPinned: true)
    Mapper->>Domain: SfuParticipantJoinedEvent(isPinned: true)
    Domain->>Domain: detect isPinned flag
    alt isPinned == true
        Domain->>StateMgr: sfuParticipantJoined(event with isPinned)
        StateMgr->>StateMgr: create CallParticipantState with pin\n(CallParticipantPin{isLocalPin:false, pinnedAt: now})
        StateMgr->>Store: update participants with pinned state
    else isPinned == false
        Domain->>StateMgr: sfuParticipantJoined(event)
        StateMgr->>Store: update participants normally
    end
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A join comes in with a pin so bright,
The SFU whispers, "Make them right."
Protobuf hops, the mapper sings,
State sets the pin and joy it brings.
📌✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The pull request lacks a description entirely, missing all required template sections including Goal, Implementation details, Testing, and Contributor Checklist. Add a comprehensive description following the template: explain the goal of handling participant pinning, describe implementation details across protobuf and event layers, specify testing approach, and complete the contributor checklist.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: handling the isPinned field in the joinParticipant event, which aligns with the protobuf schema updates, event mapping, and participant state management throughout the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/participant-join-pinned

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.

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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/stream_video/lib/protobuf/video/sfu/signal_rpc/signal.pb.dart (1)

1553-1643: ⚠️ Potential issue | 🟠 Major

Wire negotiationId through the answer flow.

The generated protobuf models now include negotiationId in both SubscriberOffer (incoming) and SendAnswerRequest (outgoing), but the intermediate layers haven't been updated: SfuSubscriberOfferEvent lacks the field, the event mapper doesn't extract it, _onSubscriberOffer() doesn't pass it to the request, and SendAnswerRequestX.toJson() omits it. This means the new field will be unused end-to-end, breaking SFU answer correlation if the backend expects it.

Add negotiationId to SfuSubscriberOfferEvent, extract it in the mapper from SubscriberOffer, pass it when constructing sfu.SendAnswerRequest(...), and include it in SendAnswerRequestX.toJson():

Suggested updates
extension SendAnswerRequestX on sfu.SendAnswerRequest {
  Map<String, dynamic> toJson() {
    return {
      'peerType': peerType.value,
      'sdp': sdp,
      'sessionId': sessionId,
+     if (hasNegotiationId()) 'negotiationId': negotiationId,
    };
  }
}

Also propagate negotiationId through SfuSubscriberOfferEvent, the event mapper, and the request builder.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/stream_video/lib/protobuf/video/sfu/signal_rpc/signal.pb.dart`
around lines 1553 - 1643, The new negotiationId field must be propagated
end-to-end: add a negotiationId (int?) property to SfuSubscriberOfferEvent,
update the event mapper that converts SubscriberOffer -> SfuSubscriberOfferEvent
to extract SubscriberOffer.negotiationId, update _onSubscriberOffer to include
event.negotiationId when constructing the outgoing sfu.SendAnswerRequest, and
modify SendAnswerRequestX.toJson() to include negotiationId in the serialized
map; ensure you reference the protobuf types SubscriberOffer and
sfu.SendAnswerRequest and the classes/methods SfuSubscriberOfferEvent, the event
mapper function, _onSubscriberOffer, and SendAnswerRequestX so the new field is
wired through all layers.
packages/stream_video/lib/src/models/call_participant_state.dart (1)

19-24: ⚠️ Potential issue | 🟠 Major

Provide a warning-free migration path for the deprecated custom parameter.

The custom parameter is deprecated but still required in the public constructor, which forces external callers to continue passing it explicitly even when migrating to customData. This prevents clean deprecation for library users. Make custom optional with a default value in the public constructor to allow callers to stop using the deprecated parameter. The private constructor can keep it required without the deprecation annotation since it's internal.

Proposed adjustment
   CallParticipantState({
     required this.userId,
     required this.roles,
     required this.name,
-    `@Deprecated`('Use customData instead') required this.custom,
+    `@Deprecated`('Use customData instead') this.custom = const {},
     this.customData = const {},
     this.image,
     required this.sessionId,
@@
   CallParticipantState._({
     required this.userId,
     required this.roles,
     required this.name,
-    `@Deprecated`('Use customData instead') required this.custom,
+    required this.custom,
     required this.customData,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/stream_video/lib/src/models/call_participant_state.dart` around
lines 19 - 24, The public CallParticipantState constructor currently requires
the deprecated parameter custom; make the deprecated custom parameter optional
with a sensible default (e.g. an empty map/const {}) so callers can stop passing
it and migrate to customData without warnings, while leaving the
private/internal CallParticipantState._ (or any private constructor overloads)
unchanged (they can keep custom required) and update any forwarding/redirecting
constructors or factory methods that call the public constructor to rely on the
new optional default for custom; ensure the `@Deprecated` annotation remains on
the public parameter so users see the deprecation but are not forced to supply
the value.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@packages/stream_video/lib/protobuf/video/sfu/signal_rpc/signal.pb.dart`:
- Around line 1553-1643: The new negotiationId field must be propagated
end-to-end: add a negotiationId (int?) property to SfuSubscriberOfferEvent,
update the event mapper that converts SubscriberOffer -> SfuSubscriberOfferEvent
to extract SubscriberOffer.negotiationId, update _onSubscriberOffer to include
event.negotiationId when constructing the outgoing sfu.SendAnswerRequest, and
modify SendAnswerRequestX.toJson() to include negotiationId in the serialized
map; ensure you reference the protobuf types SubscriberOffer and
sfu.SendAnswerRequest and the classes/methods SfuSubscriberOfferEvent, the event
mapper function, _onSubscriberOffer, and SendAnswerRequestX so the new field is
wired through all layers.

In `@packages/stream_video/lib/src/models/call_participant_state.dart`:
- Around line 19-24: The public CallParticipantState constructor currently
requires the deprecated parameter custom; make the deprecated custom parameter
optional with a sensible default (e.g. an empty map/const {}) so callers can
stop passing it and migrate to customData without warnings, while leaving the
private/internal CallParticipantState._ (or any private constructor overloads)
unchanged (they can keep custom required) and update any forwarding/redirecting
constructors or factory methods that call the public constructor to rely on the
new optional default for custom; ensure the `@Deprecated` annotation remains on
the public parameter so users see the deprecation but are not forced to supply
the value.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fd6b996f-1576-41ad-97e4-a260e7522592

📥 Commits

Reviewing files that changed from the base of the PR and between 45dffe2 and 1afc770.

📒 Files selected for processing (10)
  • packages/stream_video/CHANGELOG.md
  • packages/stream_video/lib/protobuf/video/sfu/event/events.pb.dart
  • packages/stream_video/lib/protobuf/video/sfu/event/events.pbjson.dart
  • packages/stream_video/lib/protobuf/video/sfu/signal_rpc/signal.pb.dart
  • packages/stream_video/lib/protobuf/video/sfu/signal_rpc/signal.pbjson.dart
  • packages/stream_video/lib/src/call/call_events.dart
  • packages/stream_video/lib/src/call/state/mixins/state_sfu_mixin.dart
  • packages/stream_video/lib/src/models/call_participant_state.dart
  • packages/stream_video/lib/src/sfu/data/events/sfu_event_mapper_extensions.dart
  • packages/stream_video/lib/src/sfu/data/events/sfu_events.dart

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 23, 2026

Codecov Report

❌ Patch coverage is 2.43902% with 40 lines in your changes missing coverage. Please review.
✅ Project coverage is 5.77%. Comparing base (45dffe2) to head (ff21d2d).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
..._video/lib/protobuf/video/sfu/event/events.pb.dart 0.00% 20 Missing ⚠️
...o/lib/protobuf/video/sfu/signal_rpc/signal.pb.dart 0.00% 10 Missing ⚠️
...ackages/stream_video/lib/src/call/call_events.dart 0.00% 7 Missing ⚠️
...deo/lib/src/call/state/mixins/state_sfu_mixin.dart 50.00% 1 Missing ⚠️
...c/sfu/data/events/sfu_event_mapper_extensions.dart 0.00% 1 Missing ⚠️
...ream_video/lib/src/sfu/data/events/sfu_events.dart 0.00% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff            @@
##            main   #1220      +/-   ##
========================================
- Coverage   5.77%   5.77%   -0.01%     
========================================
  Files        676     676              
  Lines      49296   49335      +39     
========================================
+ Hits        2849    2850       +1     
- Misses     46447   46485      +38     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Brazol Brazol merged commit 4a2e21a into main Apr 23, 2026
15 of 16 checks passed
@Brazol Brazol deleted the feat/participant-join-pinned branch April 23, 2026 08:27
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