WebRtc SDK nodeJS

Hello,

I'm working on a project where we've implemented the SDK. They work well except for one thing: when I try to watch live video via WEBRTC, it doesn't work, whereas when I use the Ziti Tunnelers, it works. The strategy used is the same, and the configuration is also the same. How can I fix this problem?

Thanks in advance

can you provide more details, please:

  • WebRTC service setup
  • on what side are you using nodeJS-SDK?
  • sample code would be helpful

Thanks

Thanks for the quick reply! Details below.

On which side is the nodeJS SDK used?

Client/consumer side. The viewer is an Electron desktop app. We run

@openziti/ziti-sdk-nodejs v0.29.1 in a forked Node worker (the system Node,

not the Chromium/renderer process). The media server (MediaMTX) is on the

remote device and is reached as a Ziti service <id>.pix. The SDK is NOT used

on the camera/server side.

WebRTC service setup

  • Media server: MediaMTX, exposing WHEP at

    http://<id>.pix:8889/<camera>_<quality>/whep.

  • That host:port is an OpenZiti service; all \.pix HTTP requests are routed

    through the SDK.

  • The player runs in the Chromium renderer: a standard WHEP client with an

    RTCPeerConnection, recvonly audio+video transceivers, iceServers: []

    (host candidates only, LAN). It POSTs the SDP offer

    (Content-Type: application/sdp) and applies the SDP answer.

  • We use the SDK ONLY to proxy the WHEP HTTP signaling (POST offer /

    DELETE session), via ziti.httpAgent(baseUrl) + Node http.request.

What works / what doesn't

  • Signaling works: the SDP offer POST goes through Ziti and MediaMTX returns

    201 + a valid SDP answer.

  • Media never flows: the PeerConnection never reaches connected, ICE fails.

Our current understanding (please confirm or correct)

The SDK proxies the HTTP signaling fine, but the WebRTC media plane (ICE

connectivity checks + SRTP, over UDP) is handled by Chromium's

RTCPeerConnection, which has no knowledge of Ziti. The SDP answer's ICE

candidates are the server's LAN host candidates (e.g. 10.x.x.x), which are

unreachable remotely, and that media UDP does not traverse the SDK (we only

wrapped the HTTP agent). With the Ziti Tunneler the exact same setup

works, because the Tunneler intercepts at the OS/IP layer and tunnels the

media UDP as well.

Question

Is there a recommended way to carry the WebRTC media plane through the nodeJS

SDK (e.g. MediaMTX webrtcLocalTCPAddress single-port TCP + a local relay

that dials the Ziti service), or is the nodeJS SDK intended for signaling

only, with the media expected to rely on a tunneler / a separate transport? A

minimal working pattern for WebRTC/WHEP over the nodeJS SDK would help a lot.

async function startLive(streamBase, stream, video) {
const pc = new RTCPeerConnection({ iceServers: 
 });
pc.addTransceiver('video', { direction: 'recvonly' });
pc.addTransceiver('audio', { direction: 'recvonly' });

pc.ontrack = (e) => {
if (e.receiver && 'playoutDelayHint' in e.receiver) e.receiver.playoutDelayHint = 0.25;
video.srcObject = e.streams[0];
video.play().catch(() => {});
};

const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
await waitIceGathering(pc, 500);

const whepUrl = ${streamBase}_${stream}/whep;

const res = await window.zitiAPI.mediaSignal(whepUrl, {
method:  'POST',
headers: { 'Content-Type': 'application/sdp' },
body:    pc.localDescription.sdp,
});
}

function waitIceGathering(pc, timeoutMs) {
return new Promise((resolve) => {
if (pc.iceGatheringState === 'complete') return resolve();
const check = () => { if (pc.iceGatheringState === 'complete') { cleanup(); resolve(); } };
const cleanup = () => pc.removeEventListener('icegatheringstatechange', check);
pc.addEventListener('icegatheringstatechange', check);
setTimeout(() => { cleanup(); resolve(); }, timeoutMs);
});
}

[post edited/cleaned by clint]

Hello,

Do you have any news for me?

Thanks in advance.

It seems that way to do it would be something like this:

  • define a UDP service for UDP traffic
  • open a local UDP listener that bridges connection to the above service
  • rewrite the signaling response replacing advertised host:port with local listener

with this setup Chromium would do discovery and connect media plane to the local UDP listener that proxied via overlay to the backend