Я внедряю экран для звонков из службы Twilio: < /p>
На данный момент вызовы Connect Connect, и я могу повесить трубку. Проблема в том, что я не могу отключить микрофон или вызов (кнопка ничего не делает), и «Статус (эстадо)» текст обновляется только от «Отключить (desconectado)» до «по вызову (en llamada.)». Вот код фронта: < /p>
Llamadas en linea
#contenido_cliente table td {
vertical-align: top;
padding: 0.25rem 0.5rem;
}
#contenido_cliente td {
padding: 4px 8px;
vertical-align: top;
}
Llamadas en linea
Llamadas Telefónicas
Número a llamar
Llamar
Colgar
Silenciar
Estado: Desconectado
Duración: 00:00
1
2
3
4
5
6
7
8
9
*
0
#
Borrar último
Borrar todo
Nombre
Celular
Estatus numero
Información del Cliente
Seleccione un contacto para ver los detalles.
< /code>
Вот скрипт: < /p>
let device;
let currentConnection;
let isMuted = false;
let callStartTime;
let durationInterval;
function actualizarEstado(estado) {
document.getElementById("estado_llamada").textContent = estado;
}
function actualizarDuracion() {
if (!callStartTime) return;
const now = new Date();
const diff = Math.floor((now - callStartTime) / 1000);
const minutes = String(Math.floor(diff / 60)).padStart(2, '0');
const seconds = String(diff % 60).padStart(2, '0');
document.getElementById("duracion_llamada").textContent = `${minutes}:${seconds}`;
}
let listaContactos = [];
function cargarContactos() {
fetch('php/llamadas.php?accion=contactos')
.then(res => res.json())
.then(clientes => {
listaContactos = clientes; // Guardamos para filtrar después
renderizarContactos(clientes);
})
.catch(err => {
console.error("Error al cargar contactos:", err);
});
}
function renderizarContactos(clientes) {
const tabla = document.getElementById("tabla_contactos");
tabla.innerHTML = "";
const agrupado = {};
// Agrupar por ID_Cliente
clientes.forEach(c => {
if (!agrupado[c.ID_Cliente]) {
agrupado[c.ID_Cliente] = [];
}
agrupado[c.ID_Cliente].push(c);
});
// Dibujar por cada grupo
Object.values(agrupado).forEach(grupo => {
grupo.forEach(c => {
const fila = document.createElement("tr");
fila.style.cursor = "pointer";
let numero = '';
let etiqueta = '';
if (c.Estatus === "1") {
numero = c.Telefono;
etiqueta = 'Actual';
} else if (c.Estatus === "0") {
numero = c.Telefono;
etiqueta = 'Anterior';
} else {
numero = c.Celular;
etiqueta = ''; // Sin etiqueta visible
}
// Acción al hacer clic
fila.addEventListener("click", () => seleccionarNumero(numero));
fila.innerHTML = `
${c.NombreCompleto}
${numero}
${etiqueta}
`;
tabla.appendChild(fila);
});
});
if (tabla.innerHTML.trim() === "") {
const fila = document.createElement("tr");
fila.innerHTML = `Información del cliente no disponible`;
tabla.appendChild(fila);
}
}
function filtrarContactos() {
const filtro = document.getElementById("filtro_contactos").value.toLowerCase();
const filtrados = listaContactos.filter(c =>
c.NombreCompleto.toLowerCase().includes(filtro)
);
renderizarContactos(filtrados);
}
function seleccionarNumero(numero) {
document.getElementById("numero_llamar").value = numero;
const contenedor = document.getElementById("contenido_cliente");
contenedor.innerHTML = `Cargando información del cliente...`;
fetch(`php/llamadas.php?accion=reporte_contratos&telefono=${numero}`)
.then(res => res.json())
.then(data => {
if (!Array.isArray(data) || data.length === 0) {
contenedor.innerHTML = `Información del cliente no disponible.`;
return;
}
contenedor.innerHTML = ""; // Limpiar contenido
// Si hay más de un contrato, usar pestañas
if (data.length > 1) {
const navTabs = document.createElement("ul");
navTabs.classList.add("nav", "nav-tabs");
navTabs.role = "tablist";
const tabContent = document.createElement("div");
tabContent.classList.add("tab-content");
data.forEach((contrato, index) => {
const contratoId = contrato.ID_Contrato || `Contrato ${index + 1}`;
const tabId = `contrato-${index}`;
// Crear pestaña
const tab = document.createElement("li");
tab.classList.add("nav-item");
tab.innerHTML = `
${contratoId}
`;
navTabs.appendChild(tab);
// Crear contenido de la pestaña
const tabPane = document.createElement("div");
tabPane.classList.add("tab-pane", "fade");
if (index === 0) {
tabPane.classList.add("show", "active");
}
tabPane.id = tabId;
tabPane.role = "tabpanel";
tabPane.appendChild(crearTablaCliente(contrato));
tabContent.appendChild(tabPane);
});
contenedor.appendChild(navTabs);
contenedor.appendChild(tabContent);
} else {
// Solo un contrato
contenedor.appendChild(crearTablaCliente(data[0]));
}
})
.catch(err => {
console.error("Error al obtener reporte del cliente:", err);
contenedor.innerHTML = `Ocurrió un error al obtener la información del cliente.`;
});
}
function crearTablaCliente(data) {
const tabla = document.createElement("table");
tabla.classList.add("table", "table-bordered", "table-sm", "mb-0", "w-100");
tabla.style.tableLayout = "fixed";
for (const [key, value] of Object.entries(data)) {
const fila = document.createElement("tr");
const celdaClave = document.createElement("td");
celdaClave.classList.add("fw-bold", "text-end", "bg-light");
celdaClave.style.width = "45%"; // Aumentamos para dejar más espacio
celdaClave.style.paddingRight = "1rem";
celdaClave.style.whiteSpace = "nowrap";
celdaClave.textContent = key;
const celdaValor = document.createElement("td");
celdaValor.classList.add("text-start");
celdaValor.style.width = "55%";
celdaValor.style.paddingLeft = "1rem";
celdaValor.textContent = formatearValor(key, value);
fila.appendChild(celdaClave);
fila.appendChild(celdaValor);
tabla.appendChild(fila);
}
return tabla;
}
function formatearValor(key, valor) {
if (!valor) return "";
// Fechas (YYYY-MM-DD)
if (/fecha/i.test(key) && /^\d{4}-\d{2}-\d{2}/.test(valor)) {
const fecha = new Date(valor);
if (!isNaN(fecha)) {
return fecha.toLocaleDateString("es-MX", {
day: '2-digit',
month: 'long',
year: 'numeric'
}).replace(/^(\d+)\sde\s(\w+)\sde\s(\d{4})$/, (_, d, m, y) => `${d}-${m.charAt(0).toUpperCase() + m.slice(1)}-${y}`);
}
}
// Monto / dinero
if (/monto|precio|cuota|total|costo|pago|importe/i.test(key)) {
const num = parseFloat(valor);
if (!isNaN(num)) {
return num.toLocaleString('es-MX', {
style: 'currency',
currency: 'MXN',
minimumFractionDigits: 2
});
}
}
return valor;
}
function inicializarTwilio() {
fetch('{Servidor}/Twilio/example/token.php')
.then(response => response.json())
.then(data => {
device = new Twilio.Device(data.token, { debug: true });
device.on('ready', () => {
actualizarEstado('Listo para llamar');
});
device.on('error', (error) => {
actualizarEstado(`Error: ${error.message}`);
});
device.on('connect', (conn) => {
currentConnection = conn;
conn.on('disconnect', () => currentConnection = null);
});
device.on('disconnect', () => currentConnection = null);
})
.catch(err => {
actualizarEstado('Error al obtener token');
console.error(err);
});
}
function realizarLlamada() {
const numero = document.getElementById("numero_llamar").value;
if (!device) {
alert("Dispositivo aún no inicializado.");
return;
}
fetch('{Servidor}/Twilio/example/voice.php', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `To=+52${encodeURIComponent(numero)}`
}).then(() => {
device.connect();
callStartTime = new Date();
durationInterval = setInterval(actualizarDuracion, 1000);
actualizarEstado('En llamada');
document.getElementById("llamar").disabled = true;
}).catch(err => {
console.error("Error al enviar número al backend:", err);
alert("No se pudo iniciar la llamada.");
});
}
function colgarLlamada() {
if (device) device.disconnectAll();
callStartTime = null;
clearInterval(durationInterval);
document.getElementById("duracion_llamada").textContent = '00:00';
actualizarEstado('Desconectado');
document.getElementById("llamar").disabled = false;
}
function toggleMute() {
if (!currentConnection) return;
const localStream = currentConnection.mediaStream?.stream;
if (localStream) {
const audioTrack = localStream.getAudioTracks()[0];
if (audioTrack) {
isMuted = !isMuted;
audioTrack.enabled = !isMuted;
actualizarEstado(isMuted ? "Silenciado (micrófono apagado)" : "En llamada");
}
}
}
function agregarNumero(digito) {
const input = document.getElementById("numero_llamar");
input.value += digito;
}
function borrarUltimoDigito() {
const input = document.getElementById("numero_llamar");
input.value = input.value.slice(0, -1);
}
function llenarNumero(numero) {
document.getElementById("numero_llamar").value = numero;
}
function borrarTodoNumero() {
document.getElementById("numero_llamar").value = '';
}
window.addEventListener('DOMContentLoaded', () => {
inicializarTwilio();
});
document.addEventListener("DOMContentLoaded", () => {
cargarContactos();
});
< /code>
В разделе Twilio API у меня есть два файла настроены. Первый - это "token.php", где настроено соединение: < /p>
< /code>
и, наконец, "vicom.php", где выполняется запрос на подключение вызова. Оба файла существуют на одном уровне API: < /p>
No se proporcionó un número para llamar.
< /code>
Главное, что мне нужно исправить, - это микрофон, не приглушенный, но я открыт для любых других улучшений кода, которые вы можете предложить. Спасибо за помощь!
Подробнее здесь: https://stackoverflow.com/questions/796 ... wilio-call
Не может отключить микрофон на вызове Twilio ⇐ Javascript
Форум по Javascript
-
Anonymous
1750982037
Anonymous
Я внедряю экран для звонков из службы Twilio: < /p>
На данный момент вызовы Connect Connect, и я могу повесить трубку. Проблема в том, что я не могу отключить микрофон или вызов (кнопка ничего не делает), и «Статус (эстадо)» текст обновляется только от «Отключить (desconectado)» до «по вызову (en llamada.)». Вот код фронта: < /p>
Llamadas en linea
#contenido_cliente table td {
vertical-align: top;
padding: 0.25rem 0.5rem;
}
#contenido_cliente td {
padding: 4px 8px;
vertical-align: top;
}
Llamadas en linea
Llamadas Telefónicas
Número a llamar
Llamar
Colgar
Silenciar
[b]Estado:[/b] Desconectado
[b]Duración:[/b] 00:00
1
2
3
4
5
6
7
8
9
*
0
#
Borrar último
Borrar todo
Nombre
Celular
Estatus numero
Información del Cliente
Seleccione un contacto para ver los detalles.
< /code>
Вот скрипт: < /p>
let device;
let currentConnection;
let isMuted = false;
let callStartTime;
let durationInterval;
function actualizarEstado(estado) {
document.getElementById("estado_llamada").textContent = estado;
}
function actualizarDuracion() {
if (!callStartTime) return;
const now = new Date();
const diff = Math.floor((now - callStartTime) / 1000);
const minutes = String(Math.floor(diff / 60)).padStart(2, '0');
const seconds = String(diff % 60).padStart(2, '0');
document.getElementById("duracion_llamada").textContent = `${minutes}:${seconds}`;
}
let listaContactos = [];
function cargarContactos() {
fetch('php/llamadas.php?accion=contactos')
.then(res => res.json())
.then(clientes => {
listaContactos = clientes; // Guardamos para filtrar después
renderizarContactos(clientes);
})
.catch(err => {
console.error("Error al cargar contactos:", err);
});
}
function renderizarContactos(clientes) {
const tabla = document.getElementById("tabla_contactos");
tabla.innerHTML = "";
const agrupado = {};
// Agrupar por ID_Cliente
clientes.forEach(c => {
if (!agrupado[c.ID_Cliente]) {
agrupado[c.ID_Cliente] = [];
}
agrupado[c.ID_Cliente].push(c);
});
// Dibujar por cada grupo
Object.values(agrupado).forEach(grupo => {
grupo.forEach(c => {
const fila = document.createElement("tr");
fila.style.cursor = "pointer";
let numero = '';
let etiqueta = '';
if (c.Estatus === "1") {
numero = c.Telefono;
etiqueta = 'Actual';
} else if (c.Estatus === "0") {
numero = c.Telefono;
etiqueta = 'Anterior';
} else {
numero = c.Celular;
etiqueta = ''; // Sin etiqueta visible
}
// Acción al hacer clic
fila.addEventListener("click", () => seleccionarNumero(numero));
fila.innerHTML = `
${c.NombreCompleto}
${numero}
${etiqueta}
`;
tabla.appendChild(fila);
});
});
if (tabla.innerHTML.trim() === "") {
const fila = document.createElement("tr");
fila.innerHTML = `Información del cliente no disponible`;
tabla.appendChild(fila);
}
}
function filtrarContactos() {
const filtro = document.getElementById("filtro_contactos").value.toLowerCase();
const filtrados = listaContactos.filter(c =>
c.NombreCompleto.toLowerCase().includes(filtro)
);
renderizarContactos(filtrados);
}
function seleccionarNumero(numero) {
document.getElementById("numero_llamar").value = numero;
const contenedor = document.getElementById("contenido_cliente");
contenedor.innerHTML = `Cargando información del cliente...`;
fetch(`php/llamadas.php?accion=reporte_contratos&telefono=${numero}`)
.then(res => res.json())
.then(data => {
if (!Array.isArray(data) || data.length === 0) {
contenedor.innerHTML = `Información del cliente no disponible.`;
return;
}
contenedor.innerHTML = ""; // Limpiar contenido
// Si hay más de un contrato, usar pestañas
if (data.length > 1) {
const navTabs = document.createElement("ul");
navTabs.classList.add("nav", "nav-tabs");
navTabs.role = "tablist";
const tabContent = document.createElement("div");
tabContent.classList.add("tab-content");
data.forEach((contrato, index) => {
const contratoId = contrato.ID_Contrato || `Contrato ${index + 1}`;
const tabId = `contrato-${index}`;
// Crear pestaña
const tab = document.createElement("li");
tab.classList.add("nav-item");
tab.innerHTML = `
[url=#${tabId}]${contratoId}[/url]
`;
navTabs.appendChild(tab);
// Crear contenido de la pestaña
const tabPane = document.createElement("div");
tabPane.classList.add("tab-pane", "fade");
if (index === 0) {
tabPane.classList.add("show", "active");
}
tabPane.id = tabId;
tabPane.role = "tabpanel";
tabPane.appendChild(crearTablaCliente(contrato));
tabContent.appendChild(tabPane);
});
contenedor.appendChild(navTabs);
contenedor.appendChild(tabContent);
} else {
// Solo un contrato
contenedor.appendChild(crearTablaCliente(data[0]));
}
})
.catch(err => {
console.error("Error al obtener reporte del cliente:", err);
contenedor.innerHTML = `Ocurrió un error al obtener la información del cliente.`;
});
}
function crearTablaCliente(data) {
const tabla = document.createElement("table");
tabla.classList.add("table", "table-bordered", "table-sm", "mb-0", "w-100");
tabla.style.tableLayout = "fixed";
for (const [key, value] of Object.entries(data)) {
const fila = document.createElement("tr");
const celdaClave = document.createElement("td");
celdaClave.classList.add("fw-bold", "text-end", "bg-light");
celdaClave.style.width = "45%"; // Aumentamos para dejar más espacio
celdaClave.style.paddingRight = "1rem";
celdaClave.style.whiteSpace = "nowrap";
celdaClave.textContent = key;
const celdaValor = document.createElement("td");
celdaValor.classList.add("text-start");
celdaValor.style.width = "55%";
celdaValor.style.paddingLeft = "1rem";
celdaValor.textContent = formatearValor(key, value);
fila.appendChild(celdaClave);
fila.appendChild(celdaValor);
tabla.appendChild(fila);
}
return tabla;
}
function formatearValor(key, valor) {
if (!valor) return "";
// Fechas (YYYY-MM-DD)
if (/fecha/i.test(key) && /^\d{4}-\d{2}-\d{2}/.test(valor)) {
const fecha = new Date(valor);
if (!isNaN(fecha)) {
return fecha.toLocaleDateString("es-MX", {
day: '2-digit',
month: 'long',
year: 'numeric'
}).replace(/^(\d+)\sde\s(\w+)\sde\s(\d{4})$/, (_, d, m, y) => `${d}-${m.charAt(0).toUpperCase() + m.slice(1)}-${y}`);
}
}
// Monto / dinero
if (/monto|precio|cuota|total|costo|pago|importe/i.test(key)) {
const num = parseFloat(valor);
if (!isNaN(num)) {
return num.toLocaleString('es-MX', {
style: 'currency',
currency: 'MXN',
minimumFractionDigits: 2
});
}
}
return valor;
}
function inicializarTwilio() {
fetch('{Servidor}/Twilio/example/token.php')
.then(response => response.json())
.then(data => {
device = new Twilio.Device(data.token, { debug: true });
device.on('ready', () => {
actualizarEstado('Listo para llamar');
});
device.on('error', (error) => {
actualizarEstado(`Error: ${error.message}`);
});
device.on('connect', (conn) => {
currentConnection = conn;
conn.on('disconnect', () => currentConnection = null);
});
device.on('disconnect', () => currentConnection = null);
})
.catch(err => {
actualizarEstado('Error al obtener token');
console.error(err);
});
}
function realizarLlamada() {
const numero = document.getElementById("numero_llamar").value;
if (!device) {
alert("Dispositivo aún no inicializado.");
return;
}
fetch('{Servidor}/Twilio/example/voice.php', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `To=+52${encodeURIComponent(numero)}`
}).then(() => {
device.connect();
callStartTime = new Date();
durationInterval = setInterval(actualizarDuracion, 1000);
actualizarEstado('En llamada');
document.getElementById("llamar").disabled = true;
}).catch(err => {
console.error("Error al enviar número al backend:", err);
alert("No se pudo iniciar la llamada.");
});
}
function colgarLlamada() {
if (device) device.disconnectAll();
callStartTime = null;
clearInterval(durationInterval);
document.getElementById("duracion_llamada").textContent = '00:00';
actualizarEstado('Desconectado');
document.getElementById("llamar").disabled = false;
}
function toggleMute() {
if (!currentConnection) return;
const localStream = currentConnection.mediaStream?.stream;
if (localStream) {
const audioTrack = localStream.getAudioTracks()[0];
if (audioTrack) {
isMuted = !isMuted;
audioTrack.enabled = !isMuted;
actualizarEstado(isMuted ? "Silenciado (micrófono apagado)" : "En llamada");
}
}
}
function agregarNumero(digito) {
const input = document.getElementById("numero_llamar");
input.value += digito;
}
function borrarUltimoDigito() {
const input = document.getElementById("numero_llamar");
input.value = input.value.slice(0, -1);
}
function llenarNumero(numero) {
document.getElementById("numero_llamar").value = numero;
}
function borrarTodoNumero() {
document.getElementById("numero_llamar").value = '';
}
window.addEventListener('DOMContentLoaded', () => {
inicializarTwilio();
});
document.addEventListener("DOMContentLoaded", () => {
cargarContactos();
});
< /code>
В разделе Twilio API у меня есть два файла настроены. Первый - это "token.php", где настроено соединение: < /p>
< /code>
и, наконец, "vicom.php", где выполняется запрос на подключение вызова. Оба файла существуют на одном уровне API: < /p>
No se proporcionó un número para llamar.
< /code>
Главное, что мне нужно исправить, - это микрофон, не приглушенный, но я открыт для любых других улучшений кода, которые вы можете предложить. Спасибо за помощь!
Подробнее здесь: [url]https://stackoverflow.com/questions/79681280/cannot-mute-microphone-on-twilio-call[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия