[asterisk-commits] dlee: branch dlee/ASTERISK-21096 r383540 - /team/dlee/ASTERISK-21096/main/
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Thu Mar 21 15:03:23 CDT 2013
Author: dlee
Date: Thu Mar 21 15:03:22 2013
New Revision: 383540
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=383540
Log:
Handle snapshot monitors independently, avoiding a single BBOM function.
Modified:
team/dlee/ASTERISK-21096/main/manager_channels.c
Modified: team/dlee/ASTERISK-21096/main/manager_channels.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ASTERISK-21096/main/manager_channels.c?view=diff&rev=383540&r1=383539&r2=383540
==============================================================================
--- team/dlee/ASTERISK-21096/main/manager_channels.c (original)
+++ team/dlee/ASTERISK-21096/main/manager_channels.c Thu Mar 21 15:03:22 2013
@@ -121,6 +121,36 @@
<syntax>
<xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
<xi:include xpointer="xpointer(/docs/managerEvent[@name='Hangup']/managerEventInstance/syntax/parameter[@name='Cause'])" />
+ </syntax>
+ </managerEventInstance>
+ </managerEvent>
+ <managerEvent language="en_US" name="NewExten">
+ <managerEventInstance class="EVENT_FLAG_DIALPLAN">
+ <synopsis>Raised when a channel enters a new context, extension, priority.</synopsis>
+ <syntax>
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+ <parameter name="Extension">
+ <para>Deprecated in 12, but kept for
+ backward compatability. Please use
+ 'Exten' instead.</para>
+ </parameter>
+ <parameter name="Application">
+ <para>The application about to be executed.</para>
+ </parameter>
+ <parameter name="AppData">
+ <para>The data to be passed to the application.</para>
+ </parameter>
+ </syntax>
+ </managerEventInstance>
+ </managerEvent>
+ <managerEvent language="en_US" name="NewCallerid">
+ <managerEventInstance class="EVENT_FLAG_CALL">
+ <synopsis>Raised when a channel receives new Caller ID information.</synopsis>
+ <syntax>
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+ <parameter name="CID-CallingPres">
+ <para>A description of the Caller ID presentation.</para>
+ </parameter>
</syntax>
</managerEventInstance>
</managerEvent>
@@ -186,158 +216,256 @@
return out;
}
-static inline int cep_has_changed(
+/*! \brief Struct containing info for an AMI channel event to send out. */
+struct snapshot_manager_event {
+ AST_LIST_ENTRY(snapshot_manager_event) list;
+ const char *manager_event;
+ int event_flags;
+ char extra_fields[];
+};
+
+/*!
+ * \brief Construct a \ref snapshot_manager_event.
+ * \param event_flags manager_event() flags parameter.
+ * \param manager_event manager_event() category.
+ * \param extra_fields_fmt Format string for extra fields to include.
+ * \return New \ref snapshot_manager_event object.
+ * \return \c NULL on error.
+ */
+static struct snapshot_manager_event *
+__attribute__((format(printf, 3, 4)))
+snapshot_manager_event_create(
+ int event_flags,
+ const char *manager_event,
+ const char *extra_fields_fmt,
+ ...)
+
+{
+ RAII_VAR(struct snapshot_manager_event *, ev, NULL, ao2_cleanup);
+ RAII_VAR(char *, extra_fields, NULL, ast_free);
+ va_list argp;
+
+ ast_assert(extra_fields_fmt != NULL);
+ ast_assert(manager_event != NULL);
+
+ va_start(argp, extra_fields_fmt);
+ ast_vasprintf(&extra_fields, extra_fields_fmt, argp);
+ if (!extra_fields) {
+ return NULL;
+ }
+
+ ev = ao2_alloc(sizeof(*ev) + strlen(extra_fields) + 1, NULL);
+ if (!ev) {
+ return NULL;
+ }
+
+ ev->manager_event = manager_event;
+ ev->event_flags = event_flags;
+ strcpy(ev->extra_fields, extra_fields);
+
+ ao2_ref(ev, +1);
+ return ev;
+}
+
+/*! \brief Typedef for callbacks that get called on channel snapshot updates */
+typedef struct snapshot_manager_event *(*snapshot_monitor)(
+ struct ast_channel_snapshot *old_snapshot,
+ struct ast_channel_snapshot *new_snapshot);
+
+/*! \brief Handle channel state changes */
+static struct snapshot_manager_event *channel_state_change(
+ struct ast_channel_snapshot *old_snapshot,
+ struct ast_channel_snapshot *new_snapshot)
+{
+ RAII_VAR(char *, extra_fields, NULL, ast_free);
+ char *manager_event = NULL;
+ int is_hungup, was_hungup;
+
+ if (!new_snapshot) {
+ /* Ignore cache clearing events; we'll see the hangup first */
+ return NULL;
+ }
+
+ extra_fields = ast_strdup("");
+
+ was_hungup = (old_snapshot && ast_test_flag(&old_snapshot->flags, AST_FLAG_ZOMBIE)) ? 1 : 0;
+ is_hungup = ast_test_flag(&new_snapshot->flags, AST_FLAG_ZOMBIE) ? 1 : 0;
+
+ /* The Newchannel, Newstate and Hangup events are closely related, in
+ * in that they are mutually exclusive, basically different flavors
+ * of a new channel state event.
+ */
+
+ if (!old_snapshot) {
+ manager_event = "Newchannel";
+ }
+
+ if (old_snapshot && old_snapshot->state != new_snapshot->state) {
+ manager_event = "Newstate";
+ }
+
+ if (!was_hungup && is_hungup) {
+ manager_event = "Hangup";
+ ast_asprintf(&extra_fields,
+ "Cause: %d\r\n"
+ "Cause-txt: %s\r\n",
+ new_snapshot->hangupcause,
+ ast_cause2str(new_snapshot->hangupcause));
+ if (!extra_fields) {
+ return NULL;
+ }
+ }
+
+ /* No event */
+ if (!manager_event) {
+ return NULL;
+ }
+
+ return snapshot_manager_event_create(
+ EVENT_FLAG_CALL, manager_event, "%s", extra_fields);
+}
+
+/*!
+ * \brief Compares the context, exten and priority of two snapshots.
+ * \param old_snapshot Old snapshot
+ * \param new_snapshot New snapshot
+ * \return True (non-zero) if context, exten or priority are identical.
+ * \return False (zero) if context, exten and priority changed.
+ */
+static inline int cep_equal(
const struct ast_channel_snapshot *old_snapshot,
const struct ast_channel_snapshot *new_snapshot)
{
ast_assert(old_snapshot != NULL);
ast_assert(new_snapshot != NULL);
- return old_snapshot->priority != new_snapshot->priority ||
- strcmp(old_snapshot->context, new_snapshot->context) != 0 ||
- strcmp(old_snapshot->exten, new_snapshot->exten) != 0;
-}
-
-static inline int caller_id_changed(
+
+ /* We actually get some snapshots with CEP set, but before the
+ * application is set. Since empty application is invalid, we treat
+ * setting the application from nothing as a CEP change.
+ */
+ if (ast_strlen_zero(old_snapshot->appl) &&
+ !ast_strlen_zero(new_snapshot->appl)) {
+ return 0;
+ }
+
+ return old_snapshot->priority == new_snapshot->priority &&
+ strcmp(old_snapshot->context, new_snapshot->context) == 0 &&
+ strcmp(old_snapshot->exten, new_snapshot->exten) == 0;
+}
+
+static struct snapshot_manager_event *channel_newexten(
+ struct ast_channel_snapshot *old_snapshot,
+ struct ast_channel_snapshot *new_snapshot)
+{
+ /* No Newexten event on cache clear */
+ if (!new_snapshot) {
+ return NULL;
+ }
+
+ /* Empty application is not valid for a Newexten event */
+ if (ast_strlen_zero(new_snapshot->appl)) {
+ return NULL;
+ }
+
+ if (old_snapshot && cep_equal(old_snapshot, new_snapshot)) {
+ return NULL;
+ }
+
+ /* DEPRECATED: Extension field deprecated in 12; remove in 14 */
+ return snapshot_manager_event_create(
+ EVENT_FLAG_CALL, "Newexten",
+ "Extension: %s\r\n"
+ "Application: %s\r\n"
+ "AppData: %s\r\n",
+ new_snapshot->exten,
+ new_snapshot->appl,
+ new_snapshot->data);
+}
+
+/*!
+ * \brief Compares the callerid info of two snapshots.
+ * \param old_snapshot Old snapshot
+ * \param new_snapshot New snapshot
+ * \return True (non-zero) if callerid are identical.
+ * \return False (zero) if callerid changed.
+ */
+static inline int caller_id_equal(
const struct ast_channel_snapshot *old_snapshot,
const struct ast_channel_snapshot *new_snapshot)
{
+ ast_assert(old_snapshot != NULL);
ast_assert(new_snapshot != NULL);
- return old_snapshot && (
- strcmp(old_snapshot->caller_number, new_snapshot->caller_number) != 0 ||
- strcmp(old_snapshot->caller_name, new_snapshot->caller_name) != 0);
-}
+ return strcmp(old_snapshot->caller_number, new_snapshot->caller_number) == 0 &&
+ strcmp(old_snapshot->caller_name, new_snapshot->caller_name) == 0);
+}
+
+static struct snapshot_manager_event *channel_new_callerid(
+ struct ast_channel_snapshot *old_snapshot,
+ struct ast_channel_snapshot *new_snapshot)
+{
+ /* No NewCallerid event on cache clear or first event */
+ if (!old_snapshot || !new_snapshot) {
+ return NULL;
+ }
+
+ if (caller_id_equal(old_snapshot, new_snapshot)) {
+ return NULL;
+ }
+
+ return snapshot_manager_event_create(
+ EVENT_FLAG_CALL, "NewCallerid",
+ "CID-CallingPres: %d (%s)\r\n",
+ new_snapshot->caller_pres,
+ ast_describe_caller_presentation(new_snapshot->caller_pres));
+}
+
+snapshot_monitor monitors[] = {
+ channel_state_change,
+ channel_newexten,
+ channel_new_callerid
+};
+
+size_t monitors_size = sizeof(monitors) / sizeof(monitors[0]);
static void channel_snapshot_update(void *data, struct stasis_subscription *sub,
struct stasis_topic *topic,
struct stasis_message *message)
{
- RAII_VAR(struct ast_str *, extra_fields, NULL, ast_free);
RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
- struct stasis_cache_update *update = stasis_message_data(message);
+ struct stasis_cache_update *update;
struct ast_channel_snapshot *old_snapshot;
struct ast_channel_snapshot *new_snapshot;
- int is_hungup, was_hungup;
- char *manager_event = NULL;
- int new_exten, new_callerid;
+ size_t i;
+
+ update = stasis_message_data(message);
if (ast_channel_snapshot() != update->type) {
return;
}
- extra_fields = ast_str_create(20);
- if (!extra_fields) {
- return;
- }
-
old_snapshot = stasis_message_data(update->old_snapshot);
new_snapshot = stasis_message_data(update->new_snapshot);
- if (!new_snapshot) {
- /* Ignore cache clearing events; we'll see the hangup first */
- return;
- }
-
- was_hungup = (old_snapshot && ast_test_flag(&old_snapshot->flags, AST_FLAG_ZOMBIE)) ? 1 : 0;
- is_hungup = ast_test_flag(&new_snapshot->flags, AST_FLAG_ZOMBIE) ? 1 : 0;
-
- if (!old_snapshot) {
- manager_event = "Newchannel";
- }
-
- if (old_snapshot && old_snapshot->state != new_snapshot->state) {
- manager_event = "Newstate";
- }
-
- if (!was_hungup && is_hungup) {
- manager_event = "Hangup";
- ast_str_append(&extra_fields, 0,
- "Cause: %d\r\n"
- "Cause-txt: %s\r\n",
- new_snapshot->hangupcause,
- ast_cause2str(new_snapshot->hangupcause));
- }
-
- /* Detect Newexten transitions
- * - if new snapshot has an application set AND
- * - first snapshot OR
- * - if the old snapshot has no application (first Newexten) OR
- * - if the context/priority/exten changes
- */
- new_exten = !ast_strlen_zero(new_snapshot->appl) && (
- !old_snapshot ||
- ast_strlen_zero(old_snapshot->appl) ||
- cep_has_changed(old_snapshot, new_snapshot));
-
- new_callerid = caller_id_changed(old_snapshot, new_snapshot);
-
- if (manager_event || new_exten || new_callerid) {
- channel_event_string =
- manager_build_channel_state_string(new_snapshot);
- }
-
- if (!channel_event_string) {
- return;
- }
-
- /* Channel state change events */
- if (manager_event) {
- manager_event(EVENT_FLAG_CALL, manager_event, "%s%s",
- ast_str_buffer(channel_event_string),
- ast_str_buffer(extra_fields));
- }
-
- if (new_exten) {
- /* DEPRECATED: Extension field deprecated in 12; remove in 14 */
- /*** DOCUMENTATION
- <managerEventInstance>
- <synopsis>Raised when a channel enters a new context, extension, priority.</synopsis>
- <syntax>
- <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
- <parameter name="Extension">
- <para>Deprecated in 12, but kept for
- backward compatability. Please use
- 'Exten' instead.</para>
- </parameter>
- <parameter name="Application">
- <para>The application about to be executed.</para>
- </parameter>
- <parameter name="AppData">
- <para>The data to be passed to the application.</para>
- </parameter>
- </syntax>
- </managerEventInstance>
- ***/
- manager_event(EVENT_FLAG_DIALPLAN, "Newexten",
- "%s"
- "Extension: %s\r\n"
- "Application: %s\r\n"
- "AppData: %s\r\n",
- ast_str_buffer(channel_event_string),
- new_snapshot->exten,
- new_snapshot->appl,
- new_snapshot->data);
- }
-
- if (new_callerid) {
- const char *pres_str = ast_describe_caller_presentation(
- new_snapshot->caller_pres);
- /*** DOCUMENTATION
- <managerEventInstance>
- <synopsis>Raised when a channel receives new Caller ID information.</synopsis>
- <syntax>
- <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
- <parameter name="CID-CallingPres">
- <para>A description of the Caller ID presentation.</para>
- </parameter>
- </syntax>
- </managerEventInstance>
- ***/
- manager_event(EVENT_FLAG_CALL, "NewCallerid",
- "%s"
- "CID-CallingPres: %d (%s)\r\n",
- ast_str_buffer(channel_event_string),
- new_snapshot->caller_pres,
- pres_str);
+ for (i = 0; i < monitors_size; ++i) {
+ RAII_VAR(struct snapshot_manager_event *, ev, NULL, ao2_cleanup);
+ ev = monitors[i](old_snapshot, new_snapshot);
+
+ if (!ev) {
+ continue;
+ }
+
+ /* If we haven't already, build the channel event string */
+ if (!channel_event_string) {
+ channel_event_string =
+ manager_build_channel_state_string(new_snapshot);
+ if (!channel_event_string) {
+ return;
+ }
+ }
+
+ manager_event(ev->event_flags, ev->manager_event, "%s%s",
+ ast_str_buffer(channel_event_string),
+ ev->extra_fields);
}
}
More information about the asterisk-commits
mailing list