Newer
Older
return 0;
}
if (!ao2_container_count(conference_bridges)) {
astman_send_error(s, m, "No active conferences.");
return 0;
}
conference = ao2_find(conference_bridges, conference_name, OBJ_KEY);
if (!conference) {
astman_send_error(s, m, "No Conference by that name found.");
return 0;
}
found = !kick_conference_participant(conference, channel);
ao2_ref(conference, -1);
astman_send_ack(s, m, !strcmp("all", channel) ? "All participants kicked" : "User kicked");
} else {
astman_send_error(s, m, "No Channel by that name found in Conference.");
}
return 0;
}
static int action_confbridgestartrecord(struct mansession *s, const struct message *m)
{
const char *conference_name = astman_get_header(m, "Conference");
const char *recordfile = astman_get_header(m, "RecordFile");
struct confbridge_conference *conference;
if (ast_strlen_zero(conference_name)) {
astman_send_error(s, m, "No Conference name provided.");
return 0;
}
if (!ao2_container_count(conference_bridges)) {
astman_send_error(s, m, "No active conferences.");
return 0;
}
conference = ao2_find(conference_bridges, conference_name, OBJ_KEY);
if (!conference) {
astman_send_error(s, m, "No Conference by that name found.");
return 0;
}
ao2_lock(conference);
if (conf_is_recording(conference)) {
astman_send_error(s, m, "Conference is already being recorded.");
ao2_unlock(conference);
ao2_ref(conference, -1);
return 0;
}
if (!ast_strlen_zero(recordfile)) {
ast_copy_string(conference->b_profile.rec_file, recordfile, sizeof(conference->b_profile.rec_file));
Richard Mudgett
committed
if (conf_start_record(conference)) {
astman_send_error(s, m, "Internal error starting conference recording.");
ao2_unlock(conference);
ao2_ref(conference, -1);
ao2_unlock(conference);
ao2_ref(conference, -1);
astman_send_ack(s, m, "Conference Recording Started.");
return 0;
}
static int action_confbridgestoprecord(struct mansession *s, const struct message *m)
{
const char *conference_name = astman_get_header(m, "Conference");
struct confbridge_conference *conference;
if (ast_strlen_zero(conference_name)) {
astman_send_error(s, m, "No Conference name provided.");
return 0;
}
if (!ao2_container_count(conference_bridges)) {
astman_send_error(s, m, "No active conferences.");
return 0;
}
conference = ao2_find(conference_bridges, conference_name, OBJ_KEY);
if (!conference) {
astman_send_error(s, m, "No Conference by that name found.");
return 0;
}
ao2_lock(conference);
if (conf_stop_record(conference)) {
ao2_unlock(conference);
astman_send_error(s, m, "Internal error while stopping recording.");
ao2_ref(conference, -1);
ao2_unlock(conference);
ao2_ref(conference, -1);
astman_send_ack(s, m, "Conference Recording Stopped.");
return 0;
}
static int action_confbridgesetsinglevideosrc(struct mansession *s, const struct message *m)
{
const char *conference_name = astman_get_header(m, "Conference");
const char *channel = astman_get_header(m, "Channel");
struct confbridge_user *user;
struct confbridge_conference *conference;
if (ast_strlen_zero(conference_name)) {
astman_send_error(s, m, "No Conference name provided.");
return 0;
}
if (ast_strlen_zero(channel)) {
astman_send_error(s, m, "No channel name provided.");
return 0;
}
if (!ao2_container_count(conference_bridges)) {
astman_send_error(s, m, "No active conferences.");
return 0;
}
conference = ao2_find(conference_bridges, conference_name, OBJ_KEY);
if (!conference) {
astman_send_error(s, m, "No Conference by that name found.");
return 0;
}
/* find channel and set as video src. */
ao2_lock(conference);
AST_LIST_TRAVERSE(&conference->active_list, user, list) {
if (!strncmp(channel, ast_channel_name(user->chan), strlen(channel))) {
ast_bridge_set_single_src_video_mode(conference->bridge, user->chan);
ao2_unlock(conference);
ao2_ref(conference, -1);
/* do not access user after conference unlock. We are just
* using this check to see if it was found or not */
astman_send_error(s, m, "No channel by that name found in conference.");
return 0;
}
astman_send_ack(s, m, "Conference single video source set.");
return 0;
}
static int func_confbridge_info(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
{
char *parse;
struct confbridge_conference *conference;
struct confbridge_user *user;
int count = 0;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(type);
AST_APP_ARG(confno);
);
/* parse all the required arguments and make sure they exist. */
if (ast_strlen_zero(data)) {
return -1;
}
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
if (ast_strlen_zero(args.confno) || ast_strlen_zero(args.type)) {
return -1;
}
conference = ao2_find(conference_bridges, args.confno, OBJ_KEY);
if (!conference) {
snprintf(buf, len, "0");
return 0;
}
/* get the correct count for the type requested */
ao2_lock(conference);
if (!strcasecmp(args.type, "parties")) {
AST_LIST_TRAVERSE(&conference->active_list, user, list) {
AST_LIST_TRAVERSE(&conference->waiting_list, user, list) {
count++;
}
} else if (!strcasecmp(args.type, "admins")) {
AST_LIST_TRAVERSE(&conference->active_list, user, list) {
if (ast_test_flag(&user->u_profile, USER_OPT_ADMIN)) {
} else if (!strcasecmp(args.type, "marked")) {
AST_LIST_TRAVERSE(&conference->active_list, user, list) {
if (ast_test_flag(&user->u_profile, USER_OPT_MARKEDUSER)) {
} else if (!strcasecmp(args.type, "locked")) {
count = conference->locked;
} else if (!strcasecmp(args.type, "muted")) {
count = conference->muted;
ast_log(LOG_ERROR, "Invalid keyword '%s' passed to CONFBRIDGE_INFO.\n", args.type);
}
snprintf(buf, len, "%d", count);
ao2_unlock(conference);
ao2_ref(conference, -1);
void conf_add_user_active(struct confbridge_conference *conference, struct confbridge_user *user)
Matthew Jordan
committed
{
AST_LIST_INSERT_TAIL(&conference->active_list, user, list);
conference->activeusers++;
Matthew Jordan
committed
}
void conf_add_user_marked(struct confbridge_conference *conference, struct confbridge_user *user)
Matthew Jordan
committed
{
AST_LIST_INSERT_TAIL(&conference->active_list, user, list);
conference->activeusers++;
conference->markedusers++;
Matthew Jordan
committed
}
void conf_add_user_waiting(struct confbridge_conference *conference, struct confbridge_user *user)
Matthew Jordan
committed
{
AST_LIST_INSERT_TAIL(&conference->waiting_list, user, list);
conference->waitingusers++;
Matthew Jordan
committed
}
void conf_remove_user_active(struct confbridge_conference *conference, struct confbridge_user *user)
Matthew Jordan
committed
{
AST_LIST_REMOVE(&conference->active_list, user, list);
conference->activeusers--;
Matthew Jordan
committed
}
void conf_remove_user_marked(struct confbridge_conference *conference, struct confbridge_user *user)
Matthew Jordan
committed
{
AST_LIST_REMOVE(&conference->active_list, user, list);
conference->activeusers--;
conference->markedusers--;
Matthew Jordan
committed
}
void conf_mute_only_active(struct confbridge_conference *conference)
Matthew Jordan
committed
{
struct confbridge_user *only_user = AST_LIST_FIRST(&conference->active_list);
Matthew Jordan
committed
/* Turn on MOH if the single participant is set up for it */
if (ast_test_flag(&only_user->u_profile, USER_OPT_MUSICONHOLD)) {
conf_moh_start(only_user);
Matthew Jordan
committed
}
conf_update_user_mute(only_user);
Matthew Jordan
committed
}
void conf_remove_user_waiting(struct confbridge_conference *conference, struct confbridge_user *user)
Matthew Jordan
committed
{
AST_LIST_REMOVE(&conference->waiting_list, user, list);
conference->waitingusers--;
Matthew Jordan
committed
}
Richard Mudgett
committed
/*!
* \internal
* \brief Unregister a ConfBridge channel technology.
* \since 12.0.0
*
* \param tech What to unregister.
*
* \return Nothing
*/
static void unregister_channel_tech(struct ast_channel_tech *tech)
{
ast_channel_unregister(tech);
ao2_cleanup(tech->capabilities);
Richard Mudgett
committed
}
/*!
* \internal
* \brief Register a ConfBridge channel technology.
* \since 12.0.0
*
* \param tech What to register.
*
* \retval 0 on success.
* \retval -1 on error.
*/
static int register_channel_tech(struct ast_channel_tech *tech)
{
tech->capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
Richard Mudgett
committed
if (!tech->capabilities) {
return -1;
}
ast_format_cap_append_by_type(tech->capabilities, AST_MEDIA_TYPE_UNKNOWN);
Richard Mudgett
committed
if (ast_channel_register(tech)) {
ast_log(LOG_ERROR, "Unable to register channel technology %s(%s).\n",
tech->type, tech->description);
return -1;
}
return 0;
}
/*! \brief Called when module is being unloaded */
static int unload_module(void)
{
ast_unregister_application(app);
ast_custom_function_unregister(&confbridge_function);
ast_custom_function_unregister(&confbridge_info_function);
ast_cli_unregister_multiple(cli_confbridge, ARRAY_LEN(cli_confbridge));
ast_manager_unregister("ConfbridgeList");
ast_manager_unregister("ConfbridgeListRooms");
ast_manager_unregister("ConfbridgeMute");
ast_manager_unregister("ConfbridgeUnmute");
ast_manager_unregister("ConfbridgeKick");
ast_manager_unregister("ConfbridgeUnlock");
ast_manager_unregister("ConfbridgeLock");
ast_manager_unregister("ConfbridgeStartRecord");
ast_manager_unregister("ConfbridgeStopRecord");
ast_manager_unregister("ConfbridgeSetSingleVideoSrc");
Richard Mudgett
committed
/* Unsubscribe from stasis confbridge message type and clean it up. */
manager_confbridge_shutdown();
/* Get rid of the conference bridges container. Since we only allow dynamic ones none will be active. */
ao2_cleanup(conference_bridges);
conference_bridges = NULL;
Richard Mudgett
committed
unregister_channel_tech(conf_announce_get_tech());
unregister_channel_tech(conf_record_get_tech());
return 0;
/*!
* \brief Load the module
*
* Module loading including tests for configuration or dependencies.
* This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
* or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
* tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
* configuration file or other non-critical problem return
* AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
*/
static int load_module(void)
{
ast_log(LOG_ERROR, "Unable to load config. Not loading module.\n");
return AST_MODULE_LOAD_DECLINE;
}
Richard Mudgett
committed
if (register_channel_tech(conf_record_get_tech())
|| register_channel_tech(conf_announce_get_tech())) {
unload_module();
return AST_MODULE_LOAD_DECLINE;
/* Create a container to hold the conference bridges */
conference_bridges = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
CONFERENCE_BRIDGE_BUCKETS,
conference_bridge_hash_cb, NULL, conference_bridge_cmp_cb);
if (!conference_bridges) {
unload_module();
return AST_MODULE_LOAD_DECLINE;
Richard Mudgett
committed
/* Setup manager stasis subscriptions */
res |= manager_confbridge_init();
res |= ast_register_application_xml(app, confbridge_exec);
res |= ast_custom_function_register_escalating(&confbridge_function, AST_CFE_WRITE);
res |= ast_custom_function_register(&confbridge_info_function);
res |= ast_cli_register_multiple(cli_confbridge, ARRAY_LEN(cli_confbridge));
res |= ast_manager_register_xml("ConfbridgeList", EVENT_FLAG_REPORTING, action_confbridgelist);
res |= ast_manager_register_xml("ConfbridgeListRooms", EVENT_FLAG_REPORTING, action_confbridgelistrooms);
res |= ast_manager_register_xml("ConfbridgeMute", EVENT_FLAG_CALL, action_confbridgemute);
res |= ast_manager_register_xml("ConfbridgeUnmute", EVENT_FLAG_CALL, action_confbridgeunmute);
res |= ast_manager_register_xml("ConfbridgeKick", EVENT_FLAG_CALL, action_confbridgekick);
res |= ast_manager_register_xml("ConfbridgeUnlock", EVENT_FLAG_CALL, action_confbridgeunlock);
res |= ast_manager_register_xml("ConfbridgeLock", EVENT_FLAG_CALL, action_confbridgelock);
res |= ast_manager_register_xml("ConfbridgeStartRecord", EVENT_FLAG_SYSTEM, action_confbridgestartrecord);
res |= ast_manager_register_xml("ConfbridgeStopRecord", EVENT_FLAG_SYSTEM, action_confbridgestoprecord);
res |= ast_manager_register_xml("ConfbridgeSetSingleVideoSrc", EVENT_FLAG_CALL, action_confbridgesetsinglevideosrc);
unload_module();
return AST_MODULE_LOAD_DECLINE;
return AST_MODULE_LOAD_SUCCESS;
static int reload(void)
{
return conf_reload_config();
Tilghman Lesher
committed
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Conference Bridge Application",
Mark Michelson
committed
.support_level = AST_MODULE_SUPPORT_CORE,
Tilghman Lesher
committed
.load = load_module,
.unload = unload_module,
Tilghman Lesher
committed
.load_pri = AST_MODPRI_DEVSTATE_PROVIDER,
.optional_modules = "codec_speex,func_jitterbuffer",