Asterisk模塊編寫1

 

How-to: Write an Asterisk Module, Part 1

June 19th, 2008 · 22 Comments

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.

 

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: %ld\n",
        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!

 

 

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 foo\n"
            "       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 echo\n\n");
        return CLI_SHOWUSAGE;
    }

    ast_cli(a->fd, "%s\n", 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 echo\n\n");
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, "%s\n", 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

 

 

link from :

http://www.russellbryant.net/blog/2008/06/19/how-to-write-an-asterisk-module-part-1/

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章