Implementation of OpenSIPS 3.1 load balancing MRCP server

1. Scheme design

FreeSWITCH connects to the MRCP server through the unimrcp module, which creates an MRCP client based on the mrcp profile configuration file when it is started. When using the MRCP function, FreeSWITCH specifies the MRCP client to be used through the name of the mrcp profile, and then determines the MRCP server to connect to. In Analysis of load distribution scheme of MRCPv2 server, the author analyzed that MRCP load balancing can be achieved as long as SIP signaling is well balanced. Based on this, A possible solution is as follows:

  1. FreeSWITCH configures the mrcp profile to point to the OpenSIPS server.Configure the ua name in profile as an identification mark for mrcp requests
  2. The OpenSIPS script determines the ua name in the INVITE request. If it is an mrcp request, handle it accordingly.
  3. Insert the corresponding mrcp server address record in the OpenSIPS database, and call the ds_select_dst function of the dispatcher module to select the mrcp server during processing.This function will populate $du and forward the request to the address pointed to by $du

Insert image description here

2. Implementation method

2.1 FreeSWITCH configuration

In FreeSWITCHconf/mrcp_profiles directoryCreate a new configuration file under , point it to the OpenSIPS server and specify the UA name, then restart FreeSWITCH

<include>
  <!-- UniMRCP Server MRCPv2 -->
  <profile name="opensips-tts-mrcp2" version="2">
    <!-- OpenSIPS 服务器地址 端口号-->
    <param name="server-ip" value="127.0.0.1"/>
    <param name="server-port" value="8060"/>

    <!-- FreeSWITCH IP、端口以及 SIP 传输方式 -->
    <param name="client-ip" value="$${local_ip_v4}" />
    <param name="client-port" value="5072"/>
    <param name="sip-transport" value="udp"/>

    <param name="speechsynth" value="speechsynthesizer"/>
    <param name="speechrecog" value="speechrecognizer"/>
    <!-- SIP 请求携带的 ua 名称 -->
    <param name="ua-name" value="OPENSIPS_TTS_MRCP_CLIENT"/> 

    <!-- Add any default MRCP params for SPEAK requests here -->
    <synthparams>
    </synthparams>

    <!-- Add any default MRCP params for RECOGNIZE requests here -->
    <recogparams>
      <!--param name="start-input-timers" value="false"/-->
    </recogparams>
  </profile>
</include>

2.2 Configuration of OpenSIPS 3.1

  1. Note that the author here emphasizes that the OpenSIPS version is 3.1. This is because the APIs of different versions of OpenSIPS have changes. If the version does not match the script code given in this article, an exception is likely to occur.
  2. Before practice, readers must ensure that OpenSIPS has been compiled and loaded with the dispatcher module.If an exception that the module cannot be found is reported during the startup process of OpenSIPS, you can compile the source code module yourself, and then copy the so dynamic library in the corresponding module directory in the source code root directorymodules目录 Just go to the directory where the exception prompts
2.2.1 OpenSIPS saves MRCP server address

Execute the following SQL statement to insert the target MRCP server address record into the dispatcher table of the OpenSIPS database. setid in this table is the identifier of the group concept. This parameter needs to be specified when calling the ds_select_dst function in the script. If the database address of the dispatcher module is configured in the script, OpenSIPS will query the data from the database and load it into the memory when it starts. Readers who are interested can refer to dispatcher official documentation

The dispatcher table can be created withopensips-cli tool. If it cannot be created due to permission issues, it can also be created in the OpenSIPS source code root directory Select the corresponding database type directory in a>scripts目录 and search for the corresponding table creation file in the directory, for examplescripts/mysql/dispatcher-create.sql, copy its content to the database and execute it

INSERT INTO `dispatcher` (`setid`, `destination`, `state`, `weight`, `priority`, `attrs`, `description`) VALUES
    (19, 'sip:10.129.39.88:7010', 0, 1, 100, 'pstn=100', 'TTS_MRCP_CLIENT_FS_7010'),
    (19, 'sip:10.129.39.88:7011', 0, 1, 100, 'pstn=100', 'TTS_MRCP_CLIENT_FS_7011');
2.2.2 OpenSIPS script development

The main distribution code of the script is as follows. The specific processing has been mentioned above and will not be repeated here. However, you still need to pay attention to the following points:

  1. For the MRCP INVITE request initiated by FreeSWITCH, $rU must be null. If there is a null judgment on this variable in the script, corresponding avoidance needs to be made. If readers do not understand the core variables of OpenSIPS, they can go to the official portal
  2. OpenSIPS will perform a syntax check on the script when it starts.Readers can first start OpenSIPS in foreground mode and then observe the startup log. If there are any error messages, they can solve them one by one.
route {
    
    
    # 省略无关代码 ...
    if (is_method("INVITE")) {
    
    
        xlog("ua = $ua , callid = $ci, fu = $fu , tu = $tu , ru = $ru , du =$du src:$si, $(rb{sdp.line,m})");
        $var(dlgPingTag) = "Pp";
        if ( $ua == "OPENSIPS_TTS_MRCP_CLIENT" ) {
    
    
               $var(dlgPingTag) = "";  # TTS 的SIP通道不能做 OPTION 探测
        }
        if ( !create_dialog("$var(dlgPingTag)")) {
    
    
            send_reply(500,"Internal Server Error");
            exit;
        }
        if ( $ua == "OPENSIPS_TTS_MRCP_CLIENT" ) {
    
    
             # 指定 setid 为 19,与插入 dispatcher 表的数据相匹配,选择可用的节点
             $var(lbRst) = ds_select_dst(19, 4);
             if($var(lbRst) == -1) {
    
    
                  xlog("Failed by dispatcher group_id: 19");
                  t_reply(480, "MRCP server Unavailable");
                  exit();
             }
             if ( $var(lbRst) > 0) {
    
    
                 $ru = "sip:" + $(du{
    
    uri.host}) + ":" + $dp;
                 xlog("[$fU->$rU] Route to $ru");
             } else {
    
    
                xlog("[$fU->$rU] No available server now");
                t_reply(480, "$var(node_type) Unavailable");
                exit();
             }
        } else {
    
    
            # 其他类型 INVITE 处理 .....
        }
    }
    route(relay);
}

route[relay] {
    
    
    # for INVITEs enable some additional helper routes
    if (isflagset("NAT")) {
    
    
        add_rr_param(";nat=yes");
    } 
    
    if (!t_relay()) {
    
    
        send_reply(500,"Internal Error");
    }
    exit;
}

2.3 Achieve results

Insert image description here

Guess you like

Origin blog.csdn.net/weixin_45505313/article/details/130802700