Membatasi panggilan pengguna MSTeams Direct Routing ke kode area tertentu

Latar belakang

Ada permintaan dari sebuah perusahaan yang sudah menggunakan MSTeams Direct Routing untuk membatasi panggilan pengguna MSTeams Phone System di kantor cabang Lampung supaya hanya bisa melakukan panggilan ke seluruh kode area Lampung saja (yang menurut wikipedia, ada 9 kode area: 0721 s/d 0729), dan tidak memperbolehkan panggilan ke nomer selular.

Cara konfigurasi

Sebenarnya ada banyak cara yang dapat dilakukan. Jika ngobrol sama rekan-rekan kerja, ada yang suka menggunakan dialplan, ada juga yang lebih nyaman melakukan di level VoiceRoute. Tapi kali ini saya akan menggunakan PSTNUsages. Jadi cara apa pun ndak masalah yang penting tujuan utama tercapai, yaitu membatasi panggilan hanya ke seluruh kode area wilayah Lampung.

Langkah awal adalah membuat kompartemen PSTNUsage untuk menampung semua OnlineVoiceRoute untuk wilayah Lampung (semua perintah dijalankan via powershell:

PS> Set-CsOnlinePstnUsage -Identity Global -Usage @{Add="Lokal_Lampung"}

Setelah kompartemen dibuat, berikutnya adalah menentukan number pattern melalui OnlineVoiceRoute:

PS> CsOnlineVoiceRoute -Identity "Lokal_Lampung072X" -NumberPattern "^072[1-9](\d{5,})$" -OnlinePstnGatewayList sbc.directrouting.tld -OnlinePstnUsages Lokal_Lampung

PS> CsOnlineVoiceRoute -Identity "Lokal_Lampung+62" -NumberPattern "^\+6272[1-9](\d{5,})$" -OnlinePstnGatewayList sbc.directrouting.tld -OnlinePstnUsages Lokal_Lampung

Saya membuat dua pattern yang satu berawalan 0 dan satunya berawalan +62. Biasanya, pengguna yang melakukan panggilan dengan menekan numpad ke kode area, akan menggunakan awalan 0, sedangkan untuk panggilan dari phonebook, call history, dst, kadang ada awalan +62.

Setelah kedua VoiceRoute di atas tersimpan dalam satu PSTNUsage Lokal_Lampung, berikutnya kita buat VoiceRoutingPolicy seperti berikut:

PS> New-CsOnlineVoiceRoutingPolicy -Identity "Lokal_Lampung" -OnlinePstnUsages Lokal_Lampung

Jika kita memiliki lebih dari satu PSTNUsage bisa ditambahkan juga di baris atas dengan pemisah koma. Misal saya sudah pernah membuat PSTNUsage untuk panggilan emergency, dan saya beri nama Emergency, maka bisa ditambahkan sebagai berikut:

PS> New-CsOnlineVoiceRoutingPolicy -Identity "Lokal_Lampung" -OnlinePstnUsages Lokal_Lampung, Emergency

Jika tidak ada error yang muncul, maka sematkan policy dengan nama (kebetulan sama) “Lokal_Lampung” di atas ke pengguna, misal seperti berikut:

PS> Grant-CsOnlineVoiceRoutingPolicy -Identity "user@directrouting.tld" -PolicyName Lokal_Lampung

Selamat mencoba.

Pranala luar

  • https://docs.microsoft.com/en-us/powershell/module/skype/new-csonlinevoiceroutingpolicy
  • https://docs.microsoft.com/en-us/powershell/module/skype/set-csonlinepstnusage

Microsoft Teams Chat Bubbles

Jika mengikuti Roadmap Microsoft, baru-baru ini ada pengumuman di Roadmap ID 65948 yang bakal dirollout per akhir Juli 2021 ini, yaitu fitur chat bubbles ketika sedang konferensi video. Selama ini jika kita konferensi video di MSTeams, lalu ingin menambahkan informasi di dalam diskusi (misal tautan/pranala, atau mengkoreksi informasi yang disampaikan pembicara, dan lain sebagainya), peserta harus repot-repot membuka jendela chat terlebih dahulu untuk mengetik maupun membaca percakapan. Rencananya dengan chat bubbles ini, apa yang kita ketik di chat ketika orang lain sedang bicara akan muncul sebagai bubbles di jendela video wajah kita dari perspektif orang lain, yang kira-kira bakal seperti ini:

Chat bubbles

Jangan sampai dibuat ngomentarin orang lain yang ada di dalam pertemuan tersebut ya? Baik-baik jaga chat nya atau bakal malu keceplosan dilihat orang banyak. Lebih sial lagi jika ada yang sempat membuat tangkapan layar.

Fitur ini katanya bisa diaktifkan dengan menu elpisis di kanan atas, lalu ada pilihan Don’t show chat bubbles

Chat bubbles

ya kira-kira tujuannya untuk menghindarkan kejadian memalukan seperti yang dibahas di atas, jadi sebaiknya fitur tersebut dimatikan sama sekali.

Saya belum tau pasti seberapa membantunya fitur ini di pertemuan-pertemuan selanjutnya. Bisa jadi cukup membantu, atau bahkan bisa jadi menyebalkan, apalagi kalo berhadapan dengan netijen +62 wkwkwkwkwkw….

Calling Policy Busy on Busy (Busy Options)

Saat kita tengah melakukan panggilan MSTeams atau sedang di tengah pertemuan daring dengan MSTeams, kadang masih bisa menerima panggilan masuk. Dan ternyata di beberapa negara/budaya, hal ini termasuk tidak sopan. Jika kebetulan sedang bekerja sama dengan orang lain yang memiliki kebudayaan tersebut, alangkah baiknya kita mengatur panggilan masuk ditengah sedang menerima panggilan atau sedang tengah konferensi daring.

Busy on Busy ini dapat diaktifkan melalui web GUI portal MSTeams, dan juga bisa dilakukan melalui perintah powershell Set-CSTeamsCallingPolicy dengan opsi:

  • Enabled – yang akan langsung menolak panggilan jika ada panggillan kedua masuk ditengah kita sedang menerima panggilan lain atau sedang dalam pertemuan daring.
  • Unanswered – yang dikombinasikan dengan pengaturan berikutnya dengan mengalikan panggilan ke voicemail, atau ke pengguna lain sebagai perwakilan kita,
  • Disabled – ini adalah setting default.

Untuk setting dari TAC (Teams Admin Console), dapat melalui menu Voice -> Calling policies -> Global (Org-wide default).

Tautan:

Routing Dua SBC untuk Microsoft Teams Direct Routing

Jadi ada kebutuhan untuk menyambungkan Microsoft Teams ke Cloud PBX kantor, tapi sekaligus masih bisa menjalankan Demo untuk IVR yang full menggunakan “PBX” Microsoft Teams.

Saat ini ada dua SBC yang sudah terdaftar di OnlinePstnGateway kantor, yang satu untuk integrasi ke Cloud PBX, dan yang satu bener-benef full MSTeams Direct Routing yaitu sbc01.ofon.co.id dan sbc02.ofon.co.id, yang bisa dilihat dengan perintah Get-CsOnlinePstnGateway. Semua panggilan ke ekstensi (format nomer ekstensi 4 digit) CloudPBX akan dilewatkan sbc02.ofon.co.id, dan panggilan ke offnet (landline dan mobile) akan dilewatkan melalui kedua sbc tersebut.

Langkah-langkahnya seperti berikut:

  • Buat container baru dengan nama DualSBC untuk mengelompokkan rute panggilan di atas yang nantinya dijadikan satu ke OnlineVoiceRoutingPolicy baru.
Set-CsOnlinePstnUsage -Identity Global -Usage @{Add="DualSBC"}
  • Lalu buat rule baru dengan nama, misal, SBC2CloudPBX panggilan ke ekstensi (4 digit) untuk diarahkan ke sbc02.ofon.co.id (perhatikan format regexnya):
New-CsOnlineVoiceRoute -Identity "SBC2CloudPBX" -NumberPattern "^\d{4}$" -OnlinePstnGatewayList sbc02.ofon.co.id -Priority 0 -OnlinePstnUsages DualSBC
  • Dan untuk panggilan ke offnet kita buatkan rule baru dengan nama, misal, SBC2PSTN melaui sbc01.ofon.co.id dan sbc02.ofon.co.id:
New-CsOnlineVoiceRoute -Identity "SBC2PSTN" -NumberPattern ".*" -OnlinePstnGatewayList sbc01.ofon.co.id, sbc02.ofon.co.id -Priority 10 -OnlinePstnUsages "DualSBC"
  • Setelah itu kumpulkan kedua OnlineVoiceRoute di atas menjadi satu OnlineVoiceRoutingPolicy:
New-CsOnlineVoiceRoutingPolicy -Identity "DualSBC" -OnlinePstnUsages "DualSBC"
  • Dan terakhir, sematkan policy baru tersebut ke pengguna MSTeams Phone System:
Grant-CsOnlineVoiceRoutingPolicy -Identity user@domain.tld -PolicyName DualSBC
  • Test panggilan.

Pranala Luar:

  • https://docs.microsoft.com/en-us/powershell/module/skype/set-csonlinepstnusage?view=skype-ps
  • https://docs.microsoft.com/en-us/powershell/module/skype/new-csonlinevoiceroute?view=skype-ps
  • https://docs.microsoft.com/en-us/powershell/module/skype/new-csonlinevoiceroutingpolicy?view=skype-ps
  • https://blogs.perficient.com/2018/06/28/direct-routing-for-microsoft-teams-deep-dive-part-4/

[tips] Problem Perintah Connect-MicrosoftTeams Tidak Dikenali

Sering beberapa kali pada saat pindah laptop/PC untuk mengakses Microsoft Teams cmdlet mengalami kendala perintah tidak dikenali seperti berikut ini:

PS C:\windows\system32> Install-Module MicrosoftTEams
PS C:\windows\system32> Connect-MicrosoftTeams
Connect-MicrosoftTeams : The term 'Connect-MicrosoftTeams' is not recognized as the name of a cmdlet, function, script
file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct
and try again.
At line:1 char:1
+ Connect-MicrosoftTeams
+ ~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (Connect-MicrosoftTeams:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

Kalau dibaca-baca di beberapa mailing-list, ini karena environment PowerShell untuk keamanan terhadap script yang tidak dikenal dan berbahaya. Tapi ya belum paham-paham banget detailnya bagaimana. Cuma dapat saran untuk menjalankan perintah berikut ini:

PS C:\windows\system32> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned

Lalu pilih All jika muncul pertanyaan berikut:

Execution Policy Change
The execution policy helps protect you from scripts that you do not trust. Changing the execution policy might expose
you to the security risks described in the about_Execution_Policies help topic at
https:/go.microsoft.com/fwlink/?LinkID=135170. Do you want to change the execution policy?
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "N"): a

Setelah itu kita dapat menjalakan MSTeams CmdLet. Dari petunjuk tersebut juga diarahkan untuk membaca doc di https:/go.microsoft.com/fwlink/?LinkID=135170.

Bagaimana kalo di Ubuntu?

Jika menjalankan cmdlet Microsoft Teams dari powershell Ubuntu, tidak memerlukan setting policy seperti di atas. Setelah menginstall module, langsung bisa menjalankan Connect-MicrosoftTeams.

Tautan

Akses Microsoft Teams dari Powershell Ubuntu

Akhirnya module MicrosoftTeams yang untuk menggantikan SkypeOnlineConnector dapat juga digunakan di Linux, terutama distro Ubuntu. Setupnya cukup mudah seperti yang ada di postingan https://www.otakudang.org/?p=1097. Berikut tangkapan layar ketika menjalankan perintah Install-Module MicrosoftTeams:

Dan untuk login ke Microsoft Teams admin console dengan perintah Connect-MicrosoftTeams (akan muncul login tab di browser yang menanyakan informasi login admin):

Muncul beberapa warning tapi bisa diabaikan. Berikutnya test perintah , misal, untuk Direct Routing:

PS /home/godril> Get-CsOnlinePSTNGateway | Select-Object -Property Identity

Identity
--------
sbc01.ofon.biz
sbc02.ofon.biz
sbc03.ofon.biz

Siplah! Jadi ndak harus buka laptop Windows lagi jika sedang di station Ubuntu.

Module MicrosoftTeams sebagai pengganti SkypeOnlineConnector

Mungkin sehubungan dengan akan pensiunnya Skype for Business Online, module administrasi powershell untuk MSTeams juga akan diganti. Jika pernah membaca postingan persiapan setup Direct Routing di postingan Microsoft Teams Phone System (Tulisan 2) – otakudang.org (v2.0) , masih menggunkana modul SkypeOnlineConnector. Yang baru menurut postingan di Download and install the Skype for Business Online Connector module – Skype for Business Online | Microsoft Docs.

Cara installnya begini:

PS C:\WINDOWS\system32> Install-module microsoftteams                                                                                                                                                                                           NuGet provider is required to continue
PowerShellGet requires NuGet provider version '2.8.5.201' or newer to interact with NuGet-based repositories. The NuGet
 provider must be available in 'C:\Program Files\PackageManagement\ProviderAssemblies' or
'C:\Users\tunju\AppData\Local\PackageManagement\ProviderAssemblies'. You can also install the NuGet provider by running
 'Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force'. Do you want PowerShellGet to install and
import the NuGet provider now?
[Y] Yes  [N] No  [S] Suspend  [?] Help (default is "Y"): yes

Untrusted repository
You are installing the modules from an untrusted repository. If you trust this repository, change its
InstallationPolicy value by running the Set-PSRepository cmdlet. Are you sure you want to install the modules from
'PSGallery'?
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "N"): yes

Tautan:

Microsoft Teams Call Transfer

Karena pada dasarnya Microsoft Teams ini semacam PBX bermerk Microsoft, salah satu fiturnya tentu ada yang namanya call transfer, walaupun istilahnya agak berbeda sedikit dengan PBX pada umumnya. Di Microsoft Teams (selanjutnya saya sebut sebagai MSTeams saja biar ndak ribet ngetiknya), menyebutnya sebagai Transfer now untuk blind (call) transfer, dan Consult then transfer untuk attended (call) transfer. Kurang ribet gimana coba?

Transfer now

Blind (call) transfer adalah meneruskan panggilan ke nomor telepon atau ekstensi tujuan tanpa menanyakan terlebih dahulu apakah orang yang tertuju bersedia mengangkat telepon atau tidak. Jadi jika orang tertuju tidak ada di tempat, maka panggilan akan berdering terus sampai dengan ring timeout atau penelpon memutuskan untuk menutup telepon. Blind transfer biasanya terjadi jika:

  • panggilan terjadi di dalam satu organisasi saja, dan biasanya dengan peer.
  • Anda tipe BOFH.

Transfer now di Desktop app

Untuk melakukan Tranfer now di Desktop app cukup mudah. Ketika menerima panggilan masuk dan hendak mentransfer panggilan tersebut, klik ikon elipsis () di kiri atas, lalu pilih Transfer.

Lalu di bagian isian Invite someone or dial a number, isikan nama kontak yang hendak dituju. Jika nama kontak berada di tenant yang sama, menuliskan beberapa huruf depan saja akan memunculkan kemungkinan nama yang hendak dituju:

Jika nama sudah muncul dari kemungkinan yang ditampilkan, klik kontak tersebut. Jika belum, teruskan mengetik nama kontak. Jika sudah klik nama tersebut.

Selain dapat melakukan transfer, panggilan masuk juga dapat ditransfer ke voicemail nomer tertuju apabila orang yang tertuju sedang tidak di tempat (sedang cuti, atau tugas ke luar kota), sehingga pemanggil dapat meninggalkan pesan penting yang dapat didengarkan kembali oleh orang yang dituju melalui MSTeams atau surel.

Jika kita mengaktifkan Ring back if there’s no answer, maka panggilan tersebut akan kembali ke kita jika transfer tidak dijawab oleh orang tertuju dengan pesan seperti berikut:

Jika mengaktifkan Ring back if there’s no answer, maka kita tidak dapat transfer panggilan ke voicemail nomer tertuju.

Selain dapat melakukan transfer panggilan ke akun MSTeams di tenant yang sama, kita juga dapat melakukan transfer panggilan ke akun MSTeams tenant yang berbeda (beda organisasi), dengan catatan, MSTeams sudah dilakukan federation, yaitu memperbolehkan satu domain tenant berbicara dengan domain tenant lain di luar organisasi tersebut. Ijin akses ini harus dua arah. Misal, jika tenant MSTeams ofon.co.id memperbolehkan semua penggunanya menghubungi langsung ke pengguna di domain tenant microsoft.com, maka sebaliknya di MSTeams tenant microsoft.com juga harus memperbolehkan komunikasi dari MSTeams ofon.co.id.

Transfer panggilan lain yang diperbolehkan adalah ke nomer PSTN eksternal atau ke nomor mobile jika trunk operator memperbolehkan.

Apa maksudnya “jika trunk operator memperbolehkan?”

Salah satu implementasi yang pernah saya lakukan adalah menghubungkan MSTeams dengan nomer PSTN onpremise yang turun ke lokasi kantor pelanggan berupa satu line analog. Satu line analog ini berarti 1 conccurent call baik masuk ataupun keluar tapi tidak dua-duanya.

Jadi jika ada panggilan masuk ke nomer tersebut, maka line analog sudah terpakai, sehingga tidak memungkinkan melakukan transfer panggilan ke nomer PSTN atau nomor mobile di luar organisasi tersebut.

Untuk melakukan transfer panggilan ke nomor telepon lain di luar organisasi, cukup masukkan nomer telepon lengkap seperti berikut:

lalu klik Transfer.

Transfer now di mobile app

Ketika panggilan masuk ke mobile app, untuk melakukan transfer panggilan, pilih menu elpisis () di layar bagian bawah, lalu pilih Transfer.

Di bagian “Search for people” isikan nama kontak tertuju. Jika kontak tersebut ada di dalam MSTeams tenant, maka akan muncul secara otomatis:

Ketuk di daftar nama tersebut untuk mentrasnfer panggilan.

Atau, kita bisa memasukkan nomor telepon eksternal seperti berikut:

ketuk nomor telepon eksternal untuk mentransfer panggilan ke nomor tersebut. Jika tranfer berasil akan muncul status seperti berikut:

Consult then transfer

Attended (call) transfer adalah transfer panggilan yang agak sopan karena penerima telepon akan menanyakan terlebih dahulu ke orang tujuan apakah bersedia atau available untuk menerima panggilan atau tidak. Di MSTeams, kita dapat menanyakan dengan dua cara ketika melalui desktop app, yaitu dengan melakukan panggilan terlebih dahulu, atau mengirimkan pesan chat. Sedangkan untuk mobile app per tanggal tulisan ini, hanya dapat melakukan attended transfer dengan bertanya melalui chat saja, karena tidak ada menu panggilan suara. Mungkin nanti-nanti akan ada rilis untuk kemampuan tersebut.

Consult then transfer di Desktop App

Di dalam dekstop app kita dapat menanyakan telepon tertuju untuk transfer panggilan melalui panggilan suara atau pesan chat. Di menu elipsis () kanan atas, pilih Consult then transfer.

ketika memilih kontak tertuju, kita akan diberikan dua pilihan untuk memberitahukan melalui panggilan telepon atau via chat seperti berikut:

Di contoh ini kita pilihh Teams audio call. Jika nomer tertuju bersedia menerima panggilan telepon, maka untuk mentransfer panggilan cukup tekan Transfer :

Jika nomer tertuju tidak bersedia menerima telepon atau sedang tidak berada di tempat, maka pilih Leave, lalu di halaman penerimaan panggilan tekan Resume untuk kembali berbicara ke nomer pemanggil yang sebelumnya masuk hold.

Sedangkan pemberitahuan melalui Chat akan mengirimkan pesan otomatis seperti berikut:

jika nomer tertuju bersedia menerima panggilan, maka cukup tekan tombol Transfer di atas. Apabila tidak, kembali ke layar utama panggilan dan tekan Resume untuk berbicara kembali ke nomor pemanggil.

This image has an empty alt attribute; its file name is image-20.png

Consult then transfer dengan Mobile app

Untuk mobile app, pilih elipsis lalu pilih menu Transfer -> Consult first.

Karena pilihannya hanya pemberitahuan via Chat, maka otomatis akan digenerate pesan seperti berikut:

Perhatikan dua icon di kanan atas:

Icon handle telepon di sebelah kanan untuk melakukan transfer jika tertuju bersedia menerima telepon, dan gambar icon panah untuk melakukan Resume panggilan jika tidak tersambung dan kembali berbicara ke nomor pemanggil.

Complete Issabel Configs for MSTeams Direct Routing

Related to previous post about how to setup Issabel as Direct Routing SBC to MSTeams,I got requests from acquintances about the complete configurations from Issabel side.

So here they are:

sip_custom.conf (modify this from Asterisk File Editor webGUI)

[MSTeams-Inbound]
disallow=all
host=sip.pstnhub.microsoft.com
type=friend
transport=tls
port=5061
allow=all
allow=ulaw
qualify=yes
dtmfmode=rfc2833
context=from-internal
insecure=port,invite
nat=force_rport,comedia
fromdomain=ast.ofon.biz

[MSTeams02-Inbound]
disallow=all
host=sip2.pstnhub.microsoft.com
type=friend
transport=tls
port=5061
allow=all
allow=ulaw
qualify=yes
dtmfmode=rfc2833
context=from-internal
insecure=port,invite
nat=force_rport,comedia
fromdomain=ast.ofon.biz

[MSTeams03-Inbound]
disallow=all
host=sip3.pstnhub.microsoft.com
type=friend
transport=tls
port=5061
allow=all
allow=ulaw
qualify=yes
dtmfmode=rfc2833
context=from-internal
insecure=port,invite
nat=force_rport,comedia
fromdomain=ast.ofon.biz

[Carrier-Inbound]
disallow=all
host=xxx.xxx.xxx.xxx
type=friend
port=xxxx
allow=all
allow=ulaw
qualify=yes
dtmfmode=rfc2833
context=from-internal
insecure=port,invite
nat=force_rport,comedia

replace xxx are Carrier ip address, and port. replace fromdomain with your own FQDN Issabel server.

sip_additional.conf (modify this from Trunk webGUI menu)

[MSTeams-Outbound]
disallow=all
host=sip.pstnhub.microsoft.com
type=peer
transport=tls
port=5061
allow=all
allow=ulaw
qualify=yes
dtmfmode=rfc2833
context=from-trunk
insecure=port,invite
nat=force_rport,comedia
fromdomain=ast.ofon.biz
encryption=yes

[MSTeams02-Outbound]
disallow=all
host=sip.pstnhub.microsoft.com
type=peer
transport=tls
port=5061
allow=all
allow=ulaw
qualify=yes
dtmfmode=rfc2833
context=from-trunk
insecure=port,invite
nat=force_rport,comedia
fromdomain=ast.ofon.biz
encryption=yes

[MSTeams03-Outbound]
disallow=all
host=sip3.pstnhub.microsoft.com
type=peer
transport=tls
port=5061
allow=all
allow=ulaw
qualify=yes
dtmfmode=rfc2833
context=from-trunk
insecure=port,invite
nat=force_rport,comedia
fromdomain=ast.ofon.biz
encryption=yes

[Carrier-Outbound]
host=xxx.xxx.xxx.xxx
port=xxxx
canreinvite=yes
type=peer
insecure=port,invite
nat=force_rport,comedia
context=from-trunk
qualify=yes
dtmfmode=rfc2833

replace xxx are Carrier ip address, and port. replace fromdomain with your own FQDN Issabel server.

Outbound to MSTeams DID

I created 3 outbounds route with this order:

  • Outbound to MSTeams
  • Outbound to Carrier for REFER
  • Outbound to Carrier for each DID

The order should as such. And you dont need to setup any Inbound Routes.

Outbound route to MSTeams should contain your assigned DIDs toward MSTeams account. Should look like this:

Outbound Route to Accomodate REFER

Since I dont know how to replace user part of the URI with RPID, I just pick one DID to accomodate REFER. This is less desireable but the REFER outbound route can act as Global CallerID for the direct routing. Notice that the route contains disposable prefix 9 to avoid overriding from 3rd route (i.e Route for each DID).

This image has an empty alt attribute; its file name is image-2.png

Outbound Route to Carrier for Each DID

(extra) Asterisk SIP Settings from Unembedded IssabelPBX menu

Point the tlsprivatekey, tlscertfile, and tlscafile to your approriate files. And realm should be the Issabel server’s FQDN. The tlsbindaddr can by any ip address and port you wish to use.

That should do it. If I miss anything, please clue me at the comment.

Microsoft Teams Direct Routing with Issabel (Asterisk)

Why?

FYI

  • Should have Issabel server properly installed with ip public and . The server firewall should be hardened by only allowing Carrier and Microsoft cloud ip address blocks (52.112.0.0/14). Even better if the only maintenance can only be accessed by VPN. Dont open your Issabel webGUI, SSH, SIP & RTP ports to public internet whenever possible.
  • My Issbel (Asterisk) server is already connected to Ofon as the PSTN Carrier, and already has a DID assigned.
  • Requires to edit chan_sip.c to comply with Microsoft Teams Phone System that demands SIP From and Contact header host part to be FQDN. From header is easy, just add fromdomain at the Asterisk trunk config and you’re good. The Contact header is the tricky one, based on this screenshot clue (stolen from thread https://community.asterisk.org/t/fqdn-in-the-contact-header/77625):
  • By half-assed editing the chan_sip.c , I expect there will be repercussion somewhere else in the system (plus I am no good at C, should find a better way to insert the change with more elegant solution), so dont share the PBX with something else for production, and use this as POC only.
  • Dont ever think to commercialize this without Microsoft approval, nor use this for officials. You may not be able to open tickets if you encounter problems with this installation although you are a legit Office 365 tenant with Phone System license. The certified SBC list can be found here.
  • Should have access to DNS server to add TXT type record for domain authentication.
  • Should have global admin account to make changes in O365 portal.
  • In this example, I have two E1 O365 + Phone System licenses. One to be assigned to my account and one to be assigned to SIP trunk domain dummy user.
  • You cant do multi tenant with this installation. Asterisk itself is a single realm (CMIIW).
  • Still cant find how to modify Contact header in OPTIONS, hence you’ll find tlsdontverifyserver=yes in Issabel general config.
  • Will periodically update this post with something new whenever I find improvement. So forgive me if you find something different when you read back the post later.

Microsoft Teams Phone System Side Config

In this stage you will need to add an SSL’ed domain to Office 365 portal. Microsoft-recommended CA list can be found here. I myself use GeoTrust.

  • Microsoft has a very detailed documentation that can be found at https://docs.microsoft.com/en-us/microsoftteams/direct-routing-plan . I wont rewrite the details here.
  • Using global admin to add domain (mine is ast.ofon.biz), to O365 admin portal.
  • Add a dummy user for that domain and assign O365 + Phone System license for that dummy user. For example, my dummy user for the newly added domain is sip@ast.ofon.biz. If successfully added, I will find the user in Active users table like this:
  • that is how Microsoft Teams will recognize the SIP trunk to our Issabel (Asterisk) server and assign license to the trunk.
  • Login using powershell to your account using global admin user. Again, the powershell preparation wont be repeated here since the detailed documentation can be found at https://docs.microsoft.com/en-us/microsoftteams/direct-routing-configure. Next steps will require us to import Sfbonline module to powershell.
  • Start the session (you will be asked for password on a popped up windows) :
$sfb = New-CsOnlineSession -Username "admin@ofonio.onmicrosoft.com"
Import-PSSession $sfb -AllowClobber
  • Add the Issabel (Asterisk server) as PSTN Gateway:
New-CsOnlinePSTNGateway -Fqdn ast.ofon.biz -SipSignalingPort 5061 -ForwardCallHistory $true -Enabled $true -ForwardPai $true -MaxConcurrentSessions 5
  • See if the server is properly added with Get-CsOnlinePstnGateway :
 Get-CsOnlinePSTNGateway


Identity                            : ast.ofon.biz
InboundTeamsNumberTranslationRules  : {}
InboundPstnNumberTranslationRules   : {}
OutboundTeamsNumberTranslationRules : {}
OutboundPstnNumberTranslationRules  : {}
Fqdn                                : ast.ofon.biz
SipSignalingPort                    : 5061
FailoverTimeSeconds                 : 10
ForwardCallHistory                  : True
ForwardPai                          : True
SendSipOptions                      : True
MaxConcurrentSessions               : 5
Enabled                             : True
MediaBypass                         : False
GatewaySiteId                       :
GatewaySiteLbrEnabled               : False
FailoverResponseCodes               : 408,503,504
GenerateRingingWhileLocatingUser    : True
PidfLoSupported                     : False
MediaRelayRoutingLocationOverride   :
ProxySbc                            :
BypassMode                          : None
  • Create a routing and routing policy that will utilize the Issabel (Asterisk) server:
Set-CsOnlinePstnUsage -Identity Global -Usage @{Add="Default"}

New-CsOnlineVoiceRoute -Identity "CatchAll" -NumberPattern ".*" -OnlinePstnGatewayList ast.ofon.biz -Priority 1 -OnlinePstnUsages "Default"

New-CsOnlineVoiceRoutingPolicy -Identity "DefaultVoicePolicy" -OnlinePstnUsages "Default"
  • Assign DID & VoiceRoutingPolicy to my account.

Issabel (Asterisk) Side Config

We will have two SIP connection configs for Microsoft Teams Phone System and two SIP connection configs for Carrier. Each connection will have different contexts. One SIP connection for Microsoft Teams will be from-internal, so call from Microsoft Teams will be treated as call from extension. And the other SIP connection will be treated as outbound trunk with from-trunk context. Same deal with the two SIP connections toward Carrier.

Microsoft provides 3 hosts to connect a SIP trunk with:

  • sip.pstnhub.microsoft.com
  • sip2.pstnhub.microsoft.com
  • sip3.pstnhub.microsoft.com

This example will only test the first one (sip.pstnhub.microsoft.com).

  • Adding Trunk to Microsoft Teams from PBX -> PBX Configuration -> Trunks. Add SIP Trunk and fill these parameters :
Trunk Name: MSTeams-Outbound
PEER Details:
disallow=all
host=sip.pstnhub.microsoft.com
type=peer
transport=tls
port=5061
allow=all&ulaw
qualify=yes
dtmfmode=rfc2833
context=from-trunk
insecure=port,invite
nat=force_rport,comedia
fromdomain=ast.ofon.biz
encryption=yes
  • And as “extension” add the following configs to sip_custom.conf using PBX -> Tools -> Asterisk File Editor :
[MSTeams-Inbound]
disallow=all
host=sip.pstnhub.microsoft.com
type=friend
transport=tls
port=5061
allow=all
allow=ulaw
qualify=yes
dtmfmode=rfc2833
context=from-internal
insecure=port,invite
nat=force_rport,comedia
fromdomain=ast.ofon.biz
  • To refer to certifcate files, go to PBX -> PBX Configuration -> Unembedded IssabelPBX. At the following page, go to Settings -> Asterisk SIP Settings and then Add field at the Other SIP Settings with these:
realm=ast.ofon.biz
tlsenable=yes
tlsbindaddr=0.0.0.0:5061
tlsprivatekey=/etc/asterisk/keys/star_ofon_biz.key
tlscertfile=/etc/asterisk/keys/star_ofon_biz.pem
tlscafile=/etc/asterisk/keys/star_ofon_biz.crt
tlscipher=ALL
tlsclientmethod=tlsv1
tlsdontverifyserver=yes
  • Save and reload the config.
  • Add the Outbound Routes to Microsoft Teams and Carrier (Microsoft Teams outbound should be aboive the Carrier). Since my carrier mostly sends with prefix 0, I have to convert it to E.164. Please modify these according to your apporpriate settings:

At this point, you should be able to call outbound from Microsoft Teams account but not the other way (inbound). As mentioned before, Microsoft Teams Phone System require us to send From and Contact header host as FQDN. The trunk settings in Asterisk wont change Contact header host to FQDN hence we’ll receive this message:

INVITE sip:+622430000062@sip.pstnhub.microsoft.com:5061 SIP/2.0
Via: SIP/2.0/TLS xxx.xxx.xxx.xxx:5061;branch=z9hG4bK4e781f8a;rport
Max-Forwards: 70
From: "02139700001" <sip:02139700001@ast.ofon.biz>;tag=as36acd9d9
To: <sip:+622430000062@sip.pstnhub.microsoft.com:5061>
Contact: <sip:02139700001@xxx.xxx.xxx.xxx:5061;transport=tls>
Call-ID: 2239ff467456d8f03c4348826168d7a6@ast.ofon.biz
CSeq: 102 INVITE
User-Agent: Asterisk 16.7.0
Date: Fri, 08 May 2020 04:45:38 GMT
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH, MESSAGE
Supported: replaces, timer
Content-Type: application/sdp
Content-Length: 1324

...
...
...
SIP/2.0 403 Forbidden
FROM: "02139700001"<sip:02139700001@ast.ofon.biz>;tag=as36acd9d9
TO: <sip:+622430000062@sip.pstnhub.microsoft.com:5061>
CSEQ: 102 INVITE
CALL-ID: 2239ff467456d8f03c4348826168d7a6@ast.ofon.biz
VIA: SIP/2.0/TLS xxx.xxx.xxx.xxx:5061;branch=z9hG4bK4e781f8a;rport
REASON: Q.850;cause=63;text="735a16a2-5f83-4cb0-bdec-9cb64edff551;Provided Trunk FQDN 'xxx.xxx.xxx.xxx' is not allowed. Connection allows following fqdns: *.ofon.biz, ofon.biz, *.ofon.biz."
CONTENT-LENGTH: 0
ALLOW: INVITE,ACK,OPTIONS,CANCEL,BYE,NOTIFY
SERVER: Microsoft.PSTNHub.SIPProxy v.2020.5.6.2 i.ASEA.2

chan_sip.c

There is no Asterisk source in Issabel distro so we have to get it ourself. From Issabel linux console, git clone the Asterisk github and checkout for 16.7.0 (since this is my Issabel’s Asterisk version).:

cd /usr/src
git clone https://github.com/asterisk/asterisk.git
cd asterisk
git checkout 16.7.0

Edit file /usr/src/asterisk/channel/chan_sip.c. Look at build_contact() we will find these lines:

static void build_contact(struct sip_pvt *p, struct sip_request *req, int incoming)
{
        char tmp[SIPBUFSIZE];
        char *user = ast_uri_encode(p->exten, tmp, sizeof(tmp), ast_uri_sip_user);
        int use_sips;
        char *transport = ast_strdupa(sip_get_transport(p->socket.type));

        if (incoming) {
                use_sips = uas_sips_contact(req);
        } else {
                use_sips = uac_sips_contact(req);
        }

        if (p->socket.type == AST_TRANSPORT_UDP) {
                ast_string_field_build(p, our_contact, "<%s:%s%s%s>", use_sips ? "sips" : "sip",
                        user, ast_strlen_zero(user) ? "" : "@",
                        ast_sockaddr_stringify_remote(&p->ourip));
        } else {
                ast_string_field_build(p, our_contact, "<%s:%s%s%s;transport=%s>",
                        use_sips ? "sips" : "sip", user, ast_strlen_zero(user) ? "" : "@",
                        ast_sockaddr_stringify_remote(&p->ourip), ast_str_to_lower(transport));
        }
}

The last conditional lines are where the Contact header gets value from. Since we only need to modify for TCP transport, edit the line:

 else {
                ast_string_field_build(p, our_contact, "<%s:%s%s%s;transport=%s>",
                        use_sips ? "sips" : "sip", user, ast_strlen_zero(user) ? "" : "@",
                        ast_sockaddr_stringify_remote(&p->ourip), ast_str_to_lower(transport));
        }

to become :

 else {
                ast_string_field_build(p, our_contact, "<%s:%s%s%s;transport=%s>",
                        use_sips ? "sips" : "sip", user, ast_strlen_zero(user) ? "" : "@",
                        p->fromdomain, ast_str_to_lower(transport));
        }

p->fromdomain will follow whatever “fromdomain=” value in the SIP trunk config.

Update:
Got input from Igo Cunha that the call from MSteams to PSTN will be disconnected after 6 sec. I can confirm I got random disconnect call at about 6 sec from the same direction. Try replace:
 
ast_sockaddr_stringify_remote(&p->ourip) 

with your Asterisk's FQDN string (e.g "ast.ofon.biz" in my case) instead of p->fromdomain.

Thanks Igo!

I understand this is not elegant way, but that should do it. Compile the source and we will have brand new chan_sip.so. Backup the original one and replace it after:

copy /usr/lib64/asterisk/modules/chan_sip.so /usr/local/src/chan_sip.so.original
copy /usr/src/asterisk/channels/chan_sip.so /usr/lib64/asterisk/modules/chan_sip.so

then reload the module from Asterisk console:

asterisk -vr

ast*CLI> module reload chan_sip.so
Module 'chan_sip.so' reloaded successfully.
 Reloading SIP

Now test call to inbound, we should have correct SIP Contact header requirement as follows:

INVITE sip:+622430000062@sip.pstnhub.microsoft.com:5061 SIP/2.0
Via: SIP/2.0/TLS 103.135.74.15:5061;branch=z9hG4bK394b6483;rport
Max-Forwards: 70
From: "02139700001" <sip:02139700001@ast.ofon.biz>;tag=as20858906
To: <sip:+622430000062@sip.pstnhub.microsoft.com:5061>
Contact: <sip:02139700001@ast.ofon.biz;transport=tls>
Call-ID: 1a5d05f10eadb0036683f88a6177f80f@ast.ofon.biz
CSeq: 102 INVITE
User-Agent: Asterisk 16.7.0
Date: Fri, 08 May 2020 04:54:36 GMT
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH, MESSAGE
Supported: replaces, timer
Content-Type: application/sdp
Content-Length: 1324

and the call went through:

Remarks

Although it is possible to connect Direct Routing with Asterisk, still easier using Kamailio (and OpenSIPS) since they’re built solely for SIP packet engineering. Until some of them become certified with Microsoft, I guess I will be using the already ceritfied ones, like Sonus or AudioCodes, or just connect to a hosted Direct Routing Provider in Indonesia, like Ofon. Alternatively, there are Kamailo based products start providing hosted DR, like Gilawa and dSIPRouter. Check them out.

Complete Configs

Links: