如何通过FreeSWITCH Lua API获取通道呼叫状态?
问题原因分析与解决方案
问题1:事件监听获取状态失败的原因
- 事件范围过广:你监听了
all类型的事件,但并非所有FreeSWITCH事件都包含Channel-Call-State头部(比如系统心跳、模块加载类事件),这类事件调用getHeader自然返回nil,导致打印失败。 - 未过滤目标呼叫:即使是通道相关事件,也可能来自其他呼叫,必须通过
Channel-UUID头部筛选出当前目标UUID的事件,否则会拿到无关呼叫的状态或空值。 - 拼写笔误(潜在问题):代码中
EventComsumer是拼写错误,正确应为EventConsumer,若实际运行时未修正,会导致事件消费者创建失败。
问题2:通过API命令获取状态提前返回的原因
- API方法名错误:FreeSWITCH Lua API的正确方法名是
executeString,而非execute_string,错误方法名会导致调用失败。 - 命令格式错误:
eval命令的UUID变量引用格式错误,正确格式应为${uuid:<uuid> Channel-Call-State},更推荐使用uuid_getvar命令直接获取通道变量。 - 时机不匹配:
- 若
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
相关产品推荐
相关产品推荐

