Webrtcbin / WHIP: connection-state and ice-connection-state never change after remote disappears

Hi,

I’m running a GStreamer pipeline that publishes video via WHIP to LiveKit Ingress using whipsink / webrtcbin.
I’m trying to reliably detect when the remote side (Ingress / LiveKit) goes away.

Setup

  • GStreamer (Python GI bindings)

  • whipsink → internal webrtcbin

  • Send-only video (H264 RTP)

  • Docker environment (publisher and ingress on same Docker network)

What I’m observing

  1. I attach notify::connection-state and notify::ice-connection-state on webrtcbin.

    for prop in ("connection-state", "ice-connection-state"):
        if webrtcbin.find_property(prop):
            webrtcbin.connect(f"notify::{prop}", on_notify)
    
    
  2. I correctly see the initial transitions:

    • connection-state = CONNECTED

    • ice-connection-state = COMPLETED

  3. I then stop both LiveKit and Ingress containers completely (WHIP HTTP endpoint + ICE UDP port are gone).

  4. Even after 5+ minutes, I observe:

    • connection-state remains CONNECTED

    • ice-connection-state remains COMPLETED

    • No WARN/ERROR/ELEMENT messages from webrtcbin or nicesink on the bus

    • Outbound RTP counters (OUTBOUND_RTP packetsSent/bytesSent) continue to increase

    • get-stats() does not expose REMOTE_INBOUND_RTP or any bytesReceived fields on this build

  5. The only bus messages I see are periodic TAG messages from GstNiceSink, which appear to be metadata only.

Stats visibility (from get-stats)

The following stat types are present:

  • PEER_CONNECTION

  • OUTBOUND_RTP

  • TRANSPORT

  • CANDIDATE_PAIR

  • local/remote ICE candidates

But no:

  • REMOTE_INBOUND_RTP

  • INBOUND_RTP

  • bytesReceived

  • RTT / jitter / packetsLost

So I currently have no receiver feedback stats to rely on.

Question

Is this expected behaviour?

Specifically:

  1. Is it normal for webrtcbin to remain in CONNECTED / ICE COMPLETED indefinitely if the remote peer disappears and UDP sends still succeed locally?

  2. Is there a recommended signal or mechanism in GStreamer to detect that a WHIP/WebRTC peer is no longer reachable when:

    • no receiver-report stats are exposed, and

    • no bus ERROR/WARNING is emitted?

  3. Should ICE consent / keepalive eventually transition the connection state to DISCONNECTED / FAILED, or can it legitimately remain COMPLETED forever in this scenario?

  4. Is there a way to force or configure stricter liveness detection (timeouts, consent checks, etc.) in webrtcbin?

I’m not trying to restart the whole pipeline on transient issues — I just need a reliable signal that the remote endpoint is gone.

Any guidance on the intended behaviour here (or what signal I should be watching instead) would be much appreciated.

Thanks!

Whether ICE consent works depends on the version of webrtcbin that you are using. In theory any version of 1.26 should produce ICE connection failure after roughly 30 seconds of no consent checks.

As your are using livekit, then using livekitwebrtcsink would also be preferable over whip as that would also include a long running websocket signalling connection that would die when the livekit server is closed. This will be used as a death notification within lvekitwebrtcsink.

Thank you very much, this worked like a charm.