En mi vida profesional estuve varios años trabajando en el departamento de investigación y desarrollo de una empresa de telefonía. En este tutorial, voy a brindar al lector
con conocimientos básicos de JTAPI una serie de ejemplos que le orienten y sirvan de base para realizar sus pruebas en su plataforma telefónica.
Este tutorial no es teórico, en caso de querer aprender acerca de este tema, recomiendo que se lea la especificación pues es bastante clara y fácil de comprender.
Introducción
En el mundillo Java, JTAPI es a la telefonía lo que JDBC es a las bases de datos.
Al igual que JDBC, JTAPI es una especificación (no una implementación) definida por Sun para el desarrollo de aplicaciones CTI en el lenguaje de programación Java.
¿Para que sirve JTAPI?
Su principal uso se da en aquellos entornos donde se requiere una programación de sistemas telefónicos. Por ejemplo, en los centros de llamadas a través
de los cuales las empresas realizan tareas de atención al cliente, telemarketing, etc.
¿Qué puedo hacer con JTAPI?
Entre otras muchas cosas podrá hacer las siguientes tareas:
- Realizar llamadas.
- Contestar llamadas.
- Capturar llamadas que están sonando en un determinado terminal.
- Realizar conferencias.
- Realizar transferencias tanto directas como indirectas.
- Realizar llamadas predictivas.
- Retener llamadas.
- Redireccionar llamadas.
- Recuperar llamadas retenidas.
- Obtener información de las llamadas en curso.
- Asociar datos a llamadas.
- Gestionar grupos de teleoperadores (agentes).
- Logar/deslogar a agentes en grupos.
- Gestionar las rutas por las que pasará la llamada.
- Gestionar la pantalla y el teclado de los dispositivos telefónicos.
Estructuración de JTAPI
JTAPI está estructurado en los siguientes paquetes:
Paquete Core
Bajo este paquete se incluyen las clases que aportan la funcionalidad básica que debe implementar un sistema telefónico para decir que implementa JTAPI.
- Realizar, finalizar y contestar llamadas.
- Obtener el estado en el que se encuentran el proveedor, las llamadas, los componentes de la llamada.
- Obtener los terminales y direcciones que forman parte del dominio del entorno telefónico.
- Poner oyentes a las llamadas, terminales, proveedor, etc. para que se nos avise mediante la invocación de un método que ha sucedido algo. Por ejemplo la llamada a finalizado, o el proveedor ha dejado de estar en servicio.
Ejemplo: Realización de una llamada telefónica.
package com.autentia.tutoriales.jtapi; import javax.telephony.*; /** * Realiza una llamada telefónica desde un origen a un destino. * @author Carlos García. Autentia */ public class RealizarLlamadaApp { /** * @param args Origen y destino de la llamada */ public static void main(String[] args){ Provider prov = null; // Verificamos los argumentos (número de teléfono de origen y destino) if ( args.length != 2 ){ System.out.println("Formato:\"RealizarLlamadaApp\""); return; } try { // Obtenemos una instancia que implemente javax.telephony.JtapiPeer. JtapiPeer peer = JtapiPeerFactory.getJtapiPeer(null); // Obtenemos un proveedor que de el servicio prov = peer.getProvider(null); // Instanciamos y configuramos los objetos necesarios para la llamada Terminal term = prov.getTerminal(args[0]); // Creamos un objeto llamada Call call = prov.createCall(); // Realizamos una llamada call.connect(term, term.getAddresses()[0], args[1]); } catch ( Exception e ){ System.out.println(e.toString()); } finally { try { prov.shutdown(); // Finalizamos el proveedor } catch (Exception ex){} } } }
Ejemplo: Descolgado automático de todas las llamadas que suenen en un terminal.
import javax.telephony.*; import javax.telephony.TerminalConnection; import javax.telephony.events.CallEv; import javax.telephony.events.TermConnRingingEv; /** * Durante un tiempo, descuelgará todas las llamadas que suenen en un terminal. * @author Carlos García. Autentia */ public class DescolgandoLlamadasApp { public static void main(String args[]) { JtapiPeer peer = null; Provider prov = null; Terminal term = null; CallObserver myObserver = null; try { if (args.length != 1) { System.out.println("Formato \"DescolgandoLlamadasApp\""); return; } // Obtenemos la implementación javax.telephony.JtapiPeer. peer = JtapiPeerFactory.getJtapiPeer(null); // Obtenemos un proveedor que de el servicio. // (Consulte su proveedor para ver los parámetros requeridos para la funcionalidad Core) prov = peer.getProvider(null); // Obtenemos el terminal del cual vamos a descolgar las llamadas. term = prov.getTerminal(args[0]); myObserver = new MiBonitoCallObserver(); term.addCallObserver(myCallObserver); Thread.sleep(21000); // Descuelga las llamadas durante un tiempo term.removeCallObserver(myObserver); } catch (Exception ex) { System.out.println(ex.toString()); } finally { // Finalizamos el proveedor. try { prov.shutdown(); } catch (Exception ex) {} } } } class MiBonitoCallObserver implements CallObserver { public void callChangedEvent(CallEv[] ev) { TerminalConnection tc; for (int i = 0; i < ev.length; i++) { if (ev[i].getID() != TermConnRingingEv.ID){ continue; } try { tc = ((TermConnRingingEv) ev[i]).getTerminalConnection(); tc.answer(); } catch (Exception ex) { // No se dará } } } }
Paquete CallControl
Este paquete extiende el paquete Core, permitiendo la siguiente funcionalidad:
- Transferencia de llamadas tanto directas como indirectas.
- Realizar conferencias.
- Redireccionar llamadas.
- Descolgar llamadas que están sonando en otro terminal.
- Realizar llamadas de consulta.
- Agregar un terminal a una conferencia ya establecida.
- Retener y recuperar llamadas.
- Estados más finos sobre llamadas, terminales, conexiones, direcciones, etc.
- Información del número de teléfono de todos los interlocutores de la llamada.
Ejemplo: Realizar una llamada y transferirla a otro puesto.
import javax.telephony.*; import javax.telephony.events.*; import javax.telephony.callcontrol.*; import javax.telephony.callcontrol.events.*; /** * Ejemplo de transferencias (indirecta) de llamadas * @author Carlos García. Autentia */ public class LlamarYTransferirApp { /** * Realizamos una llamada del terminal 430 al 777 y esperamos que descuelge, posteriormente * realizamos otra llamada del 430 al 555 y el tranferimos la primera llamada */ public static void main(String[] args) { JtapiPeer peer = null; Provider prov = null; CallControlCall call = null; CallControlCall call2 = null; Terminal term = null; TerminalConnection[] tcs = null; Connection[] cons = null; try { peer = JtapiPeerFactory.getJtapiPeer(null); prov = peer.getProvider(null); term = prov.getTerminal("430"); call = (CallControlCall) prov.createCall(); call.connect(term, term.getAddresses()[0], "777"); // Esperamos unos segundos en los que debe descolgar. Thread.sleep(8000); call2 = (CallControlCall) prov.createCall(); tcs = call.getConnections()[0].getTerminalConnections(); cons = call2.consult(tcs[0], "555"); call.setTransferController(call.getConnections()[0].getTerminalConnections()[0]); call2.setTransferController(call2.getConnections()[0].getTerminalConnections()[0]); // Realiamos la tranferencia call.transfer(cons[0].getCall()); } catch (Exception e) { System.out.println(e.toString()); } finally { try { // Liberamos recursos prov.shutdown(); } catch (Exception ex){} } } }
Ejemplo: Conferencia de llamadas.
import javax.telephony.*; import javax.telephony.events.*; import javax.telephony.callcontrol.*; import javax.telephony.callcontrol.events.*; /** * Ejemplo de conferencia de llamadas. * @author Carlos García. Autentia */ public class EstablecerConferenciaApp { /** * Pasos: * 1) Llamamos del terminal 555 al 666. * 2) Llamamos del terimnal 555 al 777. * 3) Realizamos la conferencia. */ public static void main(String args[]) { JtapiPeer peer = null; Provider prov = null; CallControlCall call1 = null; CallControlCall call2 = null; Connection[] connections1 = null; Connection[] connections2 = null; TerminalConnection[] tcs = null; try { peer = JtapiPeerFactory.getJtapiPeer(null); prov = peer.getProvider(null); call1 = (CallControlCall) prov.createCall(); connections1 = call1.connect(prov.getTerminal("555"), prov.getAddress("555"), "666"); Thread.sleep(2000); // Realizamos la segunda llamada call2 = (CallControlCall) prov.createCall(); connections2 = call2.connect(prov.getTerminal("555"), prov.getAddress("555"), "777"); Thread.sleep(2000); // Configuramos los controladores de conferencias call1.setConferenceController(connections1[0].getTerminalConnections()[0]); call2.setConferenceController(connections2[0].getTerminalConnections()[0]); ((CallControlTerminalConnection) call1.getConferenceController()).unhold(); // Realizamos la conferencia call1.conference(call2); Thread.sleep(2000); } catch (Exception e) { System.out.println(e.toString()); } finally { try { // Liberamos recursos call1.drop(); call2.drop(); prov.shutdown(); }catch (Exception ex){} } } }
Paquete CallCenter
Este paquete extiende el paquete Core, permitiendo la siguiente funcionalidad:
- Operaciones con grupos de agentes (consultar y modificar).
- Obtener información de llamdas por grupo de agentes (teleoperadores, etc.).
- Consultar estados de agentes.
- Asociar datos (objetos) a llamadas.
- Realizar llamadas predictivas (muy usado en marcadores automáticos).
Ejemplo: Dar de alta a un agente en un grupo.
import javax.telephony.*; import javax.telephony.callcenter.*; /** * Damos de alta al teleoperador "carlos_garcia" en el grupo 150, para ello usará el terminal 555. * @author Carlos García. Autentia */ public class LoggedOnApp { public static void main(String[] args){ JtapiPeer peer = null; CallCenterProvider prov = null; AgentTerminal term = null; ACDAddress[] groups = null; Agent agente = null; try { peer = JtapiPeerFactory.getJtapiPeer(null); prov = (CallCenterProvider) peer.getProvider(null); groups = prov.getACDAddresses(); term = (AgentTerminal) prov.getTerminal("555"); agente = term.addAgent(term.getAddresses()[0], groups[150], Agent.READY, "carlos_garcia", null); } catch ( Exception e ){ System.out.println(e); } finally { try { prov.shutdown(); } catch (Exception ex){} } } }
Ejemplo: Realizamos una llamada telefónica y le asociamos información de negocio.
import javax.telephony.*; import javax.telephony.callcenter.*; /** * Realizamos una llamada y le asociamos datos (cualquier objeto serializable) * @author Carlos García. Autentia */ public class AssingDataToCallApp { public static void main(String[] args) { JtapiPeer peer = null; CallCenterProvider prov = null; CallCenterCall call = null; try { peer = JtapiPeerFactory.getJtapiPeer(null); prov = (CallCenterProvider) peer.getProvider(null); call = (CallCenterCall) prov.createCall(); // Realizamos una llamada call.connect(prov.getTerminal("555"), prov.getAddress("555"), "444"); // Asociamos datos a la llamada call.setApplicationData("En un lugar de la mancha..."); } catch (Exception ex) { System.out.println(ex); } finally { try { // Liberamos recursos prov.shutdown(); } catch (Exception ex){} } } }
Paquete Phone
Este paquete extiende el paquete Core, permitiendo la siguiente funcionalidad:
- Consultar y modificar la pantalla, el volumen y los indicadores luminosos de un terminal.
- Pulsar los botones del teclado del terminal.
- Monitorizar los cambios en la pantalla y detectar pulsaciones de las teclas.
Ejemplo: Pulsación de teclas.
import javax.telephony.*; import javax.telephony.phone.*; /** * Pulsamos la tecla 5 dos veces * @author Carlos García. Autentia */ public class PhoneTerminalPressKeyApp { public static void main(String[] args){ JtapiPeer peer = null; Provider prov = null; Terminal term = null; ComponentGroup[] groups = null; Component[] botones = null; try { peer = JtapiPeerFactory.getJtapiPeer(null); prov = peer.getProvider(null); term = prov.getTerminal("666"); groups = ((PhoneTerminal) term).getComponentGroups(); for ( int i = 0; i < groups.length; i++ ){ if ( "Button".equalsIgnoreCase(groups[i].getDescription())){ botones = groups[i].getComponents(); break; } } PhoneTerminalPressKeyApp.PressKey(botones, "5"); PhoneTerminalPressKeyApp.PressKey(botones, "5"); } catch ( Exception ex ){ System.out.println(ex); } finally { try { prov.shutdown(); } catch (Exception ex){} } } /** * Presiona un tecla por su identificador */ private static void PressKey(Component[] botones, String buttonID){ PhoneButton btn; for ( int i = 0; i < botones.length; i++){ btn = (PhoneButton) botones[i]; if (btn.getName().equalsIgnoreCase(buttonID) ){ btn.buttonPress(); return; } } } }
Referencias
- Especificación JTAPI
- Introducción a JTAPI (PDF en Inglés)
Conclusiones
Comparada con otras APIs de teléfonia, desde mi punto de vista JTAPI gana por goleada en sencillez debido a su diseño orientado a objetos y portabilidad entre plataformas.
En su última versión (1.4) no le falta de nada, eso sí, cada proveedor de telefonía puede o no implementar lo que dice la especificación, para ello primeramente se debería
de preguntar por las capacidades del mismo en relación a cada clase (getCapabilities()).
Un saludo, espero que os haya resultado de ayuda.
Carlos García Pérez. Creador de MobileTest, un complemento educativo para los profesores y sus alumnos.
cgpcosmad@gmail.com
Hola que tal, me gustaría saber la forma en que puedo identificar cuando una llamada se ha contestado satisfactoriamente, o cuando el destinatário no ha contestado la llamada?.
Por cierto, los anteriores ejemplos me parecen muy buenos para las personas como yo que hemos comenzado con la paquetería JTAPI.
Graicas.
Hola \\\»Vainilla\\\».
Si la implementación de JTAPI realizada por el proveedor y la linea (digital) lo permiten.. podrás registrar un oyente y detectar el evento que indique el cambio de estado apropiado…
Saludos
Carlos, cordial saludo:
Me presenta el siguiente error en el momento de ejecutar la aplicación:
javax.telephony.JtapiPeerUnavailableException: JtapiPeer: DefaultJtapiPeer could not be instantiated.
Gracias por tu ayuda.
Manuel
Tengo una pregunta cómo identificar llamadas con jtapi????
Porque me pidieron que hiciera eso y no tengo idea de cómo hacerlo.
Utilizo Netbeans y Java.
Por favor una ayuda no me vendría mal.
Hola
Quiero desarrollar una aplicacion en la que pueda identificar el numero de la extension emisora, y grabar la conversacion. Alguna luz sobre como puedo hacer esto con JTAPI?.
Como conecto el codigo con el telefono (Como es la comunicacion entre el telefono y el codigo java, por serial, usb…etc)?
Gracias por tu colaboracion.
Hola, disculpa
necesito desarrollar una aplicacion en la q se tendra q identificar el numero entrante, con eso ya podria hacer el resto del trabajo, porfavor me podrias decir si es posible esto con JTAPI.
gracias de antemano
Hola. Disculpe la molestia pero quiero pedirte ayuda en algo. Soy nueva programando y tengo que realizar un proyecto en .NET y pues quiero saber si esta libreria la puedo utilizar en .NET o tengo que buscar otra y como la puedo implementar
se puede identificar el numero de telefono que hace la llamada?
alguien sabe como hacer los import? yo se como obtener el numero de la llamada entrante