This post has been edited to include new and changed information.
Unfortunately, the original method described below worked for a time in mid-2018. It has not worked at all since then, for one simple reason: Something has changed on Google’s web site and the PyGoogleVoice script that is central to this method no longer works, period. If you run it from the command line, you just get a bunch of errors.
The source code for PyGoogleVoice is here. If you are conversant in Python, maybe you can fork the project and make a version that works. If so, it would be much appreciated if you would share your working version. There is a discussion here that may be informative, but it appears further development has stalled.
Or, if you are conversant in PHP, there is a PHP script posted here that works in a similar manner to PyGoogleVoice. Maybe you can modify it and get that one to work, and if so again it would be appreciated it you’d post the working version.
Or, there is something called selgooglevoice which is “A Selenium with Python replacement for pygooglevoice.” If someone could post detailed instructions for getting this to work, it would be appreciated. If it is using Selenium as the name implies, then it may be that you’d need to have a web browser running, which of course is not possible on a typical Asterisk/FreePBX server with no desktop environment. This is a case where code exists, but there is pretty much zero information on how to use it. EDIT: Jeff Dobkin posted a comment about using selgooglevoice on June 4, 2021 in the comments section, so apparently at least one person has it working! EDIT 2: It may be possible to use Selenium with a “headless” browser which would NOT require a desktop environment. See Setup Selenium with Python and Chrome on Ubuntu & Debian for possible installation instructions – we have NOT tested this but please leave a comment if you get it to work!
Perhaps the most promising potential solution that I have come across so far is contained in this thread about UI.Vision RPA. As shown in December 2023, it will only work with a single Google Voice account, and you must have the Google Chrome browser up and running and you must already be logged into Google Voice. Given the relative simplicity of the script, it might not be that difficult to modify it to support logging into Google Voice, setting up the call, and then logging out (so that multiple Google Voice accounts could be used). However, keep in mind that Google occasionally throws a curve ball during the login process by bringing up an unexpected screen or popup (usually related to security), so you would need to be able to detect and/or bypass that, and also I have read in various places that Google attempts to detect and block automated logins, and if that is the case it may make logging in a lot more difficult than I had originally envisioned. And, as with selgooglevoice, you would probably want to have Google Chrome (or Chromium, or probably any Chrome-based browser that will work with the UI.Vision RPA extension) running on the same system as Asterisk and FreePBX, which would probably mean you’d need to use a desktop version of Debian (or whatever Linux distro you use), although it could possibly be a very lightweight desktop environment (unless perhaps you can figure out how to make “headless Chrome” or “headless Chromium” work in this application). If you can get this to work, you may be able to use it in a similar manner to the way PyGoogleVoice was used in the instructions below, but it probably won’t be nearly as easy to set up.
I had previously suggested that you might also want to keep an eye on this thread, GV Outbound Calls After EOL in the hope that something useful might be posted there. Another thread that was started by the same person is here: GV Callback script. The major issue with the solution posted in those threads is that the script shown only runs on Windows, which of course means it cannot be run on the same system as Asterisk and FreePBX (and for many users involves paying for a Windows license). And given the Windows propensity to do system upgrades at inopportune times, this is not a solution I would trust.
If no one is able to fix any of these scripts (to support logging into Google Voice, setting up the call, and then logging out), the method shown below will not work at all, ever, period. We now seem to have entered an era where no one wants to post complete instructions on how they get something like this running, or if they do the major search engines won’t index it (for example, as I write this there are no links on either Google or Bing to the thread about UI.Vision RPA that I linked above). I have been searching in vain for a web article or video that would show all the steps involved in getting something like this working with Asterisk and FreePBX, to no avail. There are pieces here and there, but no one is combining those pieces and explaining how they did it. Even this article is rarely accessed anymore, though that is understandable because I’m not able to provide a complete solution here.
Up until mid-December of 2023, the only semi-reliable method for connecting FreePBX to Asterisk involved the use of an Obihai/Polycom device 🤮, for example using the method shown here to connect Google Voice to FreePBX. But now the OBi200, OBi202 and OBi212 are considered obsolete, and if you have not already set one up to work with Google Voice you are probably out of luck, first because they are no longer being sold, but even if you could obtain one, the Obitalk configuration portal no longer supports those devices, so you cannot now set them up to use Google Voice. And if your device configuration is ever lost for any reason, you will not be able to add your Google Voice settings back in.
The only other possible option available now for such devices that were not configured while the Obitak portal was still functional or that have lost their configuration (which, by the way, is an option that the self-proclaimed “Google Voice Product Expert” you may encounter in various forums will never tell you about, nor allow anyone else to tell you about in the forums he moderates) is to use third party firmware and then read this very long thread for further instructions. This will require you to have a certain degree of technical prowess (and to assume responsibility if you manage to put your Obihai/Polycom device into a completely non-functional state). But, ultimately no one knows how long the OBi devices that still support Google Voice will continue to do so, so if you don’t already have an Obihai/Polycom device that is working with Google Voice, I do not advise trying to obtain one – it could be a lot of hassle for something that will only work for a short time, if it works at all.
So, it appears those are your two choices if you want to continue using Google Voice with FreePBX – use hardware that is now considered obsolete and that has already been set up to use Google Voice prior to mid-December, 2023 or figure out how to make one of the scripts work. There is a third choice mentioned on some other sites (naf’s GVSIP) but if you go that route you’ll find that it’s a bit of a pain in the butt to set up and get working unless you are very experienced (though maybe easier than any other solution proposed above), and you run the very real risk that Google will shut down your Google Voice account if they catch you using it, though to my knowledge so far no one has reported that their account has been shut down for that reason.
I’m leaving this article here in case someone does manage to rewrite one of the scripts, but please be aware that if you attempt to do this, I’m sorry to say that you’ll probably be disappointed with the results if you don’t or can’t fix one of the scripts so that it works reliably. If you do, please leave a comment and share how you did it! Also please be aware that much of the information in the text below has become obsolete. For example, Callcentric no longer offers free DID’s; their price for a residential DID is currently $1/month in December, 2023 (you may be able to get similar deals from other providers).
In mid-July, 2018 Google Voice shut down XMPP access. The problem is that if you have been using the Google Voice module in FreePBX, it used the XMPP protocol to connect to Google Voice, and that’s what no longer works.
Various possible solutions are being offered, including buying a new VoIP device and using it as a bridge between Asterisk and Google Voice. Unfortunately, at the time of this writing such devices are made by only one manufacturer, Obihai, a company I could not possibly have a lower opinion of. I used to like and support Obihai, but they have nuked any warm and fuzzy feelings I had for them in the past, several times over. My opinion now is that if you buy a new Obihai device, then P.T. Barnum was right when he said that there’s a sucker born every minute, and when you were born you fulfilled the quota for that minute! But, this is not intended to be a rant about Obihai (you can find those all over the VoIP forums, except in Obihai’s own heavily censored forum), but rather a way to keep using Google Voice with FreePBX and Asterisk, so you don’t need to buy any new hardware.
The FreePBX Google Voice module has become useless, so this method may be a bit more “hands on” than you are used to. To cut to the chase, the basic technique can be found in one of RonR’s posts in the above-mentioned DSLReports thread. Go ahead and open that up in another tab in your browser, because I’ll be referencing it throughout this article. But, that post only provides some basic configuration information, and makes some assumptions that are not clearly stated, such as that you are using FreePBX and that you already know how to perform basic administrative tasks such as creating a SIP trunk. While the general technique shown will also work with bare Asterisk (no FreePBX) or with other Asterisk-based GUI’s, you’re pretty much on your own in making the necessary dialplan modifications, or you could try following Twinclouds’ instructions (as mentioned in his comment on this article), which use a mostly similar but slightly different technique.
I should probably warn you here that this technique could potentially stop working at any time. It’s worked for years now, but when dealing with Google that doesn’t necessarily mean anything. There have been reports in late 2018 that although incoming Google Voice calls always seem to complete, outgoing calls to Google Voice will sometimes fail repeatedly for a period of time, particularly during daytime hours. Also, by publishing this I am explicitly NOT commenting on whether Google would approve of its use – I don’t work for Google, and I’m not a lawyer. If you suspect that using this technique may violate Google’s Terms of Service or some such thing, then please don’t use it until you consult with your own attorney. If you try anything shown in this post you are doing so of your own volition and at your own risk. I will not be responsible for any consequences that may occur. With that in mind, if you still want to try this technique, here’s what you need to do.
First, you must have a number coming into your system that is NOT a Google Voice number. This is sometimes referred to as a DID (and will be called that in this article), and if you don’t already have one, it is possible to get free DID’s from Callcentric. You need to have at least one DID coming into your Asterisk server, and you need to configure it as a destination (forwarding number) in your Google Voice account. So get your DID working first, and make sure you can make incoming calls to it using its assigned number. Then go into your Google Voice account(s) and set it/them up to forward calls to the DID. If you have already set up a forwarding number at some point in the past, you may still want to log in to Google Voice and check to make sure it doesn’t need to be re-validated – if you have let it lapse into an unvalidated state, Google Voice won’t forward calls to it until you re-validate it. If you tell Google Voice that the number is a “Work” number (you may need to go into “Legacy Google Voice” to do that), it can be used as a forwarding destination for at least two Google Voice accounts, and it is possible use one DID with two Google Voice accounts. So once you have your DID set up, you should be able to call your Google Voice number, and it will forward the call to your DID, and then the DID will send the call on to your Asterisk server. Note: If using Callcentric, you may wish to refer to this post: How to receive incoming Callcentric calls in FreePBX without creating multiple trunks.
Assuming you have your incoming DID working and Google Voice configured to use it as a destination, and you have tested it to make sure that the forwarding to your DID works when you call your Google Voice number, the next thing to do is is make a test call using pygooglevoice. But first you should determine whether it is installed on your system. From a Linux command prompt, enter which gvoice – if it returns a path such as /usr/bin/gvoice then it is already installed. If no path is returned, then install it using the instructions in RonR’s post mentioned above. EDIT: I’m interrupting this to note that RonR released a newer version written in PHP rather than Python, called gvcallback, which is an adaptation of an earlier program (you can read the entire thread if interested). However the syntax for calling the program isn’t exactly the same as with PyGooglVoice (though it’s very close) so you’d need to make some adaptations to the following instructions to account for the different syntax. The possible advantage of using the gvcallback program is that you don’t have to install all the dependencies that you have to install to get PyGoogleVoice to work. However, if you already have PyGoogleVoice installed on your system, there’s no compelling reason to switch to gvcallback that I’m aware of. Continuing on with the article…
Once PyGoogleVoice is installed, from a Linux command prompt, enter gvoice – it should prompt you for your Google Voice email address and password. If it connects successfully, you will see a prompt that looks like this: gvoice>. If you see a bunch of error messages (this is not unusual on the first run), refer to this DSLReports post by Cam_, which shows some of the things you may need to do to get it working. In addition, you may also need to let less secure apps access your Google account. (EDIT: Also see this DSLReports post by AllThumbs which notes that in addition to allowing less secure apps using this link, while logged into your Google Voice account and just prior to running pygooglevoice you may also need to visit this “Allow access to your Google account” link to get it working. Immediately after you click the “Continue” button, run pygooglevoice so that Google knows which “new device or application” you are trying to allow access from. Then, log into Gmail using your Google Voice account and check the Inbox – there will probably be an email from Google asking you to confirm that it was really you that just logged in, if so, do whatever the email tells you to do to confirm it. AllThumbs’ DSLReports post implies that you may have to do this again from time to time, and that will be particularly true if you don’t respond to any email Google may send asking for confirmation that it was really you, so save notes on this process. Yes, Google’s ultra-paranoid security can be a real pain in the butt sometimes).
If you think you may have a bad or old version of pygooglevoice, prior to reinstalling remove the following files from the /usr/bin directory: asterisk-gvoice-setup, gvi, and gvoice, and also check any /user/lib/python*/site-packages directories you may have for a directory called googlevoice and/or a file that starts with “pygooglevoice” and if you find either of those, remove those as well. Otherwise you may wind up with a mixture of files from the old and new versions, and that usually won’t work (also, do not run asterisk-gvoice-setup, it’s not meant for what we’re doing here). Note that there is a current version of pygooglevoice included in a download link in RonR’s post.
If you do get the gvoice> prompt, then enter the word call, and then it should prompt you for the outgoing number, which can be almost any valid 10 digit number in the USA or Canada. After that, it will prompt you for “Forwarding number [optional]:” but it really isn’t optional. What it is wanting here is one of your validated Google Voice destination numbers, such as your DID – NOT your Google Voice number! – and it wants it in the format +1 plus the ten digit number. If you try using just the ten digit number alone, it won’t work (at least not in my tests), it has to be in the form +1XXXXXXXXXX. Finally it will ask for the phone type; if you specified the number as a “work” number in the Google Voice interface then use 3. If you don’t remember how you specified it, try all three of the digits 1 through 3, one at a time – one of those should work. It may not actually matter if this number is correct in some cases; I’ve seen “1” work when the number had been specified as a “Work” number, for which the code should be “3”, but that’s not always the case.
If you entered everything correctly, you should not see any error messages, and in second or two a call should come in on your DID (hopefully you have created an Inbound Route, and made a nearby extension the temporary destination), and when you answer it you should hear the destination number start ringing. This part MUST work before you go any further – if you can’t get this to work then there is no point in doing any further configuration, because it won’t work either.
If it does work, you have a choice at this point. You can follow RonR’s instructions verbatim, which are probably fine if you are only dealing with one or two Google Voice accounts. But if you are dealing with a higher number of accounts, or if you just don’t like the fact that he hardcodes Parking Lot extension numbers, or if you don’t care to install and configure the Parking Lot module, you should know that I have made some modifications to his method, which I have added at the bottom of this article. For now you can do it either way, but be aware that because he hardcodes Parking Lot extensions, it will be impossible to place two calls on the same Google Voice account at the same time. However it may be impossible to do that anyway, if Google limits the number of simultaneous connections per account to three or fewer. Remember that with this method, there are actually two calls being placed from your account for each call you make – one to call your DID, and one to connect your call through to the called party.
I prefer not to use the Parking Lot at all, and instead to use Asterisk’s Bridge application, which I feel is much more suitable for this purpose, as I will explain in a moment. I do have some additional notes on using RonR’s original method, but I have moved them to the bottom of this article to make it a bit easier to read.
There is a caveat here. If Google changes their authentication protocols, this method could stop working until a pygooglevoice maintainer comes up with a patch. It’s happened before, though rarely, and it could happen again. If it does, incoming calls would still work, but outgoing calls would fail until the pygooglevoice code is modified to account for the change.
One other possible drawback to this method is that because pygooglevoice is considered a “less secure” app, Google may nag you with a “Security Alert” email every single time you place a call! One would hope that after you’ve confirmed that it was really you a few times, the emails would at some point stop, but if they don’t there is a way to turn them off – however in that case you won’t be notified if someone else really does try to hack your account. This is the method, according to Google:
We strongly advise leaving alerts on so you can hear about suspicious activity on your account. If you still want to disable alerts, follow the steps below.
Note: It takes about a week for alerts to get turned off. This is because Gmail wants to confirm it’s you that’s turning them off, and not someone else who might have access to your account.
- On your computer, open Gmail.
- In the bottom right, click Details.
- At the bottom of the page next to “Alert preference,” click Change.
- Select Never show an alert for unusual activity.
I have discovered that you don’t see the “Details” link unless you switch to the “basic HTML” view.
Here is my revision of RonR’s method – this uses Asterisk’s Bridge application, rather than the Asterisk Parking Lot. The advantage of using Bridge is that you don’t have to deal with the Parking Lot at all (you don’t even need to have the FreePBX Parking Lot module installed), and therefore the number of simultaneous calls is not limited to the number of available Parking Lot slots. Also you don’t have to worry about the changes in the “Park” application syntax between Asterisk versions. And, this method is better about cleaning up after itself, by removing database entries it has created after they are no longer needed. The only disadvantage is that the custom dialplan is slightly more complex.
If for some reason you really prefer to use the Asterisk Parking Lot (which I do NOT recommend), I do show alternative contexts that you can use, that more gracefully deal with a larger number of Google Voice accounts because they assign Parking Lot extensions starting with the highest available, and working down until one is found that is not in use. They are set to start with extension 78 and work down to 71. If you think there might ever be more than eight simultaneous outgoing Google Voice calls then you may need to extend the range of available Parking Lot extensions, but I think this will work for most people.
The instructions for installing PyGoogleVoice are the same (so refer to his post for that), but here’s how I configured it – note that values that you must change are in bold type:
Connectivity -> Trunks -> Add Custom Trunk
Trunk Name : username
Custom Dial String : LOCAL/$OUTNUM$@custom-username-out
Trunk Name : user2name
Custom Dial String : LOCAL/$OUTNUM$@custom-user2name-out
… and so on …
To help you keep the accounts straight, the user names should be the the same as the part of the Google Voice login names before the @ symbol. So if the login name is foo@gmail.com, the username would be just foo. This will be the case wherever you see “username” or “user2name” in bold.
Connectivity -> Outbound Routes -> Add Route
Route Name : username
Dial Pattern : see discussion below
Trunk Seq : username
Route Name : user2name
Dial Pattern : see discussion below
Trunk Seq : user2name
… and so on …
RonR only showed the dial pattern NXXNXXXXXX but that is only valid if your system only allows 10 digit dialing, and it doesn’t restrict a route to use by a particular extension. Possible patterns you might want to use include, but are not limited to:
NXXNXXXXXX/eee (where eee is a specific extension number that can use this route, and you can use patterns here such as 10X for all extensions in the range 100 to 109, or multiple instances of this line if needed for non-contiguous extensions).
1|NXXNXXXXXX/eee (same as above except allows dialing calls with a leading “1”, in case you allow 11 digit dialing)
aaa+NXXXXXX/eee (same as above except allows 7 digit calls to a particular area code, in case you allow 7 digit dialing – replace aaa with the area code)
The basic point here is that Google Voice expects to receive the called number as 10 digits, with no leading 1.
Admin -> Custom Destinations -> Add Custom Destination
Custom Destination : custom-NXXNXXXXXX-in,s,1
Description : Incoming calls NXXNXXXXXX
You need one Custom Destination for each DID you have coming into your system that is used by Google Voice. Replace “NXXNXXXXXX” with the 10 digit DID number, NOT your Google Voice number. Again, this change is just for your convenience in keeping everything straight.
Connectivity -> Inbound Route -> Callback Number
DID Number : NXXNXXXXXX
Destination : Custom Destination -> Incoming calls NXXNXXXXXX
Here you are making an Inbound Route for your DID, and sending it to the Custom Destination that contains the phone number of the DID, that was created in the previous step. So again, you need one of these Inbound Routes for each DID you have coming into your system that is used by Google Voice. In this case the Description can be anything you find meaningful. Leave ALL the other settings at the default – in particular do not enable “Detect Faxes” or “CID Superfecta”, or anything that might slow processing of the incoming call. If you need any of those features in incoming calls, you can enable them in the next section:
Connectivity -> Inbound Route -> Add Incoming Route
DID Number : NXXNXXXXXX*
Destination : Normal destination for this number
Here the DID number is the same as in the previous step except there is an added * character at the end. This is the Inbound Route for your DID that is used when it is NOT a Google Voice callback that arrives because you are making an outgoing call. In other words, if someone other than Google Voice calls your Google Voice number, or calls the DID that your Google Voice number is forwarded to directly, the call will wind up here, so normally you’d want the destination to be an Extension, Ring Group, IVR, or whatever. Since by the time the call gets here you know it’s NOT a Google Voice callback, you can enable features like Detect Faxes or CID Superfecta if you like. Again, the Description can be anything you find meaningful.
Additions to /etc/asterisk/extensions_custom.conf – first, the common contexts used by all accounts – these contexts are only added once, no matter how many Google Voice accounts or DID’s you have. I suggest using the “bridge” method rather than the Parking Lot method:
[custom-gv-out-common] exten => _X.,1,System(gvoice -b -e ${ACCTUSER} -p ${ACCTPASS} call ${EXTEN} +${RINGBACK} 1 &) exten => _X.,n,Set(DB(gv_dialout_${CUT(ACCTUSER,@,1)}/channel)=${CHANNEL}) exten => _X.,n,Wait(25) ; The following Noop lines are NOT optional, do not delete them exten => _X.,n,Noop(Never received callback from Google Voice on channel ${DB_DELETE(gv_dialout_${CUT(ACCTUSER,@,1)}/channel)} – exiting) exten => _X.,n,Goto(custom-gv-error,s,1) exten => h,1,Noop(User hung up while waiting for callback from Google Voice on channel ${DB_DELETE(gv_dialout_${CUT(ACCTUSER,@,1)}/channel)}) exten => h,n,Macro(hangupcall,)
Do NOT remove the Noop lines, they contain the function that deletes the unused database item if for some reason the returned call from Google is never received, or if the user hangs up before the callback is received. If you want your callers to hear Music on Hold rather than silence while waiting for the callback, replace
exten => _X.,n,Wait(25)
with
exten => _X.,n,Answer
exten => _X.,n,MusicOnHold(default,25)
You do have to “answer” the call or the music will not be heard. You can optionally replace “default” with any other valid Music on Hold context you have created.
IF FOR SOME REASON YOU PREFER TO USE THE PARKING LOT METHOD (NOT RECOMMENDED), then use this context instead:
[custom-gv-out-common] exten => _X.,1,Set(PARKINGEXTEN=79) exten => _X.,n(parkloop),Set(PARKINGEXTEN=$[${PARKINGEXTEN} - 1]) exten => _X.,n,GotoIf($["${EXTENSION_STATE(${PARKINGEXTEN}@park-hints)}" != "NOT_INUSE"]?parkloop) exten => _X.,n,GotoIf($["${PARKINGEXTEN}" < "71"]?custom-gv-error,s,1) exten => _X.,n,Set(DB(gv_dialout_${CUT(ACCTUSER,@,1)}/parkslot)=${PARKINGEXTEN}) exten => _X.,n,System(gvoice -b -e ${ACCTUSER} -p ${ACCTPASS} call ${EXTEN} +${RINGBACK} 1 &) exten => _X.,n,Park(default,t(25)c(custom-gv-error,s,1)rs) ;exten => _X.,n,Park(15000,custom-gv-error,s,1,rs) exten => h,1,Macro(hangupcall,)
This is the custom-gv-out-common context as used in the “Parking Lot” method. In the first line, 79 is one greater than the highest numbered Parking Lot extension (by default the Parking Lot uses parking extensions 71-78). You may need to change that if you increase the number of Parking Lot extensions. Also, I may be wrong but I believe that for the “${EXTENSION_STATE(${PARKINGEXTEN}@park-hints)}” function to work correctly, the “BLF Capabilities” setting in the FreePBX Parking module must be set to Enabled. While you’re in the Parking configuration, you may wish to set the “Pickup Courtesy Tone” option to None if you don’t want the beep tone when the callback arrives.
If you have an older version of Asterisk you might need to switch which of the “Park” lines is commented out – the one that is uncommented now is for newer versions of Asterisk. Also in the Park lines, the “r” in the “rs” signifies that you want fake ringing generated while waiting for the callback – if you omit it, it will play Music on Hold as specified in the “Parked Music Class” option in the FreePBX Parking module.
Two more additions to /etc/asterisk/extensions_custom.conf – Again these contexts are added only once. The second one is needed only if you are using the “bridge” method, which I recommend:
[custom-gv-error] exten => s,1,Playback(silence/1&cannot-complete-as-dialed) exten => s,n,Wait(1) exten => s,n,Playtones(congestion) exten => s,n,Wait(10) exten => s,n,StopPlaytones exten => s,n,Hangup() exten => h,1,Macro(hangupcall,)
The above is straight from RonR’s original instructions except for the hangup handler at the end; other than that only the context name is changed. When everything is working as it should, this context should rarely be used.
[custom-gv-cancel] exten => s,1,Answer exten => s,n,Wait(1) exten => s,n,Hangup()
The only real drawback of the “bridge” method is that if a user changes their mind about placing a call, and hangs up before the callback is received from Google Voice, Asterisk doesn’t know what to do with the callback unless you explicitly tell it what to do. So this answers the call and then hangs up, after a one second delay. In previous incarnations of this method there was a “cancel” option in pygooglevoice that could be used to cancel a call. The “cancel” function still seems to exist in pygooglevoice, but in testing it doesn’t seem to actually do anything, at least not for several seconds. I watched as Asterisk repeatedly sent the pygooglevoice cancel, only to see the call come right back in, and that loop lasted several seconds! So, it appears that the only reliable way to cancel the callback is to answer it and then hang up. If you want to experiment with the pygooglevoice cancel option, the syntax is simply:
exten => s,n,System(gvoice -b -e username@gmail.com -p password cancel &)
But if you can get it to work, you are having better luck than I did.
User-specific additions to /etc/asterisk/extensions_custom.conf – You must create these contexts for each user account or DID, as explained below:
[custom-username-out] exten => _X.,1,Set(ACCTUSER=username@gmail.com) exten => _X.,n,Set(ACCTPASS=password) exten => _X.,n,Set(RINGBACK=1NXXNXXXXXX) exten => _X.,n,Goto(custom-gv-out-common,${EXTEN},1) exten => h,1,Macro(hangupcall,)
You need one of the above for each Google Voice account, and you must change the username value in both places (don’t skip the context name) and the password value, and set the RINGBACK setting to the 11-digit DID number associated with this account (NOT your Google Voice number). “username” is just the part of the Google Voice login name before the @ symbol, same as in the Custom Trunks. If you are one of the very few people who has a Google Voice account where the login name doesn’t end in @gmail.com, then change that in the ACCTUSER setting as well.
[custom-NXXNXXXXXX-in] exten => s,1,GotoIf($["${CALLERID(number)}" = "Google Voice Number"]?cb1) ;exten => s,n,GotoIf($["${CALLERID(number)}" = "Google Voice Number 2"]?cb2); exten => s,n,Goto(from-trunk,NXXNXXXXXX*,1) exten => s,n(cb1),NoCDR() exten => s,n,GotoIf($[${ISNULL(${DB(gv_dialout_username/channel)})}]?custom-gv-cancel,s,1) exten => s,n,Bridge(${DB_DELETE(gv_dialout_username/channel)}) exten => s,n,Hangup() ;exten => s,n(cb2),NoCDR() ;exten => s,n,GotoIf($[${ISNULL(${DB(gv_dialout_user2name/channel)})}]?custom-gv-cancel,s,1) ;exten => s,n,Bridge(${DB_DELETE(gv_dialout_user2name/channel)}) ;exten => s,n,Hangup() exten => h,1,Macro(hangupcall,)
This uses the “bridge” method, which I recommend. You need one of the above for each of your DID’s that Google Voice sends calls to. You can have one or two Google Voice accounts coming to a DID if you have specified the DID as a “Work” phone in both accounts. If you have two, then uncomment the five commented-out lines. As usual, replace both instances of NXXNXXXXXX with the DID number (don’t skip the context name, and don’t lose the * character at the end of the number in the Goto line). “Google Voice Number” and (optionally) “Google Voice Number 2” should be replaced by the Google Voice numbers associated with your accounts in 10-digit format (no leading +1 here). “username” and (optionally) “user2name” are once again just the part of the Google Voice login names before the @ symbol – make sure to change them in both lines where they appear.
IF FOR SOME REASON YOU PREFER TO USE THE PARKING LOT METHOD (NOT RECOMMENDED), then use this context instead:
[custom-NXXNXXXXXX-in] exten => s,1,GotoIf($["${CALLERID(number)}" = "Google Voice Number"]?cb1) ;exten => s,n,GotoIf($["${CALLERID(number)}" = "Google Voice Number 2"]?cb2); exten => s,n,Goto(from-trunk,NXXNXXXXXX*,1) exten => s,n(cb1),ParkedCall(default,${DB_DELETE(gv_dialout_username/parkslot)}) ;exten => s,n(cb2),ParkedCall(default,${DB_DELETE(gv_dialout_user2name/parkslot)}) exten => h,1,Macro(hangupcall,)
This is the custom-NXXNXXXXXX-in context as used in the “Parking Lot” method. You need one of the above for each of your DID’s that Google Voice sends calls to. You can have one or two Google Voice accounts coming to a DID if you have specified the DID as a “Work” phone in both accounts. If you have two, then uncomment the two commented-out lines. As usual, replace both instances of NXXNXXXXXX with the DID number (don’t skip the context name, and don’t lose the * character at the end of the number in the Goto line). “Google Voice Number” and (optionally) “Google Voice Number 2” should be replaced by the Google Voice numbers associated with your accounts in 10-digit format (no leading +1 here). “username” and “user2name” are once again just the part of the Google Voice login names before the @ symbol. In the last two lines, in the ParkedCall options, you may need to omit the string “default,” if you are using an older version of Asterisk, because at some point prior to the current version the order of the items was flipped. In current versions the Parking Lot name is specified first, followed by the Parking Lot extension (which in this case is retrieved from a temporary database location), but in older versions the Parking Lot extension was given first, and then optionally the Parking Lot name.
EDIT: When using this method, you may run into a weird issue if you set one or more of your Inbound Routes for DID’s used by Google Voice to “Force Answer” under the Advanced tab, as you might if you are trying to keep calls from ever going to Google’s voicemail, or if your calls are answered immediately by an announcement or an IVR or by an Asterisk voicemail greeting or something similar. What happens is that when Google Voice forwards a call to a DID, and it’s not a “callback” of the type that the system receives when placing an outgoing call, you cannot answer the call too quickly. If you do, you will hear nothing but silence while the caller will continue to hear ringing until the call is sent to Google’s voicemail, which is in many cases exactly what you are trying to avoid.
In FreePBX inbound routes there is a setting called “Pause Before Answer” but for whatever reason it doesn’t seem to fix this problem. I think perhaps that may be because it doesn’t send a Ringing signal back to Google Voice, and Google Voice apparently really wants to see a couple seconds of Ringing before it will let the call audio go through!
So the only solution is to create a custom context in /etc/asterisk/extensions_custom.conf and then use that as the Context in the trunk associated with the provider of your DIDs. Here’s an example context:
[custom-from-my-provider] exten => DID1/GV1,1,Goto(from-pstn-e164-us,${EXTEN},1) exten => DID1/GV2,1,Goto(from-pstn-e164-us,${EXTEN},1) exten => DID2/GV1,1,Goto(from-pstn-e164-us,${EXTEN},1) exten => DID2/GV2,1,Goto(from-pstn-e164-us,${EXTEN},1) exten => _X!,1,Ringing() exten => _X!,n,Wait(2) exten => _X!,n,Goto(from-pstn-e164-us,${EXTEN},1) exten => h,1,Macro(hangupcall,)
The four lines that include DIDx and GVx are just examples – you would replace DIDx with your DIDs that you use with Google Voice (only the ones that are used for Google Voice callbacks when you are placing outgoing calls), and replace GVx with the one or two Google Voice numbers you have forwarded to that particular DID. So you might have only one such line, or you might have a few, depending on how many Google Voice numbers come into your system. The purpose of those lines is to avoid the delay when placing an outgoing call, because in that specific case it’s apparently not needed. The rest of the context puts the trunk in a Ringing state, delays two seconds, and then lets the call proceed to its ultimate destination. If your current trunk Context is not “from-pstn-e164-us” you can substitute whatever context it’s currently using in all the above lines where that context is referenced.
Change the Wait value if two seconds isn’t sufficient. This seems to be somewhat of a regional thing – in certain areas it seems no delays are needed at all, while in other areas an even longer delay might be required. Test using different delay values until you find the shortest one that lets your calls arrive reliably. Two seconds seems to be good for many people, but maybe not for all.
I’m including the following additional hints and information for those that for whatever reason really would prefer to user RonR’s original instructions, rather than the instructions shown above. I actually wrote these notes prior to documenting the above method. A small subset of these comments may still be applicable to the above method, but others clearly will not be applicable.
RonR shows two contexts, pgv-out-1 and pgv-out-2. First of all, I like to rename those to the Google Voice account names (the part of the email address before the @gmail.com) followed by -out, but if you are going to do that, you need to change those strings in all the other places where they appear in his instructions. If you have several accounts, using more meaningful context names could make it easier to know which account you are dealing with (I do this in my revisions above). And, you don’t need the second context (pgv-out-2) unless you are using the same DID as the forwarding destination for two Google Voice accounts. In the contexts themselves, you need to replace Usernamen@gmail.com and Passwordn with the actual login username and password for the account, and you must replace Callback Number with the actual 11 digit number of your DID (you do use the leading “1” here, but in this case the “+” character is added for you). The Callback Number is NOT your Google Voice number!
Also, the CALLPARK numbers must be unique in each context. You can see (and change) the allowable range of Parking Lot numbers by going into Applications | Parking. If you can’t find that selection, you may need to install the FreePBX Parking Lot module. Note that if you actually use the Parking Lot feature for something other than Google Voice, then make sure you use the highest available Parking Lot numbers in these contexts. If, probably like many users, you’re asking “What’s a Parking Lot doing in my PBX?” and have never used it and can’t imagine why you would, then you can use any of the allowable range of parking lot numbers (71 through 78 by default) in the CALLPARK settings.
In the pgv-out-common context there is a line that begins with exten => _X.,n,Park … and the line shown there is correct for the newest version of Asterisk, but the older ones used a much different syntax. For example, exten => _X.,n,Park(15000,pgv-error,s,1,rs) would be the correct equivalent in somewhat older versions. You may need to consult the Asterisk Wiki to figure out the proper syntax – in the left hand column, select your version of Asterisk’s Documentation, then Command Reference, then Dialplan Applications, and then Application_Park to see the proper syntax and the command options in your Asterisk version. By the way, the “r” option (in the “rs” string in the example) controls whether you hear a fake ringing tone while waiting for the callback from Google Voice – if you omit that “r”, you’ll hear the Music on Hold specified in the Parking Lot configuration for that (hopefully brief) period. I mention this only because some people may prefer not to hear a ringing tone until the called phone has actually started ringing.
Finally, the pgv-in-common context is another I like to rename, replacing pgv with something more meaningful (again you could use the Google Voice username, but that might not be appropriate if your DID is shared by two Google Voice accounts – I use the ten digit DID number in my revisions below). But again, if you change that string then you need to make the same change everywhere it appears in RonR’s instructions. In the first lines of the context, the “Google Voice Number n” strings must be replaced by the actual 10-digit Google Voice numbers, and if there’s only one Google Voice account associated with the DID then you can comment out (or remove) the line with “Google Voice Number 2” in it, and also the line with the (cb2) label. Also note that the ParkedCall(nn) statements must contain the correct parking lot numbers as set in the corresponding -out contexts. So each Parking Lot number should appear twice (and only twice), once in a -out context (or pgv-out-n if you use RonR’s naming system), and then again in a line with the (cbn) label in a -in-common context.
In the middle of the context there is a line, “exten => s,n,Goto(from-trunk,Callback Number*,1)” – here you replace “Callback Number” with the DID number that Google Voice is sending your incoming calls to, but in this case you’ll probably want it to be in 10-digit format (no leading + or 1). Do leave the * character, it’s not a typo. The purpose of this line is to handle calls that come in where someone has called your Google Voice number or your Callback Number (DID) directly, in other words when someone is calling you and the call is not a callback from Google Voice as a result of you placing an outgoing call. This line is why you’ll need a separate -in-common context for each of your DID’s used with Google Voice.
If you have multiple Google Voice accounts, then the general rule is that there has to be one -out (or pgv-out-n) context, and an associated Custom Trunk and Outbound Route for each Google Voice account. And, there must be one pgv-in-common context (if there is more than one context, each must have a unique name) for each DID that is used as a destination number by one of your Google Voice accounts, along with an associated Custom Destination. As for Inbound Routes, you’ll need two of those for each DID used by Google Voice, but one of them will have the * character appended to the phone number, as shown in RonR’s instructions. When you create the Inbound Routes, if you want to enable Caller ID Superfecta or any other type of local Caller ID lookup, do it only in the route with the * character at the end of the number. The use of any kind of Caller ID lookup on the non-starred number is pointless, and will slow down the connection time for your outgoing calls.
I also like to end all my contexts with a line of the form
exten => h,1,Macro(hangupcall,)
So just on the off chance the caller hangs up while in that part of the context, the hangup is correctly handled. But that is up to you.
It bothers me just a little that there appears to be no good way to cancel the call if the caller hangs up before the callback is received, but if that happens it appears that when the call comes in from Google the PBX will play a very short message about the parking lot number being invalid and then disconnect. So just be aware that if you call a number and then after dialing the last digit quickly change your mind and hang up, the called party’s phone may still ring once.
Up near the top of RonR’s post he shows how to set up the Outbound Routes (“Connectivity -> Outbound Routes -> Add Route”) and shows a Dial Pattern of NXXNXXXXXX which is correct for 10-digit dialing, but obviously you may need to add additional patterns if your system supports 7 or 11 digit dialing. You can limit the use of any particular Outbound Route to one or more specific extensions using Asterisk’s “ex-girlfriend logic” if you like.
That’s pretty much it. If you spot any errors, including any typos I haven’t yet caught, or know of a better way to do this, please leave a comment. This article may be updated if new information is received.
In Spring 2014, I wrote the original blog post “How to make and receive calls using Google Voice without XMPP” as it was likely Google was going to drop XMPP protocol in May 2014. The post attracted a lot of interest at that time. It received over 5000 visits. However, since Google eventually did not abandon XMPP, the blog was not very useful anymore.
Recently, it was announced that Google is going to drop XMPP from Google Voice on June 17, 2018 and it looks more likely to happen this time. People have started looking into the possibility of using Google Voice without XMPP again [1][2].
Due to the renewed interest, I tried the method described in my previous blog. It was found that the original approach still works after some necessary updates based on what described in [1]. The difference between my installation and that described in [1] and [2] is that mine is based on plain Debian/Ubuntu while theirs are build on top of Freepbx. The approach implemented in plain Linux may be less flexible and less versatile than the ones based on Freepbx. However, it should function fine for its scope. Moreover, the description in this revised blog uses a steps-by-step approach, which should be easier to follow if you want to try it out from ground zero.
The new blog post can be found in (https://hobbiesbytwinclouds.wordpress.com/2018/05/27/how-to-make-and-receive-calls-using-google-voice-without-xmpp-may-2018-revision/).
References:
[1] RonR’s post in “Google Voice XMPP support will go away in June” on DSLReport Forum (»Google Voice XMPP support will go away in June).
[2] How to use Google Voice with FreePBX and Asterisk without using XMPP or buying new hardware, TechNotes. (»tech.iprock.com/?p=21950)
Twinclouds, first of all I corrected the link in your comment for you, and second, I find it interesting that you bridge the calls together while RonR’s method (and my revision of his method) use the Parking Lot. I believe either method will work but it seems to me that in the early days of Google Voice, prior to the introduction of XMPP, the bridging method had a drawback in that it appeared to have a memory leak, so after about a week’s worth of usage you’d need to restart Asterisk or it would get really flaky (I had a cron job to do in in the middle of the night). However, I do not know if that memory leak has been fixed in newer versions of Asterisk (that problem was observed back in Asterisk 1.8, or maybe an even earlier version), and if it hasn’t then I don’t know that the Parking Lot approach doesn’t have the same issue. At this point I’m willing to say that either approach is probably just as valid unless actual usage proves me wrong. Anyway, thanks for your post, I’m sure it will be quite helpful to the bare Asterisk users.
Hi, TechNotes Admin:
Thank you for your correction and comment. As I said, I am not really a developer or expert on VOIP/Asterisk. I just picked up something that works for me. I will looking into the memory lead issue to see what I can do.
Thank you again for your help and comment!
I did a search on Asterisk bridge, not much was mentioned on the memory leak when using the bridge function, maybe this problem has been fixed?
I also notice that the current GV implementation using XMPP in Asterisk, either using OAuth2.0 or not, uses simple_bridge. I don’t know if it is the same as the bridge or not.
I think the memory leak may have been fixed, but I wanted to add the Bridge option to my article and while doing so, I noticed another problem that likely affects your code as well. You use this:
System(gvoice -b -e [gvusername]@gmail.com -p [gvpassword] cancel &)
But as noted in my June 7 addition to the article, my experience is that either this isn’t working at all, or it takes so long to work that it’s useless, I am not certain which. What I wound up doing was intercepting the “orphaned” incoming call from Google Voice, answering it and then immediately hanging up (after a one second wait). In my (admittedly very limited) testing that was the only thing that would reliably abort the callback. Perhaps gvoice cancel works in a non-FreePBX environment, but it does not seem to work in FreePBX for some odd reason
Thanks.
I must took the line with cancel somewhere. It seems works fine so far on plain Asterisk. Not sure if it will cause problem on FreePBX or not. Due to my limited experience in Asterisk, sorry I just cannot help more.
Please let me know if you find out more, though.
It is possible to use selgooglevoice which is “A Selenium with Python replacement for pygooglevoice”, to use googlevoice on Asterisk.
The author of the selgooglevoice program wrote 3 versions, the first 2 are to be used with Python2, the 3rd one which was released to “Improve reliability” is to be used with Python3.
selgooglevoice requires Python (2 or 3 depending on which version of the program you’re using), google-chrome with matching chromedriver, and selenium. The Python script runs Chrome in headless mode thus enabling it to work from the command line.
The Login no longer works but is bypassed if the cookie file (called Cookies) that contains a working saved google login is in place. It’s easy to get a cookie file by one time running a live CD/USB version of your linux, and from there using the desktop version of Chrome to create a new cookie file. Then copy that cookie file to the hpk/cd/selenium/Default directory on the system that you’ll be running selgooglevoice on. From Asterisk, it’s a little slow but functional.
Looks like there hasn’t been any interest in this in over 3 years and this is the only forum that I found referencing selgooglevoice so I thought I would share my findings here.
Jeff, I very much appreciate this comment, however my problem with selgooglevoice has always been that the understandable instructions are just not there. Even your comment leaves me with questions – I get part of it, but not all of it. For example:
1. I am assuming that the version of selgooglevoice at https://github.com/tsdg112/selgooglevoice is the Python3 version? Because that is the only version I can find on the web at this time.
2. Exactly how do you install google-chrome on a headless system without having a desktop installed? Using apt install google-chrome does not work in Debian or Ubuntu (I get “E: Unable to locate package google-chrome“). I could install chromium, but it wants to also install everything but the kitchen sink:
(This is part of the output of sudo apt install –dry-run chromium):
To me that sort of looks like it’s installing a lot of desktop-related components! There are even video drivers in there, which would be useless on a headless server!
3. How do you install chromedriver? Once again, apt install chromedriver doesn’t work. It looks like even figuring out which version to download isn’t exactly straightforward (https://chromedriver.chromium.org/downloads/version-selection) but I found nothing resembling useful installation instructions – they may be somewhere on that site but if so I did not find them!
4. How do you install Selenium? No, apt install doesn’t find that either. If you go to their site (https://www.selenium.dev/) the front page shows three different possible downloads, and if you go to their installation page (https://www.selenium.dev/documentation/en/selenium_installation/) it gives you a paragraph of cryptic mumbo-jumbo but doesn’t actually tell you how to install it!
At least I get the part about using a cookie file, that is easily done using a Chrome extension such as Get cookies.txt (https://chrome.google.com/webstore/detail/get-cookiestxt/bgaddhkoddajcdgocldbbfleckgcbcid). But that’s only because I’ve had to do that before with another command-line script that also uses cookie files. Of course that assumes the same technique will work with this method.
My problem with this method has always been that unless you happen to already be familiar with these pieces of software (I had never head of them prior to this, and still don’t really understand what Selenium even does) it’s going to be nearly impossible for the average user to get all this installed and working, unless someone writes a decent walk-thru or posts a video showing the process.. But also, if really you have to install some version of Google Chrome or Chromium that brings in around 190 new packages, including a lot of crap that is absolutely useless on a headless system, then my interest falls to a very low level. That said, if you or anyone can provide decent instructions on how to install all this and get it working, I’d love to see it posted just so at least some method is available that doesn’t involve buying hardware!
Package names vary from one flavor of linux to the other and also vary by which package installer you’re using. I think this is where step by step instructions will fail because they would only pertain to that particular version of linux.
Here is how I installed the packages for Ubuntu 18.04
Install asterisk 13
apt install asterisk
Install Chrome from command line: (I was not able to install this directly, so I had to download chrome specific to my version of linux google-chrome-stable_current_amd64.deb and then use apt install to install it from a file. I got the file from https://www.google.com/chrome/ and after poking around on that page was able to find the linux version and wget it from there.
apt install ./google-chrome-stable_current_amd64.deb
Install ChromeDriver
Get latest chromedriver from: https://chromedriver.chromium.org/downloads (make sure chromedriver version matches chrome version)
install version of chromedriver based on version of chrome
i.e. wget https://chromedriver.storage.googleapis.com/91.0.4472.19/chromedriver_linux64.zip
unzip chromedriver_linux64.zip
Set proper permissions/owner/executable flag for chromedriver.exe
sudo mv chromedriver /hpk/cd/chromedriver.exe
sudo chown root:root /usr/bin/chromedriver.exe
sudo chmod +x /usr/bin/chromedriver.exe
Installing Selenium is easiest with pythonpip
apt install python-pip
pip install selenium
and for python3
apt install pip3
pip3 install selenium
To find all the versions of selgooglevoice, on the developer’s page: https://github.com/tsdg112/selgooglevoice
you can click on where it says 3 commits: https://github.com/tsdg112/selgooglevoice/commits/master
and you’ll see 3 versions there. The Commits on Jul 14, 2020 is for Python 3 and Commits on Jul 26, 2019 is for Python 2
I had to edit the latest Commit (Jul 14, 2020) for python3 as the line to run Chrome headless is commented out, so I uncommented it so Chrome would run headless.
If you’ve successfully installed everything you can test it from the command prompt:
python /usr/src/selgooglevoice/gvoice.py email@address.com password 1NPANxxxxxx
and the response should be this (without the Cookies file)
LOGIN
PASSWORD
Traceback (most recent call last):
File “/usr/src/selgooglevoice/gvoice.py”, line 33, in
driver.find_element_by_id(‘Passwd’).send_keys(sys.argv[2])
File “/usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/webdriver.py”, line 360, in find_element_by_id
return self.find_element(by=By.ID, value=id_)
File “/usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/webdriver.py”, line 978, in find_element
‘value’: value})[‘value’]
File “/usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/webdriver.py”, line 321, in execute
self.error_handler.check_response(response)
File “/usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/errorhandler.py”, line 242, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {“method”:”css selector”,”selector”:”[id=”Passwd”]”}
(Session info: headless chrome=91.0.4472.77)
Once you have the Cookies file installed, the response will be:
INPUT_0
(‘ID:’, u’select_option_7′)
END
and a call will be placed based on the account stored in the Cookies file you used, regardless of what you put in on the command line for email address and password. You may have to bypass the unlock captcha: https://accounts.google.com/b/0/displayunlockcaptcha and also allow “less secure app access” to run on your google accounts security setting.
KEEP TRACK of processes as running this from the command line will create a lot of hung chrome processes (which will slow your system down) so put this in your script or run manually:
pkill -9 chrome
I’m not really good on python/html programming but I hope someone can improve on this and
1. Make the login work again so that we don’t need to put in a Cookies file. Without the Cookies file, It seems that when it attempts to log in it crashes on finding where to put in the password on the googlevoice page. I know google changed the login format a few times over the years but I don’t think it would be that complicated to figure this out. They use different pages for the login name and password, I just don’t know HTML well enough to understand it.
2. There may be a way to install chrome without all the unnecessary dependencies (video drivers, etc).
Thanks, Jeff. Just so you know, normally when someone leaves a comment I receive an email notification and then have to approve it (a spam prevention measure). Somehow your post did not generate the email notification this time around, so it sat there for quite some time until I realized it was there and approved it. I apologize that it took so long.