Comments (3)
:-D This is one of those tricky parts in ICE and TURN that just magically works out of the box, without us having to configure or add anything. I was also puzzled when I first discovered this...:-)
Here is the process flow:
- the client obtains a TURN allocation from
stunner_a
, suppose that the transport relay address (the UDP connection opened by STUNner inside the Kubernetes private pod-pod network that will it will use to forward the TURN payload received from the client) isIP_a:port_a
, whereIP_a
is the IP of thestunner_a
pod; - the client generates an ICE candidate of type
relay
with the relay addressIP_a:port_a
and sends it along to the media server via the signaling connection; - the media server opens a TURN allocation on
stunner_b
, suppose that the transport relay address isIP_b:port_b
, whereIP_b
is now the IP of thestunner_b
pod; - the media server sends the ICE relay candidate, including the relay address
IP_b:port_b
in it, to the client via the signaling connection; - the client starts ICE negotiation and, at a certain (very late) point during the ICE conversation, it selects the ICE candidate pair corresponding to the two ICE relay candidates (its own as the local candidate, plus the one received from the media server as the remote candidate);
- the client creates a permission on the TURN allocation at
stunner_a
to send toIP_b
(the IP corresponding to the remote ICE candidate in the selected ICE candidate pair); - the client tries to connect via its TURN allocation through the relay address
IP_a:port_a
toIP_b:port_b
(the relay address in the remote ICE candidate), which just happens to be the transport relay address created by the media server onstunner_b
(this is the only "magical" part here, but there is no magic here at all, it's how ICE negotiation goes over relay candidates); - the connection attempt will most probably fail, since the media server still hasn't created a TURN permission for receiving traffic from
IP_a
over its TURN allocation; - the media server also enters the ICE negotiation phase (in fact, with trickle ICE the negotiation starts immediately and the connection attempt is made right after the relay candidates become available);
- the media finally selects the relay-relay ICE candidate pair (note that this is always the least preferred ICE candidate pair since TURN is considered "expensive" in the ICE RFC, but this is only because TURN servers often add significant delay due to being hosted far from the media server, but this is not the case for STUNner whose extra latency/jitter is typically in the 10-100 microsecond range by being in the same cluster as the server);
- the media server creates a TURN permission (this is why you must add the service covering all
stunnerd
pods to the backend of the UDPRoute for symmetric ICE, otherwise the permission will not be granted by STUNner) toIP_a
(since for the server the remote ICE candidate is now the relay candidate received from the client); - the media server tries to connect via the relay address
IP_b:port_b
toIP_a:port_a
(the relay address of the client); - the connection request is now successful, since both parties have permission to send to the other, and both the sender and the receiver IP:port in the connection attempts (this is usually a STUN Binding request) are exactly the ones as specified in the relay candidates;
- ICE enters into the connected state and the media can start to flow between the client and the server over the negotiated connection.
The traffic flow is something like the below:
client <--TURN--> stunner_a(IP_a:port_a) <--UDP--> (IP_b:port_b)stunner_b <--TURN--> media server
Note that in symmetric ICE mode both parties have to go through STUNner, which adds some extra processing compared to asymmetric ICE where only the client uses STUNner, the media server connects directly to the relay address via UDP as it is in the same IP subnet as the stunnerd
pods:
client <--TURN--> stunner_a(IP_a:port_a) <--UDP--> media server
Note that even with symmetric ICE the ICE negotiation usually succeeds over asymmetric ICE and never reaches the relay-relay case. This is because, as mentioned above, ICE tries the candidate pairs in order of priority and the relay-relay pair is always the last one (minus TCP, I never know how TCP host/srflx candidates are prioritized versus UDP relay candidates). Before the relay-relay candidate, however, ICE will try to match the client's relay
candidate with the media server's host
candidate (this will contain the media server's own pod IP) and this will be successful due to the above so the relay-relay pair is never used.
As you see, the symmetric ICE mode is quite complex and the fact that it usually falls back to asymmetric ICE confuses the hell out of people. That's why we advise against using it unless it's not absolutely necessary.
Hope this clarifies the symmetric ICE case.
from stunner.
That's a great explanation; thank you so much!
from stunner.
Closing this for now, feel free to reopen if something comes up.
from stunner.
Related Issues (20)
- Mixed protocol available for AWS? If not how to setup health check if not supported? HOT 3
- Does it work with MediaMTX (Whip) and can I choose the destination server with an API? HOT 8
- Gatteway API v1.0 incompatibility on GKE HOT 6
- UDP Gateway Error HOT 11
- srflx ICE candidate wrong ip? HOT 1
- SRS integration? HOT 5
- Example app udp-greeter.yaml not working - help needed HOT 10
- v0.16.0 - Websocket error HOT 3
- v0.16.0 - Stunnerd pods get into state where they won't respond to TURN requests HOT 1
- Allow Gateways to request a specific NodePort in the automatically created Service HOT 7
- TURN connection breaks when the backend pod enters graceful shutdown HOT 13
- `stunnerctl config` does not fall back to the default namespace
- Help testing on AKS (Azure) HOT 1
- Media plane: Asymmetric ICE connection issues: no allocation found HOT 6
- Deployment in headless mode does not resolve public ip address of client HOT 4
- Turncat example not working on EKS HOT 11
- error install on container : kubernate and helm HOT 3
- Turncat does not include SNI header when using TURN/TLS HOT 5
- UDPRoute with media servers that dynamically choose the listener port HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from stunner.