node-webrtc / node-webrtc-examples

MediaStream and RTCDataChannel examples using node-webrtc
514 stars 161 forks source link

remote video blank inside of docker container / elastic beanstalk #2

Open imgntn opened 5 years ago

imgntn commented 5 years ago

if i try to expose port 3000 and run the examples inside of a docker container (on my localhost for now), the remote video of all examples is always blank. any advice?

imgntn commented 5 years ago

same result running the examples on elastic beanstalk. i'm guessing there are a range of ports that need to be exposed for webRTC to work... how do I find out what they are? Thanks!! :)

imgntn commented 5 years ago

related? https://github.com/node-webrtc/node-webrtc/issues/416

xtapac commented 5 years ago

@imgntn I found that for correct remote execution it is necessary to set ICE server in the webrtcconnection.js:

const peerConnection = new RTCPeerConnection({ sdpSemantics: 'unified-plan', iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] });

tzvc commented 4 years ago

Any update on this? I'm trying to run the video-composing example in a Docker container but only HTTP calls are let through, do we need to have a special port configuration for WEBRTC to work here?

tzvc commented 4 years ago

@xtapac What I don't get here is that the example doesn't provide a way for the peers (here, client and server) to exchange ICE candidates. Did you have to implement it yourself as an endpoint or something?

markandrus commented 4 years ago

@theochampion the way the signaling between client and server works assumes that the server discovers host candidates that the client can reach. Take a look at lib/server/connections/webrtcconnection.js: the server waits until ICE gathering is complete (and therefore the server’s localDescription contains all gathered host candidates) before returning its offer to the client. The client never exchanges ICE candidate strings with the server. Instead, assuming the client can indeed reach one or more of the server’s host candidates, the server will discover the client’s peer-reflexive candidates.

Regarding Docker, it could be that the host candidates advertised by the server are not reachable by the client (maybe they reference some IP only known within the Docker container). This could be verified by looking at the SDP generated by the server. If this is the case, the ICE server fix described above is a workaround. It might also be fine to just rewrite the IP addresses in the host candidates to the Docker container’s IP(s).

tzvc commented 4 years ago

@markandrus Thanks for the reply. So If I understand well, the server generate a list of candidates for the client to try and just "wait" for the data to arrive from the WebRTCConnection ?

Here is the list of candidates sent from my server in the SDP offer

c=IN IP4 35.181.61.8
a=rtcp:9 IN IP4 0.0.0.0
a=candidate:211781638 1 udp 2122260223 172.31.26.2 45893 typ host generation 0 network-id 1
a=candidate:2780825555 1 udp 1686052607 35.181.61.8 45893 typ srflx raddr 172.31.26.2 rport 45893 generation 0 network-id 1
a=candidate:1109161206 1 tcp 1518280447 172.31.26.2 44409 typ host tcptype passive generation 0 network-id 1

Here 35.181.61.8 is the public IP of my server (accessible from the client) and 172.31.26.2 is the private IP. From what I see here, this candidate:

a=candidate:2780825555 1 udp 1686052607 35.181.61.8 45893 typ srflx raddr 172.31.26.2 rport 45893 generation 0 network-id 1

Should allow the client to connect.

But if I inspect the webrtcconnection client side using chrome://webrtc-internals/ is appears that only ice condidates of type host are evaluated which is weird because my iceTransportPolicy is set to all.

Screen Shot 2019-12-02 at 7 33 13 pm

Any ideas?

Also, i've noticed this function

function disableTrickleIce(sdp) {
  return sdp.replace(/\r\na=ice-options:trickle/g, '');
}

that modify the SDP, what exactly does that do and should I be using it?

Cheers!

Edit : I found this post that seems to talk about the issue, but I'm no sure I understand https://groups.google.com/forum/#!topic/discuss-webrtc/MhjXHbaexLw

markandrus commented 4 years ago

@theochampion

Thanks for the reply. So If I understand well, the server generate a list of candidates for the client to try and just "wait" for the data to arrive from the WebRTCConnection ?

Yes

a=candidate:2780825555 1 udp 1686052607 35.181.61.8 45893 typ srflx raddr 172.31.26.2 rport 45893 generation 0 network-id 1

I guess you get this srflx candidate because you modified the server code to include ICE servers when configuring the RTCPeerConnection?

But if I inspect the webrtcconnection client side using chrome://webrtc-internals/ is appears that only ice condidates of type host are evaluated which is weird because my iceTransportPolicy is set to all.

The logs are showing "icecandidate" events generated in the browser, i.e., local candidates gathered by the browser. No STUN servers are configured, therefore no srflx candidates are gathered. Only host.

markandrus commented 4 years ago

Here is some information for anyone else trying to use Docker: the type of networking used is important. Notice that, if I use the default bridge network, node-webrtc inside the container is only going to discover its Docker bridge IP (172.17.0.2 in this example):

$ docker run --rm -t foo docker | grep '^candidate:'
candidate:4112619227 1 udp 2122260223 172.17.0.2 55607 typ host generation 0 ufrag 0lwU network-id 1
candidate:1510613869 1 udp 2122194687 127.0.0.1 39220 typ host generation 0 ufrag 0lwU network-id 2
candidate:3147983403 1 tcp 1518280447 172.17.0.2 46177 typ host tcptype passive generation 0 ufrag 0lwU network-id 1
candidate:344579997 1 tcp 1518214911 127.0.0.1 37497 typ host tcptype passive generation 0 ufrag 0lwU network-id 2

However, if I specify the host network, node-webrtc inside the container is going to discover the host's IP (in this case, my laptop—192.168.65.3—however, this could be an EC2 instance, or some other hosted service):

$ docker run --rm --network host -t foo docker | grep '^candidate:'
candidate:2948193667 1 udp 2122260223 192.168.65.3 60905 typ host generation 0 ufrag 20/8 network-id 1
candidate:559267639 1 udp 2122202367 ::1 41123 typ host generation 0 ufrag 20/8 network-id 3
candidate:1510613869 1 udp 2122129151 127.0.0.1 33104 typ host generation 0 ufrag 20/8 network-id 2
candidate:3778683251 1 tcp 1518280447 192.168.65.3 46337 typ host tcptype passive generation 0 ufrag 20/8 network-id 1
candidate:1876313031 1 tcp 1518222591 ::1 55243 typ host tcptype passive generation 0 ufrag 20/8 network-id 3
candidate:344579997 1 tcp 1518149375 127.0.0.1 45843 typ host tcptype passive generation 0 ufrag 20/8 network-id 2

Dockerfile, for reference:

# docker/Dockerfile
FROM node:14-alpine AS base
RUN apk update && apk add --no-cache alsa-lib
RUN ln -s /lib/libc.musl-x86_64.so.1 /lib/ld-linux-x86-64.so.2
RUN DEBUG=true npm install wrtc
ENTRYPOINT ["node", "-e", "var pc = new (require('wrtc').RTCPeerConnection); pc.addTransceiver('audio'); pc.createOffer().then(offer => pc.setLocalDescription(offer)); pc.onicecandidate = event => { if (event.candidate) { console.log(event.candidate.candidate) } else { process.exit() } }"]
regnaio commented 3 years ago

same result running the examples on elastic beanstalk. i'm guessing there are a range of ports that need to be exposed for webRTC to work... how do I find out what they are? Thanks!! :)

Just ran into this issue too, and I think imgntn's explanation is why the webrtc UDP connection is failing in Docker

regnaio commented 1 year ago

Here is some information for anyone else trying to use Docker: the type of networking used is important. Notice that, if I use the default bridge network, node-webrtc inside the container is only going to discover its Docker bridge IP (172.17.0.2 in this example):

$ docker run --rm -t foo docker | grep '^candidate:'
candidate:4112619227 1 udp 2122260223 172.17.0.2 55607 typ host generation 0 ufrag 0lwU network-id 1
candidate:1510613869 1 udp 2122194687 127.0.0.1 39220 typ host generation 0 ufrag 0lwU network-id 2
candidate:3147983403 1 tcp 1518280447 172.17.0.2 46177 typ host tcptype passive generation 0 ufrag 0lwU network-id 1
candidate:344579997 1 tcp 1518214911 127.0.0.1 37497 typ host tcptype passive generation 0 ufrag 0lwU network-id 2

However, if I specify the host network, node-webrtc inside the container is going to discover the host's IP (in this case, my laptop—192.168.65.3—however, this could be an EC2 instance, or some other hosted service):

$ docker run --rm --network host -t foo docker | grep '^candidate:'
candidate:2948193667 1 udp 2122260223 192.168.65.3 60905 typ host generation 0 ufrag 20/8 network-id 1
candidate:559267639 1 udp 2122202367 ::1 41123 typ host generation 0 ufrag 20/8 network-id 3
candidate:1510613869 1 udp 2122129151 127.0.0.1 33104 typ host generation 0 ufrag 20/8 network-id 2
candidate:3778683251 1 tcp 1518280447 192.168.65.3 46337 typ host tcptype passive generation 0 ufrag 20/8 network-id 1
candidate:1876313031 1 tcp 1518222591 ::1 55243 typ host tcptype passive generation 0 ufrag 20/8 network-id 3
candidate:344579997 1 tcp 1518149375 127.0.0.1 45843 typ host tcptype passive generation 0 ufrag 20/8 network-id 2

Dockerfile, for reference:

# docker/Dockerfile
FROM node:14-alpine AS base
RUN apk update && apk add --no-cache alsa-lib
RUN ln -s /lib/libc.musl-x86_64.so.1 /lib/ld-linux-x86-64.so.2
RUN DEBUG=true npm install wrtc
ENTRYPOINT ["node", "-e", "var pc = new (require('wrtc').RTCPeerConnection); pc.addTransceiver('audio'); pc.createOffer().then(offer => pc.setLocalDescription(offer)); pc.onicecandidate = event => { if (event.candidate) { console.log(event.candidate.candidate) } else { process.exit() } }"]

Great info, thanks markandrus!

This may explain why WebRTC in Docker Windows hasn't been working for a while