Skip to content

fix: dispose a MediaStream from onAddTrack as a view, and return its ID - #343

Merged
devopvoid merged 1 commit into
mainfrom
fix/mediastream-ownership
Oct 10, 2026
Merged

devopvoid merged 1 commit into
mainfrom
fix/mediastream-ownership

Conversation

@devopvoid

Copy link
Copy Markdown
Owner

The MediaStream counterpart of the track views in #341, plus a second bug its test turned up.

Disposing a stream from onAddTrack released the peer connection's reference

PeerConnectionObserver::OnAddTrack wrapped the remote streams without taking a reference, while MediaStream.dispose() released one. Disposing a stream handed to onAddTrack took the peer connection's reference instead; when the track was later removed, the receiver dropped the stream and freed it while the peer connection still held it, and the process crashed.

onAddTrack is the only place Java MediaStreams come from, so every one is a view, and dispose() now only detaches the Java object. It deliberately takes no reference of its own: the examples (and likely most code) never dispose these streams, so a reference per view would keep every remote stream and its tracks alive. The Javadoc of MediaStream.dispose() and of onAddTrack's mediaStreams says so.

MediaStream.id() always returned null

It returned a local reference that its JavaLocalRef had already deleted. It now hands the reference over with release(). It was the only JNI return in the codebase missing that.

Testing

Windows x64: mvn -pl webrtc-jni,webrtc verify -Pjni-check builds, and the webrtc suite passes (266 tests, 0 failures, 2 skipped) with no fatal JNI errors.

MediaStreamViewTests negotiates two local peer connections, disposes the streams in onAddTrack, renegotiates, and removes the track. With the Release() put back into dispose(), removing the track crashed the JVM in three runs out of three; before the id() fix the stream ID came back as null.

PeerConnectionObserver::OnAddTrack wrapped the remote streams without taking
a reference, while MediaStream.dispose() released one. Disposing a stream
handed to onAddTrack took the peer connection's reference instead. When the
track was later removed, the receiver dropped the stream and freed it while
the peer connection still held it, and the process crashed.

onAddTrack is the only place Java MediaStreams come from, so every one is a
view: dispose() now only detaches the Java object. It does not take a
reference of its own, as nothing disposes these streams today, and a
reference per view would keep every remote stream and its tracks alive.

MediaStream.id() returned a local reference its JavaLocalRef had already
deleted, so it always gave null. It now hands the reference over.

MediaStreamViewTests disposes the streams in onAddTrack, renegotiates, and
removes the track. With the Release() put back into dispose(), removing the
track crashed the JVM in three runs out of three; before the id() fix the
stream ID came back as null.
@devopvoid
devopvoid merged commit 8533b37 into main Oct 10, 2026
22 checks passed
@devopvoid
devopvoid deleted the fix/mediastream-ownership branch October 10, 2026 16:11
SendableMetatype added a commit to EduGeyser/webrtc-java that referenced this pull request Oct 10, 2026
Brings in the work upstream added on October 10: the missing peer
connection signaling and control calls (devopvoid#334), callback exceptions kept
from unwinding through WebRTC (devopvoid#335), first-packet observers, sender and
receiver IDs and track volume (devopvoid#338), video processors for camera and
desktop frames (devopvoid#342), and fixes to audio device changes, camera
hotplug and media stream views (devopvoid#333, devopvoid#337, devopvoid#341, devopvoid#343).

Fork-side adaptations:
- setAudioPlayout and setAudioRecording reach the voice engine, so the
  data channels variant leaves them out, like the other audio natives.
- The new tests that need audio or video carry the media tag.
- The Maven publish action stays deleted.
SendableMetatype added a commit to EduGeyser/webrtc-java that referenced this pull request Oct 10, 2026
Brings in the work upstream added on October 10: the missing peer
connection signaling and control calls (devopvoid#334), callback exceptions kept
from unwinding through WebRTC (devopvoid#335), first-packet observers, sender and
receiver IDs and track volume (devopvoid#338), video processors for camera and
desktop frames (devopvoid#342), and fixes to audio device changes, camera
hotplug and media stream views (devopvoid#333, devopvoid#337, devopvoid#341, devopvoid#343).

Fork-side adaptations:
- setBitrate, setAudioPlayout and setAudioRecording reach the call and
  the voice engine, which a factory without a media engine does not
  create, so the data channels variant leaves them out, like the other
  media natives.
- The new tests that need audio or video carry the media tag.
- The Maven publish action stays deleted.
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.

1 participant