Skip to content

Instantly share code, notes, and snippets.

@robjshaw
Created April 8, 2022 04:32
Show Gist options
  • Save robjshaw/4800d11fe5974fbddf83e5447c68283c to your computer and use it in GitHub Desktop.
Save robjshaw/4800d11fe5974fbddf83e5447c68283c to your computer and use it in GitHub Desktop.
$(function() {
var speakerDevices = document.getElementById("speaker-devices");
var ringtoneDevices = document.getElementById("ringtone-devices");
var outputVolumeBar = document.getElementById("output-volume");
var inputVolumeBar = document.getElementById("input-volume");
var volumeIndicators = document.getElementById("volume-indicators");
var device;
log("Requesting Access Token...");
// Using a relative link to access the Voice Token function
$.getJSON("./voice-token?clientid=" + getAllUrlParams().issueid)
.then(function(data) {
log("Got a token.");
console.log("Token: " + data.token);
// Setup Twilio.Device
device = new Twilio.Device(data.token, {
// Set Opus as our preferred codec. Opus generally performs better, requiring less bandwidth and
// providing better audio quality in restrained network conditions. Opus will be default in 2.0.
codecPreferences: ["opus", "pcmu"],
// Use fake DTMF tones client-side. Real tones are still sent to the other end of the call,
// but the client-side DTMF tones are fake. This prevents the local mic capturing the DTMF tone
// a second time and sending the tone twice. This will be default in 2.0.
fakeLocalDTMF: true,
// Use `enableRingingState` to enable the device to emit the `ringing`
// state. The TwiML backend also needs to have the attribute
// `answerOnBridge` also set to true in the `Dial` verb. This option
// changes the behavior of the SDK to consider a call `ringing` starting
// from the connection to the TwiML backend to when the recipient of
// the `Dial` verb answers.
enableRingingState: true
});
device.on("ready", function(device) {
log("Twilio.Device Ready!");
document.getElementById("call-controls").style.display = "block";
});
device.on("error", function(error) {
log("Twilio.Device Error: " + error.message);
});
device.on("connect", function(conn) {
log("Successfully established call!");
document.getElementById("button-call").style.display = "none";
document.getElementById("button-hangup").style.display = "inline";
volumeIndicators.style.display = "block";
bindVolumeIndicators(conn);
});
device.on("disconnect", function(conn) {
log("Call ended.");
document.getElementById("button-call").style.display = "inline";
document.getElementById("button-hangup").style.display = "none";
volumeIndicators.style.display = "none";
// window.close();
});
device.on("incoming", function(conn) {
log("Incoming connection from " + conn.parameters.From);
conn.accept();
});
setClientNameUI(data.identity);
device.audio.on("deviceChange", updateAllDevices.bind(device));
// Show audio selection UI if it is supported by the browser.
if (device.audio.isOutputSelectionSupported) {
document.getElementById("output-selection").style.display = "block";
}
})
.catch(function(err) {
console.log(err);
log("Could not get a token from server!");
});
// Bind button to make call
document.getElementById("button-call").onclick = function() {
// get the phone number to connect the call to
const formatedNumber = document.getElementById("phone-number").value.replace("0", "+61");
var params = {
To: formatedNumber
};
console.log("Calling " + params.To + "...");
if (device) {
var outgoingConnection = device.connect(params);
outgoingConnection.on("ringing", function() {
log("Ringing...");
});
}
};
// Bind button to hangup call
document.getElementById("button-hangup").onclick = function() {
log("Hanging up...");
if (device) {
device.disconnectAll();
}
};
document.getElementById("get-devices").onclick = function() {
navigator.mediaDevices
.getUserMedia({ audio: true })
.then(updateAllDevices.bind(device));
};
speakerDevices.addEventListener("change", function() {
var selectedDevices = [].slice
.call(speakerDevices.children)
.filter(function(node) {
return node.selected;
})
.map(function(node) {
return node.getAttribute("data-id");
});
device.audio.speakerDevices.set(selectedDevices);
});
ringtoneDevices.addEventListener("change", function() {
var selectedDevices = [].slice
.call(ringtoneDevices.children)
.filter(function(node) {
return node.selected;
})
.map(function(node) {
return node.getAttribute("data-id");
});
device.audio.ringtoneDevices.set(selectedDevices);
});
function bindVolumeIndicators(connection) {
connection.on("volume", function(inputVolume, outputVolume) {
var inputColor = "red";
if (inputVolume < 0.5) {
inputColor = "green";
} else if (inputVolume < 0.75) {
inputColor = "yellow";
}
inputVolumeBar.style.width = Math.floor(inputVolume * 300) + "px";
inputVolumeBar.style.background = inputColor;
var outputColor = "red";
if (outputVolume < 0.5) {
outputColor = "green";
} else if (outputVolume < 0.75) {
outputColor = "yellow";
}
outputVolumeBar.style.width = Math.floor(outputVolume * 300) + "px";
outputVolumeBar.style.background = outputColor;
});
}
function updateAllDevices() {
updateDevices(speakerDevices, device.audio.speakerDevices.get());
updateDevices(ringtoneDevices, device.audio.ringtoneDevices.get());
// updateDevices(speakerDevices, );
// updateDevices(ringtoneDevices, device);
}
// Update the available ringtone and speaker devices
function updateDevices(selectEl, selectedDevices) {
selectEl.innerHTML = "";
device.audio.availableOutputDevices.forEach(function(device, id) {
var isActive = selectedDevices.size === 0 && id === "default";
selectedDevices.forEach(function(device) {
if (device.deviceId === id) {
isActive = true;
}
});
var option = document.createElement("option");
option.label = device.label;
option.setAttribute("data-id", id);
if (isActive) {
option.setAttribute("selected", "selected");
}
selectEl.appendChild(option);
});
}
// Activity log
function log(message) {
var logDiv = document.getElementById("log");
logDiv.innerHTML += "<p>&gt;&nbsp;" + message + "</p>";
logDiv.scrollTop = logDiv.scrollHeight;
}
// Set the client name in the UI
function setClientNameUI(clientName) {
var div = document.getElementById("client-name");
div.innerHTML = "Calling as: <strong>" + clientName + "</strong>";
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment