Interagindo com um servidor Asterisk a partir de um aplicativo java através da Interface de Gerenciamento do Asterisk (AMI)
Se você está apenas começando uma pesquisa nessa área, a interação com este servidor pode parecer um pouco confusa, como me pareceu uma vez.
Para não procurar as informações necessárias nos fóruns no estilo de resposta-pergunta, estou anexando um pequeno tutorial sobre como interagir com o servidor Asterisk a partir de java.
Importante: Presumo que, uma vez que você tenha atingido o estágio de escrever código, já tenha um servidor Asterisk que possa acessar.1) O que escolher para facilitar o trabalho?Definitivamente - AMI (Asterisk Managment Interface): essa interface possui uma gama completa de funções que permitem fazer uma chamada, ouvir eventos em tempo real do servidor, receber um status de chamada e interrompê-lo, se necessário.
2) Qual biblioteca conectar?Este aqui:
<dependency> <groupId>org.asteriskjava</groupId> <artifactId>asterisk-java</artifactId> <version>2.0.4</version> </dependency>
3) Quais configurações precisam ser exibidas no servidor?extensions.conf - a configuração que descreve o diaplan. Você estará constantemente em contato com ele. Se em um idioma mais compreensível, ele conterá scripts sobre o que o servidor fará quando receber uma chamada para um número específico. Primeiro, um contexto específico é pesquisado no diaplan - ele é escrito entre colchetes, após o qual um número é pesquisado sob a tag desse contexto pelo qual você está entrando em contato.
manager.conf - config com usuário e senha para o seu servidor Asterisk
O conteúdo dessa configuração deve ser aproximadamente o seguinte:
[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
- nome_do_usuário - nome de usuário
- segredo - senha para ele
- negar - endereços IP cujo acesso é negado neste usuário
- permissão - acesso ao qual é permitido. Certifique-se de especificar o IP com o qual está entrando em contato, pois o aster pode repelir sua solicitação.
sip.conf - todos os troncos são registrados aqui. Um tronco é um telefone do qual chamaremos um cliente.
4) Por onde começar a escrever código?Existem duas opções: você precisa executar alguma ação no servidor Asterisk ou ouvir eventos no servidor. Nossa sequência inclui ambos.
Descrevemos o plano de ação:
- Abra a conexão com o servidor;
- Nós descrevemos o cenário do trabalho;
- Nós ouvimos eventos;
- Feche a conexão.
Assim, a conexão é inicializada durante a criação do objeto DefaultAsteriskServer:
import org.asteriskjava.live.AsteriskServer; import org.asteriskjava.live.DefaultAsteriskServer;
AsteriskServer asteriskServer = new DefaultAsteriskServer(HOSTNAME, USERNAME, PASSWORD); asteriskServer.initialize();
Depois de abrir a conexão, precisamos ligar para o usuário. Vamos chamar isso de cenário de ação. A descrição do cenário estará em uma classe 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() {
O que precisamos entender nesse cenário? Primeiro, uma conexão de tronco é criada. Um tronco é o número a partir do qual você ligará para o assinante. Depois disso, é criada uma conexão entre o tronco e o assinante; depois, a conexão entre o assinante e quem mais você precisa está lá.
Está nessa ordem.
this.setContext(CONTEXT_FOR_APP)
O valor transmitido: o contexto no qual procuraremos o número de telefone ao qual você deseja associar o assinante (em extensions.conf).
this.setExten(EXTEN_FOR_APP)
Valor transmitido: o script que será executado depois que você entrar em contato com o assinante (a partir de extensions.conf).
this.setCallerId(callId)
Valor transmitido: número do assinante
this.setChannel(channelAsterisk)
Valor transmitido: canal de comunicação estabelecido, geralmente se parece com isso: trunk_name / phone_user.
Onde procurar trunk_name? Há uma configuração sip.conf no servidor asterisk - todos os troncos são registrados lá.
Crie uma chamada:
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) {
Criamos uma chamada, mas como rastrear dinamicamente?
Duas coisas são feitas para isso: uma instância da classe CallBack é passada no método originateAsync
e um ouvinte está pendurado no servidor, que mesclará tudo o que acontece conosco.
Um ouvinte é necessário porque a classe CallBack não notificará você sobre o final da chamada quando o usuário já tiver falado, nem notificará que o usuário ainda pode transferir para outro lugar.
public class CallBack implements OriginateCallback { private ChannelState resultCall = ChannelState.PRERING; @Override public void onDialing(AsteriskChannel asteriskChannel) {
Como pendurar um ouvinte em um asterisco?Para fazer isso, crie uma classe de implementação AsteriskServerListener, PropertyChangeListener.
Para a conexão criada, por meio de uma instância da classe AsteriskConnection, implementamos:
this.asteriskConnection.addAsteriskServerListener(this.callBackEventListener);
this.callBackEventListener - uma instância da nossa classe ouvinte, nascida 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")) {
Aconselho você desde o início, apenas para se comprometer com o que diz respeito ao propertyChange e analisar o PropertyChangeEvent; será um monte de tudo o que acontece no servidor. Ele não filtra informações. Portanto, a conclusão: pendure o ouvinte o mínimo possível. Não é para todas as chamadas, porque isso pode ser feito mesmo na classe OriginateCallback, até onde eu achei. Isso é inútil. Veja quais objetos PropertyChangeEvent chegam até você, veja os tipos de campos e quais você precisa. Próximo - bem-vindo ao mundo do processamento de informações.
Um pouco sobre validação de dados.
Em OriginateAction.setChannel - o nome do tronco / usuário do telefone é passado
phone_user - se for russo, deve começar com um número oito, se o número internacional estiver com um sinal de mais.
Em OriginateAction.setCallerId - o número de telefone do cliente é transmitido,
em CallBackEventListener, ele entrará em callBackChannel.getCallerId ().
Vai ficar assim:
String callId = getStringWithOnlyDigits(callBackChannel.getCallerId().toString());
No final, não esqueça:
asteriskServer.shutdown();
Se você precisar interromper qualquer chamada, na classe CallBackEventListener
para o canal de comunicação existente, realizamos:
callBackChannel.hangup();
Um tutorial tão simples acabou. À primeira vista, é claro, é muito simples, mas acredite, leva muito tempo e nervos para encontrar informações, adiar todos os métodos e sair do trabalho.
Boa sorte com seus servidores Asterisk!
Leitura adicional:
1)
Tutorial Asterisk-Java2)
Interface de gerenciamento de asterisco (AMI)