diff options
author | Matthew Jordan <mjordan@digium.com> | 2013-04-08 14:26:37 +0000 |
---|---|---|
committer | Matthew Jordan <mjordan@digium.com> | 2013-04-08 14:26:37 +0000 |
commit | b8d4e573f1292688d07063542d263490536c2bc9 (patch) | |
tree | 938b0732a2311aa3c424597283aff95c85f9a98e /main/manager_channels.c | |
parent | a2a53cc306ea5fec65daf3630716a7c6ee13adad (diff) |
Add multi-channel Stasis messages; refactor Dial AMI events to Stasis
This patch does the following:
* A new Stasis payload has been defined for multi-channel messages. This
payload can store multiple ast_channel_snapshot objects along with a single
JSON blob. The payload object itself is opaque; the snapshots are stored
in a container keyed by roles. APIs have been provided to query for and
retrieve the snapshots from the payload object.
* The Dial AMI events have been refactored onto Stasis. This includes dial
messages in app_dial, as well as the core dialing framework. The AMI events
have been modified to send out a DialBegin/DialEnd events, as opposed to
the subevent type that was previously used.
* Stasis messages, types, and other objects related to channels have been
placed in their own file, stasis_channels. Unit tests for some of these
objects/messages have also been written.
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@384910 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main/manager_channels.c')
-rw-r--r-- | main/manager_channels.c | 217 |
1 files changed, 188 insertions, 29 deletions
diff --git a/main/manager_channels.c b/main/manager_channels.c index ce8e0870c..89ccd4af8 100644 --- a/main/manager_channels.c +++ b/main/manager_channels.c @@ -35,6 +35,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/manager.h" #include "asterisk/stasis_message_router.h" #include "asterisk/pbx.h" +#include "asterisk/stasis_channels.h" static struct stasis_message_router *channel_state_router; @@ -154,6 +155,81 @@ static struct stasis_message_router *channel_state_router; </syntax> </managerEventInstance> </managerEvent> + <managerEvent language="en_US" name="DialBegin"> + <managerEventInstance class="EVENT_FLAG_CALL"> + <synopsis>Raised when a dial action has started.</synopsis> + <syntax> + <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" /> + <parameter name="ChannelDest"> + </parameter> + <parameter name="ChannelStateDest"> + <para>A numeric code for the channel's current state, related to ChannelStateDescDest</para> + </parameter> + <parameter name="ChannelStateDescDest"> + <enumlist> + <enum name="Down"/> + <enum name="Rsrvd"/> + <enum name="OffHook"/> + <enum name="Dialing"/> + <enum name="Ring"/> + <enum name="Ringing"/> + <enum name="Up"/> + <enum name="Busy"/> + <enum name="Dialing Offhook"/> + <enum name="Pre-ring"/> + <enum name="Unknown"/> + </enumlist> + </parameter> + <parameter name="CallerIDNumDest"> + </parameter> + <parameter name="CallerIDNameDest"> + </parameter> + <parameter name="ConnectedLineNumDest"> + </parameter> + <parameter name="ConnectedLineNameDest"> + </parameter> + <parameter name="AccountCodeDest"> + </parameter> + <parameter name="ContextDest"> + </parameter> + <parameter name="ExtenDest"> + </parameter> + <parameter name="PriorityDest"> + </parameter> + <parameter name="UniqueidDest"> + </parameter> + <parameter name="DialString"> + <para>The non-technology specific device being dialed.</para> + </parameter> + </syntax> + <see-also> + <ref type="application">Dial</ref> + </see-also> + </managerEventInstance> + </managerEvent> + <managerEvent language="en_US" name="DialEnd"> + <managerEventInstance class="EVENT_FLAG_CALL"> + <synopsis>Raised when a dial action has completed.</synopsis> + <syntax> + <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" /> + <xi:include xpointer="xpointer(/docs/managerEvent[@name='DialBegin']/managerEventInstance/syntax/parameter[contains(@name, 'Dest')])" /> + <parameter name="DialStatus"> + <para>The result of the dial operation.</para> + <enumlist> + <enum name="ANSWER" /> + <enum name="BUSY" /> + <enum name="CANCEL" /> + <enum name="CHANUNAVAIL" /> + <enum name="CONGESTION" /> + <enum name="NOANSWER" /> + </enumlist> + </parameter> + </syntax> + <see-also> + <ref type="application">Dial</ref> + </see-also> + </managerEventInstance> + </managerEvent> ***/ /*! @@ -162,12 +238,14 @@ static struct stasis_message_router *channel_state_router; * * \param snapshot the channel snapshot for which to generate an AMI message * body + * \param suffix the suffix to append to the channel fields * * \retval NULL on error * \retval ast_str* on success (must be ast_freed by caller) */ -static struct ast_str *manager_build_channel_state_string( - const struct ast_channel_snapshot *snapshot) +static struct ast_str *manager_build_channel_state_string_suffix( + const struct ast_channel_snapshot *snapshot, + const char *suffix) { struct ast_str *out = ast_str_create(1024); int res = 0; @@ -175,30 +253,30 @@ static struct ast_str *manager_build_channel_state_string( return NULL; } res = ast_str_set(&out, 0, - "Channel: %s\r\n" - "ChannelState: %d\r\n" - "ChannelStateDesc: %s\r\n" - "CallerIDNum: %s\r\n" - "CallerIDName: %s\r\n" - "ConnectedLineNum: %s\r\n" - "ConnectedLineName: %s\r\n" - "AccountCode: %s\r\n" - "Context: %s\r\n" - "Exten: %s\r\n" - "Priority: %d\r\n" - "Uniqueid: %s\r\n", - snapshot->name, - snapshot->state, - ast_state2str(snapshot->state), - snapshot->caller_number, - snapshot->caller_name, - snapshot->connected_number, - snapshot->connected_name, - snapshot->accountcode, - snapshot->context, - snapshot->exten, - snapshot->priority, - snapshot->uniqueid); + "Channel%s: %s\r\n" + "ChannelState%s: %d\r\n" + "ChannelStateDesc%s: %s\r\n" + "CallerIDNum%s: %s\r\n" + "CallerIDName%s: %s\r\n" + "ConnectedLineNum%s: %s\r\n" + "ConnectedLineName%s: %s\r\n" + "AccountCode%s: %s\r\n" + "Context%s: %s\r\n" + "Exten%s: %s\r\n" + "Priority%s: %d\r\n" + "Uniqueid%s: %s\r\n", + suffix, snapshot->name, + suffix, snapshot->state, + suffix, ast_state2str(snapshot->state), + suffix, S_OR(snapshot->caller_number, "<unknown>"), + suffix, S_OR(snapshot->caller_name, "<unknown>"), + suffix, S_OR(snapshot->connected_number, "<unknown>"), + suffix, S_OR(snapshot->connected_name, "<unknown>"), + suffix, snapshot->accountcode, + suffix, snapshot->context, + suffix, snapshot->exten, + suffix, snapshot->priority, + suffix, snapshot->uniqueid); if (!res) { return NULL; @@ -207,15 +285,31 @@ static struct ast_str *manager_build_channel_state_string( if (snapshot->manager_vars) { struct ast_var_t *var; AST_LIST_TRAVERSE(snapshot->manager_vars, var, entries) { - ast_str_append(&out, 0, "ChanVariable(%s): %s=%s\r\n", - snapshot->name, - var->name, var->value); + ast_str_append(&out, 0, "ChanVariable%s: %s=%s\r\n", + suffix, + var->name, var->value); } } return out; } +/*! + * \brief Generate the AMI message body from a channel snapshot + * \internal + * + * \param snapshot the channel snapshot for which to generate an AMI message + * body + * + * \retval NULL on error + * \retval ast_str* on success (must be ast_freed by caller) + */ +static struct ast_str *manager_build_channel_state_string( + const struct ast_channel_snapshot *snapshot) +{ + return manager_build_channel_state_string_suffix(snapshot, ""); +} + /*! \brief Struct containing info for an AMI channel event to send out. */ struct snapshot_manager_event { /*! event_flags manager_event() flags parameter. */ @@ -602,6 +696,65 @@ static void channel_blob_cb(void *data, struct stasis_subscription *sub, } } +/*! + * \brief Callback processing messages for channel dialing + */ +static void channel_dial_cb(void *data, struct stasis_subscription *sub, + struct stasis_topic *topic, + struct stasis_message *message) +{ + struct ast_multi_channel_blob *obj = stasis_message_data(message); + const char *dialstatus; + const char *dialstring; + struct ast_channel_snapshot *caller; + struct ast_channel_snapshot *peer; + RAII_VAR(struct ast_str *, caller_event_string, NULL, ast_free); + RAII_VAR(struct ast_str *, peer_event_string, NULL, ast_free); + + if (strcmp("dial", ast_multi_channel_blob_get_type(obj))) { + ast_assert(0); + return; + } + + caller = ast_multi_channel_blob_get_channel(obj, "caller"); + peer = ast_multi_channel_blob_get_channel(obj, "peer"); + + /* Peer is required - otherwise, who are we dialing? */ + ast_assert(peer != NULL); + peer_event_string = manager_build_channel_state_string_suffix(peer, "Dest"); + if (!peer_event_string) { + return; + } + + if (caller) { + caller_event_string = manager_build_channel_state_string(caller); + if (!caller_event_string) { + return; + } + dialstatus = ast_json_string_get(ast_json_object_get(ast_multi_channel_blob_get_json(obj), "dialstatus")); + dialstring = ast_json_string_get(ast_json_object_get(ast_multi_channel_blob_get_json(obj), "dialstring")); + if (ast_strlen_zero(dialstatus)) { + manager_event(EVENT_FLAG_CALL, "DialBegin", + "%s" + "%s" + "DialString: %s\r\n", + ast_str_buffer(caller_event_string), + ast_str_buffer(peer_event_string), + S_OR(dialstring, "unknown")); + } else { + manager_event(EVENT_FLAG_CALL, "DialEnd", + "%s" + "%s" + "DialStatus: %s\r\n", + ast_str_buffer(caller_event_string), + ast_str_buffer(peer_event_string), + S_OR(dialstatus, "unknown")); + } + } else { + /* TODO: If we don't have a caller, this should be treated as an Originate */ + } +} + static void manager_channels_shutdown(void) { stasis_message_router_unsubscribe(channel_state_router); @@ -636,6 +789,11 @@ int manager_channels_init(void) channel_blob_cb, NULL); + ret |= stasis_message_router_add(channel_state_router, + ast_channel_dial_type(), + channel_dial_cb, + NULL); + /* If somehow we failed to add any routes, just shut down the whole * thing and fail it. */ @@ -646,3 +804,4 @@ int manager_channels_init(void) return 0; } + |