Salas de reunião com base no Asterisk

Prefácio


Boa tarde

Havia duas coisas que me levaram a escrever este artigo: um pequeno número ou falta de exemplos de trabalho modernos nos "chips" do Asterisk, bem como a relutância dos especialistas em compartilhar esses mesmos "chips" com o resto. Agora sou eu a comunidade RU. Todos os tipos de "avôs" nos fóruns têm maior probabilidade de encharcá-lo com slops e enviá-lo para ler livros de dez anos atrás do que fornecer informações pouco mais ou menos úteis. Os tópicos do fórum, criados em 2005-2010, estão muito desatualizados e, às vezes, algo já foi visto na versão atual do asterisco, e algo precisa ser refeito muito para que ele funcione.

Então aqui.
Como resultado do abandono do CUCM em favor do Asterisk, a gerência foi encarregada de preservar os serviços mais populares entre os usuários em sua forma mais original, para não frustrar as pessoas. Uma delas foi a criação de conferências. Naquela época, eu já estava familiarizado com o Asterisk, mas não tão profundamente, então levei cerca de uma semana e meia para classificar todos os tipos de opções de conferência, e uma tarefa diferente surgiu com uma decisão final.

O problema é que, a partir de uma solução semelhante à que existe um artigo com um encontro desatualizado, além de algum tipo de monstro que eu ainda não consegui trabalhar. Sugiro algo não tão volumoso.

Celulose


Não descreverei o que é o confbridge, quais seções em uma configuração específica são responsáveis ​​e o que é essa opção, apenas terei essas informações e estão atualizadas. Agora sobre a decisão como um todo.

Objetivo: possibilitar a criação da conferência durante uma conversa e convidar mais assinantes para lá. O principal problema é que a função channelredirect não funciona como gostaríamos. Ou seja, se você executá-lo a partir do plano de discagem durante uma conversa, um dos canais voará sempre que necessário e o segundo entrará em colapso, subindo todo o plano de discagem para 2 linhas e registrando a opção g em Dials. E não entendo por que, na maioria dos manuais, todos tentam resolver o problema apenas através do plano de discagem, ignorando a capacidade do asterisco de trabalhar com scripts externos e ami.

Então Asterisk 14.4.0

Script da conferência para 2 opções (com comentários):

conference.php
<?php //    $host = "192.168.1.1"; $port = "5038"; $timeout = "10"; $user = "conference"; $pass = "1111"; // ,    1   2  $kusok = $argv[1]; //       if ($kusok == 1){ //  $channel = $argv[2]; $bridgepeer = $argv[3]; $confnum = $argv[4]; print_r($bridgepeer); print_r($confnum); // $sconn = fsockopen ($host, $port, $timeout) or die ("Connection to $host:$port failed!"); fputs ($sconn, "Action: Login\r\n"); fputs ($sconn, "Username: $user\r\n"); fputs ($sconn, "Secret: $pass\r\n\r\n"); //   fputs ($sconn, "Action: Setvar\r\n"); fputs ($sconn, "Channel: $channel\r\n"); fputs ($sconn, "Variable: CONFNUM\r\n"); fputs ($sconn, "Value: $confnum\r\n\r\n"); fputs ($sconn, "Action: Setvar\r\n"); fputs ($sconn, "Channel: $bridgepeer\r\n"); fputs ($sconn, "Variable: CONFNUM\r\n"); fputs ($sconn, "Value: $confnum\r\n\r\n"); // fputs ($sconn, "Action: Redirect\r\n"); fputs ($sconn, "Channel: $bridgepeer\r\n"); fputs ($sconn, "ExtraChannel: $channel\r\n"); fputs ($sconn, "Context: service_code-ael\r\n"); fputs ($sconn, "Exten: conference\r\n"); fputs ($sconn, "Priority: 1\r\n\r\n"); fputs($sconn, "Action: Logoff\r\n\r\n"); sleep(2); fclose ($sconn); } //     if ($kusok == 2) { //  $confnum = $argv[2]; $inviten = $argv[3]; $sconn = fsockopen ($host, $port, $errno, $errstr, $timeout) or die ("Connection to $host:$port failed!"); // fputs ($sconn, "Action: Login\r\n"); fputs ($sconn, "Username: $user\r\n"); fputs ($sconn, "Secret: $pass\r\n\r\n"); //     fputs ($sconn, "Action: Originate\r\n"); fputs ($sconn, "Channel: Local/".$inviten."@out-ael\r\n"); fputs ($sconn, "Context: service_code-ael\r\n"); fputs ($sconn, "Exten: conference\r\n"); fputs ($sconn, "Priority: 1\r\n"); fputs ($sconn, "Variable: CONFNUM=".$confnum."\r\n\r\n"); fputs($sconn, "Action: Logoff\r\n\r\n"); sleep(2); fclose ($sconn); } } 


Gurus de programação podem consertar o código criando doces, escrevi da melhor maneira possível.
Em seguida, começamos a usar esse script diretamente no próprio Asterisk.

Para criar uma conferência, escolhi a combinação * 1. Resumidamente e não cruza com a numeração principal.

Adicione uma chamada de script ao features.conf com as variáveis ​​necessárias transmitidas a ele

 [applicationmap] conference => *1,self,System(/usr/bin/php /home/script/conference.php 1 ${CHANNEL} ${BRIDGEPEER} ${CALLERID(num)}) 

Então, para que isso funcione, crie uma variável no plano de discagem na seção [globals] e adicione nosso recurso

 DYNAMIC_FEATURES=conference 

Para adicionar novos participantes a uma conferência já criada, você precisará registrar o código em confbridge.conf

 [default_menu] type = menu *1=dialplan_exec(service_code-ael,conference_add,1) 

Bem, agora a melhor parte é extensions.ael:

Para criar uma conferência (o script php aborda os dois canais de discussão aqui):

  conference => { ConfBridge(${CONFNUM},,,default_menu); } 

Para adicionar um novo usuário (endereços dialplan_exec aqui):

 conference_add => { Read(INVITEN,dial,11,i); System(/usr/bin/php /home/script/conference.php 2 ${CALLERID(num)} ${INVITEN}); } 

Só isso. Não há quilotons de código no dialplan. Tudo é amplo. * 1 em uma conversa e você está em conflito, novamente * 1 bipe e discagem, a quem adicionar.

Crescimentos


Confuso com os desejos dos usuários, comecei a desenvolver esse recurso.

A próxima foi a oportunidade de criar conferências do zero (não de uma conversa), além de acessar as conferências já criadas pelo número e não esperar uma chamada convidativa.

Adicionar ao plano de discagem:

 _*1XXXX => { NoOp(${CONFCHAN}); Set(__CONFNUM=${EXTEN:2}); System(/usr/bin/php /home/script/conference.php 3 ${CONFCHAN} ${CONFNUM} ); } 

Adicione ao script:

conference.php
 //     if ($kusok == 3){ //  $channel = $argv[2]; $confnum = $argv[3]; // $sconn = fsockopen ($host, $port, $timeout) or die ("Connection to $host:$port failed!"); fputs ($sconn, "Action: Login\r\n"); fputs ($sconn, "Username: $user\r\n"); fputs ($sconn, "Secret: $pass\r\n\r\n"); //   fputs ($sconn, "Action: Setvar\r\n"); fputs ($sconn, "Channel: $channel\r\n"); fputs ($sconn, "Variable: CONFNUM\r\n"); fputs ($sconn, "Value: $confnum\r\n\r\n"); // fputs ($sconn, "Action: Redirect\r\n"); fputs ($sconn, "Channel: $channel\r\n"); fputs ($sconn, "Context: service_code-ael\r\n"); fputs ($sconn, "Exten: conference\r\n"); fputs ($sconn, "Priority: 1\r\n\r\n"); fputs($sconn, "Action: Logoff\r\n\r\n"); sleep(2); fclose ($sconn); 


Eu também tive que modificar a linha _ * X.

  _*X. => { set(__CONFCHAN=${CHANNEL}); Dial(Local/${EXTEN}@service_code-ael); 

Agora, para entrar na conferência ou criá-la do zero, basta fazer uma ligação para * 1 e um número, por exemplo * 15234.

A mutação final deste serviço é a chamada "conferência de grupo". É quando os grandes chefes ficam com preguiça de adicionar todos manualmente, mas eu quero pressionar um botão e tudo está montado. Para fazer isso, decidi criar códigos de serviço separados (* XXX) para que as próprias pessoas não ficassem confusas. Para nossa organização, é improvável que mais de 1000 grupos de conferências sejam necessários nos próximos 100 anos, portanto, deve haver estoque de numeração suficiente. Em casa, você pode adicionar como um prefixo diferente, para alocar uma capacidade de numeração diferente.

Plano de discagem:

  _*XXX=> { Set(CONFNUM=${CALLERID(num)}); System(/usr/bin/php /home/script/groups.php ${EXTEN:1} ${CONFNUM}); ConfBridge(${CONFNUM},,,default_menu); } 

O rangido dos próprios participantes:

groups.php
 //  function call ($group, $confnum) { $many = count($group); //       for ($i=0; $many>$i; $i++) { //    $num = trim(array_shift($group[$i])); // system("asterisk -rx \"channel originate Local/$num@out-ael application ConfBridge $confnum\""); } } //    function conf_group ($groupid) { //   $opt = array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC ); $pdo = new PDO("odbc:mssql_asterisk, "asterisk, "121212", $opt); //   $sql = "SELECT extension FROM [asterisk].[dbo].[conf_groups] where groupid = $groupid"; $select = $pdo->query($sql); $result = $select->fetchAll(); // $pdo = NULL; return $result; } //  ,    $groupid = $argv[1]; //   $confnum = $argv[2]; //   $group=conf_group($groupid); // call($group, $confnum); } 


Todos os grupos são armazenados no banco de dados de acordo com a estrutura de "Grupo, número, nome, descrição". Se um novo grupo aparecer, basta adicioná-lo ao banco de dados.

Agora, para coletar, por exemplo, todos os diretores de uma reunião, o general só precisa discar * 100. E, como regra, grandes chefes têm telefones grandes. Portanto, vinculamos * 100 a qualquer tecla de discagem rápida, assinamos como "diretores" e o usuário não se preocupa em digitar. Apertei o botão - reuni a reunião.

Agora, antecipando suas perguntas:

Por que scripts e ami? Porque, por meio do plano de discagem, não consegui fazer um redirecionamento sensato dos dois canais sem perdê-los ao longo do caminho. Além disso, na função de redirecionamento, você pode anexar um canal adicional + definir uma variável para ele (por exemplo, o número da conferência, para que ele também possa adicionar alguém a ele).

Você também pode perceber que eu coloquei recursos em um contexto separado service_code-ael. Isso é conveniente quando você tem mais do que algumas partes de todos os recursos. Decidi fazê-los passar por *, portanto, em qualquer contexto, apenas escrevi _ * X. e endereço neste contexto. Talvez alguém encontre uma solução mais elegante, mas eu não a encontro há vários meses. E essa funcionalidade atraiu os usuários.

Por que ael, não conf? Bem, porque é mais estruturado e mais fácil de ler.
e mais compreensível. Uma função gotoif vale a pena. Ainda não cheguei a lua.

Por que, no exemplo de coleta em massa, a origem é feita através do bash e não através do AMI? O problema é que, executando um monte de origens seguidas pelo ami, o sistema aguarda a conclusão do anterior para fornecer o próximo. E se ninguém atender o telefone e houver 20 segundos no_ans e essas 5 peças? Você pode esperar até a noite para cobrar.

Bem, isso é provavelmente tudo. Espero que este artigo ajude os mesmos candidatos que eu era quando tudo isso precisava ser feito rapidamente, confortavelmente para os usuários e, o mais importante, no futuro, manter esse sistema era conveniente para mim, por assim dizer, com uma reserva para o futuro.

Source: https://habr.com/ru/post/pt427117/


All Articles