现在的位置: 首页 > 综合 > 正文

Asterisk 代码架构概述

2013年08月25日 ⁄ 综合 ⁄ 共 5746字 ⁄ 字号 评论关闭

Asterisk 代码架构概述

 

 

    近日分析Asterisk 1.8源码。Asterisk trunk上有这篇架构描述的文章,根据自己的理解整理一下,以享*友。本人英语水平有限,疏漏难免,请大家指正。听雨轩。

英文出处:http://www.asterisk.org/doxygen/trunk/AsteriskArchitecture.html#ArchInterfaceCodec

 

作者:

RussellBryant <russell@digium.com>

注意:

这篇文档所描述的内容,可能已经过时。为了保证您所获取的信息是最新的,请您确保您使用的文档是从Asterisktrunk上生成的。

 

1    引言

本文档从一个开发者的角度出发,概要描述Asterisk的体系架构。至于详细的API讨论,请参考公开API头文件所关联的文档。本文档假定您了解Asterisk的一些知识,并知道如何使用它。

本文的意图是:从一个高的层次开始了解Asterisk,并逐步深入。它从Asterisk的组件差异开始,最终讨论这些组件在不同应用场景里的协作关系。

文中,提供了很多交叉引用链接,指向相关API的一些引用参考,也可能指向相关的源码链接。

欢迎对本文档的反馈和贡献。请将您的真知灼见发给asterisk开发组的邮件组:http://lists.digium.com/.

 

谢谢,并预祝您享受Asterisk!

2      模块构架

Asterisk是一个高度模块化的应用。在源码的main/目录下,建立了内核应用。然而,它(内核)本身的用处并不是很大。

运行时,Asterisk加载了许多模块。Asterisk的模块都有具体的名称,以标识模块所提供的功能,但是,这些名称没有任何技术意义上的特殊。Asterisk加载一个模块时,模块向内核注册它所提供的功能。整个流程看起来是这样的:

1.   启动Asterisk

2.   Asterisk加载模块

3.   模块跟内核说:嗨,Asterisk,我是一个模块,我能提供XYZ三种功能,用得着的时候要记得我哦。

3    抽象接口类型

Asterisk提供了许多不同类型的接口,具体的模块可以实现这些接口并注册给内核调用。任何模块,都可以注册任意多种的接口。通常,一个模块内整合了某些相关的功能。

本节讨论接口的类型,后续将讨论各种场景下不同组件间的协作关系。

3.1   编码解释器CodecInterpreter

编码解释器接口的实现,提供了两种编码间的转换能力。Asterisk当前只有音频编码转换的能力。

这些模块不了解话务相关的任何信息,也不知为什么要调用它们进行音频转换。它们仅需要知道音频采样率、音频的输入格式、期待的输出格式这些信息。

如果注册了多个编码解释器,那么编码A转换为编码B的过程,就可能有多种不同的转换路径。在(编码)模块加载之后,Asterisk建立一张转换表,表中包含不同translator的转换开销评估值,因此,Asterisk能够找出A转换B的最佳路径。

在源码树中,编码模块通常在codecs/目录下。

已有编码解释器的实现列表,请参考:Module:Codecs

更多编码解释器API的信息,请参考接口定义文件:include/asterisk/translate.h.

内核关于编码解释器的相关实现,参考源码:main/translate.c

3.2   文件格式处理器File
Format Handler

文件格式处理器接口的实现,为Asterisk提供了读写文件的能力。文件格式处理器可以提供音频、视频或图像文件的处理能力。

文件处理器的接口是相当原始的。模块简单地告诉Asterisk内核:它能处理某种具有待定扩展名的文件,比如说".wav"。同时,它还说明读取文件之后,将以编码X的形式提供音频。如果它还提供写文件的能力,那么它还必须说明用它写文件的音频编码要求(即说明它能把什么编码格式的音频编码写成带什么扩展名的文件)

源码树中,文件格式模块通存放常在formats/目录下。

现有的实现,请参考:Module:Media
File Formats

文件格式处理器的API定义信息,请参考头文件:include/asterisk/file.h

内核中,与文件格式相关的实现,请参考:main/file.c

3.3     C API Providers

Asterisk有一些可选的C API。内核API主应用内置的,始终可用。可选CAPI则是由某个模块提供的,只有在相应模块加载后,才可用。某些API的提供方,也提供了它自身的接口,供其它模块实现和注册(接口)。

提供C API的模块,通常存放在res/目录下。

一些提供C API的模块有:

·        res_musiconhold.c

·        res_calendar.c

o   提供一种日历技术接口

·        res_odbc.c

·        res_ael_share.c

·        res_crypto.c

·        res_curl.c

·        res_jabber.c

·        res_monitor.c

·        res_smdi.c

·        res_speech.c

o   提供一种语音识别引擎接口

3.4     Manager Interface
(AMI) Actions

Asterisk管理接口是一个socket接口,用于监视和控制Asterisk。它是建立于主应用的核心功能。继而,其它模块可以向AMI注册自己的action供客户端调用。

AMI注册action的模块,通常提供了某种辅助功能以补充扩展某项主要的功能(这个功能不一定是内核功能,可能是模块自身的功能)。比方说:一个提供电话会议功能的模块,提供了一个管理action接口,用于返回与会者列表。

3.5     CLI Commands

Asterisk CLI主应用实现的命令行管理功能。外围模块可以注册附加的CLI命令。

3.6     Channel
Drivers

Asterisk通道接口是最复杂、最重要的接口。Asterisk通道API提供了电话协议的抽象,这样,所有Asterisk的其它特性,才能不依赖于具体的电话协议。

通道驱动实现的具体接口是ast_channel_tech所封装的接口。一个通道驱动,必须实现执行各种呼叫信令任务的回调函数。比如说,必须实现一个初始化呼叫的方法,实现一个挂断呼叫的方法,等等。数据结构ast_channel是抽象通道数据结构。每个ast_channel实例,有一个关联的ast_channel_tech以标识通道类型。一个ast_channel实例,描述了呼叫中的一条腿(call
leg
的概念,也就是Asterisk与终端设备间的连接概念)

源码中,通道驱动通常在channels/目录里。

当前实现的通道驱动列表,请参考:Module:Asterisk
Channel Drivers

需要进一步了解通道API,请参考头文件include/asterisk/channel.h

内核中,关于ast_channel
API
的实现,则在main/channel.c中。

3.7     桥接技术

桥接,是把两个或多个通道连接在一起的操作。通道,AB的呼叫,用的是简单的双通道桥接,而在三方通话或会议中,用的就是多方桥接技术。

桥接API允许其它模块注册桥接技术。桥接技术的实现,知道如何选择两个(或多个)通道,并将它们连接在一起。具体是怎样发生的,取决于实现。

这些接口的代码,需要在两个(或多个)通道间交换音频,却又不需要知道交换的实现细节。在底层,会议可能由操作系统内核实现(通过DAHDI);也可能由Asterisk的内部方法实现;如果有人实现了硬件扩展模块,还可能用硬件实现。

写这篇文档时,桥接API相对来说还比较新,所以执行桥接应用的操作,还没有全部使用这些API。在拨号计划应用实现里,ConfBridge是在桥接API之上实现的一个会议应用。

桥接技术实现模块,存放在bridges/目录下。

桥接技术的实现列表,请参考:bridges

桥接API的更多信息,请参考头文件:include/asterisk/bridging.hinclude/asterisk/bridging_technology.h.

内核关于桥接技术的实现细节,请参考:main/bridging.c

3.8     CDR处理器

Asterisk内核实现了保留通话记录的功能。这些记录在呼叫处理过程中建立,并缓存在数据结构里。在通话结束时,这些数据结构将被释放。在记录丢弃之前,这些数据会传给已注册的CDR处理器。而处理器则会把记录写入文件或存入DB

通常,CDR模块的代码存放在cdr/目录下。

CDR处理器的实现列表,请参考:Module:CDR
Drivers

CDR API相关的更多信息,请参考头文件include/asterisk/cdr.h

内核中,与CDR相关的实现,请参考main/cdr.c

3.9     CEL处理器

Asterisk内核实现了一个通用的事件系统,这个系统允许Asterisk组件报告事件,订阅事件。呼叫事件记录(CEL)就是建立在事件系统之上的一个应用。

CELCDR有点类似,它们都跟踪通话历史记录。通常CDR记录和呼叫是一一对应的关系;而CEL事件和通话则是多对一的关系。CEL模块和CDR模块看起来很相似。

通常CEL模块存放在cel/目录下。

CEL API相关的更多信息,请参考头文件include/asterisk/cel.h

内核关于CEL API的实现细节,请参考main/cel.c

3.10拨号计划应用(APP)

app实现Asterisk拨号方案中可以与呼叫交互的功能。比如说:在extensions.conf文件中:

exten=>
123,1,NoOp()

在上例中,NoOp是一个APP。当然,实际上NoOp什么事也没做。

这些app使用Asterisk提供的一系列API与通道进行交互。App最重要的任务之一,是源源不断地从通道里读取音频,同时向通道回写音频。完成这一任务的细节,通常隐藏在一个API调用的后面,比如说播放文件或等待用户按键输入。

除了与原先执行应用的通道交互之外,APP有时还能创建额外的通道。比如说:Dial()这个APP会创建一个外呼通道,并将它与入呼通道桥接在一块。有关APP功能的进一步讨论,将在场景细节中展开。

源码中,APP的实现代码通常存放在apps/目录下。

APP的实现列表,请参考:Module:Dial
plan applications

Asterisk内核注册APP相关的API定义信息,请参考头文件:include/asterisk/pbx.h

3.11   拨号计划功能(FUN)

顾名思义,FUNAPP相同,是提供给Asterisk拨号方案用的。FUN在拨号方案中的使用方式,大部分和方案中的变量相同。它们提供读/写接口,还有可选参数。虽然它们行为上和变量类似,但比起简单的文本值,APP的存储和检索要复杂得多了。

比方说:CHANNEL()这个FUN能让您访问当前通道上的数据。

exten=>
123,1,NoOp(This channel has the name: ${CHANNEL(name)})

通常,FUN的实现代码存放在funcs/目录下。

FUN的实现列表,请参考:Module:Dial
plan functions

Asterisk内核注册FUN相关的API定义信息,请参考头文件:include/asterisk/pbx.h

3.12RTP引擎

Asterisk内核提供处理RTP流的API。但是,实际上处理这些流的是实现RTP引擎接口的模块。

RTP引擎的实现代码,存放在/res目录下,通常以res_rtp_为文件名前缀。

3.13   定时接口

Asterisk内核实现了定时API,供需要定时服务的组件调用。比如说,在向主叫方播放语音文件时,插入一个定时器来限定播放时间长度。这些API依赖定时接口的实现来提供稳定可靠的计时源。

通常,这些接口实现的代码可以在res/目录中找到。

定时接口实现列表,请参考:timing_interfaces

与定时API的定义信息,请参考头文件include/asterisk/timing.h

内核的定时API实现代码,请参考main/timing.c

4      Asterisk线程模型

Asterisk是一个多线程应用程序。它用POSIX线程API来管理线程和相碰的服务,比如说锁。Asterisk中,几乎所有与pthread交互相关的代码,都通过一套统一的封装实现,这样可以减少调试和代码量。

Asterisk里的线程,可以划分为以下几种类型“

·        通道线程(有时也称为PBX线程)

·        网络监视线程

·        服务连接线程

·        其它线程

4.1     通道线程

通道是Asterisk的一个基本概念。通道不是inbound的,就是outbound的。呼叫到达Asterisk系统时,创建一个inbound通道。这些通道是Asterisk拨号方案的执行方。每个执行拨号方案的通道,都建立一个线程。这些线程称为通道线程。因为这些线程的主要任务是为inbound呼叫执行Asterisk的拨号方案,所以有时也称它们为PBX线程。

一个通道线程开始只负责一个Asterisk通道。然而,有时一个通道线程里也会有第二个通道的存在。当inbound通道执行了诸如Dial()APP之后,就在inbound线程里创建了一个outbound通道,并在对方应答之后将两个通道桥接在一起。

拨号方案的APP始终在一个通道线程的上下文里执行。FUN也是如此。虽然可以通过AMICLI之类的异步接口读写FUN,但无论如何,通道线程始终是ast_channel数据结构的执行主体。

4.2     网络监视线程

抱歉!评论已关闭.