You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过FreeSWITCH Lua API获取通道呼叫状态?

问题原因分析与解决方案

问题1:事件监听获取状态失败的原因

  1. 事件范围过广:你监听了all类型的事件,但并非所有FreeSWITCH事件都包含Channel-Call-State头部(比如系统心跳、模块加载类事件),这类事件调用getHeader自然返回nil,导致打印失败。
  2. 未过滤目标呼叫:即使是通道相关事件,也可能来自其他呼叫,必须通过Channel-UUID头部筛选出当前目标UUID的事件,否则会拿到无关呼叫的状态或空值。
  3. 拼写笔误(潜在问题):代码中EventComsumer是拼写错误,正确应为EventConsumer,若实际运行时未修正,会导致事件消费者创建失败。

问题2:通过API命令获取状态提前返回的原因

  1. API方法名错误:FreeSWITCH Lua API的正确方法名是executeString,而非execute_string,错误方法名会导致调用失败。
  2. 命令格式错误:eval命令的UUID变量引用格式错误,正确格式应为${uuid:<uuid> Channel-Call-State},更推荐使用uuid_getvar命令直接获取通道变量。
  3. 时机不匹配:
    • 若originate使用默认同步模式(阻塞直到呼叫结束),返回时通道已被销毁,此时获取状态必然为空;
    • 若为异步模式,若立即执行获取命令,通道可能还未创建完成,也会提前返回空值。

正确获取呼叫状态的实现方法

方式一:事件监听(推荐,实时可靠)

通过监听CHANNEL_CALL_STATE事件,过滤目标UUID的事件,可实时捕获振铃、接通、忙线、拥塞、挂断等状态,且能准确判断CDR生成时机(呼叫挂断后CDR即就绪)。

api = freeswitch.API()
uuid = api:executeString("create_uuid")
-- 异步发起呼叫,避免阻塞主线程
dialstr = "{uuid=" .. uuid .. ",caller_id_number=" .. callerId .. ",async=true}user/1000"
api:execute("originate", dialstr)

-- 仅监听呼叫状态变更事件,减少无效处理
con = freeswitch.EventConsumer("CHANNEL_CALL_STATE")
local check = true
-- 定义需要关注的状态
local target_states = {["RINGING"]=true, ["ACTIVE"]=true, ["BUSY"]=true, ["CONGESTION"]=true, ["HANGUP"]=true}

while check do
    -- 1秒超时,避免无限阻塞
    local event = con:pop(1000)
    if not event then
        -- 超时后检查通道是否存在,不存在则退出循环
        local exists = api:executeString("uuid_exists " .. uuid)
        if exists == "false" then
            check = false
            print("通道已销毁,呼叫结束")
        end
        goto continue
    end

    -- 过滤当前目标UUID的事件
    local event_uuid = event:getHeader("Channel-UUID")
    if event_uuid ~= uuid then
        goto continue
    end

    local event_state = event:getHeader("Channel-Call-State")
    print("当前呼叫状态:", event_state)

    -- 检测到挂断状态时退出,此时CDR已生成
    if event_state == "HANGUP" then
        check = false
        print("呼叫结束,可访问CDR")
    end

    ::continue::
end

方式二:轮询获取通道变量

若无需实时监听,可通过uuid_getvar命令定期轮询状态:

api = freeswitch.API()
uuid = api:executeString("create_uuid")
-- 异步发起呼叫
dialstr = "{uuid=" .. uuid .. ",caller_id_number=" .. callerId .. ",async=true}user/1000"
api:execute("originate", dialstr)

local check = true
while check do
    -- 先检查通道是否存在
    local exists = api:executeString("uuid_exists " .. uuid)
    if exists == "false" then
        check = false
        print("呼叫结束,可访问CDR")
        break
    end

    -- 获取当前呼叫状态
    local state = api:executeString("uuid_getvar " .. uuid .. " Channel-Call-State")
    if state ~= "" then
        print("当前呼叫状态:", state)
        -- 检测到挂断状态时退出
        if state == "HANGUP" then
            check = false
        end
    end

    -- 每隔1秒轮询一次
    freeswitch.msleep(1000)
end

内容的提问来源于stack exchange,提问作者scharrua

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 15:44:53