调用文件,如果 webservice 这么说则取消调用

Call files, cancel call if webservice say so

我正在尝试开发一个提醒系统,该系统会自动调用以提醒人们注意特定事件。为此,我使用 Asterisk 进行调用,并使用 PHP 为 Asterisk 创建一个调用文件。我希望调用文件在添加后 30 秒执行。为此,我在 PHP 脚本中设置了修改后的时间戳。 一切都很好,除了我想 运行 再次检查 Web 服务以确定它是否仍然与调用用户相关。

这是我的 PHP 脚本

<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        $request = json_decode(file_get_contents("php://input"));

        $tmpcallfile = tempnam("/tmp", "call");
        $callfile = tempnam("/var/spool/asterisk/outgoing/", "call");

        $fh = fopen($tmpcallfile, "w");
        fwrite($fh, "Channel: SIP/voxbeam_outbound/" . $request->{'ToPhoneNumber'} . "\n");
        fwrite($fh, "CallerID: " . $request->{'FromPhoneNumber'} . "\n");
        fwrite($fh, "MaxRetries: 3\n");
        fwrite($fh, "RetryTime: 5\n");
        fwrite($fh, "Context: remind_event\n");
        fwrite($fh, "Extension: 111\n");
        fwrite($fh, "Priority: 1\n");
        fwrite($fh, "Archive: Yes\n");

        fclose($fh);

        touch($tmpcallfile, time()+30);

        rename($tmpcallfile, $callfile);
}
?>

我的想法是在 extensions.conf.

中使用 curl 简单地调用 Web 服务
[voxbeam_outbound]
exten => _X.,1,NoOp()
        same => n,Answer
        same => n,Dial(SIP/voxbeam_outbound/${EXTEN})

[remind_event]
exten => _X.,1,Answer
        same => n,Set(status=${CURL(http://localhost/ShouldRemindEvent)})
        same => n,GotoIf($["${status:0:1}" != "1"]?10)
        same => n,Dial(SIP/voxbeam_outbound/${EXTEN})
        same => n,Playback(remind_event)
        same => n,Hangup

        same => 10,Hangup

我想如果我检查网络服务然后转到 10 挂断,如果网络服务回复 1 以外的任何内容。但出于某种原因它确实调用了。

为了完整性,这里还在 sip.conf 中添加了一些行,尽管我猜这些实际上是不相关的:

[voxbeam_outbound]
type=peer
insecure=invite,port
nat=no
canreinvite=no
username=<hidden>
secret=<hidden>
host=<hidden>
context=voxbeam_outbound

所以问题是,我能不能像这样简单地做,或者我是否需要编写一个 AGI 脚本才能实现我想要的?

我意识到这是编程和配置之间的混合,我认为这最适合 Whosebug 而不是超级用户,因为它是我正在构建的应用程序并且涉及编程。

编辑:根据@arheops 的建议,我尝试使用 Local

进行调用

php 脚本中的新行,还在我想要到达的最终 phone 号码中添加了一个 PHONE_NUMBER 变量,尽管我可以在拨号方案脚本中使用它

fwrite($fh, "Channel: Local/0@remind_event\n");
...
fwrite($fh, "SetVar: PHONE_NUMBER=" . $request->{'ToPhoneNumber'} . "\n");

在 extensions.conf

的拨号方案脚本中新增 remind_event
[remind_event]
exten => 0,1,NoOp()
       same => n,Dial(SIP/voxbeam_outbound/${PHONE_NUMBER})
       same => n,Playback(remind_event)
       same => n,Hangup

但根据 asterisk 的详细日志,它似乎仍然失败

Connected to Asterisk 13.16.0 currently running on hostname (pid = 22261)
    -- Attempting call on Local/0@remind_event for 111@remind_event:1 (Retry 1)
    -- Called 0@remind_event
    -- Executing [0@remind_event:1] NoOp("Local/0@remind_event-00000000;2", "") in new stack
    -- Executing [0@remind_event:2] Dial("Local/0@remind_event-00000000;2", "SIP/voxbeam_outbound/+467<hidden>") in new stack
  == Using SIP RTP CoS mark 5
    -- Called SIP/voxbeam_outbound/+467<hidden>
    -- SIP/voxbeam_outbound-00000000 is making progress passing it to Local/0@remind_event-00000000;2
    -- Local/0@remind_event-00000000;1 is making progress
       > 0xffa3a0 -- Probation passed - setting RTP source address to <hidden ip>:15476
    -- SIP/voxbeam_outbound-00000000 requested media update control 26, passing it to Local/0@remind_event-00000000;2
    -- SIP/voxbeam_outbound-00000000 requested media update control 26, passing it to Local/0@remind_event-00000000;2
    -- SIP/voxbeam_outbound-00000000 is ringing
    -- Local/0@remind_event-00000000;1 is ringing
    -- SIP/voxbeam_outbound-00000000 answered Local/0@remind_event-00000000;2
    -- Local/0@remind_event-00000000;1 answered
[Aug  1 12:18:15] WARNING[22326][C-00000001]: pbx.c:4414 __ast_pbx_run: Channel 'Local/0@remind_event-00000000;1' sent to invalid extension but no invalid handler: context,exten,priority=remind_event,111,1
[Aug  1 12:18:15] NOTICE[22326][C-00000001]: pbx_spool.c:460 attempt_thread: Call completed to Local/0@remind_event
    -- Channel SIP/voxbeam_outbound-00000000 joined 'simple_bridge' basic-bridge <988269c4-fbe9-439f-b0a9-22af873d5118>
    -- Channel Local/0@remind_event-00000000;2 joined 'simple_bridge' basic-bridge <988269c4-fbe9-439f-b0a9-22af873d5118>
    -- Channel Local/0@remind_event-00000000;2 left 'simple_bridge' basic-bridge <988269c4-fbe9-439f-b0a9-22af873d5118>
  == Spawn extension (remind_event, 0, 2) exited non-zero on 'Local/0@remind_event-00000000;2'
    -- Channel SIP/voxbeam_outbound-00000000 left 'simple_bridge' basic-bridge <988269c4-fbe9-439f-b0a9-22af873d5118>

你的调用文件有重试参数,所以它认为调用失败并重试。

这里有 3 个选项

1) 删除不需要的文件

2) 挂断前接听电话。

3) 删除重试。

呼叫文件非常适合安排,但我会使用 PHP AGI 而不是拨号计划来完成 Web 端。

您可以让呼叫文件使用目标 phone 号码和查询 Web 服务所需的任何参数(用户 ID、电子邮件等)拨打本地分机。然后 AGI 执行 curl 请求,您可以继续从 AGI 内部拨号。我猜这对你来说比拨号方案更舒服。它会消除您的 "for some reason it does X" 部分的困惑,因为您可以直接控制 PHP 调用,并且可以从您的 AGI 脚本中记录到文件。

您还可以执行更高级的 API 查询,例如需要身份验证令牌的外部 API 查询、处理更复杂的输出等。

这里有一些有助于您入门的链接:

AGI library links(我个人比较喜欢PHPAGI)

PHP cURL docs

从 Asterisk 社区得到了一些很大的帮助。主要问题是需要两个上下文,一个用于通话的每一段。

  • 使用 Dial 进行呼叫的一个上下文(下面的message_dial)
  • 播放声音文件的另一个上下文。 (下方留言)

这是有效的 extensions.conf 文件。只需在 message_dial 中的拨号规则中的拨号命令之前添加任何条件:

[message_dial]
exten => s,1,NoOp()
        same => n,Dial(SIP/voxbeam_outbound/${PHONE_NUMBER})

[message]
exten => s,1,NoOp()
        same => n,Playback(message)
        same => n,Hangup

调用文件可能如下所示

Channel: Local/s@message_dial
CallerID: +46<hidden>
MaxRetries: 3
RetryTime: 15
Context: message
Extension: s
Priority: 1
Archive: Yes
SetVar: PHONE_NUMBER=+46<hidden>

所以看看最终的解决方案,对于任何精通 Asterisk 的人来说,实现起来真的很简单。

为此,我宁愿使用带有本地通道和 AGI 的原始 AMI 操作。另一个不错的选择是 ARI,让你用星号做任何你想做的事。

我正在使用 AJAM 或 phpAMI 或 PAMI。你必须考虑到这一点。