Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
211bfe9
fix: tighten VideoTrackRenderer Widget
holzgeist Jan 22, 2025
ff23d72
fix(web, firefox): backup old values before overwriting them
holzgeist Jul 8, 2025
591eaba
fix: copy processor
holzgeist Apr 2, 2025
64aba20
fix: properly handle processor updates
holzgeist Jul 3, 2025
7b7c583
fix: properly update processed streams
holzgeist Jul 16, 2025
d65a15d
Merge remote-tracking branch 'upstream/main' into feat-blurring
holzgeist Aug 4, 2025
19f3d05
fix: stop stream first, processor second
holzgeist Aug 21, 2025
4734a3b
Merge branch 'main' into feat-blurring
holzgeist Aug 26, 2025
e92daaa
chore: format files
holzgeist Aug 26, 2025
1cd7c2a
chore: update webrtc sdk to same version as flutter-webrtc
holzgeist Aug 26, 2025
1b0a286
chore: run import sorter
holzgeist Aug 26, 2025
8d86095
chore: fix analyzer issues
holzgeist Aug 26, 2025
8eb03d9
Merge branch 'main' into feat-blurring
cloudwebrtc Aug 28, 2025
5d24c85
chore: fix imports after merge from main
holzgeist Sep 1, 2025
3a74e8d
Merge remote-tracking branch 'upstream/main' into feat-blurring
holzgeist Sep 17, 2025
526f347
Merge tag 'v2.5.1' into feat-blurring
holzgeist Oct 14, 2025
a2b9154
Merge remote-tracking branch 'upstream/main' into feat-blurring
holzgeist Oct 14, 2025
f297b18
chore: reformat files
holzgeist Oct 14, 2025
5b6bf43
chore: run import sorter
holzgeist Oct 14, 2025
a46e292
Merge tag 'v2.5.2' into feat-blurring
holzgeist Oct 27, 2025
b647017
chore: reformat
holzgeist Oct 27, 2025
0f20487
chore: run import sorter
holzgeist Oct 27, 2025
76bafa4
fix: remove unused import
holzgeist Oct 27, 2025
ad56f16
Merge tag 'v2.5.3' into feat-blurring
holzgeist Nov 11, 2025
53f1c01
Merge branch 'main' into feat-blurring
hiroshihorie Dec 9, 2025
0c04eea
Merge remote-tracking branch 'upstream/main' into feat-blurring
holzgeist Jan 20, 2026
5fbcaad
ci: trigger
holzgeist Jan 22, 2026
7637399
Merge branch 'main' into feat-blurring
holzgeist Feb 2, 2026
2124273
Merge remote-tracking branch 'upstream/main' into feat-blurring
holzgeist Mar 17, 2026
f7b7b32
fix: merge error
holzgeist Mar 17, 2026
200df67
Merge branch 'main' into feat-blurring
holzgeist May 11, 2026
e06dc6a
Use maintain-resolution as the default video degradation preference (…
hiroshihorie Jun 6, 2026
04c164c
chore(android): support AGP 9 built-in Kotlin (#1102)
hiroshihorie Jun 11, 2026
69fbbfb
feat: add deployment field to agent dispatch (#1111)
xianshijing-lk Jun 17, 2026
d11065f
v2.8.1
hiroshihorie Jun 20, 2026
99f640e
Merge tag 'v2.8.1' into feat-blurring
holzgeist Jul 15, 2026
56f4ab9
chore: upgrade deps
holzgeist Jul 15, 2026
87e7ffa
chore: sync dependencies
holzgeist Jul 15, 2026
f9534fb
Merge tag 'v2.11.0' into feat-blurring
holzgeist Aug 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion lib/src/track/local/local.dart
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ abstract class LocalTrack extends Track {
await _processor!.init(processorOptions);

if (_processor?.processedTrack != null) {
setProcessedTrack(processor.processedTrack!);
await setProcessedTrack(processor.processedTrack!);
}

logger.fine('processor initialized');
Expand All @@ -379,6 +379,8 @@ abstract class LocalTrack extends Track {
// force re-setting of the mediaStreamTrack on the sender
//await this.setMediaStreamTrack(this._mediaStreamTrack, true);

await setProcessedTrack(null);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Stopping a camera with an active effect leaves the track pointing at a dead video source

When a local track is stopped, the newly added restore step (setProcessedTrack(null) at lib/src/track/local/local.dart:382) silently does nothing because the saved original camera source was already discarded moments earlier, so the track keeps referring to the destroyed processed source.
Impact: After stopping a track that had a processor, the track still exposes the dead processed source instead of the real camera source, so anything that inspects or re-uses the track afterwards sees an unusable source.

Why the reset branch never runs during stop()

LocalTrack.stop() (lib/src/track/local/local.dart:217-241) first calls super.stop(), and Track.stop() (lib/src/track/track.dart:139-142) stops _originalTrack and sets it to null while _mediaStreamTrack still holds the processed track. stopProcessor() then calls setProcessedTrack(null), whose reset branch is guarded by else if (_originalTrack != null) (lib/src/track/track.dart:236) — already null — so _mediaStreamTrack is never restored. Only the event at lib/src/track/track.dart:243-246 is emitted.

A fix would be to restore the original track before/inside Track.stop() (e.g. call the processor teardown before clearing _originalTrack), or make stop() reset _mediaStreamTrack = _originalTrack when it clears it.

Prompt for agents
In lib/src/track/track.dart, Track.stop() stops and nulls _originalTrack while _mediaStreamTrack still holds the processor output. The new reset logic added in LocalTrack.stopProcessor() (await setProcessedTrack(null)) is therefore a no-op during stop, leaving _mediaStreamTrack pointing at the destroyed processed track. Consider ordering the processor teardown/restore before Track.stop() clears _originalTrack, or having Track.stop() restore _mediaStreamTrack = _originalTrack when it stops and clears the original.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.


events.emit(TrackProcessorUpdateEvent(track: this));
}

Expand Down
23 changes: 20 additions & 3 deletions lib/src/track/track.dart
Original file line number Diff line number Diff line change
Expand Up @@ -224,8 +224,25 @@ abstract class Track extends DisposableChangeNotifier with EventsEmittable<Track
}

@internal
void setProcessedTrack(rtc.MediaStreamTrack track) {
_originalTrack = _mediaStreamTrack;
_mediaStreamTrack = track;
Future<void> setProcessedTrack(rtc.MediaStreamTrack? track) async {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Release notes entry is missing for a user-visible change

The pull request changes published SDK behaviour and the signature of a track method but adds no changeset file under .changes/, which the repository requires for every PR affecting the published package.
Impact: The release automation check fails and the fix will not show up in the changelog.

Repository rule

AGENTS.md: "Every PR that affects the published package needs a changeset file in .changes/ (format: patch|minor|major type=\"fixed|added|changed|...\" \"description\"); CI checks for it and runs dart-apitool against main to require a major changeset for breaking public-API changes." The .changes/ directory is currently empty, while Track.setProcessedTrack changed from void setProcessedTrack(rtc.MediaStreamTrack track) to Future<void> setProcessedTrack(rtc.MediaStreamTrack? track) — an API signature change.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

if (track != null) {
// set processed track
_originalTrack = _mediaStreamTrack;
_mediaStreamTrack = track;
if (_originalTrack != null) {
await _mediaStream.removeTrack(_originalTrack!);
}
await _mediaStream.addTrack(track);
} else if (_originalTrack != null) {
// reset processed track
await _mediaStream.removeTrack(_mediaStreamTrack);
await _mediaStream.addTrack(_originalTrack!);
_mediaStreamTrack = _originalTrack!;
_originalTrack = null;
}
events.emit(TrackStreamUpdatedEvent(
track: this,
stream: _mediaStream,
));
Comment on lines +243 to +246

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Video widgets are told to re-attach to a media stream that was just destroyed

Stopping a local track that uses a processor announces a stream update (setProcessedTrack(null) at lib/src/track/local/local.dart:382) after the underlying media stream has already been released, so the video widget tries to re-attach to a destroyed stream.
Impact: Video renderers may log platform errors or throw unhandled async errors when a camera with an effect is stopped.

Ordering of dispose and the new event

LocalTrack.stop() disposes the media stream (lib/src/track/local/local.dart:227) and only afterwards calls stopProcessor(), which now ends with setProcessedTrack(null); that method unconditionally emits TrackStreamUpdatedEvent(stream: _mediaStream) (lib/src/track/track.dart:243-246) with the disposed stream. VideoTrackRenderer reacts by assigning _renderer?.srcObject = event.stream (lib/src/widgets/video_track_renderer.dart:219-222).

Emitting only when something actually changed (i.e. inside the two branches of setProcessedTrack), or calling stopProcessor() before disposing the stream, avoids this.

Prompt for agents
setProcessedTrack in lib/src/track/track.dart always emits TrackStreamUpdatedEvent, even when neither branch changed anything (e.g. reset requested while _originalTrack is already null). Combined with LocalTrack.stop() disposing mediaStream before calling stopProcessor(), listeners such as VideoTrackRenderer receive an event carrying an already-disposed stream and re-assign it as srcObject. Consider emitting the event only when the track/stream actually changed, and/or calling stopProcessor() before disposing the media stream in LocalTrack.stop().
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

}
}
Loading