Asterisk 1.4.21.1 Released

The Asterisk.org development team has released Asterisk version 1.4.21.1.

This includes a critical bug fix for 1.4.21. All users that experienced lockups when upgrading to 1.4.21 should have their issues resolved with this update.

Asterisk 1.4.21.1 is available for download from the downloads site:

Thank you for your continued support of Asterisk!

How-to: Write an Asterisk Module, Part 3

Greetings fellow developers!

This is part 3 of a series on implementing the basic interfaces to provide features to Asterisk.

Part 1 – Basic Module Structure
Part 2 – CDR Handling Interface

In this section, you will see how to implement an Asterisk CLI command. CLI commands are extremely useful for showing configuration, statistics, and other debugging purposes.

We are going to continue editing the module from part 2, res_helloworld2.c.

The first step is to include the header file which defines the CLI command interface.

#include "asterisk/cli.h"

Here is the code for a CLI command, “echo”. It simply prints back the first argument to the CLI command. The individual parts of this function will be described later.

static char *handle_cli_echo(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
    switch (cmd) {
    case CLI_INIT:
        e->command = "echo";
        e->usage =
            "Usage: echo <stuff>n"
            "       Print back the first argument.n"
            "Examples:n"
            "       echo foon"
            "       echo "multiple words"n"
            "";
        return NULL;
    case CLI_GENERATE:
        return NULL;
    }

    if (a->argc == e->args) {
        ast_cli(a->fd, "You did not provide an argument to echonn");
        return CLI_SHOWUSAGE;
    }

    ast_cli(a->fd, "%sn", a->argv[1]);

    return CLI_SUCCESS;
}

The first line of this CLI handler matches the defined function prototype for CLI command handlers. The ast_cli_entry argument includes static information about the CLI command being executed. The cmd argument is set when the CLI command is being invoked for a reason other than normal execution from the CLI, which will be explained more later. The ast_cli_args argument contains information specific to this one time execution of the command, like the arguments to the command.

static char *handle_cli_echo(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)

The switch statement at the beginning of the function handles when the cmd argument is set to indicate that the function is being called for a reason other than normal execution. There are two cases handled.

  • CLI_INIT. Every CLI command handler is called one time with a cmd of CLI_INIT. This asks the function to fill in the documentation on what the command is, as well as usage documentation.
  • CLI_GENERATE. This cmd is used for implementing tab completion. CLI commands that provide tab completion of arguments must add code here. Implementing tab completion may be explained in a later tutorial. For now, there are many examples throughout the code.

The next code snippet ensures that at least one argument has been provided to the function. It is worth noting here that the ast_cli_entry argument is used to retrieve how many arguments define the command itself and the ast_cli_args argument is used to retrieve how many arguments were actually specified at the CLI when executing this command. If they are equal, then simply “echo” was provided.

if (a->argc == e->args) {
ast_cli(a->fd, "You did not provide an argument to echonn");
return CLI_SHOWUSAGE;
}

Finally, we print a single argument to the CLI, and return that the execution of the CLI command was successful.

ast_cli(a->fd, "%sn", a->argv[1]);
return CLI_SUCCESS;

The next thing that we have to add is the table of CLI commands included in this module. We will use AST_CLI_DEFINE() to add a single entry to this table. AST_CLI_DEFINE includes the pointer to the CLI command handling function, as well as a brief summary of what the command does.

static struct ast_cli_entry cli_helloworld[] = {
AST_CLI_DEFINE(handle_cli_echo, "Echo to the CLI"),
};

Finally, as discussed in part 2, we have to modify load_module and unload_module to register and unregister the CLI command table with the Asterisk core.

In unload_module, we add this:

ast_cli_unregister_multiple(cli_helloworld, ARRAY_LEN(cli_helloworld));

In load_module, we add this:

ast_cli_register_multiple(cli_helloworld, ARRAY_LEN(cli_helloworld));

That’s it! Recompile and reinstall the module. Take a look at res_helloworld3.c, for the completed code.

You can then try it out.

*CLI> help echo
Usage: echo 
       Print back the first argument.
Examples:
       echo foo
       echo "multiple words"

*CLI> echo
You did not provide an argument to echo

Usage: echo 
       Print back the first argument.
Examples:
       echo foo
       echo "multiple words"

*CLI> echo foo
foo

*CLI> echo hello world
hello

*CLI> echo "hello world"
hello world

How-to: Write an Asterisk Module, Part 2

In part 1, I explained the “Hello World” of Asterisk modules. It implemented just enough to properly compile, get loaded into Asterisk, and print something to the Asterisk log when the module was loaded and unloaded. Now, it’s time to start making modules that do something useful.

In res_helloworld.c, we implemented a load_module and unload_module function. In that module, they just printed to the log. They actually have a much more important purpose in life.

The job of load_module() is to say, “Hello Asterisk, I’m a module. I can provide some features to Asterisk and here is how you use them.”

Conversely, the job of unload module is to say, “Hello Asterisk, again. I’m about to disappear, so please don’t use any of these features that I was providing to you anymore. If you do, you’ll explode. kthx!”

So, it’s time to update this module to provide a feature to Asterisk. We’ll start with a CDR (Call Detail Record) handler. It is one of, if not the simplest interface to implement. To keep things simple, we’re going to implement an Asterisk CDR handler that once again, just uses the Asterisk logging interface.

The first thing to do is to add the appropriate header file so that module has the appropriate definitions for the CDR interface.


#include "asterisk/cdr.h"

Next, we’re going to add a new function. This function will get called every time that there is a new CDR to post. It takes a single argument, which is the CDR itself.

static int cdr_helloworld(struct ast_cdr *cdr)
{
    ast_log(LOG_NOTICE, "We got a CDR for channel '%s'.  "
        "Source: '%s', Dest: '%s', Duration: %ldn",
        cdr->channel, cdr->src, cdr->dst, cdr->duration);

    return 0;
}

Next, as I described before, we have to make the load_module() and unload_module() functions aware of this new feature that is implemented by the module.

In load_module(), we will add a function call to “register” the CDR handler with the Asterisk core. The arguments are the name of the handler, a short description, and the function that the Asterisk core needs to call when a CDR is ready for posting.


ast_cdr_register("HelloWorld", "Hello World CDR Handler", cdr_helloworld);

In unload_module(), we will add a function call to “unregister” the CDR handler form the Asterisk core.


ast_cdr_unregister("HelloWorld");

That’s it! See the finished code here, res_helloworld2.c.

Compile it and install it. When you start Asterisk, you should be able to verify that your new CDR handler has been registered with the Asterisk core.


*CLI> cdr show status
...
CDR registered backend: HelloWorld
...

When you hang up a call, you should see the result of your CDR handler being executed.


[Jun 20 18:08:29] NOTICE[4922]: res_helloworld.c:36 cdr_helloworld: We got a CDR for channel 'SIP/5001-007e9da8'. Source: '5001', Dest: '586', Duration: 1

And now, you have implemented an Asterisk module that adds custom handling of CDR records!

How-to: Write an Asterisk Module, Part 1

Have you ever wanted to write an Asterisk module? While some of the Asterisk modules are quite complicated, the anatomy of an Asterisk module is pretty simple. Let’s start with the “Hello World” of Asterisk modules: res_helloworld.

This example is based on Asterisk 1.6. However, creating Asterisk modules for Asterisk 1.4 is almost the exact same.

Create a file called res_helloworld.c in the res/ directory of an Asterisk source tree.

The first thing in every Asterisk module is to include the main Asterisk header file, asterisk.h.


#include "asterisk.h"

Next, include the ASTERISK_FILE_VERSION macro. This registers the file with the “core show file version” CLI command. This CLI command lists the last SVN revision where that file changed.


ASTERISK_FILE_VERSION(__FILE__, "$Revision: $")

Include the Asterisk module header file. This includes the definitions necessary for implementing an Asterisk module.


#include "asterisk/module.h"

Let’s go ahead and include the header file that lets us use the Asterisk logging interface, as well. This will let us print messages to the Asterisk log so that our new module actually does something.


#include "asterisk/logger.h"

It is now time to include the two functions that every Asterisk module must implement. Those are load_module() and unload_module(). These functions get called when Asterisk loads and unloads the module.


static int load_module(void)
{
ast_log(LOG_NOTICE, "Hello World!n");
return AST_MODULE_LOAD_SUCCESS;
}


static int unload_module(void)
{
ast_log(LOG_NOTICE, "Goodbye World!n");
return 0;
}

Finally, every module must include an instance of one of the AST_MODULE_INFO macros. This macro includes the necessary code for the module to properly register itself with the Asterisk core when it gets loaded.


AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Hello World");

The final result should look something like this: res_helloworld.c

When you run make to compile Asterisk, the build system should automatically find your module. It will be compiled and installed with the rest of Asterisk. Compile, install, and run Asterisk. Then, verify that your module has been loaded:


*CLI> module show like helloworld
Module Description Use Count
res_helloworld.so Hello World 0
1 modules loaded

You should also be able to unload and load your module, and see the appropriate message in the Asterisk logger.


*CLI> module unload res_helloworld.so
[Jun 19 10:50:57] NOTICE[26612]: res_helloworld.c:35 unload_module: Goodbye World!
*CLI> module load res_helloworld.so
[Jun 19 10:51:05] NOTICE[26612]: res_helloworld.c:42 load_module: Hello World!
Loaded res_helloworld.so => (Hello World)

Congratulations! You have successfully written an Asterisk module!

Next, we will start looking at how to start implementing more useful things inside of this module structure.

How-to: Use Dial and Another Application at the Same Time

I spend a lot of time on IRC talking about Asterisk. A lot of questions get answered there but those answers are not archived as well as they are when questions are answered on mailing lists or forums. So, I’ll start posting some questions and answers that come from IRC discussions.

This one is a simple example that shows the usefulness of Local channels in Asterisk.

In #asterisk:

Question: How can I run the Dial() and FollowMe() applications at the same time?

My Answer: It is quite simple. The Dial() application allows you to call multiple channels at the same time. If you use a Local channel, one of the things that you are dialing can be another chunk of dialplan. For example, call 1234:


[default]
exten => 1234,1,Dial(SIP/myphone&Local/followme@default)
exten => followme,1,FollowMe(default)

Here is another common question that can be answered by the use of Local channels:

Question: How do I call a second phone after a first phone has been ringing for some period of time, while still allowing the first phone to ring?

Answer: This can be accomplished by the use of Local channels. Let’s say you want to ring phone2 after phone1 has been ringing for 10 seconds, while still allowing phone1 to ring, as well.


[default]
exten => 1234,1,Dial(SIP/phone1&Local/call_phone2@default)
exten => call_phone2,1,Wait(10)
exten => call_phone2,n,Dial(SIP/phone2)

Asterisk 1.6, Now with a New Timing API

For as long as I have been involved with the project, Asterisk has used DAHDI (Zaptel) to provide timing. This has worked great, since the timing was usually provided by telephony hardware. Then, we had the ztdummy kernel module to provide timing from other parts of the kernel.

However, a lot of people have not been happy with this. Most Asterisk users don’t have telephony hardware to provide timing. Also, ztdummy does not work on all systems. Also, DAHDI was originally only for Linux.

Starting with Asterisk 1.6.1, you will no longer need DAHDI installed at all to get proper timing in Asterisk. There is a new timing API, and there are already two implementations. There is a DAHDI timing interface (res_timing_dahdi) and another (res_timing_pthread) that has no special kernel requirements.

Keep in mind, that MeetMe, the Asterisk conferencing application, still requires DAHDI. MeetMe uses the DAHDI conference mixing. It doesn’t just use it for timing. However, do not worry! Coming soon, we will have a new bridging API that provides software conference mixing, among many other benefits. The code is pretty much done. It just needs some more documentation polish and a bit of code review. Then, you will not need DAHDI for conferencing either.

Timing API

res_timing_dahdi

res_timing_pthread

Josh’s bridging code:

$ svn co http://svn.digium.com/svn/asterisk/team/file/bridging