Repository navigation
fix: keep exceptions inside the audio device change callbacks - #333
Merged
Merged
Conversation
CoreAudioDeviceManager::deviceListenerProc and the IMMNotificationClient callbacks of WindowsAudioDeviceManager run on threads the operating system owns, and call code that throws jni::Exception when a device's properties cannot be read. A device that disappears between the device list and that read is an ordinary event, and the exception had no handler above it: std::terminate, and the JVM process aborted. The callbacks now log what was thrown and return normally. Fixes devopvoid#332
Yml-0
force-pushed
the
fix/device-listener-exceptions
branch
from
October 8, 2026 12:06
6bc2840 to
7755766
Compare
devopvoid
added a commit
that referenced
this pull request
Oct 9, 2026
…ate (#337) Follow-ups to #333, which made the audio device change callbacks catch what a refresh throws. - One audio device that cannot be read no longer ends the refresh. On macOS it cut onDevicesChanged() short, so new devices were not added and removed ones stayed listed with no event; createAudioDevice() now skips it. checkDeviceGone() compares with the default the manager holds instead of re-reading a device that has gone. On Windows, a device whose transport or form factor cannot be read keeps the unknown ones. The default device getters return null when there is no such device, on both platforms. - DeviceChangeListener never throws, and describes and clears what a Java listener throws instead of leaving it pending on the OS thread. - The device listener list is locked, and listeners are called on a copy outside the lock. - JavaContext::removeNativeRef() freed a global reference twice on every listener removal, and its registry had no lock. - Track listeners are found by their track and kind, not by the listener object alone, so one listener on two tracks, or one object as both kinds, no longer has the wrong registration removed (and its observer freed while still in use). A disposed track takes its remaining listeners off first. AudioTrackTests covers listener removal alone and from eight threads, a listener on two tracks, one of both kinds, and disposing a track with listeners.
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.
Fixes #332.
What
CoreAudioDeviceManager::deviceListenerProc(macOS) andOnDeviceAdded/OnDeviceRemoved/OnDeviceStateChangedofWindowsAudioDeviceManager(Windows) now catch whatever the refresh throws, log it, and return normally.Why
These callbacks run on threads the operating system owns — a CoreAudio HAL queue, the MMDevice notification thread. They call
createAudioDevice(), which throwsjni::Exceptionwhen a device's properties cannot be read, and a device that disappears between the device list and that read is an ordinary event (a Bluetooth headset switching profile, an aggregate device torn down, a device unplugged). The exception had no handler above it, so the process aborted. The crash report and the call chain are in #332.Scope
OnDefaultDeviceChangedon Windows is left alone: it only looks devices up in the lists already held.createAudioDevice()returningnullptrfor an unreadable device so the rest of the same refresh still happens — is easy to add if you prefer it. The catch at the boundary is needed either way, since the listeners also call into Java.Testing
Not built: I do not have the WebRTC checkout the JNI build needs, so this has only been read, not compiled. The macOS path is the one I have a crash report for; the Windows half is from reading the source.
🤖 Generated with Claude Code