464 static const char app[] =
"ConfBridge";
465 static const char app2[] =
"ConfKick";
468 #define CONFERENCE_BRIDGE_BUCKETS 53
471 #define RECORD_FILENAME_INITIAL_SPACE 128
488 const char *
name = obj;
513 const char *right_name = arg;
519 right_name = right->
name;
522 cmp = strcasecmp(left->
name, right_name);
525 cmp = strncasecmp(left->
name, right_name, strlen(right_name));
535 return S_OR(custom_sounds->
hasjoin,
"conf-hasjoin");
537 return S_OR(custom_sounds->
hasleft,
"conf-hasleft");
539 return S_OR(custom_sounds->
kicked,
"conf-kicked");
541 return S_OR(custom_sounds->
muted,
"conf-muted");
543 return S_OR(custom_sounds->
unmuted,
"conf-unmuted");
549 return S_OR(custom_sounds->
onlyone,
"conf-onlyone");
561 return S_OR(custom_sounds->
getpin,
"conf-getpin");
567 return S_OR(custom_sounds->
locked,
"conf-locked");
575 return S_OR(custom_sounds->
join,
"confbridge-join");
577 return S_OR(custom_sounds->
leave,
"confbridge-leave");
583 return S_OR(custom_sounds->
begin,
"confbridge-conf-begin");
597 "conference", conference->
name);
636 "conference", conference->
name);
648 if (!bridge_snapshot) {
680 "muted",
user->muted);
760 ext = strrchr(rec_file,
'.');
765 ast_str_set(filename, 0,
"%s-%u", rec_file, (
unsigned int) now);
779 if (!*orig_rec_file) {
936 const char *filename)
939 const char *stop_digits;
1185 ast_debug(1,
"Destroying conference bridge '%s'\n", conference->
name);
1234 handler =
user->conference->state->join_waitmarked;
1263 handler =
user->conference->state->leave_waitmarked;
1265 handler =
user->conference->state->leave_unmarked;
1290 mute_user =
user->muted;
1293 mute_system =
user->playing_moh
1298 || (!
user->conference->markedusers
1301 mute_effective = mute_user || mute_system;
1303 ast_debug(1,
"User %s is %s: user:%d system:%d.\n",
1305 mute_user, mute_system);
1306 user->features.mute = mute_effective;
1309 "Conference: %s\r\n"
1311 mute_effective ?
"muted" :
"unmuted",
1312 user->conference->b_profile.name,
1327 "Message: participant %s %s\r\n"
1328 "Conference: %s\r\n"
1331 mute ?
"muted" :
"unmuted",
1343 user->playing_moh = 0;
1344 if (!
user->suspended_moh) {
1370 user->playing_moh = 1;
1371 if (!
user->suspended_moh) {
1404 if (--
user->suspended_moh == 0 &&
user->playing_moh) {
1419 if (
user->suspended_moh++ == 0 &&
user->playing_moh) {
1452 if (!(action =
ast_calloc(1,
sizeof(*action)))) {
1522 ast_debug(1,
"Created announcer channel '%s' to conference bridge '%s'\n",
1526 "Confbridge/%s", conference->
name);
1570 char *confbr_name =
NULL;
1582 new_snapshot = msg->
target;
1609 comma = strchr(confbr_name,
',');
1637 if (!found_user && conference->waitingusers) {
1647 ast_log(
LOG_ERROR,
"Unable to find user profile for channel '%s' in bridge '%s'\n",
1648 old_snapshot->
base->
name, confbr_name);
1667 "muted",
user->muted);
1687 int max_members_reached = 0;
1692 ast_debug(1,
"Trying to find conference bridge '%s'\n", conference_name);
1703 ast_debug(1,
"Conference '%s' is locked and caller is not an admin\n", conference_name);
1716 ast_log(
LOG_ERROR,
"Conference '%s' could not be created.\n", conference_name);
1736 if (!conference->
bridge) {
1739 ast_log(
LOG_ERROR,
"Conference '%s' mixing bridge could not be created.\n", conference_name);
1784 "Conference '%s' could not be added to the conferences list.\n", conference_name);
1795 ast_log(
LOG_ERROR,
"Could not allocate announcer channel for conference '%s'\n", conference_name);
1803 ast_log(
LOG_ERROR,
"Could not add announcer channel for conference '%s' bridge\n", conference_name);
1821 ast_debug(1,
"Created conference '%s' and linked to container.\n", conference_name);
1827 user->conference = conference;
1843 user->suspended_moh = 1;
1864 user->u_profile.announcement)) {
1879 (conference->
activeusers >
user->u_profile.announce_user_count_all_after)) {
1889 if (user_count_res) {
1939 }
else if (say_number >= 0) {
2085 .
type =
"Confbridge async playback",
2121 if (async_datastore) {
2124 add = async_datastore->
data;
2131 if (!async_datastore) {
2136 if (!async_datastore->
data) {
2214 if (!async_datastore) {
2218 add = async_datastore->
data;
2300 if (!async_datastore) {
2304 add = async_datastore->
data;
2339 user->talking = talking;
2343 "talking_status", talking ?
"on" :
"off",
2345 if (!talking_extras) {
2356 char pin_guess[
MAX_PIN+1] = { 0, };
2357 const char *pin =
user->u_profile.pin;
2358 char *
tmp = pin_guess;
2368 for (i = 0; i < 3; i++) {
2372 if (!strcasecmp(pin, pin_guess)) {
2384 pin_guess[1] =
'\0';
2385 tmp = pin_guess + 1;
2415 snprintf(
user->name_rec_location,
sizeof(
user->name_rec_location),
2416 "%s/confbridge-name-%s-%s", destdir,
2422 user->name_rec_location,
2433 user->name_rec_location,
2442 user->name_rec_location[0] =
'\0';
2550 int res = 0, volume_adjustments[2];
2552 int async_delete_task_pushed = 0;
2554 const char *b_profile_name =
NULL;
2555 const char *u_profile_name =
NULL;
2556 const char *menu_profile_name =
NULL;
2562 .tech_args.drop_silence = 0,
2577 goto confbridge_cleanup;
2589 goto confbridge_cleanup;
2596 goto confbridge_cleanup;
2601 b_profile_name =
args.b_profile_name;
2605 ast_log(
LOG_WARNING,
"Conference bridge profile %s does not exist\n", b_profile_name ?
2608 goto confbridge_cleanup;
2613 u_profile_name =
args.u_profile_name;
2620 goto confbridge_cleanup;
2636 goto confbridge_cleanup;
2647 goto confbridge_cleanup;
2653 menu_profile_name =
args.menu_profile_name;
2658 ast_log(
LOG_WARNING,
"Conference menu profile %s does not exist\n", menu_profile_name ?
2661 goto confbridge_cleanup;
2666 user.features.dtmf_passthrough = 1;
2668 user.features.dtmf_passthrough = 0;
2673 user.features.text_messaging = 1;
2675 user.features.text_messaging = 0;
2679 if (
user.u_profile.talking_threshold) {
2680 user.tech_args.talking_threshold =
user.u_profile.talking_threshold;
2682 if (
user.u_profile.silence_threshold) {
2683 user.tech_args.silence_threshold =
user.u_profile.silence_threshold;
2692 goto confbridge_cleanup;
2700 goto confbridge_cleanup;
2708 user.tech_args.drop_silence = 1;
2749 if (
user.u_profile.timeout) {
2752 user.u_profile.timeout * 1000,
2764 join_hook_data =
ast_malloc(
sizeof(*join_hook_data));
2765 if (!join_hook_data) {
2767 goto confbridge_cleanup;
2777 goto confbridge_cleanup;
2780 leave_hook_data =
ast_malloc(
sizeof(*leave_hook_data));
2781 if (!leave_hook_data) {
2784 goto confbridge_cleanup;
2795 goto confbridge_cleanup;
2828 goto confbridge_cleanup;
2840 async_delete_task_pushed = 1;
2861 if (volume_adjustments[0]) {
2864 if (volume_adjustments[1]) {
2896 unsigned int binaural;
2909 const char *sound_to_play;
2966 const char *playback_file,
2967 const char *cur_dtmf,
2987 }
else if (
digit == -1) {
3009 dtmf[i] = cur_dtmf[i];
3027 &new_menu_entry, menu);
3043 ast_log(
LOG_WARNING,
"Only admin users can use the kick_last menu action. Channel %s of conf %s is not an admin.\n",
3060 }
else if (!last_user->
kicked) {
3080 args.no_hangup_chan = 1;
3122 int stop_prompts = 0;
3126 switch (menu_action->
id) {
3143 if (!stop_prompts) {
3146 "Message: %s\r\nChannel: %s",
3173 if (!(stop_prompts)) {
3245 const char *channel)
3250 int all = !strcasecmp(
"all", channel);
3251 int participants = !strcasecmp(
"participants", channel);
3296 int wordlen = strlen(
word);
3301 if (!strncasecmp(conference->
name,
word, wordlen) && ++which >
state) {
3319 int wordlen = strlen(
word);
3326 if (!strncasecmp(
"all",
word, wordlen) && ++which >
state) {
3330 if (!strncasecmp(
"participants",
word, wordlen) && ++which >
state) {
3360 e->
command =
"confbridge kick";
3362 "Usage: confbridge kick <conference> <channel>\n"
3363 " Kicks a channel out of the conference bridge.\n"
3364 " (all to kick everyone, participants to kick non-admins).\n";
3382 ast_cli(
a->fd,
"No conference bridge named '%s' found!\n",
a->argv[2]);
3388 if (!strcasecmp(
"all",
a->argv[3]) || !strcasecmp(
"participants",
a->argv[3])) {
3389 ast_cli(
a->fd,
"No participants found!\n");
3391 ast_cli(
a->fd,
"No participant named '%s' found!\n",
a->argv[3]);
3395 ast_cli(
a->fd,
"Kicked '%s' out of conference '%s'\n",
a->argv[3],
a->argv[2]);
3401 char flag_str[6 + 1];
3406 flag_str[pos++] =
'A';
3409 flag_str[pos++] =
'M';
3412 flag_str[pos++] =
'W';
3415 flag_str[pos++] =
'E';
3418 flag_str[pos++] =
'm';
3421 flag_str[pos++] =
'w';
3423 flag_str[pos] =
'\0';
3425 ast_cli(
a->fd,
"%-30s %-6s %-16s %-16s %-16s %s\n",
3428 user->u_profile.name,
3429 user->conference->b_profile.name,
3441 e->
command =
"confbridge list";
3443 "Usage: confbridge list [<name>]\n"
3444 " Lists all currently active conference bridges or a specific conference bridge.\n"
3446 " When a conference bridge name is provided, flags may be shown for users. Below\n"
3447 " are the flags and what they represent.\n"
3450 " A - The user is an admin\n"
3451 " M - The user is a marked user\n"
3452 " W - The user must wait for a marked user to join\n"
3453 " E - The user will be kicked after the last marked user leaves the conference\n"
3454 " m - The user is muted\n"
3455 " w - The user is waiting for a marked user to join\n";
3467 ast_cli(
a->fd,
"Conference Bridge Name Users Marked Locked Muted\n");
3468 ast_cli(
a->fd,
"================================ ====== ====== ====== =====\n");
3471 ast_cli(
a->fd,
"%-32s %6u %6u %-6s %s\n",
3488 ast_cli(
a->fd,
"No conference bridge named '%s' found!\n",
a->argv[2]);
3491 ast_cli(
a->fd,
"Channel Flags User Profile Bridge Profile Menu CallerID\n");
3492 ast_cli(
a->fd,
"============================== ====== ================ ================ ================ ================\n");
3540 const char *chan_name)
3544 int all = !strcasecmp(
"all", chan_name);
3545 int participants = !strcasecmp(
"participants", chan_name);
3590 ast_cli(
a->fd,
"No conference bridge named '%s' found!\n",
a->argv[2]);
3592 }
else if (res == -2) {
3593 if (!strcasecmp(
"all",
a->argv[3]) || !strcasecmp(
"participants",
a->argv[3])) {
3594 ast_cli(
a->fd,
"No participants found in conference %s\n",
a->argv[2]);
3596 ast_cli(
a->fd,
"No channel named '%s' found in conference %s\n",
a->argv[3],
a->argv[2]);
3600 ast_cli(
a->fd,
"%s %s from confbridge %s\n",
mute ?
"Muting" :
"Unmuting",
a->argv[3],
a->argv[2]);
3608 e->
command =
"confbridge mute";
3610 "Usage: confbridge mute <conference> <channel>\n"
3611 " Mute a channel in a conference.\n"
3612 " (all to mute everyone, participants to mute non-admins)\n"
3613 " If the specified channel is a prefix,\n"
3614 " the action will be taken on the first\n"
3615 " matching channel.\n";
3639 e->
command =
"confbridge unmute";
3641 "Usage: confbridge unmute <conference> <channel>\n"
3642 " Unmute a channel in a conference.\n"
3643 " (all to unmute everyone, participants to unmute non-admins)\n"
3644 " If the specified channel is a prefix,\n"
3645 " the action will be taken on the first\n"
3646 " matching channel.\n";
3670 e->
command =
"confbridge lock";
3672 "Usage: confbridge lock <conference>\n"
3673 " Lock a conference. While locked, no new non-admins\n"
3674 " may join the conference.\n";
3686 ast_cli(
a->fd,
"Conference %s is not found\n",
a->argv[2]);
3688 ast_cli(
a->fd,
"Conference %s is locked.\n",
a->argv[2]);
3697 e->
command =
"confbridge unlock";
3699 "Usage: confbridge unlock <conference>\n"
3700 " Unlock a previously locked conference.\n";
3712 ast_cli(
a->fd,
"Conference %s is not found\n",
a->argv[2]);
3714 ast_cli(
a->fd,
"Conference %s is unlocked.\n",
a->argv[2]);
3721 const char *rec_file =
NULL;
3726 e->
command =
"confbridge record start";
3728 "Usage: confbridge record start <conference> <file>\n"
3729 " <file> is optional, Otherwise the bridge profile\n"
3730 " record file will be used. If the bridge profile\n"
3731 " has no record file specified, a file will automatically\n"
3732 " be generated in the monitor directory\n";
3744 rec_file =
a->argv[4];
3749 ast_cli(
a->fd,
"Conference not found.\n");
3754 ast_cli(
a->fd,
"Conference is already being recorded.\n");
3764 ast_cli(
a->fd,
"Could not start recording due to internal error.\n");
3771 ast_cli(
a->fd,
"Recording started\n");
3783 e->
command =
"confbridge record stop";
3785 "Usage: confbridge record stop <conference>\n"
3786 " Stop a previously started recording.\n";
3800 ast_cli(
a->fd,
"Conference not found.\n");
3806 ast_cli(
a->fd,
"Recording %sstopped.\n", ret ?
"could not be " :
"");
3822 .
name =
"CONFBRIDGE",
3828 .
name =
"CONFBRIDGE_INFO",
3849 "Event: ConfbridgeList\r\n"
3851 "Conference: %s\r\n"
3853 "MarkedUser: %s\r\n"
3854 "WaitMarked: %s\r\n"
3859 "AnsweredTime: %d\r\n"
3891 snprintf(id_text,
sizeof(id_text),
"ActionID: %s\r\n", actionid);
3930 char id_text[512] =
"";
3934 snprintf(id_text,
sizeof(id_text),
"ActionID: %s\r\n", actionid);
3951 "Event: ConfbridgeListRooms\r\n"
3953 "Conference: %s\r\n"
4001 }
else if (res == -2) {
4074 astman_send_ack(s, m, !strcmp(
"all", channel) ?
"All participants kicked" :
"User kicked");
4235 if (!strcasecmp(
args.type,
"parties")) {
4242 }
else if (!strcasecmp(
args.type,
"admins")) {
4248 }
else if (!strcasecmp(
args.type,
"marked")) {
4254 }
else if (!strcasecmp(
args.type,
"locked")) {
4256 }
else if (!strcasecmp(
args.type,
"muted")) {
4261 snprintf(
buf,
len,
"%d", count);
4309 ast_debug(1,
"Kicked '%s' out of conference '%s'\n",
args.channel,
args.confbridge);
4512 .optional_modules =
"codec_speex,func_jitterbuffer",
static void playback_common(struct confbridge_conference *conference, const char *filename, int say_number)
int conf_handle_only_person(struct confbridge_user *user)
Handle actions whenever an user joins an empty conference.
static void playback_task_data_init(struct playback_task_data *ptd, struct confbridge_conference *conference, const char *filename, int say_number)
static int action_confbridgemute(struct mansession *s, const struct message *m)
static int push_announcer(struct confbridge_conference *conference)
Push the announcer channel into the bridge.
void conf_moh_stop(struct confbridge_user *user)
Stop MOH for the conference user.
static struct async_delete_name_rec_task_data * async_delete_name_rec_task_data_alloc(struct confbridge_conference *conference, const char *filename)
static void send_conf_start_event(struct confbridge_conference *conference)
static struct ast_datastore_info async_datastore_info
Datastore used for timing of async announcement playback.
static int send_event_hook_callback(struct ast_bridge_channel *bridge_channel, void *data)
static int generic_lock_unlock_helper(int lock, const char *conference_name)
static int action_confbridgeunlock(struct mansession *s, const struct message *m)
static struct confbridge_conference * join_conference_bridge(const char *conference_name, struct confbridge_user *user)
Join a conference bridge.
static int join_callback(struct ast_bridge_channel *bridge_channel, void *ignore)
void conf_add_user_active(struct confbridge_conference *conference, struct confbridge_user *user)
Add a conference bridge user as an unmarked active user of the conference.
static int action_confbridgekick(struct mansession *s, const struct message *m)
static int action_dialplan_exec(struct ast_bridge_channel *bridge_channel, struct conf_menu_action *menu_action)
const char * conf_get_sound(enum conf_sounds sound, struct bridge_profile_sounds *custom_sounds)
Looks to see if sound file is stored in bridge profile sounds, if not default sound is provided.
static void hangup_data_init(struct hangup_data *hangup, struct confbridge_conference *conference)
static int register_channel_tech(struct ast_channel_tech *tech)
static void unregister_channel_tech(struct ast_channel_tech *tech)
static void conf_moh_unsuspend(struct confbridge_user *user)
static int action_confbridgesetsinglevideosrc(struct mansession *s, const struct message *m)
static char * handle_cli_confbridge_mute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int action_playback_and_continue(struct confbridge_conference *conference, struct confbridge_user *user, struct ast_bridge_channel *bridge_channel, struct conf_menu *menu, const char *playback_file, const char *cur_dtmf, int *stop_prompts)
int conf_handle_inactive_waitmarked(struct confbridge_user *user)
Handle actions every time a waitmarked user joins w/o a marked user present.
static int action_confbridgeunmute(struct mansession *s, const struct message *m)
static int action_confbridgestoprecord(struct mansession *s, const struct message *m)
void confbridge_handle_atxfer(struct ast_attended_transfer_message *msg)
Create join/leave events for attended transfers.
void conf_add_user_marked(struct confbridge_conference *conference, struct confbridge_user *user)
Add a conference bridge user as a marked active user of the conference.
static struct ast_custom_function confbridge_function
static int is_new_rec_file(const char *rec_file, struct ast_str **orig_rec_file)
static void playback_task_data_destroy(struct playback_task_data *ptd)
static int action_playback(struct ast_bridge_channel *bridge_channel, const char *playback_file)
static int cli_mute_unmute_helper(int mute, struct ast_cli_args *a)
static int handle_conf_user_leave(struct confbridge_user *user)
Call the proper leave event handler for the user for the conference bridge's current state.
static int action_toggle_mute(struct confbridge_conference *conference, struct confbridge_user *user, struct ast_bridge_channel *bridge_channel)
static void send_join_event(struct confbridge_user *user, struct confbridge_conference *conference)
static void send_stop_record_event(struct confbridge_conference *conference)
static int func_confbridge_info(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static void send_mute_event(struct confbridge_user *user, struct confbridge_conference *conference)
#define CONFERENCE_BRIDGE_BUCKETS
static void leave_conference(struct confbridge_user *user)
Leave a conference.
void conf_add_user_waiting(struct confbridge_conference *conference, struct confbridge_user *user)
Add a conference bridge user as an waiting user of the conference.
static char * handle_cli_confbridge_lock(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int conf_stop_record(struct confbridge_conference *conference)
static int action_confbridgelist(struct mansession *s, const struct message *m)
void conf_remove_user_waiting(struct confbridge_conference *conference, struct confbridge_user *user)
Remove a conference bridge user from the waiting conference users in the conference.
static int conf_get_pin(struct ast_channel *chan, struct confbridge_user *user)
static int conf_rec_name(struct confbridge_user *user, const char *conf_name)
static void handle_video_on_join(struct confbridge_conference *conference, struct ast_channel *chan, int marked)
static int kick_conference_participant(struct confbridge_conference *conference, const char *channel)
static char * handle_cli_confbridge_kick(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
void conf_ended(struct confbridge_conference *conference)
Callback to be called when the conference has become empty.
static int conference_bridge_cmp_cb(void *obj, void *arg, int flags)
Comparison function used for conference bridges container.
static int action_toggle_mute_participants(struct confbridge_conference *conference, struct confbridge_user *user)
static struct ast_custom_function confbridge_info_function
static void async_delete_name_rec_task_data_destroy(struct async_delete_name_rec_task_data *atd)
int async_play_sound_file(struct confbridge_conference *conference, const char *filename, struct ast_channel *initiator)
Play sound file into conference bridge asynchronously.
static int play_sound_number(struct confbridge_conference *conference, int say_number)
Play number into the conference bridge.
int play_sound_file(struct confbridge_conference *conference, const char *filename)
Play sound file into conference bridge.
static void async_datastore_data_destroy(void *data)
static int confbridge_exec(struct ast_channel *chan, const char *data)
The ConfBridge application.
static int conf_start_record(struct confbridge_conference *conference)
static void send_leave_event(struct confbridge_user *user, struct confbridge_conference *conference)
void conf_remove_user_marked(struct confbridge_conference *conference, struct confbridge_user *user)
Remove a conference bridge user from the marked active conference users in the conference.
static void async_playback_task_data_destroy(struct async_playback_task_data *aptd)
static int play_sound_helper(struct confbridge_conference *conference, const char *filename, int say_number)
int conf_handle_dtmf(struct ast_bridge_channel *bridge_channel, struct confbridge_user *user, struct conf_menu_entry *menu_entry, struct conf_menu *menu)
Once a DTMF sequence matches a sequence in the user's DTMF menu, this function will get called to per...
static char * handle_cli_confbridge_stop_record(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static void conf_moh_suspend(struct confbridge_user *user)
static char * complete_confbridge_participant(const char *conference_name, const char *line, const char *word, int pos, int state)
static int action_mute_unmute_helper(struct mansession *s, const struct message *m, int mute)
static int playback_task(void *data)
Play an announcement into a confbridge.
void conf_update_user_mute(struct confbridge_user *user)
Update the actual mute status of the user and set it on the bridge.
static int announce_user_count(struct confbridge_conference *conference, struct confbridge_user *user, struct ast_bridge_channel *bridge_channel)
Announce number of users in the conference bridge to the caller.
static void destroy_conference_bridge(void *obj)
Destroy a conference bridge.
static int async_delete_name_rec(struct confbridge_conference *conference, const char *filename)
static int user_timeout(struct ast_bridge_channel *bridge_channel, void *ignore)
static int action_kick_last(struct confbridge_conference *conference, struct ast_bridge_channel *bridge_channel, struct confbridge_user *user)
static int action_toggle_binaural(struct confbridge_conference *conference, struct confbridge_user *user, struct ast_bridge_channel *bridge_channel)
static int async_delete_name_rec_task(void *data)
Delete user's name file asynchronously.
static int handle_conf_user_join(struct confbridge_user *user)
Call the proper join event handler for the user for the conference bridge's current state.
static void send_unmute_event(struct confbridge_user *user, struct confbridge_conference *conference)
static int action_confbridgestartrecord(struct mansession *s, const struct message *m)