summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES16
-rw-r--r--apps/app_meetme.c72
-rw-r--r--apps/app_queue.c49
-rw-r--r--channels/chan_dahdi.c283
-rw-r--r--channels/chan_gtalk.c7
-rw-r--r--channels/chan_iax2.c33
-rw-r--r--channels/chan_sip.c150
-rw-r--r--channels/sig_analog.c64
-rw-r--r--channels/sig_pri.c270
-rw-r--r--channels/sip/include/sip.h2
-rw-r--r--configs/sip.conf.sample2
-rw-r--r--include/asterisk/json.h12
-rw-r--r--include/asterisk/stasis.h26
-rw-r--r--main/core_local.c222
-rw-r--r--main/json.c69
-rw-r--r--res/res_agi.c16
16 files changed, 888 insertions, 405 deletions
diff --git a/CHANGES b/CHANGES
index 0d4649829..8c12974d2 100644
--- a/CHANGES
+++ b/CHANGES
@@ -143,7 +143,7 @@ AMI (Asterisk Manager Interface)
* The SIPqualifypeer action now acknowledges the request once it has established
that the request is against a known peer. It also issues a new event,
- 'SIPqualifypeerdone', once the qualify action has been completed.
+ 'SIPQualifyPeerDone', once the qualify action has been completed.
* The PlayDTMF action now supports an optional 'Duration' parameter. This
specifies the duration of the digit to be played, in milliseconds.
@@ -238,6 +238,20 @@ AMI (Asterisk Manager Interface)
information about each channel. The (infamous) "Join" and "Leave" AMI
events have been changed to "QueueCallerJoin" and "QueueCallerLeave".
+ * The MCID AMI event now publishes a channel snapshot when available and
+ its non-channel-snapshot parameters now use either the "MCallerID" or
+ "MConnectedID" prefixes with Subaddr*, Name*, and Num* suffixes instead
+ of "CallerID" and "ConnectedID" to avoid confusion with similarly named
+ parameters in the channel snapshot.
+
+ * The "Agentlogin" and "Agentlogoff" events have been renamed "AgentLogin" and
+ "AgentLogoff" respectively.
+
+ * The "Channel" key used in the "AlarmClear", "Alarm", and "DNDState" has been
+ renamed "DAHDIChannel" since it does not convey an Asterisk channel name.
+
+ * "ChannelUpdate" events have been removed.
+
AGI (Asterisk Gateway Interface)
------------------
* The manager event AGIExec has been split into AGIExecStart and AGIExecEnd.
diff --git a/apps/app_meetme.c b/apps/app_meetme.c
index 4bd732b59..b79ab63eb 100644
--- a/apps/app_meetme.c
+++ b/apps/app_meetme.c
@@ -1117,75 +1117,15 @@ static const char gain_map[] = {
15,
};
-/*!
- * \internal
- * \brief accessor for join message type
- * \since 12.0.0
- *
- * \retval pointer to the stasis message type
- * \retval NULL if not initialized
- */
-static struct stasis_message_type *meetme_join_type(void);
-
-/*!
- * \internal
- * \brief accessor for leave message type
- * \since 12.0.0
- *
- * \retval pointer to the stasis message type
- * \retval NULL if not initialized
- */
-static struct stasis_message_type *meetme_leave_type(void);
-
-/*!
- * \internal
- * \brief accessor for end message type
- * \since 12.0.0
- *
- * \retval pointer to the stasis message type
- * \retval NULL if not initialized
- */
-static struct stasis_message_type *meetme_end_type(void);
-
-/*!
- * \internal
- * \brief accessor for mute message type
- * \since 12.0.0
- *
- * \retval pointer to the stasis message type
- * \retval NULL if not initialized
- */
-static struct stasis_message_type *meetme_mute_type(void);
-
-/*!
- * \internal
- * \brief accessor for talking message type
- * \since 12.0.0
- *
- * \retval pointer to the stasis message type
- * \retval NULL if not initialized
- */
-static struct stasis_message_type *meetme_talking_type(void);
-
-/*!
- * \internal
- * \brief accessor for talk request message type
- * \since 12.0.0
- *
- * \retval pointer to the stasis message type
- * \retval NULL if not initialized
- */
-static struct stasis_message_type *meetme_talk_request_type(void);
-
/* Routes the various meetme message types to the meetme stasis callback function to turn them into events */
static struct stasis_message_router *meetme_event_message_router;
-STASIS_MESSAGE_TYPE_DEFN(meetme_join_type);
-STASIS_MESSAGE_TYPE_DEFN(meetme_leave_type);
-STASIS_MESSAGE_TYPE_DEFN(meetme_end_type);
-STASIS_MESSAGE_TYPE_DEFN(meetme_mute_type);
-STASIS_MESSAGE_TYPE_DEFN(meetme_talking_type);
-STASIS_MESSAGE_TYPE_DEFN(meetme_talk_request_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_join_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_leave_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_end_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_mute_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_talking_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_talk_request_type);
static void meetme_stasis_cb(void *data, struct stasis_subscription *sub,
struct stasis_topic *topic, struct stasis_message *message);
diff --git a/apps/app_queue.c b/apps/app_queue.c
index 7ff94c6b5..660b87701 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -1811,39 +1811,22 @@ static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, st
new->opos = *pos;
}
-struct stasis_message_type *queue_caller_join_type(void);
-struct stasis_message_type *queue_caller_leave_type(void);
-struct stasis_message_type *queue_caller_abandon_type(void);
-
-struct stasis_message_type *queue_member_status_type(void);
-struct stasis_message_type *queue_member_added_type(void);
-struct stasis_message_type *queue_member_removed_type(void);
-struct stasis_message_type *queue_member_pause_type(void);
-struct stasis_message_type *queue_member_penalty_type(void);
-struct stasis_message_type *queue_member_ringinuse_type(void);
-
-struct stasis_message_type *queue_agent_called_type(void);
-struct stasis_message_type *queue_agent_connect_type(void);
-struct stasis_message_type *queue_agent_complete_type(void);
-struct stasis_message_type *queue_agent_dump_type(void);
-struct stasis_message_type *queue_agent_ringnoanswer_type(void);
-
-STASIS_MESSAGE_TYPE_DEFN(queue_caller_join_type);
-STASIS_MESSAGE_TYPE_DEFN(queue_caller_leave_type);
-STASIS_MESSAGE_TYPE_DEFN(queue_caller_abandon_type);
-
-STASIS_MESSAGE_TYPE_DEFN(queue_member_status_type);
-STASIS_MESSAGE_TYPE_DEFN(queue_member_added_type);
-STASIS_MESSAGE_TYPE_DEFN(queue_member_removed_type);
-STASIS_MESSAGE_TYPE_DEFN(queue_member_pause_type);
-STASIS_MESSAGE_TYPE_DEFN(queue_member_penalty_type);
-STASIS_MESSAGE_TYPE_DEFN(queue_member_ringinuse_type);
-
-STASIS_MESSAGE_TYPE_DEFN(queue_agent_called_type);
-STASIS_MESSAGE_TYPE_DEFN(queue_agent_connect_type);
-STASIS_MESSAGE_TYPE_DEFN(queue_agent_complete_type);
-STASIS_MESSAGE_TYPE_DEFN(queue_agent_dump_type);
-STASIS_MESSAGE_TYPE_DEFN(queue_agent_ringnoanswer_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_caller_join_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_caller_leave_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_caller_abandon_type);
+
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_status_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_added_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_removed_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_pause_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_penalty_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_ringinuse_type);
+
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_called_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_connect_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_complete_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_dump_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_ringnoanswer_type);
static void queue_channel_manager_event(void *data,
struct stasis_subscription *sub, struct stasis_topic *topic,
diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c
index 24337e385..b22e73800 100644
--- a/channels/chan_dahdi.c
+++ b/channels/chan_dahdi.c
@@ -131,6 +131,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/data.h"
#include "asterisk/features_config.h"
#include "asterisk/bridging.h"
+#include "asterisk/stasis_channels.h"
/*** DOCUMENTATION
<application name="DAHDISendKeypadFacility" language="en_US">
@@ -296,6 +297,85 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<para>Similar to the CLI command "pri show spans".</para>
</description>
</manager>
+ <managerEvent language="en_US" name="AlarmClear">
+ <managerEventInstance class="EVENT_FLAG_SYSTEM">
+ <synopsis>Raised when an alarm is cleared on a DAHDI channel.</synopsis>
+ <syntax>
+ <parameter name="DAHDIChannel">
+ <para>The DAHDI channel on which the alarm was cleared.</para>
+ <note><para>This is not an Asterisk channel identifier.</para></note>
+ </parameter>
+ </syntax>
+ </managerEventInstance>
+ </managerEvent>
+ <managerEvent language="en_US" name="SpanAlarmClear">
+ <managerEventInstance class="EVENT_FLAG_SYSTEM">
+ <synopsis>Raised when an alarm is cleared on a DAHDI span.</synopsis>
+ <syntax>
+ <parameter name="Span">
+ <para>The span on which the alarm was cleared.</para>
+ </parameter>
+ </syntax>
+ </managerEventInstance>
+ </managerEvent>
+ <managerEvent language="en_US" name="DNDState">
+ <managerEventInstance class="EVENT_FLAG_SYSTEM">
+ <synopsis>Raised when the Do Not Disturb state is changed on a DAHDI channel.</synopsis>
+ <syntax>
+ <parameter name="DAHDIChannel">
+ <para>The DAHDI channel on which DND status changed.</para>
+ <note><para>This is not an Asterisk channel identifier.</para></note>
+ </parameter>
+ <parameter name="Status">
+ <enumlist>
+ <enum name="enabled"/>
+ <enum name="disabled"/>
+ </enumlist>
+ </parameter>
+ </syntax>
+ </managerEventInstance>
+ </managerEvent>
+ <managerEvent language="en_US" name="Alarm">
+ <managerEventInstance class="EVENT_FLAG_SYSTEM">
+ <synopsis>Raised when an alarm is set on a DAHDI channel.</synopsis>
+ <syntax>
+ <parameter name="DAHDIChannel">
+ <para>The channel on which the alarm occurred.</para>
+ <note><para>This is not an Asterisk channel identifier.</para></note>
+ </parameter>
+ <parameter name="Alarm">
+ <para>A textual description of the alarm that occurred.</para>
+ </parameter>
+ </syntax>
+ </managerEventInstance>
+ </managerEvent>
+ <managerEvent language="en_US" name="SpanAlarm">
+ <managerEventInstance class="EVENT_FLAG_SYSTEM">
+ <synopsis>Raised when an alarm is set on a DAHDI span.</synopsis>
+ <syntax>
+ <parameter name="Span">
+ <para>The span on which the alarm occurred.</para>
+ </parameter>
+ <parameter name="Alarm">
+ <para>A textual description of the alarm that occurred.</para>
+ </parameter>
+ </syntax>
+ </managerEventInstance>
+ </managerEvent>
+ <managerEvent language="en_US" name="DAHDIChannel">
+ <managerEventInstance class="EVENT_FLAG_CALL">
+ <synopsis>Raised when a DAHDI channel is created or an underlying technology is associated with a DAHDI channel.</synopsis>
+ <syntax>
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+ <parameter name="DAHDISpan">
+ <para>The DAHDI span associated with this channel.</para>
+ </parameter>
+ <parameter name="DAHDIChannel">
+ <para>The DAHDI channel associated with this channel.</para>
+ </parameter>
+ </syntax>
+ </managerEventInstance>
+ </managerEvent>
***/
#define SMDI_MD_WAIT_TIMEOUT 1500 /* 1.5 seconds */
@@ -2270,6 +2350,50 @@ static void my_deadlock_avoidance_private(void *pvt)
DEADLOCK_AVOIDANCE(&p->lock);
}
+static struct ast_manager_event_blob *dahdichannel_to_ami(struct stasis_message *msg)
+{
+ RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
+ struct ast_channel_blob *obj = stasis_message_data(msg);
+ struct ast_json *span, *channel;
+
+ channel_string = ast_manager_build_channel_state_string(obj->snapshot);
+ if (!channel_string) {
+ return NULL;
+ }
+
+ span = ast_json_object_get(obj->blob, "span");
+ channel = ast_json_object_get(obj->blob, "channel");
+
+ return ast_manager_event_blob_create(EVENT_FLAG_CALL, "DAHDIChannel",
+ "%s"
+ "DAHDISpan: %d\r\n"
+ "DAHDIChannel: %s\r\n",
+ ast_str_buffer(channel_string),
+ (unsigned int)ast_json_integer_get(span),
+ ast_json_string_get(channel));
+}
+
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(dahdichannel_type,
+ .to_ami = dahdichannel_to_ami,
+ );
+
+/*! \brief Sends a DAHDIChannel channel blob used to produce DAHDIChannel AMI messages */
+static void publish_dahdichannel(struct ast_channel *chan, int span, const char *dahdi_channel)
+{
+ RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
+
+ ast_assert(dahdi_channel != NULL);
+
+ blob = ast_json_pack("{s: i, s: s}",
+ "span", span,
+ "channel", dahdi_channel);
+ if (!blob) {
+ return;
+ }
+
+ ast_channel_publish_blob(chan, dahdichannel_type(), blob);
+}
+
/*!
* \internal
* \brief Post an AMI DAHDI channel association event.
@@ -2294,20 +2418,7 @@ static void dahdi_ami_channel_event(struct dahdi_pvt *p, struct ast_channel *cha
/* Real channel */
snprintf(ch_name, sizeof(ch_name), "%d", p->channel);
}
- /*** DOCUMENTATION
- <managerEventInstance>
- <synopsis>Raised when a DAHDI channel is created or an underlying technology is associated with a DAHDI channel.</synopsis>
- </managerEventInstance>
- ***/
- ast_manager_event(chan, EVENT_FLAG_CALL, "DAHDIChannel",
- "Channel: %s\r\n"
- "Uniqueid: %s\r\n"
- "DAHDISpan: %d\r\n"
- "DAHDIChannel: %s\r\n",
- ast_channel_name(chan),
- ast_channel_uniqueid(chan),
- p->span,
- ch_name);
+ publish_dahdichannel(chan, p->span, ch_name);
}
#ifdef HAVE_PRI
@@ -3956,6 +4067,37 @@ static void dahdi_queue_frame(struct dahdi_pvt *p, struct ast_frame *f)
}
}
+static void publish_channel_alarm_clear(int channel)
+{
+ RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
+ RAII_VAR(struct ast_str *, dahdi_chan, ast_str_create(32), ast_free);
+ if (!dahdi_chan) {
+ return;
+ }
+
+ ast_str_set(&dahdi_chan, 0, "%d", channel);
+ ast_log(LOG_NOTICE, "Alarm cleared on channel DAHDI/%d\n", channel);
+ body = ast_json_pack("{s: s}", "DAHDIChannel", ast_str_buffer(dahdi_chan));
+ if (!body) {
+ return;
+ }
+
+ ast_manager_publish_event("AlarmClear", EVENT_FLAG_SYSTEM, body);
+}
+
+static void publish_span_alarm_clear(int span)
+{
+ RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
+
+ ast_log(LOG_NOTICE, "Alarm cleared on span %d\n", span);
+ body = ast_json_pack("{s: i}", "Span", span);
+ if (!body) {
+ return;
+ }
+
+ ast_manager_publish_event("SpanAlarmClear", EVENT_FLAG_SYSTEM, body);
+}
+
static void handle_clear_alarms(struct dahdi_pvt *p)
{
#if defined(HAVE_PRI)
@@ -3965,22 +4107,10 @@ static void handle_clear_alarms(struct dahdi_pvt *p)
#endif /* defined(HAVE_PRI) */
if (report_alarms & REPORT_CHANNEL_ALARMS) {
- ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", p->channel);
- /*** DOCUMENTATION
- <managerEventInstance>
- <synopsis>Raised when an alarm is cleared on a DAHDI channel.</synopsis>
- </managerEventInstance>
- ***/
- manager_event(EVENT_FLAG_SYSTEM, "AlarmClear", "Channel: %d\r\n", p->channel);
+ publish_channel_alarm_clear(p->channel);
}
if (report_alarms & REPORT_SPAN_ALARMS && p->manages_span_alarms) {
- ast_log(LOG_NOTICE, "Alarm cleared on span %d\n", p->span);
- /*** DOCUMENTATION
- <managerEventInstance>
- <synopsis>Raised when an alarm is cleared on a DAHDI span.</synopsis>
- </managerEventInstance>
- ***/
- manager_event(EVENT_FLAG_SYSTEM, "SpanAlarmClear", "Span: %d\r\n", p->span);
+ publish_span_alarm_clear(p->span);
}
}
@@ -8037,6 +8167,39 @@ static void dahdi_handle_dtmf(struct ast_channel *ast, int idx, struct ast_frame
}
}
+static void publish_span_alarm(int span, const char *alarm_txt)
+{
+ RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
+
+ body = ast_json_pack("{s: i, s: s}",
+ "Span", span,
+ "Alarm", alarm_txt);
+ if (!body) {
+ return;
+ }
+
+ ast_manager_publish_event("SpanAlarm", EVENT_FLAG_SYSTEM, body);
+}
+
+static void publish_channel_alarm(int channel, const char *alarm_txt)
+{
+ RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
+ RAII_VAR(struct ast_str *, dahdi_chan, ast_str_create(32), ast_free);
+ if (!dahdi_chan) {
+ return;
+ }
+
+ ast_str_set(&dahdi_chan, 0, "%d", channel);
+ body = ast_json_pack("{s: s, s: s}",
+ "DAHDIChannel", ast_str_buffer(dahdi_chan),
+ "Alarm", alarm_txt);
+ if (!body) {
+ return;
+ }
+
+ ast_manager_publish_event("Alarm", EVENT_FLAG_SYSTEM, body);
+}
+
static void handle_alarms(struct dahdi_pvt *p, int alms)
{
const char *alarm_str;
@@ -8050,28 +8213,12 @@ static void handle_alarms(struct dahdi_pvt *p, int alms)
alarm_str = alarm2str(alms);
if (report_alarms & REPORT_CHANNEL_ALARMS) {
ast_log(LOG_WARNING, "Detected alarm on channel %d: %s\n", p->channel, alarm_str);
- /*** DOCUMENTATION
- <managerEventInstance>
- <synopsis>Raised when an alarm is set on a DAHDI channel.</synopsis>
- </managerEventInstance>
- ***/
- manager_event(EVENT_FLAG_SYSTEM, "Alarm",
- "Alarm: %s\r\n"
- "Channel: %d\r\n",
- alarm_str, p->channel);
+ publish_channel_alarm(p->channel, alarm_str);
}
if (report_alarms & REPORT_SPAN_ALARMS && p->manages_span_alarms) {
ast_log(LOG_WARNING, "Detected alarm on span %d: %s\n", p->span, alarm_str);
- /*** DOCUMENTATION
- <managerEventInstance>
- <synopsis>Raised when an alarm is set on a DAHDI span.</synopsis>
- </managerEventInstance>
- ***/
- manager_event(EVENT_FLAG_SYSTEM, "SpanAlarm",
- "Alarm: %s\r\n"
- "Span: %d\r\n",
- alarm_str, p->span);
+ publish_span_alarm(p->span, alarm_str);
}
}
@@ -10083,6 +10230,26 @@ static int dahdi_wink(struct dahdi_pvt *p, int idx)
return 0;
}
+static void publish_dnd_state(int channel, const char *status)
+{
+ RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
+ RAII_VAR(struct ast_str *, dahdichan, ast_str_create(32), ast_free);
+ if (!dahdichan) {
+ return;
+ }
+
+ ast_str_set(&dahdichan, 0, "%d", channel);
+
+ body = ast_json_pack("{s: s, s: s}",
+ "DAHDIChannel", ast_str_buffer(dahdichan),
+ "Status", status);
+ if (!body) {
+ return;
+ }
+
+ ast_manager_publish_event("DNDState", EVENT_FLAG_SYSTEM, body);
+}
+
/*! \brief enable or disable the chan_dahdi Do-Not-Disturb mode for a DAHDI channel
* \param dahdichan "Physical" DAHDI channel (e.g: DAHDI/5)
* \param flag on 1 to enable, 0 to disable, -1 return dnd value
@@ -10107,24 +10274,7 @@ static int dahdi_dnd(struct dahdi_pvt *dahdichan, int flag)
ast_verb(3, "%s DND on channel %d\n",
flag? "Enabled" : "Disabled",
dahdichan->channel);
- /*** DOCUMENTATION
- <managerEventInstance>
- <synopsis>Raised when the Do Not Disturb state is changed on a DAHDI channel.</synopsis>
- <syntax>
- <parameter name="Status">
- <enumlist>
- <enum name="enabled"/>
- <enum name="disabled"/>
- </enumlist>
- </parameter>
- </syntax>
- </managerEventInstance>
- ***/
- manager_event(EVENT_FLAG_SYSTEM, "DNDState",
- "Channel: DAHDI/%d\r\n"
- "Status: %s\r\n", dahdichan->channel,
- flag? "enabled" : "disabled");
-
+ publish_dnd_state(dahdichan->channel, flag ? "enabled" : "disabled");
return 0;
}
@@ -17154,6 +17304,7 @@ static int __unload_module(void)
ast_cond_destroy(&ss_thread_complete);
dahdi_tech.capabilities = ast_format_cap_destroy(dahdi_tech.capabilities);
+ STASIS_MESSAGE_TYPE_CLEANUP(dahdichannel_type);
return 0;
}
@@ -19154,6 +19305,10 @@ static int load_module(void)
int y;
#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
+ if (STASIS_MESSAGE_TYPE_INIT(dahdichannel_type)) {
+ return AST_MODULE_LOAD_FAILURE;
+ }
+
if (!(dahdi_tech.capabilities = ast_format_cap_alloc())) {
return AST_MODULE_LOAD_FAILURE;
}
diff --git a/channels/chan_gtalk.c b/channels/chan_gtalk.c
index 49e7ce8ff..a0aa0b95d 100644
--- a/channels/chan_gtalk.c
+++ b/channels/chan_gtalk.c
@@ -86,6 +86,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/jabber.h"
#include "asterisk/jingle.h"
#include "asterisk/features.h"
+#include "asterisk/stasis_channels.h"
#define GOOGLE_CONFIG "gtalk.conf"
@@ -546,8 +547,6 @@ static int gtalk_answer(struct ast_channel *ast)
ast_debug(1, "Answer!\n");
ast_mutex_lock(&p->lock);
gtalk_invite(p, p->them, p->us,p->sid, 0);
- manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate", "Channel: %s\r\nChanneltype: %s\r\nGtalk-SID: %s\r\n",
- ast_channel_name(ast), "GTALK", p->sid);
ast_mutex_unlock(&p->lock);
return res;
}
@@ -1216,9 +1215,7 @@ static struct ast_channel *gtalk_new(struct gtalk *client, struct gtalk_pvt *i,
ast_hangup(tmp);
tmp = NULL;
} else {
- manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate",
- "Channel: %s\r\nChanneltype: %s\r\nGtalk-SID: %s\r\n",
- i->owner ? ast_channel_name(i->owner) : "", "Gtalk", i->sid);
+ send_channel_update(i->owner, i->sid);
}
return tmp;
}
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index 46d1f7d06..23006364c 100644
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -1392,17 +1392,6 @@ static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub,
reload_config(1);
}
-
-/*! \brief Send manager event at call setup to link between Asterisk channel name
- and IAX2 call identifiers */
-static void iax2_ami_channelupdate(struct chan_iax2_pvt *pvt)
-{
- manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate",
- "Channel: %s\r\nChanneltype: IAX2\r\nIAX2-callno-local: %d\r\nIAX2-callno-remote: %d\r\nIAX2-peer: %s\r\n",
- pvt->owner ? ast_channel_name(pvt->owner) : "",
- pvt->callno, pvt->peercallno, pvt->peer ? pvt->peer : "");
-}
-
static const struct ast_datastore_info iax2_variable_datastore_info = {
.type = "IAX2_VARIABLE",
.duplicate = iax2_dup_variable_datastore,
@@ -5552,10 +5541,6 @@ static int iax2_answer(struct ast_channel *c)
{
unsigned short callno = PTR_TO_CALLNO(ast_channel_tech_pvt(c));
ast_debug(1, "Answering IAX2 call\n");
- ast_mutex_lock(&iaxsl[callno]);
- if (iaxs[callno])
- iax2_ami_channelupdate(iaxs[callno]);
- ast_mutex_unlock(&iaxsl[callno]);
return send_command_locked(callno, AST_FRAME_CONTROL, AST_CONTROL_ANSWER, 0, NULL, 0, -1);
}
@@ -5678,7 +5663,6 @@ static struct ast_channel *ast_iax2_new(int callno, int state, iax2_format capab
}
return NULL;
}
- iax2_ami_channelupdate(i);
if (!tmp) {
return NULL;
}
@@ -9367,23 +9351,6 @@ static void log_jitterstats(unsigned short callno)
iaxs[callno]->remote_rr.dropped,
iaxs[callno]->remote_rr.ooo,
iaxs[callno]->remote_rr.packets);
- manager_event(EVENT_FLAG_REPORTING, "JitterBufStats", "Owner: %s\r\nPing: %d\r\nLocalJitter: %d\r\nLocalJBDelay: %d\r\nLocalTotalLost: %d\r\nLocalLossPercent: %d\r\nLocalDropped: %d\r\nLocalooo: %d\r\nLocalReceived: %d\r\nRemoteJitter: %d\r\nRemoteJBDelay: %d\r\nRemoteTotalLost: %d\r\nRemoteLossPercent: %d\r\nRemoteDropped: %d\r\nRemoteooo: %d\r\nRemoteReceived: %d\r\n",
- ast_channel_name(iaxs[callno]->owner),
- iaxs[callno]->pingtime,
- localjitter,
- localdelay,
- locallost,
- locallosspct,
- localdropped,
- localooo,
- localpackets,
- iaxs[callno]->remote_rr.jitter,
- iaxs[callno]->remote_rr.delay,
- iaxs[callno]->remote_rr.losscnt,
- iaxs[callno]->remote_rr.losspct/1000,
- iaxs[callno]->remote_rr.dropped,
- iaxs[callno]->remote_rr.ooo,
- iaxs[callno]->remote_rr.packets);
}
ast_mutex_unlock(&iaxsl[callno]);
}
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 4b795521e..9a5f086ad 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -295,6 +295,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/app.h"
#include "asterisk/bridging.h"
#include "asterisk/stasis_endpoints.h"
+#include "asterisk/stasis_channels.h"
#include "asterisk/features_config.h"
/*** DOCUMENTATION
@@ -563,7 +564,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<para>Qualify a SIP peer.</para>
</description>
<see-also>
- <ref type="managerEvent">SIPqualifypeerdone</ref>
+ <ref type="managerEvent">SIPQualifyPeerDone</ref>
</see-also>
</manager>
<manager name="SIPshowregistry" language="en_US">
@@ -621,6 +622,37 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<para>Specifying a prefix of <literal>sip:</literal> will send the
message as a SIP MESSAGE request.</para>
</info>
+ <managerEvent language="en_US" name="SIPQualifyPeerDone">
+ <managerEventInstance class="EVENT_FLAG_CALL">
+ <synopsis>Raised when SIPQualifyPeer has finished qualifying the specified peer.</synopsis>
+ <syntax>
+ <parameter name="Peer">
+ <para>The name of the peer.</para>
+ </parameter>
+ <parameter name="ActionID">
+ <para>This is only included if an ActionID Header was sent with the action request, in which case it will be that ActionID.</para>
+ </parameter>
+ </syntax>
+ <see-also>
+ <ref type="manager">SIPqualifypeer</ref>
+ </see-also>
+ </managerEventInstance>
+ </managerEvent>
+ <managerEvent language="en_US" name="SessionTimeout">
+ <managerEventInstance class="EVENT_FLAG_CALL">
+ <synopsis>Raised when a SIP session times out.</synopsis>
+ <syntax>
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+ <parameter name="Source">
+ <para>The source of the session timeout.</para>
+ <enumlist>
+ <enum name="RTPTimeout" />
+ <enum name="SIPSessionTimer" />
+ </enumlist>
+ </parameter>
+ </syntax>
+ </managerEventInstance>
+ </managerEvent>
***/
static int min_expiry = DEFAULT_MIN_EXPIRY; /*!< Minimum accepted registration time */
@@ -1042,6 +1074,11 @@ static struct sip_auth_container *authl = NULL;
/*! \brief Global authentication container protection while adjusting the references. */
AST_MUTEX_DEFINE_STATIC(authl_lock);
+static struct ast_manager_event_blob *session_timeout_to_ami(struct stasis_message *msg);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(session_timeout_type,
+ .to_ami = session_timeout_to_ami,
+ );
+
/* --- Sockets and networking --------------*/
/*! \brief Main socket for UDP SIP communication.
@@ -8212,13 +8249,6 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
append_history(i, "NewChan", "Channel %s - from %s", ast_channel_name(tmp), i->callid);
}
- /* Inform manager user about new channel and their SIP call ID */
- if (sip_cfg.callevents) {
- manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate",
- "Channel: %s\r\nUniqueid: %s\r\nChanneltype: %s\r\nSIPcallid: %s\r\nSIPfullcontact: %s\r\n",
- ast_channel_name(tmp), ast_channel_uniqueid(tmp), "SIP", i->callid, i->fullcontact);
- }
-
return tmp;
}
@@ -20007,6 +20037,21 @@ static int manager_sip_peer_status(struct mansession *s, const struct message *m
return 0;
}
+static void publish_qualify_peer_done(const char *id, const char *peer)
+{
+ RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
+
+ if (ast_strlen_zero(id)) {
+ body = ast_json_pack("{s: s}", "Peer", peer);
+ } else {
+ body = ast_json_pack("{s: s, s: s}", "Peer", peer, "ActionID", id);
+ }
+ if (!body) {
+ return;
+ }
+
+ ast_manager_publish_event("SIPQualifyPeerDone", EVENT_FLAG_CALL, body);
+}
/*! \brief Send qualify message to peer from cli or manager. Mostly for debugging. */
static char *_sip_qualify_peer(int type, int fd, struct mansession *s, const struct message *m, int argc, const char *argv[])
@@ -20019,41 +20064,15 @@ static char *_sip_qualify_peer(int type, int fd, struct mansession *s, const str
load_realtime = (argc == 5 && !strcmp(argv[4], "load")) ? TRUE : FALSE;
if ((peer = sip_find_peer(argv[3], NULL, load_realtime, FINDPEERS, FALSE, 0))) {
-
const char *id = astman_get_header(m,"ActionID");
- char idText[256] = "";
if (type != 0) {
astman_send_ack(s, m, "SIP peer found - will qualify");
}
- if (!ast_strlen_zero(id)) {
- snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
- }
-
sip_poke_peer(peer, 1);
- /*** DOCUMENTATION
- <managerEventInstance>
- <synopsis>Raised when SIPqualifypeer has finished qualifying the specified peer.</synopsis>
- <syntax>
- <parameter name="Peer">
- <para>The name of the peer.</para>
- </parameter>
- <parameter name="ActionID">
- <para>This is only included if an ActionID Header was sent with the action request, in which case it will be that ActionID.</para>
- </parameter>
- </syntax>
- <see-also>
- <ref type="manager">SIPqualifypeer</ref>
- </see-also>
- </managerEventInstance>
- ***/
- manager_event(EVENT_FLAG_CALL, "SIPqualifypeerdone",
- "Peer: %s\r\n"
- "%s",
- argv[3],
- idText);
+ publish_qualify_peer_done(id, argv[3]);
sip_unref_peer(peer, "qualify: done with peer");
} else if (type == 0) {
@@ -20887,7 +20906,6 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_
ast_cli(a->fd, " From: Domain: %s\n", default_fromdomain);
}
ast_cli(a->fd, " Record SIP history: %s\n", AST_CLI_ONOFF(recordhistory));
- ast_cli(a->fd, " Call Events: %s\n", AST_CLI_ONOFF(sip_cfg.callevents));
ast_cli(a->fd, " Auth. Failure Events: %s\n", AST_CLI_ONOFF(global_authfailureevents));
ast_cli(a->fd, " T.38 support: %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[1], SIP_PAGE2_T38SUPPORT)));
@@ -23140,11 +23158,6 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
if (!req->ignore && p->owner) {
if (!reinvite) {
ast_queue_control(p->owner, AST_CONTROL_ANSWER);
- if (sip_cfg.callevents) {
- manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate",
- "Channel: %s\r\nChanneltype: %s\r\nUniqueid: %s\r\nSIPcallid: %s\r\nSIPfullcontact: %s\r\nPeername: %s\r\n",
- ast_channel_name(p->owner), "SIP", ast_channel_uniqueid(p->owner), p->callid, p->fullcontact, p->peername);
- }
} else { /* RE-invite */
if (p->t38.state == T38_DISABLED || p->t38.state == T38_REJECTED) {
ast_queue_control(p->owner, AST_CONTROL_UPDATE_RTP_PEER);
@@ -28458,6 +28471,39 @@ static int sip_send_mwi_to_peer(struct sip_peer *peer, int cache_only)
return 0;
}
+static struct ast_manager_event_blob *session_timeout_to_ami(struct stasis_message *msg)
+{
+ RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
+ struct ast_channel_blob *obj = stasis_message_data(msg);
+ const char *source = ast_json_string_get(ast_json_object_get(obj->blob, "source"));
+
+ channel_string = ast_manager_build_channel_state_string(obj->snapshot);
+ if (!channel_string) {
+ return NULL;
+ }
+
+ return ast_manager_event_blob_create(EVENT_FLAG_CALL, "SessionTimeout",
+ "%s"
+ "Source: %s\r\n",
+ ast_str_buffer(channel_string), source);
+}
+
+/*! \brief Sends a session timeout channel blob used to produce SessionTimeout AMI messages */
+static void send_session_timeout(struct ast_channel *chan, const char *source)
+{
+ RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
+
+ ast_assert(chan != NULL);
+ ast_assert(source != NULL);
+
+ blob = ast_json_pack("{s: s}", "source", source);
+ if (!blob) {
+ return;
+ }
+
+ ast_channel_publish_blob(chan, session_timeout_type(), blob);
+}
+
/*!
* \brief helper function for the monitoring thread -- seems to be called with the assumption that the dialog is locked
*
@@ -28533,8 +28579,8 @@ static int check_rtp_timeout(struct sip_pvt *dialog, time_t t)
}
ast_log(LOG_NOTICE, "Disconnecting call '%s' for lack of RTP activity in %ld seconds\n",
ast_channel_name(dialog->owner), (long) (t - dialog->lastrtprx));
- manager_event(EVENT_FLAG_CALL, "SessionTimeout", "Source: RTPTimeout\r\n"
- "Channel: %s\r\nUniqueid: %s\r\n", ast_channel_name(dialog->owner), ast_channel_uniqueid(dialog->owner));
+ send_session_timeout(dialog->owner, "RTPTimeout");
+
/* Issue a softhangup */
ast_softhangup_nolock(dialog->owner, AST_SOFTHANGUP_DEV);
ast_channel_unlock(dialog->owner);
@@ -28813,8 +28859,7 @@ static int proc_session_timer(const void *vp)
sip_pvt_lock(p);
}
- manager_event(EVENT_FLAG_CALL, "SessionTimeout", "Source: SIPSessionTimer\r\n"
- "Channel: %s\r\nUniqueid: %s\r\n", ast_channel_name(p->owner), ast_channel_uniqueid(p->owner));
+ send_session_timeout(p->owner, "SIPSessionTimer");
ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_DEV);
ast_channel_unlock(p->owner);
sip_pvt_unlock(p);
@@ -29551,10 +29596,6 @@ static struct ast_channel *sip_request_call(const char *type, struct ast_format_
callid = ast_callid_unref(callid);
}
- if (sip_cfg.callevents)
- manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate",
- "Channel: %s\r\nChanneltype: %s\r\nSIPcallid: %s\r\nSIPfullcontact: %s\r\nPeername: %s\r\n",
- p->owner? ast_channel_name(p->owner) : "", "SIP", p->callid, p->fullcontact, p->peername);
sip_pvt_unlock(p);
if (!tmpc) {
dialog_unlink_all(p);
@@ -31160,7 +31201,6 @@ static int reload_config(enum channelreloadreason reason)
/* Misc settings for the channel */
global_relaxdtmf = FALSE;
- sip_cfg.callevents = DEFAULT_CALLEVENTS;
global_authfailureevents = FALSE;
global_t1 = DEFAULT_TIMER_T1;
global_timer_b = 64 * DEFAULT_TIMER_T1;
@@ -31641,8 +31681,6 @@ static int reload_config(enum channelreloadreason reason)
ast_log(LOG_WARNING, "Invalid qualifyfreq number '%s' at line %d of %s\n", v->value, v->lineno, config);
global_qualifyfreq = DEFAULT_QUALIFYFREQ;
}
- } else if (!strcasecmp(v->name, "callevents")) {
- sip_cfg.callevents = ast_true(v->value);
} else if (!strcasecmp(v->name, "authfailureevents")) {
global_authfailureevents = ast_true(v->value);
} else if (!strcasecmp(v->name, "maxcallbitrate")) {
@@ -32079,8 +32117,6 @@ static int reload_config(enum channelreloadreason reason)
notify_types = NULL;
}
- /* Done, tell the manager */
- manager_event(EVENT_FLAG_SYSTEM, "ChannelReload", "ChannelType: SIP\r\nReloadReason: %s\r\nRegistry_Count: %d\r\nPeer_Count: %d\r\n", channelreloadreason2txt(reason), registry_count, peer_count);
run_end = time(0);
ast_debug(4, "SIP reload_config done...Runtime= %d sec\n", (int)(run_end-run_start));
@@ -34059,6 +34095,10 @@ static int load_module(void)
{
ast_verbose("SIP channel loading...\n");
+ if (STASIS_MESSAGE_TYPE_INIT(session_timeout_type)) {
+ return AST_MODULE_LOAD_FAILURE;
+ }
+
if (!(sip_tech.capabilities = ast_format_cap_alloc())) {
return AST_MODULE_LOAD_FAILURE;
}
@@ -34425,6 +34465,8 @@ static int unload_module(void)
ast_format_cap_destroy(sip_tech.capabilities);
sip_cfg.caps = ast_format_cap_destroy(sip_cfg.caps);
+ STASIS_MESSAGE_TYPE_CLEANUP(session_timeout_type);
+
return 0;
}
diff --git a/channels/sig_analog.c b/channels/sig_analog.c
index 9660d3fe6..276e0fd3e 100644
--- a/channels/sig_analog.c
+++ b/channels/sig_analog.c
@@ -2622,6 +2622,19 @@ int analog_ss_thread_start(struct analog_pvt *p, struct ast_channel *chan)
return ast_pthread_create_detached(&threadid, NULL, __analog_ss_thread, p);
}
+static void analog_publish_channel_alarm_clear(int channel)
+{
+ RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
+
+ ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", channel);
+ body = ast_json_pack("{s: i}", "Channel", channel);
+ if (!body) {
+ return;
+ }
+
+ ast_manager_publish_event("AlarmClear", EVENT_FLAG_SYSTEM, body);
+}
+
static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_channel *ast)
{
int res, x;
@@ -3086,14 +3099,7 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
break;
case ANALOG_EVENT_NOALARM:
analog_set_alarm(p, 0);
- ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", p->channel);
- /*** DOCUMENTATION
- <managerEventInstance>
- <synopsis>Raised when an Alarm is cleared on an Analog channel.</synopsis>
- </managerEventInstance>
- ***/
- manager_event(EVENT_FLAG_SYSTEM, "AlarmClear",
- "Channel: %d\r\n", p->channel);
+ analog_publish_channel_alarm_clear(p->channel);
break;
case ANALOG_EVENT_WINKFLASH:
if (p->inalarm) {
@@ -3735,9 +3741,7 @@ void *analog_handle_init_event(struct analog_pvt *i, int event)
break;
case ANALOG_EVENT_NOALARM:
analog_set_alarm(i, 0);
- ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", i->channel);
- manager_event(EVENT_FLAG_SYSTEM, "AlarmClear",
- "Channel: %d\r\n", i->channel);
+ analog_publish_channel_alarm_clear(i->channel);
break;
case ANALOG_EVENT_ALARM:
analog_set_alarm(i, 1);
@@ -3940,6 +3944,26 @@ int analog_fixup(struct ast_channel *oldchan, struct ast_channel *newchan, void
return 0;
}
+static void analog_publish_dnd_state(int channel, const char *status)
+{
+ RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
+ RAII_VAR(struct ast_str *, dahdichan, ast_str_create(32), ast_free);
+ if (!dahdichan) {
+ return;
+ }
+
+ ast_str_set(&dahdichan, 0, "DAHDI/%d", channel);
+
+ body = ast_json_pack("{s: s, s: s}",
+ "Channel", ast_str_buffer(dahdichan),
+ "Status", status);
+ if (!body) {
+ return;
+ }
+
+ ast_manager_publish_event("DNDState", EVENT_FLAG_SYSTEM, body);
+}
+
int analog_dnd(struct analog_pvt *p, int flag)
{
if (flag == -1) {
@@ -3951,23 +3975,7 @@ int analog_dnd(struct analog_pvt *p, int flag)
ast_verb(3, "%s DND on channel %d\n",
flag ? "Enabled" : "Disabled",
p->channel);
- /*** DOCUMENTATION
- <managerEventInstance>
- <synopsis>Raised when the Do Not Disturb state is changed on an Analog channel.</synopsis>
- <syntax>
- <parameter name="Status">
- <enumlist>
- <enum name="enabled"/>
- <enum name="disabled"/>
- </enumlist>
- </parameter>
- </syntax>
- </managerEventInstance>
- ***/
- manager_event(EVENT_FLAG_SYSTEM, "DNDState",
- "Channel: DAHDI/%d\r\n"
- "Status: %s\r\n", p->channel,
- flag ? "enabled" : "disabled");
+ analog_publish_dnd_state(p->channel, flag ? "enabled" : "disabled");
return 0;
}
diff --git a/channels/sig_pri.c b/channels/sig_pri.c
index d5d6f4976..5f0792878 100644
--- a/channels/sig_pri.c
+++ b/channels/sig_pri.c
@@ -26,6 +26,68 @@
/*** MODULEINFO
<support_level>core</support_level>
***/
+/*** DOCUMENTATION
+ <managerEvent language="en_US" name="MCID">
+ <managerEventInstance class="EVENT_FLAG_CALL">
+ <synopsis>Published when a malicious call ID request arrives.</synopsis>
+ <syntax>
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+ <parameter name="MCallerIDNumValid">
+ </parameter>
+ <parameter name="MCallerIDNum">
+ </parameter>
+ <parameter name="MCallerIDton">
+ </parameter>
+ <parameter name="MCallerIDNumPlan">
+ </parameter>
+ <parameter name="MCallerIDNumPres">
+ </parameter>
+ <parameter name="MCallerIDNameValid">
+ </parameter>
+ <parameter name="MCallerIDName">
+ </parameter>
+ <parameter name="MCallerIDNameCharSet">
+ </parameter>
+ <parameter name="MCallerIDNamePres">
+ </parameter>
+ <parameter name="MCallerIDSubaddr">
+ </parameter>
+ <parameter name="MCallerIDSubaddrType">
+ </parameter>
+ <parameter name="MCallerIDSubaddrOdd">
+ </parameter>
+ <parameter name="MCallerIDPres">
+ </parameter>
+ <parameter name="MConnectedIDNumValid">
+ </parameter>
+ <parameter name="MConnectedIDNum">
+ </parameter>
+ <parameter name="MConnectedIDton">
+ </parameter>
+ <parameter name="MConnectedIDNumPlan">
+ </parameter>
+ <parameter name="MConnectedIDNumPres">
+ </parameter>
+ <parameter name="MConnectedIDNameValid">
+ </parameter>
+ <parameter name="MConnectedIDName">
+ </parameter>
+ <parameter name="MConnectedIDNameCharSet">
+ </parameter>
+ <parameter name="MConnectedIDNamePres">
+ </parameter>
+ <parameter name="MConnectedIDSubaddr">
+ </parameter>
+ <parameter name="MConnectedIDSubaddrType">
+ </parameter>
+ <parameter name="MConnectedIDSubaddrOdd">
+ </parameter>
+ <parameter name="MConnectedIDPres">
+ </parameter>
+ </syntax>
+ </managerEventInstance>
+ </managerEvent>
+ ***/
#include "asterisk.h"
@@ -51,6 +113,7 @@
#include "asterisk/features.h"
#include "asterisk/aoc.h"
#include "asterisk/bridging.h"
+#include "asterisk/stasis_channels.h"
#include "sig_pri.h"
#ifndef PRI_EVENT_FACILITY
@@ -2270,9 +2333,74 @@ static int sig_pri_msn_match(const char *msn_patterns, const char *exten)
}
#if defined(HAVE_PRI_MCID)
+static void party_number_json_to_ami(struct ast_str **msg, const char *prefix, struct ast_json *number)
+{
+ const char *num_txt, *pres_txt;
+ int plan, pres;
+ if (!number) {
+ ast_str_append(msg, 0,
+ "%sNumValid: 0\r\n"
+ "%sNum: \r\n"
+ "%ston: 0\r\n",
+ prefix, prefix, prefix);
+ return;
+ }
+
+ num_txt = ast_json_string_get(ast_json_object_get(number, "number"));
+ plan = ast_json_integer_get(ast_json_object_get(number, "plan"));
+ pres = ast_json_integer_get(ast_json_object_get(number, "presentation"));
+ pres_txt = ast_json_string_get(ast_json_object_get(number, "presentation_txt"));
+
+ ast_str_append(msg, 0, "%sNumValid: 1\r\n", prefix);
+ ast_str_append(msg, 0, "%sNum: %s\r\n", prefix, num_txt);
+ ast_str_append(msg, 0, "%ston: %d\r\n", prefix, plan);
+ ast_str_append(msg, 0, "%sNumPlan: %d\r\n", prefix, plan);
+ ast_str_append(msg, 0, "%sNumPres: %d (%s)\r\n", prefix, pres, pres_txt);
+}
+
+static void party_name_json_to_ami(struct ast_str **msg, const char *prefix, struct ast_json *name)
+{
+ const char *name_txt, *pres_txt, *charset;
+ int pres;
+ if (!name) {
+ ast_str_append(msg, 0,
+ "%sNameValid: 0\r\n"
+ "%sName: \r\n",
+ prefix, prefix);
+ return;
+ }
+
+ name_txt = ast_json_string_get(ast_json_object_get(name, "name"));
+ charset = ast_json_string_get(ast_json_object_get(name, "character_set"));
+ pres = ast_json_integer_get(ast_json_object_get(name, "presentation"));
+ pres_txt = ast_json_string_get(ast_json_object_get(name, "presentation_txt"));
+
+ ast_str_append(msg, 0, "%sNameValid: 1\r\n", prefix);
+ ast_str_append(msg, 0, "%sName: %s\r\n", prefix, name_txt);
+ ast_str_append(msg, 0, "%sNameCharSet: %s\r\n", prefix, charset);
+ ast_str_append(msg, 0, "%sNamePres: %d (%s)\r\n", prefix, pres, pres_txt);
+}
+
+static void party_subaddress_json_to_ami(struct ast_str **msg, const char *prefix, struct ast_json *subaddress)
+{
+ const char *subaddress_txt, *type_txt;
+ int odd;
+ if (!subaddress) {
+ return;
+ }
+
+ subaddress_txt = ast_json_string_get(ast_json_object_get(subaddress, "subaddress"));
+ type_txt = ast_json_string_get(ast_json_object_get(subaddress, "type"));
+ odd = ast_json_is_true(ast_json_object_get(subaddress, "odd")) ? 1 : 0;
+
+ ast_str_append(msg, 0, "%sSubaddr: %s\r\n", prefix, subaddress_txt);
+ ast_str_append(msg, 0, "%sSubaddrType: %s\r\n", prefix, type_txt);
+ ast_str_append(msg, 0, "%sSubaddrOdd: %d\r\n", prefix, odd);
+}
+
/*!
* \internal
- * \brief Append the given party id to the event string.
+ * \brief Append the given JSON party id to the event string.
* \since 1.8
*
* \param msg Event message string being built.
@@ -2281,58 +2409,72 @@ static int sig_pri_msn_match(const char *msn_patterns, const char *exten)
*
* \return Nothing
*/
-static void sig_pri_event_party_id(struct ast_str **msg, const char *prefix, struct ast_party_id *party)
+static void party_json_to_ami(struct ast_str **msg, const char *prefix, struct ast_json *party)
{
- int pres;
+ struct ast_json *presentation = ast_json_object_get(party, "presentation");
+ struct ast_json *presentation_txt = ast_json_object_get(party, "presentation_txt");
+ struct ast_json *name = ast_json_object_get(party, "name");
+ struct ast_json *number = ast_json_object_get(party, "number");
+ struct ast_json *subaddress = ast_json_object_get(party, "subaddress");
/* Combined party presentation */
- pres = ast_party_id_presentation(party);
- ast_str_append(msg, 0, "%sPres: %d (%s)\r\n", prefix, pres,
- ast_describe_caller_presentation(pres));
+ ast_str_append(msg, 0, "%sPres: %d (%s)\r\n", prefix,
+ (uint32_t)ast_json_integer_get(presentation),
+ ast_json_string_get(presentation_txt));
/* Party number */
- ast_str_append(msg, 0, "%sNumValid: %d\r\n", prefix,
- (unsigned) party->number.valid);
- ast_str_append(msg, 0, "%sNum: %s\r\n", prefix,
- S_COR(party->number.valid, party->number.str, ""));
- ast_str_append(msg, 0, "%ston: %d\r\n", prefix, party->number.plan);
- if (party->number.valid) {
- ast_str_append(msg, 0, "%sNumPlan: %d\r\n", prefix, party->number.plan);
- ast_str_append(msg, 0, "%sNumPres: %d (%s)\r\n", prefix,
- party->number.presentation,
- ast_describe_caller_presentation(party->number.presentation));
- }
+ party_number_json_to_ami(msg, prefix, number);
/* Party name */
- ast_str_append(msg, 0, "%sNameValid: %d\r\n", prefix,
- (unsigned) party->name.valid);
- ast_str_append(msg, 0, "%sName: %s\r\n", prefix,
- S_COR(party->name.valid, party->name.str, ""));
- if (party->name.valid) {
- ast_str_append(msg, 0, "%sNameCharSet: %s\r\n", prefix,
- ast_party_name_charset_describe(party->name.char_set));
- ast_str_append(msg, 0, "%sNamePres: %d (%s)\r\n", prefix,
- party->name.presentation,
- ast_describe_caller_presentation(party->name.presentation));
- }
+ party_name_json_to_ami(msg, prefix, name);
-#if defined(HAVE_PRI_SUBADDR)
/* Party subaddress */
- if (party->subaddress.valid) {
- static const char subaddress[] = "Subaddr";
+ party_subaddress_json_to_ami(msg, prefix, subaddress);
+}
+
+static struct ast_manager_event_blob *mcid_to_ami(struct stasis_message *msg)
+{
+ RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
+ RAII_VAR(struct ast_str *, party_string, ast_str_create(256), ast_free);
+ struct ast_channel_blob *obj = stasis_message_data(msg);
- ast_str_append(msg, 0, "%s%s: %s\r\n", prefix, subaddress,
- S_OR(party->subaddress.str, ""));
- ast_str_append(msg, 0, "%s%sType: %d\r\n", prefix, subaddress,
- party->subaddress.type);
- ast_str_append(msg, 0, "%s%sOdd: %d\r\n", prefix, subaddress,
- party->subaddress.odd_even_indicator);
+ if (obj->snapshot) {
+ channel_string = ast_manager_build_channel_state_string(obj->snapshot);
+ if (!channel_string) {
+ return NULL;
+ }
}
-#endif /* defined(HAVE_PRI_SUBADDR) */
+
+ party_json_to_ami(&party_string, "MCallerID", ast_json_object_get(obj->blob, "caller"));
+ party_json_to_ami(&party_string, "MConnectedID", ast_json_object_get(obj->blob, "connected"));
+
+ return ast_manager_event_blob_create(EVENT_FLAG_CALL, "MCID",
+ "%s"
+ "%s",
+ S_COR(obj->snapshot, ast_str_buffer(channel_string), ""), ast_str_buffer(party_string));
+}
+
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(mcid_type,
+ .to_ami = mcid_to_ami,
+ );
+
+static void send_mcid(struct ast_channel *chan, struct ast_party_id *caller, struct ast_party_id *connected)
+{
+ RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
+
+ ast_assert(caller != NULL);
+ ast_assert(connected != NULL);
+
+ blob = ast_json_pack("{s: o, s: o}",
+ "caller", ast_json_party_id(caller),
+ "connected", ast_json_party_id(connected));
+ if (!blob) {
+ return;
+ }
+
+ ast_channel_publish_blob(chan, mcid_type(), blob);
}
-#endif /* defined(HAVE_PRI_MCID) */
-#if defined(HAVE_PRI_MCID)
/*!
* \internal
* \brief Handle the MCID event.
@@ -2350,15 +2492,12 @@ static void sig_pri_event_party_id(struct ast_str **msg, const char *prefix, str
*/
static void sig_pri_mcid_event(struct sig_pri_span *pri, const struct pri_subcmd_mcid_req *mcid, struct ast_channel *owner)
{
- struct ast_channel *chans[1];
- struct ast_str *msg;
- struct ast_party_id party;
-
- msg = ast_str_create(4096);
- if (!msg) {
- return;
- }
+ struct ast_party_id caller_party;
+ struct ast_party_id connected_party;
+ /* Always use libpri's called party information. */
+ ast_party_id_init(&connected_party);
+ sig_pri_party_id_convert(&connected_party, &mcid->answerer, pri);
if (owner) {
/*
* The owner channel is present.
@@ -2366,31 +2505,18 @@ static void sig_pri_mcid_event(struct sig_pri_span *pri, const struct pri_subcmd
*/
ast_queue_control(owner, AST_CONTROL_MCID);
- ast_str_append(&msg, 0, "Channel: %s\r\n", ast_channel_name(owner));
- ast_str_append(&msg, 0, "UniqueID: %s\r\n", ast_channel_uniqueid(owner));
-
- sig_pri_event_party_id(&msg, "CallerID", &ast_channel_connected(owner)->id);
+ send_mcid(owner, &ast_channel_connected(owner)->id, &connected_party);
} else {
/*
* Since we no longer have an owner channel,
* we have to use the caller information supplied by libpri.
*/
- ast_party_id_init(&party);
- sig_pri_party_id_convert(&party, &mcid->originator, pri);
- sig_pri_event_party_id(&msg, "CallerID", &party);
- ast_party_id_free(&party);
+ ast_party_id_init(&caller_party);
+ sig_pri_party_id_convert(&caller_party, &mcid->originator, pri);
+ send_mcid(owner, &caller_party, &connected_party);
+ ast_party_id_free(&caller_party);
}
-
- /* Always use libpri's called party information. */
- ast_party_id_init(&party);
- sig_pri_party_id_convert(&party, &mcid->answerer, pri);
- sig_pri_event_party_id(&msg, "ConnectedID", &party);
- ast_party_id_free(&party);
-
- chans[0] = owner;
- ast_manager_event_multichan(EVENT_FLAG_CALL, "MCID", owner ? 1 : 0, chans, "%s",
- ast_str_buffer(msg));
- ast_free(msg);
+ ast_party_id_free(&connected_party);
}
#endif /* defined(HAVE_PRI_MCID) */
@@ -10003,6 +10129,12 @@ void sig_pri_cc_monitor_destructor(void *monitor_pvt)
*/
int sig_pri_load(const char *cc_type_name)
{
+#if defined(HAVE_PRI_MCID)
+ if (STASIS_MESSAGE_TYPE_INIT(mcid_type)) {
+ return -1;
+ }
+#endif /* defined(HAVE_PRI_MCID) */
+
#if defined(HAVE_PRI_CCSS)
sig_pri_cc_type_name = cc_type_name;
sig_pri_cc_monitors = ao2_container_alloc(37, sig_pri_cc_monitor_instance_hash_fn,
@@ -10028,6 +10160,10 @@ void sig_pri_unload(void)
sig_pri_cc_monitors = NULL;
}
#endif /* defined(HAVE_PRI_CCSS) */
+
+#if defined(HAVE_PRI_MCID)
+ STASIS_MESSAGE_TYPE_CLEANUP(mcid_type);
+#endif /* defined(HAVE_PRI_MCID) */
}
#endif /* HAVE_PRI */
diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h
index 8b4672b25..302943941 100644
--- a/channels/sip/include/sip.h
+++ b/channels/sip/include/sip.h
@@ -219,7 +219,6 @@
#define DEFAULT_QUALIFY FALSE /*!< Don't monitor devices */
#define DEFAULT_KEEPALIVE 0 /*!< Don't send keep alive packets */
#define DEFAULT_KEEPALIVE_INTERVAL 60 /*!< Send keep alive packets at 60 second intervals */
-#define DEFAULT_CALLEVENTS FALSE /*!< Extra manager SIP call events */
#define DEFAULT_ALWAYSAUTHREJECT TRUE /*!< Don't reject authentication requests always */
#define DEFAULT_AUTH_OPTIONS FALSE
#define DEFAULT_AUTH_MESSAGE TRUE
@@ -744,7 +743,6 @@ struct sip_settings {
int accept_outofcall_message; /*!< Accept MESSAGE outside of a call */
int compactheaders; /*!< send compact sip headers */
int allow_external_domains; /*!< Accept calls to external SIP domains? */
- int callevents; /*!< Whether we send manager events or not */
int regextenonqualify; /*!< Whether to add/remove regexten when qualifying peers */
int legacy_useroption_parsing; /*!< Whether to strip useroptions in URI via semicolons */
int send_diversion; /*!< Whether to Send SIP Diversion headers */
diff --git a/configs/sip.conf.sample b/configs/sip.conf.sample
index 57692b2a8..70aabb956 100644
--- a/configs/sip.conf.sample
+++ b/configs/sip.conf.sample
@@ -397,8 +397,6 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls
;maxcallbitrate=384 ; Maximum bitrate for video calls (default 384 kb/s)
; Videosupport and maxcallbitrate is settable
; for peers and users as well
-;callevents=no ; generate manager events when sip ua
- ; performs events (e.g. hold)
;authfailureevents=no ; generate manager "peerstatus" events when peer can't
; authenticate with Asterisk. Peerstatus will be "rejected".
;alwaysauthreject = yes ; When an incoming INVITE or REGISTER is to be rejected,
diff --git a/include/asterisk/json.h b/include/asterisk/json.h
index 43b4b5cf5..61685fd9f 100644
--- a/include/asterisk/json.h
+++ b/include/asterisk/json.h
@@ -906,6 +906,18 @@ struct ast_json_payload {
*/
struct ast_json_payload *ast_json_payload_create(struct ast_json *json);
+struct ast_party_id;
+/*!
+ * \brief Construct an ast_party_id as JSON.
+ * \since 12.0.0
+ *
+ * \param party The party ID to represent as JSON.
+ *
+ * \return JSON object with \c name, \c number and \c subaddress objects
+ * for those that are valid in the party ID
+ */
+struct ast_json *ast_json_party_id(struct ast_party_id *party);
+
/*!@}*/
#endif /* _ASTERISK_JSON_H */
diff --git a/include/asterisk/stasis.h b/include/asterisk/stasis.h
index 19ebb41c9..fd51cf51d 100644
--- a/include/asterisk/stasis.h
+++ b/include/asterisk/stasis.h
@@ -736,6 +736,32 @@ void stasis_log_bad_type_access(const char *name);
}
/*!
+ * \brief Boiler-plate removing macro for defining local message types.
+ *
+ * \code
+ * STASIS_MESSAGE_TYPE_DEFN_LOCAL(ast_foo_type,
+ * .to_ami = foo_to_ami,
+ * .to_json = foo_to_json,
+ * );
+ * \endcode
+ *
+ * \param name Name of message type.
+ * \param ... Virtual table methods for messages of this type.
+ * \since 12
+ */
+#define STASIS_MESSAGE_TYPE_DEFN_LOCAL(name, ...) \
+ static struct stasis_message_vtable _priv_ ## name ## _v = { \
+ __VA_ARGS__ \
+ }; \
+ static struct stasis_message_type *_priv_ ## name; \
+ static struct stasis_message_type *name(void) { \
+ if (_priv_ ## name == NULL) { \
+ stasis_log_bad_type_access(#name); \
+ } \
+ return _priv_ ## name; \
+ }
+
+/*!
* \brief Boiler-plate removing macro for initializing message types.
*
* \code
diff --git a/main/core_local.c b/main/core_local.c
index 5c7a34f1f..16abc428c 100644
--- a/main/core_local.c
+++ b/main/core_local.c
@@ -47,6 +47,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/core_unreal.h"
#include "asterisk/core_local.h"
#include "asterisk/_private.h"
+#include "asterisk/stasis_channels.h"
/*** DOCUMENTATION
<manager name="LocalOptimizeAway" language="en_US">
@@ -65,6 +66,101 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
it to optimize away if it's bridged or when it becomes bridged.</para>
</description>
</manager>
+ <managerEvent language="en_US" name="LocalBridge">
+ <managerEventInstance class="EVENT_FLAG_CALL">
+ <synopsis>Raised when two halves of a Local Channel form a bridge.</synopsis>
+ <syntax>
+ <parameter name="LocalOneChannel">
+ </parameter>
+ <parameter name="LocalOneChannelState">
+ <para>A numeric code for the channel's current state, related to ChannelStateDesc</para>
+ </parameter>
+ <parameter name="LocalOneChannelStateDesc">
+ <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="LocalOneCallerIDNum">
+ </parameter>
+ <parameter name="LocalOneCallerIDName">
+ </parameter>
+ <parameter name="LocalOneConnectedLineNum">
+ </parameter>
+ <parameter name="LocalOneConnectedLineName">
+ </parameter>
+ <parameter name="LocalOneAccountCode">
+ </parameter>
+ <parameter name="LocalOneContext">
+ </parameter>
+ <parameter name="LocalOneExten">
+ </parameter>
+ <parameter name="LocalOnePriority">
+ </parameter>
+ <parameter name="LocalOneUniqueid">
+ </parameter>
+ <parameter name="LocalTwoChannel">
+ </parameter>
+ <parameter name="LocalTwoChannelState">
+ <para>A numeric code for the channel's current state, related to ChannelStateDesc</para>
+ </parameter>
+ <parameter name="LocalTwoChannelStateDesc">
+ <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="LocalTwoCallerIDNum">
+ </parameter>
+ <parameter name="LocalTwoCallerIDName">
+ </parameter>
+ <parameter name="LocalTwoConnectedLineNum">
+ </parameter>
+ <parameter name="LocalTwoConnectedLineName">
+ </parameter>
+ <parameter name="LocalTwoAccountCode">
+ </parameter>
+ <parameter name="LocalTwoContext">
+ </parameter>
+ <parameter name="LocalTwoExten">
+ </parameter>
+ <parameter name="LocalTwoPriority">
+ </parameter>
+ <parameter name="LocalTwoUniqueid">
+ </parameter>
+ <parameter name="Context">
+ <para>The context in the dialplan that Channel2 starts in.</para>
+ </parameter>
+ <parameter name="Exten">
+ <para>The extension in the dialplan that Channel2 starts in.</para>
+ </parameter>
+ <parameter name="LocalOptimization">
+ <enumlist>
+ <enum name="Yes"/>
+ <enum name="No"/>
+ </enumlist>
+ </parameter>
+ </syntax>
+ </managerEventInstance>
+ </managerEvent>
***/
static const char tdesc[] = "Local Proxy Channel Driver";
@@ -230,6 +326,49 @@ static int local_devicestate(const char *data)
return res;
}
+static struct ast_manager_event_blob *local_bridge_to_ami(struct stasis_message *msg)
+{
+ RAII_VAR(struct ast_str *, channel_one_string, NULL, ast_free);
+ RAII_VAR(struct ast_str *, channel_two_string, NULL, ast_free);
+ struct ast_multi_channel_blob *obj = stasis_message_data(msg);
+ struct ast_json *blob, *context, *exten, *optimize;
+ struct ast_channel_snapshot *chan_one, *chan_two;
+
+ chan_one = ast_multi_channel_blob_get_channel(obj, "1");
+ chan_two = ast_multi_channel_blob_get_channel(obj, "2");
+ blob = ast_multi_channel_blob_get_json(obj);
+
+ channel_one_string = ast_manager_build_channel_state_string_prefix(chan_one, "LocalOne");
+ if (!channel_one_string) {
+ return NULL;
+ }
+
+ channel_two_string = ast_manager_build_channel_state_string_prefix(chan_two, "LocalTwo");
+ if (!channel_two_string) {
+ return NULL;
+ }
+
+ context = ast_json_object_get(blob, "context");
+ exten = ast_json_object_get(blob, "exten");
+ optimize = ast_json_object_get(blob, "optimize");
+
+ return ast_manager_event_blob_create(EVENT_FLAG_CALL, "LocalBridge",
+ "%s"
+ "%s"
+ "Context: %s\r\n"
+ "Exten: %s\r\n"
+ "LocalOptimization: %s\r\n",
+ ast_str_buffer(channel_one_string),
+ ast_str_buffer(channel_two_string),
+ ast_json_string_get(context),
+ ast_json_string_get(exten),
+ ast_json_is_true(optimize) ? "Yes" : "No");
+}
+
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(local_bridge_type,
+ .to_ami = local_bridge_to_ami,
+ );
+
/*!
* \internal
* \brief Post the LocalBridge AMI event.
@@ -241,45 +380,45 @@ static int local_devicestate(const char *data)
*/
static void local_bridge_event(struct local_pvt *p)
{
- ao2_lock(p);
- /*** DOCUMENTATION
- <managerEventInstance>
- <synopsis>Raised when two halves of a Local Channel form a bridge.</synopsis>
- <syntax>
- <parameter name="Channel1">
- <para>The name of the Local Channel half that bridges to another channel.</para>
- </parameter>
- <parameter name="Channel2">
- <para>The name of the Local Channel half that executes the dialplan.</para>
- </parameter>
- <parameter name="Context">
- <para>The context in the dialplan that Channel2 starts in.</para>
- </parameter>
- <parameter name="Exten">
- <para>The extension in the dialplan that Channel2 starts in.</para>
- </parameter>
- <parameter name="LocalOptimization">
- <enumlist>
- <enum name="Yes"/>
- <enum name="No"/>
- </enumlist>
- </parameter>
- </syntax>
- </managerEventInstance>
- ***/
- manager_event(EVENT_FLAG_CALL, "LocalBridge",
- "Channel1: %s\r\n"
- "Channel2: %s\r\n"
- "Uniqueid1: %s\r\n"
- "Uniqueid2: %s\r\n"
- "Context: %s\r\n"
- "Exten: %s\r\n"
- "LocalOptimization: %s\r\n",
- ast_channel_name(p->base.owner), ast_channel_name(p->base.chan),
- ast_channel_uniqueid(p->base.owner), ast_channel_uniqueid(p->base.chan),
- p->context, p->exten,
- ast_test_flag(&p->base, AST_UNREAL_NO_OPTIMIZATION) ? "Yes" : "No");
- ao2_unlock(p);
+ RAII_VAR(struct ast_multi_channel_blob *, multi_blob, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
+ RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_channel_snapshot *, one_snapshot, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_channel_snapshot *, two_snapshot, NULL, ao2_cleanup);
+ SCOPED_AO2LOCK(lock, p);
+
+ blob = ast_json_pack("{s: s, s: s, s: b}",
+ "context", p->context,
+ "exten", p->exten,
+ "optimize", ast_test_flag(&p->base, AST_UNREAL_NO_OPTIMIZATION));
+ if (!blob) {
+ return;
+ }
+
+ multi_blob = ast_multi_channel_blob_create(blob);
+ if (!multi_blob) {
+ return;
+ }
+
+ one_snapshot = ast_channel_snapshot_create(p->base.owner);
+ if (!one_snapshot) {
+ return;
+ }
+
+ two_snapshot = ast_channel_snapshot_create(p->base.chan);
+ if (!two_snapshot) {
+ return;
+ }
+
+ ast_multi_channel_blob_add_channel(multi_blob, "1", one_snapshot);
+ ast_multi_channel_blob_add_channel(multi_blob, "2", two_snapshot);
+
+ msg = stasis_message_create(local_bridge_type(), multi_blob);
+ if (!msg) {
+ return;
+ }
+
+ stasis_publish(ast_channel_topic(p->base.owner), msg);
}
int ast_local_setup_bridge(struct ast_channel *ast, struct ast_bridge *bridge, struct ast_channel *swap, struct ast_bridge_features *features)
@@ -744,10 +883,15 @@ static void local_shutdown(void)
locals = NULL;
ast_format_cap_destroy(local_tech.capabilities);
+ STASIS_MESSAGE_TYPE_CLEANUP(local_bridge_type);
}
int ast_local_init(void)
{
+ if (STASIS_MESSAGE_TYPE_INIT(local_bridge_type)) {
+ return -1;
+ }
+
if (!(local_tech.capabilities = ast_format_cap_alloc())) {
return -1;
}
diff --git a/main/json.c b/main/json.c
index a403b40cf..dff35dbab 100644
--- a/main/json.c
+++ b/main/json.c
@@ -40,6 +40,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/module.h"
#include "asterisk/utils.h"
#include "asterisk/astobj2.h"
+#include "asterisk/channel.h"
+#include "asterisk/callerid.h"
#include <jansson.h>
#include <time.h>
@@ -599,3 +601,70 @@ struct ast_json_payload *ast_json_payload_create(struct ast_json *json)
return payload;
}
+
+static struct ast_json *json_party_number(struct ast_party_number *number)
+{
+ if (!number->valid) {
+ return NULL;
+ }
+ return ast_json_pack("{s: s, s: i, s: i, s: s}",
+ "number", number->str,
+ "plan", number->plan,
+ "presentation", number->presentation,
+ "presentation_txt", ast_describe_caller_presentation(number->presentation));
+}
+
+static struct ast_json *json_party_name(struct ast_party_name *name)
+{
+ if (!name->valid) {
+ return NULL;
+ }
+ return ast_json_pack("{s: s, s: s, s: i, s: s}",
+ "name", name->str,
+ "character_set", ast_party_name_charset_describe(name->char_set),
+ "presentation", name->presentation,
+ "presentation_txt", ast_describe_caller_presentation(name->presentation));
+}
+
+static struct ast_json *json_party_subaddress(struct ast_party_subaddress *subaddress)
+{
+ if (!subaddress->valid) {
+ return NULL;
+ }
+ return ast_json_pack("{s: s, s: i, s: b}",
+ "subaddress", subaddress->str,
+ "type", subaddress->type,
+ "odd", subaddress->odd_even_indicator);
+}
+
+struct ast_json *ast_json_party_id(struct ast_party_id *party)
+{
+ RAII_VAR(struct ast_json *, json_party_id, NULL, ast_json_unref);
+ int pres;
+
+ /* Combined party presentation */
+ pres = ast_party_id_presentation(party);
+ json_party_id = ast_json_pack("{s: i, s: s}",
+ "presentation", pres,
+ "presentation_txt", ast_describe_caller_presentation(pres));
+ if (!json_party_id) {
+ return NULL;
+ }
+
+ /* Party number */
+ if (party->number.valid && ast_json_object_set(json_party_id, "number", json_party_number(&party->number))) {
+ return NULL;
+ }
+
+ /* Party name */
+ if (party->name.valid && ast_json_object_set(json_party_id, "name", json_party_name(&party->name))) {
+ return NULL;
+ }
+
+ /* Party subaddress */
+ if (party->subaddress.valid && ast_json_object_set(json_party_id, "subaddress", json_party_subaddress(&party->subaddress))) {
+ return NULL;
+ }
+
+ return ast_json_ref(json_party_id);
+}
diff --git a/res/res_agi.c b/res/res_agi.c
index a841f3623..eff753e5c 100644
--- a/res/res_agi.c
+++ b/res/res_agi.c
@@ -1027,17 +1027,11 @@ enum agi_result {
AGI_RESULT_HANGUP,
};
-struct stasis_message_type *agi_exec_start_type(void);
-struct stasis_message_type *agi_exec_end_type(void);
-struct stasis_message_type *agi_async_start_type(void);
-struct stasis_message_type *agi_async_exec_type(void);
-struct stasis_message_type *agi_async_end_type(void);
-
-STASIS_MESSAGE_TYPE_DEFN(agi_exec_start_type);
-STASIS_MESSAGE_TYPE_DEFN(agi_exec_end_type);
-STASIS_MESSAGE_TYPE_DEFN(agi_async_start_type);
-STASIS_MESSAGE_TYPE_DEFN(agi_async_exec_type);
-STASIS_MESSAGE_TYPE_DEFN(agi_async_end_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(agi_exec_start_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(agi_exec_end_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(agi_async_start_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(agi_async_exec_type);
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(agi_async_end_type);
static void agi_channel_manager_event(void *data,
struct stasis_subscription *sub, struct stasis_topic *topic,