1. Entendendo melhor o Dialplan
O dialplan é verdadeiramente o coração de qualquer sistema Asterisk, já que define como o Asterisk
manipula os telefonemas que chegam e que são enviados. Em resumo, o dialplan consiste de uma
lista de instruções ou passos que o Asterisk irá seguir. Estes passos são totalmente personalisaveis.
Sintaxe do dialpan
O dialplan do Asterisk é especificado no arquivo de configuração chamado de
/etc/asterisk/extensions.conf.
O dialplan é composto de quatro partes principais: contextos, extensões, prioridades e
aplicações.
Contextos
O dialplan é dividido em seções chamadas de contexto, tais contextos evitam que partes diferentes
do dialplan interajam umas com as outras. Assim, uma extensão (as funções de um grupo) definida
em um contexto é completamente isolada das extensões de outro contexto, a não ser que a interação
seja especificamente permitida.
Os contexto são denotados pela colocação do nome de contexto dentro de colchetes [], por
exemplo, [incoming]. Todas as instruções colocadas depois da definição de um contexto fazem
parte do contexto até que seja definido outro contexto.
Um dos mais importantes usos de contextos é garantir a segurança. Pelo uso correto dos contextos, é
possível permitir a determinadas pessoas acesso a algumas funções que não serão disponibilizadas a
outras.
Extensões
Uma extensão é uma instrução que o Asterisk irá seguir e é incluída dentro de cada contexto. A
extensão é acionada por uma chamada de entrada ou por dígitos sendo discados em um canal. Então
as extensões especificam o que acontece às chamadas enquanto seguem seu caminho pelo dialplan.
A sintaxe para uma extensão é a palavra exten seguida por uma seta formada pelo sinal de igual e
de maior que:
exten =>
Uma extensão completa é formada pelos seguintes componentes:
● O nome (ou número) da extensão;
● A prioridade, na qual cada extensão pode incluir vários passos a ser executado na
chamada;
● Aplicação (ou comando) que executa alguma ação na chamada.
2. Esses três componentes são separados por vírgulas, da seguinte forma:
exten => nome,prioridade,aplicação()
Um simples exemplo:
exten => 123,1,Answer()
Neste exemplo, o nome da extensão é 123, a prioridade é 1 e a aplicação é Answer().
O nome da extensão. Quando lidamos com sistemas telefônicos, temos a tendência de usar
números que devemos digitar para fazer outro telefone tocar, mas no Asterisk é possível fazer
muito mais, tal como colocar nomes.
Prioridades
Cada extensão pode ter vários passos, chamados de prioridades. Cada prioridade é numerada
seqüencialmente e cada prioridade executa uma aplicação específica. Por exemplo, a seguinte
extensão pode responder a uma chamada (na prioridade 1) e então desligar (na prioridade 2):
exten => 123,1,Answer()
exten => 123,2,Hangup()
Atenção as prioridades devem iniciar em 1 e são numeradas consecutivamente. Caso uma
prioridade fique fora de ordem numérica o Asterisk não continua depois dela.
As versões mais recentes do Asterisk, a partir da 1.2, é possível usar um truque para enumerar as
prioridades, como por exemplo usar o “n” que indica a próxima, ou seja, cada vez que o
Asterisk achar um “n” ele pega o número da prioridade anterior e acrescenta mais 1. Por exemplo:
exten => 123,1,Answer()
exten => 123,n,faça alguma coisa
exten => 123,n,faça outra coisa
exten => 123,n,Hangup()
É possível ainda acrescentar textos as prioridades, por exemplo:
exten => 123,n(texto),faça algo.
Aplicações
As aplicações são os cavalos de batalha do dialplan. Cada aplicação executa uma ação
específica no canal em questão, tal como emitir um som, aceitar uma entrada toquetom ou desligar
a chamada. Algumas aplicações precisam de argumentos a serem passados juntos com as aplicações
para determinar como devem executar suas ações. Para passar argumentos às aplicações,
coloqueos entre os parênteses que se seguem ao nome da aplicação, separados por vírgulas.
3. Um simples exemplo de dialplan
Vamos criar um dialplan simples para entender como este funciona. Em nosso exemplo iremos criar
um diaplan para que quando a chamada chegar, o Asterisk irá responder à chamada, tocar um
arquivo de som e então desligar a chamada.
Antes de iniciar o dialplan, nós devemos explicar sobre uma extensão especial chamada de
extensão “s”, quando as chamadas entram num contexto sem uma extensão
específ ica de destino (por exemplo, uma linha FXO chamado), elas são automaticamente
manipuladas pela extensão “s”. O “s” indica início (start).
Nosso dialplan irá iniciar com a extensão “s” e executaremos três ações: responder, tocar um
arquivo de som e desligar:
[incoming]
exten => s,1,Answer()
exten => s,2,Playback(hello-world)
exten => s,3,Hangup()
A aplicação Answer() é utilizada para responder a um canal que está chamando, isso faz a
configuração inicial do canal que recebe a chamada que está entrando, Answer() não tem
argumentos.
A aplicação Playback() é utilizada para tocar um arquivo de som previamente gravado
sobre um canal. Ao utilizar a aplicação Playback() a entrada do usuário é simplesmente
ignorada. Para utilizar o Playback(), especifique um nome de arquivo sem extensão como
argumento, por exemplo, Playback(musica) que fará tocar musica.gsm. O Asterisk vem
com muitos arquivos de som profissionalmente gravados, que podem ser encontrados no diretório
de som usualmente /var/lib/asterisk/sounds.
A aplicação Hangup() desliga o canal ativo e quem está chamando recebe uma indicação que
a chamada foi desligada, devese utilizar essa aplicação ao final do contexto quando quiser terminar
a atual ligação para assegurar que o dialplan não continuará sendo utilizado. Essa aplicação não tem
argumento.
O dialplan até agora não tem muita utilidade é mais para entender a teoria e testes, caso os canais
estejam configurados é possível testálo. Vamos tornar o dialplan mais dinâmico.
Aplicações Background() e Goto()
Uma chave importante para montar sistemas Asterisk interativos é aplicação
Background(), que funciona da mesma forma que a Playback(), mas na Background()
quando o chamador pressionar uma tecla, ou uma série de teclas, em seu telefone, ela interrompe a
música (ou um som qualquer, exemplo um menu de voz) e vai para a extensão que
corresponder ao(s) dígito(s) pressionado(s). Se o chamador pressiona o 5, por exemplo, o
Asterisk irá para de tocar o arquivo de som e enviar o controle da chamada para a primeira
prioridade de extensão 5.
4. exten =>123,1,Background(hello-world)
O uso mais comum da aplicação Background() é criar menus de vozes, freqüentemente
chamados de autoatendentes). Muitas empresas criam menus de vozes para dirigir as chamadas
para os ramais adequados, aliviando, assim seus recepcionistas a cada chamada.
Outra aplicação útil é Goto(), que é usada para enviar a chamada para outro
contexto, extensão e prioridade. A aplicação Goto() torna fácil se mover
programaticamente uma chamada entre duas partes diferentes do dialplan. A sintaxe para a
aplicação Goto() nos pede que passemos os argumentos do contexto, da extensão e da prioridade
para a aplicação, da seguinte forma:
exten => 123,1,Goto(contexto,extensão,prioridade)
Neste próximo exemplo, iremos tocar o arquivo de amostra de som chamado de vm-enter-num-
to-call.gsm. E depois adicionar duas extensões que serão acionadas pelo chamador ao inserir 1
ou 2 no telefone.
[incoming]
exten => s,1,Answer()
exten => s,2,Background(vm-enter-num-to-call)
exten => 1,1,Playback(digits/1)
exten => 1,2,Goto(incoming,s,1)
exten => 2,1,Playback(digits/2)
exten => 2,2,Goto(incoming,s,1)
Então quando os usuários chamam nosso dialplan, eles vão ouvir uma saudação, e devem inserir um
digito, se eles pressionarem 1, irão ouvir o número 1 e, se pressionarem o número 2, irão ouvir o
número 2. E o Goto() irá fazer tudo ser repetido.
Manipulando entradas inválidas e tempos decorridos
Bem com os exemplos anteriores temos um menu de voz, mas é preciso controlar algumas
anomalias, a primeira é a entrada inválida de um usuário, tal função é feita pela extensão “i”.
Outra situação é quando o usuário não digita uma entrada a tempo (o tempo provisório é
de 10 segundos), estas chamadas devem ser tratadas pela extensão “t” se o chamador demorar a
pressionar um digito depois que Background() tiver terminado de tocar o arquivo de som.
[incoming]
exten => s,1,Answer()
exten => s,2,Background(vm-enter-num-to-call)
exten => 1,1,Playback(digits/1)
exten => 1,2,Goto(incoming,s,1)
exten => 2,1,Playback(digits/2)
exten => 2,2,Goto(incoming,s,1)
exten => i,1,Playback(pbx-invalid)
exten => i,2,Goto(incoming,s,1)
exten => t,1,Playback(vm-goodbye)
exten => t,2,Hangup()
5. Uso da aplicação Dial()
Uma das mais importantes características do Asterisk é sua habilidade para conectar diferentes
chamadores, uns com os outros. Isso é especialmente útil se os chamadores aplicarem diferentes
métodos de comunicação (SIP, H.323, PSTN, etc).
A sintaxe da aplicação Dial() é um pouco mais complexa que as das outras aplicações, já que
utiliza 4 argumentos.
O primeiro argumento é o destino que está tentando chamar, que é feito de uma
tecnologia por meio do qual será feita a chamada, uma barra normal e o recurso remoto
(normalmente um nome ou número de canal). Exemplo:
exten => 123,1,Dial(Zap/1)
Neste exemplo assumimos que queremos chamar um canal ZAP chamando ZAP/1, que é um canal
FXS com um fone analógico conectado. A tecnologia é “Zap” e o recurso é “1”, e o 123 indica que
o Asterisk deve chamar o canal Zap/1 quando forem digitados 123.
Também é possível chamar vários canais ao mesmo tempo:
exten => 123,1,Dial(Zap/1&Zap/2&Zap/3)
A aplicação Dial() irá ligar a chamada a aquele que atender primeiro.
O segundo argumento da aplicação Dial() é o tempo decorrido, especificado em
segundos. Se não for especificado um tempo, o telefone irá continuar tocando até
alguém atender ou que a pessoa chamando desista.
exten => 123,1,Dial(Zap/1,10)
Se a chamada for atendida antes do tempo decorrido, os canais são ligados e o dialplan será
concluído. Se o destino simplesmente não responder, Dial() vai para a próxima prioridade na
extensão. Se, entretanto, o canal de destino estiver ocupado, Dial() irá para a
prioridade n+101, se a prioridade existir (onde n é a prioridade onde a aplicação Dial() foi
chamada). Isso nos permite manipular chamadas não respondidas de maneira diferente das
chamadas cujos destinos estavam ocupados.
exten => 123,1,Dial(Zap/1,10)
exten => 123,2,Playback(vm-nobodavail)
exten => 123,3,Hangup()
exten => 123,102,Playback(tt-allbusy)
exten => 123,103,hangup()
O terceiro argumento de Dial() é uma seqüência opcional, que pode conter um ou
mais caracteres que modificam o comportamento da aplicação Dial(), esta lista é muito grande,
então iremos ver apenas a letra “r” que é a mais usada, esta opção indica que a pessoa que fez a
chamada irá ouvir um tom de chamada enquanto o canal de destino estiver sendo
6. notif icado que está sendo chamado, mas nem sempre isto é necessário, pois o Asterisk pode
automaticamente fazer tal tom.
exten => 123,1,Dial(Zap/1,10,r)
Vamos fazer agora um DialPlan que permita que falemos com John e Jane.
[incoming]
exten => s,1,Answer()
exten => s,2,Background(enter-ext-of-person)
exten => 101,1,Dial(Zap/1,10)
exten => 101,2,Playback(vm-nobodyavail)
exten => 101.3,Hangup()
exten => 101,102,Playback(tt-allbusy)
exten => 102,1,Dial(SIP/Jane,10)
exten => 102,2,Playback(vm-nobodyavail)
exten => 102,3,Hangup()
exten => 102,102,Playback(tt-allbusy)
exten => 102,103,Hangup()
exten => i,1,Playback(pbx-invalid)
exten => i,2,Goto(incoming,s,1)
exten => t,1,Playback(vm-goodbye)
exten => t,2,Hangup()
O quarto e último argumento da aplicação Dial() é um URL, assim, se o canal de
destino tem a capacidade de receber um URL no momento da chamada, a URL especificada será
enviada, este argumento é raramente utilizado.
Qualquer um desses argumento de Dial() podem ser deixados em branco.
exten => 123,1,Dial(Zap/1,,r)
Contexto para tratar as chamadas internas
Bem depois de entender como funciona basicamente o dialplan vamos entender como criar mais de
um contexto e fazer estes interagirem, lembre que é essa uma das funções do dialplan.
Então vamos criar um contexto chamado (ramais) internos e configurar a capacidade desses dois
ramais ligar um para o outro, este novo contexto vai se chamar [internal].
Nós iremos deduzir que já esteja configurado um canal FXS Zap (Zap/1) e um canal FXO (Zap/4)
que utilizam o canal [incoming] e um ou mais canal SIP (SIP/jane), que está configurado no
contexto [internal]
Nosso dialplan vai ser parecer da seguinte forma:
[incoming]
exten => s,1,Answer()
exten => s,2,Background(enter-ext-of-person)
exten => 101,1,Dial(Zap/1,10)
7. exten => 101,2,Playback(vm-nobodyavail)
exten => 101,3,Hangup()
exten => 101,102,Playback(tt-allbusy)
exten => 101,103,Hangup()
exten => 102,1,Dial(SIP/jane,10)
exten => 102,2,Playback(vm-nobodyavail)
exten => 102,3,Hangup()
exten => 102,102,Playback(tt-allbusy)
exten => 102,103,Hangup()
exten => i,1,Playback(pbx-invalid)
exten => i,2,Goto(incoming,s,1)
exten => t,1,Playback(vm-goodbye)
exten => t,2,Hangup()
[internal]
exten => 101,1,Dial(Zap/1,,r)
exten => 102,1,Dial(SIP/jane,,r)
Neste exemplo, foi adicionado duas novas extensões ao contexto [internal]. Dessa forma, a
pessoa que estiver utilizando o canal Zap/1 pode pegar o fone e chamar a pessoa que está no canal
SIP/Jane discando 102. Pela mesma razão, o telefone registrado como SIP/Jane pode chamar Zap/1
discando 101.
Até agora só foi usado três dígitos, mas é possível utilizar até 80 caracteres, ou seja, também é
possível usar letras, é claro que o terminal vai ter de suportar caracteres.
[internal]
exten => 101,1,Dial(Zap/1,,r)
exten => john,1,Dial(Zap/1,,r)
exten => 102,1,Dial(SIP/jane,,r)
exten => jane,1,Dial(SIP/jane,,r)
Uso de variáveis
As variáveis podem ser utilizadas em um dialplan do Asterisk para ajudar a reduzir a
digitação, melhorar a clareza ou acrescentar lógica ao dialplan.
No Asterisk existem duas formas de referenciar uma variável. Para referenciar o nome da variável, é
necessário digitar simplesmente o nome da variável, tal como JOHN. Se, por outro lado for
necessário acessar o valor da variável, devese digitar um símbolo de dólar, abrir uma chave, o nome
da variável e fechar a chave. Exemplo ${JOHN}.
JOHN=Zap/1
exten => 555,1,Dial(${JOHN},,r)
que é igual á:
exten => 555,1,Dial(Zap/1,,r)
Existem três tipos de variáveis no Asterisk: globais, de canal e de ambiente.
8. Variáveis globais: Se aplicam a todas as extensões em todos os contextos, assim, é possível
utilizar as variáveis globais em qualquer lugar do dialplan.
As variáveis globais podem ser declaradas no contexto [globals] no início do arquivo
extensions.conf. Ou podem ser definidas programaticamente, usandose a aplicação
SetGlobalVar().
[globals]
JOHN=ZAP/1
ou
[internal]
exten => 123,1,SetGlobalVar(JOHN=Zap/1)
Variáveis de Canal: É uma variável que é somente associada a uma chamada em
particular, ou seja, são definidas somente na duração da chamada atual e estão disponíveis
somente para o canal que está participando dessa chamada.
As variáveis de canal são definidas por meio da aplicação Set()
exten => 123,1,Set(MAGICNUNBER=42)
Existem variáveis de canal predefinidas em README.variables, mas veremos estas depois.
Variáveis de Ambiente: são uma forma de acesso as variáveis do ambiente UNIX de
dentro do Asterisk. E são referenciadas na forma de ${ENV(variável)}, onde variável é o
nome da variável UNIX.
Adaptação de modelos
Será impossível acrescentar cada possível extensão ao dialplan, especialmente o caso
das chamadas para fora. Imagine um dialplan com uma extensão para todos os números que se pode
discar? Impossível não é!
Felizmente, o Asterisk tem uma forma para solucionar isso: adaptação de modelos, que permite que
se utilize uma seção de código para muitos ramais diferentes.
Sintaxe da adaptação de modelos
Ao utilizar a adaptação de modelos, é necessário utilizar letras e símbolos para representar os
possíveis dígitos que queremos adaptar. Os modelos sempre começam com um sublinhado (_). Isso
diz ao Asterisk que estamos adaptando sobre um modelo, e não um nome de extensão.
Depois do sublinhado, devese utilizar um ou mais dos seguintes caracteres:
X Adapta qualquer dígito de 0 a 9.
Z Adapta qualquer dígito de 1 a 9.
N Adapta qualquer dígito de 2 a 9.
9. [17] Adapta qualquer dígito na faixa indicada. No caso do 1 ao 7.
Para utilizar a adaptação de modelos no dialplan, simplesmente é necessário colocar no lugar do
nome ou número da extensão a adaptação:
exten => _NXX,1,Playback(auth-thankyou)
Neste exemplo, o modelo deve adaptar quaisquer ramais de 3 dígitos de 200 a 999 (lembrese o N
adapta qualquer dígito entre 2 e 9, e cada X entre 0 e 9. Isto que dizer que se um chamador digitou
qualquer ramal de 3 dígitos entre 200 a 999 nesse contexto, ele deverá ouvir o arquivo de som
atuth-tahkyou.gsm.
Se tiver mais do que um modelo que se adapte a chamada (ao ramal discado) o Asterisk utilizará o
mais específico. Digamos que tenhase digitado 5551212:
exten => _555XXXX,1,Playback(digits/1)
exten => _55512,1,Playback(digits/2)
Neste caso, o chamador ouvirá o digito 2
Uso de variável de canal
$(EXTEN)
Bem e se tivermos que saber quais números foram discados em uma adaptação de
contexto? Bem neste caso o Asterisk define a variável de canal ${EXTEN} para os dígitos que
foram discados. Nós podemos usar uma aplicação chamada SayDigits() para testar esta
funcionalidade.
exten => _XXX,1,SayDigits(${EXTEN})
Freqüentemente, é útil se manipular o ${EXTEN} removendo um certo número de dígitos da frente
da extensão. Isto é feito usandose a sintaxe ${EXTEN:x}, onde x ;e o número de dígitos que quer
se remover.
Por exemplo, se o valor de EXTEN é 95551212, então ${EXTEN:1} é 5551212.
exten => _XXX,1,SayDigits(${EXTEN:1})
Se o x for negativo será obtido os últimos dígitos x do ramal discado.
exten => _XXX,1,SayDigits(${EXTEN:-1})
Habilitações de discagem de ligações externas
Agora que já foi apresentado a adaptação de modelos, podemos fazer ligações externas.
Então podemos acrescentar uma variável ao contexto [globals] para definir quais canais serão
utilizados para fazer ligações externas:
[globals]
JOHN=Zap/1
10. JANE=SIP/jane
OUTBOUNDTRUNK=Zap/4
Vamos criar um contexto para ligações externas, isto é necessário para colocar um pouco de
segurança, regular e controlar as ligações externas (quem pode fazer ligações externas).
Então vamos criar um contexto chamado [outbound-local]. Vamos usar o número 9 no início,
de forma que os usuários deveram usar o 9 para chamar um número externo.
[outbound-local]
exten => _9NXXXXXX,1,Dial(${OUTBOUNDTRUNK}/${EXTEN:1})
exten => _9NXXXXXX,2,Congestion()
exten => _9NXXXXXX,102,Congestion()
Então neste contexto anterior, nós acrescentamos uma variável global chamada OUTBOUNDTRUNK,
que irá controlar qual ramal será utilizado para fazer ligações externas.
Nós também adicionamos um contexto para ligações externas locais. Na prioridade 1, nós pegamos
o ramal discado, eliminando o 9 com a sintaxe ${EXTEN:1} e então tentamos discar aquele
número no canal significando pela variável OUTBOUNDTRUNK.
Se a chamada funcionar, o chamador é ligado ao canal de saída. Se a chamada falhar, por que o
canal está ocupado, ou porque o número não pode ser discado por qualquer razão, a aplicação
Congestion() é chamada e toca um “sinal de ocupado”, para permitir que o chamador saiba
que sua chamada falhou.
Ao discar o 9 não será fornecido realmente uma linha externa como em um sistema PBX
tradicional, mas sim aparecerá um silêncio, caso queirase um tom de discagem adicione ao
contexto:
ignorepat => 9
Que diz ao Asterisk para continuar a tocar o tom de discagem mesmo depois de o chamador discar o
9.
É sempre interessante permitir que o dialplan possa discar para números de emergência:
[outbound-local]
exten => _9NXXXXXX,1,Dial(${OUTBOUNDTRUNK}/${EXTEN:1})
exten => _9NXXXXXX,2,Congestion()
exten => _9NXXXXXX,102,Congestion()
exten => 190,1,Dial(${OUTBOUNDTRUNK}/190)
Inclusos
O Asterisk permite que utilizemos um contexto dentro de outro contexto por meio da
diretiva include. Assim o include é utilizado para fornecer acesso a diferentes seções do dialplan.
Nós utilizaremos a funcionalidade include para permitir que usuários do contexto [internal]
11. (da rede local) tenham a capacidade de fazer chamadas para telefones externos (rede PSTN, no
nosso caso).
Estrutura do include
A definição de include toma a seguinte forma, em que context é o nome do contexto remoto que
gostaríamos de incluir no contexto atual:
include => context
Quando existirem contextos dentro do contexto atual, é necessário observar a ordem em que
estamos incluindo os contextos, já que o Asterisk irá primeiro tentar corresponder a extensão do
contexto atual, se este falhar o Asterisk chamará o primeiro que aparecer e se der errado o próximo
e assim por diante, na ordem que forem incluídos.
Vamos ao último exemplo usando os inclusos:
[globals]
JOHN=Zap/1
JANE=SIP/jane
OUTBOUNDTRUNK=Zap/4
[incoming]
exten => s,1,Answer()
exten => s,2,Background(enter-ext-of-person)
exten => 101,1,Dial(Zap/1,10)
exten => 101,2,Playback(vm-nobodyavail)
exten => 101,3,Hangup()
exten => 101,102,Playback(tt-allbusy)
exten => 101,103,Hangup()
exten => 102,1,Dial(SIP/jane,10)
exten => 102,2,Playback(vm-nobodyavail)
exten => 102,3,Hangup()
exten => 102,102,Playback(tt-allbusy)
exten => 102,103,Hangup()
exten => i,1,Playback(pbx-invalid)
exten => i,2,Goto(incoming,s,1)
exten => t,1,Playback(vm-goodbye)
exten => t,2,Hangup()
[internal]
include => outbound-local
exten => 101,1,Dial(Zap/1,,r)
exten => 102,1,Dial(SIP/jane,,r)
[outbound-local]
exten => _9NXXXXXX,1,Dial(${OUTBOUNDTRUNK}/${EXTEN:1})
exten => _9NXXXXXX,2,Congestion()
exten => _9NXXXXXX,102,Congestion()
exten => 190,1,Dial(${OUTBOUNDTRUNK}/190)