Hi there,
I am building a WebRTC Producer on an M1 Mac using node-datachannel to stream audio to Cloudflare Calls (an SFU). I’ve run into a significant hurdle regarding the SDP handshake.
The Setup:
Local: node-datachannel (v0.11.x) on macOS.
Remote: Cloudflare Calls SFU (ICE-Lite).
Role: Local is Producer (Offer), Cloudflare is Answerer.
The Problem:
Cloudflare Calls is designed for "Trickle ICE" browsers. Its initial SDP Answer is "minimal"—it lacks the a=ice-ufrag and a=ice-pwd attributes in the initial response, as it expects to trade these via ICE candidates later.
When I pass this minimal SDP to pc.setRemoteDescription(sdp, "answer"), the library correctly throws:
Error: libdatachannel error while adding remote description: Remote description has no ICE user fragment.
What I've Tried:
I have attempted to manually "reconstruct" a full SDP Answer in my signaling worker by injecting a dummy ufrag/pwd and the Cloudflare Anycast IP (162.159.195.1). While this satisfies the parser, the ICE state ultimately moves to failed because the credentials don't match the SFU's internal session state.
The Question:
Is there a recommended pattern for using node-datachannel with an SFU that doesn't provide ICE credentials until the "Trickle" phase? Can I manually set the ICE credentials on the PeerConnection after setRemoteDescription, or is there a way to force the library to wait for a "complete" SDP before starting the handshake?
Any advice on bridging the gap between a Non-Trickle client and a Trickle-heavy SFU would be greatly appreciated.
Hi there,
I am building a WebRTC Producer on an M1 Mac using node-datachannel to stream audio to Cloudflare Calls (an SFU). I’ve run into a significant hurdle regarding the SDP handshake.
The Setup:
Local: node-datachannel (v0.11.x) on macOS.
Remote: Cloudflare Calls SFU (ICE-Lite).
Role: Local is Producer (Offer), Cloudflare is Answerer.
The Problem:
Cloudflare Calls is designed for "Trickle ICE" browsers. Its initial SDP Answer is "minimal"—it lacks the a=ice-ufrag and a=ice-pwd attributes in the initial response, as it expects to trade these via ICE candidates later.
When I pass this minimal SDP to pc.setRemoteDescription(sdp, "answer"), the library correctly throws:
Error: libdatachannel error while adding remote description: Remote description has no ICE user fragment.
What I've Tried:
I have attempted to manually "reconstruct" a full SDP Answer in my signaling worker by injecting a dummy ufrag/pwd and the Cloudflare Anycast IP (162.159.195.1). While this satisfies the parser, the ICE state ultimately moves to failed because the credentials don't match the SFU's internal session state.
The Question:
Is there a recommended pattern for using node-datachannel with an SFU that doesn't provide ICE credentials until the "Trickle" phase? Can I manually set the ICE credentials on the PeerConnection after setRemoteDescription, or is there a way to force the library to wait for a "complete" SDP before starting the handshake?
Any advice on bridging the gap between a Non-Trickle client and a Trickle-heavy SFU would be greatly appreciated.