Turning your OBi200 and OBi202 into an ITSP for Google Voice

Robert Stampfli — r5519@cboh.org — Published June, 2018; last updated Friday, 8 July 2018

Please Note: Although I have successfully programmed three OBi devices to perform the SIP/GVsip bridge function using these notes, and use these devices on a daily basis to interact with Asterisk servers, I have received limited feedback from others. While these notes were clear enough for me — after all, I wrote them — there are numerous ways in which minor differences in initialization, interpretation, and/or execution can lead to a lack of success. So, if you are struggling, feel free to contact me so that not only can we get your issues resolved, but also so that I can document the problem and make these notes clearer as a result. And, successful or not, feel free to critique these notes if you see areas where they can be improved.

Introduction

Many VoIP hobbyists and experimenters have come to rely on Google Voice for their trunking needs. While it's certainly not a perfect fit, it can be made to work reasonably well and free offsets a multitude of sins. Recently, Google announced it will be shutting down its XMPP servers — the protocol the Asterisk PBX uses to access GV. Polycom (neé OBiHAI) makes the only non-Google devices which currently have access to the new GV network with Google's blessing, and this got me thinking: The OBi 200 and 202 devices are themselves a feature-rich ATA — some might even say a mini-PBX in themselves — capable of handling four trunks and/or endpoint devices. Could they be pulled into service to provide a SIP-to-GV bridge? Think of this as a small localized version of Bill Simon's Google Voice Gateway. After some experimentation I came to the conclusion that, yes, they can.

I was able to interface an OBi202 to an Asterisk 13 server such that (1) outgoing calls from Asterisk would flow into the 202 using the SIP protocol, where they would be bridged to a corresponding GV line to complete the call. And (2) incoming GV calls would be automatically translated into SIP and delivered to Asterisk. In essence, the OBi200 or 202 ATA look like an ITSP to the Asterisk server and make it possible for Asterisk to continue to support up to three GV lines per OBi.

The OBi200 can be had for around $50 and as low as $35 on sale. The 202 costs a bit more. However, many of us already use these OBi units as ATAs in which case the additional functionality can often be added without any additional hardware costs.

What follows is a description of how to configure Asterisk and the OBi device to accomplish this task. Every configuration option described herein is based on publicly available published documentation. I will address two scenarios: The first, and simpler, implementation presumes that the Asterisk server and OBi device are on the same local LAN. The second, more involved, approach will work with an Asterisk server with a static IP address on the Internet interfacing with an OBI sitting behind a firewall that has a dynamic IP. (Think Asterisk on a VPS here.)

These notes presume the reader is familiar with programming the FreePBX Asterisk server, including how to add a trunk and make it functional. My personal testing was performed on a FreePBX 13 system running Asterisk 13. A Debian 8 system supported the first implementation and a CentOS 6 system the second.

There are several ways make the changes we will be making below. One way involves disabling all OBiTalk updates and making the changes via the OBi's built-in web server. Although I rather dislike dealing with programming the OBi via OBiTalk.com, it's probably easier overall to bite the bullet use the OBiTalk Expert interface. If you are not familiar with how to do this, take the time to learn how it works before you begin.

One shortcoming to this approach has surfaced since its introduction: If the called number is not answered within about 23 seconds of call placement the OBi returns a SIP error 503 (trunk congestion). This most often occurs when the call is about to roll to an answering machine or voicemail system. We are continuing to investigate this problem.

Preliminaries...

Verify your OBi firmware is current:
You must be on a firmware load that supports the new GVsip protocol or GV will not work. The firmware ("Software Version") can be found under Product Information on the status page, from either the device's internal server or the OBiTalk.com website. The version must be 3.2.2 Build 5859EX or later.
Program the GV service(s) into your OBi:
This is normally done using the OBiTalk.com interface. Refer to the instructions on the website.

Make a note of the site-specific data you'll need:

Method 1: Your OBi and Asterisk are on the same LAN

If your Asterisk server and OBi are located on the same LAN and both have static IP addresses, then this method should work and is the simplest way to proceed. No registrations or authentications are needed; instead, the IP addresses themselves provide the necessary authentication. For the OBi, a static IP address can either be assigned manually, or by setting up your DHCP server to always serve the same IP address when presented with the OBi's MAC address. The latter is often the easier way to make this happen.

The OBi20X boxes have support for four Voice Services, named SP1 - SP4. It also has provisions for handling four Service Provider ITSP Profiles. By convention, SP1 is linked to ITSP Profile A, SP2 to Profile B, etc., but this is not a requirement.

In addition to the GV Service(s) you already have programmed (via OBiTalk.com), you'll need at least one unencumbered Voice Service for the SIP-side interface. In the description below, I use SPx to denote the Sip-side SP and SPgv for the Google Voice side. The "x" and "gv" should be replaced by the appropriate numeric voice service designator for your setup.

Now, before we begin, raise your right hand and repeat after me: "I will NOT change any parameter under any Google Voice Service or its ITSP Profile except for X_InboundCallRoute". If you do accidentally change a GV parameter it may break your GV or cause odd problems which are hard to diagnose.

On the OBi, here are the changes I made to the default settings, or in the case of SPgv, the settings OBiTALK made when setting up the Google Voice Service:

*** Changes to the OBi SIP-side service:

Using the ITSP profile you previously assigned to your SIP Voice Service:
Service Providers > ITSP Profile X > SIP > ProxyServer          [Set to the IP-addr of your A* Server]
Service Providers > ITSP Profile X > SIP > ProxyPort            [Set to the listening SIP port on your A* server (typically 5060 or 5160)]
Service Providers > ITSP Profile X > SIP > X_SpoofCallerID      (check)

Voice Services > SPx Service > X_ServProvProfile                [The ITSP profile you selected and modified above]
Voice Services > SPx Service > X_InboundCallRoute               {SPgv}
Voice Services > SPx Service > X_RegisterEnable                 (uncheck)
Voice Services > SPx Service > AuthUserName                     OBi202 *
Voice Services > SPx Service > X_EnforceRequestUserID           (must be unchecked)
–––––––––––––––
* – AuthUserName can be anything, but it must match username below.

*** Changes to the OBi GV-side service:

(This will be the only change you should make to the GV Service.)
Voice Services > SPgv Service > X_InboundCallRoute       {SPx(6145551212)} ¹
–––––––––––––––
¹ – Substitute your GV DID for 6145551212.

A word about the choice of a DID number above: Any number will work here as long as it does not conflict with another number on your server, but your GV DID is a good choice because it is logical as well as unique. You can prepend a leading '1' to it or not; just make sure it matches the DID you code in the Inbound Route below.

*** Changes on your Asterisk/FreePBX server:

Create a SIP trunk:
Creation is straightforward and left as an exercise for the reader. I set Maximum Channels to '2' to avoid abusing GV. The Incoming SIP Settings should all be left blank. The Outgoing Peer Details should contain something like:
host=192.168.1.202 *
port=5060 ¹
username=OBi202 *
type=peer
context=from-pstn
insecure=invite,port
qualify=yes
directmedia=no
disallow=all
allow=ulaw,opus ²
–––––––––––––––
* – replace with whatever is appropriate in your environment
¹ – replace with the value of X_UserAgentPort in the above SPx.
² – Remove ,opus if your server does not support this codec.
Create an Outbound Route
No special configurations are required here.
Create an Inbound Route
No special configurations are required here. Use your GV number, the one you substituted for 6145551212 above, as the DID.

Method 2: You have an exposed Asterisk server with an OBi behind a firewall

Notice that the above implementation was done without any registrations. Registrations exist (1) to inform the far end of an endpoint's IP address when it is dynamic, and (2) to circumvent NAT issues. On local LANs, neither is typically a problem and thus registrations are rarely required or desired — you can just code the applicable IPs and Port numbers directly. However, VPSes don't have local LANs — at least not LANs that can do us any good. So, can we use our OBis to provide GV access to VPS PBXes? The answer is again yes, we just need to situate the OBi at a convenient spot on the Internet that we control, and hopefully one "close" (in Internet terms) to the VPS to avoid latency issues.

Here's the tricky part: If the convenient spot of choice is served by a dynamic IP address or located behind a firewall then you'll probably have to resort to using registrations. Normally, we are familiar with registrations in two contexts: (1) registering extensions (our VoIP phones), and (2) registering with ITSPs to gain access to trunks. In this case, however, we are dealing with something rarely encountered — here it's the OBi box (the ITSP) that has the labile IP address, so it needs to register with Asterisk (the client) as opposed to the other way around. Let's see how we can make this happen.

To be honest, I never could make this happen with SIP. I could get as far as answering a ringing phone, but never could get the audio. Hence, I abandoned SIP on the Asterisk server and went with PJsip.

*** Changes to the OBi SIP-side service

Service Providers > ITSP Profile X > SIP > ProxyServer          [Set to the IP addr of your A* server]
Service Providers > ITSP Profile X > SIP > ProxyPort		[Set to the PJsip listening port of above server]
Service Providers > ITSP Profile X > SIP > RegistrationPeriod	(not less than 120) ¹
Service Providers > ITSP Profile X > SIP > X_SpoofCallerID      (verify UNchecked, for now)
Service Providers > ITSP Profile X > SIP > X_NoNonceAuth	(check) ¹

Voice Services > SPx Service > X_ServProvProfile                [The ITSP profile selected above]
Voice Services > SPx Service > X_InboundCallRoute               {SPgv}
Voice Services > SPx Service > X_AcceptsSipFromRegistrarOnly    (check) ¹
Voice Services > SPx Service > X_NoRegNoCall                    (check) ¹
Voice Services > SPx Service > AuthUserName                     OBi200 *
Voice Services > SPx Service > AuthPassword                     (set passwd)
Voice Services > SPx Service > X_EnforceRequestUserID           (verify unchecked)
–––––––––––––––
* – Select AuthUserName at your discretion, but it must match Trunk name below.
¹ – Not required, but this setting suggested for additional security and/or efficiency.

*** Changes to the OBi GV-side service:

Voice Services > SPgv Service > X_InboundCallRoute               SPx(6145551212) ¹
–––––––––––––––
¹ – Substitute your GV number for 6145551212.

*** Changes on the Asterisk/FreePBX server:

Note: If you are replacing a Motif trunk on your server, we recommend removing the trunk and Motif entry before adding the PJsip trunk below. Otherwise, unless you are careful, the Motif removal may also remove the newly added PJsip trunk.

Create a PJsip trunk:
Under Connectivity > Trunks > Add Trunk > chan_pjsip
General > Trunk Name 						[same as AuthUserName above]
General > Outbound CallerID					[The Google Voice Number above]
PJsip Settings > General > Secret				[same as AuthPassword above]
PJsip Settings > General > Authentication 			(select Inbound)
PJsip Settings > General > Registration				(select Receive)
PJsip Settings> Codecs						ulaw (+ opus if you have it)
Create an Inbound and Outbound route:
(Refer to the Inbound/Outbound documentation above.)

Troubleshooting:

If everything to this point has gone according to plan, you should now be able to call in and out on your new trunk. But, what do you do if your setup doesn't work? Here are some pointers:

Have your Cake and Eat It Too: Passing Inbound CallerID (Method 2):

If you've played around with your new trunk at all, you've probably noticed that it does not pass the proper CallerID. Instead, it substitutes the name of the trunk. This is because we did not set X_SpoofCallerID above. But, unfortunately, our hands are tied, as PJsip relies on the trunk name being passed to match the incoming call to the proper trunk. If we spoof the CallerID, we get a PJsip error and the call never completes. Fortunately, though, there is a way to work around this, and I'm sure you want to know who's calling, so lets make it happen!

It turns out PJsip implements several algorithms for matching an incoming call to a PJsip trunk, but only two (three if you count Anonymous) are activated by default. The first uses the SIP INVITE's IP address, but this doesn't work for us because (among other reasons) our address is dynamic. The second uses the first part of the FROM field of INVITE, the same as what we need to spoof, so this won't work either. However, there is a third option that uses the AUTHENTICATE field of the INVITE, and since we always authenticate our incoming GV calls, this looks like an excellent alternative for us. But, since tha AUTHENTICATE option is not active by default we need to activate it via a PJsip configuration change. Unfortunately, it seems to be beyond the capabilities of FreePBX to accomplish this, so we'll have to modify the Asterisk config files directly.

Insert the following line at the very top of /etc/asterisk/pjsip_custom_post.conf, which up to this point is likely an empty file:
endpoint_identifier_order=ip,username,auth_username,anonymous
Next, add the following to /etc/asterisk/pjsip.endpoint_custom_post.conf
[OBi200](+)
identify_by=auth_username
where the OBi200 above is whatever you named your trunk. Finally, reload PJsip to allow the above changes to take effect:
asterisk -rx "module reload res_pjsip.so"

Don't be surprised if the above reload command produces a few errors from the pjsip.conf file concerning an identify object; they come from the code FreePBX generates and are apparently benign. Now you should be able to go back to your OBi and check X_SpoofCallerID on the SIP-side SPx to allow the original CallerID to be passed to Asterisk.

Optional Enhancements:

One Google Voice Line, Multiple Endpoints

There is no reason why multiple endpoints cannot use the same GV line. Provided you have a remaining unassigned Voice Service, it can be pressed into service as a second SIP-side interface. Just configure it as described above, as if it were the sole user of the GV trunk. In this case it would be prudent to set Maximum Channels so as to avoid overloading the GV channel should both endpoints attempt to use the GV line at the same time.

Of course, incoming calls will be routed according to the GV channel's X_InboundCallRoute (which, incidentally, does not need to be set to one of the outgoing endpoints). Typically, these calls will be routed to only one destination, but here is an example of an X_InboundCallRoute which will ring two endpoints simultaneously and dispatch the call to the first one answered:
X_InboundCallRoute			 {sp3(6145551212),sp4(6145551212)}

Multiple Google Voice Lines, one Asterisk Trunk

In a similar vein, one Asterisk trunk can be made to control all the GV lines assigned to an OBi. You can direct a call to a specific GV line based on several criteria such as the called number, a prefix code, or even the passed CallerID. (Since GV will not pass CallerID, opting instead to always use its own number, this makes the passed CallerID a good candidate for selecting between GV lines.) This post from dslreports, https://www.dslreports.com/forum/r31956002-, describes in greater detail how this is done.
The following route will direct a call to SP1 if the passed CallerID matches 6145551212, else the call will go to SP2:
X_InboundCallRoute				{6145551212:sp1},{:sp2}

A word about how to configure this in FreePBX: Create the trunk, but make sure that CID Options is set to "Allow Any CID". Then create two or more Outbound Routes, one for each Google Voice instance. Code the applicable GV number in the Route CID field of each Outbound Route, and the check Override Extension "Yes". Now each Outbound Route will pass its CID to the OBi, which will in turn direct the call the the proper GV instance.

Installing the Opus Codec on Asterisk

GVsip uses two codecs, ulaw and opus. While theoretically only ulaw is needed on the SIP side, it's handy to have to have the opus codec on Asterisk so no transcoding is necessary. Unfortunately, all my systems already had opus installed, so these instructions have never been tested in a opus-free environment.

I believe opus is installed by default in Asterisk 14, but must be explicitly built into Asterisk 13. There are two ways to accomplish this: The preferred method is to build and install opus as part of the Asterisk build. However, there is a quick and dirty alternative for Intel-based servers which involves downloading the libraries from Digicom and manually copying them into the Asterisk directories. This latter method worked fine for me. I used the notes from https://gist.github.com/worldadventurer/757bf4b10af2356d83d57a8a6bb3e4e8 to do the install on my system. Just make sure when you are done that you perform an " asterisk -rx 'core show translation' " to verify the codec is indeed loaded and usable.

Other Alternatives:

Although the OBi solution has worked well for me, it is only one of several options available to Asterisk users. With the announced impending demise of Bill Simon's excellent Google Voice Gateway, which was essentially a similar implementation done on a grander scale using commercial hardware, I see the following as potential alternatives:

Final Thoughts and Observations:

The OBi solution for adding Google Voice lines as trunks on an Asterisk system is viable and if OBi20x boxes are already in use as ATAs the additional functionality can often be added to them at no additional hardware cost. The implementation appears robust and, especially if everything resides on the same LAN, adds only minimal latency compared to the existing XMPP solution.

These instructions are designed for and were tested with a FreePBX/Asterisk server. However, they no doubt could be updated to apply to any VoIP PBX, or even providing Google Voice support for the older OBi100 series of devices.

One final caveat: Understand that it was never Google's intent for Google Voice to sub as a provider of free PBX trunks. As we alluded to in the first paragraph, these notes are mainly directed towards hobbyists and experimenters, not professionals running call centers. The OBis may be the equivalent of a Swiss army knife for VoIP interconnections, but that doesn't alter the fact that if you run afoul Google's Terms of Service (aka "The Gospel According to Google, available to only a select few", to paraphrase a recent Bill Simon post), don't be surprised if you find your Google Voice service suspended.