#include "asterisk.h"
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
#include "asterisk/stasis_bridges.h"
#include "asterisk/stasis_channels.h"
#include "asterisk/manager.h"
<syntax>
<bridge_snapshot/>
</syntax>
+ <see-also>
+ <ref type="managerEvent">BridgeDestroy</ref>
+ <ref type="managerEvent">BridgeEnter</ref>
+ <ref type="managerEvent">BridgeLeave</ref>
+ </see-also>
</managerEventInstance>
</managerEvent>
<managerEvent language="en_US" name="BridgeDestroy">
<syntax>
<bridge_snapshot/>
</syntax>
+ <see-also>
+ <ref type="managerEvent">BridgeCreate</ref>
+ <ref type="managerEvent">BridgeEnter</ref>
+ <ref type="managerEvent">BridgeLeave</ref>
+ </see-also>
</managerEventInstance>
</managerEvent>
<managerEvent language="en_US" name="BridgeEnter">
<para>The uniqueid of the channel being swapped out of the bridge</para>
</parameter>
</syntax>
+ <see-also>
+ <ref type="managerEvent">BridgeCreate</ref>
+ <ref type="managerEvent">BridgeDestroy</ref>
+ <ref type="managerEvent">BridgeLeave</ref>
+ </see-also>
</managerEventInstance>
</managerEvent>
<managerEvent language="en_US" name="BridgeLeave">
<bridge_snapshot/>
<channel_snapshot/>
</syntax>
+ <see-also>
+ <ref type="managerEvent">BridgeCreate</ref>
+ <ref type="managerEvent">BridgeDestroy</ref>
+ <ref type="managerEvent">BridgeEnter</ref>
+ </see-also>
+ </managerEventInstance>
+ </managerEvent>
+ <managerEvent language="en_US" name="BridgeVideoSourceUpdate">
+ <managerEventInstance class="EVENT_FLAG_CALL">
+ <synopsis>Raised when the channel that is the source of video in a bridge changes.</synopsis>
+ <syntax>
+ <bridge_snapshot/>
+ <parameter name="BridgePreviousVideoSource">
+ <para>The unique ID of the channel that was the video source.</para>
+ </parameter>
+ </syntax>
+ <see-also>
+ <ref type="managerEvent">BridgeCreate</ref>
+ <ref type="managerEvent">BridgeDestroy</ref>
+ </see-also>
</managerEventInstance>
</managerEvent>
<manager name="BridgeList" language="en_US">
<description>
<para>Returns a list of bridges, optionally filtering on a bridge type.</para>
</description>
+ <see-also>
+ <ref type="manager">Bridge</ref>
+ <ref type="manager">BridgeDestroy</ref>
+ <ref type="manager">BridgeInfo</ref>
+ <ref type="manager">BridgeKick</ref>
+ </see-also>
</manager>
<manager name="BridgeInfo" language="en_US">
<synopsis>
<syntax>
<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
<parameter name="BridgeUniqueid" required="true">
- <para>The unique ID of the bridge about which to retreive information.</para>
+ <para>The unique ID of the bridge about which to retrieve information.</para>
</parameter>
</syntax>
<description>
<para>Returns detailed information about a bridge and the channels in it.</para>
</description>
+ <see-also>
+ <ref type="manager">Bridge</ref>
+ <ref type="manager">BridgeDestroy</ref>
+ <ref type="manager">BridgeKick</ref>
+ <ref type="manager">BridgeList</ref>
+ </see-also>
+ <responses>
+ <list-elements>
+ <managerEvent language="en_US" name="BridgeInfoChannel">
+ <managerEventInstance class="EVENT_FLAG_COMMAND">
+ <synopsis>Information about a channel in a bridge.</synopsis>
+ <syntax>
+ <channel_snapshot/>
+ </syntax>
+ </managerEventInstance>
+ </managerEvent>
+ </list-elements>
+ <managerEvent language="en_US" name="BridgeInfoComplete">
+ <managerEventInstance class="EVENT_FLAG_COMMAND">
+ <synopsis>Information about a bridge.</synopsis>
+ <syntax>
+ <bridge_snapshot/>
+ </syntax>
+ </managerEventInstance>
+ </managerEvent>
+ </responses>
</manager>
<manager name="BridgeDestroy" language="en_US">
<synopsis>
<description>
<para>Deletes the bridge, causing channels to continue or hang up.</para>
</description>
+ <see-also>
+ <ref type="manager">Bridge</ref>
+ <ref type="manager">BridgeInfo</ref>
+ <ref type="manager">BridgeKick</ref>
+ <ref type="manager">BridgeList</ref>
+ <ref type="managerEvent">BridgeDestroy</ref>
+ </see-also>
</manager>
<manager name="BridgeKick" language="en_US">
<synopsis>
<description>
<para>The channel is removed from the bridge.</para>
</description>
+ <see-also>
+ <ref type="manager">Bridge</ref>
+ <ref type="manager">BridgeDestroy</ref>
+ <ref type="manager">BridgeInfo</ref>
+ <ref type="manager">BridgeList</ref>
+ <ref type="managerEvent">BridgeLeave</ref>
+ </see-also>
</manager>
***/
"%sBridgeUniqueid: %s\r\n"
"%sBridgeType: %s\r\n"
"%sBridgeTechnology: %s\r\n"
- "%sBridgeNumChannels: %d\r\n",
+ "%sBridgeCreator: %s\r\n"
+ "%sBridgeName: %s\r\n"
+ "%sBridgeNumChannels: %u\r\n"
+ "%sBridgeVideoSourceMode: %s\r\n",
prefix, snapshot->uniqueid,
prefix, snapshot->subclass,
prefix, snapshot->technology,
- prefix, snapshot->num_channels);
+ prefix, ast_strlen_zero(snapshot->creator) ? "<unknown>": snapshot->creator,
+ prefix, ast_strlen_zero(snapshot->name) ? "<unknown>": snapshot->name,
+ prefix, snapshot->num_channels,
+ prefix, ast_bridge_video_mode_to_string(snapshot->video_mode));
if (!res) {
ast_free(out);
return NULL;
}
+ if (snapshot->video_mode != AST_BRIDGE_VIDEO_MODE_NONE
+ && !ast_strlen_zero(snapshot->video_source_id)) {
+ res = ast_str_append(&out, 0, "%sBridgeVideoSource: %s\r\n",
+ prefix, snapshot->video_source_id);
+ if (!res) {
+ ast_free(out);
+ return NULL;
+ }
+ }
+
return out;
}
EVENT_FLAG_CALL, "BridgeCreate", NO_EXTRA_FIELDS);
}
+/* \brief Handle video source updates */
+static struct ast_manager_event_blob *bridge_video_update(
+ struct ast_bridge_snapshot *old_snapshot,
+ struct ast_bridge_snapshot *new_snapshot)
+{
+ if (!new_snapshot || !old_snapshot) {
+ return NULL;
+ }
+
+ if (!strcmp(old_snapshot->video_source_id, new_snapshot->video_source_id)) {
+ return NULL;
+ }
+
+ return ast_manager_event_blob_create(
+ EVENT_FLAG_CALL, "BridgeVideoSourceUpdate",
+ "BridgePreviousVideoSource: %s\r\n",
+ old_snapshot->video_source_id);
+}
+
/*! \brief Handle bridge destruction */
static struct ast_manager_event_blob *bridge_destroy(
struct ast_bridge_snapshot *old_snapshot,
EVENT_FLAG_CALL, "BridgeDestroy", NO_EXTRA_FIELDS);
}
-
bridge_snapshot_monitor bridge_monitors[] = {
bridge_create,
+ bridge_video_update,
bridge_destroy,
};
return strcmp(bridge_type, snapshot->technology) ? CMP_MATCH : 0;
}
+struct bridge_list_data {
+ const char *id_text;
+ int count;
+};
+
static int send_bridge_list_item_cb(void *obj, void *arg, void *data, int flags)
{
struct ast_bridge_snapshot *snapshot = stasis_message_data(obj);
struct mansession *s = arg;
- char *id_text = data;
- RAII_VAR(struct ast_str *, bridge_info, ast_manager_build_bridge_state_string(snapshot), ast_free_ptr);
+ struct bridge_list_data *list_data = data;
+ RAII_VAR(struct ast_str *, bridge_info, ast_manager_build_bridge_state_string(snapshot), ast_free);
if (!bridge_info) {
return 0;
"%s"
"%s"
"\r\n",
- ast_str_buffer(bridge_info),
- id_text);
+ list_data->id_text,
+ ast_str_buffer(bridge_info));
+ ++list_data->count;
return 0;
}
const char *type_filter = astman_get_header(m, "BridgeType");
RAII_VAR(struct ast_str *, id_text, ast_str_create(128), ast_free);
RAII_VAR(struct ao2_container *, bridges, NULL, ao2_cleanup);
+ struct bridge_list_data list_data;
if (!id_text) {
astman_send_error(s, m, "Internal error");
return -1;
}
- astman_send_ack(s, m, "Bridge listing will follow");
+ astman_send_listack(s, m, "Bridge listing will follow", "start");
if (!ast_strlen_zero(type_filter)) {
char *type_filter_dup = ast_strdupa(type_filter);
- ao2_callback(bridges, OBJ_MULTIPLE | OBJ_NODATA | OBJ_UNLINK, filter_bridge_type_cb, type_filter_dup);
+
+ ao2_callback(bridges, OBJ_MULTIPLE | OBJ_NODATA | OBJ_UNLINK,
+ filter_bridge_type_cb, type_filter_dup);
}
- ao2_callback_data(bridges, OBJ_NODATA, send_bridge_list_item_cb, s, ast_str_buffer(id_text));
+ list_data.id_text = ast_str_buffer(id_text);
+ list_data.count = 0;
+ ao2_callback_data(bridges, OBJ_NODATA, send_bridge_list_item_cb, s, &list_data);
- astman_append(s,
- "Event: BridgeListComplete\r\n"
- "%s"
- "\r\n",
- ast_str_buffer(id_text));
+ astman_send_list_complete_start(s, m, "BridgeListComplete", list_data.count);
+ astman_send_list_complete_end(s);
return 0;
}
{
char *uniqueid = obj;
struct mansession *s = arg;
- char *id_text = data;
+ struct bridge_list_data *list_data = data;
RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
struct ast_channel_snapshot *snapshot;
RAII_VAR(struct ast_str *, channel_text, NULL, ast_free);
+
msg = stasis_cache_get(ast_channel_cache(),
ast_channel_snapshot_type(), uniqueid);
-
if (!msg) {
return 0;
}
"%s"
"%s"
"\r\n",
- ast_str_buffer(channel_text),
- id_text);
+ list_data->id_text,
+ ast_str_buffer(channel_text));
+ ++list_data->count;
return 0;
}
RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
RAII_VAR(struct ast_str *, bridge_info, NULL, ast_free);
struct ast_bridge_snapshot *snapshot;
+ struct bridge_list_data list_data;
if (!id_text) {
astman_send_error(s, m, "Internal error");
return 0;
}
- astman_send_ack(s, m, "Bridge channel listing will follow");
-
snapshot = stasis_message_data(msg);
bridge_info = ast_manager_build_bridge_state_string(snapshot);
+ if (!bridge_info) {
+ astman_send_error(s, m, "Internal error");
+ return -1;
+ }
- ao2_callback_data(snapshot->channels, OBJ_NODATA, send_bridge_info_item_cb, s, ast_str_buffer(id_text));
+ astman_send_listack(s, m, "Bridge channel listing will follow", "start");
- astman_append(s,
- "Event: BridgeInfoComplete\r\n"
- "%s"
- "%s"
- "\r\n",
- S_COR(bridge_info, ast_str_buffer(bridge_info), ""),
- ast_str_buffer(id_text));
+ list_data.id_text = ast_str_buffer(id_text);
+ list_data.count = 0;
+ ao2_callback_data(snapshot->channels, OBJ_NODATA, send_bridge_info_item_cb, s, &list_data);
+
+ astman_send_list_complete_start(s, m, "BridgeInfoComplete", list_data.count);
+ if (!ast_strlen_zero(ast_str_buffer(bridge_info))) {
+ astman_append(s, "%s", ast_str_buffer(bridge_info));
+ }
+ astman_send_list_complete_end(s);
return 0;
}
}
} else {
bridge = ast_bridge_find_by_id(bridge_uniqueid);
- if (!bridge) {
+ if (!bridge || ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_INVISIBLE)) {
astman_send_error(s, m, "Bridge not found");
return 0;
}
{
stasis_forward_cancel(topic_forwarder);
topic_forwarder = NULL;
-}
-static void manager_bridging_shutdown(void)
-{
ast_manager_unregister("BridgeList");
ast_manager_unregister("BridgeInfo");
ast_manager_unregister("BridgeDestroy");
return 0;
}
- ast_register_atexit(manager_bridging_shutdown);
ast_register_cleanup(manager_bridging_cleanup);
manager_topic = ast_manager_get_topic();
* thing and fail it.
*/
if (ret) {
- manager_bridging_shutdown();
+ manager_bridging_cleanup();
return -1;
}