Asterisk Internal Architecture Overview

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().

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().

Created by: knielsen, Last modification: Wed 04 of May, 2005 (10:31 UTC)
Please update this page with new information, just login and click on the "Edit" or "Discussion" tab. Get a free login here: Register Thanks! - Find us on Google+