Microsoft Teams Direct Routing with Cisco Cube Part Two

In part one of this blog post I discussed why we choose to use the Cisco Cube router to route calls to Microsoft Teams. Before I discuss how to configure Call Manager to route calls to Microsoft Teams, I would like to point out that Cisco Cube is not the only game in town when you are integrating Cisco Call Manager with Microsoft Teams. Another great choice (I might have went with this after seeing some of the struggles and lack of documentation from Cisco) is AudioCodes. They have great documentation and support a number of configurations. You can also run AudioCodes on a VM if you would like. (You can run the Cisco Cube on a VM also, but I would be concerned about DSP resources. Our vendor suggested we should not run the Cube router virtually and I agree with that assessment.)

I am going to assume that you have the router configured and on your network and you have opened the firewall to allow Microsoft Teams to communicate with the router. I am also gong to assume you have all of the TLS/SSL certificates installed on the Cisco Cube Router and you have selected a hostname and have configured that name in your public DNS. You should also have your SIP profile and SIP security profile created. I am not going to discuss how to create the profiles or the settings needed in those profiles.

Cisco Call Manager

The first step is to create a SIP trunk from Call Manager to the Cisco router. Name the trunk and give it a description and put it in the device pool that makes sense for your environment. Make sure media termination point required is checked and retry video call as audio is checked.

Check Asserted-Identity and Redirecting Diversion Header Delivery - Inbound.

Select the setting below.

Put the name or IP address of the Cisco CUBE router inside IP address  or hostname in the destination address and destination port. Select a SIP Security Profile (I am not going to show you how to configure the security profile, that should be common knowledge). Also select a SIP profile.

Select save to save the trunk configuration.

The next step is to route calls over to the Cisco Router. Since we are using *8, that will be the route pattern that will be sent to the Cisco Cube router. We decided to route the entire ten digit number to Microsoft Teams. This allowed for 4 digit calls from Teams to be routed back to Call Manager. Since we are using Teams as softphone and not everyone will want to use it as a softphone, I wanted to make sure 4 digit calls route back to Microsoft Teams.

The route pattern will be setup to look like what is in screen shot below. You might have to setup a route pattern per partition if you have your route partitions based on site or geographical location. Select the name of your Cisco Cube Router you created and select save.

Cisco Call Manager is now configured to route *8 calls to the Cisco Cube router, which in turn will route the call to Microsoft Teams. This is the easy part. The difficult part is the Cisco Cube Configuration.

Microsoft Teams SBC Configuration

You will need to connect to powershell as a Teams Administrator and run the following command to create the Cisco Cube router in Microsoft Teams. (This Microsoft article is a good guide on how to configure the router and dialing plans).  You will also need to configure route patterns, I am not going to show you how to do that. The Microsoft article is a good guide and you can find other resources on the Internet that will explain how this works much better than I can.

I set ForwardPai to false and MediaBypass too false. Media Bypass is special configuration that is not necessary unless you are concerned about latency. ForwardPai has to do with Caller-id and privacy. Unless you want your outgoing calls to be anonymous, you do not need to set this setting.

New-CsOnlinePSTNGateway -Fqdn sbc.example.com -SipSignallingPort 5061 -ForwardCallHistory $False -ForwardPai $false -MaxConcurrentSessions 100 -Enabled $true

The following command will allow you to verify the router has been created.

get-CsOnlinePSTNGateway sbc.example.com

Once you create the object, it can take up to 4 hours for the object to be created and replicated in Microsoft Teams.

You will need to configure a Online PSTN usage object in order to route calls to the Cisco Cube router,

Set-CsOnlinePstnUsage -identity Global -Usage @{Add="Unrestricted"}

You will also need to create a voice route and voice routing policy, I have an example listed below, but you will need to customize these policies to fit your environment.

New-CsOnlineVoiceRoute -Identity "USA" -NumberPattern "\+1.*" OnlinePstnGatewayList "sbc.example.com" -Priority 1 -OnlinePstnUsages "Unrestricted"

New-CsOnlineVoiceRoutingPolicy "VRPolicy" -OnlinePstnUsages "Unrestricted"

You should have the policies that you need to assign to users and also to route Calls to the Cisco Cube Router.

Cisco Cube Router Configuration to Communicate with Microsoft Teams and route calls

You will also need to configure the Cisco Cube Router to Communicate with Microsoft Team's. The Cisco Guide in the first blog post in the series discusses how to complete those steps, but I will provide an example here. I also did not include how to configure certs required by Microsoft Teams on the Cisco Cube Router, that can be found in this guide. Make sure you have the SSL/TLS certs added correctly or routing and peering will fail.

Listed below are the commands and dial peers we used to route calls to/from Call Manager to/from Microsoft Teams. This is a bit different than the configuration example provided by Cisco. We are routing Calls to Call Manager and letting Call Manager route the calls to the PSTN. This took the voice and network engineer about two weeks to perfect. I thought I would share this as I have not seen a guide on how to make this work and I have taken so much from others over the years, it is time to give back. (My team did a great job in configuring this, I would rate them good or better then some of the consultants I worked with over the years. I am blessed with a great team)

Caution, this is specific for my company's needs, take that into account when reviewing this configuration. Make sure you adjust it to your needs.

Allow the Headers to Pass the SBC Router

voice class sip-hdr-passthrulist 290
passthru-hdr Refer-To
passthru-hdr Referred-By

Global Configuration Need for Teams

voice service voip
ip address trusted list
ipv4 52.114.0.0 255.255.0.0
ipv4 x.x.x.x 255.255.0.0 (Allows internal networks to communication using SIP with the Router.
rtcp keepalive
address-hiding
mode border-element
allow-connections sip to sip
no supplementary-service sip refer
supplementary-service media-renegotiate
fax protocol t38 version 0 ls-redundancy 0 hs-redundancy 0 fallback none
trace
sip
session refresh
header-passing
pass-thru headers 290

error-passthru


conn-reuse
!

Sets the hostname for the Cisco Cube Router

voice class uri 290 sip
host sbc.example.com

Dial Peers need to accept inbound calls from Microsoft Teams

dial-peer voice 100 voip
description inbound from Microsoft Teams
rtp payload-type comfort-noise 13
session protocol sipv2
session transport tcp tls
incoming called-number .T
incoming uri to 290
voice-class codec 1
voice-class sip localhost dns:sbc.example.com
voice-class sip early-offer forced
voice-class sip profiles 200
voice-class sip profiles 290 inbound
voice-class sip srtp-crypto 1
voice-class sip block 183 sdp present
voice-class sip pass-thru headers 290
no voice-class sip pass-thru content custom-sdp
voice-class sip bind control source-interface GigabitEthernetx/x/x
voice-class sip bind media source-interface GigabitEthernetx/x/x
no voice-class sip referto-passing
dtmf-relay rtp-nte
srtp
no vad

dial-peer voice 110 voip
description inbound 4 Digit from Microsoft Teams
rtp payload-type comfort-noise 13
session protocol sipv2
session transport tcp tls
incoming called-number [1-8]...$
incoming uri to 290
voice-class codec 1
voice-class sip localhost dns:sbc.example.com
voice-class sip early-offer forced
voice-class sip profiles 200
voice-class sip profiles 290 inbound
voice-class sip srtp-crypto 1
voice-class sip block 183 sdp present
voice-class sip pass-thru headers 290
no voice-class sip pass-thru content custom-sdp
voice-class sip bind control source-interface GigabitEthernetx/x/x
voice-class sip bind media source-interface GigabitEthernetx/x/x
no voice-class sip referto-passing
dtmf-relay rtp-nte
srtp
no vad

Voice Profiles need to route calls correctly to/from Teams

(The Cisco Guide located here, explains what the voice profiles are used for.  You also need to make sure you have the correct cube router in the voice profiles. I added what we uses as they needed some modification as we are routing to Cisco Call Manager and not the PSTN.

voice class sip-profiles 100
rule 10 request ANY sdp-header Audio-Attribute modify "a=candidate." "a=label:main-audio"
rule 20 response ANY sdp-header Audio-Attribute modify "a=candidate." "a=label:main-audio"
rule 30 request ANY sdp-header Audio-Attribute modify "a=sendonly" "a=inactive"
!
voice class sip-profiles 290
rule 10 request REFER sip-header From copy "@(.com)" u05
rule 40 response ANY sip-header Server modify "(IOS.)" "\1\x0D\x0AX-MS-SBC: Cisco UBE/ISR4431/\1"
!
voice class sip-profiles 280
rule 10 request ANY sip-header User-Agent modify "(IOS.)" "\1\x0D\x0AX-MS-SBC: Cisco UBE/ISR4431/\1"
rule 20 response ANY sip-header Server modify "(IOS.)" "\1\x0D\x0AX-MS-SBC: Cisco UBE/ISR4431/\1"
rule 30 request INVITE sip-header SIP-Req-URI copy "@(.:5061)" u01
rule 40 request INVITE sip-header From copy "@(.)>" u02
rule 50 request INVITE sip-header Refer-To copy "sip:sip.tls(;.)>" u03
rule 60 request INVITE sip-header Refer-To remove
rule 130 request ANY sip-header Contact modify "@.*:" "@\u02:"

rule 140 response ANY sip-header Contact modify "@.:" "@\u02:"
rule 150 request ANY sdp-header Audio-Attribute modify "a=sendonly" "a=inactive"
rule 160 response 200 sdp-header Session-Owner copy "IN IP4 (.)" u04
rule 170 response 200 sdp-header Audio-Connection-Info modify "0.0.0.0" "\u04"
!
voice class sip-profiles 299
rule 10 request OPTIONS sip-header From modify "<sip:.:5061" "<sip:mkenirsbc01.quarles.com"
rule 20 request OPTIONS sip-header Contact modify "<sip:.:5061" "<sip:mkenirsbc01.quarles.com"
rule 30 request OPTIONS sip-header User-Agent modify "(IOS.)" "\1\x0D\x0AX-MS-SBC: Cisco UBE/ISR4431/\1"
!
voice class sip-profiles 200
rule 10 request ANY sip-header Contact modify "@.:" "@sbc.example.com:"
rule 20 response ANY sip-header Contact modify "@.:" "@sbc.example.com:"
rule 30 request ANY sip-header SIP-Req-URI modify "sip:(.):5061 (.)" "sip:\1:5061;user=phone \2"
rule 40 request ANY sip-header User-Agent modify "(IOS.)" "\1\x0D\x0AX-MS-SBC: Cisco UBE/ISR4431/\1"
rule 50 response ANY sip-header Server modify "(IOS.)" "\1\x0D\x0AX-MS-SBC: Cisco UBE/ISR4431/\1"
rule 60 request ANY sdp-header Audio-Attribute modify "a=sendonly" "a=inactive"
rule 70 response 200 sdp-header Audio-Connection-Info modify "0.0.0.0" "38.71.69.114"
rule 80 request ANY sdp-header Audio-Attribute modify "(a=crypto:.inline:[A-Za-z0-9+/=]+)" "\1|2^31"
rule 90 response ANY sdp-header Audio-Attribute modify "(a=crypto:.inline:[A-Za-z0-9+/=]+)" "\1|2^31"
!

Drop Referred-By

During our testing, we discovered that 4 digit call transfers failed. After some great debugging by the voice and network engineer, they discovered that the "Referred-By" header going to Microsoft Teams was Invalid, once it was removed, the call routed correctly. It was adding an extra Referred-By host with a , which is an invalid character in a SIP header.  Since we are routing all 4 digit calls back to Cisco Call Manager, I am sure that using mobility for calling routing was part of the reason this was failing.

Consult and transfer also does not function. This feature is rarely used by our end users, so we decided it was not important to make this function. I believe the busy on busy setting in teams is why this is not working.


voice class sip-profiles 281
rule 10 request ANY sip-header User-Agent modify "(IOS.)" "\1\x0D\x0AX-MS-SBC: Cisco UBE/ISR4431/\1"
rule 20 response ANY sip-header Server modify "(IOS.)" "\1\x0D\x0AX-MS-SBC: Cisco UBE/ISR4431/\1"
rule 30 request INVITE sip-header SIP-Req-URI copy "@(.:5061)" u01
rule 40 request INVITE sip-header From copy "@(.)>" u02
rule 50 request INVITE sip-header Refer-To copy "sip:sip.tls(;.)>" u03
rule 60 request INVITE sip-header Refer-To remove
rule 70 request INVITE sip-header Referred-By remove
rule 130 request ANY sip-header Contact modify "@.:" "@\u02:"
rule 140 response ANY sip-header Contact modify "@.:" "@\u02:"
rule 150 request ANY sdp-header Audio-Attribute modify "a=sendonly" "a=inactive"
rule 160 response 200 sdp-header Session-Owner copy "IN IP4 (.)" u04
rule 170 response 200 sdp-header Audio-Connection-Info modify "0.0.0.0" "\u04"

Translation Patterns need to normalize calls

These are needed to drop the *8, add or drop the + sign, which teams uses to route calls and to add the 9 or 91 to outgoing calls to Cisco Call Manager. These are needed before you create the dial peers.

voice translation-rule 100
rule 1 /^([2-9].........)/ /+1\1/
!
voice translation-rule 150
rule 1 /^([2-9].........)/ /9\1/
!
voice translation-rule 160
rule 1 /^([2-9].........)/ /91\1/
!
voice translation-rule 200
rule 1 /^+1(.)/ /\1/
!
voice translation-rule 210
rule 1 /^+(.)/ /9\1/
!
voice translation-rule 220
rule 1 /^(.)/ /9\1/
!
voice translation-rule 240
rule 1 /^*8(.)/ /+\1/
--More--          rule 2 /^44(.*)/ /+\1/
!
!
voice translation-profile ADD_9
translate calling 200
translate called 220
!
voice translation-profile ADD_91
translate called 160
!
voice translation-profile ADD_PLUS1
translate calling 100
translate called 100
!
voice translation-profile DROP_*8_ADD_PLUS
translate called 240
!
voice translation-profile DROP_PLUS1
translate calling 200
translate called 200
!
voice translation-profile DROP_PLUS1_CALLING
translate calling 200
!
voice translation-profile DROP_PLUS_ADD_9
translate calling 200
translate called 210

Dial Peer need to route Calls to CUCM

We are adding the 9 as we are route to Call Manager than outbound. You will need to add a dial peers for each Call Manager in your environment.

dial-peer voice 200 voip
description outbound to CUCM
translation-profile outgoing ADD_9
destination-pattern .T
session protocol sipv2
-session target ipv4:x.x.x.x:5060
session transport udp
voice-class codec 1
voice-class sip asserted-id pai
voice-class sip privacy-policy passthru
voice-class sip options-ping 60
voice-class sip bind control source-interface GigabitEthernetx/x/x
voice-class sip bind media source-interface GigabitEthernetx/x/x
dtmf-relay rtp-nte
no vad

Route 4 Digit Calls from Teams to Call Manager and Drop the plus sign and a 1 if it exists

dial-peer voice 230 voip
description Outbound 4 Digit to CUCM
translation-profile outgoing DROP_PLUS1_CALLING
destination-pattern [1-8]...$
session protocol sipv2
session target ipv4:x.x.x.x:5060
session transport udp
voice-class codec 1
voice-class sip asserted-id pai
voice-class sip privacy-policy passthru
voice-class sip options-ping 60
voice-class sip bind control source-interface GigabitEthernetx/x/x
voice-class sip bind media source-interface GigabitEthernetx/x/x
dtmf-relay rtp-nte
no vad

Accept *8 Calls on the Cisco Cube from Call Manager

dial-peer voice 300 voip
description *8 Inbound from CUCM
session protocol sipv2
session transport udp
incoming called-number *81[2-9]..[2-9]......
voice-class codec 1
voice-class sip bind control source-interface GigabitEthernetx/x/x
voice-class sip bind media source-interface GigabitEthernetx/x/x
dtmf-relay rtp-nte
no vad

Route Mobility Calls to Microsoft Teams From Call Manager


dial-peer voice 400 voip
description Outbound to Teams 1
translation-profile outgoing DROP_*8_ADD_PLUS
preference 1
destination-pattern *81[2-9]..[2-9]......
rtp payload-type comfort-noise 13
session protocol sipv2
session target dns:sip.pstnhub.microsoft.com
session transport tcp tls
voice-class codec 1
voice-class sip localhost dns:sbc.example.com
voice-class sip early-offer forced
voice-class sip profiles 280
voice-class sip srtp-crypto 1
voice-class sip block 183 sdp present
voice-class sip options-keepalive profile 200
voice-class sip pass-thru headers 290
no voice-class sip pass-thru content custom-sdp
voice-class sip bind control source-interface GigabitEthernetx/x/x
voice-class sip bind media source-interface GigabitEthernetx/x/x
no voice-class sip referto-passing
voice-class sip requri-passing
dtmf-relay rtp-nte
srtp
fax protocol none
no vad

Adding additional users to a phone call the Microsoft conference bridge

During our testing, we discovered that if you added a second user to a phone call, it converted it to a conference call and used the conference bridge to add the second user. To get this to function correctly, we had the conference bridge utilize the direct route using the Cisco Cube instead of Microsofts Network. You need to create a new policy and assign that policy to the users.  Microsoft calls this On-Network Conferencing, details about how this functions can be found here.

The command below creates the policy.

New-CsOnlineAudioConferencingRoutingPolicy"Policy 1" -OnlinePstnUsages"Name of your PSTN usage policy"

Enabling Users in Microsoft Teams for Voice Dialing

You will need to run the following commands to enable outbound calling using the Cisco Cube router and also to assign a phone number to your users

Set-CsUser -Identity "spencer.low@contoso.com" -OnPremLineURI tel:+14255388797 -EnterpriseVoiceEnabled $true -HostedVoiceMail $false

Grant-CsOnlineAudioConferencingRoutingPolicy -Identity "spencer.low@contoso.com" -PolicyName "Your  Conferencing Direct Route Policy Name”

Grant-CsOnlineVoiceRoutingPolicy -Identity "spencer.low@contoso.com" -PolicyName "Your Voice Routing Policy Name"

Grant-CsTenantDialPlan -Identity "spencer.low@contoso.com"-PolicyName "Your Dialing Plan Name."

I have seen it take up to four hours before the phone dialer will show up for users. Teams is not the most quick.

Cisco Mobility Setup

If your users want incoming calls routed to teams, you need to enable Cisco Mobility using *8 and adjust timers.

Add an additional Phone, the URI should be *8 and then the users phone number in Teams.

I also modify the Mobility timers to make call routing quicker. Set the wait timer to 0.0 to route calls to Teams right away. You might have to adjust the stop ringing this phone timer. I found 12.0 seconds more than enough time to pickup a call.

The additional Cisco Call Manager setting I adjusted is located under the End User configuration for each user. If you have enable mobile voice access enabled, the default timer is 10 seconds. I suggest adjusting this timer to 5 seconds. If you don't and you leave voicemails, it will have about 5 seconds of dead air. Adjusting this setting seems to address that issue.

This setting is used if you want to move your call back from your mobile phone back to your desk phone. You more than likely could also uncheck it if it is not used in your environment.

Final Thought's

This configuration took a good month too perfect, so I hope this saves others some time. It would be nice if Cisco offered an official guide on how to route to/from Call Manager. The have a great guide on how to route to/from the PSTN. (I am not sure why they don't create this guide, my best guess is they don't want to make it easy to migrate to Microsoft Teams)

This configuration will also work if you want to migrate users to Microsoft Teams from Cisco Call Manager. You would just need to create the route patterns on Cisco Call Manager and the cube router for the users you migrate to Microsoft Teams.

Since Microsoft only support cloud voicemail, I choose to go the mobility route when integrating the two phone systems. Voicemails are left onsite and not in the cloud. But you might not care about that.

We did attempt to get media bypass to work, but it was a galactic failure and at the end of the day we have a fast low latency pipe to Microsoft and media bypass was not going to gain the efficiencies need to get this feature functioning.

I hope you found this article useful, if you have any questions, feel free to contact me.

TBJ Consulting

TBJ Consulting