freeswitch离线对帐话单的产生及保存方式及配置说明

一、 离线话单有三种保存方式:

1. 文件保存: 方便,快捷, 简配置, 支持多格式, 但是如果是多台集群的话, 取出话单比较麻烦要一台一台的取。

2. 数据库保存: 可以集中管理话单, 统计, 分析, 查询, 但是对第三方资源有依赖。

3. HTTP到远程服务保存: 更灵活, 可以支持更多业务及更复杂业务的操作, 可以做到实时监控, 但HTTP服务可靠性要求非常高(实际应用中我会选择这种方式)


二、 文件保存方式的配置及参数分析:

<configuration name="cdr_csv.conf" description="CDR CSV Format">
  <settings>
    <!-- 日志保存的基本路径 -->
    <!--<param name="log-base" value="/var/log"/>-->
    <span style="font-family: Arial, Helvetica, sans-serif;"><!-- 默认的话单产生及保存方式 --></span>
    <param name="default-template" value="example"/>
    <!-- 电话挂掉后的信息日志 -->
    <!--<param name="debug" value="true"/>-->
    <span style="font-family: Arial, Helvetica, sans-serif;"><!-- 将话单以时间为后缀重命名,以便入库或分析处理时影响新写入的话单--></span>
    <param name="rotate-on-hup" value="true"/>
    <!-- 记录对象, 可以是A, B, 或 AB-->
    <param name="legs" value="a"/>
    <!-- 只记录总的话单, 不记录分机话单 --> 
    <!-- <param name="master-file-only" value="true"/> -->
  </settings>
  <templates>
    <template name="sql">INSERT INTO cdr VALUES ("${caller_id_name}","${caller_id_number}","${destination_number}","${context}","${start_stamp}","${answer_stamp}","${en
d_stamp}","${duration}","${billsec}","${hangup_cause}","${uuid}","${bleg_uuid}", "${accountcode}");</template> 
    <template name="example">"${caller_id_name}","${caller_id_number}","${destination_number}","${context}","${start_stamp}","${answer_stamp}","${end_stamp}","${duratio
n}","${billsec}","${hangup_cause}","${uuid}","${bleg_uuid}","${accountcode}","${read_codec}","${write_codec}"</template>
    <template name="snom">"${caller_id_name}","${caller_id_number}","${destination_number}","${context}","${start_stamp}","${answer_stamp}","${end_stamp}","${duration}"
,"${billsec}","${hangup_cause}","${uuid}","${bleg_uuid}", "${accountcode}","${read_codec}","${write_codec}","${sip_user_agent}","${call_clientcode}","${sip_rtp_rxstat}"
,"${sip_rtp_txstat}","${sofia_record_file}"</template>
    <template name="linksys">"${caller_id_name}","${caller_id_number}","${destination_number}","${context}","${start_stamp}","${answer_stamp}","${end_stamp}","${duratio
n}","${billsec}","${hangup_cause}","${uuid}","${bleg_uuid}","${accountcode}","${read_codec}","${write_codec}","${sip_user_agent}","${sip_p_rtp_stat}"</template>
    <template name="asterisk">"${accountcode}","${caller_id_number}","${destination_number}","${context}","${caller_id}","${channel_name}","${bridge_channel}","${last_a
pp}","${last_arg}","${start_stamp}","${answer_stamp}","${end_stamp}","${duration}","${billsec}","${hangup_cause}","${amaflags}","${uuid}","${userfield}"</template>
    <template name="opencdrrate">"${uuid}","${signal_bond}","${direction}","${ani}","${destination_number}","${answer_stamp}","${end_stamp}","${billsec}","${accountcode
}","${userfield}","${network_addr}","${regex('${original_caller_id_name}'|^.)}","${sip_gateway_name}"</template>
  </templates>
</configuration>

1. templates里定义了各种话单的样式模板, 如有sql:入库语句, example为文本的','号隔开的记录话单, 其它的也类似, 其中的字段为channel中的变量字段 , 在挂机后的最终值。


caller_id_name: 主叫方昵称;

caller_id_number:主叫号码;

destination_number:被叫号码;

content: 内容;

start_stamp: 开始时间;

anser_stamp: 应答时间;

end_stamp: 结束时间;

duration: 呼叫总时间, 开始到结束的总时间;

billsec: 计费总时长, 应答时间到结束时间总长;

hangup_cause:挂断原因

uuid:本leg唯一ID;

bleguuid: 另一方leg唯一ID;

accountcode: 帐号;

2. 让话单文件每5分钟或1000条  这样的条件产生一个对帐文件的做法有以下3种:

   A: 用脚本操作: fs_cli -x "cdr_csv rotate"  定时5分钟或一千条时执行这个指令即可;

   B: 0 * * * * fs_cli -x "cdr_csv rotate"  在linux上加入定时任务进行操作;

   C: kill -HUP freeswitch进程ID; 这个不知道会不会对主业务有影响, 个人觉得前两种足以, 这个就不用了吧。


三、直接写入数据库: 这个方法只支持内嵌数据库, 不实用, 这里从略。


四、 使用HTTP服务器接收话单 (比较实用)

  有三个模块可用, mod_xml_cdr, mod_json_cdr, mod_format_cdr 前两个分别是产生xml和json的话单, 最后一个可以配置产生xml或json格式的话单, 直接配置HTTP服务地址及认证方式, 再开发一套HTTP业务逻辑处理的应用服务用来对话单做各种处理。

  一般配置如下项就差不多了:

<configuration name="xml_cdr.conf" description="XML CDR CURL logger">
<settings>
   <param name="cred" value="user:pass"/>   //认证用户密码
   <param name="url" value="http://myhost/cdr.php"/>   //实际的发送地址
   <param name="retries" value="2"/>  //错误及超时重试次数
   <param name="delay" value="120"/>  //重试延迟时间
   <param name="log-dir" value="/var/log/cdr"/>  //日志本地保存目录
   <param name="err-log-dir" value="/var/log/cdr/errors"/> //错误日志目录
   <param name="encode" value="True"/> //url是否要base64编码
</settings>

xml话单格式串类似如下:

<?xml version="1.0"?>
 <cdr>
   <channel_data>
     <state>CS_REPORTING</state>
     <direction>inbound</direction>
     <state_number>11</state_number>
     <flags>0=1;36=1;38=1;51=1</flags>
     <caps>1=1;2=1;3=1</caps>
   </channel_data>
   <variables>
    <uuid>2e831835-d336-4735-b3e5-90e5d7dc8187</uuid>
    <sip_network_ip>192.168.0.2</sip_network_ip>
    <sip_network_port>56866</sip_network_port>
    <sip_received_ip>192.168.0.2</sip_received_ip>
    <sip_received_port>56866</sip_received_port>
    <sip_via_protocol>udp</sip_via_protocol>
    <sip_from_user>1000</sip_from_user>
    <sip_from_uri>1000%40192.168.0.2</sip_from_uri>
    <sip_from_host>192.168.0.2</sip_from_host>
    <sip_from_user_stripped>1000</sip_from_user_stripped>
    <sip_from_tag>BD37552C-4B5</sip_from_tag>
    ...
   </variables>
   <app_log>
    <application app_name="set" app_data="continue_on_fail=true"></application>
    <application app_name="bridge" app_data="sofia/external/gateway/gw001/1000"></application>
    <application app_name="bridge" app_data="sofia/external/gateway/gw002/1000"></application>
   </app_log>
   <callflow dialplan="XML" profile_index="1">
    <extension name="1000" number="1000">
     <application app_name="set" app_data="continue_on_fail=true"></application>
     <application app_name="bridge" app_data="sofia/external/gateway/gw001/1000"></application>
     <application app_name="bridge" app_data="sofia/external/gateway/gw002/1000"></application>
     <application app_name="bridge" app_data="sofia/external/gateway/gw003/1000"></application>
     <application app_name="bridge" app_data="sofia/external/gateway/gw004/1000"></application>
     <application app_name="bridge" app_data="sofia/external/gateway/gw005/1000"></application>
    </extension>
   </callflow>
   <caller_profile>
     <username>1000</username>
     <dialplan>XML</dialplan>
     <caller_id_name>1000</caller_id_name>
     <ani>1000</ani>
     <aniii></aniii>
     <caller_id_number>1000</caller_id_number>
     <network_addr>192.168.0.2</network_addr>
     <rdnis>1000</rdnis>
     <destination_number>1000</destination_number>
     <uuid>2e831835-d336-4735-b3e5-90e5d7dc8187</uuid>
     <source>mod_sofia</source>
     <context>default</context>
     <chan_name>sofia/default/[email protected]</chan_name>
   </caller_profile>
   <times>
     <created_time>1274439432438053</created_time>
     <profile_created_time>1274439432448060</profile_created_time>
     <progress_time>0</progress_time>
     <progress_media_time>0</progress_media_time>
     <answered_time>0</answered_time>
     <hangup_time>1274439438418776</hangup_time>
     <resurrect_time>0</resurrect_time>
     <transfer_time>0</transfer_time>
   </times>
 </cdr>

  解析方法类似如下:

 [HttpPost]
        public void CDR(string uuid)
        {
            var auth = ASCIIEncoding.ASCII.GetString(
                       Convert.FromBase64String(Request.Headers["AUTHORIZATION"]));

            // TODO: Using auth check against your DB or whatever if user:pass is authorized.

            // Get the xml from the input stream.
            StreamReader r = new StreamReader(Request.InputStream);
            string xml = r.ReadToEnd();
            // Strips some unwanted chars.
            xml.Substring(4, xml.Length - 4);

            // Parse the string. Used XElement below but you could use XmlDocument also.
            XElement elm = XElement.Parse(xml);

            // Now using xpath or LINQ grab the element values you need.
            // For ex: YOUR_ELEMENT could = variables/hangup_cause.
            string selectedElm = Uri.UnescapeDataString(elm.XPathSelectElement("//" + "YOUR_ELEMENT").Vmialue); 
        }

更详细的说明, 请猛戳:http://wiki.freeswitch.org/wiki/Mod_xml_cdr  


完结!




你可能感兴趣的:(freeswitch离线对帐话单的产生及保存方式及配置说明)