2019独角兽企业重金招聘Python工程师标准>>>

在asterisk执行拨号计划的业务过程中,我们经常会调用Hangup()这个App来结束呼叫,然而在asterisk中有多处逻辑位置可以调用Hangup(),而且调用此App后,呼叫通道还要继续执行后续的业务逻辑(比如:是否写CDR,是否调用发送短信接口等)。下面我们就来"踩"一下拨号计划中调用Hangup()后的一些"坑"。

在asterisk拨号计划中,主要可以在以下几处位置调用拨号计划的Hangup() App:
1)普通的context段,包含Goto语句跳转的嵌入context段。
2)Macro()宏调用context里面。
3)Gosub()子程序的context里面。
下面来实际测试每种情况,并根据拨号计划的走向得出具体的结论。

1. 普通的context段的情况:
1.1 Hangup()调用和h分机同在一个context中的情况。
1.1.1 拨号计划脚本如下:
[from-internal]
exten => _.,1,NoOp(cid=${CALLERID(num)})
exten => _.,n,Hangup()
exten => h,1,NoCDR()
exten => h,n,Verbose(-----1----)
exten => h,n,Hangup()
1.1.2 用软电话测试执行结果如下:
dotasterisk*CLI> 
  == Using SIP RTP TOS bits 184
  == Using SIP RTP CoS mark 5
    -- Executing [8888@from-internal:1] NoOp("SIP/8001-00000025", "cid=8001") in new stack
    -- Executing [8888@from-internal:2] Hangup("SIP/8001-00000025", "") in new stack
  == Spawn extension (from-internal, 8888, 2) exited non-zero on 'SIP/8001-00000025'
    -- Executing [h@from-internal:1] NoCDR("SIP/8001-00000025", "") in new stack
    -- Executing [h@from-internal:2] Verbose("SIP/8001-00000025", "-----1----") in new stack
-----1----
    -- Executing [h@from-internal:3] Hangup("SIP/8001-00000025", "") in new stack
  == Spawn extension (from-internal, h, 3) exited non-zero on 'SIP/8001-00000025'
dotasterisk*CLI> 
1.1.3  说明:
执行流程很简单,在当前context(8888@from-internal)上执行Hangup()后,直接调到当前context的h分机(h@from-internal),整个过程很自然,无需过多解释。

1.2 用Goto语句跳到下一级,并在下一级中执行Hangup()的情况:
1.2.1 拨号计划脚本如下:
[from-internal]
exten => _.,1,NoOp(cid=${CALLERID(num)})
exten => _.,n,Goto(next-context,${EXTEN},1)
exten => h,1,NoCDR()
exten => h,n,Verbose(-----1----)
exten => h,n,Hangup()

[next-context]
exten => _8.,1,NoOp(come here)
exten => _8.,n,Hangup()
exten => h,1,Verbose(-----2----) ;注:此处是h分机执行代码的开始
exten => h,n,Hangup()

1.2.2 用软电话测试执行结果如下:
dotasterisk*CLI> 
  == Using SIP RTP TOS bits 184
  == Using SIP RTP CoS mark 5
    -- Executing [8888@from-internal:1] NoOp("SIP/8001-0000002a", "cid=8001") in new stack
    -- Executing [8888@from-internal:2] Goto("SIP/8001-0000002a", "next-context,8888,1") in new stack
    -- Goto (next-context,8888,1)
    -- Executing [8888@next-context:1] NoOp("SIP/8001-0000002a", "come here") in new stack
    -- Executing [8888@next-context:2] Hangup("SIP/8001-0000002a", "") in new stack
  == Spawn extension (next-context, 8888, 2) exited non-zero on 'SIP/8001-0000002a'
    -- Executing [h@next-context:1] Verbose("SIP/8001-0000002a", "-----2----") in new stack //注:仅仅执行了当前context的h分机
-----2----
    -- Executing [h@next-context:2] Hangup("SIP/8001-0000002a", "") in new stack
  == Spawn extension (next-context, h, 2) exited non-zero on 'SIP/8001-0000002a'
dotasterisk*CLI> 
1.3.3 说明:
从执行结果看,发现只输出了[h@next-context]里面的Verbose(-----2----),而没有输出上一级[from-internal]里面Hangup()之后的拨号计划。

结论:对于普通context段里面的Hangup() App,不管里面Goto到了多少层级别,只要在某一个context执行的Hangup(),那么就在当前这个context里面寻找h分机,如果有h分机匹配,就执行h分机里面的流程。注意,h分机的拨号计划只在此处context执行,绝不会跳出此处的context,即使是当前context中没有匹配到h分机,也仍然不会跳出此context而去寻找上一级调用Goto()语句的context里面的h分机来执行。举个例子,拨号计划是:
[from-internal]
exten => _.,1,NoOp(cid=${CALLERID(num)})
exten => _.,n,Goto(next-context,${EXTEN},1)
exten => h,1,NoCDR()
exten => h,n,Verbose(-----1----)
exten => h,n,Hangup()

[next-context] ;此段没有匹配h分机
exten => _8.,1,NoOp(come here)
exten => _8.,n,Hangup()
执行结果如下:
dotasterisk*CLI> 
  == Using SIP RTP TOS bits 184
  == Using SIP RTP CoS mark 5
    -- Executing [8888@from-internal:1] NoOp("SIP/8001-00000029", "cid=8001") in new stack
    -- Executing [8888@from-internal:2] Goto("SIP/8001-00000029", "next-context,8888,1") in new stack
    -- Goto (next-context,8888,1)
    -- Executing [8888@next-context:1] NoOp("SIP/8001-00000029", "come here") in new stack
    -- Executing [8888@next-context:2] Hangup("SIP/8001-00000029", "") in new stack  //注:仅仅在这里就停止了,没有跳到上一层context
  == Spawn extension (next-context, 8888, 2) exited non-zero on 'SIP/8001-00000029'
dotasterisk*CLI>

2. Macro()宏里面执行Hangup():
2.1 拨号计划如下:
[from-internal]
exten => _.,1,NoOp(cid=${CALLERID(num)})
exten => _.,n,Macro(m1)
exten => h,1,NoCDR()
exten => h,n,Verbose(-----1----)
exten => h,n,Hangup()

[macro-m1]
exten => s,1,NoOp(come here)
exten => s,n,Hangup()
exten => s,n,MacroExit()
exten => h,1,Verbose(-----2----) ;//此处的h分机永远不会被执行
exten => h,n,Hangup()
2.2 执行结果如下:
dotasterisk*CLI> 
  == Using SIP RTP TOS bits 184
  == Using SIP RTP CoS mark 5
    -- Executing [8888@from-internal:1] NoOp("SIP/8001-0000002b", "cid=8001") in new stack
    -- Executing [8888@from-internal:2] Macro("SIP/8001-0000002b", "m1") in new stack
    -- Executing [s@macro-m1:1] NoOp("SIP/8001-0000002b", "come here") in new stack
    -- Executing [s@macro-m1:2] Hangup("SIP/8001-0000002b", "") in new stack
  == Spawn extension (macro-m1, s, 2) exited non-zero on 'SIP/8001-0000002b' in macro 'm1'
  == Spawn extension (from-internal, 8888, 2) exited non-zero on 'SIP/8001-0000002b'
    -- Executing [h@from-internal:1] NoCDR("SIP/8001-0000002b", "") in new stack //注:没有执行宏里面的h分机
    -- Executing [h@from-internal:2] Verbose("SIP/8001-0000002b", "-----1----") in new stack
-----1----
    -- Executing [h@from-internal:3] Hangup("SIP/8001-0000002b", "") in new stack
  == Spawn extension (from-internal, h, 3) exited non-zero on 'SIP/8001-0000002b'
dotasterisk*CLI> 
2.3 说明:从执行结果看,发现里面执行Hangup()后没有执行宏里面h分机,而是跳到调用宏的普通的context里面的h分机(h@from-internal)中去执行了。
2.4 结论:在宏Macro中一般只执行s分机,定义的h分机永远也不会执行,只会跳到调用处的Macro()代码里面的context去执行,也就是说宏中定义h分机本来就是没意义的。

3. Gosub()子程序里面执行Hangup():
3.1 情况1:sub子程序明确指定了h分机
3.1.1 拨号脚本如下:
[from-internal]
exten => _.,1,NoOp(cid=${CALLERID(num)})
exten => _.,n,Gosub(s1,${EXTEN},1)
exten => h,1,NoCDR()
exten => h,n,Verbose(-----1----)
exten => h,n,Hangup()

[s1]
exten => _.,1,NoOp(come here)
exten => _.,n,Hangup()
exten => _.,n,Return()
exten => h,1,Verbose(-----2----)
exten => h,n,Hangup()
3.1.2 执行结果如下:
dotasterisk*CLI> 
  == Using SIP RTP TOS bits 184
  == Using SIP RTP CoS mark 5
    -- Executing [8888@from-internal:1] NoOp("SIP/8001-0000002c", "cid=8001") in new stack
    -- Executing [8888@from-internal:2] Gosub("SIP/8001-0000002c", "s1,8888,1") in new stack
    -- Executing [8888@s1:1] NoOp("SIP/8001-0000002c", "come here") in new stack
    -- Executing [8888@s1:2] Hangup("SIP/8001-0000002c", "") in new stack
  == Spawn extension (s1, 8888, 2) exited non-zero on 'SIP/8001-0000002c'
    -- Executing [h@s1:1] Verbose("SIP/8001-0000002c", "-----2----") in new stack //注:只执行当前context的h分机,没有调到上一层
-----2----
    -- Executing [h@s1:2] Hangup("SIP/8001-0000002c", "") in new stack
  == Spawn extension (s1, h, 2) exited non-zero on 'SIP/8001-0000002c'
dotasterisk*CLI>

3.2 情况2:sub子程序里面没有h分机
3.2.1 拨号脚本如下:
[s1]
exten => _8.,1,NoOp(come here)
exten => _8.,n,Hangup()
exten => _8.,n,Return()
3.2.2 执行结果如下:
dotasterisk*CLI> 
  == Using SIP RTP TOS bits 184
  == Using SIP RTP CoS mark 5
    -- Executing [8888@from-internal:1] NoOp("SIP/8001-0000002f", "cid=8001") in new stack
    -- Executing [8888@from-internal:2] Gosub("SIP/8001-0000002f", "s1,8888,1") in new stack
    -- Executing [8888@s1:1] NoOp("SIP/8001-0000002f", "come here") in new stack //注:发现直接在这里挂机停止了,end了
    -- Executing [8888@s1:2] Hangup("SIP/8001-0000002f", "") in new stack
  == Spawn extension (s1, 8888, 2) exited non-zero on 'SIP/8001-0000002f'
dotasterisk*CLI>

3.3 结论
goSub的context普通的context执行Hangup() App后后续的拨号计划执行流程规则是一样的。可以这样理解:普通的context和子程序context是一样的,除了子程序context里面可以有Return()语句跳回到上一处拨号计划,其余方面的特性是一模一样的。据测试,通道变量也没有什么变量作用域的概念,在子程序里面一样可以直接用外面的变量,子程序里面设置的变量一样可以带到外面去,不同于其他编程语言里面有什么函数里面有局部变量的概念。同子程序一样,也没有局部变量的概念。关于变量测试代码如下:
[from-internal]
exten => _.,1,NoOp(cid=${CALLERID(num)})
exten => _.,n,Set(varOUT=AA)
exten => _.,n,Gosub(s1,${EXTEN},1)
exten => _.,n,NoOp(--varIN=${varIN}--) ;//可以直接用子程序里面定义的变量,不存在变量作用域的概念
exten => _.,n,WaitExten(100)
exten => h,1,NoCDR()
exten => h,n,Verbose(-----1----)
exten => h,n,Hangup()

[s1]
exten => _8.,1,NoOp(--varOUT=${varOUT}--) ;//可以打印外部变量
exten => _8.,n,Set(varIN=BB) ;//定义的变量,可以带到外部去
exten => _8.,n,Return()
输出结果:
dotasterisk*CLI> 
  == Using SIP RTP TOS bits 184
  == Using SIP RTP CoS mark 5
    -- Executing [8888@from-internal:1] NoOp("SIP/8001-00000031", "cid=8001") in new stack
    -- Executing [8888@from-internal:2] Set("SIP/8001-00000031", "varOUT=AA") in new stack
    -- Executing [8888@from-internal:3] Gosub("SIP/8001-00000031", "s1,8888,1") in new stack
    -- Executing [8888@s1:1] NoOp("SIP/8001-00000031", "--varOUT=AA--") in new stack
    -- Executing [8888@s1:2] Set("SIP/8001-00000031", "varIN=BB") in new stack
    -- Executing [8888@s1:3] Return("SIP/8001-00000031", "") in new stack
    -- Executing [8888@from-internal:4] NoOp("SIP/8001-00000031", "--varIN=BB--") in new stack
    -- Executing [8888@from-internal:5] WaitExten("SIP/8001-00000031", "100") in new stack

转载于:https://my.oschina.net/enjoycti/blog/754063

asterisk拨号计划中Hangup() App执行规则相关推荐

  1. Asterisk拨号方案中变量的应用

    在拨号方案中使用变量可以减少打字.增加清晰度,也有助于在拨号方案中加入逻辑. 这里的变量有全局变量,通道变量和环境变量. 1.全局变量 全局变量应该在extensions.conf文件的开始利用[gl ...

  2. oracle 计划中的view,执行计划里的view

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 FYI Views ===== When a view cannot be merged into the main query you will oft ...

  3. Asterisk拨号方案一

    9|.是去掉号码前面的9, 0755|.是去掉号码前面的0755 X代表一个0-9中的任意一个数字 Z代表一个1-9中的任意一个数字 N代表一个2-9中的任意一个数字 |号代表去掉号码前面的指定数字 ...

  4. Asterisk权威指南/第六章 拨号计划基础

    拨号计划是你的Asterisk系统的心脏.它定义了呼叫是如何流进和流出系统的.拨号计划用一种脚本语言写成的,Asterisk依照其中的指令响应外部触发.和传统电话系统相比,Asterisk的拨号计划是 ...

  5. 《实施Cisco统一通信管理器(CIPT2)》一1.6 拨号计划方面面临的挑战

    本节书摘来异步社区<实施Cisco统一通信管理器(CIPT2)>一书中的第1章,第1.6节,作者: [美]Chris Olsen 译者: 刘丹宁, CCIE#19920 , 卢铭 , 陈国 ...

  6. Microsoft Teams Voice语音落地系列-3 实战:拨号计划的配置

    上一节我们讨论了所有用于Teams语音落地的前置条件准备,一齐来回顾一下: 1) 权限与管理员准备:O365管理员/Teams管理员:SBC管理员:本地Skype管理员:网络管理员:DNS/CA管理员 ...

  7. oracle cost cardinality,ORACLE 执行计划中cost cardinality bytes cpu_cost io_cost解释

    从网上找到的资料,加上我在文档中查到的内容: ■ Cost The cost assigned to each step of the query plan by the CBO. The CBO w ...

  8. oracle 计划中的view,为何执行计划中会出现个VIEW: VM_NWVW_1 ?

    为何执行计划中会出现个VIEW:  VM_NWVW_1 ? 数据库中根本没有这个OBJECT. 也不象系统自己产生的! SELECT R.CREATED_OFFICE STOCK_CODE, R.CU ...

  9. 执行计划中的参数解释

    执行计划中的各个参数解释: 一.Recursive calls (递归调用) 1.参考:Oracle Database Reference, 10g Release 2 (10.2).pdf第916页 ...

最新文章

  1. Python 之 matplotlib (五)Annotation注解
  2. WindowManager如何被Android深度解析(3)
  3. Java 多线程使用
  4. 微信订阅号开发笔记(三)
  5. Three.js中自定义控制几何体的点和面的属性
  6. Gym - 101889I Imperial roads(最小生成树+树链剖分+线段树)
  7. 数据库查询求小于_SQL学习笔记(二)简单查询
  8. 论文致谢走红后,中科院博士回信了!
  9. 4027-计数排序(C++,附解析)
  10. csredis封装_在.NET Core中使用CSRedis
  11. 让你在职场游刃有余的10句话
  12. VS 2005部署应用程序提示“应用程序无法正常启动( 0x0150002)” 解决方案
  13. docker中 system limit for_springboot中redis的缓存穿透问题
  14. MSBuild 命令参数
  15. 数据分析中会常犯哪些错误,如何解决? 三
  16. vrchat模型保存_VRChat简易教程3-往世界里导入模型和VRC接口初探
  17. react实现关于文本框的双向绑定
  18. 360免费wifi的linux驱动下载,360随身wifi驱动
  19. 华为云计算机访问手机软件,手机也能当电脑使用?华为黑科技:手机云电脑
  20. SSM项目使用Mybatis通用mapper插件tk.mybatis的用法

热门文章

  1. 多值依赖与部分函数依赖 转
  2. 多媒体操作系统──BeOS
  3. C语言读取midi文件,《MIDI指令协议格式》.doc
  4. 笔记本电脑英文技术规格解释
  5. Java集合案例图书管理系统
  6. PLP: 4.2/4.3 Attribute Gramma阅读笔记3
  7. 蓝桥杯 算法训练 Tennis Rackets (50%通过)
  8. 机器学习模型中的评价指标
  9. javaweb面向对象
  10. 带你理解面向过程与面向对象