Running webrtc in a docker container: candidate IP issue

When running webrtc streamer inside a docker container, it reports candidate IPs as local docker IPs to the signalling server, therefore client fails to connect. Is there any option to forcefully define e.g. “EXTERNAL_IP” reported to signalling server?
Note: using --network=host is not an option for my case as there are other conflicts in my stack.

1 Like

With recent GStreamer, you can get the ice-agent on webrtcbin and use the add-local-ip-address signal on it to provide your external IP address.

And be sure to do it before setting the local description, as this is the point where the list of local candidates is “frozen” in libnice.

1 Like

So no way to do the same from gst-launch right? Would it be a useful to add this as a parameter of webrtcbin?

Not possible from gst-launch, no.

I’m not really going to entertain the idea of adding ICE-specific properties that are not specified in JSEP on the webrtcbin object.

Could you help to extract webrtcbin from the pipeline which uses webrtcsink? Basically something like:

wrs = Gst.ElementFactory.make("webrtcsink", "wrs")
wrb = wrs.get_property("webrtcbin")

doesn’t work.
Or it’s also not possible and I need to build the whole pipeline from scratch without webrtcsink if I need to set a custom external IP?

Connect to the consumer-added signal on webrtcsink. See also net/webrtc/src/webrtcsink/imp.rs · main · GStreamer / gst-plugins-rs · GitLab

You can also connect to the consumer-added signal on the signaller which will also give you the same information.

Tried this:

def consumer_added_callback(wrs, session_id, udata):
    print('Consumer {} added'.format(udata))
    iceagent = udata.get_property("ice-agent")
    print(iceagent)
    iceagent.emit('add-local-ip-address', '192.168.1.66')

And it gives:

Consumer <__gi__.GstWebRTCBin object at 0x7f2ee74fcd00 (GstWebRTCBin at 0x7f2ed8068120)> added
<__gi__.GstWebRTCNice object at 0x7f2ee74c30c0 (GstWebRTCNice at 0x7f2ed8074110)>

(runme.py:3748198): GStreamer-WebRTC-CRITICAL **: 08:24:09.901: gst_webrtc_ice_add_stream: assertion 'GST_IS_WEBRTC_ICE (ice)' failed

(runme.py:3748198): GStreamer-WebRTC-CRITICAL **: 08:24:09.901: gst_webrtc_ice_find_transport: assertion 'GST_IS_WEBRTC_ICE (ice)' failed

(runme.py:3748198): GStreamer-WebRTC-CRITICAL **: 08:24:09.901: gst_webrtc_dtls_transport_set_transport: assertion 'GST_IS_WEBRTC_ICE_TRANSPORT (ice)' failed

(runme.py:3748198): GStreamer-CRITICAL **: 08:24:09.901: gst_object_unref: assertion 'object != NULL' failed
Segmentation fault

Critical errors are coming after this particular line of code:

iceagent = udata.get_property("ice-agent")

As far as I understood, ice-agent is not yet initialized when consumer_added_callback is triggered…

Ok, the latter most probably is a Pythons’ binder issue: Certain referenced objects are being destroyed within a callback (#605) · Issues · GNOME / pygobject · GitLab

@arun, @ocrete, the add-local-ip-address method doesn’t work as libnice tries to create a socket using this IP and fails (which is expected as external IPs are not available inside a docker container). E.g. if user passes 192.168.1.113, then:

libnice-DEBUG: 01:07:31.411: Agent 0x7f7e50093170: s1/c1: creation of host candidate udp:[192.168.1.113]:50003: can't create socket
libnice-DEBUG: 01:07:31.411: Interface:  lo
libnice-DEBUG: 01:07:31.411: IP Address: 127.0.0.1
libnice-DEBUG: 01:07:31.411: Interface:  eth0
libnice-DEBUG: 01:07:31.411: IP Address: 172.17.0.6
libnice-DEBUG: 01:07:31.411: Agent 0x7f7e50093170: s1/c1: creation of host candidate udp:[192.168.1.113]:50004: can't create socket
libnice-DEBUG: 01:07:31.411: Interface:  lo
libnice-DEBUG: 01:07:31.411: IP Address: 127.0.0.1
libnice-DEBUG: 01:07:31.411: Interface:  eth0
libnice-DEBUG: 01:07:31.411: IP Address: 172.17.0.6
libnice-DEBUG: 01:07:31.411: Agent 0x7f7e50093170: s1/c1: creation of host candidate udp:[192.168.1.113]:50005: can't create socket
libnice-DEBUG: 01:07:31.411: Interface:  lo
libnice-DEBUG: 01:07:31.411: IP Address: 127.0.0.1
libnice-DEBUG: 01:07:31.411: Interface:  eth0
libnice-DEBUG: 01:07:31.411: IP Address: 172.17.0.6

From one side, it’s expected, from another - this could be a bug and libnice should be tweaked to always create socket on 0.0.0.0 in case add-local-ip-address was used?

It’s on purpose, those APIs are meant to allow the application developer to select the local interface on which to create the socket.

The general solution is to use a stun server, as this can quickly get complicated, for example if you have your Docker inside a cloud server which itself has another set of private IP addresses.

Also, if you use some kind of address translation, it may also change the ports…

Seems I’m looking for a non-existing “add-external-ip-address” interface then. I believe that having such an option in layered environments, as you’ve described, would prove to be highly beneficial.

Stun servers present a challenge due to the need to manage distinct stun server configurations at various layers, depending on where the server and client are deployed. This entails maintaining separate configurations when operating the server and client on localhost, within a local network, or beyond the LAN. It would be far more convenient to streamline this process by simply passing an external IP address as a configuration parameter.

Additionally, I have observed that responses from a coturn/coturn server operating in a stun-only mode may not be correctly identified by libnice. It’s possible that certain properties in the coturn configuration need to be adjusted to address this issue…

See also: Running libnice in a containerized environment (#182) · Issues · libnice / libnice · GitLab

Passing the external IP address is not really useful, you’d also need to be able to do the port mapping correctly…

You’re correct, seems the only valid way to run webrtc server inside a docker container is with a --network=host parameter.