Webrtc client peer connection state goes to fail after a few seconds of inactivity

22 Views Asked by At

javascript code:

// peer connection
var pc = null;
var total_clients_audio = 0;
var total_clients_video = 0;
var have_server_video = false;
var have_server_audio = false;

var local_call_number = null;
var clients_pc = [];

var closing = false


var controller = null;
var signal;

var local_stream = {"audio":null,"video":null};
var stream_client_1 = {"audio":null,"video":null};
var stream_client_2 = {"audio":null,"video":null};
var stream_client_3 = {"audio":null,"video":null};

function createLocalPeerConnection(client_call_number,client_name,client_surname){
    var config = {
        sdpSemantics: 'unified-plan',
        iceServers: [{urls: ["stun:stun1.l.google.com:19302","stun:stun2.l.google.com:19302","stun:stun.l.google.com:19302","stun:stun3.l.google.com:19302","stun:stun4.l.google.com:19302"]}]
    };
    

    clients_pc.push(new RTCPeerConnection(config));

    clients_pc[clients_pc.length-1].addEventListener('track', function(evt) {
        
        console.log(client_call_number);
        if (evt.track.kind == 'audio'){
            if (local_call_number == 1){
                if (client_call_number == 2){
                    document.getElementById('client-audio-2').srcObject = evt.streams[0];
                    stream_client_2.audio = evt.streams[0];
                }else if (client_call_number == 3){
                    document.getElementById('client-audio-3').srcObject = evt.streams[0];
                    stream_client_3.audio = evt.streams[0];
                }
            }else if (local_call_number == 2){
                if (client_call_number == 1){
                    document.getElementById('client-audio-2').srcObject = evt.streams[0];
                    stream_client_2.audio = evt.streams[0];
                }else if (client_call_number == 3){
                    document.getElementById('client-audio-3').srcObject = evt.streams[0];
                    stream_client_3.audio = evt.streams[0];
                }
            }else{
                if (client_call_number == 1){
                    document.getElementById('client-audio-2').srcObject = evt.streams[0];
                    stream_client_2.audio = evt.streams[0];
                }else if (client_call_number == 2){
                    document.getElementById('client-audio-3').srcObject = evt.streams[0];
                    stream_client_3.audio = evt.streams[0];
                }
            }
        }else{
            if (local_call_number == 1){
                if (client_call_number == 2){
                    document.getElementById('client-video-2').srcObject = evt.streams[0];
                    stream_client_2.video = evt.streams[0];
                }else if (client_call_number == 3){
                    document.getElementById('client-video-3').srcObject = evt.streams[0];
                    stream_client_3.video = evt.streams[0];
                }
            }else if (local_call_number == 2){
                if (client_call_number == 1){
                    document.getElementById('client-video-2').srcObject = evt.streams[0];
                    stream_client_2.video = evt.streams[0];
                }else if (client_call_number == 3){
                    document.getElementById('client-video-3').srcObject = evt.streams[0];
                    stream_client_3.video = evt.streams[0];
                }
            }else{
                if (client_call_number == 1){
                    document.getElementById('client-video-2').srcObject = evt.streams[0];
                    stream_client_2.video = evt.streams[0];
                }else if (client_call_number == 2){
                    document.getElementById('client-video-3').srcObject = evt.streams[0];
                    stream_client_3.video = evt.streams[0];
                }
            }
        }
    });
    


    return clients_pc[clients_pc.length-1];
}

function createPeerConnection() {
    var config = {
        sdpSemantics: 'unified-plan',
        iceServers: [{urls: ['stun:stun.l.google.com:19302']}]
    };
    

    pc = new RTCPeerConnection(config);
    //pc = new RTCPeerConnection();

    // connect audio
    pc.addEventListener('track', function(evt) {
        console.log("track");
        console.log(evt.streams[0].getTracks());
        //alert(pc.getTransceivers().length);
        if (evt.track.kind == 'audio'){
            $("#signal-audio").trigger("pause");
            $("#signal-audio").currentTime = 0; // Reset time
            document.getElementById('server-audio').srcObject = evt.streams[0];
            
            $("#control_call_button").addClass("d-none")
            $("#stop_call_button").removeClass("d-none")
        }else if (evt.track.kind == 'video'){
            document.getElementById('server-video').srcObject = evt.streams[0];
        }
    });
    


    return pc;
}

function timeoutPromise(ms, promise) {
  return new Promise((resolve, reject) => {
    const timeoutId = setTimeout(() => {
      reject(new Error("promise timeout"))
    }, ms);
    promise.then(
      (res) => {
        clearTimeout(timeoutId);
        resolve(res);
      },
      (err) => {
        clearTimeout(timeoutId);
        reject(err);
      }
    );
  })
}
function negotiate() {
    return pc.createOffer({"offerToReceiveAudio":true,"offerToReceiveVideo":true}).then(function(offer) {
        return pc.setLocalDescription(offer);
    }).then(function() {
        // wait for ICE gathering to complete
        return new Promise(function(resolve) {
            console.log(pc.iceGatheringState);
            if (pc.iceGatheringState === 'complete') {
                resolve();
            } else {
                function checkState() {
                    console.log(pc.iceGatheringState);
                    if (pc.iceGatheringState === 'complete') {
                        pc.removeEventListener('icegatheringstatechange', checkState);
                        resolve();
                    }
                }
                pc.addEventListener('icegatheringstatechange', checkState);

            }
        });
    }).then(function() {
        var offer = pc.localDescription;
        controller = new AbortController();
        signal = controller.signal;
        return timeoutPromise(30000, fetch('/offer', {
            body: JSON.stringify({
                sdp: offer.sdp,
                type: offer.type,
                "name":name,
                "surname":surname
            }),
            headers: {
                'Content-Type': 'application/json'
            },
            method: 'POST',
            signal
        }));
    }).then(function(response) {
        return response.json();
    }).then(function(answer) {
        if (answer.sdp == "" && answer.type == ""){
            console.log("call rejected 167");
            setTimeout(call_rejected, 1000);
            return null;
        }else{
            return pc.setRemoteDescription(answer);
        }
    }).catch(function(e) {
        setTimeout(call_rejected, 1000);
        //alert(e);
        console.log(e);
        return null;
    });
    
}

function negotiate_client(call_number) {
    return clients_pc[clients_pc.length-1].createOffer({"offerToReceiveAudio":true,"offerToReceiveVideo":true}).then(function(offer) {
        return clients_pc[clients_pc.length-1].setLocalDescription(offer);
    }).then(function() {
        // wait for ICE gathering to complete
        return new Promise(function(resolve) {
            console.log(clients_pc[clients_pc.length-1].iceGatheringState);
            if (clients_pc[clients_pc.length-1].iceGatheringState === 'complete') {
                resolve();
            } else {
                function checkStateClient() {
                    console.log(clients_pc[clients_pc.length-1].iceGatheringState);
                    if (clients_pc[clients_pc.length-1].iceGatheringState === 'complete') {
                        clients_pc[clients_pc.length-1].removeEventListener('icegatheringstatechange', checkStateClient);
                        resolve();
                    }
                }
                clients_pc[clients_pc.length-1].addEventListener('icegatheringstatechange', checkStateClient);

            }
        });
    }).then(function() {
        var offer = clients_pc[clients_pc.length-1].localDescription;
        
        return fetch('/offer-client', {
            body: JSON.stringify({
                sdp: offer.sdp,
                type: offer.type,
                "desired_call":call_number,
                "call_number":local_call_number
            }),
            headers: {
                'Content-Type': 'application/json'
            },
            method: 'POST'
        });
    }).then(function(response) {
        return response.json();
    }).then(function(answer) {
        return clients_pc[clients_pc.length-1].setRemoteDescription(answer);
    }).catch(function(e) {
        //alert(e);
        console.log(e);
    });
    
}



function call_rejected(){
    console.log("call rejected");
    console.log("251");
    stop_peer_connection(false);
}

function stop_peer_connection(dc_message=true) {
    console.log("stop peer connection");
    //alert("stop peer connection");
    $("#signal-audio").trigger("pause");
    $("#signal-audio").currentTime = 0; // Reset time       
    // send disconnect message because iceconnectionstate slow to go in failed or in closed state
    try{
        if (dc.readyState == "open"){
            if (dc_message){
                dc.send("disconnected");
                console.log("sending disconnect message");
            }
        }
    }catch (e){
        console.log(e);
    }
    try{
        if (local_stream["audio"] != null){
            local_stream.audio.stop();
            local_stream.video.stop();
            local_stream = {"audio":null,"video":null};
        }
    }
    catch (e){
        console.log(e);
    }
    
    $("#control_call_button").removeClass("d-none")
    $("#stop_call_button").addClass("d-none")
    
    document.getElementById('client-video-1').srcObject = null;
    document.getElementById('server-video').srcObject = null;
    document.getElementById('server-audio').srcObject = null;
    document.getElementById('client-audio-2').srcObject = null;
    document.getElementById('client-video-2').srcObject = null;
    document.getElementById('client-audio-3').srcObject = null;
    document.getElementById('client-video-3').srcObject = null;

    try{
        if (controller != null){
            controller.abort();
        }
        if (dc.readyState != "open"){
            pc.close();
        }
    }catch (e){
        console.log(e);
    }

}

function stop_client_peer_connection(call_number) {
    if (local_call_number == 1){
        if (call_number == 2){
            document.getElementById('client-audio-2').srcObject = null;
            document.getElementById('client-video-2').srcObject = null;
        }else if (call_number == 3){
            document.getElementById('client-audio-3').srcObject = null;
            document.getElementById('client-video-3').srcObject = null;
        }
    }else if (local_call_number == 2){
        if (call_number == 1){
            document.getElementById('client-audio-2').srcObject = null;
            document.getElementById('client-video-2').srcObject = null;
        }else if (call_number == 3){
            document.getElementById('client-audio-3').srcObject = null;
            document.getElementById('client-video-3').srcObject = null;
        }
    }else{
        if (call_number == 1){
            document.getElementById('client-audio-2').srcObject = null;
            document.getElementById('client-video-2').srcObject = null;
        }else if (call_number == 2){
            document.getElementById('client-audio-3').srcObject = null;
            document.getElementById('client-video-3').srcObject = null;
        }
    }
}

function start_client(client_call_number,client_name,client_surname){
    if (local_call_number == 1){
        if (client_call_number == 2){
            $("#listener-2").html("Άλλος ακροατής: "+client_name+" "+client_surname+":");
        }else if (client_call_number == 3){
            $("#listener-3").html("Άλλος ακροατής: "+client_name+" "+client_surname+":");
        }
    }else if (local_call_number == 2){
        if (client_call_number == 1){
            $("#listener-2").html("Άλλος ακροατής: "+client_name+" "+client_surname+":");
        }else if (client_call_number == 3){
            $("#listener-3").html("Άλλος ακροατής: "+client_name+" "+client_surname+":");
        }
    }else{
        if (client_call_number == 1){
            $("#listener-2").html("Άλλος ακροατής: "+client_name+" "+client_surname+":");
        }else if (client_call_number == 2){
            $("#listener-3").html("Άλλος ακροατής: "+client_name+" "+client_surname+":");
        }
    }


    
    createLocalPeerConnection(client_call_number,client_name,client_surname);
    
    clients_pc[clients_pc.length-1].onclose = function() {
        // close data channel
        
        // close local audio / video
        clients_pc[clients_pc.length-1].getSenders().forEach(function(sender) {
            sender.track.stop();
        });

        // close transceivers
        if (clients_pc[clients_pc.length-1].getTransceivers) {
            clients_pc[clients_pc.length-1].getTransceivers().forEach(function(transceiver) {
                if (transceiver.stop) {
                    transceiver.stop();
                }
            });
        }
        clients_pc.splice(clients_pc.length-1, 1);
        console.log("Local peer connection closed");
        if (local_call_number == 1){
            if (client_call_number ==2){
                stream_client_2 = stream_client_3;
                stream_client_3 = {"audio":null,"video":null};
                $("#listener-2").html($("#listener-3").html());
                $("#listener-3").html("Άλλος ακροατής:");
                document.getElementById('client-audio-2').srcObject = stream_client_2.audio;
                document.getElementById('client-audio-3').srcObject = null;
                document.getElementById('client-video-2').srcObject = stream_client_2.video;
                document.getElementById('client-video-3').srcObject = null;
            }else{//client_call_number = 3
                $("#listener-3").html("Άλλος ακροατής:");
                document.getElementById('client-audio-3').srcObject = null;
                document.getElementById('client-video-3').srcObject = null;         
            }
        }else{
            if (local_call_number == 2){
                if (client_call_number ==1){
                    stream_client_2 = stream_client_3;
                    stream_client_3 = {"audio":null,"video":null};
                    $("#listener-2").html($("#listener-3").html());
                    $("#listener-3").html("Άλλος ακροατής:");
                    document.getElementById('client-audio-2').srcObject = stream_client_2.audio;
                    document.getElementById('client-audio-3').srcObject = null;
                    document.getElementById('client-video-3').srcObject = stream_client_2.video;
                    document.getElementById('client-video-3').srcObject = null;
                
                }else{//client_call_number = 3
                    stream_client_3 = {"audio":null,"video":null};
                    $("#listener-3").html("Άλλος ακροατής:");
                    document.getElementById('client-audio-3').srcObject = null;
                    document.getElementById('client-video-3').srcObject = null;             
                }
            }else{//local_call_number = 3
                if (client_call_number ==1){
                    stream_client_2 = stream_client_3;
                    stream_client_3 = {"audio":null,"video":null};
                    $("#listener-2").html($("#listener-3").html());
                    $("#listener-3").html("Άλλος ακροατής:");
                    document.getElementById('client-audio-2').srcObject = stream_client_2.audio;
                    document.getElementById('client-audio-3').srcObject = null;
                    document.getElementById('client-video-2').srcObject = stream_client_2.video;
                    document.getElementById('client-video-3').srcObject = null;
                
                }else{//client_call_number = 2
                    stream_client_3 = {"audio":null,"video":null};
                    $("#listener-3").html("Άλλος ακροατής:");
                    document.getElementById('client-audio-3').srcObject = null;
                    document.getElementById('client-video-3').srcObject = null;             
                }
            }
        }
    };
    
    
    negotiate_client(client_call_number);
    
    
    constraints = {audio:true,video:true};
    
    /*navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
        stream.getTracks().forEach(function(track) {
            clients_pc[clients_pc.length-1].addTrack(track, stream);
        });
        return negotiate_client(client_call_number);
        }, function(err) {
            alert('Could not acquire media: ' + err);
    });
    */
}

function start(name,surname) {
    $("#control_call_button").addClass("d-none");
    $("#stop_call_button").removeClass("d-none");
    
    $("#signal-audio").trigger("play");
    pc = createPeerConnection();
    
    dc = pc.createDataChannel('chat', {"ordered": true});
    dc.onclose = function() {
        
    };
    dc.onopen = function() {
        
    };
    dc.onmessage = function(evt) {
        console.log(evt.data);
        data = JSON.parse(evt.data);
        if(data["type"] == "closing-call-1"){
            
            if (local_call_number == 1){
                if (closing == false){
                    closing = true;
                    console.log("470");
                    stop_peer_connection();
                }
            }else{
                stop_client_peer_connection(1);
            }
        }else if (data["type"] == "closing-call-2"){
            if (local_call_number == 2){
                if (closing == false){
                    closing = true;
                    console.log("480");
                    stop_peer_connection();
                }
            }else{
                stop_client_peer_connection(2);
            }
        }else if (data["type"] == "closing-call-3"){
            if (local_call_number == 3){
                if (closing == false){
                    closing = true;
                    console.log("489");
                    stop_peer_connection();
                }
            }else{
                stop_client_peer_connection(3);
            }
        }
            
        
        if (data["type"] == "local_call_number"){
            local_call_number = data["call_number"];
            stream_client_1 = local_stream;
        }
        
        if (data["type"] == "new-client"){
            var client_call_number = data["call_number"]
            var client_name = data["name"]
            var client_surname = data["surname"]
            start_client(client_call_number,client_name,client_surname)
            
        }
        
    };

    pc.onconnectionstatechange = (event) => {
       let newCS = pc.connectionState;
       if (newCS == "disconnected" || newCS == "failed" || newCS == "closed") {
           console.log(newCS);
           console.log("517");
          stop_peer_connection();
       }
    }

    
    pc.onclose = function() {
        closing = true;
        console.log("525");
        stop_peer_connection(false);
        
        // close data channel
        if (dc) {
            dc.close();
        }

        // close local audio / video
        pc.getSenders().forEach(function(sender) {
            sender.track.stop();
        });

        // close transceivers
        if (pc.getTransceivers) {
            pc.getTransceivers().forEach(function(transceiver) {
                if (transceiver.stop) {
                    transceiver.stop();
                }
            });
        }
        pc = null;
        console.log("Local peer connection closed");
        //alert("Local peer connection closed");
    
    };
    
    
    
    //negotiate();
    
    constraints = {audio:true,video:true};
    
    navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
        //local_stream = stream;
        stream.getTracks().forEach(function(track) {
            
            try {
                pc.addTrack(track, stream);
                if (track.kind == "video"){
                    //correct
                    local_stream.video = track;
                    document.getElementById('client-video-1').srcObject = stream;
                }else{
                    local_stream.audio = track;
                }
                stream_client_1 = local_stream;
            } catch(e){
                //console.log(e);
            }
        });
        return negotiate();
        }, function(err) {
            alert('Could not acquire media: ' + err);
    });
    
    
}

$(document).ready(function(){
    $("#control_call_button").on( "click", function() {
        name = $("#name").val();
        surname = $("#surname").val();
        closing = false;
        controller = null;
        start(name,surname)
    });
    
    $("#stop_call_button").on( "click", function() {
        closing = true;
        console.log("595");
        stop_peer_connection();
    });
    //debug code
    /*$("#name").on( "focus",async function(){
        for(var i=0;i<10;i++){
            $("#control_call_button").click();
            await sleep(2000);
            $("#stop_call_button").click();
            await sleep(2000);
        }
    });
    */
})

function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

/*
window.addEventListener("beforeunload", function (e) {
    console.log("Before unload");
    fetch('/cancel_call', {
            body: JSON.stringify({}),
            headers: {
                'Content-Type': 'application/json'
            },
            method: 'POST'
        });
    const sleep = ms => new Promise(r => setTimeout(r, 5000));
});
*/

after a few seconds of inactivity this code run:

    pc.onconnectionstatechange = (event) => {
       let newCS = pc.connectionState;
       if (newCS == "disconnected" || newCS == "failed" || newCS == "closed") {
           console.log(newCS);//failed
           console.log("517");
          stop_peer_connection();
       }
    }

I want to ask why this is happened and how can i keep the connection alive.

Full project on github

0

There are 0 best solutions below