Turning your OBi200 and OBi202 into a SIP-to-Google-Voice Bridge

I have successfully programmed five OBi devices (three using Method 1 and two using Method 2) to perform the SIP/GVsip bridge function using these notes. I use these devices on a daily basis to interact with my Asterisk servers. In addition, I have exchanged emails with perhaps a dozen other individuals who have successfully implemented their own bridge using these notes. 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. In mid-2018, Google shut down its XMPP servers — the protocol the Asterisk PBX used 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 pressed 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 two ways to make the changes we will be making below. One way is through the obitalk.com website using their Expert interface. The other is via the OBi's built-in web server (but only if Auto Provisioning is disabled first, or they will fight each other). Unfortunately, the Expert interface lacks the ability to enable X_EarlyICEEnableIn, and without this feature being enabled unanswered outbound calls will generate an error 503 after approximately 22 seconds of unanswered ringing, effectively denying access to most voicemail systems and answering machines. Because of this, I recommend disabling Auto Provisioning and using the built-in web server to configure your OBi. However, if you still prefer the online Expert interface, X_EarlyICEEnableIn may be enabled via the built-in web server and the rest configured via obitalk.com.

One shortcoming of using an OBi for Google Voice access is that you must have a physical location and network in which to place your OBi device, and this makes interfacing your OBi to a remoted Virtual Private Server (VPS) problematic when compared to a software-only solution.

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:

Identify the IP address of your Asterisk server along with the Port number it is listening on for the protocol (SIP or PJsip) you will be using.

Do the same for your OBi device. (Dial "***1" from a phone port to get its IP.)

Record which Voice Profile on the OBi is associated with each GV trunk you will be using and which will be associated with its SIP counterpart, and record the listening port of the latter. (The OBi's listening port for a given Voice Service is listed under the X_UserAgentPort parameter for that SP.)

Identify the Service Provider Profile ('A', 'B', 'C', or 'D') associated with each of the Voice Profiles above.

In the descriptions below, I use SPx to denote the Sip-side SP assignment and SPgv for the Google Voice side. The "x" and "gv" should be replaced by the appropriate numeric voice service designator for your setup.

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.

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:

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

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:

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 GV-side service:

*** 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.

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:

See if GV works by itself: You should be able to initiate a GV call from the attached phone port on the OBi by using the "**X" prefix, where 'X' is the number associated with the SPgv Voice Service. And, you can change the SPgv X_InboundCallRoute to "{:ph1,sp1(6145551212)}" to ring the OBi phone port on incoming calls in addition to passing the call to the SIP channel.

If GV works, but you can't receive incoming calls, make sure your OBi is talking to the right port on your PBX: If you're using Method 1, this should be the SIP listening port; for Method 2 it should be PJSip. These are usually ports 5060 and 5160, but which-is-which is a tossup, so make sure you know the configuration of your PBX before you begin. Set the SIP-side ProxyServerPort to this value.

If you can't originate calls from your PBX using Method 1, make sure your PBX is talking to the right port on your OBi: Each SP has a "listening port" called the X_UserAgentPort. Make sure your port entry in your Outgoing Peer Details points to your OBi's SIP-side X_UserAgentPort.

If you're using the Expert interface on obihai.com, verify the changes via the OBi's internal GUI. I've seen one case where the Expert interface did not reflect the true configuration on the OBi. (Note: Only verify under these circumstances; don't make changes here as any changes made via the internal GUI will not stick.)

If you are using iptables on your server, verify that the configuration allows for access from the OBi.

Make sure that SIP ALG is disabled on any intervening router.

Verify that the SIP and GV services on the OBi are both functional: The GV service should say Connected on the OBi Status page. For Method 2, the SIP service should show Registered. Method 1 should show Registration not required.

Check the Call History page on the OBi's internal webserver for any information it may have recorded on the failed call.

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:

Sign up for a "free" account at pbxes.com. It will set you back $15 for their one-time signup fee, but after that there are no recurring charges and pbxes.com can bridge to Google Voice, although it is unclear whether they have inked an agreement with Google to permit them to do so legally.

A group of folks at DSL Report's VOIP Tech Chat forum, led by 'NAF', reverse engineered the new Google protocol and made modifications to PJsip to provide native support for GVsip under PJsip, a solution which certainly proved to be one of the the better ones. However, this work was essentially shut down when Google indicated it was in violation of their terms of service and modified their servers to prevent its use.

Finally, with the price of commercial VoIP service at an all-time low, it's certainly feasible to consider scrapping Google Voice altogether and going with a paid provider. For example, Sam Moat's CircleNet, has US48 rates which have been hovering as low as .002 cents/minute.

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.