简介:本资源是一份面向企业通信架构师、云网络工程师及系统集成商的官方级培训材料,聚焦Microsoft Teams Direct Routing与Azure托管SBC(Session Border Controller)的端到端部署实践,解决PSTN语音接入、多租户中继配置、转码许可等关键集成难题。文件为单个5.63MB的PPTX课件,内容结构完整,涵盖作者背景、前置条件清单(Office 365租户、Azure订阅、AudioCodes Mediant CE设备及CA证书)、Azure资源逐项配置流程(资源组、VNet、NSG、存储账户上传VHD、VM镜像部署)、AudioCodes设备双模型(企业/托管)中继配置要点、SILK载荷调优与转码许可计算规则,以及Office 365租户配对、用户启用与语音路由验证等实操模块。已有92人学习下载,内容由NBConsult高级解决方案架构师Warren du Toit主笔,兼具技术深度与工程落地性,特别提供Syslog日志分析、INI配置备份等排错提示,是实施Teams语音直连方案不可多得的权威参考。
1. Microsoft Teams Direct Routing + Azure 托管 SBC:不是“配个IP就能打通电话”的玄学,而是要亲手把 AudioCodes CE VHD 拆开、重签名、调性能、压 License 的硬核工程
你手头刚拿到一份叫Microsoft Teams Direct Routing with SBC hosted in Azure.pptx的培训材料——别急着点开幻灯片。它表面是 PPT,内里是一套完整可落地的Azure 上部署 AudioCodes Mediant CE 作为 Teams Direct Routing 边界控制器的实战路径图。这不是概念宣讲,而是 Warren du Toit(NBConsult 高级云网络架构师)在 Ignite 会场实操后反向整理的血泪笔记:从 Office 365 租户配 License 开始,到 Azure 虚拟机跑起 AudioCodes CE 镜像,再到config.ini里改 SILK payload、调performance_profile、算清「50 张 SBC 许可 ≠ 50 路并发」的 License 坑——每一步都卡在真实生产环境的边界上。适合两类人:一是正被客户逼着两周内上线 Teams 语音直连 PSTN 的系统集成商工程师;二是想把 Azure 网络能力从 IaaS 深耕到 VoIP 层的云架构师。如果你以为这只是“在 Azure 里装个 SBC 虚拟机”,那等你第一次看到SIP 403 Forbidden: Invalid certificate chain或Media path failed: no codec match时,就会明白为什么这份材料被标注为「官方优质资源」——它不教你怎么截图,只告诉你哪一行 INI 配错了会导致整条中继静音。
2. Azure 基础设施层:不是建完 VM 就完事,VHD 上传、镜像生成、NSG 规则必须按 VoIP 流量特征定制
2.1 创建 Resource Group 与 Virtual Network:命名规则决定后续排错效率
Azure 资源组(Resource Group)不是容器,是权限和生命周期管理单元。我们不建议用teams-sbc-rg这类泛称,而应采用rg-teams-dr-prod-westeurope-01格式:rg-<业务域>-<环境>-<区域>-<序号>。原因很实际——当客户有多个 Direct Routing 实例时,PowerShell 脚本批量查日志或删资源时,靠-like "*dr*"会误杀测试环境。Virtual Network 同理,地址空间必须避开 Teams 客户端默认使用的192.168.0.0/16和10.0.0.0/8(Teams 客户端可能在本地 NAT 后使用这些网段),推荐用172.28.0.0/16,子网划分至少预留/26给 SBC VM(AudioCodes CE 最小要求 4 vCPU / 16GB RAM,需足够 IP)。关键点:VNet 必须启用Enable DNS forwarding,否则 AudioCodes 设备无法解析teams.microsoft.com和sipfed.online.lync.com的 SRV 记录——这是后续 SIP 中继注册失败的隐形杀手。
az group create --name rg-teams-dr-prod-westeurope-01 --location westeurope az network vnet create \ --resource-group rg-teams-dr-prod-westeurope-01 \ --name vnet-teams-dr-prod \ --address-prefixes 172.28.0.0/16 \ --dns-servers 168.63.129.16 \ --tags "Purpose=DirectRouting" "Owner=VoiceTeam"提示:
168.63.129.16是 Azure 平台 DNS 转发器地址,非此地址会导致 AudioCodes CE 的nslookup sipfed.online.lync.com返回NXDOMAIN,进而使中继注册卡在REGISTERING状态。
2.2 Public IP 与 Network Security Group:VoIP 不是 HTTP,端口开放逻辑完全不同
Public IP 必须分配给 SBC VM 的 NIC(而非 Load Balancer),且类型选Static(非 Dynamic)——Teams Direct Routing 要求 SBC 的公网 IP 在Teams Admin Center > Voice > Direct Routing > SBCs页面中静态填写,IP 变更即导致中继断连。NSG 规则常被误配为“放行所有 TCP/UDP”,这是翻车高发区。AudioCodes CE 与 Teams 通信实际依赖以下最小端口集:
| 方向 | 协议 | 端口 | 用途 | 是否必需 |
|---|---|---|---|---|
| Inbound | UDP | 5061 | SIP TLS(中继信令) | ✅ 必须 |
| Inbound | UDP | 10000-20000 | RTP/RTCP 媒体流(Teams 动态分配) | ✅ 必须 |
| Outbound | TCP/UDP | Any | SBC 主动连接 Teams 云(如证书 OCSP 检查) | ✅ 必须 |
| Inbound | TCP | 22 | SSH 管理(仅限调试期) | ⚠️ 生产环境应禁用 |
# 创建 NSG 并附加入站规则 az network nsg create --resource-group rg-teams-dr-prod-westeurope-01 --name nsg-sbc-inbound az network nsg rule create \ --resource-group rg-teams-dr-prod-westeurope-01 \ --nsg-name nsg-sbc-inbound \ --name Allow-SIP-TLS \ --priority 100 \ --direction Inbound \ --access Allow \ --protocol Tcp \ --source-port-range "*" \ --destination-port-range "5061" \ --source-address-prefixes "*" \ --destination-address-prefixes "VirtualNetwork" az network nsg rule create \ --resource-group rg-teams-dr-prod-westeurope-01 \ --nsg-name nsg-sbc-inbound \ --name Allow-RTP-Range \ --priority 110 \ --direction Inbound \ --access Allow \ --protocol Udp \ --source-port-range "*" \ --destination-port-range "10000-20000" \ --source-address-prefixes "*" \ --destination-address-prefixes "VirtualNetwork"注意:
--destination-address-prefixes "VirtualNetwork"表示该规则只允许流量进入 VNet 内部(即 SBC VM),而非整个 Azure 区域。这是 VoIP 安全基线——禁止公网直接访问 SBC 的管理界面(HTTP/HTTPS 端口)。
2.3 Storage Account 上传 VHD:不是拖进去就完事,必须校验 SHA256 且设为 Page Blob
AudioCodes 官方提供的.vhd文件(如MediantCE-8.2.0-azure.vhd)体积通常超 8GB。Azure Storage Account 必须创建为General Purpose v2类型,并启用Hierarchical Namespace(ADLS Gen2)——虽非强制,但能加速后续 PowerShell 脚本调用Get-AzStorageBlobContent下载配置文件。关键动作:上传前用sha256sum MediantCE-8.2.0-azure.vhd计算校验值,上传后通过 Azure Portal 或 CLI 验证 blob 的Content-MD5是否匹配(VHD 上传若中断,Azure 不会自动重试,损坏的 VHD 会导致 VM 创建后蓝屏)。
# PowerShell 示例:上传并验证 $ctx = (Get-AzStorageAccount -ResourceGroupName "rg-teams-dr-prod-westeurope-01" -Name "stteamsdrprod01").Context $localVhdPath = "C:\downloads\MediantCE-8.2.0-azure.vhd" $blobName = "mediant-ce-8.2.0-azure.vhd" # 上传为 Page Blob(VHD 必须) $uploadTask = Set-AzStorageBlobContent -File $localVhdPath ` -ContainerName "vhds" ` -Blob $blobName ` -Context $ctx ` -BlobType "PageBlob" ` -StandardBlobTier "Premium_LRS" ` -Verbose # 验证 SHA256(需提前保存本地校验值) $expectedSha = "a1b2c3d4e5f6..." # 替换为实际值 $uploadedBlob = Get-AzStorageBlob -Container "vhds" -Blob $blobName -Context $ctx $actualSha = $uploadedBlob.ICloudBlob.Properties.ContentMD5 if ($expectedSha -ne $actualSha) { throw "VHD upload corrupted! Expected SHA256: $expectedSha, got: $actualSha" }提示:
-StandardBlobTier "Premium_LRS"是必须项。AudioCodes CE 对磁盘 IOPS 敏感,标准 LRS 存储的随机读写延迟(>10ms)会导致媒体包乱序,表现为通话单通或断续。Premium LRS 提供稳定 5000 IOPS,满足 CE 设备最低要求。
3. AudioCodes Mediant CE 部署与初始化:从 VHD 到可 ping 通的 VM,中间隔着三个必须手动干预的环节
3.1 创建 VM Image:不能直接用 VHD 创建 VM,必须先转为托管镜像
Azure 不允许直接从上传的 VHD 启动 VM(除非用az vm create --use-unmanaged-disk,但 AudioCodes CE 不支持非托管磁盘)。正确路径是:VHD → 托管镜像 → VM。这步常被跳过,导致 VM 启动后网卡无 IP 或eth0未激活。原因在于 AudioCodes CE VHD 内置的 Linux initrd 依赖 Azure 特定的walinuxagent和udev规则,只有通过az image create注册为镜像,Azure 才会在 VM 启动时注入正确的 cloud-init 配置。
az image create \ --resource-group rg-teams-dr-prod-westeurope-01 \ --name img-audiocodes-ce-820 \ --source https://stteamsdrprod01.blob.core.windows.net/vhds/mediant-ce-8.2.0-azure.vhd \ --os-type linux \ --hyper-v-generation V2 \ --storage-sku Premium_LRS注意:
--hyper-v-generation V2是强制项。AudioCodes CE 8.x+ 仅支持 Gen2 VM(UEFI 启动),若用 Gen1,VM 会卡在 BIOS 初始化阶段,串口日志显示No bootable device。
3.2 部署 VM 并配置 NIC:必须绑定 Public IP 且禁用 Accelerated Networking
VM 规格选择Standard_D4s_v3(4 vCPU / 16GB RAM)是 AudioCodes CE 8.2 的官方最低要求。但关键在 NIC 配置:Public IP 必须绑定到 NIC,而非 VM 本身;且必须关闭Accelerated Networking——这是绝大多数初学者踩坑的根源。AudioCodes CE 的内核驱动(acp模块)与 Azure 的 SR-IOV 硬件卸载不兼容,开启后会导致eth0收不到任何 SIP 包,Wireshark 抓包显示no packets received。
az vm create \ --resource-group rg-teams-dr-prod-westeurope-01 \ --name vm-sbc-prod-01 \ --image img-audiocodes-ce-820 \ --size Standard_D4s_v3 \ --admin-username audiocodes \ --generate-ssh-keys \ --vnet-name vnet-teams-dr-prod \ --subnet default \ --public-ip-address pip-sbc-prod-01 \ --nsg nsg-sbc-inbound \ --os-disk-size-gb 128 \ --tags "SBCVersion=8.2.0" "Deployment=DirectRouting" # 关闭 Accelerated Networking(必须!) az network nic update \ --resource-group rg-teams-dr-prod-westeurope-01 \ --name vm-sbc-prod-01VMNic \ --accelerated-networking false3.3 首次登录与基础网络验证:用audiocodes账户而非 root
AudioCodes CE 默认禁用 root SSH 登录,必须用预置账户audiocodes(密码在文档中提供,首次登录后强制修改)。登录后第一件事不是配 SIP,而是验证三层连通性:
# 检查网卡状态(必须 UP 且有 IPv4 地址) ip addr show eth0 | grep "inet " # 测试到 Teams 云的连通性(关键!) ping -c 3 sipfed.online.lync.com # 应返回 IP 且无丢包 telnet sipfed.online.lync.com 5061 # 应显示 Connected(证明 TLS 握手可达) # 检查 DNS 解析(必须返回 SRV 记录) nslookup -type=SRV _sipfederationtls._tcp.teams.microsoft.com # 正确响应示例:sipfed.online.lync.com service = 10 100 5061 sipfed.online.lync.com.提示:若
nslookup返回*** Can't find _sipfederationtls._tcp.teams.microsoft.com: Non-existent domain,说明 VNet DNS 设置错误(见 2.1 节),此时 SIP 中继永远无法注册。
4. AudioCodes CE 配置核心:config.ini里改 7 行,决定中继是“通”还是“哑”
4.1 License 激活:不是上传 lic 文件就生效,必须重启acp服务
AudioCodes CE 的 License 文件(.lic)需上传至/usr/local/audiocodes/license/目录,但仅上传不触发激活。必须执行:
sudo systemctl restart acp sudo systemctl status acp | grep "Active:" # 应显示 active (running)验证 License 是否生效:
sudo /usr/local/audiocodes/bin/acp_license_info # 输出中必须包含: # Concurrency: 50 # Transcoding: 25 ← 注意:Transcoding 并发数 = Concurrency / 2注意:License 文件名必须为
license.lic(固定名),且权限为600。若命名为mylicense.lic,acp_license_info会显示No license found。
4.2 SIP Trunk 配置:企业模型 vs 托管模型,trunk_type决定路由逻辑
AudioCodes CE 支持两种 Direct Routing 模式,由trunk_type参数控制:
| 参数 | 企业模型(Enterprise) | 托管模型(Hosting) |
|---|---|---|
trunk_type | enterprise | hosting |
| 适用场景 | 单一租户,PBX 直连 Teams | MSP 托管多租户,每个租户独立中继 |
| SIP URI 格式 | user@contoso.com | user@contoso.com;transport=tls(需加 transport 参数) |
| 路由策略 | 由 Teams Admin Center 的 Voice Routing Policy 控制 | 由 AudioCodes CE 的route_pattern规则控制 |
配置片段(/usr/local/audiocodes/config/config.ini):
[trunk_1] name = Teams-Trunk-01 trunk_type = enterprise signaling_ip = 172.28.1.10 signaling_port = 5061 transport = tls domain = contoso.com ; 企业模型下,Teams 会自动发送 REGISTER 到此 IP:Port[trunk_2] name = PSTN-Trunk-01 trunk_type = pstn signaling_ip = 192.168.100.50 ; 你的本地 PBX IP signaling_port = 5060 transport = udp4.3 媒体参数调优:SILK Payload 修改是解决“单通”的后悔药
Teams 默认使用 SILK 编解码器(窄带 8kHz / 宽带 16kHz)。若 AudioCodes CE 未显式声明支持,媒体协商会 fallback 到 G.711,但 Teams 客户端可能拒绝 G.711(尤其移动 App)。必须在config.ini的[media]区块中强制声明:
[media] codec_priority_list = silknb,silkwb,g711a,g711u silk_nb_payload_type = 103 silk_wb_payload_type = 104 ; Teams 使用 payload type 103/104,若此处不匹配,Wireshark 显示 "RTP: Unknown payload type"提示:修改后必须执行
sudo /usr/local/audiocodes/bin/acp_reload_config重载配置,不能 reboot——reboot 会丢失所有 runtime 状态,中继需重新注册(耗时 2-3 分钟)。
5. 避坑:AudioCodes CE + Teams Direct Routing 的五个血泪现场
5.1 现象:SBC 在 Teams Admin Center 显示 “Registered”,但用户拨号无响应
原因:config.ini中trunk_1的signaling_ip填写了私网 IP(如10.0.0.10),而 Teams 云只能访问 SBC 的公网 IP。Teams 发送 SIP INVITE 到私网 IP,自然超时。
解决:signaling_ip必须填 SBC 的公网 IP(即pip-sbc-prod-01的 IP),并在 AudioCodes CE 的network配置中将该公网 IP 绑定到eth0的 secondary address(主 IP 仍为 VNet 内网 IP)。
5.2 现象:通话建立后 30 秒自动挂断,日志显示BYE reason=Timeout
原因:Azure NSG 缺少对Outbound方向的Keep-Alive流量放行。Teams 云每 25 秒发送 SIP OPTIONS 包探测中继存活,若 NSG 拦截,SBC 认为链路中断。
解决:在 NSG 中添加出站规则,允许Any协议到Internet,优先级低于入站规则(如 200)。
5.3 现象:启用 Transcoding 后并发数暴跌,License 显示Used: 50/25
原因:Transcoding 按 call leg 计费,一个双向通话消耗 2 个 transcoding license(上行 + 下行)。50 张 Transcoding License 仅支持 25 路并发。
解决:在config.ini中关闭不必要的 transcoding:transcoding_enabled = false,或升级 License。
5.4 现象:audiocodes INI Edit工具无法连接,浏览器提示ERR_CONNECTION_REFUSED
原因:AudioCodes CE 的 Web 管理界面默认绑定到127.0.0.1:80,未监听0.0.0.0。
解决:SSH 登录后执行sudo /usr/local/audiocodes/bin/acp_webserver_config --bind 0.0.0.0:80,再sudo systemctl restart acp_webserver。
5.5 现象:Teams 用户拨打 PSTN 号码,对方听到忙音,SBC 日志无 SIP 消息
原因:Office 365 租户未启用Enterprise Voice,或用户未分配Phone SystemLicense。
解决:PowerShell 执行:
Set-CsUser -Identity user@contoso.com -EnterpriseVoiceEnabled $true -HostedVoiceMail $true # 并确认 License 已分配:Get-MsolUser -UserPrincipalName user@contoso.com | fl Licenses6. 进阶验证:用sipcmd模拟 Teams 云注册,把黑匣子变成透明管道
6.1 构建最小化 SIP 注册验证脚本
与其等 Teams Admin Center 的“绿色 Registered”图标,不如用开源工具sipcmd主动模拟 Teams 云的注册行为。这能绕过 Teams 后端缓存,5 秒内定位信令层问题。
# 在任意 Linux 机器(非 SBC)安装 sipcmd wget https://github.com/asipto/sipcmd/releases/download/v1.2.0/sipcmd-1.2.0-linux-x86_64.tar.gz tar -xzf sipcmd-1.2.0-linux-x86_64.tar.gz cd sipcmd-1.2.0-linux-x86_64 # 执行注册测试(替换 YOUR_SBC_PUBLIC_IP) ./sipcmd -u testuser@contoso.com \ -w contoso.com \ -h YOUR_SBC_PUBLIC_IP \ -p 5061 \ -t tls \ -x "reg 3600" \ -v预期成功输出:
INFO: Sending REGISTER to YOUR_SBC_PUBLIC_IP:5061 INFO: Received 200 OK for REGISTER INFO: Registration successful, expires in 3600 seconds若失败,-v参数会打印完整 SIP 消息,可直接比对:
401 Unauthorized→ SBC 证书未被 Teams 信任(检查 CA 证书是否上传且cert_name配置正确)403 Forbidden→config.ini中domain与 Teams 租户域名不匹配Timeout→ NSG 阻断 UDP 5061 或 SBC 未监听该端口(netstat -tuln | grep 5061)
6.2 媒体路径抓包:Wireshark 过滤规则表
当通话单通时,SIP 信令正常但 RTP 不通,必须抓包。在 SBC VM 上执行:
sudo tcpdump -i eth0 -w /tmp/sbc-media.pcap port 10000-20000 and udp # 生成 pcap 后下载到本地,用 Wireshark 分析常用 Wireshark 过滤表达式:
| 场景 | 过滤表达式 | 说明 |
|---|---|---|
| 查看所有 RTP 流 | rtp | 确认是否有 RTP 包发出 |
| 查看 Teams 客户端发来的 RTP | ip.addr == 52.114.132.100 && rtp | Teams 云媒体服务器 IP 段(需查最新) |
| 查看 SBC 回传的 RTP | ip.addr == 172.28.1.10 && rtp | SBC 内网 IP |
| 检查编解码协商 | sip && sip.Method == "INVITE" | 查看 SDP 中m=audio行的 codec |
提示:Teams 云媒体服务器 IP 不固定,但主要分布在
52.114.0.0/16、52.120.0.0/16。若ip.addr == 52.114.132.100无 RTP,说明 Teams 未发送媒体——问题在 Teams 侧或 SIP 路由策略。
6.3 License 使用率实时监控:用acp_license_info+ cron 自动告警
生产环境必须监控 License 使用率。我一般会写一个脚本每 5 分钟检查,并在超 80% 时发邮件:
#!/bin/bash # /opt/monitor/sbc-license-check.sh USED=$(sudo /usr/local/audiocodes/bin/acp_license_info 2>/dev/null | grep "Used:" | awk '{print $2}' | sed 's/\///') TOTAL=$(sudo /usr/local/audiocodes/bin/acp_license_info 2>/dev/null | grep "Total:" | awk '{print $2}') USAGE_PCT=$((USED * 100 / TOTAL)) if [ $USAGE_PCT -gt 80 ]; then echo "ALERT: SBC License usage at ${USAGE_PCT}% on $(hostname)" | mail -s "SBC License Warning" admin@contoso.com fi加入 crontab:
*/5 * * * * /opt/monitor/sbc-license-check.sh从那以后我每次部署新 SBC,都强制走一遍sipcmd注册测试 +tcpdump抓包验证,哪怕客户说“只要 Admin Center 显示绿色就行”。因为绿色图标只代表 SIP REGISTER 成功,不代表媒体通、License 足、DNS 准——而用户投诉的“打不通”,90% 出现在这三处。希望帮到你。
本文还有配套的精品资源,点击获取