[asterisk-dev] Is there a possibility get async notificaiton when a channel state changed

Matthew Jordan mjordan at digium.com
Sat Jul 12 16:04:26 CDT 2014


On Sat, Jul 12, 2014 at 2:25 PM, vassilux . <v.gontcharov at gmail.com> wrote:
> Yes sure, it was a newbie question.
> I want to use it in an asterisk module
>

While there is no specific callback simply for a change in some
chanenl's ast_channel.state property, there are options.

If you are using Asterisk 12+, you can use Stasis to subscribe to a
particular channel (or all channels). Generally, if you want to track
changes in a channel, you would subscribe to a channel's caching
topic, which will give you old and new snapshots of a channel. A good
example of this can be seen in res_chan_stats, which uses res_statsd
to publish channel statistics to a statsd server. The following is
taken from that module (and paraphrased slightly for brevity):

/*!
 * \brief Router callback for \ref stasis_cache_update messages.
 * \param data Data pointer given when added to router.
 * \param sub This subscription.
 * \param topic The topic the message was posted to. This is not necessarily the
 *              topic you subscribed to, since messages may be forwarded between
 *              topics.
 * \param message The message itself.
 */
static void updates(void *data, struct stasis_subscription *sub,
    struct stasis_message *message)
{
    /* Since this came from a message router, we know the type of the
     * message. We can cast the data without checking its type.
     */
    struct stasis_cache_update *update = stasis_message_data(message);

    /* We're only interested in channel snapshots, so check the type
     * of the underlying message.
     */
    if (ast_channel_snapshot_type() != update->type) {
        return;
    }

    /* There are three types of cache updates.
     * !old && new -> Initial cache entry
     * old && new -> Updated cache entry
     * old && !new -> Cache entry removed.
     */

    if (!update->old_snapshot && update->new_snapshot) {
        /* Initial cache entry; count a channel creation */
        ast_statsd_log("channels.count", AST_STATSD_COUNTER, 1);
    } else if (update->old_snapshot && !update->new_snapshot) {
        /* Cache entry removed. Compute the age of the channel and post
         * that, as well as decrementing the channel count.
         */
        struct ast_channel_snapshot *last;
        int64_t age;

        last = stasis_message_data(update->old_snapshot);
        age = ast_tvdiff_ms(*stasis_message_timestamp(message),
            last->creationtime);
        ast_statsd_log("channels.calltime", AST_STATSD_TIMER, age);

        /* And decrement the channel count */
        ast_statsd_log("channels.count", AST_STATSD_COUNTER, -1);
    }
}

static int load_module(void)
{

    /* You can create a message router to route messages by type */
    router = stasis_message_router_create(
        ast_channel_topic_all_cached());
    if (!router) {
        return AST_MODULE_LOAD_FAILURE;
    }
    stasis_message_router_add(router, stasis_cache_update_type(),
        updates, NULL);

...
}

If what you cared about was the channel state changing, you could
inspect the old/new snapshots in something like the following manner:

if (!old_snapshot || !new_snapshot) {
    /* Creation or destruction, handle differently */
} else if (old_snapshot->state != new_snapshot->state) {
    /* State change! */
}

Since snapshots are immutable and are *not* the channel, they can be
accessed without locking and without affecting the actual operating
channel.

This mechanism is how CDRs, CEL, events in ARI/AMI, various internal
functionality during attended transfers, and a whole bunch of other
modules all work. Stasis is incredibly flexible, very well documented
in doxygen, and there's a lot of examples in the codebase on using it.

In versions of Asterisk prior to Asterisk 12, this concept doesn't
exist. You do have one work around in Asterisk 11: you could register
an AMI event hook (in manager.h) which will forward all AMI events to
your callback function. You could then parse the event string out
looking for a channel state change event.

Matt

-- 
Matthew Jordan
Digium, Inc. | Engineering Manager
445 Jan Davis Drive NW - Huntsville, AL 35806 - USA
Check us out at: http://digium.com & http://asterisk.org



More information about the asterisk-dev mailing list