mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-12 15:45:18 +00:00
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:
207
apps/confbridge/conf_chan_announce.c
Normal file
207
apps/confbridge/conf_chan_announce.c
Normal 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;
|
||||
}
|
94
apps/confbridge/conf_chan_record.c
Normal file
94
apps/confbridge/conf_chan_record.c
Normal 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;
|
||||
}
|
@@ -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);
|
||||
|
339
apps/confbridge/confbridge_manager.c
Normal file
339
apps/confbridge/confbridge_manager.c
Normal 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;
|
||||
}
|
@@ -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
|
||||
|
Reference in New Issue
Block a user