[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