2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2013, Digium, Inc.
6 * David M. Lee, II <dlee@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief The Asterisk Management Interface - AMI (channel event handling)
23 * \author David M. Lee, II <dlee@digium.com>
25 * AMI generated many per-channel and global-channel events by converting Stasis
26 * messages to AMI events. It makes sense to simply put them into a single file.
31 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
33 #include "asterisk/callerid.h"
34 #include "asterisk/channel.h"
35 #include "asterisk/manager.h"
36 #include "asterisk/stasis_message_router.h"
37 #include "asterisk/pbx.h"
38 #include "asterisk/stasis_channels.h"
40 static struct stasis_message_router *channel_state_router;
43 <managerEvent language="en_US" name="Newchannel">
44 <managerEventInstance class="EVENT_FLAG_CALL">
45 <synopsis>Raised when a new channel is created.</synopsis>
47 <parameter name="Channel">
49 <parameter name="ChannelState">
50 <para>A numeric code for the channel's current state, related to ChannelStateDesc</para>
52 <parameter name="ChannelStateDesc">
56 <enum name="OffHook"/>
57 <enum name="Dialing"/>
59 <enum name="Ringing"/>
62 <enum name="Dialing Offhook"/>
63 <enum name="Pre-ring"/>
64 <enum name="Unknown"/>
67 <parameter name="CallerIDNum">
69 <parameter name="CallerIDName">
71 <parameter name="ConnectedLineNum">
73 <parameter name="ConnectedLineName">
75 <parameter name="AccountCode">
77 <parameter name="Context">
79 <parameter name="Exten">
81 <parameter name="Priority">
83 <parameter name="Uniqueid">
86 </managerEventInstance>
88 <managerEvent language="en_US" name="Newstate">
89 <managerEventInstance class="EVENT_FLAG_CALL">
90 <synopsis>Raised when a channel's state changes.</synopsis>
92 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
94 </managerEventInstance>
96 <managerEvent language="en_US" name="Hangup">
97 <managerEventInstance class="EVENT_FLAG_CALL">
98 <synopsis>Raised when a channel is hung up.</synopsis>
100 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
101 <parameter name="Cause">
102 <para>A numeric cause code for why the channel was hung up.</para>
104 <parameter name="Cause-txt">
105 <para>A description of why the channel was hung up.</para>
108 </managerEventInstance>
110 <managerEvent language="en_US" name="HangupRequest">
111 <managerEventInstance class="EVENT_FLAG_CALL">
112 <synopsis>Raised when a hangup is requested.</synopsis>
114 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
115 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Hangup']/managerEventInstance/syntax/parameter[@name='Cause'])" />
117 </managerEventInstance>
119 <managerEvent language="en_US" name="SoftHangupRequest">
120 <managerEventInstance class="EVENT_FLAG_CALL">
121 <synopsis>Raised when a soft hangup is requested with a specific cause code.</synopsis>
123 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
124 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Hangup']/managerEventInstance/syntax/parameter[@name='Cause'])" />
126 </managerEventInstance>
128 <managerEvent language="en_US" name="NewExten">
129 <managerEventInstance class="EVENT_FLAG_DIALPLAN">
130 <synopsis>Raised when a channel enters a new context, extension, priority.</synopsis>
132 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
133 <parameter name="Extension">
134 <para>Deprecated in 12, but kept for
135 backward compatability. Please use
136 'Exten' instead.</para>
138 <parameter name="Application">
139 <para>The application about to be executed.</para>
141 <parameter name="AppData">
142 <para>The data to be passed to the application.</para>
145 </managerEventInstance>
147 <managerEvent language="en_US" name="NewCallerid">
148 <managerEventInstance class="EVENT_FLAG_CALL">
149 <synopsis>Raised when a channel receives new Caller ID information.</synopsis>
151 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
152 <parameter name="CID-CallingPres">
153 <para>A description of the Caller ID presentation.</para>
156 </managerEventInstance>
158 <managerEvent language="en_US" name="DialBegin">
159 <managerEventInstance class="EVENT_FLAG_CALL">
160 <synopsis>Raised when a dial action has started.</synopsis>
162 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
163 <parameter name="ChannelDest">
165 <parameter name="ChannelStateDest">
166 <para>A numeric code for the channel's current state, related to ChannelStateDescDest</para>
168 <parameter name="ChannelStateDescDest">
172 <enum name="OffHook"/>
173 <enum name="Dialing"/>
175 <enum name="Ringing"/>
178 <enum name="Dialing Offhook"/>
179 <enum name="Pre-ring"/>
180 <enum name="Unknown"/>
183 <parameter name="CallerIDNumDest">
185 <parameter name="CallerIDNameDest">
187 <parameter name="ConnectedLineNumDest">
189 <parameter name="ConnectedLineNameDest">
191 <parameter name="AccountCodeDest">
193 <parameter name="ContextDest">
195 <parameter name="ExtenDest">
197 <parameter name="PriorityDest">
199 <parameter name="UniqueidDest">
201 <parameter name="DialString">
202 <para>The non-technology specific device being dialed.</para>
206 <ref type="application">Dial</ref>
208 </managerEventInstance>
210 <managerEvent language="en_US" name="DialEnd">
211 <managerEventInstance class="EVENT_FLAG_CALL">
212 <synopsis>Raised when a dial action has completed.</synopsis>
214 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
215 <xi:include xpointer="xpointer(/docs/managerEvent[@name='DialBegin']/managerEventInstance/syntax/parameter[contains(@name, 'Dest')])" />
216 <parameter name="DialStatus">
217 <para>The result of the dial operation.</para>
219 <enum name="ANSWER" />
221 <enum name="CANCEL" />
222 <enum name="CHANUNAVAIL" />
223 <enum name="CONGESTION" />
224 <enum name="NOANSWER" />
229 <ref type="application">Dial</ref>
231 </managerEventInstance>
235 struct ast_str *ast_manager_build_channel_state_string_suffix(
236 const struct ast_channel_snapshot *snapshot,
239 struct ast_str *out = ast_str_create(1024);
244 res = ast_str_set(&out, 0,
246 "ChannelState%s: %d\r\n"
247 "ChannelStateDesc%s: %s\r\n"
248 "CallerIDNum%s: %s\r\n"
249 "CallerIDName%s: %s\r\n"
250 "ConnectedLineNum%s: %s\r\n"
251 "ConnectedLineName%s: %s\r\n"
252 "AccountCode%s: %s\r\n"
256 "Uniqueid%s: %s\r\n",
257 suffix, snapshot->name,
258 suffix, snapshot->state,
259 suffix, ast_state2str(snapshot->state),
260 suffix, S_OR(snapshot->caller_number, "<unknown>"),
261 suffix, S_OR(snapshot->caller_name, "<unknown>"),
262 suffix, S_OR(snapshot->connected_number, "<unknown>"),
263 suffix, S_OR(snapshot->connected_name, "<unknown>"),
264 suffix, snapshot->accountcode,
265 suffix, snapshot->context,
266 suffix, snapshot->exten,
267 suffix, snapshot->priority,
268 suffix, snapshot->uniqueid);
274 if (snapshot->manager_vars) {
275 struct ast_var_t *var;
276 AST_LIST_TRAVERSE(snapshot->manager_vars, var, entries) {
277 ast_str_append(&out, 0, "ChanVariable%s: %s=%s\r\n",
279 var->name, var->value);
286 struct ast_str *ast_manager_build_channel_state_string(
287 const struct ast_channel_snapshot *snapshot)
289 return ast_manager_build_channel_state_string_suffix(snapshot, "");
292 /*! \brief Struct containing info for an AMI channel event to send out. */
293 struct snapshot_manager_event {
294 /*! event_flags manager_event() flags parameter. */
296 /*! manager_event manager_event() category. */
297 const char *manager_event;
298 AST_DECLARE_STRING_FIELDS(
299 /* extra fields to include in the event. */
300 AST_STRING_FIELD(extra_fields);
304 static void snapshot_manager_event_dtor(void *obj)
306 struct snapshot_manager_event *ev = obj;
307 ast_string_field_free_memory(ev);
311 * \brief Construct a \ref snapshot_manager_event.
312 * \param event_flags manager_event() flags parameter.
313 * \param manager_event manager_event() category.
314 * \param extra_fields_fmt Format string for extra fields to include.
315 * Or NO_EXTRA_FIELDS for no extra fields.
316 * \return New \ref snapshot_manager_event object.
317 * \return \c NULL on error.
319 static struct snapshot_manager_event *
320 __attribute__((format(printf, 3, 4)))
321 snapshot_manager_event_create(
323 const char *manager_event,
324 const char *extra_fields_fmt,
327 RAII_VAR(struct snapshot_manager_event *, ev, NULL, ao2_cleanup);
330 ast_assert(extra_fields_fmt != NULL);
331 ast_assert(manager_event != NULL);
333 ev = ao2_alloc(sizeof(*ev), snapshot_manager_event_dtor);
338 if (ast_string_field_init(ev, 20)) {
342 ev->manager_event = manager_event;
343 ev->event_flags = event_flags;
345 va_start(argp, extra_fields_fmt);
346 ast_string_field_ptr_build_va(ev, &ev->extra_fields, extra_fields_fmt,
354 /*! GCC warns about blank or NULL format strings. So, shenanigans! */
355 #define NO_EXTRA_FIELDS "%s", ""
357 /*! \brief Typedef for callbacks that get called on channel snapshot updates */
358 typedef struct snapshot_manager_event *(*snapshot_monitor)(
359 struct ast_channel_snapshot *old_snapshot,
360 struct ast_channel_snapshot *new_snapshot);
362 /*! \brief Handle channel state changes */
363 static struct snapshot_manager_event *channel_state_change(
364 struct ast_channel_snapshot *old_snapshot,
365 struct ast_channel_snapshot *new_snapshot)
367 int is_hungup, was_hungup;
370 /* Ignore cache clearing events; we'll see the hangup first */
374 /* The Newchannel, Newstate and Hangup events are closely related, in
375 * in that they are mutually exclusive, basically different flavors
376 * of a new channel state event.
380 return snapshot_manager_event_create(
381 EVENT_FLAG_CALL, "Newchannel", NO_EXTRA_FIELDS);
384 was_hungup = ast_test_flag(&old_snapshot->flags, AST_FLAG_ZOMBIE) ? 1 : 0;
385 is_hungup = ast_test_flag(&new_snapshot->flags, AST_FLAG_ZOMBIE) ? 1 : 0;
387 if (!was_hungup && is_hungup) {
388 return snapshot_manager_event_create(
389 EVENT_FLAG_CALL, "Hangup",
392 new_snapshot->hangupcause,
393 ast_cause2str(new_snapshot->hangupcause));
396 if (old_snapshot->state != new_snapshot->state) {
397 return snapshot_manager_event_create(
398 EVENT_FLAG_CALL, "Newstate", NO_EXTRA_FIELDS);
406 * \brief Compares the context, exten and priority of two snapshots.
407 * \param old_snapshot Old snapshot
408 * \param new_snapshot New snapshot
409 * \return True (non-zero) if context, exten or priority are identical.
410 * \return False (zero) if context, exten and priority changed.
412 static inline int cep_equal(
413 const struct ast_channel_snapshot *old_snapshot,
414 const struct ast_channel_snapshot *new_snapshot)
416 ast_assert(old_snapshot != NULL);
417 ast_assert(new_snapshot != NULL);
419 /* We actually get some snapshots with CEP set, but before the
420 * application is set. Since empty application is invalid, we treat
421 * setting the application from nothing as a CEP change.
423 if (ast_strlen_zero(old_snapshot->appl) &&
424 !ast_strlen_zero(new_snapshot->appl)) {
428 return old_snapshot->priority == new_snapshot->priority &&
429 strcmp(old_snapshot->context, new_snapshot->context) == 0 &&
430 strcmp(old_snapshot->exten, new_snapshot->exten) == 0;
433 static struct snapshot_manager_event *channel_newexten(
434 struct ast_channel_snapshot *old_snapshot,
435 struct ast_channel_snapshot *new_snapshot)
437 /* No Newexten event on cache clear */
442 /* Empty application is not valid for a Newexten event */
443 if (ast_strlen_zero(new_snapshot->appl)) {
447 if (old_snapshot && cep_equal(old_snapshot, new_snapshot)) {
451 /* DEPRECATED: Extension field deprecated in 12; remove in 14 */
452 return snapshot_manager_event_create(
453 EVENT_FLAG_CALL, "Newexten",
455 "Application: %s\r\n"
463 * \brief Compares the callerid info of two snapshots.
464 * \param old_snapshot Old snapshot
465 * \param new_snapshot New snapshot
466 * \return True (non-zero) if callerid are identical.
467 * \return False (zero) if callerid changed.
469 static inline int caller_id_equal(
470 const struct ast_channel_snapshot *old_snapshot,
471 const struct ast_channel_snapshot *new_snapshot)
473 ast_assert(old_snapshot != NULL);
474 ast_assert(new_snapshot != NULL);
475 return strcmp(old_snapshot->caller_number, new_snapshot->caller_number) == 0 &&
476 strcmp(old_snapshot->caller_name, new_snapshot->caller_name) == 0;
479 static struct snapshot_manager_event *channel_new_callerid(
480 struct ast_channel_snapshot *old_snapshot,
481 struct ast_channel_snapshot *new_snapshot)
483 /* No NewCallerid event on cache clear or first event */
484 if (!old_snapshot || !new_snapshot) {
488 if (caller_id_equal(old_snapshot, new_snapshot)) {
492 return snapshot_manager_event_create(
493 EVENT_FLAG_CALL, "NewCallerid",
494 "CID-CallingPres: %d (%s)\r\n",
495 new_snapshot->caller_pres,
496 ast_describe_caller_presentation(new_snapshot->caller_pres));
499 snapshot_monitor monitors[] = {
500 channel_state_change,
505 static void channel_snapshot_update(void *data, struct stasis_subscription *sub,
506 struct stasis_topic *topic,
507 struct stasis_message *message)
509 RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
510 struct stasis_cache_update *update;
511 struct ast_channel_snapshot *old_snapshot;
512 struct ast_channel_snapshot *new_snapshot;
515 update = stasis_message_data(message);
517 if (ast_channel_snapshot_type() != update->type) {
521 old_snapshot = stasis_message_data(update->old_snapshot);
522 new_snapshot = stasis_message_data(update->new_snapshot);
524 for (i = 0; i < ARRAY_LEN(monitors); ++i) {
525 RAII_VAR(struct snapshot_manager_event *, ev, NULL, ao2_cleanup);
526 ev = monitors[i](old_snapshot, new_snapshot);
532 /* If we haven't already, build the channel event string */
533 if (!channel_event_string) {
534 channel_event_string =
535 ast_manager_build_channel_state_string(new_snapshot);
536 if (!channel_event_string) {
541 manager_event(ev->event_flags, ev->manager_event, "%s%s",
542 ast_str_buffer(channel_event_string),
547 static void channel_varset(struct ast_channel_blob *obj)
549 RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
550 const char *variable = ast_json_string_get(ast_json_object_get(obj->blob, "variable"));
551 const char *value = ast_json_string_get(ast_json_object_get(obj->blob, "value"));
554 channel_event_string = ast_manager_build_channel_state_string(obj->snapshot);
556 channel_event_string = ast_str_create(35);
557 ast_str_set(&channel_event_string, 0,
559 "Uniqueid: none\r\n");
562 if (!channel_event_string) {
567 <managerEventInstance>
568 <synopsis>Raised when a variable is set to a particular value.</synopsis>
570 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
571 <parameter name="Variable">
572 <para>The variable being set.</para>
574 <parameter name="Value">
575 <para>The new value of the variable.</para>
578 </managerEventInstance>
580 manager_event(EVENT_FLAG_DIALPLAN, "VarSet",
584 ast_str_buffer(channel_event_string),
588 static void channel_userevent(struct ast_channel_blob *obj)
590 RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
591 const char *eventname;
594 eventname = ast_json_string_get(ast_json_object_get(obj->blob, "eventname"));
595 body = ast_json_string_get(ast_json_object_get(obj->blob, "body"));
596 channel_event_string = ast_manager_build_channel_state_string(obj->snapshot);
598 if (!channel_event_string) {
603 <managerEventInstance>
604 <synopsis>A user defined event raised from the dialplan.</synopsis>
606 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
607 <parameter name="UserEvent">
608 <para>The event name, as specified in the dialplan.</para>
612 <ref type="application">UserEvent</ref>
614 </managerEventInstance>
616 manager_event(EVENT_FLAG_USER, "UserEvent",
620 ast_str_buffer(channel_event_string), eventname, body);
623 static void channel_hangup_request(struct ast_channel_blob *obj)
625 RAII_VAR(struct ast_str *, extra, NULL, ast_free);
626 RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
627 struct ast_json *cause;
629 char *manager_event = "HangupRequest";
631 extra = ast_str_create(20);
636 channel_event_string = ast_manager_build_channel_state_string(obj->snapshot);
638 if (!channel_event_string) {
642 cause = ast_json_object_get(obj->blob, "cause");
644 ast_str_append(&extra, 0,
646 ast_json_integer_get(cause));
649 is_soft = ast_json_is_true(ast_json_object_get(obj->blob, "soft"));
651 manager_event = "SoftHangupRequest";
654 manager_event(EVENT_FLAG_CALL, manager_event,
656 ast_str_buffer(channel_event_string),
657 ast_str_buffer(extra));
661 * \brief Callback processing messages on the channel topic.
663 static void channel_blob_cb(void *data, struct stasis_subscription *sub,
664 struct stasis_topic *topic,
665 struct stasis_message *message)
667 struct ast_channel_blob *obj = stasis_message_data(message);
669 if (strcmp("varset", ast_channel_blob_json_type(obj)) == 0) {
671 } else if (strcmp("userevent", ast_channel_blob_json_type(obj)) == 0) {
672 channel_userevent(obj);
673 } else if (strcmp("hangup_request", ast_channel_blob_json_type(obj)) == 0) {
674 channel_hangup_request(obj);
679 * \brief Callback processing messages for channel dialing
681 static void channel_dial_cb(void *data, struct stasis_subscription *sub,
682 struct stasis_topic *topic,
683 struct stasis_message *message)
685 struct ast_multi_channel_blob *obj = stasis_message_data(message);
686 const char *dialstatus;
687 const char *dialstring;
688 struct ast_channel_snapshot *caller;
689 struct ast_channel_snapshot *peer;
690 RAII_VAR(struct ast_str *, caller_event_string, NULL, ast_free);
691 RAII_VAR(struct ast_str *, peer_event_string, NULL, ast_free);
693 if (strcmp("dial", ast_multi_channel_blob_get_type(obj))) {
698 caller = ast_multi_channel_blob_get_channel(obj, "caller");
699 peer = ast_multi_channel_blob_get_channel(obj, "peer");
701 /* Peer is required - otherwise, who are we dialing? */
702 ast_assert(peer != NULL);
703 peer_event_string = ast_manager_build_channel_state_string_suffix(peer, "Dest");
704 if (!peer_event_string) {
709 caller_event_string = ast_manager_build_channel_state_string(caller);
710 if (!caller_event_string) {
713 dialstatus = ast_json_string_get(ast_json_object_get(ast_multi_channel_blob_get_json(obj), "dialstatus"));
714 dialstring = ast_json_string_get(ast_json_object_get(ast_multi_channel_blob_get_json(obj), "dialstring"));
715 if (ast_strlen_zero(dialstatus)) {
716 manager_event(EVENT_FLAG_CALL, "DialBegin",
719 "DialString: %s\r\n",
720 ast_str_buffer(caller_event_string),
721 ast_str_buffer(peer_event_string),
722 S_OR(dialstring, "unknown"));
724 manager_event(EVENT_FLAG_CALL, "DialEnd",
727 "DialStatus: %s\r\n",
728 ast_str_buffer(caller_event_string),
729 ast_str_buffer(peer_event_string),
730 S_OR(dialstatus, "unknown"));
733 /* TODO: If we don't have a caller, this should be treated as an Originate */
737 static void manager_channels_shutdown(void)
739 stasis_message_router_unsubscribe(channel_state_router);
740 channel_state_router = NULL;
743 int manager_channels_init(void)
747 if (channel_state_router) {
748 /* Already initialized */
752 ast_register_atexit(manager_channels_shutdown);
754 channel_state_router = stasis_message_router_create(
755 stasis_caching_get_topic(ast_channel_topic_all_cached()));
757 if (!channel_state_router) {
761 ret |= stasis_message_router_add(channel_state_router,
762 stasis_cache_update_type(),
763 channel_snapshot_update,
766 ret |= stasis_message_router_add(channel_state_router,
767 ast_channel_blob_type(),
771 ret |= stasis_message_router_add(channel_state_router,
772 ast_channel_dial_type(),
776 /* If somehow we failed to add any routes, just shut down the whole
780 manager_channels_shutdown();