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/conf_chan_announce.c | |
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/conf_chan_announce.c')
-rw-r--r-- | apps/confbridge/conf_chan_announce.c | 207 |
1 files changed, 207 insertions, 0 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; +} |