diff options
author | Richard Mudgett <rmudgett@digium.com> | 2013-05-21 18:00:22 +0000 |
---|---|---|
committer | Richard Mudgett <rmudgett@digium.com> | 2013-05-21 18:00:22 +0000 |
commit | 3d63833bd6c869b7efa383e8dea14be1a6eff998 (patch) | |
tree | 34957dd051b8f67c7cc58a510e24ee3873a61ad4 /apps/confbridge | |
parent | e1e1cc2deefb92f8b43825f1f34e619354737842 (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.c | 207 | ||||
-rw-r--r-- | apps/confbridge/conf_chan_record.c | 94 | ||||
-rw-r--r-- | apps/confbridge/conf_config_parser.c | 4 | ||||
-rw-r--r-- | apps/confbridge/confbridge_manager.c | 339 | ||||
-rw-r--r-- | apps/confbridge/include/confbridge.h | 63 |
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 |