summaryrefslogtreecommitdiff
path: root/apps/confbridge
diff options
context:
space:
mode:
authorRichard Mudgett <rmudgett@digium.com>2013-05-21 18:00:22 +0000
committerRichard Mudgett <rmudgett@digium.com>2013-05-21 18:00:22 +0000
commit3d63833bd6c869b7efa383e8dea14be1a6eff998 (patch)
tree34957dd051b8f67c7cc58a510e24ee3873a61ad4 /apps/confbridge
parente1e1cc2deefb92f8b43825f1f34e619354737842 (diff)
Merge in the bridge_construction branch to make the system use the Bridging API.
Breaks many things until they can be reworked. A partial list: chan_agent chan_dahdi, chan_misdn, chan_iax2 native bridging app_queue COLP updates DTMF attended transfers Protocol attended transfers git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@389378 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'apps/confbridge')
-rw-r--r--apps/confbridge/conf_chan_announce.c207
-rw-r--r--apps/confbridge/conf_chan_record.c94
-rw-r--r--apps/confbridge/conf_config_parser.c4
-rw-r--r--apps/confbridge/confbridge_manager.c339
-rw-r--r--apps/confbridge/include/confbridge.h63
5 files changed, 706 insertions, 1 deletions
diff --git a/apps/confbridge/conf_chan_announce.c b/apps/confbridge/conf_chan_announce.c
new file mode 100644
index 000000000..46e074b20
--- /dev/null
+++ b/apps/confbridge/conf_chan_announce.c
@@ -0,0 +1,207 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013 Digium, Inc.
+ *
+ * Richard Mudgett <rmudgett@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ * \brief ConfBridge announcer channel driver
+ *
+ * \author Richard Mudgett <rmudgett@digium.com>
+ *
+ * See Also:
+ * \arg \ref AstCREDITS
+ */
+
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/channel.h"
+#include "asterisk/bridging.h"
+#include "asterisk/core_unreal.h"
+#include "include/confbridge.h"
+
+/* ------------------------------------------------------------------- */
+
+/*! ConfBridge announcer channel private. */
+struct announce_pvt {
+ /*! Unreal channel driver base class values. */
+ struct ast_unreal_pvt base;
+ /*! Conference bridge associated with this announcer. */
+ struct ast_bridge *bridge;
+};
+
+static int announce_call(struct ast_channel *chan, const char *addr, int timeout)
+{
+ /* Make sure anyone calling ast_call() for this channel driver is going to fail. */
+ return -1;
+}
+
+static int announce_hangup(struct ast_channel *ast)
+{
+ struct announce_pvt *p = ast_channel_tech_pvt(ast);
+ int res;
+
+ if (!p) {
+ return -1;
+ }
+
+ /* give the pvt a ref to fulfill calling requirements. */
+ ao2_ref(p, +1);
+ res = ast_unreal_hangup(&p->base, ast);
+ ao2_ref(p, -1);
+
+ return res;
+}
+
+static void announce_pvt_destructor(void *vdoomed)
+{
+ struct announce_pvt *doomed = vdoomed;
+
+ ao2_cleanup(doomed->bridge);
+ doomed->bridge = NULL;
+}
+
+static struct ast_channel *announce_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
+{
+ struct ast_channel *chan;
+ const char *conf_name = data;
+ RAII_VAR(struct confbridge_conference *, conference, NULL, ao2_cleanup);
+ RAII_VAR(struct announce_pvt *, pvt, NULL, ao2_cleanup);
+
+ conference = ao2_find(conference_bridges, conf_name, OBJ_KEY);
+ if (!conference) {
+ return NULL;
+ }
+ ast_assert(conference->bridge != NULL);
+
+ /* Allocate a new private structure and then Asterisk channels */
+ pvt = (struct announce_pvt *) ast_unreal_alloc(sizeof(*pvt), announce_pvt_destructor,
+ cap);
+ if (!pvt) {
+ return NULL;
+ }
+ ast_set_flag(&pvt->base, AST_UNREAL_NO_OPTIMIZATION);
+ ast_copy_string(pvt->base.name, conf_name, sizeof(pvt->base.name));
+ pvt->bridge = conference->bridge;
+ ao2_ref(pvt->bridge, +1);
+
+ chan = ast_unreal_new_channels(&pvt->base, conf_announce_get_tech(),
+ AST_STATE_UP, AST_STATE_UP, NULL, NULL, requestor, NULL);
+ if (chan) {
+ ast_answer(pvt->base.owner);
+ ast_answer(pvt->base.chan);
+ if (ast_channel_add_bridge_role(pvt->base.chan, "announcer")) {
+ ast_hangup(chan);
+ chan = NULL;
+ }
+ }
+
+ return chan;
+}
+
+static struct ast_channel_tech announce_tech = {
+ .type = "CBAnn",
+ .description = "Conference Bridge Announcing Channel",
+ .requester = announce_request,
+ .call = announce_call,
+ .hangup = announce_hangup,
+
+ .send_digit_begin = ast_unreal_digit_begin,
+ .send_digit_end = ast_unreal_digit_end,
+ .read = ast_unreal_read,
+ .write = ast_unreal_write,
+ .write_video = ast_unreal_write,
+ .exception = ast_unreal_read,
+ .indicate = ast_unreal_indicate,
+ .fixup = ast_unreal_fixup,
+ .send_html = ast_unreal_sendhtml,
+ .send_text = ast_unreal_sendtext,
+ .queryoption = ast_unreal_queryoption,
+ .setoption = ast_unreal_setoption,
+};
+
+struct ast_channel_tech *conf_announce_get_tech(void)
+{
+ return &announce_tech;
+}
+
+void conf_announce_channel_depart(struct ast_channel *chan)
+{
+ struct announce_pvt *p = ast_channel_tech_pvt(chan);
+
+ if (!p) {
+ return;
+ }
+
+ ao2_ref(p, +1);
+ ao2_lock(p);
+ if (!ast_test_flag(&p->base, AST_UNREAL_CARETAKER_THREAD)) {
+ ao2_unlock(p);
+ ao2_ref(p, -1);
+ return;
+ }
+ ast_clear_flag(&p->base, AST_UNREAL_CARETAKER_THREAD);
+ chan = p->base.chan;
+ if (chan) {
+ ast_channel_ref(chan);
+ }
+ ao2_unlock(p);
+ ao2_ref(p, -1);
+ if (chan) {
+ ast_bridge_depart(chan);
+ ast_channel_unref(chan);
+ }
+}
+
+int conf_announce_channel_push(struct ast_channel *ast)
+{
+ struct ast_bridge_features *features;
+ RAII_VAR(struct announce_pvt *, p, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_channel *, chan, NULL, ast_channel_unref);
+
+ {
+ SCOPED_CHANNELLOCK(lock, ast);
+
+ p = ast_channel_tech_pvt(ast);
+ if (!p) {
+ return -1;
+ }
+ ao2_ref(p, +1);
+ chan = p->base.chan;
+ if (!chan) {
+ return -1;
+ }
+ ast_channel_ref(chan);
+ }
+
+ features = ast_bridge_features_new();
+ if (!features) {
+ return -1;
+ }
+ ast_set_flag(&features->feature_flags, AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE);
+
+ /* Impart the output channel into the bridge */
+ if (ast_bridge_impart(p->bridge, chan, NULL, features, 0)) {
+ return -1;
+ }
+ ao2_lock(p);
+ ast_set_flag(&p->base, AST_UNREAL_CARETAKER_THREAD);
+ ao2_unlock(p);
+ return 0;
+}
diff --git a/apps/confbridge/conf_chan_record.c b/apps/confbridge/conf_chan_record.c
new file mode 100644
index 000000000..18f971f35
--- /dev/null
+++ b/apps/confbridge/conf_chan_record.c
@@ -0,0 +1,94 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013 Digium, Inc.
+ *
+ * Richard Mudgett <rmudgett@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ * \brief ConfBridge recorder channel driver
+ *
+ * \author Richard Mudgett <rmudgett@digium.com>
+ *
+ * See Also:
+ * \arg \ref AstCREDITS
+ */
+
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/channel.h"
+#include "asterisk/bridging.h"
+#include "include/confbridge.h"
+
+/* ------------------------------------------------------------------- */
+
+static int rec_call(struct ast_channel *chan, const char *addr, int timeout)
+{
+ /* Make sure anyone calling ast_call() for this channel driver is going to fail. */
+ return -1;
+}
+
+static struct ast_frame *rec_read(struct ast_channel *ast)
+{
+ return &ast_null_frame;
+}
+
+static int rec_write(struct ast_channel *ast, struct ast_frame *f)
+{
+ return 0;
+}
+
+static struct ast_channel *rec_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
+{
+ struct ast_channel *chan;
+ struct ast_format format;
+ const char *conf_name = data;
+
+ chan = ast_channel_alloc(1, AST_STATE_UP, NULL, NULL, NULL, NULL, NULL, NULL, 0,
+ "CBRec/conf-%s-uid-%d",
+ conf_name, (int) ast_random());
+ if (!chan) {
+ return NULL;
+ }
+ if (ast_channel_add_bridge_role(chan, "recorder")) {
+ ast_channel_release(chan);
+ return NULL;
+ }
+ ast_format_set(&format, AST_FORMAT_SLINEAR, 0);
+ ast_channel_tech_set(chan, conf_record_get_tech());
+ ast_format_cap_add_all(ast_channel_nativeformats(chan));
+ ast_format_copy(ast_channel_writeformat(chan), &format);
+ ast_format_copy(ast_channel_rawwriteformat(chan), &format);
+ ast_format_copy(ast_channel_readformat(chan), &format);
+ ast_format_copy(ast_channel_rawreadformat(chan), &format);
+ return chan;
+}
+
+static struct ast_channel_tech record_tech = {
+ .type = "CBRec",
+ .description = "Conference Bridge Recording Channel",
+ .requester = rec_request,
+ .call = rec_call,
+ .read = rec_read,
+ .write = rec_write,
+};
+
+struct ast_channel_tech *conf_record_get_tech(void)
+{
+ return &record_tech;
+}
diff --git a/apps/confbridge/conf_config_parser.c b/apps/confbridge/conf_config_parser.c
index 1bca2d5c2..6cec25522 100644
--- a/apps/confbridge/conf_config_parser.c
+++ b/apps/confbridge/conf_config_parser.c
@@ -1924,6 +1924,7 @@ int conf_load_config(int reload)
/* This option should only be used with the CONFBRIDGE dialplan function */
aco_option_register_custom(&cfg_info, "template", ACO_EXACT, user_types, NULL, user_template_handler, 0);
+/* BUGBUG need a user supplied bridge merge_priority to merge ConfBridges (default = 1, range 1-INT_MAX) */
/* Bridge options */
aco_option_register(&cfg_info, "type", ACO_EXACT, bridge_types, NULL, OPT_NOOP_T, 0, 0);
aco_option_register(&cfg_info, "jitterbuffer", ACO_EXACT, bridge_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct bridge_profile, flags), USER_OPT_JITTERBUFFER);
@@ -2156,7 +2157,8 @@ int conf_set_menu_to_user(const char *menu_name, struct confbridge_user *user)
ao2_ref(menu, +1);
pvt->menu = menu;
- ast_bridge_features_hook(&user->features, pvt->menu_entry.dtmf, menu_hook_callback, pvt, menu_hook_destroy);
+ ast_bridge_dtmf_hook(&user->features, pvt->menu_entry.dtmf, menu_hook_callback,
+ pvt, menu_hook_destroy, 0);
}
ao2_unlock(menu);
diff --git a/apps/confbridge/confbridge_manager.c b/apps/confbridge/confbridge_manager.c
new file mode 100644
index 000000000..56fedb98e
--- /dev/null
+++ b/apps/confbridge/confbridge_manager.c
@@ -0,0 +1,339 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Jonathan Rose <jrose@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Confbridge manager events for stasis messages
+ *
+ * \author Jonathan Rose <jrose@digium.com>
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/channel.h"
+#include "asterisk/bridging.h"
+#include "asterisk/stasis.h"
+#include "asterisk/stasis_channels.h"
+#include "asterisk/stasis_bridging.h"
+#include "asterisk/manager.h"
+#include "asterisk/stasis_message_router.h"
+#include "include/confbridge.h"
+
+/*** DOCUMENTATION
+ <managerEvent language="en_US" name="ConfbridgeStart">
+ <managerEventInstance class="EVENT_FLAG_CALL">
+ <synopsis>Raised when a conference starts.</synopsis>
+ <syntax>
+ <parameter name="Conference">
+ <para>The name of the Confbridge conference.</para>
+ </parameter>
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='BridgeCreate']/managerEventInstance/syntax/parameter)" />
+ </syntax>
+ <see-also>
+ <ref type="managerEvent">ConfbridgeEnd</ref>
+ <ref type="application">ConfBridge</ref>
+ </see-also>
+ </managerEventInstance>
+ </managerEvent>
+ <managerEvent language="en_US" name="ConfbridgeEnd">
+ <managerEventInstance class="EVENT_FLAG_CALL">
+ <synopsis>Raised when a conference ends.</synopsis>
+ <syntax>
+ <parameter name="Conference">
+ <para>The name of the Confbridge conference.</para>
+ </parameter>
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='BridgeCreate']/managerEventInstance/syntax/parameter)" />
+ </syntax>
+ <see-also>
+ <ref type="managerEvent">ConfbridgeStart</ref>
+ <ref type="application">ConfBridge</ref>
+ </see-also>
+ </managerEventInstance>
+ </managerEvent>
+ <managerEvent language="en_US" name="ConfbridgeJoin">
+ <managerEventInstance class="EVENT_FLAG_CALL">
+ <synopsis>Raised when a channel joins a Confbridge conference.</synopsis>
+ <syntax>
+ <parameter name="Conference">
+ <para>The name of the Confbridge conference.</para>
+ </parameter>
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='BridgeCreate']/managerEventInstance/syntax/parameter)" />
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+ </syntax>
+ <see-also>
+ <ref type="managerEvent">ConfbridgeLeave</ref>
+ <ref type="application">ConfBridge</ref>
+ </see-also>
+ </managerEventInstance>
+ </managerEvent>
+ <managerEvent language="en_US" name="ConfbridgeLeave">
+ <managerEventInstance class="EVENT_FLAG_CALL">
+ <synopsis>Raised when a channel leaves a Confbridge conference.</synopsis>
+ <syntax>
+ <parameter name="Conference">
+ <para>The name of the Confbridge conference.</para>
+ </parameter>
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='BridgeCreate']/managerEventInstance/syntax/parameter)" />
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+ </syntax>
+ <see-also>
+ <ref type="managerEvent">ConfbridgeJoin</ref>
+ <ref type="application">ConfBridge</ref>
+ </see-also>
+ </managerEventInstance>
+ </managerEvent>
+ <managerEvent language="en_US" name="ConfbridgeRecord">
+ <managerEventInstance class="EVENT_FLAG_CALL">
+ <synopsis>Raised when a conference starts recording.</synopsis>
+ <syntax>
+ <parameter name="Conference">
+ <para>The name of the Confbridge conference.</para>
+ </parameter>
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='BridgeCreate']/managerEventInstance/syntax/parameter)" />
+ </syntax>
+ <see-also>
+ <ref type="managerEvent">ConfbridgeStopRecord</ref>
+ <ref type="application">ConfBridge</ref>
+ </see-also>
+ </managerEventInstance>
+ </managerEvent>
+ <managerEvent language="en_US" name="ConfbridgeStopRecord">
+ <managerEventInstance class="EVENT_FLAG_CALL">
+ <synopsis>Raised when a conference that was recording stops recording.</synopsis>
+ <syntax>
+ <parameter name="Conference">
+ <para>The name of the Confbridge conference.</para>
+ </parameter>
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='BridgeCreate']/managerEventInstance/syntax/parameter)" />
+ </syntax>
+ <see-also>
+ <ref type="managerEvent">ConfbridgeRecord</ref>
+ <ref type="application">ConfBridge</ref>
+ </see-also>
+ </managerEventInstance>
+ </managerEvent>
+ <managerEvent language="en_US" name="ConfbridgeMute">
+ <managerEventInstance class="EVENT_FLAG_CALL">
+ <synopsis>Raised when a Confbridge participant mutes.</synopsis>
+ <syntax>
+ <parameter name="Conference">
+ <para>The name of the Confbridge conference.</para>
+ </parameter>
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='BridgeCreate']/managerEventInstance/syntax/parameter)" />
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+ </syntax>
+ <see-also>
+ <ref type="managerEvent">ConfbridgeUnmute</ref>
+ <ref type="application">ConfBridge</ref>
+ </see-also>
+ </managerEventInstance>
+ </managerEvent>
+ <managerEvent language="en_US" name="ConfbridgeUnmute">
+ <managerEventInstance class="EVENT_FLAG_CALL">
+ <synopsis>Raised when a confbridge participant unmutes.</synopsis>
+ <syntax>
+ <parameter name="Conference">
+ <para>The name of the Confbridge conference.</para>
+ </parameter>
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='BridgeCreate']/managerEventInstance/syntax/parameter)" />
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+ </syntax>
+ <see-also>
+ <ref type="managerEvent">ConfbridgeMute</ref>
+ <ref type="application">ConfBridge</ref>
+ </see-also>
+ </managerEventInstance>
+ </managerEvent>
+
+ <managerEvent language="en_US" name="ConfbridgeTalking">
+ <managerEventInstance class="EVENT_FLAG_CALL">
+ <synopsis>Raised when a confbridge participant unmutes.</synopsis>
+ <syntax>
+ <parameter name="Conference">
+ <para>The name of the Confbridge conference.</para>
+ </parameter>
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='BridgeCreate']/managerEventInstance/syntax/parameter)" />
+ <xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
+ <parameter name="TalkingStatus">
+ <enumlist>
+ <enum name="on"/>
+ <enum name="off"/>
+ </enumlist>
+ </parameter>
+ </syntax>
+ <see-also>
+ <ref type="application">ConfBridge</ref>
+ </see-also>
+ </managerEventInstance>
+ </managerEvent>
+***/
+
+static struct stasis_message_router *bridge_state_router;
+static struct stasis_message_router *channel_state_router;
+
+static void append_event_header(struct ast_str **fields_string,
+ const char *header, const char *value)
+{
+ struct ast_str *working_str = *fields_string;
+
+ if (!working_str) {
+ working_str = ast_str_create(128);
+ if (!working_str) {
+ return;
+ }
+ *fields_string = working_str;
+ }
+
+ ast_str_append(&working_str, 0,
+ "%s: %s\r\n",
+ header, value);
+}
+
+static void stasis_confbridge_cb(void *data, struct stasis_subscription *sub,
+ struct stasis_topic *topic,
+ struct stasis_message *message)
+{
+ struct ast_bridge_blob *blob = stasis_message_data(message);
+ const char *type = ast_bridge_blob_json_type(blob);
+ const char *conference_name;
+ RAII_VAR(struct ast_str *, bridge_text, NULL, ast_free);
+ RAII_VAR(struct ast_str *, channel_text, NULL, ast_free);
+ RAII_VAR(struct ast_str *, extra_text, NULL, ast_free);
+ char *event;
+
+ if (!blob || !type) {
+ ast_assert(0);
+ return;
+ }
+
+ if (!strcmp("confbridge_start", type)) {
+ event = "ConfbridgeStart";
+ } else if (!strcmp("confbridge_end", type)) {
+ event = "ConfbridgeEnd";
+ } else if (!strcmp("confbridge_leave", type)) {
+ event = "ConfbridgeLeave";
+ } else if (!strcmp("confbridge_join", type)) {
+ event = "ConfbridgeJoin";
+ } else if (!strcmp("confbridge_record", type)) {
+ event = "ConfbridgeRecord";
+ } else if (!strcmp("confbridge_stop_record", type)) {
+ event = "ConfbridgeStopRecord";
+ } else if (!strcmp("confbridge_mute", type)) {
+ event = "ConfbridgeMute";
+ } else if (!strcmp("confbridge_unmute", type)) {
+ event = "ConfbridgeUnmute";
+ } else if (!strcmp("confbridge_talking", type)) {
+ const char *talking_status = ast_json_string_get(ast_json_object_get(blob->blob, "talking_status"));
+ event = "ConfbridgeTalking";
+
+ if (!talking_status) {
+ return;
+ }
+
+ append_event_header(&extra_text, "TalkingStatus", talking_status);
+
+ } else {
+ return;
+ }
+
+ conference_name = ast_json_string_get(ast_json_object_get(blob->blob, "conference"));
+
+ if (!conference_name) {
+ ast_assert(0);
+ return;
+ }
+
+ bridge_text = ast_manager_build_bridge_state_string(blob->bridge, "");
+ if (blob->channel) {
+ channel_text = ast_manager_build_channel_state_string(blob->channel);
+ }
+
+ manager_event(EVENT_FLAG_CALL, event,
+ "Conference: %s\r\n"
+ "%s"
+ "%s"
+ "%s",
+ conference_name,
+ ast_str_buffer(bridge_text),
+ channel_text ? ast_str_buffer(channel_text) : "",
+ extra_text ? ast_str_buffer(extra_text) : "");
+}
+
+static struct stasis_message_type *confbridge_msg_type;
+
+struct stasis_message_type *confbridge_message_type(void)
+{
+ return confbridge_msg_type;
+}
+
+void manager_confbridge_shutdown(void) {
+ ao2_cleanup(confbridge_msg_type);
+ confbridge_msg_type = NULL;
+
+ if (bridge_state_router) {
+ stasis_message_router_unsubscribe(bridge_state_router);
+ bridge_state_router = NULL;
+ }
+
+ if (channel_state_router) {
+ stasis_message_router_unsubscribe(channel_state_router);
+ channel_state_router = NULL;
+ }
+}
+
+int manager_confbridge_init(void)
+{
+ if (!(confbridge_msg_type = stasis_message_type_create("confbridge"))) {
+ return -1;
+ }
+
+ bridge_state_router = stasis_message_router_create(
+ stasis_caching_get_topic(ast_bridge_topic_all_cached()));
+
+ if (!bridge_state_router) {
+ return -1;
+ }
+
+ if (stasis_message_router_add(bridge_state_router,
+ confbridge_message_type(),
+ stasis_confbridge_cb,
+ NULL)) {
+ manager_confbridge_shutdown();
+ return -1;
+ }
+
+ channel_state_router = stasis_message_router_create(
+ stasis_caching_get_topic(ast_channel_topic_all_cached()));
+
+ if (!channel_state_router) {
+ manager_confbridge_shutdown();
+ return -1;
+ }
+
+ if (stasis_message_router_add(channel_state_router,
+ confbridge_message_type(),
+ stasis_confbridge_cb,
+ NULL)) {
+ manager_confbridge_shutdown();
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/apps/confbridge/include/confbridge.h b/apps/confbridge/include/confbridge.h
index 245561376..f0620149a 100644
--- a/apps/confbridge/include/confbridge.h
+++ b/apps/confbridge/include/confbridge.h
@@ -222,6 +222,8 @@ struct confbridge_conference {
AST_LIST_HEAD_NOLOCK(, confbridge_user) waiting_list; /*!< List of users waiting to join the conference bridge */
};
+extern struct ao2_container *conference_bridges;
+
struct post_join_action {
int (*func)(struct confbridge_user *user);
AST_LIST_ENTRY(post_join_action) list;
@@ -460,4 +462,65 @@ void conf_remove_user_waiting(struct confbridge_conference *conference, struct c
* \retval non-zero failure
*/
int conf_add_post_join_action(struct confbridge_user *user, int (*func)(struct confbridge_user *user));
+
+/*!
+ * \since 12.0
+ * \brief get the confbridge stasis message type
+ *
+ * \retval stasis message type for confbridge messages if it's available
+ * \retval NULL if it isn't
+ */
+struct stasis_message_type *confbridge_message_type(void);
+
+/*!
+ * \since 12.0
+ * \brief register stasis message routers to handle manager events for confbridge messages
+ *
+ * \retval 0 success
+ * \retval non-zero failure
+ */
+int manager_confbridge_init(void);
+
+/*!
+ * \since 12.0
+ * \brief unregister stasis message routers to handle manager events for confbridge messages
+ */
+void manager_confbridge_shutdown(void);
+
+/*!
+ * \brief Get ConfBridge record channel technology struct.
+ * \since 12.0.0
+ *
+ * \return ConfBridge record channel technology.
+ */
+struct ast_channel_tech *conf_record_get_tech(void);
+
+/*!
+ * \brief Get ConfBridge announce channel technology struct.
+ * \since 12.0.0
+ *
+ * \return ConfBridge announce channel technology.
+ */
+struct ast_channel_tech *conf_announce_get_tech(void);
+
+/*!
+ * \brief Remove the announcer channel from the conference.
+ * \since 12.0.0
+ *
+ * \param chan Either channel in the announcer channel pair.
+ *
+ * \return Nothing
+ */
+void conf_announce_channel_depart(struct ast_channel *chan);
+
+/*!
+ * \brief Push the announcer channel into the conference.
+ * \since 12.0.0
+ *
+ * \param ast Either channel in the announcer channel pair.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int conf_announce_channel_push(struct ast_channel *ast);
#endif