您的位置 首页 > 德语词汇

asterisk是什么意思?用法、例句,著名开源软件架构设计剖析系列1:Asterisk

其实asterisk是什么意思?用法、例句的问题并不复杂,但是又很多的朋友都不太了解著名开源软件架构设计剖析系列1:Asterisk,因此呢,今天小编就来为大家分享asterisk是什么意思?用法、例句的一些知识,希望可以帮助到大家,下面我们一起来看看这个问题的分析吧!

asterisk是什么意思?用法、例句,著名开源软件架构设计剖析系列1:Asterisk

建筑架构和软件架构有很多共同点,但是建筑师在学习期间会观察数以千计的建筑,并研究大师们对这些建筑的评论。相比之下,大多数软件开发设计人员只熟悉少数大型程序——通常是他们自己编写的程序——而很少研究历史上伟大的程序。结果,他们重复彼此的错误,而不是在彼此成功的基础上再接再厉。

本文为《TheArchitectureofOpenSourceApplications》的学习笔记,四十多个著名开源软件的作者深度剖析他们的作品,讲述系统如架构如何设计,为什么这么设计,以及从中获得的经验教训。

Asterisk1是基于GPLv2协议发布的一款开源电话应用平台。简单地说,这是一个服务端程序,用于处理电话的拨出、接入以及自定义流程。Asterisk得名于Unix通配符:*,该项目的宗旨是能做所有与电话相关的事情。如今的Asterisk已经支持一系列用于接拨电话的技术。这些技术包括诸多VoIP(VoiceoverIP,语音IP)协议,与传统电话网络的模/数连接性,以及PSTN(PublicSwithedTelephoneNetwork,公共交换电话网络)。

本节讨论一些跟Asterisk每一部分息息相关的概念。这些思想是Asterisk架构的基础。

通道表示Asterisk系统与某电话端点的一条连接(如图1)。一路电话呼叫接入了Asterisk系统,就用通道表示这一连接。在Asterisk代码中,通道是数据结构ast_channel的实例。图中这个呼叫场景可以视为呼叫方与某一系统应用(比如语音信箱)的交互。

更熟悉的一个呼叫场景是两个电话之间的连接:一个人使用电话A呼叫另一个使用电话B的人。在此场景下,连接到Asterisk系统的有两个电话终端,因而分配了两个通道(如图1.2)。

如上图连接的通道称之为通道桥接。为了实现在通道间传输媒体的目的而把通道连接起来,称为通道桥接。然而,在电话呼叫过程中也可能有视频流或文本流。即使有多种类型的媒体流,也是由Asterisk系统中负责连接两端的通道独立处理。

有两种方法可以完成两个通道的桥接:通用桥接和本地桥接。通用桥接时,无论通道使用什么技术都能够工作,它上层通过Asterisk抽象通道接口传输所有的音频和信号。尽管这是一种最灵活的桥接方式,却是最低效的,因为完成桥接必须有多层抽象。图1.2描述的就是通用桥接。

本地桥接是面向特定技术的通道连接方式。如果连接到Asterisk的两个通道使用相同的媒体传输技术,则势必有一种比通过抽象层更为高效的连接方式,因为抽象层是为使用不同技术的通道之间连接而准备的。例如,如果使用相同专用硬件连接的电话网络,则可以在硬件上直接桥接,这样根本不必通过应用程序向上流动,只有呼叫信号流经Asterisk,通话的媒体流直接连接,高效的多。

在桥接两个通道的时候,系统通过比较两通道的连接技术来决定使用通用桥接还是本地桥接。如果两通道都标识出支持相同的连接方式,那么就用本地桥接;反之使用通用方式。图1.3描述的是本地桥接的一个实例,呼叫信号流经Asterisk传递,媒体流建立直接连接。

在呼叫过程中,Asterisk帧来通信使用帧,帧是数据结构ast_frame的实例。帧可以是媒体帧,也可以是信号帧。在一个基本的呼叫过程中,媒体帧的流包含音频,是通过系统传输的。信号帧则用于发送呼叫事件相关的消息,如按下数字键,挂起电话,挂断电话等。

可用的帧类型是静态定义的。帧由一个编码类型和一个子类型表示。完整列表可在源码文件include.asterisk/frame.h中找到。下面举几个例子:

Asterisk是一款高度模块化的软件。其内核程序可由源码树上的main/目录的源码构建而成。但是内核程序本身作用不大,其主要作用是模块注册。系统还有一些代码负责连接所有抽象接口,使电话呼叫工作起来。这些接口的具体实现是由一些可载入模块在运行时完成注册的。

默认状态下,出于简便性的考虑,当主程序启动时,Asterisk会在文件系统上一个预先指定的目录下找到所有模块,并加载。还有一个可更改的配置文件,可具体指定加载哪些模块及其加载顺序。如果一个模块可从网络接受连接,但实际并不需要用它,那么最好还是不要加载它。

通道驱动接口是Asterisk提供的最复杂且最重要的接口。Asterisk通道API提供了电话协议抽象层,使得其它所有Asterisk特性能够独立于所使用的电话协议而工作。此组件负责在Asterisk通道抽象层与其实现的电话技术细节层面进行转换。

Asterisk通道驱动接口定义称为ast_channel_tech接口。它定义了通道驱动必须实现的一组方法。通道驱动须实现的第一个方法是ast_channel工厂方法,也是ast_channel_tech中的requester方法。当Asterisk为一个接入或拨出的电话呼叫建立通道后,该通道类型对应的ast_channel_tech实现方法负责对ast_channel进行实例化和初始化。

ast_channel实例创建完成后,有一个对其创建者ast_channel_tech的引用,因为还有其他一些针对具体技术的操作需要处理,这些操作必须由*ast_channel*执行,但是实际的处理就需要由ast_channel_tech的适当方法来完成。图1.2表示Asterisk中的两个通道,在图1.4中进行拓展,表示两个桥接通道,以及图中对应的通道技术实现。

ast_channel_tech中最重要的方法有:

呼叫结束后,Asterisk内核中负责抽象通道处理的代码调用*ast_channel_tech*的hangup回调函数,销毁*ast_channel*对象。

Asterisk管理员使用Asterisk拨号计划(存于/etc/asterisk/extensions.conf文件)来设置呼叫路由表。拨号计划是由一系列被称为扩展规则的呼叫规则组成。当有一个电话呼叫接入,系统用被叫号码在拨号计划中查找扩展规则,用以处理本次呼叫。扩展规则包括一组拨号计划应用,由通道执行。拨号计划中可用于执行的应用由一个应用注册表维护,在运行期间,模块被加载填充至注册表。

Asterisk内置近200个应用。应用定义非常松散,并可任意使用系统内部API与通道交互。有些应用执行单个任务,如回放(用于向呼叫方回放一个音频文件);还有一些应用则复杂得多,要执行大量操作,如语音信箱。

你可以集成诸多使用Asterisk拨号计划的应用,用于自定义呼叫处理。如果你需要对内置拨号计划语言的能力做些自定义扩展,系统也有脚本接口,允许使用任意编程语言做自定义呼叫处理。即使通过另一编程语言使用这些脚本接口,也需要调用拨号计划应用来实现与通道交互。

举例说明之前,我们先看一个Asterisk拨号计划的语法,此拨号计划用于处理对号码1234的呼叫。共有3个拨号程序被调用:首先,应答呼叫;其次,回放音频文件;最后,挂断呼叫。

;Definetherulesforwhathappenswhensomeonedials1234.\n;\nexten=>1234,1,Answer()\nsame=>n,Playback(demo-congrats)\nsame=>n,Hangup()

关键字exten用于定义扩展。在exten一行的右侧,1234的意思是我们为呼叫1234定义了一组处理规则;紧接着,1的意思是此号码被拨叫后的第一个处理步骤;最后,Answer指示系统应答此呼叫。下面两行都以关键字same起始,是为最后一个扩展(此例指1234)指定的规则。n是下一步(next)的简写;该行的最后一项指定了采取的动作。

下面是一个Asterisk拨号计划的应用示例。此例做的事情是应答接入的一个呼叫,向呼叫方播放蜂鸣音,然后从呼叫方读入最多4个数字,存入变量DIGITS,接着读入的数字重复播放给呼叫方,最后结束呼叫。

exten=>5678,1,Answer()\nsame=>n,Read(DIGITS,beep,4)\nsame=>n,SayDigits(${DIGITS})\nsame=>n,Hangup()

如前所述,应用定义得非常松散--注册原型非常简单:

int(*execute)(structast_channel*chan,constchar*args);

应用的实现可以使用/asterisk/目录下几乎所有的API。

大多数拨号计划应用接受字符串参数。其中有些值是硬编码,但在某些地方的行为需要有更多的动态处理,这时应使用变量。下面这个例子是一个拨号计划的代码片段,其作用是设置一个变量,并使用Verbose应用在Asterisk命令行界面上打印这个变量值。

exten=>1234,1,Set(MY_VARIABLE=foo)\nsame=>n,Verbose(MY_VARIABLEis${MY_VARIABLE})

调用拨号计划函数的语法与应用相同。Asterisk模块可注册拨号计划函数,取得一些信息并返回给拨号计划;反之,函数也可以从拨号计划中取数据并有所动作。一个通用规则是:拨号计划可设置或获取通道的元数据,但不发任何信号,也不做任何媒体处理,这些工作留给拨号计划应用来做。

下面这个例子展示了拨号计划函数的用法。此函数首先向Asterisk命令行界面打印当前通道的CallerID,然后调用Set应用更改CallerID。此例中,Verbose和Set是应用,CALLERID是函数。

exten=>1234,1,Verbose(ThecurrentCallerIDis${CALLERID(num)})\nsame=>n,Set(CALLERID(num)=<256>555-1212)

CallerID信息存于数据结构*ast_channel*的实例中,不仅仅是一个变量,更多是一个用于信息存储的数据结构。拨号计划函数中的代码能够从这些数据结构中存取数据。

还有一个拨号计划函数的用法示例--在呼叫日志中添加自定义信息,即CDR(呼叫详细记录)。CDR函数允许获取呼叫详细记录信息以及添加自定义信息。

exten=>555,1,Verbose(Timethiscallstarted:${CDR(start)})\nsame=>n,Set(CDR(mycustomfield)=snickerdoodle)

1.2.4编解码转换器

在VOIP领域有许多编解码器用于媒体编码及跨网络发送。多种技术选择为媒体质量、CPU消耗、带宽需求等方面提供了折中方案。Asterisk支持多种不同的编解码器,必要时能够在它们之间进行转码。

Asterisk设置完呼叫后,将会尝试使用公共媒体编解码器来沟通两个端点,这样就不需要转码。然而实际上这种情况不太可能发生。即使使用公共编解码器,也可能需要转码。比如,如果通过配置使Asterisk对流经系统的音频做信号处理(如增大或减小音量),就需要将音频转换为未压缩形式之后,才能执行信号处理。也可以通过配置使Asterisk做呼叫录音。如果配置的录音格式与呼叫的音频格式不同,也需要转码。

用于协商媒体流将使用哪个编解码器的方法和连接到asterisk的通信技术密切相关。在某些情况下,例如在传统电话网络(PSTN)上的呼叫,可能不需要进行任何协商。然而,在其他情况下,尤其是使用IP协议时,会使用一种协商机制来根据能力和偏好需求就编解码器达成一致。

例如,对于SIP(最常用的VOIP协议),从高层视角来看,当呼叫送达Asterisk系统时,编解码器的协调执行如下:

对于更复杂的编解码,尤其是视频方面,Asterisk对此领域处理得还不够好。在过去十年里,编解码器协商需求变得更加复杂。我们还有更多的工作要做,才能更好的处理最新的视频编解码,才能使系统对视频的支持比现在更好。

Asterisk是多线程应用程序,使用POSIX线程API来管理线程,并使用了相关服务,如加锁。所有与线程相关的调用的Asterisk代码都会被包装一层,这样调试会更方便。Asterisk的大多数线程可归类为网络监视线程或通道线程(有时亦称为PBX线程)。

Asterisk的每个主要通道驱动程序中都存在网络监视线程,负责监视任何网络(IP网络,或PSTN,等等)连接,以及接入的呼叫或其它类型的请求。这类线程还要处理连接的建立和初始工作,如认证及拨号验证。呼叫建立完成后,监视线程将创建Asterisk通道(ast_channel)的一个实例,并启动一个通道线程在其生命周期的剩余时间内处理该呼叫。

前面讨论过,通道是Asterisk的基本概念。通道有入站通道和出站通道之分。当有呼叫接入Asterisk系统时,就创建一个入站通道,执行拨号计划。Asterisk为每个入站通道创建一个线程来执行拨号计划。这类线程即被称为通道线程。

拨号计划应用一定是在通道线程的环境中执行。拨号计划函数亦如此。尽管也可能从诸如AsteriskCLI的异步接口读写拨号计划函数,但通常情况下,通道线程仍是ast_channel结构的拥有者,控制着其对象的生命周期。

前两节介绍了Asterisk组件的重要接口以及线程执行模型。本节将分解一些常见的呼叫场景演示Asterisk组件如何协同工作来处理电话呼叫。

有这样一个呼叫场景的示例:呼叫接入电话系统,检查语音信箱。此场景涉及的第一个主要组件是通道驱动。通道驱动负责处理接入系统的电话呼叫请求,此动作发生在通道驱动的监视线程中。实现对系统的呼叫依赖于所使用的电话技术,因而可能会要求某种协商机制来设置呼叫。建立呼叫的另一个步骤是确定呼叫的预期目的地。这通常由呼叫者拨打的号码指定。但是,在某些特殊情况下,没有可用的特定号码,因为用于传递呼叫的技术不支持拨打指定的号码。

如果拨号计划(呼叫路由配置)为拨叫的号码定义了扩展,而通道驱动也查到了Asterisk配置有这样的扩展,系统将分配一个Asterisk通道对象(*ast_channel*),并创建一个通道线程。通道线程主要负责处理呼叫的余下动作。

通道线程的主循环用于处理拨号计划的执行,按照拨号扩展定义的规则执行。下面是一个扩展示例,用拨号计划的语法编写,存于extension.conf文件。有人拨叫**123*时,此扩展应答呼叫,并执行应用VoicemailMain。用户调用此应用就能检查邮箱里的信息。

exten=>*123,1,Answer()\nsame=>n,VoicemailMain()

当通道线程执行应用Answer时,Asterisk就会应答接入的呼叫。应答呼叫除了一些通用的接听处理之外,还需调用关联ast_channel_tech结构中的回调来处理电话接听,这可能会涉及通过IP网络发送特殊数据包、将模拟线路连通等操作。

下一步就是由通道线程执行应用VoicemailMain(如图1.6)。此应用是由*app_voicemail*模块提供的。需要注意:虽然Voicemail代码处理大量呼叫交互,但它对用于将呼叫传送到Asterisk系统的技术一无所知,它只负责语音信箱相关的处理。Asterisk通道的抽象对语音邮件的实现隐藏了这些细节。

为呼叫方提供对语音信箱的访问涉及很多系统功能。然而,所有这些功能主要都实现为读写音频文件响应呼叫方的输入(主要是以数字按键的形式输入)。DTMF数字可以通过多种不同的方式发送给Asterisk系统。同样,这些实现细节都由通道驱动处理。当读入一个按键输入时,Asterisk将其转换为一个通用按键事件,传递给语音信箱代码。

我们讨论过,Asterisk重要接口之一是编解码转换器接口。编解码的实现对于这类呼叫场景而言非常重要。语音信箱代码向呼叫方回放一个音频文件时,Asterisk系统与呼叫方通信使用的音频格式不一定和该音频格式相同。如果需要音频转码,系统会生成一个转码路径,从源格式经一个或多个编解码转换器到目标格式。

在某一时刻,呼叫者完成与语音信箱的交互,挂断了呼叫。这时通道驱动检测到此动作的发生,并将其转换为Asterisk通道的一个通用信号事件。语音信箱代码接收到这一信号事件后退出,因为呼叫方挂断后就没有什么可执行的了。然后通道线程中的控制流程将返回到主循环,继续执行拨号计划。

Asterisk中还有一个很常用的呼叫场景叫做两通道间的呼叫桥接。此场景即一方电话通过系统呼叫另一方电话。呼叫的初始设置过程与前例相同。呼叫设置完毕,通道线程开始执行呼叫计划,之后的处理流程是不同的。

下面这个拨号计划是呼叫桥接的一个简单示例。如果系统使用了此扩展,当一方电话拨叫1234时,拨号计划执行应用Dial,这正是发起出站呼叫的主应用。

exten=>1234,1,Dial(SIP/bob)

Dial应用的参数SIP/bob的含义是,系统应发起一个出站呼叫,发送到设备SIP/bob。此参数的SIP部分指定了传送呼叫应使用SIP协议,bob部分由实现SIP协议的通道驱动*chan_sip*负责解释。假设此通道驱动有一个叫做bob的账户已经配置正确,那么它就知道如何将呼叫送达Bob的电话。

首先,应用Dial要求Asterisk内核根据SIP/bob标识符分配一个新的Asterisk通道。然后,内核请求SIP通道驱动执行针对所用技术的初始化操作。通道驱动也会发起出站呼叫过程。随着请求操作的继续执行,将会有事件传回给Asterisk内核,并由Dial应用接收。这些事件包括呼叫响应、目标忙、网络拥塞、呼叫被拒,或者其它很多可能的响应。理想情况下,呼叫会被应答。当两个通道都有应答时,通道桥接就开始了(如图1.7)。

通道桥接过程中,音频和信号事件由一个通道不断传送至另一通道,直到发生某些导致桥接终止的事件,如一方呼叫挂断。图1.8所示的顺序图阐释了通过呼叫桥接传输音频帧的执行过程。

呼叫完成时,挂断流程与前例很相似。主要不同之处在于此处涉及两个通道。通道线程结束之前,两个通道都要执行对应技术的挂断处理操作。

迄今为止,Asterisk的架构已有十年以上的历史。然而,尽管这个行业在不断发展,Asterisk的一些东西,如通道的基本概念、使用拨号计划进行灵活的呼叫处理,仍然支持着复杂电话系统的开发。有一个领域Asterisk的架构还没有处理的太好,即如何使系统在多服务器间可伸缩。Asterisk开发社区正在开发一个叫做AsteriskSCF(可伸缩通信框架)的伙伴项目,目的就是解决可伸缩性的课题。未来几年,我们期待看到Asterisk以及AsteriskSCF继续称雄电话市场,包括更大型的系统项目。

OK,关于asterisk是什么意思?用法、例句和著名开源软件架构设计剖析系列1:Asterisk的内容到此结束了,希望对大家有所帮助。

本站涵盖的内容、图片、视频等数据,部分未能与原作者取得联系。若涉及版权问题,请及时通知我们并提供相关证明材料,我们将及时予以删除!谢谢大家的理解与支持!

Copyright © 2023