Envisioning a FreePBX Google Voice trunk module
I don’t know if there has been any serious consideration given to developing a FreePBX Google Voice trunk module, but I’d like to at least attempt to lay out the definition for what it would need to do. I can’t code it. but I think I can pretty well define what it would need to do, or at least give a nudge in the right direction.
At the time of installation, the module would need to make sure the all of the following are true:
-
The version of Asterisk installed is 1.8.1.1 or later (if earlier than 1.8.1.1 but still in the 1.8 branch, it should print a warning that Google Voice may not work until Asterisk is upgraded, but install anyway provided the drivers are present). (asterisk -rx “core show version”)
-
The following channel drivers are registered: Jingle, Gtalk (asterisk -rx “core show channeltypes”)
-
The resource module res_jabber must be installed, though it’s probably not necessary to check for this separately because it’s a dependency for the above channel drivers.
If any of the above are not true, the module should print a notice of the deficiency and not install until the dependency is satisfied.
At the time of installation, the module should check for the existence of the following files in the /etc/asterisk directory, and create them if they do not exist, with the contents shown:
- /etc/asterisk/gtalk.conf :
If the file does not exist it should be created with these lines:
[general]
allowguest=yes
context=googlein
stunaddr=stun01.sipphone.com
[guest]
disallow=all
allow=ulaw
connection=asterisk
context=googlein
Note that the stunaddr= line should work on all systems whether behind a NAT firewall or not, although if the system is not behind a firewall then I have read in some places that it’s better to use these:
bindaddr=0.0.0.0
externip=system’s external IP address
However I have not personally found any definitive documentation on the subject so until or unless we can get some clarification on this, it might be better to just stick with the stun server, since this is known to work on all systems (at least as long as the stun server is accessible).
Note that if the file already exists when the module is installed it should probably be backed up, as there might be some configuration for a messaging application in the file.
- /etc/asterisk/jabber.conf
If the file does not exist it should be created with these lines:
[general]
debug=no
autoprune=no
autoregister=yes
This file will be managed by FreePBX (or, you could possibly place an include in the file and use a jabber_additional.conf file to contain the generated context, but one or the other must contain the section shown above). Then for each trunk, there will be a section as follows (this will be revisited later):
[user from trunk config]
type=client
serverhost=talk.google.com
username=user from trunk config@gmail.com/Talk
secret=password from trunk config
port=5222
usetls=yes
usesasl=yes
status=Available
statusmessage="FreePBX rocks!"
timeout=100
keepalive=yes
- One other file that may need to be created during installation if it does not exist is jingle.conf. However Google Voice apparently does not actually use any of the jingle.conf configuration, so it may not be necessary at all, or it may be sufficient to simply make sure it exists.
All of the above files should have the same permissions and ownership as other Asterisk .conf files.
- The trunk GUI page:
The trunk GUI page should read somewhat as follows. Note that at present you cannot set outbound Caller ID on a Google voice trunk so those fields are omitted. Therefore the trunk page could look something like this (where you see [_____] that indicates a text box, [] is a check box, and there is one dropdown as indicated):
Add Google Voice Trunk
General Settings
Trunk Name: []
Gmail address associated with account: []@gmail.com
Gmail/Google Voice password: []
Maximum Channels: []
Disable Trunk: [] Disable
Monitor Trunk Failures: [_____] [] Enable
Dialed Number Manipulation Rules:
[This section is the same as in other trunks, but should probably be pre-populated with one rule: 1+NXXNXXXXXX]
Incoming Settings:
Telephone number associated with account: [_____]
Defer answering call until extension answers: [] Include waits [Dropdown - choices 0,1,2 default 0][/b]
The “Telephone number associated with account” setting is ONLY used as the DID for the inbound route - whatever is put here is the DID that the inbound route will match on. But for most users, it will be easier if the actual phone number associated with the account is placed here, plus it provides a convenient place to store the number for future reference.
“Defer answering call until extension answers” is normally only used if the end user wishes to use Google Voice’s voicemail instead of Asterisk’s voicemail. When the called extension answers, the channel will be answered and a DTMF “1” will be sent to Google Voice (but not the called user) immediately. The number of waits corresponds to one-half second delays after the channel is answered but before the DTMF “1” is sent, and may be included if it appears that Google Voice isn’t reliably receiving the DTMF “1” tone. Only after the DTMF “1” is sent will the call be bridged to the user, so you don’t want to use waits if you don’t have to, or any more than you absolutely need.
- The generated context in extensions_additional.conf:
For inbound calls, there needs to be a single [googlein] context generated, with a section for each trunk. It should look like this if “Defer answering call until extension answers” is NOT checked:
exten => user@gmail.com,1,Set(CALLERID(name)=${CUT(CALLERID(name),@,1)})
exten => user@gmail.com,n,GotoIf($["${CALLERID(name):0:2}" != “+1”]?notrim)
exten => user@gmail.com,n,Set(CALLERID(name)=${CALLERID(name):2})
exten => user@gmail.com,n(notrim),Set(CALLERID(number)=${CALLERID(name)})
exten => user@gmail.com,n,Answer
exten => user@gmail.com,n,Wait(1)
exten => user@gmail.com,n,SendDTMF(1)
exten => user@gmail.com,n,Goto(from-trunk,telnumber,1)
I’m not familiar enough with how extensions_additional.conf differs from extension_custom.conf to know if a hangup context is needed at the end, but I’m sure those who create modules would know that. In the above context, user comes from the “Gmail address associated with account” text field, and telnumber is from the “Telephone number associated with account” field.
If “Defer answering call until extension answers” IS checked then the generated context is altered slightly. If zero “waits” are used it looks like this:
exten => user@gmail.com,1,Set(CALLERID(name)=${CUT(CALLERID(name),@,1)})
exten => user@gmail.com,n,GotoIf($["${CALLERID(name):0:2}" != “+1”]?notrim)
exten => user@gmail.com,n,Set(CALLERID(name)=${CALLERID(name):2})
exten => user@gmail.com,n(notrim),Set(CALLERID(number)=${CALLERID(name)})
exten => user@gmail.com,n,Set(DIAL_OPTIONS=${DIAL_OPTIONS}aD(:1))
exten => user@gmail.com,n,Goto(from-trunk,telnumber,1)
If “waits” are added, a corresponding number of w characters are placed before the :1 in this line. Each “wait” corresponds to one-half second delay. Two waits would be included in this manner:
exten => user@gmail.com,n,Set(DIAL_OPTIONS=${DIAL_OPTIONS}aD(ww:1))
For outgoing calls, there needs to be a context generated for EACH trunk (not placed under a single context as for incoming calls) that looks like this:
[gvoice-user]
exten => _X.,1,Dial(Gtalk/user/+${EXTEN}@voice.google.com)
exten => _X.,n,Noop(GVoice Call to ${EXTEN} failed)
Again, I’m not showing a hangup context because I don’t know if one is needed. In the above context, user comes from the “Gmail address associated with account” text field. Note that some “recipes” on the ‘net include a first line that I’m not showing here, that looks like this:
exten => _X.,1,JABBERSend(user,user@gmail.com,Placing GVoice Call: ${EXTEN})
I’m not convinced the above line is really necessary - it appears to only send a useless notification message that doesn’t hurt anything, but as far as I can determine, it doesn’t help anything either.
- Revisiting /etc/asterisk/jabber.conf (or jabber_additional.conf if that is used instead), for each trunk the following needs to be added:
[user]
type=client
serverhost=talk.google.com
username=user@gmail.com/Talk
secret=password
port=5222
usetls=yes
usesasl=yes
status=Available
statusmessage="FreePBX rocks!"
timeout=100
keepalive=yes
In the above, user and password are both taken from the trunk configuration. For simplicity, the context name is the same as the user name (in the user@gmail.com address).
I suppose that the statusmessage could also be made a configurable option in the trunk setup, but why? In many recipes it says something like “I am an Asterisk server”, which is not something you might necessarily want to advertise (could that be helpful to hackers? I have no idea).
Outgoing calls would use the trunk just like any other. Incoming calls would be brought into an inbound route, using the “Telephone number associated with account” from the trunk setting as the DID.
I am not a coder so I can’t make this happen, but it seems fairly straightforward. I’m sure there are minor “gotchas” I haven’t accounted for, but nothing that should be difficult to work out. Most of the dialplan and configuration samples were lifted from How to use Google Voice for free calls on an Asterisk 1.8+/FreePBX 2.8 system (the easy way), with minor modifications, although I have seen similar “recipes” at other sites on the web.
So, if anyone is bored during the holidays and would like to attempt to code this, please be my guest. It would make Google Voice setup a lot easier for many folks. Or if you see any flaws in what I’m envisioning, please feel free to point them out.