需要帮助在出站呼叫中获取 Twilio X-Twilio-CallSid 或 X-Twilio-RecordingSid
Need help getting Twilio X-Twilio-CallSid or X-Twilio-RecordingSid on outbound calls
我们正在将调用与 Twilio 的记录 Sids 一起记录到数据库中,并且由于 Asterisk 仅根据请求(而不是响应)将 Twilio 的 sip-headers 暴露给拨号方案,我们无法获得 headers X-Twilio-CallSid 和 X-Twilio-RecordingSid 在远端通道上。
在由 Twilio 的本地分机发起并被 BYE 消息来自我们本地的原始分机挂断的呼叫中,Asterisk 所看到的只是 SIP 响应。
任何人都可以通过拨号方案或 PHP AGI 脚本帮助获得 CallSid 或 RecordingSid 吗?
我们尝试在被调用的通道 (far-end) 上放置一个 gosub 例程,这允许我们访问该通道上的变量,但是可用的 SIP headers 仅来自 Asterisk 的 INVITE。来自 Twilio 回复的 headers 中的 None 曾经暴露过。除非 Twilio 发送 BYE 请求,在这种情况下,挂断处理程序将公开 CallSid 和 RecordingSid。但是,如果 Asterisk 挂断电话,Asterisk 生成的 BYE 消息会在 asterisk 收到所需的 Twilio SIP 响应 headers 之前触发挂断处理程序。
PHP 带有 gosub 例程的 AGI DialScript。
$agi->exec("Dial", "SIP/twilio-out/+1$call->dnid,180,rU(far-channel-hangup-hook,".$call->calllog_listid.")");
Dial-Plan 设置 (extensions.conf)
[far-channel-hangup-hook]
exten => s,1,Set(calllog_listid=${ARG1})
exten => s,n,Set(CHANNEL(hangup_handler_push)=far-channel-hangup,s,1)
exten => s,n,Return()
[far-channel-hangup]
exten => _.!,1,AGI(log_sid.php)
exten => _.!,n,Return()
这个问题很难解决。在您发起的呼叫中,Twilio 在对您的初始 INVITE 的 200 OK 响应中首先提供 CallSid。由于它只是一个响应,Asterisk 将不允许您通过 SIP_HEADER() 访问 SIP header。
你是对的,如果 Asterisk 发起呼叫,你可以安装一个 hangup-handler,它会在挂断电话时触发,如果 Twilio 发送 BYE,你将拥有对 "X-Twilio" headers 在你的处理程序中,但如果 Asterisk 用它自己的 BYE 终止调用则不是。但是,如果您可以在对话生命周期中的某个时间将 Twilio-CallSid 哄出 Asterisk,则可以在 hangup-handler 中使用 cURL 来获取有关该对话框的更多信息根据 CallSid 记录的呼叫。
Twilio documentation 说明您可以将带有 CallSid 的 HTTP GET 请求发送到他们的录音 API 并获取有关录音的信息。
curl -X GET -https://video.twilio.com/v1/Recordings/RMXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' -u ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:your_auth_token
在您的 PHPAGI 代码中,您可以这样做:
$recording_object = NULL;
$accountsid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
$auth_token = "xxxxxxxxxxxxxxxxxxx"; // Your API access auth token
$cidurl = "https://api.twilio.com/2010-04-01/Accounts/$accountsid/Calls/$CallSid/Recordings.json";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $cidurl);
curl_setopt($ch, CURLOPT_USERPWD, "$accountsid:$auth_token");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$retval = curl_exec($ch);
$obj = json_decode($retval);
curl_close($ch);
if ($obj) {
if (property_exists($obj, "recordings")) {
$recording_object = $obj->recordings;
}
}
并且您将能够通过以下方式访问 RecordingSid 和 RecordingDuration:
$recording_object->sid
和
$recording_object->duration
(如果 $recording_object 不为 NULL)
现在,要在呼叫(SIP 对话)中更早地实际获取 X-Twilio-CallSid 是更加棘手的地方。
我总是从源代码构建 Asterisk。这很容易。甚至还有脚本可以根据您的 Linux Distro 存储库为您安装依赖项。
Here is an example for CentOS.
以下是我为解决此问题所做的工作。现在有两个 SIP 通道 driver 随 Asterisk "chan_sip" 和 "chan_pjsip" 一起提供。我使用 chan_sip,较旧的(成熟、可靠的)渠道 driver。效果很好。
如果您下载了 Asterisk 的源代码,并且在按照 above-referenced 指南中的步骤进行操作之前,请找到文件 "chan_sip.c"。通常在目录/channels
编辑文件。
在该文件中,有一个名为 handle_response() 的函数。
/*! \brief Handle SIP response in dialogue
\note only called by handle_incoming */
static void handle_response(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, uint32_t seqno)
搜索该函数。
在该函数内,搜索第一个 switch 语句,然后按照代码找到 "case 200:" 条件。
它应该类似于以下内容:
case 200: /* 200 OK */
p->authtries = 0; /* Reset authentication counter */
if (sipmethod == SIP_INVITE) {
handle_response_invite(p, resp, rest, req, seqno);
} else if (sipmethod == SIP_REGISTER) {
handle_response_register(p, resp, rest, req, seqno);
} else if (sipmethod == SIP_SUBSCRIBE) {
ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
handle_response_subscribe(p, resp, rest, req, seqno);
} else if (sipmethod == SIP_BYE) { /* Ok, we're ready to go */
pvt_set_needdestroy(p, "received 200 response");
ast_clear_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
}
break;
将其更改为如下所示:
case 200: /* 200 OK */
p->authtries = 0; /* Reset authentication counter */
if (sipmethod == SIP_INVITE) {
const char *twilio_callsid = sip_get_header(req, "X-Twilio-CallSid");
if (twilio_callsid) {
ast_verb(1, "** Setting channel variable 'twiliocallsid' to '%s'\n", twilio_callsid);
pbx_builtin_setvar_helper(owner, "twiliocallsid", twilio_callsid);
}
handle_response_invite(p, resp, rest, req, seqno);
} else if (sipmethod == SIP_REGISTER) {
handle_response_register(p, resp, rest, req, seqno);
} else if (sipmethod == SIP_SUBSCRIBE) {
ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
handle_response_subscribe(p, resp, rest, req, seqno);
} else if (sipmethod == SIP_BYE) { /* Ok, we're ready to go */
pvt_set_needdestroy(p, "received 200 response");
ast_clear_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
}
break;
保存文件。然后按照步骤构建和安装 Asterisk。
现在,一旦 Twilio 回答您的 INVITE,并发送一个 200 OK ,其中将包含 X-Twilio-CallSid chan_sip 将其设置为一个名为 的通道变量 "twiliocallsid" 并且可以从拨号计划或您的 PHPAGI 脚本访问它。您可以获得 CallSid,并在对 Twilio 的 cURL 查询中使用它来获取录音信息并根据需要保存它。
我对此不是很确定,但是如果您已经安装了 Asterisk,您可能 仍然可以关闭它,转到包含源代码的目录和 运行 "make install"。其他人可能对此有意见,但是当您从源代码构建和安装它时,仅此而已。您可以根据需要修改源代码并编译使用 "make install".
修改的内容
然后停止,重启 Asterisk 就可以了!
不修改源码也是可以的
为此,您使用了 iptables 操作 NLOG。
像这样
iptables -I INPUT -p udp --dport 5060 -m string --string "X-Twilio-" --algo bm -j NFLOG
之后你需要通过脚本 nflog 读取,解析它,将记录保存在某处并捕获它。
tcpdump -i nflog -s0 -vvv -n|script here
脚本可以使用 callid 作为键将结果存储在 memcached 或 mysql 中,之后您可以在您的 asterisk 拨号方案中捕获它。
不要忘记项目 wiki 中的文档解决方案。我的经验表明从备份恢复时很容易错过这样的更改(尤其是在星号源中)。
我们正在将调用与 Twilio 的记录 Sids 一起记录到数据库中,并且由于 Asterisk 仅根据请求(而不是响应)将 Twilio 的 sip-headers 暴露给拨号方案,我们无法获得 headers X-Twilio-CallSid 和 X-Twilio-RecordingSid 在远端通道上。
在由 Twilio 的本地分机发起并被 BYE 消息来自我们本地的原始分机挂断的呼叫中,Asterisk 所看到的只是 SIP 响应。
任何人都可以通过拨号方案或 PHP AGI 脚本帮助获得 CallSid 或 RecordingSid 吗?
我们尝试在被调用的通道 (far-end) 上放置一个 gosub 例程,这允许我们访问该通道上的变量,但是可用的 SIP headers 仅来自 Asterisk 的 INVITE。来自 Twilio 回复的 headers 中的 None 曾经暴露过。除非 Twilio 发送 BYE 请求,在这种情况下,挂断处理程序将公开 CallSid 和 RecordingSid。但是,如果 Asterisk 挂断电话,Asterisk 生成的 BYE 消息会在 asterisk 收到所需的 Twilio SIP 响应 headers 之前触发挂断处理程序。
PHP 带有 gosub 例程的 AGI DialScript。
$agi->exec("Dial", "SIP/twilio-out/+1$call->dnid,180,rU(far-channel-hangup-hook,".$call->calllog_listid.")");
Dial-Plan 设置 (extensions.conf)
[far-channel-hangup-hook]
exten => s,1,Set(calllog_listid=${ARG1})
exten => s,n,Set(CHANNEL(hangup_handler_push)=far-channel-hangup,s,1)
exten => s,n,Return()
[far-channel-hangup]
exten => _.!,1,AGI(log_sid.php)
exten => _.!,n,Return()
这个问题很难解决。在您发起的呼叫中,Twilio 在对您的初始 INVITE 的 200 OK 响应中首先提供 CallSid。由于它只是一个响应,Asterisk 将不允许您通过 SIP_HEADER() 访问 SIP header。
你是对的,如果 Asterisk 发起呼叫,你可以安装一个 hangup-handler,它会在挂断电话时触发,如果 Twilio 发送 BYE,你将拥有对 "X-Twilio" headers 在你的处理程序中,但如果 Asterisk 用它自己的 BYE 终止调用则不是。但是,如果您可以在对话生命周期中的某个时间将 Twilio-CallSid 哄出 Asterisk,则可以在 hangup-handler 中使用 cURL 来获取有关该对话框的更多信息根据 CallSid 记录的呼叫。
Twilio documentation 说明您可以将带有 CallSid 的 HTTP GET 请求发送到他们的录音 API 并获取有关录音的信息。
curl -X GET -https://video.twilio.com/v1/Recordings/RMXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' -u ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:your_auth_token
在您的 PHPAGI 代码中,您可以这样做:
$recording_object = NULL;
$accountsid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
$auth_token = "xxxxxxxxxxxxxxxxxxx"; // Your API access auth token
$cidurl = "https://api.twilio.com/2010-04-01/Accounts/$accountsid/Calls/$CallSid/Recordings.json";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $cidurl);
curl_setopt($ch, CURLOPT_USERPWD, "$accountsid:$auth_token");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$retval = curl_exec($ch);
$obj = json_decode($retval);
curl_close($ch);
if ($obj) {
if (property_exists($obj, "recordings")) {
$recording_object = $obj->recordings;
}
}
并且您将能够通过以下方式访问 RecordingSid 和 RecordingDuration:
$recording_object->sid
和
$recording_object->duration
(如果 $recording_object 不为 NULL)
现在,要在呼叫(SIP 对话)中更早地实际获取 X-Twilio-CallSid 是更加棘手的地方。
我总是从源代码构建 Asterisk。这很容易。甚至还有脚本可以根据您的 Linux Distro 存储库为您安装依赖项。
Here is an example for CentOS.
以下是我为解决此问题所做的工作。现在有两个 SIP 通道 driver 随 Asterisk "chan_sip" 和 "chan_pjsip" 一起提供。我使用 chan_sip,较旧的(成熟、可靠的)渠道 driver。效果很好。
如果您下载了 Asterisk 的源代码,并且在按照 above-referenced 指南中的步骤进行操作之前,请找到文件 "chan_sip.c"。通常在目录/channels
编辑文件。
在该文件中,有一个名为 handle_response() 的函数。
/*! \brief Handle SIP response in dialogue
\note only called by handle_incoming */
static void handle_response(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, uint32_t seqno)
搜索该函数。
在该函数内,搜索第一个 switch 语句,然后按照代码找到 "case 200:" 条件。
它应该类似于以下内容:
case 200: /* 200 OK */
p->authtries = 0; /* Reset authentication counter */
if (sipmethod == SIP_INVITE) {
handle_response_invite(p, resp, rest, req, seqno);
} else if (sipmethod == SIP_REGISTER) {
handle_response_register(p, resp, rest, req, seqno);
} else if (sipmethod == SIP_SUBSCRIBE) {
ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
handle_response_subscribe(p, resp, rest, req, seqno);
} else if (sipmethod == SIP_BYE) { /* Ok, we're ready to go */
pvt_set_needdestroy(p, "received 200 response");
ast_clear_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
}
break;
将其更改为如下所示:
case 200: /* 200 OK */
p->authtries = 0; /* Reset authentication counter */
if (sipmethod == SIP_INVITE) {
const char *twilio_callsid = sip_get_header(req, "X-Twilio-CallSid");
if (twilio_callsid) {
ast_verb(1, "** Setting channel variable 'twiliocallsid' to '%s'\n", twilio_callsid);
pbx_builtin_setvar_helper(owner, "twiliocallsid", twilio_callsid);
}
handle_response_invite(p, resp, rest, req, seqno);
} else if (sipmethod == SIP_REGISTER) {
handle_response_register(p, resp, rest, req, seqno);
} else if (sipmethod == SIP_SUBSCRIBE) {
ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
handle_response_subscribe(p, resp, rest, req, seqno);
} else if (sipmethod == SIP_BYE) { /* Ok, we're ready to go */
pvt_set_needdestroy(p, "received 200 response");
ast_clear_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
}
break;
保存文件。然后按照步骤构建和安装 Asterisk。
现在,一旦 Twilio 回答您的 INVITE,并发送一个 200 OK ,其中将包含 X-Twilio-CallSid chan_sip 将其设置为一个名为 的通道变量 "twiliocallsid" 并且可以从拨号计划或您的 PHPAGI 脚本访问它。您可以获得 CallSid,并在对 Twilio 的 cURL 查询中使用它来获取录音信息并根据需要保存它。
我对此不是很确定,但是如果您已经安装了 Asterisk,您可能 仍然可以关闭它,转到包含源代码的目录和 运行 "make install"。其他人可能对此有意见,但是当您从源代码构建和安装它时,仅此而已。您可以根据需要修改源代码并编译使用 "make install".
修改的内容然后停止,重启 Asterisk 就可以了!
不修改源码也是可以的
为此,您使用了 iptables 操作 NLOG。
像这样
iptables -I INPUT -p udp --dport 5060 -m string --string "X-Twilio-" --algo bm -j NFLOG
之后你需要通过脚本 nflog 读取,解析它,将记录保存在某处并捕获它。
tcpdump -i nflog -s0 -vvv -n|script here
脚本可以使用 callid 作为键将结果存储在 memcached 或 mysql 中,之后您可以在您的 asterisk 拨号方案中捕获它。
不要忘记项目 wiki 中的文档解决方案。我的经验表明从备份恢复时很容易错过这样的更改(尤其是在星号源中)。