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
This commit is contained in:
Richard Mudgett
2013-05-21 18:00:22 +00:00
parent e1e1cc2dee
commit 3d63833bd6
99 changed files with 19717 additions and 7682 deletions

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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