跳到主要内容

在线计费系统 (OCS) 集成

全面指南,介绍 OmniTAS 如何通过 Diameter Ro 接口与在线计费系统集成,包括实时信用控制、AVP 提取和 FreeSWITCH 变量映射。

目录

架构概述

OmniTAS 根据 3GPP TS 32.299 实现 Diameter Ro 接口以进行实时在线计费。该系统通过在呼叫建立之前向 OCS 请求信用来授权呼叫,在呼叫过程中监控信用,并在终止时报告最终使用情况。

关键组件

信用控制请求 (CCR):

  • CCR-Initial (类型 1): 在呼叫建立之前发送以请求初始信用授权
  • CCR-Update (类型 2): 在活动呼叫期间发送以进行重新授权或临时更新
  • CCR-Terminate (类型 3): 在呼叫终止时发送以报告最终使用情况

信用控制应答 (CCA):

  • 包含授予的服务单元(以秒为单位的时间配额)
  • 包含供应商特定的 AVPs 以及附加的计费数据
  • 提供路由信息、被收费方详细信息和服务标识符

信用控制流程

呼叫授权序列

信用耗尽处理

OmniTAS 支持多种处理信用耗尽的机制,自动集成计划挂断和信用耗尽公告。

动态重新调度的计划挂断

schedule_hangup_auth 启用时,OmniTAS 会调度一个 FreeSWITCH 定时器,当授予的信用到期时自动终止呼叫。每次通过 CCR-Update 响应授予新信用时,该定时器会 动态重新调度

工作原理:

缓冲逻辑:

OmniTAS 在授予的信用到期 之前 发送 CCR-Update 消息,以确保持续服务。缓冲时间可以通过 ccr_update_buffer_seconds 配置(默认:2 秒)。

示例时间线:

  • T+0s: 呼叫接听,OCS 授予 10s,定时器计划在 T+10s
  • T+8s: 发送 CCR-U(10s - 2s 缓冲)
  • T+8.1s: OCS 授予 10s,定时器重新调度到 T+18.1s(从现在起 10s)
  • T+16.1s: 发送 CCR-U
  • T+16.2s: OCS 授予 10s,定时器重新调度到 T+26.2s
  • 呼叫在 OCS 持续授予信用时继续进行

需要关注的日志:

[OCS HANGUP RESCHEDULE] 找到 UUID <uuid> 的呼叫 <id> - 将定时器重新调度到从现在起 10s
[SCHED TRANSFER] 在 10s 内调度转接到 credit_exhausted 拨号计划 <uuid>
[OCS HANGUP RESCHEDULE] 成功重新调度呼叫 <id> 的定时器 (UUID: <uuid>)

集成:schedule_hangup_auth + credit_exhaustion_announcement

两个 功能都启用时,OmniTAS 自动使用计划 转接 而不是直接挂断,允许呼叫者在呼叫终止之前听到公告。

未配置公告时:

config :tas, :online_charging,
schedule_hangup_auth: true,
credit_exhaustion_announcement: nil

→ 使用 sched_hangup - 当信用到期时直接挂断

配置公告时:

config :tas, :online_charging,
schedule_hangup_auth: true,
credit_exhaustion_announcement: "${base_dir}/sounds/en/us/callie/misc/8000/credit_exhausted.wav"

→ 使用 sched_transfer - 转接到 credit_exhausted 拨号计划,播放公告后挂断

转接工作原理:

  1. OmniTAS ���置 tas_call_reason=credit_exhausted 通道变量
  2. 调度转接到 credit_exhausted 扩展,在 ims_as 拨号计划上下文中
  3. 当定时器触发时:
    • FreeSWITCH 将 A-leg 转接到 credit_exhausted 拨号计划
    • 桥接自动断开,B-leg 收到 BYE
    • 拨号计划向 A-leg 播放公告
    • 呼叫在公告后终止

好处:

  • 呼叫者听到专业公告,而不是突然断开
  • B-leg(被叫方)听不到公告
  • CCR-T 仍然发送实际使用情况
  • 公告路径:必须相对于 FreeSWITCH 基目录(使用 ${base_dir} 变量)

CCR-Update 中的即时信用耗尽

如果 OCS 在 CCR-Update 中 拒绝信用 或返回 零秒,OmniTAS 会立即触发信用耗尽处理,覆盖任何计划的定时器。

OCS 响应场景:

处理的错误代码:

OCS 响应动作日志
{:ok, 0} (零秒)立即信用耗尽挂断信用耗尽(分配零秒) - 触发立即挂断
{:error, 4012} (CREDIT_LIMIT_REACHED)立即信用耗尽挂断信用耗尽(4012 CREDIT_LIMIT_REACHED) - 触发立即挂断
{:error, 4010} (END_USER_SERVICE_DENIED)立即信用耗尽挂断服务拒绝(4010 END_USER_SERVICE_DENIED) - 触发立即挂断
{:error, reason} (其他错误)停止周期性 CCR 作业,计划的定时器触发周期性 CCR 失败,错误 <reason> - 停止作业
{:ok, N} 其中 N > 0重新调度定时器到 +N 秒周期性 CCA 分配 Ns,将在 (N-buffer)s 内发送下一个 CCR-U

优先级: 立即信用耗尽处理 优先 于计划定时器。如果 OCS 在 T+8s 拒绝信用,但定时器计划在 T+10s,则在 T+8s 立即挂断,计划的定时器变得无关紧要。

中途信用拒绝的示例时间线:

T+0s:   呼叫接听
T+0.1s: OCS 授予 10s → 定时器计划在 T+10.1s
T+8s: 发送 CCR-U(缓冲 = 2s)
T+8.1s: OCS 返回 0 秒 → 立即转接到 credit_exhausted 拨号计划
T+8.2s: 向呼叫者播放公告
T+10s: 呼叫终止(计划的定时器无关紧要)

立即信用耗尽的日志:

[warning] 信用耗尽(分配零秒) - 触发立即挂断
[warning] 正在挂断呼叫 <id> (UUID: <uuid>),由于信用耗尽
[info] 信用耗尽公告配置: "${base_dir}/sounds/..."
[info] 在挂断之前播放公告: ...
[info] 为 <uuid> 设置 tas_call_reason=credit_exhausted
[info] 转接到信用耗尽拨号计划: uuid_transfer <uuid> credit_exhausted XML ims_as

总结:信用耗尽机制

OmniTAS 提供两种互补机制:

  1. 计划定时器 (schedule_hangup_auth):

    • 当授予的信用到期时自动挂断/转接
    • 在每个 CCR-U 响应时动态重新调度
    • 使用缓冲逻辑在到期之前发送 CCR-U
    • 与公告功能集成
  2. 即时耗尽处理:

    • 当 OCS 在 CCR-U 中拒绝信用时触发
    • 覆盖计划定时器
    • 支持公告播放
    • 处理特定的 Diameter 错误代码

这两种机制都遵循 credit_exhaustion_announcement 配置,并将在配置时在终止呼叫之前播放配置的音��。

AVP 解析和变量映射

概述

OmniTAS 自动从信用控制应答消息中提取属性值对 (AVPs),并将其作为通道变量提供给 FreeSWITCH。这使得拨号计划逻辑可以使用 OCS 提供的数据进行路由决策、计费目的或呼叫处理。

支持的 AVP 类型:

  • 简单值 (UTF8String, Unsigned32, Integer32)
  • 带有嵌套结构的分组 AVPs
  • 供应商特定的 AVPs (例如,3GPP 服务信息)

变量命名约定: AVPs 被扁平化为点符号通道变量,前缀为 CCA:

CCA.<AVP-名称>.<嵌套-AVP-名称>.<值-AVP-名称> = "值"

常见 AVP 映射

服务信息 AVP (3GPP)

服务信息分组 AVP (AVP 代码 873, 供应商 ID 10415) 包含 IMS 特定的计费详细信息:

示例 OCS 响应:

服务信息
├── IMS-信息
│ ├── 运营商选择路由信息: "1408"
│ └── 节点功能: 6
└── 替代收费方地址: "NickTest"

生成的 FreeSWITCH 变量:

CCA.Service-Information.Carrier-Select-Routing-Information = "1408"
CCA.Service-Information.Alternate-Charged-Party-Address = "NickTest"

在拨号计划中访问: 变量使用点符号和连字符,如上所示:

<action application="log" data="INFO 运营商: ${CCA.Service-Information.Carrier-Select-Routing-Information}"/>

使用 uuid_dump 查看: 在 FreeSWITCH 控制台或 ESL 中,变量以 variable_ 前缀出现:

variable_CCA.Service-Information.Carrier-Select-Routing-Information: 1408
variable_CCA.Service-Information.Alternate-Charged-Party-Address: NickTest

注意: FreeSWITCH 保留变量名称中的点和连字符。变量在所有拨号计划上下文和应用程序中都可以使用。

授予服务单元 AVP

时间配额被提取并可用:

OCS 响应:

授予服务单元
└── CC-时间: 600

变量:

allocated_time = 600

AVP 处理逻辑

处理规则:

  1. 分组 AVPs 增加变量名称层次,但没有值本身
  2. 简单 AVPs 被映射到具有其完整��路径的变量
  3. 供应商特定的 AVPs 与标准 AVPs 处理相同
  4. 未知 AVPs 安全跳过而不产生错误

示例:多层嵌套

OCS CCA 结构:

服务信息 (分组)
├── IMS-信息 (分组)
│ ├── 节点功能: 6
│ ├── 节点角色: 1
│ ├── 呼叫方地址: "tel:+313380000000670"
│ └── 时间戳 (分组)
│ ├── SIP-请求时间戳: "2026-01-24T22:40:18Z"
│ └── SIP-响应时间戳: "2026-01-24T22:40:18Z"
└── IN-信息 (分组)
└── 实际被叫号码: "24724741234"

生成的 FreeSWITCH 变量:

CCA.Service-Information.IMS-Information.Node-Functionality = "6"
CCA.Service-Information.IMS-Information.Role-Of-Node = "1"
CCA.Service-Information.IMS-Information.Calling-Party-Address = "tel:+313380000000670"
CCA.Service-Information.IMS-Information.Time-Stamps.SIP-Request-Timestamp = "2026-01-24T22:40:18Z"
CCA.Service-Information.IMS-Information.Time-Stamps.SIP-Response-Timestamp = "2026-01-24T22:40:18Z"
CCA.Service-Information.IN-Information.Real-Called-Number = "24724741234"

配置

在线计费参数

参数类型必需默认描述
enabled布尔值false启用在线计费集成。当为 false 时,所有呼叫绕过 OCS 授权。
periodic_ccr_time_seconds整数60在活动呼叫期间 CCR-Update 消息之间的间隔(以秒为单位)。当启用 schedule_hangup_auth 时不使用(基于授予信用的动态定时)。推荐范围:30-300 秒用于传统模式。
ccr_update_buffer_seconds整数2在发送 CCR-Update 时,信用到期前的安全缓冲(以秒为单位)。OmniTAS 在 (allocated_time - buffer) 时发送 CCR-U,以确保在到期之前延长信用。推荐:2-5 秒。
schedule_hangup_auth布尔值false启用当授予的信用到期时自动挂断/转接呼叫。当为 true 时,OmniTAS 根据每个 CCA 的 allocated_time 调度 FreeSWITCH 定时器,并在每个 CCR-U 响应时动态重新调度。与 credit_exhaustion_announcement 一起工作。
credit_exhaustion_announcement字符串nil信用耗尽公告的音频文件路径。当与 schedule_hangup_auth 一起配置时,使用计划 转接 在挂断之前播放公告。当单独配置(不与 schedule_hangup_auth 一起)时,仅在立即信用耗尽时播放公告。路径必须使用 FreeSWITCH 变量:"${base_dir}/sounds/..."。设置为 nil 以直接挂断而不播放公告。
skipped_regex列表[字符串][]绕过 OCS 的目标号码的正则表达式模式列表。对紧急号码(例如,"^911$""^000$")很有用。

Diameter 连接参数

参数类型必需默认描述
origin_host字符串-OmniTAS Diameter 身份 (FQDN)。在您的 Diameter 网络中必须唯一。例如:"tas01.epc.mnc123.mcc456.3gppnetwork.org"
origin_realm字符串-OmniTAS Diameter 领域。用于路由决策。例如:"epc.mnc123.mcc456.3gppnetwork.org"
destination_realm字符串-OCS Diameter 领域。请求路由到该领域中的对等方。
destination_host字符串nil特定 OCS Diameter 身份。当为 nil 时,仅基于 destination_realm 进行路由。当需要直接路由到特定 OCS 实例时使用。

配置示例

config :tas, :online_charging,
# 启用在线计费
enabled: true,

# 每 60 秒发送一次 CCR-Update
periodic_ccr_time_seconds: 60,

# 根据授予的信用调度挂断
schedule_hangup_auth: true,

# 在信用耗尽挂断之前播放公告
credit_exhaustion_announcement: "ivr/ivr-account_balance_low.wav",

# 跳过紧急呼叫和语音信箱的 OCS
skipped_regex: [
"^911$", # 紧急(美国)
"^000$", # 紧急(澳大利亚)
"^\*86$" # 语音信箱访问
]

config :tas, :diameter,
# 服务身份
origin_host: "tas01.epc.mnc380.mcc313.3gppnetwork.org",
origin_realm: "epc.mnc380.mcc313.3gppnetwork.org",

# OCS 路由
destination_realm: "epc.mnc380.mcc313.3gppnetwork.org",
destination_host: nil # 基于领域的路由

工作原理:

当接收到呼叫时:

  1. 检查目标号码是否与 skipped_regex 模式匹配
  2. 如果匹配,呼叫绕过 OCS(对紧急服务很有用)
  3. 如果不匹配,CCR-Initial 在 destination_realm 发送到 OCS
  4. 解析 CCA 响应以获取授予的单位和 AVPs
  5. 将 AVPs 映射到 FreeSWITCH 变量(见 AVP 映射
  6. 呼叫继续进行,allocated_time 和 AVP 数据可用
  7. 在呼叫期间每 periodic_ccr_time_seconds 发送 CCR-Update
  8. 如果启用 schedule_hangup_auth,当信用到期时自动挂断
  9. 在呼叫完成时发送 CCR-Terminate

用例:

  • 基本 OCS: 启用默认设置以进行标准信用控制
  • 高价值呼叫: 将 periodic_ccr_time_seconds 减少到 30s 以进行频繁的重新认证
  • 预付费服务: 启用 schedule_hangup_auth 并设置 credit_exhaustion_announcement
  • 紧急合规性: 将紧急号码添加到 skipped_regex 以确保始终连接

FreeSWITCH 集成

在拨号计划中访问 AVP 变量

从 CCA 消息中提取的 AVP 数据可作为通道变量在 FreeSWITCH 拨号计划中使用:

<extension name="Route_with_OCS_Data">
<condition field="destination_number" expression="^(.+)$">

<!-- 访问来自 OCS 的运营商路由信息 -->
<action application="log"
data="INFO 运营商代码: ${CCA.Service-Information.Carrier-Select-Routing-Information}"/>

<!-- 访问来自 OCS 的被收费方 -->
<action application="log"
data="INFO 被收费方: ${CCA.Service-Information.Alternate-Charged-Party-Address}"/>

<!-- 访问授予的时间 -->
<action application="log"
data="INFO 分配时间: ${allocated_time} 秒"/>

<!-- 根据运营商代码路由 -->
<action application="set"
data="carrier_code=${CCA.Service-Information.Carrier-Select-Routing-Information}"/>
<action application="bridge"
data="sofia/external/$1@carrier-${carrier_code}.sip.example.com"/>

</condition>
</extension>

变量可用性

时机:

  • 变量在 FreeSWITCH 呼叫设置 之前 设置
  • 在整个呼叫持续期间可用
  • 在呼叫转接和更新之间保持

范围:

  • 通道范围(特定于单个呼叫腿)
  • 不会被桥接/转接的腿继承
  • 在所有拨号计划应用程序中安全使用

示例用例

1. 基于 OCS 数据的运营商选择

使用 OCS 提供的运营商代码路由呼叫:

<extension name="Carrier_Selection">
<condition field="${CCA.Service-Information.Carrier-Select-Routing-Information}" expression="^(.+)$">
<action application="bridge"
data="sofia/external/${destination_number}@carrier-$1.example.com"/>
</condition>

<!-- 如果未指定运营商则回退 -->
<condition field="${CCA.Service-Information.Carrier-Select-Routing-Information}" expression="^$">
<action application="bridge"
data="sofia/external/${destination_number}@default-carrier.example.com"/>
</condition>
</extension>

工作原理: OCS 在服务信息 AVP 中返回运营商代码 "1408"。FreeSWITCH 根据此数据将呼叫路由到 carrier-1408.example.com 网关。

2. 替代计费方

根据 OCS 响应将计费路由到不同方:

<extension name="Alternate_Billing">
<condition field="${CCA.Service-Information.Alternate-Charged-Party-Address}" expression="^(.+)$">

<!-- 记录计费方以用于 CDR -->
<action application="set"
data="billed_party=$1"/>
<action application="export"
data="billed_party=$1"/>

<!-- 包含在 SIP 头中 -->
<action application="set"
data="sip_h_X-Billed-Party=$1"/>

<action application="bridge"
data="sofia/external/${destination_number}@trunk.example.com"/>
</condition>
</extension>

工作原理: OCS 指定替代收费方(例如,公司账户)。OmniTAS 从 AVP 中提取 "NickTest",并使其可用于拨号计划以进行 CDR 记录和 SIP 头插入。

3. 有时间限制的呼叫与警告

在信用到期之前提供警告:

<extension name="Credit_Warnings">
<condition field="destination_number" expression="^(.+)$">

<!-- 在挂断前 30 秒调度警告 -->
<action application="set"
data="warning_time=${expr(${allocated_time} - 30)}"/>

<action application="sched_hangup"
data="+${allocated_time} ALLOTTED_TIMEOUT"/>

<action application="sched_broadcast"
data="+${warning_time} playback::ivr/ivr-account_balance_low.wav"/>

<action application="bridge"
data="sofia/external/$1@trunk.example.com"/>
</condition>
</extension>

工作原理: 使用来自 OCS 的 allocated_time 来调度自动挂断,并在断开连接前 30 秒播放警告公告。

Diameter 消息

CCR-Initial (请求类型 1)

在呼叫设置之前发送以请求授权和初始信用分配。

发送的关键 AVPs:

AVP代码类型描述
Session-Id263UTF8String唯一会话标识符:<origin_host>;<timestamp>;<random>
Auth-Application-Id258Unsigned324 用于 Diameter 信用控制应用程序,见 RFC 4006
Service-Context-Id461UTF8String"000.000.12.32260@3gpp.org" 用于 IMS 计费,见 TS 32.299
CC-Request-Type416枚举1 (INITIAL_REQUEST)
CC-Request-Number415Unsigned32序列号,从 1 开始
Subscription-Id443分组订阅者 MSISDN 或 IMSI
Requested-Service-Unit437分组请求的信用(时间或单位)
Service-Information873分组IMS 特定的呼叫详细信息(呼叫方/被叫方、时间戳)

示例 CCR-I:

Session-Id: "tas01.example.org;1769294418268;8a078232"
Auth-Application-Id: 4
CC-Request-Type: 1 (INITIAL_REQUEST)
CC-Request-Number: 1
Subscription-Id:
- Subscription-ID-Type: 0 (END_USER_E164)
Subscription-ID-Data: "313380000000670"
Requested-Service-Unit:
- CC-Time: 0 (请求最大可用)
Service-Information:
- IMS-Information:
- Calling-Party-Address: "tel:+313380000000670"
- Called-Party-Address: "tel:+24724741234"
- Node-Functionality: 6 (AS)

CCA (信用控制应答)

来自 OCS 的响应,包含授权决定和授予的信用。

接收的关键 AVPs:

AVP代码类型描述
Result-Code268Unsigned322001 表示成功。有关错误值,请参见 结果代码
Granted-Service-Unit431分组分配的信用(以秒为单位的时间)
Service-Information873分组附加的计费数据(运营商信息、收费方等)

示例 CCA 及 AVPs:

Session-Id: "tas01.example.org;1769294418268;8a078232"
Result-Code: 2001 (DIAMETER_SUCCESS)
CC-Request-Type: 1
CC-Request-Number: 1
Granted-Service-Unit:
- CC-Time: 600 (授予 10 分钟)
Service-Information:
- IMS-Information:
- Carrier-Select-Routing-Information: "1408"
- Alternate-Charged-Party-Address: "NickTest"

生成的变量:

allocated_time = 600
CCA.Service-Information.Carrier-Select-Routing-Information = "1408"
CCA.Service-Information.Alternate-Charged-Party-Address = "NickTest"

CCR-Update (请求类型 2)

在活动呼叫期间发送,用于周期性重新授权或临时使用报告。

发送时机:

  • periodic_ccr_time_seconds(默认:60s)
  • 在呼叫接听时(从设置转为活动)
  • 当显式触发时(例如,服务变更)

与 CCR-I 的关键区别:

  • CC-Request-Type: 2 (UPDATE_REQUEST)
  • CC-Request-Number: 随每次更新递增
  • Used-Service-Unit: 报告自上次请求以来的使用情况
  • Requested-Service-Unit: 请求额外的信用

CCR-Terminate (请求类型 3)

在呼叫终止时发送,报告最终使用情况。

关键 AVPs:

  • CC-Request-Type: 3 (TERMINATION_REQUEST)
  • Used-Service-Unit: 总呼叫持续时间
  • Termination-Cause: 会话结束的原因

结果代码

代码名称描述OmniTAS 动作
2001DIAMETER_SUCCESS请求批准解析 AVPs,设置呼叫
4010DIAMETER_END_USER_SERVICE_DENIED服务拒绝给订阅者拒绝呼叫,返回 CALL_REJECTED
4012DIAMETER_CREDIT_LIMIT_REACHED信用不足拒绝呼叫,返回 OUTGOING_CALL_BARRED
5003DIAMETER_AUTHORIZATION_REJECTEDOCS 策略拒绝拒绝呼叫,记录错误
5xxx永久性故障OCS 配置或系统错误拒绝呼叫,记录错误

参考: RFC 6733 §7.13GPP TS 32.299

指标

Diameter 请求指标

指标: diameter_requests_total 类型: 计数器 描述: 应用程序和请求类型发送的总 Diameter 请求 标签:

  • application - Diameter 应用程序: ro (在线计费)
  • command - 请求类型: ccr
  • status - 结果: success, error, timeout

示例查询:

# CCR 成功率
sum(rate(diameter_requests_total{application="ro",command="ccr",status="success"}[5m]))
/ sum(rate(diameter_requests_total{application="ro",command="ccr"}[5m]))

# CCR 超时率
rate(diameter_requests_total{application="ro",command="ccr",status="timeout"}[5m])

Diameter 响应指标

指标: diameter_responses_total 类型: 计数器 描述: 根据结果代码接收的 Diameter 响应 标签:

  • application - ro
  • command - ccr
  • result_code - Diameter 结果代码 (2001, 4012, 等)

示例查询:

# 按结果代码的响应
sum by (result_code) (rate(diameter_responses_total{application="ro"}[5m]))

# 信用限制拒绝 (4012)
rate(diameter_responses_total{application="ro",result_code="4012"}[5m])

OCS 授权指标

指标: ocs_authorizations_total 类型: 计数器 描述: OCS 授权尝试和结果 标签:

  • result - success, nocredit, timeout, error
  • skipped - true 如果通过正则表达式绕过,false 否则

示例查询:

# 授权成功率(不包括跳过的)
sum(rate(ocs_authorizations_total{result="success",skipped="false"}[5m]))
/ sum(rate(ocs_authorizations_total{skipped="false"}[5m]))

# 无信用拒绝
rate(ocs_authorizations_total{result="nocredit"}[5m])

Diameter 持续时间指标

指标: diameter_request_duration_seconds 类型: 直方图 描述: Diameter 请求的往返时间 标签:

  • application - ro
  • command - ccr
  • status - success, error, timeout

示例查询:

# CCR 延迟的第 95 百分位
histogram_quantile(0.95,
sum(rate(diameter_request_duration_seconds_bucket{application="ro"}[5m])) by (le)
)

# 按状态的平均延迟
avg(rate(diameter_request_duration_seconds_sum{application="ro"}[5m]))
by (status)
/ avg(rate(diameter_request_duration_seconds_count{application="ro"}[5m]))
by (status)

故障排除

FreeSWITCH 中未找到 AVP 变量

症状:

  • FreeSWITCH 拨号计划无法访问 ${CCA.Service-Information.*} 变量
  • 变量显示为空或未定义

可���原因:

  1. OCS 在 CCA 中未返回服务信息 AVPs
  2. AVP 解析因意外结构失败
  3. 变量未导出到 FreeSWITCH 通道

解决方案:

  1. 验证 OCS 响应包含 AVPs

    检查 OmniTAS 日志中的 CCA 消息:

    [debug] 信用控制应答: {:diameter_packet, ...}
    [debug] 解析的 AVP 变量: %{
    "CCA.Service-Information.Carrier-Select-Routing-Information" => "1408",
    "CCA.Service-Information.Alternate-Charged-Party-Address" => "NickTest"
    }

    如果 "解析的 AVP 变量" 为空 %{},则 OCS 未返回预期的 AVPs。

  2. 检查 AVP 解析错误

    查找日志中的警告:

    [warning] 收到另一种类型的回复: {...}

    这表明 AVP 结构与预期格式不匹配。检查 Diameter 数据包结构。

  3. 验证 FreeSWITCH 变量导出

    在 FreeSWITCH 控制台或 ESL 中:

    freeswitch> uuid_dump <call-uuid>

    查找带有 variable_ 前缀和 CCA. 的变量:

    variable_CCA.Service-Information.Carrier-Select-Routing-Information: 1408
    variable_CCA.Service-Information.Alternate-Charged-Party-Address: NickTest
    variable_CCA.Auth-Application-Id: 4
    variable_CCA.Result-Code: 2001

    注意: FreeSWITCH 保留变量名称中的点和连字符。它们在拨号计划中正常工作:

    <action application="log" data="运营商: ${CCA.Service-Information.Carrier-Select-Routing-Information}"/>

呼叫被拒绝,错误为 "unhandled"

症状:

  • 日志显示: [warning] 无法授权呼叫: :unhandled
  • 有效的 CCA 响应 (结果代码 2001) 被拒绝
  • 尽管 OCS 批准,呼叫仍然失败

可能原因:

  • CCA 消息结构与预期模式不匹配
  • 供应商特定的 AVPs 在意外位置
  • AVP 位置索引不匹配

解决方案:

这是最近版本修复的已知问题。确保您正在运行当前版本。

以前的行为: 模式匹配要求:

  • 授予服务单元 AVP 必须在位置 7
  • 空的供应商特定 AVP 列表 []

当前行为: 模式匹配接受:

  • 授予服务单元 AVP 在任何位置
  • 非空的供应商特定 AVP 列表

如果问题仍然存在:

  1. 捕获 CCA 数据包结构的日志
  2. 检查 AVPs 是否符合预期的 Diameter 格式
  3. 验证结果代码为 2001

OCS 所有请求超时

症状:

  • 所有 CCR 请求超时
  • 日志显示: [debug] 收到授权响应: {:error, :timeout}
  • 5 秒内未收到 CCA

可能原因:

  • 与 OCS/DRA 的网络连接问题
  • 防火墙阻止 Diameter 端口 (3868)
  • destination_realmdestination_host 不正确
  • OCS 未对请求做出响应

解决方案:

  1. 验证网络连接

    测试与 OCS 的 TCP 连接:

    telnet ocs.example.com 3868

    应成功连接。如果连接被拒绝或超时,请检查防火墙规则。

  2. 检查 Diameter 配置

    验证 destination_realm 是否与 OCS 配置匹配:

    config :tas, :diameter,
    destination_realm: "epc.mnc380.mcc313.3gppnetwork.org" # 必须与 OCS 领域匹配
  3. 查看 OCS 日志

    检查 OCS 是否接收到 CCR 消息。如果 OCS 收到请求但未响应:

    • 验证 OmniTAS 的 origin_host 是否被 OCS 识别
    • 检查 OCS 对等方配置是否允许来自 OmniTAS 的连接
    • 验证服务上下文 ID 和应用程序 ID 是否与 OCS 预期匹配

信用耗尽未挂断呼叫

症状:

  • 呼叫继续超出授予的信用时间
  • allocated_time 到期时未自动挂断
  • schedule_hangup_auth 启用但未生效

可能原因:

  • FreeSWITCH 计划挂断未配置
  • schedule_hangup_authfalse
  • 呼叫状态未正确跟踪

解决方案:

  1. 验证配置

    确保启用 schedule_hangup_auth

    config :tas, :online_charging,
    schedule_hangup_auth: true
  2. 检查 FreeSWITCH ESL 连接

    验证 OmniTAS 是否可以向 FreeSWITCH 发送命令:

    [debug] 调度挂断响应: {:ok, "+OK"}

    如果出现错误或没有响应,请检查 FreeSWITCH 事件套接字配置。

  3. 监控呼叫状态

    检查呼叫 UUID 是否在呼叫状态中跟踪:

    [debug] 为呼叫设置计划挂断,600 秒后

    如果未找到 UUID,呼叫状态跟踪可能存在问题。

跳过的正则表达式未绕过 OCS

症状:

  • 紧急呼叫 (911, 000) 仍然通过 OCS 授权
  • 匹配 skipped_regex 模式的号码未被绕过
  • 紧急呼叫延迟

可能原因:

  • 正则表达式模式语法错误
  • 目标号码格式不匹配
  • 正则表达式未正确转义

解决方案:

  1. 验证正则表达式模式

    测试正则表达式编译:

    Regex.compile("^911$")  # 应返回 {:ok, ~r/^911$/}

    常见错误:

    • 缺少锚点:使用 ^911$ 而不是 911
    • 转义:使用 \* 表示字面星号,而不是 \*
  2. 检查号码格式

    验证目标号码格式是否与模式匹配:

    [debug] 检查拨打的号码 "911" 是否匹配跳过的正则表达式...

    如果号码格式为 "+1911",但模式为 "^911$",则不会匹配。

  3. 示例模式

    config :tas, :online_charging,
    skipped_regex: [
    "^911$", # 美国紧急
    "^000$", # 澳大利亚紧急
    "^112$", # 国际紧急
    "^\*86$", # 语音信箱(转义星号)
    "^1?800\d{7}$" # 免费电话
    ]

参考

3GPP 规范

规范标题相关章节
TS 32.299Diameter 计费应用§6.3 (Ro 接口), §7.2 (AVP 定义)
TS 32.240计费架构和原则§5 (在线计费)
TS 29.229Cx 和 Dx 接口服务信息 AVP 在 IMS 中的使用

IETF RFCs

RFC标题相关章节
RFC 6733Diameter 基础协议§3 (协议概述), §7 (错误处理)
RFC 4006Diameter 信用控制应用§8 (信用控制消息)

AVP 代码参考

在 OCS 集成中使用的常见 AVPs:

AVP 名称代码供应商 ID类型描述
Session-Id2630UTF8String唯一会话标识符
Auth-Application-Id2580Unsigned32Diameter 应用程序 ID (4 ��� CC)
CC-Request-Type4160枚举1=初始,2=更新,3=终止
CC-Request-Number4150Unsigned32序列号
Result-Code2680Unsigned32请求结果 (2001=成功)
Granted-Service-Unit4310分组分配的信用
CC-Time4200Unsigned32以秒为单位的时间配额
Service-Information87310415分组3GPP 特定的服务数据
IMS-Information87610415分组IMS 计费信息
Carrier-Select-Routing-Information202310415UTF8String运营商路由代码
Alternate-Charged-Party-Address128010415UTF8String计费方标识符

供应商 ID 10415 = 3GPP

FreeSWITCH 通道变量

所有提取的 AVP 数据作为 FreeSWITCH 通道变量可用:

变量名称来源示例值描述
${allocated_time}授予服务单元 / CC-时间600以秒为单位的分配时间
${CCA.Session-Id}Session-Id AVPomni-as01.epc...;1769299669873;325e2f2eDiameter 会话标识符
${CCA.Result-Code}Result-Code AVP2001CCA 结果 (2001 = 成功)
${CCA.Auth-Application-Id}Auth-Application-Id AVP4Diameter 应用程序 (4 = CC)
${CCA.CC-Request-Type}CC-Request-Type AVP1请求类型 (1=初始)
${CCA.CC-Request-Number}CC-Request-Number AVP1序列号
${CCA.CC-Time}CC-时间 AVP(如果存在)600授予的时间配额
${CCA.Origin-Host}Origin-Host AVPocs01.epc.mnc380.mcc313.3gppnetwork.orgOCS 主机标识符
${CCA.Origin-Realm}Origin-Realm AVPepc.mnc380.mcc313.3gppnetwork.orgOCS 领域
${CCA.Service-Information.Carrier-Select-Routing-Information}Service-Information → Carrier-Select-Routing-Information1408来自 OCS 的运营商路由代码
${CCA.Service-Information.Alternate-Charged-Party-Address}Service-Information → Alternate-Charged-Party-AddressNickTest替代计费方

变量格式:

  • 所有 CCA AVPs 使用前缀 CCA.
  • 嵌套 AVPs 使用点符号表示:CCA.Parent.Child
  • 变量名称中的点和连字符被保留
  • 在 uuid_dump 中,变量以 variable_ 前缀出现

示例 uuid_dump 输出:

variable_allocated_time: 600
variable_CCA.Service-Information.Carrier-Select-Routing-Information: 1408
variable_CCA.Service-Information.Alternate-Charged-Party-Address: NickTest
variable_CCA.Result-Code: 2001