· KLDP.org · KLDP.net · KLDP Wiki · KLDP BBS ·
Asterisk Docs/Internal Architecture


* Asterisk Internal Architecture Overview
This page tries to present an overview of the Asterisk core.

The information here is based on my study of the Asterisk source at a point (May 2005) where I was a relative newcomer to Asterisk, and needed this information in order to program a new channel driver. Corrections and additions welcome!

* Channels
Call processing in Asterisk is centered around channel drivers. Many channel drivers are included with Asterisk in the channels/ subdirectory; other channel drivers are available separately. Channel drivers handle all the protocol-specific details of ISDN, SIP, and other telephony protocols and interface them to Asterisk.
Some channel drivers (like chan_local and chan_agent) work as “proxy channels” and do not directly interface to real protocols or hardware.

A channel driver is a shared object (.so) file that is loaded dynamically into Asterisk as a module. Modules are usually loaded automatically from modules.conf, but may also be loaded/unloaded explicitly from the CLI with the load and unload commands. Use show channeltypes to list all loaded channel drivers.

A channel driver must export the functions load_module(), unload_module(), usecount(), description(), and key(). Since Asterisk applications are also modules, the example skeleton application in apps/app_skel.c may be useful to get started with channel drivers.

The main task of the module part of the channel driver is to have the load_module() entry point call ast_channel_register() with a pointer to its struct ast_channel_tech. This is what makes the channel driver available in Asterisk.

* Channel Technology Descriptor
The struct ast_channel_tech is the channel technology descriptor and defines the complete behaviour of the channel driver. It includes

    * The type name used to reference the channel (eg. `SIP’); this is used as the part before the slash in Dial(SIP/xxx).
    * Textual description.
    * Set of audio formats supported (ULAW, GSM, …).
    * Callback functions called by Asterisk to initiate and manage calls to and from the channel.

The requester callback is used to reserve a single channel from the driver (some channels like an E1 PRI interface has a limited number of channels available). It calls ast_channel_alloc() to allocate a new struct ast_channel and returns it. It also fills in the tech_pvt field with a pointer to a channel private structure that holds driver-specific data. All other operations on the channel reference the struct ast_channel. The requester callback does not block waiting for I/O. Called by ast_request().

The call callback initiates outgoing calls on the channel. It may block on I/O waiting to get the call established, but it does not wait for the remote end to answer (that is indicated by returning an AST_CONTROL_ANSWER control frame from the read callback). Called by ast_call().

The main call processing happens in the read and write callbacks. A channel does not have a specific OS thread associated with it (though a driver is free to create one for it if necessary). Instead the driver registers one or more file descriptors in the fds field of struct ast_channel. When data becomes available on any of the file descriptors, the read callback is called (via ast_read() to read the data and return an appropriate frame. This includes incoming audio data, but also control frames indicating things like remote answer or hangup; see frame.h for possible frame types. The driver may also inject frames outside of the read callback using ast_queue_frame() or ast_queue_control() (this may require calling ast_channel_alloc(1) to reserve an “alert pipe” if not using zaptel(?)). The write callback is called periodically by Asterisk (via ast_write()) to pass outgoing voice frames to the channel.

* Getting things moving
The is no central “main loop” or kernel thread in Asterisk. Instead, processing is distributed among a number of threads, mainly of two kinds:

    * Dialplan threads, started by ast_pbx_start() to run a single instance/session of the dial plan. Such a thread may control multiple active channels at once, for example when forwarding a call with the Dial or Queue applications.
    * Channel driver monitor threads. Most channel drivers have a single monitor thread that listens for incoming calls. When a call arrives it is passed to ast_pbx_start() to start executing the dialplan.

When a thread is in control of one or more active channels, it must continously call ast_read() and ast_write() on these channels to keep the voice and control frames flowing. Again, there is no central loop in the code where this happens, instead custom read/write loops are used in each instance as appropriate. For example wait_for_answer() in the Dial application, ast_generic_bridge in channel.c to connect two channels during a conversation, and ast_waitstream() in file.c. The ast_waitfor*() family of functions are used in these loops to wait until input is available on a channel, at which point ast_read() is called on that channel (maybe passing the data on to ast_write() on another channel).

* Conclusion
The overall flow of control in Asterisk is as follows:

    * Channel drivers monitor threads listen for incoming calls and starts dialplan threads for each new call with ast_pbx_start().
    * Dialplan threads run applications as specified by the dialplan.
    * Application commands process voice and control frames in processing loops alternating calls to ast_waitfor*() and ast_read()/ast_write(); and initiate new outgoing calls with ast_request() and ast_call().

sponsored by andamiro
sponsored by cdnetworks
sponsored by HP

Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2009-07-04 08:56:03
Processing time 0.0043 sec