記事ディレクトリ
1. スキーム設計
FreeSWITCH は、unimrcp モジュールを通じて MRCP サーバーに接続します。このモジュールは、起動時に mrcp プロファイル構成ファイルに基づいて MRCP クライアントを作成します。 MRCP 機能を使用する場合、FreeSWITCH は mrcp プロファイルの名前によって使用する MRCP クライアントを指定し、接続する MRCP サーバーを決定します。 MRCPv2 サーバーの負荷分散スキームの分析では、SIP シグナリングのバランスが取れていれば MRCP 負荷分散が実現できると分析しました。 , 考えられる解決策は次のとおりです。
- FreeSWITCH は、OpenSIPS サーバーを指すように mrcp プロファイルを構成します。プロファイル内の ua 名を mrcp リクエストの識別マークとして設定します。
- OpenSIPS スクリプトは INVITE リクエスト内の ua 名を決定します。それが mrcp リクエストの場合は、それに応じて処理します。
- 対応する mrcp サーバー アドレス レコードを OpenSIPS データベースに挿入し、ディスパッチャー モジュールの ds_select_dst 関数を呼び出して、処理中に mrcp サーバーを選択します。この関数は $du を設定し、$du が指すアドレスにリクエストを転送します。
2. 実施方法
2.1 FreeSWITCHの設定
FreeSWITCHではconf/mrcp_profiles ディレクトリの下に新しい構成ファイルを作成し、OpenSIPS サーバーを指定して UA 名を指定し、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 OpenSIPS 3.1の構成
- なお、著者はここで OpenSIPS のバージョンが 3.1 であることを強調しています。これは、OpenSIPS のバージョンが異なると API に変更が加えられているためであり、バージョンがこの記事で指定されているスクリプト コードと一致しない場合、例外が発生する可能性があります。
- 演習の前に、読者は OpenSIPS がコンパイルされ、ディスパッチャー モジュールでロードされていることを確認する必要があります。OpenSIPS の起動プロセス中にモジュールが見つからないという例外が報告された場合は、ソース コード モジュールを自分でコンパイルし、ソース コード ルート ディレクトリの対応するモジュール ディレクトリに動的ライブラリをコピーできます。
modules目录
例外プロンプトが表示されるディレクトリに移動するだけです。
2.2.1 OpenSIPS は MRCP サーバーのアドレスを保存します
次の SQL ステートメントを実行して、ターゲット MRCP サーバーのアドレス レコードを OpenSIPS データベースのディスパッチャ テーブルに挿入します。この表の setid
はグループ概念の識別子です。このパラメータは、スクリプトで ds_select_dst 関数を呼び出すときに指定する必要があります。ディスパッチャ モジュールのデータベース アドレスがスクリプトで設定されている場合、OpenSIPS は起動時にデータベースからデータをクエリし、メモリにロードします。興味のある読者は、ディスパッチャの公式を参照してください。ドキュメント
ディスパッチャ テーブルはopensips-cli ツールで作成できます。権限の問題により作成できない場合は、作成することもできます。 OpenSIPS ソース コードのルート ディレクトリで、a>
scripts目录
で対応するデータベース タイプのディレクトリを選択し、ディレクトリ内で対応するテーブル作成ファイルを検索します。スクリプト/mysql/dispatcher-create.sql、その内容をデータベースにコピーして実行します
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 スクリプトの開発
スクリプトの主な配布コードは以下の通りで、具体的な処理については前述したため割愛しますが、以下の点に注意が必要です。
- FreeSWITCH によって開始される MRCP INVITE リクエストの場合、$rU は null でなければなりません。スクリプト内でこの変数の null 判定がある場合は、対応する回避を行う必要があります。読者が OpenSIPS の中核となる変数を理解していない場合は、公式ポータルにアクセスしてください。
- OpenSIPS は、スクリプトの起動時に構文チェックを実行します。読者は、まず OpenSIPS をフォアグラウンド モードで起動し、起動ログを観察し、エラー メッセージがあれば 1 つずつ解決していきます。
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;
}