Interactuando con un servidor Asterisk desde una aplicación Java a través de la Interfaz de Administración de Asterisk (AMI)
Si recién está comenzando a investigar en esta área, la interacción con este servidor puede parecerle algo confusa, como alguna vez me pareció.
Para no buscar los bits de información necesarios en los foros al estilo de respuesta a preguntas, adjunto un pequeño tutorial sobre cómo interactuar con el servidor Asterisk de Java.
Importante: supongo que una vez que haya alcanzado la etapa de escribir el código, entonces ya tiene un servidor Asterisk en funcionamiento al que puede acceder.1) ¿Qué elegir para que sea conveniente trabajar?Definitivamente - Asterisk Managment Interface (AMI): esta interfaz tiene una gama completa de funciones que le permiten hacer una llamada, escuchar eventos en tiempo real desde el servidor, recibir un estado de llamada e interrumpirlo si es necesario.
2) ¿Qué biblioteca conectar?Este:
<dependency> <groupId>org.asteriskjava</groupId> <artifactId>asterisk-java</artifactId> <version>2.0.4</version> </dependency>
3) ¿Qué configuraciones se deben ver en el servidor?extensions.conf: la configuración que describe el diaplan. Estarás constantemente en contacto con él. Si está en un lenguaje más comprensible, contiene scripts de lo que hará el servidor cuando reciba una llamada a un número específico. Primero, se busca un contexto específico en el diaplan: se escribe entre corchetes, después de lo cual se busca un número bajo la etiqueta de este contexto con el que se está contactando.
manager.conf - config con usuario y contraseña para su servidor Asterisk
El contenido de esta configuración debe ser aproximadamente el siguiente:
[user_name] secret = password read = all write = all deny=0.0.0.0/0.0.0.0 permit=0.0.0.0/255.255.255.0
- nombre_usuario - nombre de usuario
- secreto - contraseña para ello
- denegar: direcciones IP a las que se les niega el acceso bajo este usuario
- permiso: acceso al cual está permitido. Asegúrese de especificar la IP con la que está contactando en el permiso, ya que el aster puede rechazar su solicitud.
sip.conf: todas las troncales están registradas aquí. Una troncal es un teléfono desde el cual llamaremos a un cliente.
4) ¿Dónde comenzar a escribir código?Hay dos opciones: debe realizar alguna acción en el servidor Asterisk o escuchar eventos en el servidor. Nuestra secuencia incluye ambos.
Describimos el plan de acción:
- Abra la conexión al servidor;
- Describimos el escenario de trabajo;
- Escuchamos eventos;
- Cierra la conexión.
En consecuencia, la conexión se inicializa durante la creación del objeto DefaultAsteriskServer:
import org.asteriskjava.live.AsteriskServer; import org.asteriskjava.live.DefaultAsteriskServer;
AsteriskServer asteriskServer = new DefaultAsteriskServer(HOSTNAME, USERNAME, PASSWORD); asteriskServer.initialize();
Después de abrir la conexión, debemos llamar al usuario. Llamaremos a esto un escenario de acción. La descripción del escenario estará en una clase separada:
public class ScenarioCall extends OriginateAction { private final Logger log = LoggerFactory.getLogger(ScenarioCall.class); private String TRUNK; private final String PHONE_FOR_RINGING; private final String EXTEN_FOR_APP; private final String CONTEXT_FOR_APP; public ScenarioCall(String trunk, String phoneForRinging, String extension, String context) { this.TRUNK = trunk; this.PHONE_FOR_RINGING = phoneForRinging; this.EXTEN_FOR_APP = extension; this.CONTEXT_FOR_APP = context; this.init(); } private void init() {
¿Qué necesitamos entender en este escenario? Primero, se crea una conexión troncal. Una troncal es el número desde el cual llamará al suscriptor. Después de eso, se crea una conexión entre la troncal y el suscriptor, después de eso, la conexión entre el suscriptor y quién más necesita está allí.
Está en ese orden.
this.setContext(CONTEXT_FOR_APP)
El valor transmitido: el contexto en el que buscaremos el número de teléfono con el que desea asociar al suscriptor (desde extensiones.conf).
this.setExten(EXTEN_FOR_APP)
Valor transmitido: el script que se ejecutará después de contactar al suscriptor (desde extensiones.conf).
this.setCallerId(callId)
Valor transmitido: el número de nuestro suscriptor
this.setChannel(channelAsterisk)
Valor transmitido: canal de comunicación establecido, por lo general se ve así: trunk_name / phone_user.
¿Dónde buscar trunk_name? Hay una configuración sip.conf en el servidor de asterisco: todas las troncales están registradas allí.
Crea una llamada:
if (asteriskServer .getManagerConnection().getState().equals(ManagerConnectionState.CONNECTED) || asteriskServer .getManagerConnection().getState().equals(ManagerConnectionState.CONNECTING) || asteriskServer .getManagerConnection().getState().equals(ManagerConnectionState.INITIAL)) { try { ScenarioCall scenarioCall = new ScenarioCall(trank, phone, extension, context); CallBack callBackForScenarioCall = new CallBack(); asteriskServer.originateAsync(scenarioCall, callBackForScenarioCall); } catch (ManagerCommunicationException e) {
Creamos una llamada, pero ¿cómo rastrearla dinámicamente?
Se hacen dos cosas para esto: se pasa una instancia de la clase CallBack en el método originateAsync
y se cuelga un oyente en el servidor, que fusionará todo lo que nos suceda.
Se necesita un oyente porque la clase CallBack no le notificará el final de la llamada cuando el usuario ya ha hablado, ni le notificará que el usuario aún podría transferirse a otro lugar.
public class CallBack implements OriginateCallback { private ChannelState resultCall = ChannelState.PRERING; @Override public void onDialing(AsteriskChannel asteriskChannel) {
¿Cómo colgar a un oyente en un asterisco?Para hacer esto, cree una clase de implementación AsteriskServerListener, PropertyChangeListener.
Para la conexión creada, a través de una instancia de la clase AsteriskConnection, implementamos:
this.asteriskConnection.addAsteriskServerListener(this.callBackEventListener);
this.callBackEventListener: una instancia de nuestra clase de escucha, nacida de:
** * Asterisk * PropertyChangeListener , . * AsteriskServerListener , AsteriskConnection. */ public class CallBackEventListener implements AsteriskServerListener, PropertyChangeListener { public void onNewAsteriskChannel(AsteriskChannel channel) { channel.addPropertyChangeListener(this); } public void onNewMeetMeUser(MeetMeUser user) { user.addPropertyChangeListener(this); } public void onNewQueueEntry(AsteriskQueueEntry user) { user.addPropertyChangeListener(this); } public void onNewAgent(AsteriskAgent asteriskAgent) { asteriskAgent.addPropertyChangeListener(this); } public void propertyChange(PropertyChangeEvent propertyChangeEvent) { findEventEndCall(propertyChangeEvent); } private void findEventEndCall(PropertyChangeEvent event) { if (event.getSource() instanceof AsteriskChannel) { AsteriskChannel callBackChannel = (AsteriskChannel) event.getSource(); String callId = getStringWithOnlyDigits(callBackChannel.getCallerId().toString()); callId = ValidValues.getValidCallId(callId); if (callBackChannel.getState().toString().equals("HUNGUP") && event.getOldValue().toString().contains("RINGING")) {
Le aconsejo al principio que solo se comprometa, lo que viene a propertyChange y mire PropertyChangeEvent, será un montón de todo lo que sucede en el servidor. No filtra la información en absoluto. Por lo tanto, la conclusión: cuelgue al oyente lo menos posible. No para cada llamada, porque puedo hacerlo incluso en la clase OriginateCallback, por lo que encontré. Esto es inútil Mira qué objetos PropertyChangeEvent te llegan, mira el tipo de campos allí y cuáles necesitas. A continuación, bienvenido al mundo del procesamiento de la información.
Un poco sobre validación de datos.
En OriginateAction.setChannel - se pasa el nombre del tronco / usuario del teléfono
phone_user: si es ruso, debe comenzar con una cifra de ocho, si el número internacional tiene un signo más.
En OriginateAction.setCallerId: el número de teléfono del cliente se transmite,
luego en CallBackEventListener vendrá en callBackChannel.getCallerId ().
Lo tomaré así:
String callId = getStringWithOnlyDigits(callBackChannel.getCallerId().toString());
Al final, no te olvides de:
asteriskServer.shutdown();
Si necesita interrumpir cualquier llamada, en la clase CallBackEventListener
al canal de comunicación existente que realizamos:
callBackChannel.hangup();
Un tutorial tan simple resultó. A primera vista, por supuesto, es muy simple, pero créanme, toma mucho tiempo y nervios encontrar información, posponer todos los métodos y dejar de funcionar.
¡Buena suerte con tus servidores Asterisk!
Lectura adicional:
1)
Tutorial Asterisk-Java2)
Interfaz de gestión de asterisco (AMI)