Repository navigation
feat: add first-packet observers, sender and receiver IDs, and track volume - #338
Merged
Merged
Conversation
The callbacks WebRTC invokes ended with ExceptionCheck(), which turns a Java exception thrown by the application into a C++ exception. It then unwound through WebRTC's frames, which are built without unwinding support, leaving WebRTC's locks held or ending the process, depending on the platform. The same held for C++ exceptions thrown while converting a callback's arguments. Every such callback now catches its own C++ exceptions, turns them into Java ones, and ends with ReportPendingException(), which clears the pending exception and hands it to the thread's uncaught exception handler: the peer connection, session description, data channel, DTLS, DTMF and stats observers, the audio and video track sinks, the track observer, the audio device's recorded-data sink and the desktop capture callback. The add-ICE-candidate and data channel send observers, which already reported exceptions this way, now share the helper. While in these callbacks: - the audio sinks hold their byte array in a JavaLocalRef, so it is freed when the callback throws, and pass jint values to the Java callback instead of size_t through varargs; - the track observer no longer leaks a local reference per event; - CustomVideoSource.pushFrame catches conversion errors instead of letting a C++ exception leave the JNI call.
…volume - RTCRtpReceiver.setObserver(RTCRtpReceiverObserver) reports the first RTP packet a receiver receives, and RTCRtpSender.setObserver( RTCRtpSenderObserver) the first one a sender sends. An observer set after that is called right away. It belongs to the Java object it was set through, which removes it from WebRTC before freeing it, when it is replaced, set to null or disposed. - RTCRtpReceiver.getId(), RTCRtpSender.getId() and RTCRtpSender.getStreams(), the counterpart of setStreams. - AudioTrack.setVolume(double) sets the playout volume of a remote track, from 0 to 10, rejecting values outside that range, which WebRTC only checks in debug builds. A local track ignores it. The observers report a Java exception to the thread's uncaught exception handler, like the other callbacks WebRTC invokes.
devopvoid
force-pushed
the
feat/rtp-sender-receiver-extras
branch
from
October 9, 2026 23:04
0a44d4b to
9caf8aa
Compare
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #335: the new observers end with its
ReportPendingExceptionhelper. The base becomesmainonce #335 is merged.More of the Android SDK's
RtpReceiver,RtpSenderandAudioTrackAPI.First-packet observers
RTCRtpReceiver.setObserver(RTCRtpReceiverObserver):onFirstPacketReceived(MediaType)when the receiver gets its first RTP packet, for example to show a remote video only once there is something to show.RTCRtpSender.setObserver(RTCRtpSenderObserver):onFirstPacketSent(MediaType)for the first packet a sender sends.An observer set after the packet already went through is called right away, before
setObserverreturns, as WebRTC does.nullremoves it. Both run on the signaling thread, and an exception they throw goes to the thread's uncaught exception handler.Lifetime: WebRTC requires an observer to be removed before it is destroyed. The native observer is held by the Java object it was set through (an
observerHandlefield, asRTCDataChanneldoes) and freed when it is replaced, set tonullor that object is disposed, each time afterSetObserverhas handed it back. That call runs on the signaling thread, the thread that calls the observer, so no call is in progress once it returns. A receiver has one observer, so setting one through a second Java object of the same receiver replaces it, and disposing the first object then removes it; the javadoc says to set it through one object, such as the oneonTrackprovides.IDs and streams
RTCRtpReceiver.getId()andRTCRtpSender.getId().RTCRtpSender.getStreams(), the counterpart ofsetStreams(). A track added without streams has none, as Unified Plan does.Remote track volume
AudioTrack.setVolume(double)sets the playout volume of a remote track, from 0 (silent) to 10, where 1 plays it as received. Values outside that range, and NaN, throwIllegalArgumentException: WebRTC only checks the range in debug builds. The gain is applied after the audio is handed to anAudioTrackSink, so sinks are unaffected, and a local track's source ignores it.Docs
get-started.mdgains a "Receiving Tracks" section with the receiver observer and the volume.Tests
RTCRtpSenderReceiverTests:firstPacketEvents: in a real call with audio and video, the sender and both receivers report their first packet with the right media type, observers set afterwards are called duringsetObserver, and removing and disposing work.senderIdAndStreams,streamsOfSenderWithoutStreams,receiverId: IDs are the same through every Java object of a sender or receiver; stream IDs followaddTrackandsetStreams.remoteTrackVolume,localTrackIgnoresVolume: valid volumes apply, invalid ones throw.The full
webrtcsuite passes on Windows (259 run, 0 failures, 2 skipped), also under-Pjni-checkwith no JNI errors.