Everything works except Turn servers

I see all the server/mobile etc. stuff working including audio and video, but the second it has to use the TURN servers, it doesn’t show audio/video. I can see candidates going in between, and connection established the same as local, but no audio or video transferred. I’m thinking there is a syntax issue, since the TURN servers aren’t mine/not custom.

Turn servers are from xirsys.net/
Static configuration (just copy pasting the creds/servers etc)

import { io } from 'lib'
import {
  RTCPeerConnection,
  RTCIceCandidate,
  RTCSessionDescription,
  RTCView,
  MediaStream,
  MediaStreamTrack,
  mediaDevices,
  registerGlobals
} from 'react-native-webrtc'

const config = {
  iceServers: [
    { url: 'stun:eu-turn1.xirsys.com' },
    {
      username: '*****',
      credential: '*****',
      urls: [
        'turn:eu-turn1.xirsys.com:80?transport=udp',
        'turn:eu-turn1.xirsys.com:3478?transport=udp',
        'turn:eu-turn1.xirsys.com:80?transport=tcp',
        'turn:eu-turn1.xirsys.com:3478?transport=tcp',
        'turns:eu-turn1.xirsys.com:443?transport=tcp',
        'turns:eu-turn1.xirsys.com:5349?transport=tcp'
      ]
    },
  ]
}

let myConn = new RTCPeerConnection(config),
  clients = {},
  local,
  guestPeer,
  remoteStream

function getRemoteStream() {
  return remoteStream
}
// starts the camera
function localStream() {
  if(local) return local

  mediaDevices.enumerateDevices()
    .then(sourceInfos => {
      let videoSourceId
      for (let i = 0; i < sourceInfos.length; i++) {
        const sourceInfo = sourceInfos[i]
        if(sourceInfo.kind == 'videoinput' && sourceInfo.facing == 'front') {
          videoSourceId = sourceInfo.deviceId
        }
      }

    mediaDevices
      .getUserMedia({
        audio: true,
        video: {
          mandatory: {
            minFrameRate: 30,
            minHeight: 768,
            minWidth: 1280
          },
          facingMode: 'user',
          // optional: videoSourceId ? [{ sourceId: videoSourceId }] : [],
        },
      })
      .then(stream => {
        local = stream
        myConn.addStream(stream)
        return stream
      })
      .catch(error => {
        // Log error
      })
    })
}

// TODO: handle later. for now, handle the people that come in later
// tell the existing guests the host started streaming
function startStreaming() {
  io.startStreaming()
}

// HOST should send an offer
function onNewGuest({ guestId, hostId }) {
  let newPeer = new RTCPeerConnection(config)
  clients[guestId] = newPeer

  newPeer.addStream(local)

  newPeer.createOffer()
    .then(sdp => newPeer.setLocalDescription(sdp))
    .then(() => {
      io.sendOffer({ guestId, offer: newPeer.localDescription })
    })
    .catch(e => console.log('err create offer', e))

  newPeer.onicecandidate = (e) => {
    if(!e.candidate) return
    io.candidate({ guestId, candidate: e.candidate })
  }
}

// GUEST received an offer
function onOffer({ hostId, offer, guestId }) {
  console.log('offer?', offer);
  guestPeer = new RTCPeerConnection(config)
  guestPeer
    .setRemoteDescription(new RTCSessionDescription(offer))
    .then(() => guestPeer.createAnswer())
    .then(sdp => guestPeer.setLocalDescription(sdp))
    .then(() => io.sendAnswer({ hostId, offer: guestPeer.localDescription }))
    .catch(e => console.log('err onOffer', e))

  guestPeer.onicecandidate = e => {
    if(!e.candidate) return
    io.candidate({ hostId, candidate: e.candidate })
  }

  guestPeer.onaddstream = e => {
    if(!e.stream || remoteStream === e.stream) return console.log('same stream')
    remoteStream = e.stream
  }
}

// HOST received an answer to offer
function onAnswer({ guestId, offer }) {
  clients[guestId]
    .setRemoteDescription(new RTCSessionDescription(offer))
}

function addIceCandidate({ guestId, hostId, candidate }) {
  console.log('got ice', candidate);
  if(guestId) guestPeer.addIceCandidate(new RTCIceCandidate(candidate))
  if(hostId) clients[guestId]?.addIceCandidate(new RTCIceCandidate(candidate))
}

function close(isHost) {
  isHost
    ? clients.forEach(x => x.close())
    : guestPeer?.close()
}

const streaming = {
  localStream,
  getRemoteStream,
  onAnswer,
  onOffer,
  onNewGuest,
  guestPeer,
  startStreaming,
  addIceCandidate,
  close,
  switchCamera: () => {
    local
      .getVideoTracks()
      .forEach((track) => {
        track._switchCamera()
      })
  },
  // Mutes the local's outgoing audio
  toggleMute: () => {
    local
      .getAudioTracks()
      .forEach(track => {
        track.enabled = !track.enabled
      })
  }
}

export default streaming

Is this some kind of syntax issue, or am I missing something?

I have just changed the TURN servers to http://numb.viagenie.ca/, and these are the ice candidates. the issue is still the same

SOLVED. There was just a small mistake sending the candidate from the server.