Tutorial - Jitsi / Jigasi & FreePBX integration. Along with Asterisk IVR to use Jitsi conference mapper API

What can I do against the DTMF error in FreePBX that it runs?

@SaHa - Before exploring DTMF, make sure you are using CHAN_SIP extensions (not PJSIP) as Hackuppp mentioned. Using an incorrect technology type will not work.

If that’s good, then back to DTMF issues… If you’re seeing DTMF lines (like in my example) after enabling them in your log, they’re notifications not errors. This would be normal function, just showing that it’s actually registering the DTMF input:

DTMF[16902][C-00000067] channel.c: DTMF begin '1' received on SIP/6580-000000c0
DTMF[16902][C-00000067] channel.c: DTMF begin ignored '1' on SIP/6580-000000c0

If you’re not seeing them after enabling them in the log, that’s an issue. Did you test an internal and an external call to the IVR? Did only one or both not work?

Thanks for the hint. When going external it does in fact not register, so I will try using another trunk.

When going internal, I do see them:

[2020-05-04 11:52:16] DTMF[23196][C-000000a4] channel.c: DTMF end '2' received on SIP/102-0000005f, duration 120 ms
[2020-05-04 11:52:16] DTMF[23196][C-000000a4] channel.c: DTMF end accepted with begin '2' on SIP/102-0000005f
[2020-05-04 11:52:16] DTMF[23196][C-000000a4] channel.c: DTMF end passthrough '2' on SIP/102-0000005f
[2020-05-04 11:52:17] DTMF[23196][C-000000a4] channel.c: DTMF begin '8' received on SIP/102-0000005f
[2020-05-04 11:52:17] DTMF[23196][C-000000a4] channel.c: DTMF begin passthrough '8' on SIP/102-0000005f
[2020-05-04 11:52:17] DTMF[23196][C-000000a4] channel.c: DTMF end '8' received on SIP/102-0000005f, duration 120 ms
[2020-05-04 11:52:17] DTMF[23196][C-000000a4] channel.c: DTMF end accepted with begin '8' on SIP/102-0000005f
[2020-05-04 11:52:17] DTMF[23196][C-000000a4] channel.c: DTMF end passthrough '8' on SIP/102-0000005f
[2020-05-04 11:52:17] DTMF[23196][C-000000a4] channel.c: DTMF begin '0' received on SIP/102-0000005f
[2020-05-04 11:52:17] DTMF[23196][C-000000a4] channel.c: DTMF begin passthrough '0' on SIP/102-0000005f
[2020-05-04 11:52:18] DTMF[23196][C-000000a4] channel.c: DTMF end '0' received on SIP/102-0000005f, duration 120 ms
[2020-05-04 11:52:18] DTMF[23196][C-000000a4] channel.c: DTMF end accepted with begin '0' on SIP/102-0000005f
[2020-05-04 11:52:18] DTMF[23196][C-000000a4] channel.c: DTMF end passthrough '0' on SIP/102-0000005f
[2020-05-04 11:52:18] DTMF[23196][C-000000a4] channel.c: DTMF begin '#' received on SIP/102-0000005f
[2020-05-04 11:52:18] DTMF[23196][C-000000a4] channel.c: DTMF begin passthrough '#' on SIP/102-0000005f
[2020-05-04 11:52:18] DTMF[23196][C-000000a4] channel.c: DTMF end '#' received on SIP/102-0000005f, duration 120 ms
[2020-05-04 11:52:18] DTMF[23196][C-000000a4] channel.c: DTMF end accepted with begin '#' on SIP/102-0000005f
[2020-05-04 11:52:18] DTMF[23196][C-000000a4] channel.c: DTMF end passthrough '#' on SIP/102-0000005f

But then it ends on:

[2020-05-04 11:52:19] VERBOSE[23197][C-000000a5] app_read.c: User entered nothing.

I’m investigating, but let me know if you have any ideas.

Have you confirmed that you have two way audio working? (example - 2 phones, you can hear audio at both endpoints).

Also, check that DTMF settings are set to RFC 2833 (should be the default on a fresh install):

  • FreePBX > Settings > Advanced > SIP DTMF Signaling > “rfc2833”
  • FreePBX > Applications > Extensions > (edit individual extension) > Advanced > DTMF Signaling > “RFC 2833”

Yeah, two way audio is working fine.

I have now setup with another provider and it is working fine now. Not sure what the issue was. Thank you for looking into it with me!

1 Like

Another idea instead of adding

<Directory />
    Header set Access-Control-Allow-Origin "https://meet.domain.com"
    AllowOverride none
    Require all denied
</Directory>

to the webserver config is, that you add this header informations inside the PHP file.

<?php
    header("Access-Control-Allow-Origin: https://meet.domain.tld");
    header('Content-Type: application/json');
    readfile("./numbers.json");
?>

This is also working fine and maybe it is more easier then change in the apache / nginx config.

1 Like

Nice! I like your method much better :slight_smile:
I just tested and it’s working on mine as well. Thanks for the feedback!

1 Like

Pro Tip: Route SIP calls to your DID internally

If you’re in a multi-user/multi-extension voip environment, There may be times when an internal SIP user will call your DID in order to access a conference. What happens by default is that the call will route outbound to your Voip provider, then the provider routes it back based on matching the DID to your server.

If you’re voip plan is bill by duration, You or your company will end up being charged for the outbound + inbound duration. Even if you have unlimited minutes, there’s typically a cap on the number of concurrent calls (channels) and you’d be using 2 channels for each instance of this scenario. Which can add up quickly, potentially consuming all available channels.

To circumvent this issue, create an outbound route without a trunk and make the congestion destination your IVR. In the case of this tutorial , your Custom Destination "Jitsi-Bridge"

Steps

  • FreePBX > Connectivity > Outbound routes > + Add outbound route

  • Route Settings tab > provide a name, leave trunk blank, and set “optional destination on congestion” to your Custom destination we created for the IVR.

  • Dial Patterns > input your DID. I typically add a pattern with and without the country code.

  • Submit > Apply

  • Lastly, go back to Connectivity > Outbound routes > move new route to the top so that it’s matched first

@BasilDane

Here’s my approach - self hosted conference mapper API

Many Many thanks for this great tutorial !!!

I’m now reading on asterisk.org to learn how works dial plan and IVR.

I have one question.
Now Https port is exposed to the outside. Is there anyway to allow access to jitsi files without allowing access to admin console?

Hi, I assume you’re referencing the FreePBX server, in which case is handled by the adaptive firewall.

If your Jitsi server and FreePBX are on the same local network , you don’t need to allow https through to FreePBX. Jitsi will request the phone number list from freepbx and send to the end user.

If the 2 servers are on separate networks across the internet, then yes I agree https open, but lock down the web access…

  1. Connectivity > Firewall. Make sure your firewall interfaces and networks are setup so that the firewall knows the difference between external and internal networks.
  2. Connectivity > Firewall > Services. define which services should be local or rejected (example - secure https)

Hi Craig,

Thanks for your answer, unfortunately for me I did not found the fine tuning.

If I activate the sec web interface in https and the DMZ nic to trusted it works, but my admin is exposed.
But if I de-activate the secure web interface and leave the DMZ nic to trusted the access to the jitsi files does not work anymore.

same if the DMZ is set to standard firewall rules.

But a least thanks for your answer. I’ll ask my question on freePBX forums and let this topic clean !

Just for those that could be interested.

To allow https connexion from outside but forbid access to web admin at the same time, this is what I did :

  • In System Admin > Ports > Set secured port to 1443
  • In Connectivity > Firewall > Services > allowed Web Management (Secure) only on local
  • In Connectivity > Firewall > Services > Custom Services > Added Custom services on port tcp/443
  • Created a file : /etc/httpd/conf.d/voip.conf and added the following :
LoadModule ssl_module modules/mod_ssl.so
SetEnv SSLSETUP true
SSLPassPhraseDialog  builtin
SSLSessionCache         shmcb:/var/cache/mod_ssl/scache(512000)
SSLSessionCacheTimeout  300
# Not valid in Apache 2.4
# SSLMutex default
SSLRandomSeed startup file:/dev/urandom  256
SSLRandomSeed connect builtin
SSLCryptoDevice builtin
#https://mozilla.github.io/server-side-tls/ssl-config-generator/
SSLProtocol all -SSLv2 -SSLv3
SSLHonorCipherOrder on
SSLCipherSuite ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS
Listen 443
# Skipping sslucp as it is disabled
# Skipping sslrestapi as it is disabled
# Skipping sslrestapps as it is disabled
# Skipping sslhpro as it is disabled
<VirtualHost *:443>
  ServerName voip.mysite.fr:443
  LogLevel warn
  SSLEngine on
  SSLCertificateFile /etc/httpd/pki/webserver.crt
  SSLCertificateKeyFile /etc/httpd/pki/webserver.key
  SSLCertificateChainFile /etc/httpd/pki/ca-bundle.crt
  DocumentRoot /var/www/html/jitsi-addons
  Alias /.well-known /var/www/html/.well-known
  Alias /.freepbx-known /var/www/html/.freepbx-known
  RewriteEngine on
  RewriteRule ^/\.(well-known|freepbx-known)/ - [H=text/plain,L]
  RewriteRule (^\.|/\.) - [F]
</VirtualHost>
  • Ran systemctl restart httpd

And the trick was done. Hope i’ll help someone else.

Bye

1 Like

Hi Craig,

Thanks for all, this is working like a charm.

One question, if entered pin is not yet associated to an existing meeting there is vocal message like :
“The meeting will start when the host will be there” (translated so may be not very accurate)

A waiting music start and then the call hang up after few seconds, no matter if someone connect as host.

Do you know how to correct this behavior? 2 options :
-Make a not associated pin create a random jitsi room. (Not sure i’m clear)
or
-change the message to something llike : “There is no meeting using this pin yet, thanks to call back later”

Proc.

That’s an incorrect assumption, the behavior is intended. The IVR dials the meeting (curl result) once for 3 seconds. Then , it assumes the host simply hasn’t started the meeting If no answer and will dial again and wait for 120 seconds. Before the second dial, the IVR informs the caller “The conference will begin when the leader arrives”.

What you’re wanting is a way to determine the PIN is invalid and take an additional action specific to a non-existent meeting.

In that case, the API does return a “FALSE” statement for anything it doesn’t like. One could simply inject something like

exten => s,n,ExecIf($["${CURL_RESULT}"="false"]?goto(conf-no-match))

and then at the very end of your Dial plan, place something like:

exten => s,n,Dial(SIP/${Jitsi},120,m(default)A(/tmp/name-${rnum})M(Jitsi-join))
exten => s,n,Hangup()
exten => s,n(conf-no-match),Playback(conf-invalid)
exten => s,n,GoTo(Jitsi-Conference-Entry,s,4)

First 2 lines should already be there, you’re adding the last 2. Of which, the last line would give the caller another chance to enter a correct pin.

I haven’t tested that myself, but let me know if you have any issues and I’ll check into it further.

Many thanks for taking time to answer.

I think the way you made your script is already good enough as there is a check of the pin before to join it.

But then I regarding the logs I have the impression that the call is not tried for only three seconds.
It seems keep it ringing until the provider hang up the call (about 30 seconds) because of busy line.

[2020-05-16 20:38:14] VERBOSE[16573][C-0000001e] app_dial.c: SIP/5000-0000001d is ringing
[2020-05-16 20:38:15] VERBOSE[16573][C-0000001e] app_dial.c: SIP/5000-0000001d is ringing
[2020-05-16 20:38:16] VERBOSE[16573][C-0000001e] app_dial.c: SIP/5000-0000001d is ringing
[2020-05-16 20:38:18] VERBOSE[16573][C-0000001e] app_dial.c: SIP/5000-0000001d is ringing
[2020-05-16 20:38:44] VERBOSE[2370][C-0000001e] chan_sip.c: Got SIP response 486 "Busy here" back from 11.111.11.1:5060
[2020-05-16 20:38:44] VERBOSE[16573][C-0000001e] app_dial.c: SIP/5000-0000001d is busy

Weird, Do you think the operator could be the issue?

That’s probably the second, 120sec ring attempt. My guess is that something is timing out before the 120 seconds is exhausted.

The first dial attempt can be spotted in the Asterisk log with this line (note the 3 before “m(silence)”)

 "PJSIP/226,3,m(silence)A(/tmp/name-1656247108)M(Jitsi-join)") in new stack

After several ring attempts, you “should” have an unanswered response:

[2020-05-16 20:43:50] VERBOSE[26113][C-0000004b] app_dial.c: Nobody picked up in 3000 ms

The second dial attempt can be spotted in the log with this line (note the 120 before “m(silence)”)

It’s after this line, I suspect the ring attempts are hitting timeout before it ever exhausts the 120 seconds of desired ring time. Maybe the extension settings or could be a jigasi timer.

 "PJSIP/226,120,m(silence)A(/tmp/name-1656247108)M(Jitsi-join)") in new stack
1 Like

Ok many thanks.

I’ll check this a little bit later.

Your assumption was right.
It was the default jigasi timer the source of the issue.

Adding this in /etc/jitsi/jigasi/sip-communicator.properties resolved my problem :

org.jitsi.jigasi.JVB_INVITE_TIMEOUT=300000

It makes the conference wait for 5 minutes before closing the call.

And this worked to reenter the pin in case of timeout :

exten => s,n,Dial(SIP/${Jitsi},120,m(default)A(/tmp/name-${rnum})M(Jitsi-join))
;exten => s,n,Hangup()
exten => s,n(conf-no-match),Playback(conf-invalid)
exten => s,n,GoTo(Jitsi-Conference-Entry,s,4)

The hangup has to be removed (commented here) otherwise the call is close before being sent to pin entry.
For now I commented this feature as your protocol is already good for me. Will see in the future if needed.

thanks for your help

1 Like

Great tutorial !
For those interested in using “PJSIP” with SIP-Header, I did:

exten => s,n,Dial(PJSIP/${Jitsi},5,m(silence)A(/tmp/name-${rnum})b(Jitsi-Header^addheader^1(${CURL_RESULT},${confpin}))M(Jitsi-join))

add a new Sub / Context at the end of the script:

[Jitsi-Header]
exten => addheader,1,Set(PJSIP_HEADER(add,Jitsi-Conference-Room)=${ARG1})
exten => addheader,2,Set(PJSIP_HEADER(add,Jitsi-Conference-Room-Pass)=${ARG2})
exten => addheader,3,Return()
1 Like