JTAPI. El API de Telefonía para Java

9
30749

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:

  1. Realizar llamadas.
  2. Contestar llamadas.
  3. Capturar llamadas que están sonando en un determinado terminal.
  4. Realizar conferencias.
  5. Realizar transferencias tanto directas como indirectas.
  6. Realizar llamadas predictivas.
  7. Retener llamadas.
  8. Redireccionar llamadas.
  9. Recuperar llamadas retenidas.
  10. Obtener información de las llamadas en curso.
  11. Asociar datos a llamadas.
  12. Gestionar grupos de teleoperadores (agentes).
  13. Logar/deslogar a agentes en grupos.
  14. Gestionar las rutas por las que pasará la llamada.
  15. Gestionar la pantalla y el teclado de los dispositivos telefónicos.

Estructuración de JTAPI

JTAPI está estructurado en los siguientes paquetes:

  1. Core
  2. CallControl
  3. CallCenter
  4. Phone

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.

  1. Realizar, finalizar y contestar llamadas.
  2. Obtener el estado en el que se encuentran el proveedor, las llamadas, los componentes de la llamada.
  3. Obtener los terminales y direcciones que forman parte del dominio del entorno telefónico.
  4. 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:

  1. Transferencia de llamadas tanto directas como indirectas.
  2. Realizar conferencias.
  3. Redireccionar llamadas.
  4. Descolgar llamadas que están sonando en otro terminal.
  5. Realizar llamadas de consulta.
  6. Agregar un terminal a una conferencia ya establecida.
  7. Retener y recuperar llamadas.
  8. Estados más finos sobre llamadas, terminales, conexiones, direcciones, etc.
  9. 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:

  1. Operaciones con grupos de agentes (consultar y modificar).
  2. Obtener información de llamdas por grupo de agentes (teleoperadores, etc.).
  3. Consultar estados de agentes.
  4. Asociar datos (objetos) a llamadas.
  5. 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:

  1. Consultar y modificar la pantalla, el volumen y los indicadores luminosos de un terminal.
  2. Pulsar los botones del teclado del terminal.
  3. 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

9 COMENTARIOS

  1. 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.

  2. 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

  3. 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

  4. 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.

  5. 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.

  6. 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

  7. 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

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad