Get build/tests working for M114#49
Get build/tests working for M114#49kevindhanna wants to merge 14 commits intoWonderInventions:developfrom
Conversation
2b04f68 to
7d785f2
Compare
…tion Since M111 (commit e04c3970994b), RtpSenderBase::set_stream_ids() deduplicates stream IDs before they reach SDP serialization. This aligns with the W3C WebRTC spec: "For each stream in streams, add stream.id to [[AssociatedMediaStreamIds]] if it's not already there." The test creates stream2 and stream3 with the same id "testStreamId", so M114 correctly deduplicates: 2 unique stream IDs × 2 tracks = 4 msid lines, not 6. See: https://webrtc-review.googlesource.com/c/src/+/288701 See: webrtc bug 14769
duvallj
left a comment
There was a problem hiding this comment.
Thanks for the PR!! I too have been using Claude Code, and you seem to have used it responsibly since the code changes are overall of good quality. I do have some feedback I'd like to be addressed before this can be merged however:
406136f to
ab7942a
Compare
|
Running I think this has something to do with the new thread changes? |
|
It seems it's a debug build assertion, yeah, looks like SctpTransport needs to be updated now it's owned by the network thread https://github.com/kevindhanna/node-webrtc/blob/develop/src/interfaces/rtc_sctp_transport.cc#L42 we can see the debug assertion: I'll update it |
a8da607 to
b8d56c8
Compare
Dispatch close events proactively during RTCPeerConnection.close(), before calling the underlying PeerConnection::Close(). This matters because PeerConnection::Close() calls PrepareForShutdown() (data_channel_controller.cc:173) which deactivates the SafeTask safety flag, silently cancelling any pending OnStateChange callbacks from the network thread. By dispatching close events first, they reach JS regardless of the C++ shutdown sequence.
The macOS 26 (Tahoe) SDK removed the CG_AVAILABLE_BUT_DEPRECATED macro from CoreGraphics. This macro was used in M114's modules/desktop_capture/mac/screen_capturer_mac.mm to provide correct deprecation annotations for CGDisplayStream wrapper functions (a workaround for incorrect annotations in the 13.3 SDK, see https://crbug.com/1431897). The patch adds a fallback #define that maps CG_AVAILABLE_BUT_DEPRECATED to API_DEPRECATED when the macro is not provided by the SDK, preserving the deprecation annotations on older SDKs while allowing compilation on macOS 26+. This only affects macOS builds — the file is not compiled on Linux or Windows. Also adds a general-purpose patch script (scripts/patch-webrtc.sh) and PATCH_COMMAND to the libwebrtc ExternalProject in CMakeLists.txt, so patches are applied automatically and idempotently during the build.
…le-peer Replace the simple-peer dependency with direct RTCPeerConnection usage. simple-peer is unmaintained (last release 2021) and was only used in these two test files.
…based The timing approach was flakey due to event loop timing jitter.
BuiltinVideoEncoderFactory::CreateVideoEncoder() constructs a SimulcastEncoderAdapter (builtin_video_encoder_factory.cc:45), but librtc_simulcast_encoder_adapter.a was never linked into the final binary. The constructor symbol resolved to 0x0, causing a segfault on the EncoderQueue when sending video frames through a negotiated peer connection. Found via `nm -g wrtc.node | grep "U "` which showed a single undefined webrtc symbol: SimulcastEncoderAdapterC1.
…loss In M114, SctpDataChannel uses an ObserverAdapter that relays callbacks through the signaling thread via SafeTask. When RegisterObserver was called twice (first from DataChannelObserver's constructor, then from RTCDataChannel's constructor), the adapter's SetDelegate call could race with in-flight message delivery tasks on the signaling thread, causing messages sent immediately after dc.onopen to be silently lost. The fix removes the initial RegisterObserver from DataChannelObserver, so registration only happens once in RTCDataChannel's constructor. The SCTP layer queues any messages that arrive before an observer is registered, and DeliverQueuedReceivedData() delivers them when RegisterObserver is called. Also dispatches the "open" state change event if the channel has already transitioned to kOpen before the RTCDataChannel wrapper is constructed, ensuring JS onopen handlers fire.
Previously, the same thread was passed for both network_thread and worker_thread to CreatePeerConnectionFactory. In M114, many operations moved to the network thread, and PeerConnection::Close() does sequential BlockingCalls to network then worker threads (pc/peer_connection.cc:1909-1929). Sharing a single thread caused cleanup contention that limited sequential connection throughput. This matches Chrome's architecture (pc/connection_context.cc:85-98) where network, worker, and signaling threads are all separate. The network thread gets a socket server for ICE port management, matching the CreateWithSocketServer() pattern Chrome uses.
CMakeLists.txt previously required a nix.gni file (generated by the Nix shell hook) containing platform-specific GN args. Builds outside Nix failed with "file STRINGS file nix.gni cannot be read". Now falls back to sensible defaults (is_clang=true, use_lld=false, clang_use_chrome_plugins=false) when the file doesn't exist. Also add a default UknownError path for ErrorFactory::DOMExceptionNameToString
WebRTC's SctpTransport is constructed on the network thread and asserts owner_thread_->IsCurrent() on most methods (see the RTC_DCHECK_RUN_ON in the WebRTC source at pc/sctp_transport.cc lines 59, 66, 105). The node-webrtc code was dispatching to WorkerThread instead, which is the wrong thread. Expose NetworkThread so callers can dispatch correctly.
WebRTC's SctpTransport, DtlsTransport, and IceTransport are all constructed on the network thread and assert owner_thread_->IsCurrent() (or creator_thread_->IsCurrent()) on methods like dtls_transport(), RegisterObserver(), UnregisterObserver(), and internal(). See the RTC_DCHECK_RUN_ON assertions in the WebRTC source: - pc/sctp_transport.cc lines 59, 66, 105 - pc/dtls_transport.cc lines 55, 61 - pc/ice_transport.cc line 27 The node-webrtc code was dispatching these calls to WorkerThread, which is the wrong thread and causes a crash in debug builds: Fatal error in: pc/sctp_transport.cc, line 105 Check failed: (owner_thread_)->IsCurrent() Additionally, PeerConnection::GetSctpTransport() requires the network thread (pc/peer_connection.cc line 1817). Change all call sites to use NetworkThread(). For Stop() methods that may be called from network-thread callbacks (e.g. OnStateChange), use IsCurrent() to avoid a redundant BlockingCall.
Move libwebrtc after the video codec factory libraries so the GNU linker sees their unresolved symbols before processing libwebrtc. Fixes undefined symbol _ZN6webrtc18SupportedVP9CodecsEb on Linux (macOS is unaffected due to its two-pass linker).
These are needed inside the Nix FHS environment for depot_tools bootstrapping (curl) and CMake ExternalProject downloads (git).
|
@duvallj do you ever experience the tests hanging after completion when running the debug build? I've tried on Linux and Mac and all pass, but 9 out of 10 times the process doesn't exit cleanly afterward. I tried checking out v0.10.0 (e1189c plus the Linux compatibility changes above) and running the debug build and it exited cleanly. I added the DataChannel close changes and peer connection factory network thread changes and it still exited fine, so I'm not sure what's causing it. Node doesn't seem to have any open handles... Release builds work a-ok |
In debug builds, a Node.js-internal referenced async handle keeps the event loop alive after all tests complete. This is not caused by the native addon — all addon handles are verified stopped via per-object create/stop tracking. This does not occur in release builds. Use tape's onFinish callback to exit with the appropriate code.
Hi there 👋
I got the build and I think all the required changes for M114 working, and got the test suite to run reliably
FYI Claude Code was used when making these changes, hopefully that's ok (though I see from your develop commits maybe you're using it as well)
Threading & lifecycle
PeerConnection::Close()does sequentialBlockingCalls to nework then worker. Sharing the thread caused contention, so changed to match Chrome's architecturePeerConnection::Close()callsPrepareForShutdown()which deactivates theSafeTasksafety flag, silently droppingOnStateChangecallbacks. Close events are now dispatched before the `Close()SctpDataChanneluses anObserverAdapterthat relays callbacks viaSafeTask. There was a race betweenRegisterObservercalls (DataChannelObserverandRTCDataChannel) that resulted in messages being silently dropped when sent ondc.onopenBuild
SimulcastEncoderAdapter: library was never linked, causing a segfaultGC_AVAILABLE_BUT_DEPRECATEDhas een removed since 26 Tahoe, so we patch a fallbacknix.gnifallback: use some default values when outside nixTests
simple-peerdependency: It's unmaintained for 4 years