• 【顶顶通呼叫中心中间件(mod_cti 基于 FreeSWITCH)-拨号方案和路由配置】


    介绍

    为了实现动态组合拨号方案避免重复配置,把拨号方案拆分成了2个部分,一个是cti_dialplan_extensio@domain,保存单个拨号方案配置,一个是cti_dialplan_context@domain把多个拨号方案组合一个路由表。拨号方案和路由配置修改后会实时生效。

    用法

    通道变量

    拨号方案的原理就是对通道变量执行正则表达式匹配,如果匹配上了,就执行对应的动作(APP)。fs的很多特性是通过设置通道变量来实现的。这里介绍一下常用的通道变量,更详细的说明参考 https://freeswitch.org/confluence/display/FREESWITCH/Channel+Variables 和 https://freeswitch.org/confluence/display/FREESWITCH/Variables+Master+List

    • caller_id_number 来电号码
    • network_addr 来电IP
    • destination_number DID

    下面几个时设置系统特性常用的通道变量

    • absolute_codec_string 设置声音编码
    • call_timeout 设置呼叫超时 ,只作用于后续桥接的通道
    • effective_caller_id_number 设置主叫号码,只作用于后续桥接的通道
    • originate_timeout 设置呼叫超时 ,只作用于本端,一般添加在拨号串里,或者export设置
    • origination_caller_id_number 设置主叫号码,只作用于本端,一般添加在拨号串里,或者export设置

    fs的通道变量非常多,怎么查看通话的通道变量呢,有2个方法 方法1 执行fs控制台命令 uuid_dump 通话UUID,方法2 拨号方案里面执行fs的动作info 也可以输出通道变量,info输出的通道变量有些名字和uuid_dump的不一样,文末复制了一个fs官方文档里面的对应关系。

    拨号方案中调用http接口

    通过API cti_http_get url [connect_timeout] [response_timeout] [varname] 可以在拨号方案任意位置调用http接口,可以把通道变量作为 http接口的参数,传递给接口。

    • connect_timeout 连接超时
    • response_timeout 等待返回超时
    • varname 返回的数据写入这个变量,如果不设置,就会写入默认变量cti_http_get_last_result
    • 例子
      • 例子1 eval ${cti_http_get(http://ip?arg=${通道变量})}
        执行http请求,返回的结果会写入默认变量cti_http_get_last_result
      • 例子2 set myval=${cti_http_get(http://ip?arg=${通道变量})}
        把cti_http_get返回的结果写入myval变量
    • 接口返回数据说明
      • 返回文本数据
        返回文本数据不会进行解析和也不会去除空格换行,会把原始数据设置到变量里面。
      • 返回JSON数据
        {"header":{"value1":"1","value2":"2"},"body":""}
        head可用来设置自定义的变量,body会写入cti_http_get_last_result,或者自定义的变量名里面。

    拨号方案的condition(条件),也可以调用http接口,根据返回的结果和正则表达式进行匹配。具体可以看下图的例子。注意返回的数据前后不要有空格换行等不可见字符,会导致和正则表达式匹配不上。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vMaJvNes-1661834141133)(dialplan/image-20220830104137369.png)]

    拨号方案中写redis和读redis

    cti_hash_get hash field [varname] ,cti模块定义了cti_hash_get这个同名的API和APP,用来读取redis的hash表.

    • hash 表的key

    • field hash表的 field

    • varname 读取到的value存放的变量

    cti_hash_set hash field value cti模块定义了cti_hash_set这个同名的API和APP,用来设置redis的hash表

    APP就是一个动作,拨号方案里面可以直接添加动作,拨号方案调用API就和使用变量一样${API名字(参数)},多个参数用空格隔开,可以用set 这个APP把API的返回结果写入变量。也可以嵌套使用比如${cti_extension_exists(${cti_hash_get(callhistory@${cti_domain} ${cti_mid_string(${caller_id_number} -11)})})},如果不需要把返回结果写入变量,只是想执行这个API,可以用eval ,这个什么也不做的APP去调用API。

    通过http接口返回动作

    APP cti_curl http://ip/app?number=${destination_number} cti_curl 这个APP会调用http,执行接口返回的动作。

    返回例子说明,数组格式,支持多个动作。

    [{"application":"log","data":"INFO 3text"}]

    配置

    1. cti_dialplan_extensio@domain [哈希表]
    • key 拨号方案的名字
    • value
    录音的例子
    {
        "condition": [
            {
                "field": "${record_filename}",
                "description": "测试是否已经启动录音",
                "expression": ".+",
                "anti-action": [
                    {
                        "application": "export",
                        "data": "RECORD_READ_ONLY=false",
                        "description": "是否只录音对方"
                    },
                    {
                        "application": "export",
                        "data": "RECORD_WRITE_ONLY=false",
                        "description": "是否只录音本方"
                    },
                    {
                        "application": "export",
                        "data": "RECORD_BRIDGE_REQ=false",
                        "description": "是否应答后开始录音"
                    },
                    {
                        "application": "export",
                        "data": "RECORD_STEREO=false",
                        "description": "是否双道录音"
                    },
                    {
                        "application": "export",
                        "data": "record_filename=$${recordings_dir}/${strftime(%Y-%m-%d)}/${caller_id_number}.${destination_number}.${strftime(%H-%M-%S)}.${uuid}.wav",
                        "description": "录音录音文件名"
                    },
                    {
                        "application": "record_session",
                        "data": "${record_filename}",
                        "description": "开始录音"
                    }
                ]
            }
        ],
        "continue": true
    }
    
    外呼的例子
    {
        "condition": [
            {
                "field": "destination_number",
                "expression": "^00\\d*$",
                "description": "静止呼叫国际长途",
                "action": [
                    {
                        "application": "hangup",
                        "description": "00开始的号码挂断"
                    }
                ],
                "break": "on-true"
            },
            {
                "field": "destination_number",
                "expression": "^\\d+$",
                "description": "允许全数字号码呼出",
                "action": [
                    {
                        "application": "bridge",
                        "description": "通过default网关呼出",
                        "data": "sofia/gateway/default/${destination_number}"
                    }
                ]
            }
        ]
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    这里就不做解释了,具体参考FreeSWITCH的拨号方案写法。
    支持嵌套等XML拨号方案的所有功能。

    1. cti_dialplan_context@domain [list]
    [
        "call extension",
        "call trunk",
        "testabc"
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5

    CTI模块根据顺序把cti_dialplan_extensio@domain里面的内容组合成一个拨号方案的XML文件。

    呼叫路由规则

    1. 分机呼叫使用的呼叫路由规则
      如果分机配置了呼叫路由,就优先使用分机配置的呼叫路由,如果分机没单独配置呼叫路由,就使用SIP配置internal(分机注册的那个profile)的呼叫路由,如果sip的profile配置也没配置呼叫路由,就使用default这个呼叫路由。
    2. 网关呼入使用的呼叫路由
      如果网关配置了呼叫路由,就使用网关配置的呼叫路由,如果网关配置没配置呼叫路由,就使用SIp配置external(关联网关的那个profile)的呼叫路由,如果sip的profile配置也没配置呼叫路由,就使用default这个呼叫路由。
    3. 呼叫路由配置必须小心,防止给盗打,网关和external配置的呼叫路由不能配置呼叫外线的拨号方案。

    Info Application Variable Names (variable_xxxx)

    Some variables, as shown from the info app, may have variable_ in front of their names. For example, if you pass a header variable called type from the proxy server, it will get displayed as variable_sip_h_type in FreeSWITCH™. To access that variable, you should strip off the variable_, and just do ${sip_h_type}. Other variables shown in the info app are prepended with channel, which should be stripped as well. The example below show a list of info app variables and the corresponding channel variable names:

    Info variable namechannel variable nameDescription
    Channel-StatestateCurrent state of the channel
    Channel-State-Numberstate_numberInteger
    Channel-Namechannel_nameChannel name
    Unique-IDuuiduuid of this channel’s call leg
    Call-DirectiondirectionInbound or Outbound
    Answer-Statestate-
    Channel-Read-Codec-Nameread_codecthe read codec variable mean the source codec
    Channel-Read-Codec-Rateread_ratethe source rate
    Channel-Write-Codec-Namewrite_codecthe destination codec same to write_codec if not transcoded
    Channel-Write-Codec-Ratewrite_ratedestination rate same to read rate if not transcoded
    Caller-Usernameusername.
    Caller-Dialplandialplanuser dialplan like xml, lua, enum, lcr
    Caller-Caller-ID-Namecaller_id_name.
    Caller-Caller-ID-Numbercaller_id_number.
    Caller-ANIaniANI of caller, frequently the same as caller ID number
    Caller-ANI-IIaniiiANI II Digits (OLI - Originating Line Information), if available. Refer to: http://www.nanpa.com/number_resource_info/ani_ii_digits.html
    Caller-Network-Addrnetwork_addrIP address of calling party
    Caller-Destination-Numberdestination_numberDestination (dialed) number
    Caller-Unique-IDuuidThis channel’s uuid
    Caller-SourcesourceSource module, i.e. mod_sofia, mod_openzap, etc.
    Caller-ContextcontextDialplan context
    Caller-RDNISrdnisRedirected DNIS info. See mod_dptools: transfer application
    Caller-Channel-Namechannel_name.
    Caller-Profile-Indexprofile_index.
    Caller-Channel-Created-Timecreated_timeGMT microseconds timestamp when the channel was created
    Caller-Channel-Answered-Timeanswered_timeGMT microseconds timestamp when the channel was answered
    Caller-Channel-Hangup-Timehangup_timeGMT microseconds timestamp when the channel was hung up
    Caller-Channel-Transfer-Timetransfer_timeGMT microseconds timestamp when the channel was transfered
    Caller-Screen-Bitscreen_bit.
    Caller-Privacy-Hide-Nameprivacy_hide_name.
    Caller-Privacy-Hide-Numberprivacy_hide_numberThis variable tells you if the inbound call is asking for CLIR[Calling Line ID presentation Restriction] (either with anonymous method or Privacy:id method)
    initial_callee_id_nameSets the callee id name during the 183. This allows the phone to see a name of who they are calling prior to the phone being answered. An example of setting this to the caller id name of the number being dialled:
    variable_sip_received_ipsip_received_ip.
    variable_sip_received_portsip_received_port.
    variable_sip_authorizedsip_authorized.
    variable_sip_mailboxsip_mailbox.
    variable_sip_auth_usernamesip_auth_username.
    variable_sip_auth_realmsip_auth_realm.
    variable_mailboxmailbox.
    variable_user_nameuser_name.
    variable_domain_namedomain_name.
    variable_record_stereorecord_stereo.
    variable_accountcodeaccountcodeAccountcode for the call. This is an arbitrary value. It can be defined in the user variables in the directory, or it can be set/modified from dialplan. The accountcode may be used to force a specific CDR CSV template for the call; if the value of the accountcode variable matches the name of a template then that template will be used. This is valuable for having a specific template be used on a per-call basis. See mod_cdr_csv.
    variable_user_contextuser_context.
    variable_effective_caller_id_nameeffective_caller_id_name.
    variable_effective_caller_id_numbereffective_caller_id_number.
    variable_caller_domaincaller_domain.
    variable_sip_from_usersip_from_user.
    variable_sip_from_urisip_from_uri.
    variable_sip_from_hostsip_from_host.
    variable_sip_from_user_strippedsip_from_user_stripped.
    variable_sip_from_tagsip_from_tag.
    variable_sofia_profile_namesofia_profile_name.
    variable_sofia_profile_domain_namesofia_profile_domain_name.
    variable_sip_full_routesip_full_routeThe complete contents of the Route: header.
    variable_sip_full_viasip_full_viaThe complete contents of the Via: header.
    variable_sip_full_fromsip_full_fromThe complete contents of the From: header.
    variable_sip_full_tosip_full_toThe complete contents of the To: header.
    variable_sip_req_paramssip_req_params.
    variable_sip_req_usersip_req_user.
    variable_sip_req_urisip_req_uri.
    variable_sip_req_hostsip_req_host.
    variable_sip_to_paramssip_to_params.
    variable_sip_to_tagsip_to_tag.
    variable_sip_to_usersip_to_user.
    variable_sip_to_urisip_to_uri.
    variable_sip_to_hostsip_to_host.
    variable_sip_contact_paramssip_contact_params.
    variable_sip_contact_usersip_contact_user.
    variable_sip_contact_portsip_contact_port.
    variable_sip_contact_urisip_contact_uri.
    variable_sip_contact_hostsip_contact_host.
    variable_sip_invite_domainsip_invite_domain.
    variable_channel_namechannel_name.
    variable_sip_call_idsip_call_idSIP header Call-ID
    variable_sip_user_agentsip_user_agent.
    variable_sip_via_hostsip_via_host.
    variable_sip_via_portsip_via_port.
    variable_sip_via_rportsip_via_rport.
    variable_presence_idpresence_id.
    variable_sip_h_P-Key-Flagssip_h_p-key-flagsThis will contain the optional P-Key-Flags header(s) that may be received from calling endpoint.
    variable_switch_r_sdpswitch_r_sdpThe whole SDP received from calling endpoint.
    variable_remote_media_ipremote_media_ip.
    variable_remote_media_portremote_media_port.
    variable_write_codecwrite_codec.
    variable_write_ratewrite_rate.
    variable_endpoint_dispositionendpoint_disposition.
    variable_dialed_extdialed_ext.
    variable_transfer_ringbacktransfer_ringback.
    variable_call_timeoutcall_timeout.
    variable_hangup_after_bridgehangup_after_bridge.
    variable_continue_on_failcontinue_on_fail.
    variable_dialed_userdialed_user.
    variable_dialed_domaindialed_domain.
    variable_sip_redirect_contact_user_0sip_redirect_contact_user_0.
    variable_sip_redirect_contact_host_0sip_redirect_contact_host_0.
    variable_sip_h_Referred-Bysip_h_referred-by.
    variable_sip_refer_tosip_refer_toThe full SIP URI received from a SIP Refer-To: response
    variable_max_forwardsmax_forwards.
    variable_originate_dispositionoriginate_disposition.
    variable_read_codecread_codec.
    variable_read_rateread_rate.
    variable_openopen.
    variable_use_profileuse_profile.
    variable_current_applicationcurrent_application.
    variable_ep_codec_stringep_codec_stringThis variable is only available if late negotiation is enabled on the profile. It’s a readable string containing all the codecs proposed by the calling endpoint. This can be easily parsed in the dialplan.
    variable_rtp_disable_holdrtp_disable_holdThis variable when set will disable the hold feature of the phone.
    variable_sip_acl_authed_bysip_acl_authed_byThis variable holds what ACL rule allowed the call.
    variable_curl_response_datacurl_response_dataThis variable stores the output from the last curl made.
    variable_drop_dtmfdrop_dtmfSet on a channel to drop DTMF events on the way out.
    variable_drop_dtmf_masking_filedrop_dtmf_masking_fileIf drop_dtmf is true play specified file for every tone received.
    variable_drop_dtmf_masking_digitsdrop_dtmf_masking_digitsIf drop_dtmf is true play specified tone for every tone received.
    sip_codec_negotiationsip_codec_negotiationsip_codec_negotiation is basically a channel variable equivalent of inbound-codec-negotiation. sip_codec_negotiation accepts “scrooge” & “greedy” as values. This means you can change codec negotiation on a per call basis.
    Caller-Callee-ID-Name--
    Caller-Callee-ID-Number--
    Caller-Channel-Progress-Media-Time--
    Caller-Channel-Progress-Time--
    Caller-Direction--
    Caller-Profile-Created-Timeprofile_createdGMT microseconds timestamp when the caller profile was created
    Caller-Transfer-Source--
    Channel-Call-State-Current state of the call
    Channel-Call-UUID--
    Channel-HIT-Dialplan--
    Channel-Read-Codec-Bit-Rate--
    Channel-Write-Codec-Bit-Rate--
    Core-UUID--
    Event-Calling-File--
    Event-Calling-Function--
    Event-Calling-Line-Number--
    Event-Date-GMT--
    Event-Date-Local--
    Event-Date-Timestamp--
    Event-Name--
    Event-Sequence--
    FreeSWITCH-Hostname--
    FreeSWITCH-IPv4--
    FreeSWITCH-IPv6--
    FreeSWITCH-Switchname--
    Hunt-ANI--
    Hunt-Callee-ID-Name--
    Hunt-Callee-ID-Number--
    Hunt-Caller-ID-Name--
    Hunt-Caller-ID-Number--
    Hunt-Channel-Answered-Time--
    Hunt-Channel-Created-Time--
    Hunt-Channel-Hangup-Time--
    Hunt-Channel-Name--
    Hunt-Channel-Progress-Media-Time--
    Hunt-Channel-Progress-Time--
    Hunt-Channel-Transfer-Time--
    Hunt-Context--
    Hunt-Destination-Number--
    Hunt-Dialplan--
    Hunt-Direction--
    Hunt-Network-Addr--
    Hunt-Privacy-Hide-Name--
    Hunt-Privacy-Hide-Number--
    Hunt-Profile-Created-Timeprofile_created-
    Hunt-Profile-Index--
    Hunt-RDNIS--
    Hunt-Screen-Bit--
    Hunt-Source--
    Hunt-Transfer-Source--
    Hunt-Unique-ID--
    Hunt-Username--
    Presence-Call-Direction--
    variable_DIALSTATUS--
    variable_absolute_codec_string--
    variable_advertised_media_ip--
    variable_answersec
    variable_answermsec
    variable_answerusec
    variable_billsec
    variable_billmsec
    variable_billusec
    variable_bridge_channel--
    variable_bridge_hangup_cause--
    variable_bridge_uuid--
    variable_call_uuid--
    variable_current_application_response--
    variable_direction--
    variable_duration
    variable_mduration
    variable_uduration
    variable_inherit_codec--
    variable_is_outbound--
    variable_last_bridge_to--
    variable_last_sent_callee_id_name--
    variable_last_sent_callee_id_number--
    variable_local_media_ip--
    variable_local_media_port--
    variable_number_alias--
    variable_originate_early_media--
    variable_originating_leg_uuid--
    variable_originator--
    variable_originator_codec--
    variable_outbound_caller_id_number--
    variable_progresssec
    variable_progressmsec
    variable_progressusec
    variable_progress_mediasec
    variable_progress_mediamsec
    variable_progress_mediausec
    variable_recovery_profile_name--
    variable_rtp_audio_in_mosMean Opinion Score; read-only, available in CS_REPORTING state, published by CHANNEL_DESTROY event
    variable_rtp_use_ssrc--
    variable_session_id--
    variable_sip_2833_recv_payload--
    variable_sip_2833_send_payload--
    variable_sip_P-Asserted-Identity--
    variable_sip_Privacy--
    variable_sip_audio_recv_pt--
    variable_sip_cid_type--
    variable_sip_cseq--
    variable_sip_destination_url--
    variable_sip_from_displaysip_from_display‘User’ element of SIP From: line
    variable_sip_from_port--
    variable_sip_gateway--
    variable_sip_gateway_name--
    variable_sip_h_P-Charging-Vector--
    variable_sip_local_network_addr--
    variable_sip_local_sdp_str--
    variable_sip_network_ip--
    variable_sip_network_port--
    variable_sip_number_alias--
    variable_sip_outgoing_contact_uri--
    variable_sip_ph_P-Charging-Vector--
    variable_sip_profile_name--
    variable_sip_recover_contact--
    variable_sip_recover_via--
    variable_sip_reply_host--
    variable_sip_reply_port--
    variable_sip_req_port--
    variable_sip_to_port--
    variable_sip_use_codec_name--
    variable_sip_use_codec_ptime--
    variable_sip_use_codec_rate--
    variable_sip_use_pt--
    variable_sip_via_protocol--
    variable_switch_m_sdp--
    variable_transfer_history--
    variable_transfer_source--
    variable_uuid--
    variable_waitsec
    variable_waitmsec
    variable_waitusec
  • 相关阅读:
    Java 中的对象池实现
    不容错过!!C语言-回调函数详解
    基于主动视觉机制的深度学习--一个综合池化框架
    取余、取模运算及rem与mod的区别
    浙江大学主办!2024年第7届信息通信与信号处理国际会议( ICICSP2024)征稿开启!
    Java 语言实现最小生成树算法(如Prim算法、Kruskal算法)
    12月2日:thinkphp中的链式操作
    Java常见面试题1-10
    记录模型压缩概述
    figma插件都有哪些好用的,分享11个提效插件
  • 原文地址:https://blog.csdn.net/iyaosan/article/details/126601479