COTURN peerJS connectivity issue

81 Views Asked by At

I've set up a COTURN server for my Android app that utilizes peer.js for webRTC voice communication (isVideoCall is always false in the following code.) While testing with the TURN server URL using https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/, there are no apparent issues. However, in the actual application, I'm encountering intermittent connectivity problems.

Most of the time, the call fails with neither party being able to hear anything. And in successful calls, the initial voice only comes after a 3-6 seconds delay.

Here are some details about the setup:

=> Both clients are connected to Wi-Fi networks.

=>The COTURN server is running on a server with 1GB RAM and a single-core shared CPU. (Currently, my app has only less than 2k active users.)

=>Client setup - PeerJS running on android webview.

=>Firewall rules have been configured to allow traffic on ports 443 and 3478.

This is my client-side code:

let localVideo = document.getElementById("local-video");
let remoteVideo = document.getElementById("remote-video");
let myCall = undefined; 

remoteVideo.style.opacity = 0.0;

let peer;
var videoConstraints = false;
var constraints = { audio: false, video: false };

function init(userId, peerPath, peerKey, isVideoCall, turnPwd1, turnPwd2) {
  if (isVideoCall === "true") {
    videoConstraints = {
      width: { ideal: 1280, max: 1280, min: 640 },
      height: { ideal: 720, max: 720, min: 480 },
      facingMode: "user", // Force front camera
      frameRate: { ideal: 24, max: 24, min: 15 },
    };
  } else videoConstraints = false;

  let audioConstraints = {
    channelCount: 1,
    sampleRate: 8000, //16000,
    sampleSize: 8, //16,
    volume: 1,
    latency: 0.003,
    echoCancellation: true,
    noiseSuppression: true,
    autoGainControl: true,
  };
  constraints = { audio: audioConstraints, video: videoConstraints };

  peer = new Peer(userId, {
    //production
    host: "myappurl.com",
    port: 443,
    secure: true,
    path: peerPath,
    proxied: true,
    key: peerKey,

    config: {
      iceServers: [
        {
          url: "turn:turn.myappurl.com:3478",
          username: "foo",
          credential: turnPwd1,
        },
        {
          url: "turn:turn.myappurl.com:443",//<= ChatGPT suggested to use turns scheme instead of turn, I haven't tried it yet.
          username: "bar",
          credential: turnPwd1,
        },
        { url: "stun:stun.l.google.com:19302" },
        { url: "stun:stun1.l.google.com:19302" },
      ],
    },
  });

  peer.on("open", () => {
    Android.onPeerConnected();
  });

  peer.on("error", (err) => {
    Android.onError();
    Android.logEvent("onError: " + err);
  });
  peer.on("disconnected", () => {
    // peer.reconnect() //may crash the server
    Android.onDisconnect();
  });
  listen();
}
let localStream;
function listen() {
  peer.on("call", (call) => {
    myCall = call;
    navigator.mediaDevices
      .getUserMedia(constraints)
      .then(function (stream) {
        localVideo.srcObject = stream;
        localStream = stream;
        call.answer(stream, {
          sdpTransform: transformSdp,
        });
        call.on("stream", (rStream) => {
          Android.onPeerStream();
          remoteVideo.srcObject = rStream;
        });
      })
      .catch(function (err) {
        Android.logEvent("getUserMedia error: " + err);
      });
  });
}

function startCall(otherUserId) {
  navigator.mediaDevices
    .getUserMedia(constraints)
    .then(function (stream) {
      localVideo.srcObject = stream;
      localStream = stream;
      const call = peer.call(otherUserId, stream, {
        sdpTransform: transformSdp,
      });
      call.on("stream", (rStream) => {
        Android.onPeerStream();
        remoteVideo.srcObject = rStream;
      });
      myCall = call;
    })
    .catch(function (err) {
      Android.logEvent("getUserMedia error: " + err);
    });
}


function destroyPeer() {
  if (myCall) myCall.close();
  peer.destroy();
  Android.logEvent("destroying peer");
}

function transformSdp(sdp) {
  var splitArray = sdp.split("\n");
  for (let i = 0; i < splitArray.length; i++) {
    if (splitArray[i].startsWith("a=fmtp:111")) {
      //add dtx param to opus
      sdp = sdp.replace(splitArray[i], splitArray[i].concat(";usedtx=1"));
      break;
    }
  }
  //Android.logEvent(sdp);
  //sdp=setMediaBitrates(sdp)
  return sdp;
}

function setMediaBitrates(sdp) {
  return setMediaBitrate(setMediaBitrate(sdp, "video", 800), "audio", 48);
}

function setMediaBitrate(sdp, media, bitrate) {
  var lines = sdp.split("\n");
  var line = -1;
  for (var i = 0; i < lines.length; i++) {
    if (lines[i].indexOf("m=" + media) === 0) {
      line = i;
      break;
    }
  }
  if (line === -1) {
    console.debug("Could not find the m line for", media);
    return sdp;
  }
  console.debug("Found the m line for", media, "at line", line);

  // Pass the m line
  line++;

  // Skip i and c lines
  while (lines[line].indexOf("i=") === 0 || lines[line].indexOf("c=") === 0) {
    line++;
  }

  // If we're on a b line, replace it
  if (lines[line].indexOf("b") === 0) {
    console.debug("Replaced b line at line", line);
    lines[line] = "b=AS:" + bitrate;
    return lines.join("\n");
  }

  // Add a new b line
  console.debug("Adding new b line before line", line);
  var newLines = lines.slice(0, line);
  newLines.push("b=AS:" + bitrate);
  newLines = newLines.concat(lines.slice(line, lines.length));
  return newLines.join("\n");
}

Could you please provide guidance on how to troubleshoot and resolve this issue? Any insights or suggestions would be greatly appreciated.

Thank you!

0

There are 0 best solutions below