I have an elixir backend where I can retrieve the ice servers from a turn server provider or a self hosted coturn, it's a graphql query that return something like this:
{
"iceServers": {
"credential": "TheCredential",
"urls": [
"stun:{turn_host}",
"turn:{turn_host}:80?transport=udp",
"turn:{turn_host}:3478?transport=udp",
"turn:{turn_host}:80?transport=tcp",
"turn:{turn_host}:3478?transport=tcp",
"turns:{turn_host}:443?transport=tcp",
"turns:{turn_host}:5349?transport=tcp"
],
"username": "TheUserName"
}
}
}
I have a global setupPeerConnectionConfig function.
const setupPeerConnectionConfig = (adapter, iceServers) => {
const qs = new URLSearchParams(location.search);
const forceTurn = qs.get("force_turn");
const forceTcp = qs.get("force_tcp");
const peerConnectionConfig = {};
if (iceServers && iceServers.urls !== null) {
if (forceTcp) {
iceServers.urls = iceServers.urls.filter((url) => url.startsWith("turn") && url.endsWith("tcp"));
}
const hasStunServer = !!iceServers.urls.find((url) => url.startsWith('stun'));
const newIceServers = [];
if (!forceTcp && !forceTurn && !hasStunServer) {
newIceServers.push({ urls: "stun:stun1.l.google.com:19302" });
}
// remove __typename from the graphql query
newIceServers.push({username: iceServers.username, credential: iceServers.credential, urls: iceServers.urls});
peerConnectionConfig.iceServers = newIceServers;
if (forceTurn || forceTcp) {
peerConnectionConfig.iceTransportPolicy = "relay";
}
} else {
peerConnectionConfig.iceServers = [
{ urls: "stun:stun1.l.google.com:19302" },
{ urls: "stun:stun2.l.google.com:19302" }
];
}
adapter.setPeerConnectionConfig(peerConnectionConfig);
};
To test that your config is right, you can force going through turn server (iceTransportPolicy = "relay")
by adding in the url ?force_turn=true. To force turn via tcp, use ?force_tcp=true. Look at about:webrtc in Firefox to see the selected candidate.
In your adapter-ready listener, call the setupPeerConnectionConfig with the retrieved iceServers.
const iceServers = await callToServerToGetIceServers();
scene.addEventListener("adapter-ready", ({ detail: adapter }) => {
// don't use any await here, it won't be awaited before connecting
setupPeerConnectionConfig(adapter, iceServers);
// ... do your other things
});
scene.emit("connect");
Getting an iceServers config asynchronously and using connectOnLoad: true are incompatible, there is no await for adapter-ready listener in https://github.com/networked-aframe/networked-aframe/blob/41a6b484c8208ecb24e85855542a3fa40faf7bec/src/components/networked-scene.js#L33 so the user will connect before we get the config.
If your turn credential is temporary, you will need to call regularly
const iceServers = await callToServerToGetIceServers();
setupPeerConnectionConfig(NAF.connection.adapter, iceServers);
otherwise new peer connections will use expired turn credential and the connection won't succeed. You can use a setTimout similar to the JWT I explained here mozilla/janus-plugin-sfu#77 (comment)
I should probably push both the linked comment and this issue into a document that I push in this repo.
I have an elixir backend where I can retrieve the ice servers from a turn server provider or a self hosted coturn, it's a graphql query that return something like this:
I have a global
setupPeerConnectionConfigfunction.To test that your config is right, you can force going through turn server (
iceTransportPolicy = "relay")by adding in the url
?force_turn=true. To force turn via tcp, use?force_tcp=true. Look atabout:webrtcin Firefox to see the selected candidate.In your
adapter-readylistener, call thesetupPeerConnectionConfigwith the retrieved iceServers.Getting an iceServers config asynchronously and using
connectOnLoad: trueare incompatible, there is no await foradapter-readylistener in https://github.com/networked-aframe/networked-aframe/blob/41a6b484c8208ecb24e85855542a3fa40faf7bec/src/components/networked-scene.js#L33 so the user will connect before we get the config.If your turn credential is temporary, you will need to call regularly
otherwise new peer connections will use expired turn credential and the connection won't succeed. You can use a setTimout similar to the JWT I explained here mozilla/janus-plugin-sfu#77 (comment)
I should probably push both the linked comment and this issue into a document that I push in this repo.