当前位置:文档之家› Asterisk核心框架

Asterisk核心框架

Asterisk内核框架Asterisk是一个开源的pbx系统,在公开的资料中,很难找到asterisk 内核系统的详细描述。

因此,很有必要写一篇内核框架的描述文档,作为内部培训文档,相互学习提高。

本文主要从三个层面来描述asterisk内核,即asterisk内核模块、内核启动过程、基本呼叫流程。

一、asterisk内核模块Asterisk由内部核心和外围动态可加载模块组成。

内部核心由以下六个部分组成:PBX交换核心模块(PBX Switching Core)、调度和I/O管理模块(Scheduler and I/O Manager)、应用调用模块(Application Launcher)、编解码转换模块(Codec Translator)、动态模块加载器模块(Dynamic Module Loader)和CDR生成模块(CDR Core)。

外围动态可加载模块包括以App_开始的Applications、以Func_开始的Functions、以Res_开始的Resources、以Chan_开始的channels、以Codec_开始的codec编解码模块等。

1.内核模块1) PBX交换核心模块(PBX Switching Core):l pbx.cpbx.c是asterisk的核心模块,每路呼叫都需要经过它调度。

pbx实现了builtin applications,也就是内置的应用,比如最常见的Answer,Hangup, Background,Wait等等。

struct ast_app是一个关键数据结构,它定义了注册builtin applications的结构。

load_pbx函数用来注册builtin applications和一些命令行CLI命令(每个模块都有些CLI命令)。

该函数在系统启动时被调用。

pbx_exec是Answer/BackGround/Busy/Goto/GotoIf/Hangup/Set等builtin applications的执行入口函数,它被pbx_extension_helper调用。

ast_pbx_start函数是每路呼叫的起点。

2) 调度和I/O管理模块(Scheduler and I/O Manager):l Channel.c:Channel.c/channel.h定义了channel操作的结构体和接口函数。

struct ast_channel_tech结构体是所有channel都要用到的关键结构体,它定义channel操作的一系列回调函数指针,如call、 hangup、answer等。

每个channel模块都会定义ast_channel_tech的实体,并将各自的回调函数赋值给它。

例如 chan_sip.c中定义如下:/*! \brief Definition of this channel for PBX channel registration */static const struct ast_channel_tech sip_tech = {.type = "SIP",.description = "Session Initiation Protocol (SIP)",.capabilities = ((AST_FORMAT_MAX_AUDIO << 1) - 1), .properties = AST_CHAN_TP_WANTSJITTER |AST_CHAN_TP_CREATESJITTER,.requester = sip_request_call,.devicestate = sip_devicestate,.call = sip_call,.hangup = sip_hangup,.answer = sip_answer,.read = sip_read,.write = sip_write,.write_video = sip_write,.indicate = sip_indicate,.transfer = sip_transfer,.fixup = sip_fixup,.send_digit_begin = sip_senddigit_begin,.send_digit_end = sip_senddigit_end,.bridge = ast_rtp_bridge,.send_text = sip_sendtext,.func_channel_read = acf_channel_read,};ast_call、ast_hangup、ast_answer等函数分别实现ast_channel_tech中的call、hangup、answer等回调函数的调用。

struct ast_channel结构体定义了channel的上下文参数,它是每个参与呼叫的channel必不可少的,都会调用ast_channel_alloc来申请ast_channel。

l io.cio.c实现了asterisk跟外部交互时的I/O管理,如chan_sip为了从外部接收SIP信令,调用ast_io_add添加IO接口,并调用ast_io_wait实现外部消息接收。

3)应用调用模块(Application Launcher):在pbx.c中定义了一系列的应用调用接口。

applications模块定义了application回调函数并注册后,在pbx.c中通过应用调用接口回调执行。

应用调用接口的关键函数是pbx_extension_helper,它执行dialplan,在cli上打印“Executing ……”,并抛出ami event事件,同时调用pbx_exec执行application回调函数。

4) 编解码转换模块(Codec Translator):Translate.c:struct ast_translator:编码转换描述结构体,它定义了编码转换的名称、回调函数、运行时选项。

struct ast_trans_pvt:编码转换上下文描述结构体。

ast_register_translator:编码转换注册接口函数,供各编码模块调用,注册struct ast_translator类型的结构体变量。

ast_unregister_translator:编码转换注销函数ast_translate:编码转换的执行函数。

codec_gsm.c/codec_...:对应各种编码的编解码执行模块,如g.711alaw/g.711ulaw/gsm等。

5)动态模块加载器模块(Dynamic Module Loader):该模块主要是Module.h。

Module.h中定义了struct ast_module_info结构,用来保存各模块的注册、注销回调函数,以及模块描述信息。

load_module、unload_module,每个应用模块的注册、注销函数,由各个模块自行定义为static函数。

AST_MODULE_INFO_STANDARD:注册接口、注销接口、模块描述信息等模块信息的登记接口。

它是一个宏定义,动态模块调用它时,首先定义类型为ast_module_info的__mod_info静态结构变量,保存模块信息,并定义__attribute__ ((constructor))__reg_module和__attribute__ ((destructor))__unreg_module,在程序启动和退出时调用。

6)CDR生成模块(CDR Core):Cdr.c:ast_cdr_register:cdr driver注册,供cdr_mysql等调用,注册话单保存的回调函数。

ast_cdr_engine_init:CDR模块初始化,注册cdr status、加载cdr.conf、启动CDR线程。

ast_cdr_detach:产生话单的接口函数,呼叫结束时被调用。

2.外围可加载模块:1)Applications以app_开始的模块,如app_dial.c、app_db.c、app_queue.c、app_record.c、app_meetme.c 等,代码保存在apps目录中。

每个application模块都定义了load_module函数和unload_module函数,分别用来注册和注销application。

load_module函数调用ast_register_application函数,注册application命令,例如app_dial模块注册Dial:res =ast_register_application(app, dial_exec, synopsis, descrip)。

unload_module函数调用ast_unregister_application函数,注销application命令。

每个application模块都会使用AST_MODULE_INFO_STANDARD宏来登记模块信息__mod_info。

AST_MODULE_INFO_STANDARD 将load_module和unload_module注册为回调函数,供module load/unload/reload调用。

2)Channel以chan_开始的模块,如chan_sip.c、chan_h323.c、chan_mgcp.c 、chan_iax2.c、 chan_zap.c等,对应代码保存在channels目录中。

channel注册、注销过程和application基本类似。

由于每个channel需要和外部交互,都会在load_module中启用do_monitor线程来侦听外部tcp/udp端口,接收外部消息。

每个channel也定义了各自的cli命令和Function命令,例如chan_sip 定义了sip debug/history/no/notify/prune/ reload/set/show等cli命令和SIP_HEADER、CHECKSIPDOMAIN、SIPPEER、SIPCHANINFO等 Function命令。

3)Functions以Fun_开始的模块,例如Fun_db.c、func_moh.c、func_cdr.c等,对应代码保存在funcs目录中。

Function注册、注销过程也和application类似。

每个Function模块也定义了各自的Function命令,例如Fun_db.c就定义了DB、DB_EXISTS、DB_DELETE等Function命令。

二、asterisk启动过程主要就main函数讲解asterisk的启动过程:1int main(int argc, char *argv[])23 {45int c;67char filename[80] = "";89char hostname[MAXHOSTNAMELEN] = "";1011char tmp[80];1213char * xarg = NULL;1415int x;1617 FILE *f;1819 sigset_t sigs;2021int num;2223int isroot = 1;2425char *buf;2627char *runuser = NULL, *rungroup = NULL;2829/*保存命令行参数(argv[]->_argv[]),以便程序重启时使用*/ 3031/* Remember original args for restart */3233if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {3435 fprintf(stderr, "Truncating argument size to %d\n", ( (sizeof(_argv) / sizeof(_argv[0])) - 1);3637 argc = sizeof(_argv) / sizeof(_argv[0]) - 1;3839 }4041for (x=0; x<argc; x++)4243 _argv[x] = argv[x];4445 _argv[x] = NULL;4647if (geteuid() != 0)4849 isroot = 0;5051/*命令如果是rasterisk,设置AST_OPT_FLAG_NO_FORK和AST_OPT_FLAG_REMOTE标志位*/5253/* if the progname is rasterisk consider it a remote console */ 5455if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {5657 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | A 5859 }6061/*得到当前主机名,在启动时打印出来*/6263if (gethostname(hostname, sizeof(hostname)-1))6465 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));6667/*获取当前的进程标识*/6869 ast_mainpid = getpid();7071/*建立mu-law和a-law转换表*/7273 ast_ulaw_init();7475 ast_alaw_init();7677/*为FFT逆变换(傅立叶逆变换)做一些初始化,用于在zaptel里进行callerid的DTMF检测*/7879 callerid_init();8081/*初始化内置命令的_full_cmd字符串,并注册常用命令,ast_builtins_init() -> ast_cli_register_multiple() -> ast_cli_register() -> __ast_cli_register() */8283 ast_builtins_init();8485/*初始化base64转换*/8687 ast_utils_init();8889/* tty/tdd初始化*/9091 tdd_init();9293/*设置用户历史命令的保存路径*/9495if (getenv("HOME"))9697 snprintf(filename, sizeof(filename), "%s/.asterisk_history 9899/* Check for options */100101/*检查命令行的输入参数,匹配参数范围是“mtThfFdvVqprRgciInx:U:G:C:L:M:”,不同的参数输入走到不同的case分支处理。

相关主题