📜 ⬆️ ⬇️

Integration of Asterisk and Bitrix24


The network has different integration options for IP-PBX Asterisk and Bitrix24 CRM, but we, all the same, decided to write our own.

In terms of functionality, everything is standard:


Under the cut, I'll tell you how to set everything up at home and give a link to github - yes, take it and use it!

general description


We called our integration CallMe. CallMe is a small web application written in PHP.
')

Used technologies and services



Presetting


On the server with Asterisk, you need to install a web server (we have nginx + php-fpm), supervisor and git.

Command to install (CentOS):

yum install nginx php-fpm supervisor git 

Go to the directory accessible by the web server, pull the application from the gita and set the necessary rights for the folder:

 cd /var/www git clone https://github.com/ViStepRU/callme.git chown nginx. -R callme/ 

Next, configure nginx, our config is located in

 /etc/nginx/conf.d/pbx.vistep.ru.conf 

 server { server_name www.pbx.vistep.ru pbx.vistep.ru; listen *:80; rewrite ^ https://pbx.vistep.ru$request_uri? permanent; } server { # listen *:80; # server_name pbx.vistep.ru; access_log /var/log/nginx/pbx.vistep.ru.access.log main; error_log /var/log/nginx/pbx.vistep.ru.error.log; listen 443 ssl http2; server_name pbx.vistep.ru; resolver 8.8.8.8; ssl_stapling on; ssl on; ssl_certificate /etc/letsencrypt/live/pbx.vistep.ru/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/pbx.vistep.ru/privkey.pem; ssl_dhparam /etc/nginx/certs/dhparam.pem; ssl_session_timeout 24h; ssl_session_cache shared:SSL:2m; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers kEECDH+AES128:kEECDH:kEDH:-3DES:kRSA+AES128:kEDH+3DES:DES-CBC3-SHA:!RC4:!aNULL:!eNULL:!MD5:!EXPORT:!LOW:!SEED:!CAMELLIA:!IDEA:!PSK:!SRP:!SSLv2; ssl_prefer_server_ciphers on; add_header Strict-Transport-Security "max-age=31536000;"; add_header Content-Security-Policy-Report-Only "default-src https:; script-src https: 'unsafe-eval' 'unsafe-inline'; style-src https: 'unsafe-inline'; img-src https: data:; font-src https: data:; report-uri /csp-report"; root /var/www/callme; index index.php; location ~ /\. { deny all; #     } location ~* /(?:uploads|files)/.*\.php$ { deny all; #     } location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ { access_log off; log_not_found off; expires max; #   } location ~ \.php { root /var/www/callme; index index.php; fastcgi_pass unix:/run/php/php5.6-fpm.sock; # fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name; include /etc/nginx/fastcgi_params; } } 

I will leave the analysis of the config, security issues, obtaining a certificate, and even the choice of a web server outside of the article - there is a lot written about this. The application has no restrictions, it works on http and https.

We have https, let's let's encrypt certificate.

If you did everything right, then clicking on the link should see something like



Setting Bitrix24


Create two webhook.

Incoming webhuk.

Under the administrator account (with id 1) go along the path: Applications -> WebHooks -> Add WebHook -> Inbound WebHook



Fill in the parameters of the incoming webhuk as on screenshots:





And click save.

After saving, Bitrix24 will provide the URL of the incoming webhuk, for example:



Save your version of the URL without the final / profile / - it will be used in the application to work with incoming calls.

I have this https://b24-xsynia.bitrix24.ru/rest/1/7eh61lh8pahw0fwt

Outgoing webhuk.

Applications -> WebHooks -> Add WebHook -> Outgoing WebHook

Details again on screenshots:





Save and get the authorization code



I have this xcrp2ylhzzd2v43cmfjqmkvrgrcbkni6 . He also needs to be copied to himself, he is needed to make outgoing calls.

Important!
On the Bitrix24 server, an ssl certificate must be configured (you can use letsencrypt), otherwise the bitrix api will not work. If you have a cloud version, don't worry - there is already ssl.

And with the final touch, we will install our CallMeOut as an application for making calls (so that by clicking on the number on the PBX the command would fly away to originate the call).

In the menu, select: More -> Telephony -> More -> Settings, put in “Default number for outgoing call” Appendix: CallMeOut and click “Save”



Asterisk setup


For successful interaction between Asterisk and Bitrix24, we need to add the AMI callme user in manager.conf:

 [callme] secret = JD3clEB8_f23r-3ry84gJ deny = 0.0.0.0/0.0.0.0 permit = 127.0.0.1/255.255.255.0 permit= 10.100.111.249/255.255.255.255 permit = 192.168.254.0/255.255.255.0 read = system,call,log,verbose,agent,user,config,dtmf,reporting,cdr,dialplan write = system,call,agent,log,verbose,user,config,command,reporting,originate 

Then there are several tricks that need to be implemented through dialplan (we have extensions.ael).

I give the whole file, and after I give explanations:

 globals { WAV=/var/www/pbx.vistep.ru/callme/records/wav; //   WAV MP3=/var/www/pbx.vistep.ru/callme/records/mp3; //  mp3  URLRECORDS=https://pbx.vistep.ru/callme/records/mp3; RECORDING=1; // , 1 - . }; macro recording(calling,called) { if ("${RECORDING}" = "1"){ Set(fname=${UNIQUEID}-${STRFTIME(${EPOCH},,%Y-%m-%d-%H_%M)}-${calling}-${called}); Set(datedir=${STRFTIME(${EPOCH},,%Y/%m/%d)}); System(mkdir -p ${MP3}/${datedir}); System(mkdir -p ${WAV}/${datedir}); Set(monopt=nice -n 19 /usr/bin/lame -b 32 --silent "${WAV}/${datedir}/${fname}.wav" "${MP3}/${datedir}/${fname}.mp3" && rm -f "${WAV}/${fname}.wav" && chmod o+r "${MP3}/${datedir}/${fname}.mp3"); Set(FullFname=${URLRECORDS}/${datedir}/${fname}.mp3); Set(CDR(filename)=${fname}.mp3); Set(CDR(recordingfile)=${fname}.wav); Set(CDR(realdst)=${called}); MixMonitor(${WAV}/${datedir}/${fname}.wav,b,${monopt}); }; }; context incoming { 888999 => { &recording(${CALLERID(number)},${EXTEN}); Answer(); ExecIF(${CallMeCallerIDName}?Set(CALLERID(name)=${CallMeCallerIDName}):NoOp()); //  CallerID     24 Set(CallStart=${STRFTIME(epoch,,%s)}); Queue(Q1,tT); Set(CallMeDISPOSITION=${CDR(disposition)}); Hangup(); } h => { Set(CDR_PROP(disable)=true); Set(CallStop=${STRFTIME(epoch,,%s)}); Set(CallMeDURATION=${MATH(${CallStop}-${CallStart},int)}); ExecIF(${ISNULL(${CallMeDISPOSITION})}?Set(CallMeDISPOSITION=${CDR(disposition)}):NoOP(=== CallMeDISPOSITION already was set ===)); System(curl -s https://pbx.vistep.ru/CallMeOut.php --data action=sendcall2b24 --data call_id=${CallMeCALL_ID} --data-urlencode FullFname=${FullFname} --data CallIntNum=${CallIntNum} --data CallDuration=${CallMeDURATION} --data-urlencode CallDisposition=${CallMeDISPOSITION}); } } context default { _X. => { Hangup(); } }; context dial_out { _[1237]XX => { &recording(${CALLERID(number)},${EXTEN}); Set(__CallIntNum=${CALLERID(num)}) Set(CallStart=${STRFTIME(epoch,,%s)}); Dial(SIP/${EXTEN},,tTr); Hangup(); } _11XXX => { &recording(${CALLERID(number)},${EXTEN}); Set(CallStart=${STRFTIME(epoch,,%s)}); Set(__CallIntNum=${CALLERID(num)}); Dial(SIP/${EXTEN:2}@toOurAster,,t); Hangup(); } _. => { &recording(${CALLERID(number)},${EXTEN}); Set(__CallIntNum=${CALLERID(num)}) Set(CallStart=${STRFTIME(epoch,,%s)}); Dial(SIP/${EXTEN}@toOurAster,,t); Hangup(); } h => { Set(CDR_PROP(disable)=true); Set(CallStop=${STRFTIME(epoch,,%s)}); Set(CallMeDURATION=${MATH(${CallStop}-${CallStart},int)}); if(${ISNULL(${CallMeDISPOSITION})}) { Set(CallMeDISPOSITION=${CDR(disposition)}); } System(curl -s http://pbx.vistep.ru/CallMeOut.php --data action=sendcall2b24 --data call_id=${CallMeCALL_ID} --data-urlencode FullFname=${FullFname} --data CallIntNum=${CallIntNum} --data CallDuration=${CallMeDURATION} --data-urlencode CallDisposition=${CallMeDISPOSITION}); } }; 

Let's start from the beginning: the globals directive.

The URLRECORDS variable stores the URL to the conversation recording files, according to which Bitrix24 will pull them into the contact card.

Next we are interested in macro macro recording .

Here, in addition to recording conversations, we set the variable FullFname .

 Set(FullFname=${URLRECORDS}/${datedir}/${fname}.mp3); 

It stores the full URL to a specific file (the macro is called everywhere).

We analyze the outgoing call:

 _. => { &recording(${CALLERID(number)},${EXTEN}); Set(__CallIntNum=${CALLERID(num)}) Set(CallStart=${STRFTIME(epoch,,%s)}); Dial(SIP/${EXTEN}@toOurAster,,t); Hangup(); } h => { Set(CDR_PROP(disable)=true); Set(CallStop=${STRFTIME(epoch,,%s)}); Set(CallMeDURATION=${MATH(${CallStop}-${CallStart},int)}); if(${ISNULL(${CallMeDISPOSITION})}) { Set(CallMeDISPOSITION=${CDR(disposition)}); } System(curl -s http://pbx.vistep.ru/CallMeOut.php --data action=sendcall2b24 --data call_id=${CallMeCALL_ID} --data-urlencode FullFname=${FullFname} --data CallIntNum=${CallIntNum} --data CallDuration=${CallMeDURATION} --data-urlencode CallDisposition=${CallMeDISPOSITION}); } 

Suppose we call 89991234567, the first thing we get here:

 &recording(${CALLERID(number)},${EXTEN}); 

those. the call recording macro is called and the necessary variables are set.

Further

  Set(__CallIntNum=${CALLERID(num)}) Set(CallStart=${STRFTIME(epoch,,%s)}); 

we write down who initiated the call and fix the start time of the call.

And upon its completion, in a special context h

 h => { Set(CDR_PROP(disable)=true); Set(CallStop=${STRFTIME(epoch,,%s)}); Set(CallMeDURATION=${MATH(${CallStop}-${CallStart},int)}); if(${ISNULL(${CallMeDISPOSITION})}) { Set(CallMeDISPOSITION=${CDR(disposition)}); } System(curl -s http://pbx.vistep.ru/CallMeOut.php --data action=sendcall2b24 --data call_id=${CallMeCALL_ID} --data-urlencode FullFname=${FullFname} --data CallIntNum=${CallIntNum} --data CallDuration=${CallMeDURATION} --data-urlencode CallDisposition=${CallMeDISPOSITION}); } 

We disable recording to the CDR table for this extension (it is not needed there), set the call completion time, calculate the duration, if the result of the call is not known - set ( CallMeDISPOSITION variable) and, at the last step, send the bitrix through the system curl.

And a little more magic - incoming call:

 888999 => { &recording(${CALLERID(number)},${EXTEN}); Answer(); ExecIF(${CallMeCallerIDName}?Set(CALLERID(name)=${CallMeCallerIDName}):NoOp()); //  CallerID     24 Set(CallStart=${STRFTIME(epoch,,%s)}); //     Queue(Q1,tT); Set(CallMeDISPOSITION=${CDR(disposition)}); Hangup(); } 

Here we are only interested in one line.

 ExecIF(${CallMeCallerIDName}?Set(CALLERID(name)=${CallMeCallerIDName}):NoOp()); 

She tells the PBX to set the CallerID (name) to the variable CallMeCallerIDName .

The CallMeCallerIDName variable itself, in turn, is set by the CallMe application (if Bitrix24 has a full name for the caller’s number, set it as CallerID (name) , if not, we will not do anything).

Application setup


The application settings file - /var/www/pbx.vistep.ru/config.php

Description of application parameters:


sample configuration file:

  <?php return array( 'CallMeDEBUG' => 1, //    : 1 - , 0 -   'tech' => 'SIP', 'authToken' => 'xcrp2ylhzzd2v43cmfjqmkvrgrcbkni6', //   'bitrixApiUrl' => 'https://b24-xsynia.bitrix24.ru/rest/1/7eh61lh8pahw0fwt', //url  api  ( ) 'extentions' => array('888999'), //   ,   'context' => 'dial_out', //     'asterisk' => array( //      'host' => '10.100.111.249', 'scheme' => 'tcp://', 'port' => 5038, 'username' => 'callme', 'secret' => 'JD3clEB8_f23r-3ry84gJ', 'connect_timeout' => 10000, 'read_timeout' => 10000 ), 'listener_timeout' => 300, //    asterisk ); 

Supervisor setup


Supervisor is used to launch an event handler from Asterisk CallMeIn.php, which tracks incoming calls and interacts with Bitrix24 (show card, hide card, etc.).

Settings file to create:

/etc/supervisord.d/callme.conf

 [program:callme] command=/usr/bin/php CallMeIn.php directory=/var/www/pbx.vistep.ru autostart=true autorestart=true startretries=5 stderr_logfile=/var/www/pbx.vistep.ru/logs/daemon.log stdout_logfile=/var/www/pbx.vistep.ru/logs/daemon.log 

Starting and restarting the application:

 supervisorctl start callme supervisorctl restart callme 

view the status of the application:

 supervisorctl status callme callme RUNNING pid 11729, uptime 17 days, 16:58:07 

Conclusion


It turned out quite difficult, but I am sure that an experienced administrator will be able to implement and please his users.

As promised, a link to the githab .

Questions, wishes - please in the comments. Also, if you are interested in how the development of this integration was going on, write, and in the next article I will try to reveal in more detail.

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


All Articles