|
|
|
@ -1,4 +1,4 @@
|
|
|
|
|
var printStats = false; |
|
|
|
|
var displayStats = false; |
|
|
|
|
|
|
|
|
|
var socket = null; |
|
|
|
|
var ReconnectDelay = 0; |
|
|
|
@ -34,6 +34,8 @@ var muteOnMouseUp = true;
|
|
|
|
|
var lastPing = 0; |
|
|
|
|
var userPing = 0; |
|
|
|
|
|
|
|
|
|
var userList = ''; |
|
|
|
|
var userListVoice = ''; |
|
|
|
|
var userListStatus = 'Loading...'; |
|
|
|
|
|
|
|
|
|
var MessageBinary = 2; |
|
|
|
@ -49,7 +51,11 @@ var MessageTopic = 114;
|
|
|
|
|
var MessageAction = 115; |
|
|
|
|
var MessageDisconnect = 119; |
|
|
|
|
var MessageChat = 120; |
|
|
|
|
var MessageUsers = 121; |
|
|
|
|
var MessageTypingStart = 121; |
|
|
|
|
var MessageTypingStop = 122; |
|
|
|
|
var MessageTransmitStart = 123; |
|
|
|
|
var MessageTransmitStop = 124; |
|
|
|
|
var MessageUsers = 130; |
|
|
|
|
|
|
|
|
|
var tagsToReplace = { |
|
|
|
|
'&': '&', |
|
|
|
@ -75,7 +81,11 @@ function HandleInput(e) {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ($("#chatinput").val() != "") { |
|
|
|
|
w(MessageChat, $("#chatinput").val()); |
|
|
|
|
if ($("#chatinput").val() == "/debugstats") { |
|
|
|
|
enableStats(); |
|
|
|
|
} else { |
|
|
|
|
w(MessageChat, $("#chatinput").val()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$("#chatinput").val(''); |
|
|
|
@ -84,11 +94,28 @@ function HandleInput(e) {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$(document).ready(function () { |
|
|
|
|
$("#voiceButtonJoin").on("click touchstart", function () { |
|
|
|
|
$("#togglevoice").on("click touchstart", function () { |
|
|
|
|
if (peerConnections.length > 0 || voice) { |
|
|
|
|
// Quit voice chat
|
|
|
|
|
|
|
|
|
|
voice = false; |
|
|
|
|
|
|
|
|
|
w(MessageQuit, ""); |
|
|
|
|
|
|
|
|
|
peerConnections.forEach(function (pc) { |
|
|
|
|
pc.close(); |
|
|
|
|
}); |
|
|
|
|
peerConnections = []; |
|
|
|
|
|
|
|
|
|
$('#voicepttheader').css('display', 'none'); |
|
|
|
|
$('#voicepttcontainer').css('display', 'none'); |
|
|
|
|
|
|
|
|
|
updateStatus(); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Join voice chat
|
|
|
|
|
|
|
|
|
|
var i; |
|
|
|
|
for (i = 0; i < numConnections; i++) { |
|
|
|
|
peerConnections.push(createPeerConnection(i)); |
|
|
|
@ -127,7 +154,7 @@ $(document).ready(function () {
|
|
|
|
|
return false; |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
$("#inputheader, #inputfooter").on("click touchstart", function (e) { |
|
|
|
|
$("#inputheader, #voicepttheader").on("click touchstart", function (e) { |
|
|
|
|
$("#chatinput").focus(); |
|
|
|
|
|
|
|
|
|
return false; |
|
|
|
@ -139,29 +166,6 @@ $(document).ready(function () {
|
|
|
|
|
return false; |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
$("#voiceButtonQuit").on("click touchstart", function () { |
|
|
|
|
if (!voice) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
voice = false; |
|
|
|
|
|
|
|
|
|
w(MessageQuit, ""); |
|
|
|
|
|
|
|
|
|
peerConnections.forEach(function (pc) { |
|
|
|
|
pc.close(); |
|
|
|
|
}); |
|
|
|
|
peerConnections = []; |
|
|
|
|
|
|
|
|
|
$('#voicepttcontainer').css('display', 'none'); |
|
|
|
|
$('#voiceinactiveleft').css('display', 'inline-block'); |
|
|
|
|
$('#voiceactiveleft').css('display', 'none'); |
|
|
|
|
$('#voiceinactiveright').css('display', 'inline-block'); |
|
|
|
|
$('#voiceactiveright').css('display', 'none'); |
|
|
|
|
$('#voiceButton').html('Join voice chat'); |
|
|
|
|
|
|
|
|
|
updateUserStatus(); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
window.setInterval(() => { |
|
|
|
|
if (!webSocketReady()) { |
|
|
|
|
return; |
|
|
|
@ -170,43 +174,6 @@ $(document).ready(function () {
|
|
|
|
|
pingServer(); |
|
|
|
|
}, 15000); |
|
|
|
|
|
|
|
|
|
if (printStats) { |
|
|
|
|
window.setInterval(() => { |
|
|
|
|
// TODO Fix
|
|
|
|
|
|
|
|
|
|
if (!pc) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
const sender = pc.getSenders()[0]; |
|
|
|
|
if (sender === undefined) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
sender.getStats().then(stats => { |
|
|
|
|
let statsOutput = ""; |
|
|
|
|
|
|
|
|
|
stats.forEach(report => { |
|
|
|
|
if (report.type == "local-candidate" || report.type == "remote-candidate") { |
|
|
|
|
return; |
|
|
|
|
} else if (report.type == "candidate-pair" && (report.bytesSent == 0 && report.bytesReceived == 0)) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
statsOutput += `<b>Report: ${report.type}</b>\n<strong>ID:</strong> ${report.id}<br>\n` + |
|
|
|
|
`<strong>Timestamp:</strong> ${report.timestamp}<br>\n`; |
|
|
|
|
|
|
|
|
|
Object.keys(report).forEach(statName => { |
|
|
|
|
if (statName !== "id" && statName !== "timestamp" && statName !== "type") { |
|
|
|
|
statsOutput += `<strong>${statName}:</strong> ${report[statName]}<br>\n`; |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
document.querySelector("#stats").innerHTML = statsOutput; |
|
|
|
|
}); |
|
|
|
|
}, 1000); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
nickname = prompt("What is your name?", nickname); |
|
|
|
|
Connect(); |
|
|
|
|
}); |
|
|
|
@ -246,14 +213,10 @@ function createPeerConnection(id) {
|
|
|
|
|
Log("Note: Push-to-talk is bound to <F8>"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$('#voicepttheader').css('display', 'table-row'); |
|
|
|
|
$('#voicepttcontainer').css('display', 'table-row'); |
|
|
|
|
$('#voiceinactiveleft').css('display', 'none'); |
|
|
|
|
$('#voiceactiveleft').css('display', 'inline-block'); |
|
|
|
|
$('#voiceinactiveright').css('display', 'none'); |
|
|
|
|
$('#voiceactiveright').css('display', 'inline-block'); |
|
|
|
|
$('#voiceButton').html('Quit voice chat'); |
|
|
|
|
|
|
|
|
|
updateUserStatus(); |
|
|
|
|
updateStatus(); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
if (id == 0) { |
|
|
|
@ -295,8 +258,8 @@ function onRTCDescription(id) {
|
|
|
|
|
|
|
|
|
|
peerConnections[id].setLocalDescription(desc) |
|
|
|
|
.then(() => { |
|
|
|
|
desc.sdp = maybePreferCodec(desc.sdp, 'audio', 'send', 'opus'); |
|
|
|
|
desc.sdp = maybePreferCodec(desc.sdp, 'audio', 'receive', 'opus'); |
|
|
|
|
desc.sdp = maybePreferCodec(desc.sdp, 'audio', 'send', 'opus/48000'); |
|
|
|
|
desc.sdp = maybePreferCodec(desc.sdp, 'audio', 'receive', 'opus/48000'); |
|
|
|
|
|
|
|
|
|
console.log(`PC ${id} onRTCDescription`); |
|
|
|
|
|
|
|
|
@ -313,7 +276,7 @@ function Connect() {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
userListStatus = 'Connecting...'; |
|
|
|
|
updateUserStatus(); |
|
|
|
|
updateStatus(); |
|
|
|
|
|
|
|
|
|
Log("Connecting..."); |
|
|
|
|
|
|
|
|
@ -341,7 +304,7 @@ function Connect() {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
userListStatus = ""; |
|
|
|
|
updateUserStatus(); |
|
|
|
|
updateStatus(); |
|
|
|
|
|
|
|
|
|
w(MessageNick, nickname); |
|
|
|
|
|
|
|
|
@ -363,7 +326,7 @@ function Connect() {
|
|
|
|
|
if (parseInt(p.M, 10) == lastPing) { |
|
|
|
|
userPing = Date.now() - lastPing; |
|
|
|
|
|
|
|
|
|
updateUserStatus(); |
|
|
|
|
updateStatus(); |
|
|
|
|
} |
|
|
|
|
} else if (p.T == MessageAnswer) { |
|
|
|
|
if (p.PC === undefined || p.PC > peerConnections.length) { |
|
|
|
@ -383,19 +346,25 @@ function Connect() {
|
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Log(escapeEntities(p.N) + " joined #lobby voice chat"); |
|
|
|
|
Log(escapeEntities(p.N) + " joined &lobby"); |
|
|
|
|
} else if (p.T == MessageQuit) { |
|
|
|
|
if (p.N === undefined) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Log(escapeEntities(p.N) + " quit #lobby voice chat"); |
|
|
|
|
Log(escapeEntities(p.N) + " quit &lobby"); |
|
|
|
|
} else if (p.T == MessageDisconnect) { |
|
|
|
|
if (p.N === undefined) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Log(escapeEntities(p.N) + " disconnected"); |
|
|
|
|
} else if (p.T == MessageNick) { |
|
|
|
|
if (p.N === undefined) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Log(escapeEntities(p.N) + " is now known as " + escapeEntities(p.M)); |
|
|
|
|
} else if (p.T == MessageChat) { |
|
|
|
|
if (p.N === undefined) { |
|
|
|
|
return; |
|
|
|
@ -403,10 +372,44 @@ function Connect() {
|
|
|
|
|
|
|
|
|
|
Log("<" + escapeEntities(p.N) + "> " + escapeEntities(p.M)); |
|
|
|
|
} else if (p.T == MessageUsers) { |
|
|
|
|
var userListNew = '<ul>'; |
|
|
|
|
|
|
|
|
|
var u = JSON.parse(p.M); |
|
|
|
|
userListNew += '<li><b>' + u.length + ' user' + (u.length != 1 ? 's' : '') + '</b></li>'; |
|
|
|
|
for (let i = 0; i < u.length; i++) { |
|
|
|
|
// TODO: Parse
|
|
|
|
|
userListNew += '<li>' + u[i].N + '</li>'; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
userListNew += '</ul>'; |
|
|
|
|
|
|
|
|
|
userList = userListNew; |
|
|
|
|
|
|
|
|
|
var userListVoiceNew = '<ul style="padding-left: 5px;">'; |
|
|
|
|
|
|
|
|
|
var u = JSON.parse(p.M); |
|
|
|
|
for (let i = 0; i < u.length; i++) { |
|
|
|
|
if (u[i].C == 0) { |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
userListVoiceNew += '<li>'; |
|
|
|
|
if (voice) { |
|
|
|
|
userListVoiceNew += '<span id="voiceindicator' + u[i].ID + '"><div class="voiceinactive">🔈</div></span> '; |
|
|
|
|
} |
|
|
|
|
userListVoiceNew += u[i].N + '</li>'; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
userListVoiceNew += '</ul>'; |
|
|
|
|
|
|
|
|
|
userListVoice = userListVoiceNew; |
|
|
|
|
|
|
|
|
|
updateUserList(); |
|
|
|
|
} else if (p.T == MessageTransmitStart || p.T == MessageTransmitStop) { |
|
|
|
|
if (!voice || p.S === undefined) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$("#voiceindicator" + p.S).html(p.T == MessageTransmitStart ? '<div class="voiceactive">🔊</div>' : '<div class="voiceinactive">🔈</div>'); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
// TODO Binary data
|
|
|
|
@ -457,7 +460,8 @@ function waitForSocketConnection(socket, callback) {
|
|
|
|
|
|
|
|
|
|
function Log(msg) { |
|
|
|
|
var date = new Date(); |
|
|
|
|
$('#chathistory').append(chatprefix + date.getHours() + ":" + (date.getMinutes() < 10 ? "0" : "") + date.getMinutes() + " " + msg + "\n"); |
|
|
|
|
$('#chathistory').append(chatprefix + date.getHours() + ":" + (date.getMinutes() < 10 ? "0" : "") + date.getMinutes() + " " + msg + "\n") |
|
|
|
|
$('#chathistory').scrollTop($('#chathistory').prop("scrollHeight")); |
|
|
|
|
|
|
|
|
|
if (chatprefix == "") { |
|
|
|
|
chatprefix = "<br>"; |
|
|
|
@ -476,7 +480,7 @@ function StartPTT() {
|
|
|
|
|
var sender = peerConnections[0].getSenders()[0]; |
|
|
|
|
sender.replaceTrack(audioTrack); |
|
|
|
|
|
|
|
|
|
updateUserStatus(); |
|
|
|
|
updateStatus(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function StopPTT() { |
|
|
|
@ -491,10 +495,10 @@ function StopPTT() {
|
|
|
|
|
var sender = peerConnections[0].getSenders()[0]; |
|
|
|
|
sender.replaceTrack(null); |
|
|
|
|
|
|
|
|
|
updateUserStatus(); |
|
|
|
|
updateStatus(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function updateUserStatus() { |
|
|
|
|
function updateStatus() { |
|
|
|
|
var out = ''; |
|
|
|
|
if (userPing > 0) { |
|
|
|
|
out += userPing + 'ms ping'; |
|
|
|
@ -509,6 +513,14 @@ function updateUserStatus() {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$('#userstatus').html(out); |
|
|
|
|
|
|
|
|
|
$('#togglevoice').html(peerConnections.length > 0 ? 'Quit' : 'Join'); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function updateUserList() { |
|
|
|
|
$('#userlistvoice1').html(userListVoice); |
|
|
|
|
|
|
|
|
|
$('#sideright').html(userList); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function w(t, m) { |
|
|
|
@ -535,6 +547,51 @@ function escapeEntities(str) {
|
|
|
|
|
return str.replace(/[&<>]/g, escapeEntitiesCallback); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function enableStats() { |
|
|
|
|
if (displayStats) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
displayStats = true; |
|
|
|
|
|
|
|
|
|
window.setInterval(() => { |
|
|
|
|
var i; |
|
|
|
|
for (i = 0; i < peerConnections.length; i++) { |
|
|
|
|
var senders = peerConnections[i].getSenders(); |
|
|
|
|
|
|
|
|
|
var j; |
|
|
|
|
for (j = 0; j < senders.length; j++) { |
|
|
|
|
senders[j].getStats().then(stats => { |
|
|
|
|
let statsOutput = ""; |
|
|
|
|
|
|
|
|
|
stats.forEach(report => { |
|
|
|
|
if (report.type == "local-candidate" || report.type == "remote-candidate") { |
|
|
|
|
return; |
|
|
|
|
} else if (report.type == "candidate-pair" && (report.bytesSent == 0 && report.bytesReceived == 0)) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
statsOutput += `<b>PC${i}S${j} Report: ${report.type}</b>\n<strong>ID:</strong> ${report.id}<br>\n` + |
|
|
|
|
`<strong>Timestamp:</strong> ${report.timestamp}<br>\n`; |
|
|
|
|
|
|
|
|
|
Object.keys(report).forEach(statName => { |
|
|
|
|
if (statName !== "id" && statName !== "timestamp" && statName !== "type") { |
|
|
|
|
statsOutput += `<strong>${statName}:</strong> ${report[statName]}<br>\n`; |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
if (statsOutput != "") { |
|
|
|
|
Log(statsOutput); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}, 1000); |
|
|
|
|
|
|
|
|
|
Log("Debug stats enabled"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Copied from AppRTC's sdputils.js:
|
|
|
|
|
|
|
|
|
|
// Sets |codec| as the default |type| codec if it's present.
|
|
|
|
|