local cjson = require "cjson";
local param = "{}"

api = freeswitch.API()
local sys_record_path = "/home/lcc_media";
local sys_lua_path = "/home/lua";

function logN(c)
    if type(c) == "string" then
        freeswitch.consoleLog("NOTICE", c.."\n");
    end
end

function logI(c)
    if type(c) == "string" then
        freeswitch.consoleLog("INFO", c.."\n");
    end
end

function logD(c)
    if type(c) == "string" then
        freeswitch.consoleLog("DEBUG", c.."\n");
    end
end

function logW(c)
    if type(c) == "string" then
        freeswitch.consoleLog("WARNING", c.."\n");
    end
end

function logE(c)
    if type(c) == "string" then
        freeswitch.consoleLog("ERR", c.."\n");
    end
end

function string_split(target, sep)
	if target == nil then return {} end
	local sep, fields = sep or ":", {}
	local pattern = "([^"..sep.."]+)"
	target:gsub(pattern, function(c) table.insert(fields, c) end)
	return fields
end

function respon(c)
    if c then
        if c == "close" then
            stream:write(c);
            return;
        end
        stream:write("HTTP/1.1 200 OK\r\n");
        stream:write("Content-Type: application/json\r\n");
        stream:write("\r\n");
        stream:write(c.."\n");
        logD(c);
    end
end

function respon404()
    stream:write("HTTP/1.1 404 Bad Request\r\n");
	stream:write("Content-Length: 0\r\n\r\n");
end

function check_param_and_respon(msg, key)
    local rsp = {};
    rsp.result = false;
    if  msg == nil then
        rsp.msg = "参数解析失败";
        respon(cjson.encode(rsp));
        return false;
    end

    if key == nil then
        return true;
    end

    if msg[key] == nil then
        rsp.msg = key.." is null";
        respon(cjson.encode(rsp));
        return false;
    end

    return true;
end

function set_partner_var(session, key, value)
    if session and key and value then
        local partner_uuid = session:getVariable("signal_bond") or session:getVariable("originate_signal_bond");

        if partner_uuid then
            api:execute("uuid_setvar", partner_uuid.." "..key.." "..value);
        end
    end
end

function get_partner_uuid(uuid)
    if type(uuid) == "string" then
        local session = freeswitch.Session(uuid);
        return session:getVariable("signal_bond") or session:getVariable("originate_signal_bond");
    end
end

local req_method = env:getHeader("Request-Method");
local req_uri = env:getHeader("HTTP-Request-URI");
local req_content = env:getHeader("Request-Content");

if req_uri then
    -- 去除[/lcc_service_api/]
    method = string.sub(req_uri, 18);
end
logD("req_method:"..req_method..", req_content:"..req_content);

if req_content then
    if string.find(req_content, "{") then
        param = req_content;
    end
    -- local r = string.find(req_content, "{")
    -- if r then
    --     param = string.sub(req_content, r, -1);
    -- end
end 

local msg = cjson.decode(param);
local c = "";
local tmp = msg;

for k,v in pairs(tmp) do 
    local v_type = type(v);
    if v_type == "boolean" then
        if v then 
            v = "true";
        else
            v= "false"
        end
    elseif v_type == "userdata" then
        v = "nil";
        msg[k] = nil;
    end

    if c == "" then
        c = "["..k.."]= "..v;
    else
        c = c.."\n["..k.."]= "..v;
    end
end
logI("接口调用. ["..method.."]");
logN("参数\n"..c);

function main()
    if method then
        local func = _G[method];
        if func then
            func(param);
        else
            respon404();
            freeswitch.consoleLog("ERR", "没有该方法:["..method.."]\n");
        end 
    else
        respon404();
        freeswitch.consoleLog("ERR", "方法为空!\n");
    end
end

function originate_impl()

    if msg == nil then
        rsp.result = false;
        rsp.msg = "参数解析失败";
        respon(cjson.encode(rsp));
        return;
    end
    local rsp = {};
    -- 检查参数
    if msg.req_id == nil then
        rsp.result = false;
        rsp.msg = "req_id is null";
        respon(cjson.encode(rsp));
        return;
    end

    if msg.company_code == nil then
        rsp.result = false;
        rsp.msg = "company_code is null";
        respon(cjson.encode(rsp));
        return;
    end

    if msg.service_code == nil then
        rsp.result = false;
        rsp.msg = "service_code is null";
        respon(cjson.encode(rsp));
        return;
    end
    local gateway_id = msg.gateway_id;
    if gateway_id == nil then 
        rsp.result = false;
        rsp.msg = "gateway_id is null";
        respon(cjson.encode(rsp));
        return;
    end

    local uuid = msg.ori_uuid or api:execute("create_uuid");
    local lcc_cdr_id = msg.lcc_cdr_id or api:execute("create_uuid");

    local ori_param = {};
    ori_param.origination_uuid = uuid;
    ori_param.origination_caller_id_number = msg.display_number or msg.caller_number;
    ori_param.origination_caller_id_name = msg.display_number or msg.caller_number;
    ori_param.absolute_codec_string = "PCMA";

    ori_param.hangup_after_bridge = "false";
    -- ori_param.park_after_bridge = "true"; -- 这样会导致咨询c坐席，c坐席接听后挂机，触发a路也挂机。
    -- 分辨率暂不支持
    ori_param.call_timeout = msg.max_call_time or 8*3600;
    ori_param.originate_timeout = msg.max_ring_time or 60;
    ori_param.lcc_acd_server = freeswitch.getGlobalVariable("server_name");
    ori_param.lcc_company_code = msg.company_code;
    ori_param.lcc_service_code = msg.service_code;
    ori_param.lcc_caller_number = ori_param.origination_caller_id_number;
    ori_param.lcc_callee_number = msg.callee_number;
    ori_param.lcc_out_line = msg.out_line;
    ori_param.lcc_cdr_id = lcc_cdr_id;
    ori_param.execute_on_lcc_negotiate_sdp = "'lua lcc_negotiate_sdp.lua'";

    ori_param.lcc_audio_media_flow = "sendrecv";
    ori_param.lcc_video_media_flow = "inactive";
    ori_param.lcc_first_video_media_flow = "inactive";

    ori_param.rtp_force_video_fmtp = "profile-level-id=42C01E;packetization-mode=1;max-br=1200;max-mbps=108000;max-fs=3600";
    ori_param.rtp_force_video_pt = "114";
    ori_param.rtp_force_video_framerate = "12";
    ori_param.rtp_force_video_as = "1200";

    local default_suffix = "mp3";
    -- local limit_media = "audio";
    if msg.video ~= nil and msg.video ~= 0 then
        -- limit_media = "video";
        -- ori_param.absolute_codec_string = "'^^:PCMA:H264:VP8:VP9'";
        ori_param.absolute_codec_string = "'^^:PCMA:H264'";

        if msg.video == 1 then
            ori_param.lcc_video_media_flow = "sendonly";
            ori_param.lcc_first_video_media_flow = "sendonly";
            ori_param.lcc_origination_video_mode = "sendonly";
        elseif msg.video == 2 then
            ori_param.lcc_video_media_flow = "recvonly";
            ori_param.lcc_first_video_media_flow = "recvonly";
            ori_param.lcc_origination_video_mode = "recvonly";
        else
            ori_param.lcc_video_media_flow = "sendrecv";
            ori_param.lcc_first_video_media_flow = "sendrecv";
        end
        -- if msg.out_line == 1 then
        --     ori_param.rtp_force_video_fmtp = "profile-level-id=42C01E;packetization-mode=1;max-br=1200;max-mbps=108000;max-fs=3600";
        --     ori_param.rtp_force_video_pt = "114";
        --     ori_param.rtp_force_video_framerate = "15";
        --     ori_param.rtp_force_video_as = "1200";
        -- else
        --     ori_param.rtp_force_video_fmtp = "profile-level-id=42C01E;packetization-mode=1;max-br=1200;max-mbps=108000;max-fs=3600";
        --     ori_param.rtp_force_video_pt = "114";
        --     ori_param.rtp_force_video_framerate = "15";
        --     ori_param.rtp_force_video_as = "1200";
        -- end
    end
    -- 并发统计
    -- local server_id = freeswitch.getGlobalVariable("server_name");
    -- ori_param.execute_on_originate_limit = "'limit lcc_hiredis default "..limit_media.."_"..msg.company_code.."/base:call_"..server_id.." -'";
    ori_param.limit_ignore_transfer = "true";
    ori_param.lcc_last_dialplan_hangup = "false";
    
    if msg.is_ws == 1 then
        ori_param.media_webrtc = "true";
        ori_param.rtcp_audio_interval_msec = "1000";
    end

    -- 语音是否加密
    if msg.rtp_secure_media then
        ori_param.rtp_secure_media = "true";
    end

    -- 临时处理
    if msg.out_line == 1 then
        -- 添加da2
        ori_param.da2_param_autohangup = "false";
        ori_param.ignore_early_media = "false";
        ori_param.execute_on_media_da2 ="start_da2";

        if msg.da2_auto_hangup == true then
            ori_param.da2_param_autohangup = "true";
        end

        -- 是否指定路由
        if msg.route_id and type(msg.route_id) ~= "userdata" then
            ori_param["sip_h_X-LCC-ROUTE-ID"] = msg.route_id;
        end
        -- 是否指定媒体ip
        if msg.media_ip == "local" then
            local ip = freeswitch.getGlobalVariable("lcc_ip_v4");
            if ip then
                ori_param.rtp_adv_audio_ip = ip;
                ori_param.rtp_adv_video_ip = ip;
            end
        elseif msg.media_ip == "nat" then
            local ip = freeswitch.getGlobalVariable("lcc_ip_v4_nat");
            if ip then
                ori_param.rtp_adv_audio_ip = ip;
                ori_param.rtp_adv_video_ip = ip;
            end
        end
    end

    -- 排队接口
    if msg.service_url and msg.service_url ~= "" then
        ori_param.lcc_curl_server = "'"..msg.service_url.."'";
    end

    -- 录制相关
    if msg.record_start and msg.record_start ~= "NONE" then
        local record_suffix = msg.record_suffix or default_suffix;

        -- record_suffix = "mp4";
        
        local record = false;
        local time = os.time();
        local data_path = os.date("%Y/%m/%Y-%m-%d", time);
        local record_path = sys_record_path.."/"..msg.company_code.."/"..msg.service_code.."/"..data_path.."/"..uuid.."."..record_suffix;

        if msg.record_start == "MEDIA" then
            ori_param.execute_on_media_ori= "'record_session "..record_path.."'";
            record= true;
        elseif msg.record_start == "ANSWER" then
            ori_param.execute_on_answer_ori = "'record_session "..record_path.."'";
            record= true;
        end

        if  record then
            ori_param.lcc_record_file = record_path;
            ori_param.lcc_record_date = os.date("%Y-%m-%d", time);

            if record_suffix == "mp4" then
                if msg.record_contact ~= nil and msg.record_contact then
                    arg.record_concat_video = "true";
                end
            else
                if msg.record_contact ~= nil and msg.record_contact == false then
                    arg.RECORD_READ_ONLY = "true";
                end
            end
            -- 是否立体声录制
            if msg.is_stereo then
                ori_param.RECORD_STEREO = "true";
            end
        end
    end
    -- 透传通道变量
    ori_param.lcc_ori_user_data = msg.ori_user_data;

    local cmd = "sofia/gateway/"..gateway_id.."/"..msg.callee_number;

    -- 是否长通到另外一台acd
    if msg.lcc_always_acd then
        ori_param.media_webrtc = "false";
        local lcc_always_port = freeswitch.getGlobalVariable("lcc_always_port") or "10676";
        cmd = "sofia/agent/"..msg.callee_number.."@"..msg.lcc_always_acd..":"..lcc_always_port;
        -- 将真实呼叫uuid放sip头
        ori_param["sip_h_LCC-ALWAYS-UUID"] = msg.lcc_always_uuid;
    end

    -- 其他通道变量有的话就设置进去
    ori_param.lcc_sub_uuid = msg.lcc_sub_uuid;          -- 【长通】虚拟的uuid
    ori_param.lcc_always_call = msg.lcc_always_call;    -- 【长通】是否长通呼叫

    local ori_param_string, ori_param_string2 = msg_print(ori_param);

    logI("外呼参数:");
    logN("\n"..ori_param_string2);
    logI("外呼命令:"..cmd);
    return ori_param_string..cmd, uuid;
end

function always_answer_handle() 
    -- 新加长通分机逻辑(内线分机)
    if (msg.out_line == nil or msg.out_line == 0) and msg.is_always_call == 1 then 
        local sub_uuid = msg.ori_uuid;
        if sub_uuid == nil then
            -- 如果没有指定uuid，预先生成一个
            sub_uuid = api:execute("create_uuid");
        end
        local log_tag = "[always]"..msg.callee_number.." "..sub_uuid;
        -- 1.查询redis，获取分机是否有在通话
        local sub_call = false;
        local ret = api:execute("lcc_hiredis_raw", "default GET base:always:"..msg.callee_number);
        if ret ~= "" and (not string.find(ret, "ERR")) then
            -- 解析uuid和acd的ip地址[uuid_ip]
            local info  = string_split(ret, "_");
            local uuid = info[1];
            local acd_ip = info[2] or "";
            local lcoal_ip_v4 = freeswitch.getGlobalVariable("lcc_ip_v4");
            logI(log_tag.." 所在的ACD: "..acd_ip);
            if lcoal_ip_v4 == acd_ip then
                -- 通话在当前acd上，虚拟外呼和接通事件，然后bridge
                local session = freeswitch.Session(uuid);
                local session_state = session:getState();
                if session_state ~= "ERROR" then
                    logI(log_tag.." 长通在当前ACD，直接虚拟呼叫事件.");
                    local event_data = {};
                    event_data.caller_number = msg.caller_number;
                    event_data.callee_number = msg.callee_number;

                    -- 先返回成功
                    local rsp = {};
                    rsp.req_id = msg.req_id;
                    rsp.uuid = sub_uuid;
                    rsp.result = true;
                    rsp.msg = "success";
                    respon(cjson.encode(rsp));
                    -- 先虚拟外呼事件
                    event_data.status = "INVITE";
                    virtually_call_event(sub_uuid, "call_status", event_data);

                    -- 获取session的状态，只有park状态可用
                    if session_state == "CS_RESET" then
                        logI(log_tag.." 当前呼叫为RESET状态，给他置为PARK状态，不然后续无法bridge.");
                        api:execute("uuid_park", uuid);
                        api:execute("msleep", "200");
                        session_state = session:getState();
                        session:setVariable("lcc_sub_uuid", nil);
                    end

                    -- 等待500ms，避免呼叫太快，导致的话务未断的情况
                    if session_state ~= "CS_PARK" then
                        logI(log_tag.." 当前呼叫为["..session_state.."]状态，等待500ms，避免呼叫太快，导致的话务未断的情况.");
                        api:execute("msleep", "500");
                        session_state = session:getState();
                    end

                    -- 话机当前已经有个话务在通话了虚拟一个挂断事件
                    if session_state ~= "CS_PARK" then
                        local signal_bond_uuid = session:getVariable("signal_bond") or "nil";
                        local cur_sub_uuid = session:getVariable("lcc_sub_uuid") or "nil";
                        logI(log_tag.." 当前话机已经在通话中["..signal_bond_uuid.."]，虚拟呼叫["..cur_sub_uuid.."].");
                        event_data.status = "HANGUP";
                        event_data.hangup_cause = "USER_BUSY";
                        event_data.channel_data = {};
                        virtually_call_event(sub_uuid, "call_status", event_data);
                        return 2;
                    end

                    -- 是否有绑定呼叫
                    local cur_sub_uuid = session:getVariable("lcc_sub_uuid");
                    if cur_sub_uuid then
                        logI(log_tag.." 长通分机已经被占用，虚拟呼叫["..cur_sub_uuid.."].");
                        event_data.status = "HANGUP";
                        event_data.hangup_cause = "USER_BUSY";
                        event_data.channel_data = {};
                        virtually_call_event(sub_uuid, "call_status", event_data);
                        return 2;
                    end

                    session:setVariable("lcc_sub_uuid", sub_uuid);
                    session:setVariable("lcc_cdr_id", api:execute("create_uuid"));
                    logI(log_tag.." 关联话机长通["..uuid.."].");

                    local server_id = freeswitch.getGlobalVariable("server_name");
                    -- 写入redis数据
                    -- a.虚拟呼叫和真实呼叫的映射关系
                    api:execute("lcc_hiredis_raw", "default SET base:sub_call:"..sub_uuid.." "..uuid.." ex "..(7*3600));
                    -- b.虚拟呼叫所在的acd信息
                    api:execute("lcc_hiredis_raw", "default SET base:call_loc:"..sub_uuid.." "..server_id.." ex "..(7*3600));

                    -- 虚拟接通事件
                    event_data.status = "ANSWER";
                    virtually_call_event(sub_uuid, "call_status", event_data);
                    return 1, uuid;
                end
                logW(log_tag.." 长通在当前ACD，session不存在，当成新的呼叫去处理.");
                -- 如果session不存在，那么当成新的呼叫去送
                sub_call = true;
            else
                -- 通话在其他acd上，话务送到其他acd上
                logW(log_tag.." 通话在其他acd上，话务送到其他acd上.");
                msg.lcc_always_acd = acd_ip;
                msg.lcc_always_uuid = uuid;
            end
        else
            sub_call = true;
        end

        if sub_call then
            -- 生成真实通话的uuid
            -- msg.ori_uuid = api:execute("create_uuid");
            msg.ori_uuid = "always-"..string.sub(api:execute("create_uuid"), 8);
            -- 记录虚拟uuid
            msg.lcc_sub_uuid = sub_uuid;
            msg.lcc_always_call = "true";
            logN(log_tag.." 准备发起长通通话.");
            return 3;
        end
    end
    return 0;
end

function get_real_uuid(sub_uuid)
    local ret = api:execute("lcc_hiredis_raw", "default GET base:sub_call:"..sub_uuid);
    if ret == "" or string.find(ret, "ERR") then
        return sub_uuid;
    end
    return ret;
end

-- 虚拟通话事件
function virtually_call_event(uuid, name, data, event_queue_id)
    event_queue_id = event_queue_id or msg.service_code;
    local mq_msg = {};
    mq_msg.event = name;
    mq_msg.server_id = freeswitch.getGlobalVariable("server_name");
    mq_msg.uuid = uuid;
    mq_msg.company_code = msg.company_code;
    mq_msg.service_code = msg.service_code;
    mq_msg.timestamp = os.time()*1000;
    mq_msg.data = data or {};

    local json_text = cjson.encode(mq_msg);

    logN("send virtually "..(data.status or name).." event:"..uuid);
    api:execute("push_rocketmq_event", event_queue_id.." "..msg.company_code.." "..uuid.." "..json_text);
end

function msg_print(msg)
    local r = "";
    local r2 = "";
    for k, v in pairs(msg) do
        if v ~= nil then
            if r == "" then
                r = k.."="..v;
                r2 = "["..k.."]= "..v;
            else
                r = r..","..k.."="..v;
                r2 = r2.."\n["..k.."]= "..v;
            end
        end
    end
    r = "{"..r.."}"
    return r, r2;
end


-- 外呼接口
function originate(param)
    local result = always_answer_handle();
    if result == 1 or result == 2 then
        return;
    end

    local ori_cmd, uuid = originate_impl();
    if ori_cmd == nil then return end
    local server_id = freeswitch.getGlobalVariable("server_name");

    local rsp = {};
    rsp.req_id = msg.req_id;
    rsp.server_id = server_id;
    rsp.req_id = msg.req_id;
    rsp.uuid = uuid;
    rsp.result = true;
    rsp.msg = "success";
    respon(cjson.encode(rsp));
    respon("close");

    -- **WTF!!!不能这么用，会导致通话无声、接通秒挂？**
    -- local session = freeswitch.Session(ori_cmd);
    -- if session:ready() then
    --     session:execute("park");
    --     return;
    -- end
    local ret = api:execute("originate", ori_cmd.." &eval");
    if string.find(ret, "OK") then
        local limit_media = "audio";
        if msg.video == nil or msg.video ~= 0 then
            limit_media = "video";
        end
        -- local limit_cmd = "lcc_hiredis default "..limit_media.."_"..msg.company_code.."/base:call_"..server_id.." -";
        -- api:execute("uuid_limit", uuid.." "..limit_cmd);
    end
    session = freeswitch.Session(uuid);
    session:execute("lcc_read_frame");
    -- api:execute("uuid_park", uuid);
end

-- 挂机
function hangup(param)
    if check_param_and_respon(msg) == false then return end
    if check_param_and_respon(msg, "uuid") == false then return end
    
    logN("["..msg.uuid.."] hangup for "..(msg.hangup_cause or "NONE"));
    local ret = "";
    local real_uuid = get_real_uuid(msg.uuid);
    if msg.uuid ~= real_uuid then
        local session = freeswitch.Session(real_uuid);
        session:setVariable("lcc_sub_uuid", nil);
        -- 虚拟挂断事件
        local event_data = {};
        event_data.status = "HANGUP";
        event_data.hangup_cause = "NORMAL_CLEARING";
        event_data.channel_data = {};
        virtually_call_event(msg.uuid, "call_status", event_data);

        api:execute("lcc_hiredis_raw", "default DEL base:sub_call:"..msg.uuid);
        api:execute("lcc_hiredis_raw", "default DEL base:call_loc:"..msg.uuid);      
    else
        if not msg.hangup_other then
            local partner_uuid = get_partner_uuid(real_uuid);
            if partner_uuid then 
                api:execute("uuid_setvar", partner_uuid.." park_after_bridge true");
                api:execute("uuid_setvar", partner_uuid.." park_timeout 1");
            end
        end
        ret = api:execute("uuid_kill", real_uuid);
    end

    local rsp = {};
    rsp.req_id = msg.req_id;
    if msg.hangup_other then
        local partner_uuid = get_partner_uuid(real_uuid);
        if partner_uuid then 
            ret = api:execute("uuid_kill", partner_uuid);
        end
    end

    if string.find(ret, "ERR") then
        rsp.result = false;
        rsp.msg = "通话不存在:"..ret;
        respon(cjson.encode(rsp));
        return;
    end
    rsp.result = true;
    rsp.msg = "success";
    respon(cjson.encode(rsp));
end

-- 媒体切换
function media_reneg(param)
    if check_param_and_respon(msg) == false then return end
    if check_param_and_respon(msg, "uuid") == false then return end
    if check_param_and_respon(msg, "audio") == false then return end
    if check_param_and_respon(msg, "video") == false then return end
    local media = "=PCMA@8000h@20i@1c";
    if msg.video ~= 0 then
        -- media = media..",H264@90000h,VP8,VP9";
        media = media..",H264@90000h";
    end
    local rsp = {};
    rsp.req_id = msg.req_id;

    local real_uuid = get_real_uuid(msg.uuid);
    if msg.uuid ~= real_uuid then
        msg.uuid = real_uuid;
    end

    local ret = api:execute("uuid_media_reneg", msg.uuid.." "..media);

    if string.find(ret, "ERR") then
        rsp.result = false;
        rsp.msg = "切换失败:"..ret;
        respon(cjson.encode(rsp));
        return;
    else
        api:execute("uuid_setvar", msg.uuid.." lcc_media_reneging true");
        api:execute("uuid_setvar", msg.uuid.." lcc_media_reneg_req_id "..msg.req_id);
        if msg.reneg_other or msg.reneg_other == nil then
            local partner_uuid = get_partner_uuid(msg.uuid);
            if partner_uuid then
                local partner_video = api:execute("uuid_getvar", partner_uuid.." lcc_video_media_flow");
                local video_map = {sendrecv = 3, recvonly = 2, sendonly = 1, inactive = 0};
                partner_video = video_map[partner_video];
                -- 如果已经是对方要求切换的媒体，则不切换，避免信令异常(运营商会变成呼叫等待)
                if msg.video ~= partner_video then
                    ret = api:execute("uuid_media_reneg", partner_uuid.." "..media);
                    if string.find(ret, "OK") then
                        api:execute("uuid_setvar", partner_uuid.." lcc_media_reneging true");
                        api:execute("uuid_setvar", partner_uuid.." lcc_media_reneg_req_id "..msg.req_id);
                    end
                end
            end
        end
    end
    rsp.req_id = msg.req_id;
    rsp.result = true;
    rsp.msg = "success";
    respon(cjson.encode(rsp));
end
-- uuid_media_reneg fa666876-8e23-40c5-b15b-f50af7163791 =PCMA@8000h@20i@1c
-- uuid_media_reneg e7bbaccd-99db-4d12-bed1-8fe7dbf7a3f9 =PCMA@8000h@20i@1c,H264@90000h
-- 桥接
function bridge(param)
    if check_param_and_respon(msg) == false then return end
    if check_param_and_respon(msg, "s_uuid") == false then return end
    if check_param_and_respon(msg, "d_uuid") == false then return end
    local rsp = {};
    rsp.req_id = msg.req_id;

    local real_uuid = get_real_uuid(msg.s_uuid);
    if msg.s_uuid ~= real_uuid then
        msg.s_uuid = real_uuid;
    end

    local real_uuid = get_real_uuid(msg.d_uuid);
    if msg.d_uuid ~= real_uuid then
        msg.d_uuid = real_uuid;
    end

    local lcc_conf_id = api:execute("uuid_getvar", msg.s_uuid.." lcc_conf_id");
    -- 说明已经在会议中，不需要再bridge了
    if lcc_conf_id ~= nil and lcc_conf_id ~= "_undef_" then
        rsp.result = true;
        rsp.msg = "success";
        respon(cjson.encode(rsp));
        return;
    end
    
    if true then
        local a_session = freeswitch.Session(msg.s_uuid);
        if a_session:getState() == "ERROR" then
            rsp.result = false;
            rsp.msg = "源通话不存在:"..msg.s_uuid;
            respon(cjson.encode(rsp));
            return;
        end
        local b_session = freeswitch.Session(msg.d_uuid);
        if b_session:getState() == "ERROR" then
            rsp.result = false;
            rsp.msg = "目标通话不存在:"..msg.d_uuid;
            respon(cjson.encode(rsp));
            return;
        end 
        a_session:execute("lcc_unpark");
        b_session:execute("lcc_unpark");
        rsp.result = true;
        rsp.msg = "success";
        respon(cjson.encode(rsp))
        respon("close");
        api:execute("uuid_bridge", msg.s_uuid.." "..msg.d_uuid);
        --freeswitch.bridge(b_session, a_session);
        return;
    end

    local check = api:execute("uuid_exists", msg.s_uuid);
    if check == "false" then
        rsp.result = false;
        rsp.msg = "源通话不存在:"..msg.s_uuid;
        respon(cjson.encode(rsp));
        return;
    end

    check = api:execute("uuid_exists", msg.d_uuid);
    if check == "false" then
        rsp.result = false;
        rsp.msg = "目标通话不存在:"..msg.d_uuid;
        respon(cjson.encode(rsp));
        return;
    end

    rsp.req_id = msg.req_id;
    rsp.result = true;
    rsp.msg = "success";
    respon(cjson.encode(rsp))
    respon("close");
    api:execute("uuid_bridge", msg.s_uuid.." "..msg.d_uuid);
    -- if string.find(ret, "ERR") then
    --     rsp.result = false;
    --     rsp.msg = "通话不存在:"..ret;
    --     respon(cjson.encode(rsp));
    --     return;
    -- end
end

function call_bridge()
    if check_param_and_respon(msg, "s_uuid") == false then return end
    local real_s_uuid = get_real_uuid(msg.s_uuid);
    if real_s_uuid ~= "" then
        msg.s_uuid = real_s_uuid;
    end

    -- 获取A路lcc_cdr_id
    local lcc_cdr_id = api:execute("uuid_getvar", msg.s_uuid.." lcc_cdr_id");
    if lcc_cdr_id and (not string.find(lcc_cdr_id, "ERR")) then
        msg.lcc_cdr_id = lcc_cdr_id;
    end

    local result, uuid = always_answer_handle();
    -- 话机已经在通话
    if result == 2 then
        return;
    end

    -- 呼叫存在，直接bridge
    if result == 1 then
        ret = api:execute("uuid_bridge", msg.s_uuid.." "..uuid);
        return;
    end

    local ori_cmd, uuid = originate_impl();
    if ori_cmd == nil then return end
    -- logI("外呼命令. "..ori_cmd)
    local a_session = freeswitch.Session(msg.s_uuid);
    local rsp = {};
    rsp.req_id = msg.req_id;
    if a_session:getState() ~= "ERROR" then
        rsp.server_id = freeswitch.getGlobalVariable("server_name");
        rsp.req_id = msg.req_id;
        rsp.uuid = uuid;
        rsp.result = true;
        rsp.msg = "success";
        respon(cjson.encode(rsp));
        respon("close");

        -- 临时处理
        if 1 then
            a_session:execute("video_decode", "on");
        end

        if true then
            local limit_media = "audio";
            local server_id = freeswitch.getGlobalVariable("server_name");
            if msg.video == nil or msg.video ~= 0 then
                limit_media = "video";
            end
            -- 如果有放音的话就结束放音(有时候callbridge无法打断之前的放音(刚好放音结束的时候)，导致放音重叠)
            a_session:execute("lcc_playback", "stop");
            -- a_session:process_callback_result("stop");
            api:execute("msleep", "500");
            
            -- a_session:setVariable("ignore_early_media", "true");
            a_session:setVariable("ringback", "%(2000,4000,440.0,480.0)");
            -- 这样用媒体切换的时候视频为inactive???(已解决)
            -- a_session:execute("transfer", "lcc_bridge|"..ori_cmd.." xml lcc_service");
            a_session:execute("lcc_unpark");
            a_session:execute("lcc_bridge", ori_cmd);-- 这样用有问题，会没有声音????????
            -- local limit_cmd = "lcc_hiredis default "..limit_media.."_"..msg.company_code.."/base:call_"..server_id.." -";
            -- api:execute("uuid_limit", uuid.." "..limit_cmd);
            return;
        end

        --local ret = api:execute("originate", ori_cmd.." &park");-- 这样用会导致发起保持时无法给B路放音???????
        local ret = api:execute("originate", ori_cmd.." &wait_for_answer");-- 这样用会导致发起保持时无法给B路放音???????
        -- a_session:execute("bridge", ori_cmd);-- 这样用有问题，会没有声音????????

        if string.find(ret, "ERR") then
            rsp.result = false;
            rsp.msg = "呼叫失败:"..ret;
            respon(cjson.encode(rsp));
            return;
        else
            -- 呼叫并发统计
            local limit_media = "audio";
            local server_id = freeswitch.getGlobalVariable("server_name");
            if msg.video == nil or msg.video ~= 0 then
                limit_media = "video";
            end
            -- local limit_cmd = "lcc_hiredis default "..limit_media.."_"..msg.company_code.."/base:call_"..server_id.." -";
            -- api:execute("uuid_limit", uuid.." "..limit_cmd);

            ret = api:execute("uuid_bridge", msg.s_uuid.." "..uuid);
        end
    else
        rsp.result = false;
        rsp.msg = "通话不存在:"..msg.s_uuid;
        respon(cjson.encode(rsp));
        return;
    end
    
end

function answer(param)
    if check_param_and_respon(msg) == false then return end
    if check_param_and_respon(msg, "uuid") == false then return end

    -- local a_session = freeswitch.Session(msg.uuid);
    
    local ret = api:execute("uuid_answer", msg.uuid);
    local rsp = {};
    rsp.req_id = msg.req_id;
    if string.find(ret, "ERR") then
        rsp.result = false;
        rsp.msg = "通话不存在:"..ret;
        respon(cjson.encode(rsp));
        return;
    end
    rsp.req_id = msg.req_id;
    rsp.result = true;
    rsp.msg = "success";
    respon(cjson.encode(rsp));
end

function playback(param)
    if check_param_and_respon(msg) == false then return end
    if check_param_and_respon(msg, "uuid") == false then return end
    local real_uuid = get_real_uuid(msg.uuid);
    if msg.uuid ~= real_uuid then
        msg.uuid = real_uuid;
    end

    local a_session = freeswitch.Session(msg.uuid);
    local rsp = {};
    rsp.req_id = msg.req_id;

    if a_session:getState() ~= "ERROR" then
        local file = nil;
        if msg.file_name then
            file = msg.file_name;
        end

        if file == nil then
            if msg.text == nil or msg.text == ""  or msg.text == "'" or msg.text == "''" then
                rsp.result = false;
                rsp.msg = "text不能为空!";
                respon(cjson.encode(rsp));
                return;
            end
            file = "say:"..msg.text;

            if msg.engine and msg.voice then
                a_session:setVariable("tts_engine", msg.engine);
                a_session:setVariable("tts_voice", msg.voice);
            end
        else
            if string.find(file, "http") == nil and api:execute("file_exists", file) ~= "true" then
                rsp.result = false;
                rsp.msg = "文件不存在:"..file;
                respon(cjson.encode(rsp)); 
                return;
            end
        end
        rsp.result = true;
        rsp.msg = "success";
        respon(cjson.encode(rsp));
        respon("close");

        -- 看下是不是在会议里面
        local conf_id = a_session:getVariable("lcc_conf_id");
        local member_id = a_session:getVariable("conference_member_id");
        if conf_id ~= nil and member_id ~= nil then
            api:execute("conference", conf_id.." play "..file.." "..member_id);
            return;
        end

        local count = msg.count or "1";
        if count == 0 then
            count = -1;
        end

        local cmd = "+"..count.." "..file;
        local event = freeswitch.Event("CUSTOM", "lcc_service:play_start");
        event:addHeader("unique-id", msg.uuid);
        event:addHeader("Call-Direction", a_session:getVariable("direction"));
        event:addHeader("variable_lcc_company_code", a_session:getVariable("lcc_company_code"));
        event:addHeader("variable_lcc_service_code", a_session:getVariable("lcc_service_code"));
        event:addHeader("variable_lcc_caller_number", a_session:getVariable("lcc_caller_number"));
        event:addHeader("variable_lcc_callee_number", a_session:getVariable("lcc_callee_number"));
        event:addHeader("lcc_play_req_id", msg.req_id);
        event:fire();
        a_session:execute("lcc_playback", cmd);

        event = freeswitch.Event("CUSTOM", "lcc_service:play_end");
        event:addHeader("unique-id", msg.uuid);
        event:addHeader("Call-Direction", a_session:getVariable("direction"));
        event:addHeader("variable_lcc_company_code", a_session:getVariable("lcc_company_code"));
        event:addHeader("variable_lcc_service_code", a_session:getVariable("lcc_service_code"));
        event:addHeader("variable_lcc_caller_number", a_session:getVariable("lcc_caller_number"));
        event:addHeader("variable_lcc_callee_number", a_session:getVariable("lcc_callee_number"));
        event:addHeader("lcc_play_req_id", msg.req_id);
        event:fire();
        -- a_session:execute("loop_playback", cmd);
    else
        rsp.result = false;
        rsp.msg = "通话不存在:"..msg.uuid;
        respon(cjson.encode(rsp));
        return;
    end
end

function stop_play(param)
    if check_param_and_respon(msg) == false then return end
    if check_param_and_respon(msg, "uuid") == false then return end
    local real_uuid = get_real_uuid(msg.uuid);
    if msg.uuid ~= real_uuid then
        msg.uuid = real_uuid;
    end
    local a_session = freeswitch.Session(msg.uuid);
    local rsp = {};
    rsp.req_id = msg.req_id;
    if a_session:getState() ~= "ERROR" then
        -- api:execute("uuid_fileman", msg.uuid.." stop");
        -- a_session:execute("break", "all");
        a_session:execute("lcc_playback", "stop");
    else
        rsp.result = false;
        rsp.msg = "通话不存在:"..msg.uuid;
        respon(cjson.encode(rsp));
        return;
    end
    rsp.req_id = msg.req_id;
    rsp.result = true;
    rsp.msg = "success";
    respon(cjson.encode(rsp));
end

function play_and_get_digits(param)
    if check_param_and_respon(msg) == false then return end
    if check_param_and_respon(msg, "uuid") == false then return end
    local real_uuid = get_real_uuid(msg.uuid);
    if msg.uuid ~= real_uuid then
        msg.uuid = real_uuid;
    end

    local a_session = freeswitch.Session(msg.uuid);
    local rsp = {};
    rsp.req_id = msg.req_id;
    if a_session:getState() ~= "ERROR" then
        local file = msg.file_name;
        local invalid_file = msg.invalid_file_name;

        if file == nil then
            if msg.text == nil then
                rsp.result = false;
                rsp.msg = "file_name、text不能同时为空!";
                respon(cjson.encode(rsp));
                return;
            end
            file = "say:"..msg.file_name;
        end

        if invalid_file == nil then
            if msg.invalid_text == nil then
                rsp.result = false;
                rsp.msg = "invalid_file_name、invalid_text不能为空!";
                respon(cjson.encode(rsp));
                return;
            end
            invalid_file = "say:"..msg.invalid_text;
        end

        if msg.engine and msg.voice then
            session:setVariable("tts_engine", msg.engine);
            session:setVariable("tts_voice", msg.voice);
        end

        if invalid_file == "" then
            invalid_file = "silence_stream://100";
        end

        rsp.result = true;
        rsp.msg = "success";
        respon(cjson.encode(rsp));
        respon("close");
        local min = msg.min or 1;
        local max = msg.max or 1;
        local retry_times = msg.retry_times or 1;
        local loop = msg.loop or 1;
        local terminators = msg.terminators or "?";
        local timeout = msg.timeout or 5000;
        local digits_regex = msg.digits_regex or ".*";
        local digit_timeout = msg.digit_timeout or timeout;
        local cmd = min.." "..max.." "..retry_times.." "..timeout.." "..terminators.." "..file.." "..invalid_file.." lcc_digits_result "..digits_regex.." "..digit_timeout;

        a_session:execute("play_and_get_digits", cmd);
        -- a_session:execute("transfer", "play_and_get_digits|'"..cmd.."' xml lcc_service");

        local lcc_digits_result = a_session:getVariable("lcc_digits_result") or "";
        local lcc_digits_result_invalid = a_session:getVariable("lcc_digits_result_invalid" or "";
        local lcc_digits_read_result = a_session:getVariable("read_result");

        local event_queue_id = a_session:getVariable("lcc_event_queue_id");
        local company_code = a_session:getVariable("lcc_company_code");
        local service_code = a_session:getVariable("lcc_service_code");
        local caller_number = a_session:getVariable("lcc_caller_number");
        local callee_number = a_session:getVariable("lcc_callee_number");

        if event_queue_id == nil then 
            event_queue_id = service_code;
        end

        if lcc_digits_read_result == "timeout" then
            lcc_digits_read_result = "TIMEOUT";
        elseif lcc_digits_read_result == "success" then
            lcc_digits_read_result = "TERM_KEY";
        else
            lcc_digits_read_result = "NONE";
        end

        local data = {};
        data.req_id = msg.req_id;
        data.content = lcc_digits_result;
        data.caller_number = caller_number;
        data.callee_number = callee_number;
        data.end_reason = lcc_digits_read_result;

        local mq_msg = {};
        mq_msg.event = "digits_callback";
        mq_msg.server_id = freeswitch.getGlobalVariable("server_name");
        mq_msg.uuid = msg.uuid;
        mq_msg.company_code = company_code;
        mq_msg.service_code = service_code;
        mq_msg.timestamp = os.time()*1000;
        mq_msg.data = data;

        local json_text = cjson.encode(mq_msg);

        logN("send digits_callback event:"..msg.uuid);
        local rr = api:execute("push_rocketmq_event", event_queue_id.." "..company_code.." "..msg.uuid.." "..json_text);
    else
        rsp.result = false;
        rsp.msg = "通话不存在:"..msg.s_uuid;
        respon(cjson.encode(rsp));
        return;
    end
    
end

function send_dtmf(param)
    if check_param_and_respon(msg) == false then return end
    if check_param_and_respon(msg, "uuid") == false then return end
    if check_param_and_respon(msg, "content") == false then return end
    local rsp = {};
    rsp.req_id = msg.req_id;

    local real_uuid = get_real_uuid(msg.uuid);
    if msg.uuid ~= real_uuid then
        msg.uuid = real_uuid;
    end

    if false then
        local a_session = freeswitch.Session(msg.uuid);
        if a_session:getState() ~= "ERROR" then
        else
            rsp.result = false;
            rsp.msg = "通话不存在:"..ret;
            respon(cjson.encode(rsp));
            return;
        end

        local content = msg.content;
        if content == "#" then
            content = "hash";
        elseif content == "*" then
            content = "star";
        else
            content = tonumber(content);
            if content == nil then
                rsp.result = false;
                rsp.msg = "按键格式错误:"..msg.content;
                respon(cjson.encode(rsp));
                return;
            end
            content = content%10;
        end
        -- a_session:execute("send_dtmf", msg.content);
        api:execute("uuid_broadcast", msg.uuid.." $${sounds_dir}/snd_"..content..".wav both");
        -- a_session:execute("playback","/home/server/switch/freeswitch/sounds/snd_1.wav");
        rsp.req_id = msg.req_id;
        rsp.result = true;
        rsp.msg = "success";
        respon(cjson.encode(rsp));
        return;
    end
    local a_session = freeswitch.Session(msg.uuid);
    if a_session:getState() == "ERROR" then
        rsp.result = false;
        rsp.msg = "通话不存在:"..ret;
        respon(cjson.encode(rsp));
        return;
    end
    local lcc_out_line = a_session:getVariable("lcc_out_line");
    -- 如果是内部的满意度，那么就模拟收到按键
    if lcc_out_line and lcc_out_line ~= "1" then
        a_session:execute("queue_dtmf", msg.content);
    else
        a_session:execute("send_dtmf", msg.content);
    end
    
    -- local ret = api:execute("uuid_send_dtmf", msg.uuid.." "..msg.content);
    -- if string.find(ret, "ERR") then
    --     rsp.result = false;
    --     rsp.msg = "通话不存在:"..ret;
    --     respon(cjson.encode(rsp));
    --     return;
    -- end
    rsp.req_id = msg.req_id;
    rsp.result = true;
    rsp.msg = "success";
    respon(cjson.encode(rsp));
end

function hold(param)
    if check_param_and_respon(msg) == false then return end
    if check_param_and_respon(msg, "uuid") == false then return end
    if check_param_and_respon(msg, "value") == false then return end
    local real_uuid = get_real_uuid(msg.uuid);
    if msg.uuid ~= real_uuid then
        msg.uuid = real_uuid;
    end

    local ret = "";
    if msg.value then
        ret = api:execute("uuid_hold", msg.uuid);
    else
        ret = api:execute("uuid_hold", "off "..msg.uuid);
    end
    local rsp = {};
    rsp.req_id = msg.req_id;

    if string.find(ret, "ERR") then
        rsp.result = false;
        rsp.msg = "通话不存在:"..ret;
        respon(cjson.encode(rsp));
        return;
    end

    if msg.file_name then
        if api:execute("file_exists", msg.file_name) == "true" then
            api:execute("uuid_setvar", msg.uuid.." temp_hold_music "..msg.file_name);
        else
            logI("file not exist:"..msg.file_name+", use default");
        end
    end

    if msg.value then
        api:execute("uuid_setvar", msg.uuid.." lcc_hold_flag true");
    else
        api:execute("uuid_setvar", msg.uuid.." lcc_hold_flag false");
    end
    -- 睡眠500ms，等待hold流程走完。如果hold流程没有走完就去调用咨询接口会导致无声。
    api:execute("msleep", "500");
    
    rsp.result = true;
    rsp.msg = "success";
    respon(cjson.encode(rsp));
end

function mute(param)
    if check_param_and_respon(msg) == false then return end
    if check_param_and_respon(msg, "uuid") == false then return end
    if check_param_and_respon(msg, "mute") == false then return end
    local real_uuid = get_real_uuid(msg.uuid);
    if msg.uuid ~= real_uuid then
        msg.uuid = real_uuid;
    end

    local ret = "";
    if msg.mute then
        ret = api:execute("uuid_audio", msg.uuid.." start read mute -4");
    else
        ret = api:execute("uuid_audio", msg.uuid.." start read mute stop");
    end
    local rsp = {};
    rsp.req_id = msg.req_id;

    if string.find(ret, "ERR") then
        rsp.result = false;
        rsp.msg = "通话不存在:"..ret;
        respon(cjson.encode(rsp));
        return;
    end
    
    rsp.result = true;
    rsp.msg = "success";
    respon(cjson.encode(rsp));
end

-- 录音
function record(param)
    if check_param_and_respon(msg) == false then return end
    if check_param_and_respon(msg, "uuid") == false then return end
    if check_param_and_respon(msg, "req_id") == false then return end
    local rsp = {};
    rsp.req_id = msg.req_id;

    local real_uuid = get_real_uuid(msg.uuid);
    if msg.uuid ~= real_uuid then
        msg.uuid = real_uuid;
    end

    local a_session = freeswitch.Session(msg.uuid);
    if a_session:getState() == "ERROR" then
        rsp.req_id = msg.req_id;
        rsp.result = false;
        rsp.msg = "通话不存在:"..msg.uuid;
        respon(cjson.encode(rsp));
        return;
    end
    local file_name = msg.file_name or msg.req_id;
    local record_suffix = msg.record_suffix or "mp3";

    local time = os.time();
    local data_path = os.date("%Y/%m/%Y-%m-%d", time);
    local record_path = sys_record_path.."/"..msg.company_code.."/"..msg.service_code.."/"..data_path.."/"..file_name.."."..record_suffix;
    if api:execute("file_exists", record_path) == "true" then
        file_name = api:execute("create_uuid");
        record_path = sys_record_path.."/"..msg.company_code.."/"..msg.service_code.."/"..data_path.."/"..file_name.."."..record_suffix;
    end

    rsp.lcc_record_file = record_path;
    rsp.lcc_record_date = os.date("%Y-%m-%d", time);

    local arg = {};
    if record_suffix == "mp4" then
        if msg.record_contact ~= nil and msg.record_contact ~= false then
            arg.record_concat_video = "true";
        end
    else
        if msg.record_contact ~= nil and msg.record_contact == false then
            arg.RECORD_READ_ONLY = "true";
        end
    end
    -- 是否立体声录制
    if msg.is_stereo then
        -- 是否交换左右声道
        if msg.is_stereo_swap then
            arg.RECORD_STEREO_SWAP = "true";
        else
            arg.RECORD_STEREO = "true";
        end
    end

    local record_times = a_session:getVariable("lcc_record_times");
    if record_times then
        record_times = tonumber(record_times) + 1
    else
        record_times = 1;
    end

    rsp.record_id = "lcc_records_"..record_times.."_"..rsp.lcc_record_date;
    a_session:setVariable("lcc_record_times", record_times);
    a_session:setVariable(rsp.record_id, record_path);

    rsp.result = true;
    rsp.file_name = file_name;
    rsp.msg = "success";
    respon(cjson.encode(rsp));
    respon("close");

    local arg_string = msg_print(arg);
    api:execute("uuid_record", msg.uuid.." start "..record_path.." 0 "..arg_string);

end

function stop_record(param)
    if check_param_and_respon(msg) == false then return end
    if check_param_and_respon(msg, "uuid") == false then return end
    if check_param_and_respon(msg, "record_id") == false then return end
    local rsp = {};
    rsp.req_id = msg.req_id;

    local real_uuid = get_real_uuid(msg.uuid);
    if msg.uuid ~= real_uuid then
        msg.uuid = real_uuid;
    end

    local ret = api:execute("uuid_getvar", msg.uuid.." "..msg.record_id);
    if ret then
        local check = api:execute("uuid_exists", msg.uuid);
        if check == "false" then
            rsp.result = false;
            rsp.msg = "通话不存在:".. msg.uuid;
            respon(cjson.encode(rsp));
            return;
        end
        
        ret = api:execute("uuid_record", msg.uuid.." "..ret.." stop");
        if string.find(ret, "ERR") then
            rsp.result = false;
            rsp.msg = "停止录音失败:"..ret;
            respon(cjson.encode(rsp));
            return;
        end
    end
    rsp.result = true;
    rsp.msg = "success";
    respon(cjson.encode(rsp));
end

function xfer(param)
    if check_param_and_respon(msg) == false then return end
    if check_param_and_respon(msg, "uuid") == false then return end
    if check_param_and_respon(msg, "xfer_action") == false then return end
    if check_param_and_respon(msg, "x_uuid") == false then return end

    local real_uuid = get_real_uuid(msg.uuid);
    if msg.uuid ~= real_uuid then
        msg.uuid = real_uuid;
    end

    local real_uuid = get_real_uuid(msg.x_uuid);
    if msg.x_uuid ~= real_uuid then
        msg.x_uuid = real_uuid;
    end

    local rsp = {};
    rsp.req_id = msg.req_id;

    -- 咨询
    if msg.xfer_action == "consult" then
        local a_session = freeswitch.Session(msg.uuid);
        if a_session:getState() ~= "ERROR" then
            local b_uuid = a_session:getVariable("signal_bond");
            local ret = api:execute("bgapi", "uuid_broadcast "..msg.uuid.." lcc_att_xfer::"..msg.x_uuid);
            if string.find(ret, "ERR") then
                rsp.result = false;
                rsp.msg = "咨询失败:"..ret;
                respon(cjson.encode(rsp));
                return;
            end
        else
            rsp.result = false;
            rsp.msg = "通话不存在:"..msg.uuid;
            respon(cjson.encode(rsp));
        end
    elseif msg.xfer_action == "trans" then
        local a_session = freeswitch.Session(msg.uuid);
        if a_session:getState() ~= "ERROR" then
            rsp.req_id = msg.req_id;
            rsp.result = true;
            rsp.msg = "success";
            respon(cjson.encode(rsp));
            respon("close");
            a_session:execute("lcc_att_xfer", msg.x_uuid);
            return;
            -- 这样会把B路挂断
            -- a_session:execute("transfer", "lcc_att_xfer|"..msg.x_uuid.." xml lcc_service");
        else
            rsp.result = false;
            rsp.msg = "通话不存在:"..msg.uuid;
            respon(cjson.encode(rsp));
        end
    elseif msg.xfer_action == "three_way" then
        -- 测试会议方式
        if true then
            rsp.req_id = msg.req_id;
            rsp.result = true;
            rsp.msg = "success";
            respon(cjson.encode(rsp));
            respon("close");

            local session_a = freeswitch.Session(msg.uuid);
            local b_uuid = session_a:getVariable("signal_bond") or session_a:getVariable("originate_signal_bond");
            local session_b = freeswitch.Session(b_uuid);
            local session_c = freeswitch.Session(msg.x_uuid);
            
            session_a:execute("transfer", "conference|"..msg.uuid.."@video-mcu-stereo-720++flags{nomoh} xml lcc_service");
            session_b:execute("transfer", "conference|"..msg.uuid.."@video-mcu-stereo-720++flags{nomoh} xml lcc_service");
            session_c:execute("transfer", "conference|"..msg.uuid.."@video-mcu-stereo-720++flags{nomoh} xml lcc_service");
            return
        end

        local c_session = freeswitch.Session(msg.uuid);
        if c_session:getState() ~= "ERROR" then
            rsp.req_id = msg.req_id;
            rsp.result = true;
            rsp.msg = "success";
            respon(cjson.encode(rsp));
            respon("close");
            -- 需要通过转接的接口去执行lua脚本，不然会有问题(有时候有声音，有时候没有声音)
            -- c_session:execute("three_way", msg.uuid);
            c_session:execute("transfer", "three_way|"..msg.x_uuid.." xml lcc_service");
            return;
        else
            rsp.result = false;
            rsp.msg = "通话不存在:"..msg.uuid;
            respon(cjson.encode(rsp));
        end
    elseif msg.xfer_action == "whisper" then
        local c_session = freeswitch.Session(msg.uuid);
        if c_session:getState() ~= "ERROR" then
            rsp.req_id = msg.req_id;
            rsp.result = true;
            rsp.msg = "success";
            respon(cjson.encode(rsp));
            respon("close");
            c_session:setVariable("eavesdrop_whisper_bleg", "true");
            c_session:setVariable("eavesdrop_bridge_aleg", "true");
            c_session:setVariable("eavesdrop_bridge_bleg", "true");

            -- 这个方式耳语一会无声，一会有声
            -- c_session:execute("eavesdrop", msg.x_uuid);
            -- return;
            c_session:execute("transfer", "eavesdrop|"..msg.x_uuid.." xml lcc_service");
           
        else
            rsp.result = false;
            rsp.msg = "通话不存在:"..msg.uuid;
            respon(cjson.encode(rsp));
        end
        
    elseif msg.xfer_action == "eavesdrop" then
        local c_session = freeswitch.Session(msg.uuid);

        if c_session:getState() ~= "ERROR" then
            rsp.req_id = msg.req_id;
            rsp.result = true;
            rsp.msg = "success";
            respon(cjson.encode(rsp));
            respon("close");
            c_session:setVariable("eavesdrop_bridge_aleg", "true");
            c_session:setVariable("eavesdrop_bridge_bleg", "true");

            c_session:execute("eavesdrop", msg.x_uuid);
            return;
            -- 用转接方式会直接挂断
            -- c_session:execute("transfer", "eavesdrop|"..msg.uuid.." xml lcc_service");
            
        else
            rsp.result = false;
            rsp.msg = "通话不存在:"..msg.uuid;
            respon(cjson.encode(rsp));
        end
    end

    rsp.req_id = msg.req_id;
    rsp.result = true;
    rsp.msg = "success";
    respon(cjson.encode(rsp));
end

function set_session_var(param)
    if check_param_and_respon(msg) == false then return end
    if check_param_and_respon(msg, "uuid") == false then return end
    if check_param_and_respon(msg, "key") == false then return end
    if check_param_and_respon(msg, "value") == false then return end

    local real_uuid = get_real_uuid(msg.uuid);
    if msg.uuid ~= real_uuid then
        msg.uuid = real_uuid;
    end
    
    local ret = api:execute("uuid_setvar", msg.uuid.." "..msg.key.." "..msg.value);
    local rsp = {};
    rsp.req_id = msg.req_id;

    if string.find(ret, "ERR") then
        rsp.result = false;
        rsp.msg = "通话不存在:"..ret;
        respon(cjson.encode(rsp));
        return;
    end
    rsp.req_id = msg.req_id;
    rsp.result = true;
    rsp.msg = "success";
    respon(cjson.encode(rsp));
end

function get_session_var(param)
    if check_param_and_respon(msg) == false then return end
    if check_param_and_respon(msg, "uuid") == false then return end
    if check_param_and_respon(msg, "key") == false then return end
    if check_param_and_respon(msg, "value") == false then return end

    local real_uuid = get_real_uuid(msg.uuid);
    if msg.uuid ~= real_uuid then
        msg.uuid = real_uuid;
    end
    
    local ret = api:execute("uuid_getvar", msg.uuid.." "..msg.key);
    local rsp = {};
    rsp.req_id = msg.req_id;

    if string.find(ret, "ERR") then
        rsp.result = false;
        rsp.msg = "通话不存在:"..ret;
        respon(cjson.encode(rsp));
        return;
    end

    if ret == "_undef_" then
        rsp.result = false;
        rsp.msg = "key:["..msg.key.."]不存在";
        respon(cjson.encode(rsp));
        return;
    end
    rsp.req_id = msg.req_id;
    rsp.value = ret;
    rsp.result = true;
    rsp.msg = "success";
    respon(cjson.encode(rsp));
end

function execute_lua(param)
    if true then
        rsp.result = false;
        rsp.msg = "该接口已弃用，请使用trans2lua";
        respon(cjson.encode(rsp));
        return;
    end
    if check_param_and_respon(msg) == false then return end
    if check_param_and_respon(msg, "company_code") == false then return end
    if check_param_and_respon(msg, "service_code") == false then return end
    if check_param_and_respon(msg, "file_name") == false then return end
    local ret;
    local rsp = {};
    rsp.req_id = msg.req_id;
    
    local file_path = sys_lua_path.."/"..msg.company_code.."/"..msg.service_code.."/"..msg.file_name;
    if msg.uuid then
        local a_session = freeswitch.Session(msg.uuid);
        if a_session:getState() ~= "ERROR" then
            -- 检查文件
            ret = api:execute("file_exists", file_path);
            if ret == "false" then
                rsp.result = false;
                rsp.msg = "文件不存在:["..file_path.."]";
                respon(cjson.encode(rsp));
                return;
            end
            rsp.req_id = msg.req_id;
            rsp.valua = ret;
            rsp.result = true;
            rsp.msg = "success";
            respon(cjson.encode(rsp));
            respon("close");
            a_session:execute("lua", file_path);
            return;
        else
            rsp.result = false;
            rsp.msg = "通话不存在:"..msg.s_uuid;
            respon(cjson.encode(rsp));
            return;
        end
    else
        ret = api:execute("lua", file_path);
    end

    if ret and string.find(ret, "ERR") then
        rsp.result = false;
        rsp.msg = "文件不存在:["..file_path.."]";
        respon(cjson.encode(rsp));
        return;
    end
    rsp.req_id = msg.req_id;
    rsp.result = true;
    rsp.msg = "success";
    respon(cjson.encode(rsp));
end

function call_ivr_lua(param)
    if check_param_and_respon(msg) == false then return end
    if check_param_and_respon(msg, "company_code") == false then return end
    if check_param_and_respon(msg, "service_code") == false then return end
    if check_param_and_respon(msg, "file_name") == false then return end
    if check_param_and_respon(msg, "uuid") == false then return end
    local ret;
    local rsp = {};
    rsp.req_id = msg.req_id;
    
    local file_path = sys_lua_path.."/"..msg.company_code.."/"..msg.service_code.."/"..msg.file_name;
    local a_session = freeswitch.Session(msg.uuid);
    if a_session:getState() ~= "ERROR" then
        -- 检查文件
        ret = api:execute("file_exists", file_path);
        if ret == "false" then
            rsp.result = false;
            rsp.msg = "文件不存在:["..file_path.."]";
            respon(cjson.encode(rsp));
            return;
        end
        rsp.result = true;
        rsp.msg = "success";
        respon(cjson.encode(rsp));
        respon("close");
        -- a_session:execute("lua", file_path);
        a_session:execute("lcc_callin_action", file_path);
    else
        rsp.result = false;
        rsp.msg = "通话不存在:"..msg.uuid;
        respon(cjson.encode(rsp));
        return;
    end
end

function call_queue_to_agent(param)
    if check_param_and_respon(msg) == false then return end
    if check_param_and_respon(msg, "company_code") == false then return end
    if check_param_and_respon(msg, "service_code") == false then return end
    if check_param_and_respon(msg, "ext_id") == false then return end
    if check_param_and_respon(msg, "uuid") == false then return end
    local rsp = {};
    rsp.req_id = msg.req_id;
    
    local a_session = freeswitch.Session(msg.uuid);
    if a_session:getState() ~= "ERROR" then
        a_session:execute("lcc_queue_agent", msg.ext_id);
    else
        rsp.result = false;
        rsp.msg = "通话不存在:"..msg.uuid;
        respon(cjson.encode(rsp));
        return;
    end
    rsp.req_id = msg.req_id;
    rsp.result = true;
    rsp.msg = "success";
    respon(cjson.encode(rsp));
end

function call_queue_exit(param)
    if check_param_and_respon(msg) == false then return end
    if check_param_and_respon(msg, "company_code") == false then return end
    if check_param_and_respon(msg, "service_code") == false then return end
    if check_param_and_respon(msg, "uuid") == false then return end
    local rsp = {};
    rsp.req_id = msg.req_id;
    
    local a_session = freeswitch.Session(msg.uuid);
    if a_session:getState() ~= "ERROR" then
        a_session:execute("lcc_call_queue_end");
    else
        rsp.result = false;
        rsp.msg = "通话不存在:"..msg.uuid;
        respon(cjson.encode(rsp));
        return;
    end
    rsp.req_id = msg.req_id;
    rsp.result = true;
    rsp.msg = "success";
    respon(cjson.encode(rsp));
end

function trans2lua(param)
    if check_param_and_respon(msg) == false then return end
    if check_param_and_respon(msg, "company_code") == false then return end
    if check_param_and_respon(msg, "service_code") == false then return end
    if check_param_and_respon(msg, "file_name") == false then return end
    if check_param_and_respon(msg, "uuid") == false then return end
    local ret;
    local rsp = {};
    rsp.req_id = msg.req_id;
    
    local file_path = sys_lua_path.."/"..msg.company_code.."/"..msg.service_code.."/"..msg.file_name;
    local a_session = freeswitch.Session(msg.uuid);
    if a_session:getState() ~= "ERROR" then
        -- 检查文件
        ret = api:execute("file_exists", file_path);
        if ret == "false" then
            rsp.result = false;
            rsp.msg = "文件不存在:["..file_path.."]";
            respon(cjson.encode(rsp));
            return;
        end
        rsp.req_id = msg.req_id;
        rsp.result = true;
        rsp.msg = "success";
        respon(cjson.encode(rsp));

        -- a_session:execute("lcc_callin_action", file_path);
        a_session:execute("transfer", "lua|"..file_path.." xml lcc_service");
        return;
    else
        rsp.req_id = msg.req_id;
        rsp.result = false;
        rsp.msg = "通话不存在:"..msg.uuid;
        respon(cjson.encode(rsp));
        return;
    end
end

-- function hup_assoc_call_by_ext(param)
--     if check_param_and_respon(msg) == false then return end
--     local dbh=freeswitch.Dbh("sqlite://core")
--     assert(dbh:connected())
--     dbh:query("Select uuid, direction, state, callstate, dest, created_epoch From channels", function(row) -- 对每一列进行操作
--         freeswitch.consoleLog("NOTICE", row.uuid.."\n");
--     end)
--     dbh:release()
-- end

function call2java_exit(param)
    if check_param_and_respon(msg) == false then return end
    if check_param_and_respon(msg, "company_code") == false then return end
    if check_param_and_respon(msg, "service_code") == false then return end
    if check_param_and_respon(msg, "uuid") == false then return end
    local rsp = {};
    rsp.req_id = msg.req_id;
    
    local a_session = freeswitch.Session(msg.uuid);
    if a_session:getState() ~= "ERROR" then
        a_session:execute("lcc_call2java_action", "0");
    else
        rsp.result = false;
        rsp.msg = "通话不存在:"..msg.uuid;
        respon(cjson.encode(rsp));
        return;
    end
    rsp.result = true;
    rsp.msg = "success";
    respon(cjson.encode(rsp));
end

function playback_control(param)
    if check_param_and_respon(msg) == false then return end
    if check_param_and_respon(msg, "company_code") == false then return end
    if check_param_and_respon(msg, "service_code") == false then return end
    if check_param_and_respon(msg, "uuid") == false then return end

    local real_uuid = get_real_uuid(msg.uuid);
    if msg.uuid ~= real_uuid then
        msg.uuid = real_uuid;
    end

    local rsp = {};
    rsp.req_id = msg.req_id;
    local action = msg.action or "";
    if action == "speed" then
        action = "speed:"..(msg.speed_value or "0");
    elseif action == "volume" then
        action = "volume:"..(msg.volume_value or "0");
    elseif action == "seek" then
        action = "seek:"..(msg.seek_value or "0");
    elseif action == "resume" then
        action = "pause";
    -- elseif action == "pause" then
    --     action_value = "";
    -- elseif action == "stop" then
    --     action_value = "";
    -- elseif action == "restart" then
    --     action_value = "";
    end

    local ret = api:execute("uuid_fileman", msg.uuid.." "..action);
    if ret and string.find(ret, "ERR") then
        rsp.req_id = msg.req_id;
        rsp.result = false;
        rsp.msg = "操作失败:"..msg.uuid;
        respon(cjson.encode(rsp));
        return;
    end
    rsp.req_id = msg.req_id;
    rsp.result = true;
    rsp.msg = "success";
    respon(cjson.encode(rsp));
end

function check_alived(param)
    local rsp = {};
    rsp.req_id = msg.req_id;

    rsp.result = true;
    rsp.msg = "success";
    respon(cjson.encode(rsp));
    -- api:execute("");
end

function hangup_always_ext()
    if check_param_and_respon(msg) == false then return end
    if check_param_and_respon(msg, "ext_id") == false then return end
    local rsp = {};
    rsp.req_id = msg.req_id;

    local real_uuid = api:execute("lcc_hiredis_raw", "default GET base:always:"..msg.callee_number);
    if real_uuid == "" or string.find(real_uuid, "ERR") then
        rsp.result = false;
        rsp.msg = "话机当前没有通话:"..msg.ext_id;
        respon(cjson.encode(rsp));
        return;
    end

    local ret = api:execute("uuid_kill", real_uuid);

    if string.find(ret, "ERR") then
        rsp.result = false;
        rsp.msg = "通话不存在:"..real_uuid;
        respon(cjson.encode(rsp));
        return;
    end

    if msg.hangup_other then
        local partner_uuid = get_partner_uuid(real_uuid);
        if partner_uuid then 
            api:execute("uuid_kill", partner_uuid);
        end
    end
    rsp.result = true;
    rsp.msg = "success";
    respon(cjson.encode(rsp));
    
    -- local a_session = freeswitch.Session(real_uuid);
    -- if a_session:getState() == "ERROR" then
    --     rsp.result = false;
    --     rsp.msg = "通话不存在:"..real_uuid;
    --     respon(cjson.encode(rsp));
    --     return;
    -- end
end

--常用asr引擎表:
-- 0: "whisper",
-- 1: "funasr",
-- 2: "openai",
-- 3: "tencent",
-- 4: "xfai",
-- 5: "deepspeech",
-- 6: "baidu",
-- 7: "google",
-- 8: "alibaba",
-- 9: "vosk"
function get_real_engine(engine_id)
    if engine_id == "0" then return "lcc_ws_whisper" end
    if engine_id == "1" then return "lcc_ws_funasr" end
    if engine_id == "2" then return "lcc_ws_openai" end
    if engine_id == "3" then return "lcc_ws_tencent" end
    if engine_id == "4" then return "lcc_ws_xunfei" end
    if engine_id == "5" then return "lcc_ws_deepspeech" end
    if engine_id == "6" then return "lcc_ws_baidu" end
    if engine_id == "7" then return "lcc_ws_google_asr" end
    if engine_id == "8" then return "lcc_ws_ali" end
    if engine_id == "9" then return "vosk" end
end

-- 开启ASR实时语音识别 ai_asr_real_recognize
function ai_asr_real_recognize(param)
    if check_param_and_respon(msg) == false then return end
    -- if check_param_and_respon(msg, "company_code") == false then return end
    -- if check_param_and_respon(msg, "service_code") == false then return end
    if check_param_and_respon(msg, "uuid") == false then return end
    if check_param_and_respon(msg, "engine_id") == false then return end
    if check_param_and_respon(msg, "switch") == false then return end
    -- 默认参数
    if msg.is_transparent == nil then 
        msg.is_transparent = true;
    end
    if msg.is_pc == nil then
        msg.is_pc = true;
    end
    if msg.is_pc == true then
	    msg.is_pc = "pc";
    else
	    msg.is_pc = "smartphone";
    end

    local real_uuid = get_real_uuid(msg.uuid);
    if msg.uuid ~= real_uuid then
        msg.uuid = real_uuid;
    end

    local engine_id = get_real_engine(msg.engine_id);

    local rsp = {};
    rsp.req_id = msg.req_id;
    local a_session = freeswitch.Session(msg.uuid);
    if a_session:getState() ~= "ERROR" then
        -- 判定当前有没有开启语音识别
        local lcc_open_asr = a_session:getVariable("lcc_open_asr");
        if lcc_open_asr == "true" and msg.switch ~= false then
            rsp.result = false;
            rsp.msg = "ASR识别已开启，请勿重复开启";
            respon(cjson.encode(rsp));
            return;
        end
        -- 开启语音识别
        a_session:setVariable("lcc_open_asr", "true");
        if msg.switch then
            a_session:execute("set", "rtp_enable_vad_in=false");
            a_session:setVariable("fire_asr_events", "true");
            a_session:execute("detect_speech", engine_id .." default default");
        else
            a_session:setVariable("fire_asr_events", "false");
            a_session:setVariable("lcc_open_asr", "false");
            a_session:execute("detect_speech", "stop");
        end
        ----- 改成会议模式
        if true then
            local b_uuid = a_session:getVariable("signal_bond") or a_session:getVariable("originate_signal_bond") or a_session:getVariable("lcc_conf_link_uuid");
            local b_session = freeswitch.Session(b_uuid);
            if b_session:getState() ~= "ERROR" then
                -- 转到会议
                -- 如果没有在会议就进入会议
                if conf_uuid == nil then
                    local flag = "+flags{dist-dtmf}";
                    if msg.is_transparent ~= nil and msg.is_transparent == false then
                        flag = "+flags{mute|dist-dtmf}"
                        -- 开启语音识别
                        a_session:execute("set", "lcc_conf_id="..conf_id);
                        b_session:execute("set", "lcc_conf_id="..conf_id);

                        
                        a_session:execute("lcc_playback", "stop");
                        b_session:execute("lcc_playback", "stop");

                        a_session:execute("transfer", "conference|"..conf_id.."@"..flag.."default xml lcc_service");
                        b_session:execute("transfer", "conference|"..conf_id.."@+flags{dist-dtmf}default xml lcc_service");
                    end
                else
                    if msg.is_transparent == false then
                        api:execute("msleep", "500");
                        local member_id = a_session:getVariable("conference_member_id");
                        api:execute("conference", conf_id.." mute "..member_id);
                    end
                end
            end
        else
            --透传原音
            if msg.is_transparent then
                if(a_session:getVariable("is_transparent_flag") == "false") then
                    api:execute("uuid_audio", msg.uuid .. " stop write mute");
                end
                a_session:setVariable("is_transparent_flag", "true");
            else
                a_session:setVariable("is_transparent_flag", "false");
                api:execute("uuid_audio", msg.uuid .. " start write mute 1");
            end
            --
        end
    else
        rsp.result = false;
        rsp.msg = "开启ASR识别失败,通话不存在:"..msg.uuid;
        respon(cjson.encode(rsp));
        return;
    end
    
    rsp.req_id = msg.req_id;
    rsp.result = true;
    rsp.msg = "success";
    respon(cjson.encode(rsp));
end

function detect_speech()
    if check_param_and_respon(msg) == false then return end
    if check_param_and_respon(msg, "uuid") == false then return end
    local rsp = {};
    rsp.req_id = msg.req_id;
    local a_session = freeswitch.Session(msg.uuid);
    if a_session:getState() == "ERROR" then
        rsp.result = false;
        rsp.msg = "通话不存在:"..msg.uuid;
        respon(cjson.encode(rsp));
        return;
    end

    if msg.open_events then
        a_session:setVariable("fire_asr_events", "true");
    end
    local profile = msg.profile or "default";
    local engine_id = msg.engine or "default";
    local name = msg.name or api:execute("create_uuid");
    
    rsp.req_id = msg.req_id;
    rsp.result = true;
    rsp.msg = "success";
    respon(cjson.encode(rsp));
    respon("close");

    if msg.params and msg.params ~= "" then
        a_session:execute("detect_speech", "unimrcp:"..profile.." {"..msg.params.."}"..engine_id.." "..name);
    else
        a_session:execute("detect_speech", "unimrcp:"..profile.." "..engine_id.." "..name);
    end
end

-- 开启 是否透传原音开/关 默认开
function switch_ori_voice(param)
    if check_param_and_respon(msg) == false then return end
    if check_param_and_respon(msg, "uuid") == false then return end
        
    if check_param_and_respon(msg, "is_transparent") == false then
        msg.is_transparent = true;
    end     
    local real_uuid = get_real_uuid(msg.uuid);
    if msg.uuid ~= real_uuid then
        msg.uuid = real_uuid;
    end         
            
    local rsp = {};
    rsp.req_id = msg.req_id;
    local a_session = freeswitch.Session(msg.uuid);
    if a_session:getState() ~= "ERROR" then
        ----- 改成会议模式
        if true then
            local conf_id = a_session:getVariable("lcc_conf_id");            
            if conf_id == nil then
                local b_uuid = a_session:getVariable("signal_bond") or a_session:getVariable("originate_signal_bond") or a_session:getVariable("lcc_conf_link_uuid");
                local b_session = freeswitch.Session(b_uuid);
                if b_session:getState() ~= "ERROR" then
                    local flag = "+flags{dist-dtmf}";
                    if msg.is_transparent ~= nil and msg.is_transparent == false then
                        flag = "+flags{mute|dist-dtmf}"
                        -- 开启语音识别
                        a_session:execute("set", "lcc_conf_id="..conf_id);
                        b_session:execute("set", "lcc_conf_id="..conf_id);

                        
                        a_session:execute("lcc_playback", "stop");
                        b_session:execute("lcc_playback", "stop");

                        a_session:execute("transfer", "conference|"..conf_id.."@"..flag.."default xml lcc_service");
                        b_session:execute("transfer", "conference|"..conf_id.."@+flags{dist-dtmf}default xml lcc_service");
                    end
                end     
            else        
                api:execute("msleep", "500");
                local member_id = a_session:getVariable("conference_member_id");
                if msg.is_transparent then
                    api:execute("conference", conf_id.." unmute "..member_id);
                else
                    api:execute("conference", conf_id.." mute "..member_id);
                end
            end
        else
            if msg.is_transparent then
                if(a_session:getVariable("is_transparent_flag") == "false") then
                    api:execute("uuid_audio", msg.uuid .. " stop write mute");
                end
                a_session:setVariable("is_transparent_flag", "true");
            else
                a_session:setVariable("is_transparent_flag", "false");
                api:execute("uuid_audio", msg.uuid .. " start write mute 1");
            end
        end
    else
        rsp.result = false;
        rsp.msg = "透传原音失败,通话不存在:"..msg.uuid;
        respon(cjson.encode(rsp));
        return;
    end

    rsp.req_id = msg.req_id;
    rsp.result = true;
    rsp.msg = "success";
    respon(cjson.encode(rsp));
end

function broadcast()
    if check_param_and_respon(msg) == false then return end
    local rsp = {};
    rsp.req_id = msg.req_id;
    local file = msg.file_name;

    if string.find(file, "http") == nil and api:execute("file_exists", file) ~= "true" then
        rsp.result = false;
        rsp.msg = "文件不存在:"..file;
        respon(cjson.encode(rsp)); 
        return;
    end

    -- 获取A路lcc_cdr_id
    local ret = api:execute("uuid_broadcast", msg.uuid.." "..file.." aleg");
    rsp.req_id = msg.req_id;
    rsp.result = true;
    rsp.msg = "success";
    respon(cjson.encode(rsp));
end

-- 同振/顺振(此方式不支持长通)
-- function call_bridge_batch()
--     if check_param_and_respon(msg) == false then return end
--     local rsp = {};
--     rsp.req_id = msg.req_id;

--     -- 获取A路lcc_cdr_id
--     local lcc_cdr_id = api:execute("uuid_getvar", msg.s_uuid.." lcc_cdr_id");
--     if lcc_cdr_id and (not string.find(lcc_cdr_id, "ERR")) then
--         msg.lcc_cdr_id = lcc_cdr_id;
--     end
--     if msg.callee_numbers then

--     end

-- end

main()