I am making peer to peer connection for voice calling. I have call offer to other user and he receive call and connection establish successfully. After that I am getting error - 'ICE failed, see about:webrtc for more details'
Please help me what is problem in my code:
client side javascript:
if (!console || !console.log) {
var console = {
log: function() {}
};
}
// Ugh, globals.
var isFirefox = !!navigator.mozGetUserMedia;
var isChrome = !!navigator.webkitGetUserMedia;
var STUN = {
};
var TURN = {
credential: 'muazkh'
};
var iceServers = {
iceServers: [STUN]
};
if (isChrome) {
if (parseInt(navigator.userAgent.match( /Chrom(e|ium)\/([0-9]+)\./ )[2]) >= 28)
TURN = {
credential: 'muazkh',
};
iceServers.iceServers = [STUN, TURN];
}
var options = {
optional: [
{DtlsSrtpKeyAgreement: true},
//{RtpDataChannels: true}
]
};
navigator.getUserMedia = ( navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia);
var PeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
var RTCSessionDescription = window.mozRTCSessionDescription || window.RTCSessionDescription || window.webkitRTCPeerConnection;;
var RTCIceCandidate = window.mozRTCIceCandidate || window.RTCIceCandidate;
var peerc;
var source = new EventSource("events");
$("#incomingCall").modal();
$("#incomingCall").modal("hide");
$("#incomingCall").on("hidden", function() {
document.getElementById("incomingRing").pause();
});
source.addEventListener("ping", function(e) {}, false);
source.addEventListener("userjoined", function(e) {
appendUser(e.data);
}, false);
source.addEventListener("userleft", function(e) {
removeUser(e.data);
}, false);
source.addEventListener("offer", function(e) {
var offer = JSON.parse(e.data);
document.getElementById("incomingUser").innerHTML = offer.from;
document.getElementById("incomingAccept").onclick = function() {
$("#incomingCall").modal("hide");
acceptCall(offer);
};
$("#incomingCall").modal();
document.getElementById("incomingRing").play();
}, false);
source.addEventListener("answer", function(e) {
var answer = JSON.parse(e.data);
peerc.setRemoteDescription(new RTCSessionDescription(JSON.parse(answer.answer)), function() {
console.log("Call established!");
}, error);
}, false);
function log(info) {
var d = document.getElementById("debug");
d.innerHTML += info + "\n\n";
}
function appendUser(user) {
// If user already exists, ignore it
var index = users.indexOf(user);
if (index > -1)
return;
users.push(user);
console.log("appendUser: user = " + user + "users.length = " + users.length);
var d = document.createElement("div");
d.setAttribute("id", btoa(user));
var a = document.createElement("a");
a.setAttribute("class", "btn btn-block btn-inverse");
a.setAttribute("onclick", "initiateCall('" + user + "');");
a.innerHTML = "<i class='icon-user icon-white'></i> " + user;
d.appendChild(a);
d.appendChild(document.createElement("br"));
document.getElementById("users").appendChild(d);
}
function removeUser(user) {
// If user already exists, ignore it
var index = users.indexOf(user);
if (index == -1)
return;
users.splice(index, 1)
var d = document.getElementById(btoa(user));
if (d) {
document.getElementById("users").removeChild(d);
}
}
// TODO: refactor, this function is almost identical to initiateCall().
function acceptCall(offer) {
log("Incoming call with offer " + offer);
document.getElementById("main").style.display = "none";
document.getElementById("call").style.display = "block";
navigator.getUserMedia({video:false, audio:true}, function(stream) {
document.getElementById("localvideo").mozSrcObject = stream;
document.getElementById("localvideo").play();
document.getElementById("localvideo").muted = true;
//var pc = new mozRTCPeerConnection();
var pc = new PeerConnection(iceServers, options);
pc.addStream(stream);
pc.onaddstream = function(obj) {
document.getElementById("remotevideo").mozSrcObject = obj.stream;
document.getElementById("remotevideo").play();
document.getElementById("dialing").style.display = "none";
document.getElementById("hangup").style.display = "block";
};
//pc.setRemoteDescription(new mozRTCSessionDescription(JSON.parse(offer.offer)), function() {
pc.setRemoteDescription(new RTCSessionDescription(JSON.parse(offer.offer)), function() {
log("setRemoteDescription, creating answer");
pc.createAnswer(function(answer) {
pc.setLocalDescription(answer, function() {
// Send answer to remote end.
log("created Answer and setLocalDescription " + JSON.stringify(answer));
peerc = pc;
jQuery.post(
"answer", {
to: offer.from,
answer: JSON.stringify(answer)
},
function() { console.log("Answer sent!"); }
).error(error);
}, error);
}, error);
}, error);
}, error);
}
function initiateCall(user) {
document.getElementById("main").style.display = "none";
document.getElementById("call").style.display = "block";
navigator.getUserMedia({video:false, audio:true}, function(stream) {
document.getElementById("localvideo").mozSrcObject = stream;
document.getElementById("localvideo").play();
document.getElementById("localvideo").muted = true;
// var pc = new mozRTCPeerConnection();
var pc = new PeerConnection(iceServers, options);
pc.addStream(stream);
pc.onaddstream = function(obj) {
log("Got onaddstream of type " + obj.type);
document.getElementById("remotevideo").mozSrcObject = obj.stream;
document.getElementById("remotevideo").play();
document.getElementById("dialing").style.display = "none";
document.getElementById("hangup").style.display = "block";
};
pc.createOffer(function(offer) {
log("Created offer" + JSON.stringify(offer));
pc.setLocalDescription(offer, function() {
// Send offer to remote end.
log("setLocalDescription, sending to remote");
peerc = pc;
jQuery.post(
"offer", {
to: user,
from: document.getElementById("user").innerHTML,
offer: JSON.stringify(offer)
},
function() { console.log("Offer sent!"); }
).error(error);
}, error);
}, error);
}, error);
}
function endCall() {
log("Ending call");
document.getElementById("call").style.display = "none";
document.getElementById("main").style.display = "block";
document.getElementById("localvideo").mozSrcObject.stop();
document.getElementById("localvideo").mozSrcObject = null;
document.getElementById("remotevideo").mozSrcObject = null;
peerc.close();
peerc = null;
}
function error(e) {
if (typeof e == typeof {}) {
alert("Oh no! " + JSON.stringify(e));
} else {
alert("Oh no! " + e);
}
endCall();
}
var users = [];
users.push(document.getElementById("user").innerHTML);
---------------------------------
Node js server side javascript:
var express = require("express"),
https = require("https"),
app = express();
app.set("view engine", "ejs");
app.set("views", __dirname + "/views");
app.use(express.bodyParser());
app.use(express.cookieParser("thisistehsecret"));
app.use(express.session());
app.use(express.static(__dirname + "/static"));
app.get("/", function(req, res) {
res.redirect("/login");
});
app.get("/login", function(req, res) {
if (req.session.user) {
res.redirect("/chat");
return;
}
// ejs complains about undefined variable?
res.locals.message = "";
res.locals.offline = true;
if (req.query.err) {
res.locals.message = req.query.err;
}
if (process.env.ONLINE) {
res.locals.offline = false;
}
res.render("login");
});
app.get("/chat", function(req, res) {
if (!req.session.user) {
doRedirect("Access denied, try logging in?", res);
return;
}
res.locals.user = req.session.user;
res.render("chat");
});
app.get("/events", function(req, res) {
if (!req.session.user) {
res.send(401, "Unauthorized, events access denied");
return;
}
// Setup event channel.
res.type("text/event-stream");
res.write("event: ping\n");
res.write("data: ping\n\n");
// First notify this user of all users current.
var keys = Object.keys(users);
for (var i = 0; i < keys.length; i++) {
var user = keys[i];
res.write("event: userjoined\n");
res.write("data: " + user + "\n\n");
}
// Add to current list of online users.
users[req.session.user] = res;
});
if (!req.session.user) {
res.send(401, "Unauthorized, offer access denied");
return;
}
if (!
req.body.to || !req.body.from || !req.body.offer) {
res.send(400, "Invalid offer request");
return;
}
console.log(channel);
if (!channel) {
res.send(400, "Invalid user for offer");
return;
}
channel.write("event: offer\n");
channel.write("data: " + JSON.stringify(req.body));
channel.write("\n\n");
res.send(200);
});
// TODO: refactor, this is almost a duplicate of post("offer").
app.post("/answer", function(req, res) {
if (!req.session.user) {
res.send(401, "Unauthorized, answer access denied");
return;
}
if (!
req.body.to || !req.body.from || !req.body.answer) {
res.send(400, "Invalid offer request");
return;
}
if (!channel) {
res.send(400, "Invalid user for answer");
return;
}
channel.write("event: answer\n");
channel.write("data: " + JSON.stringify(req.body));
channel.write("\n\n");
res.send(200);
});
if (!req.body.assertion) {
res.send(500, "Invalid login request");
return;
}
verifyAssertion(req.body.assertion, audience, function(val) {
if (val) {
req.session.regenerate(function() {
req.session.user = val;
notifyAllAbout(val);
res.send(200);
});
} else {
res.send(401, "Invalid Persona assertion");
}
});
});
app.post("/logout", function(req, res) {
req.session.destroy(function(){
res.send(200);
});
});
var users = {};
var port = process.env.PORT || 5000;
app.listen(port, function() {
console.log("Port is " + port + " with audience " + audience);
});
// Helper functions.
function doRedirect(msg, res) {
res.redirect("/login?err=" + encodeURIComponent(msg));
}
function notifyAllAbout(user) {
var keys = Object.keys(users);
for (var i = 0; i < keys.length; i++) {
var channel = users[keys[i]];
channel.write("event: userjoined\n");
channel.write("data: " + user + "\n\n");
}
}
function verifyAssertion(ast, aud, cb) {
if (!process.env.ONLINE) {
cb(ast);
return;
}
var data = "audience=" + encodeURIComponent(aud);
data += "&assertion=" + encodeURIComponent(ast);
var options = {
path: "/verify",
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"Content-Length": data.length
}
};
var req = https.request(options, function(res) {
var ret = "";
res.on("data", function(chunk) {
ret += chunk;
});
res.on("end", function() {
try {
var val = JSON.parse(ret);
} catch(e) {
cb(false);
return;
}
if (val.status == "okay") {
cb(val.email);
} else {
// console.log(data);
//console.log(val);
cb(false);
}
});
});
req.write(data);
req.end();
}