64 #include "confbridge/include/confbridge.h"
69 #include "asterisk/stasis_bridges.h"
70 #include "asterisk/stasis_channels.h"
547 static const char app[] =
"ConfBridge";
548 static const char app2[] =
"ConfKick";
551 #define CONFERENCE_BRIDGE_BUCKETS 53
554 #define RECORD_FILENAME_INITIAL_SPACE 128
571 const char *
name = obj;
577 name = conference->
name;
596 const char *right_name = arg;
602 right_name = right->
name;
605 cmp = strcasecmp(left->
name, right_name);
608 cmp = strncasecmp(left->
name, right_name, strlen(right_name));
617 case CONF_SOUND_HAS_JOINED:
618 return S_OR(custom_sounds->hasjoin,
"conf-hasjoin");
619 case CONF_SOUND_HAS_LEFT:
620 return S_OR(custom_sounds->hasleft,
"conf-hasleft");
621 case CONF_SOUND_KICKED:
622 return S_OR(custom_sounds->kicked,
"conf-kicked");
623 case CONF_SOUND_MUTED:
624 return S_OR(custom_sounds->muted,
"conf-muted");
625 case CONF_SOUND_UNMUTED:
626 return S_OR(custom_sounds->unmuted,
"conf-unmuted");
627 case CONF_SOUND_BINAURAL_ON:
628 return S_OR(custom_sounds->binauralon,
"confbridge-binaural-on");
629 case CONF_SOUND_BINAURAL_OFF:
630 return S_OR(custom_sounds->binauraloff,
"confbridge-binaural-off");
631 case CONF_SOUND_ONLY_ONE:
632 return S_OR(custom_sounds->onlyone,
"conf-onlyone");
633 case CONF_SOUND_THERE_ARE:
634 return S_OR(custom_sounds->thereare,
"conf-thereare");
635 case CONF_SOUND_OTHER_IN_PARTY:
636 return S_OR(custom_sounds->otherinparty,
"conf-otherinparty");
637 case CONF_SOUND_PLACE_IN_CONF:
638 return S_OR(custom_sounds->placeintoconf,
"conf-placeintoconf");
639 case CONF_SOUND_WAIT_FOR_LEADER:
640 return S_OR(custom_sounds->waitforleader,
"conf-waitforleader");
641 case CONF_SOUND_LEADER_HAS_LEFT:
642 return S_OR(custom_sounds->leaderhasleft,
"conf-leaderhasleft");
643 case CONF_SOUND_GET_PIN:
644 return S_OR(custom_sounds->getpin,
"conf-getpin");
645 case CONF_SOUND_INVALID_PIN:
646 return S_OR(custom_sounds->invalidpin,
"conf-invalidpin");
647 case CONF_SOUND_ONLY_PERSON:
648 return S_OR(custom_sounds->onlyperson,
"conf-onlyperson");
649 case CONF_SOUND_LOCKED:
650 return S_OR(custom_sounds->locked,
"conf-locked");
651 case CONF_SOUND_LOCKED_NOW:
652 return S_OR(custom_sounds->lockednow,
"conf-lockednow");
653 case CONF_SOUND_UNLOCKED_NOW:
654 return S_OR(custom_sounds->unlockednow,
"conf-unlockednow");
655 case CONF_SOUND_ERROR_MENU:
656 return S_OR(custom_sounds->errormenu,
"conf-errormenu");
657 case CONF_SOUND_JOIN:
658 return S_OR(custom_sounds->join,
"confbridge-join");
659 case CONF_SOUND_LEAVE:
660 return S_OR(custom_sounds->leave,
"confbridge-leave");
661 case CONF_SOUND_PARTICIPANTS_MUTED:
662 return S_OR(custom_sounds->participantsmuted,
"conf-now-muted");
663 case CONF_SOUND_PARTICIPANTS_UNMUTED:
664 return S_OR(custom_sounds->participantsunmuted,
"conf-now-unmuted");
665 case CONF_SOUND_BEGIN:
666 return S_OR(custom_sounds->begin,
"confbridge-conf-begin");
680 "conference", conference->
name);
699 if (ast_test_flag(&conference->
b_profile, BRIDGE_OPT_ENABLE_EVENTS)) {
719 "conference", conference->
name);
731 if (!bridge_snapshot) {
749 send_conf_stasis(conference, NULL, confbridge_start_type(), NULL, 0);
754 send_conf_stasis(conference, NULL, confbridge_end_type(), NULL, 0);
762 "admin", ast_test_flag(&user->
u_profile, USER_OPT_ADMIN),
763 "muted", user->
muted);
767 send_conf_stasis(conference, user->
chan, confbridge_join_type(), json_object, 0);
776 "admin", ast_test_flag(&user->
u_profile, USER_OPT_ADMIN)
781 send_conf_stasis(conference, user->
chan, confbridge_leave_type(), json_object, 0);
787 send_conf_stasis(conference, NULL, confbridge_start_record_type(), NULL, 0);
792 send_conf_stasis(conference, NULL, confbridge_stop_record_type(), NULL, 0);
800 "admin", ast_test_flag(&user->
u_profile, USER_OPT_ADMIN)
805 send_conf_stasis(conference, user->
chan, confbridge_mute_type(), json_object, 1);
814 "admin", ast_test_flag(&user->
u_profile, USER_OPT_ADMIN)
819 send_conf_stasis(conference, user->
chan, confbridge_unmute_type(), json_object, 1);
825 char *rec_file = conference->
b_profile.rec_file;
830 && ast_test_flag(&conference->
b_profile, BRIDGE_OPT_RECORD_FILE_APPEND)
838 if (ast_strlen_zero(rec_file)) {
841 }
else if (ast_test_flag(&conference->
b_profile, BRIDGE_OPT_RECORD_FILE_TIMESTAMP)) {
843 ext = strrchr(rec_file,
'.');
848 ast_str_set(filename, 0,
"%s-%u", rec_file, (
unsigned int) now);
854 ast_test_flag(&conference->
b_profile, BRIDGE_OPT_RECORD_FILE_APPEND) ?
"a" :
"",
859 static int is_new_rec_file(
const char *rec_file,
struct ast_str **orig_rec_file)
861 if (!ast_strlen_zero(rec_file)) {
862 if (!*orig_rec_file) {
877 return ao2_find(conference_bridges, conference_name,
OBJ_KEY);
912 if (!conf_is_recording(conference)) {
923 send_stop_record_event(conference);
946 if (conf_is_recording(conference)) {
952 ast_log(LOG_WARNING,
"Cannot record ConfBridge, MixMonitor app is not installed\n");
995 send_start_record_event(conference);
1019 const char *filename)
1022 const char *stop_digits;
1025 if (bridge_channel) {
1026 chan = bridge_channel->
chan;
1027 stop_digits = AST_DIGIT_ANY;
1035 ast_log(LOG_WARNING,
"Failed to playback file '%s' to channel\n", filename);
1056 static int sound_file_exists(
const char *filename)
1061 ast_log(LOG_WARNING,
"File %s does not exist in any format\n", filename);
1106 if (
play_file(bridge_channel, user->
chan, other_in_party) < 0) {
1109 }
else if (sound_file_exists(there_are) && sound_file_exists(other_in_party)) {
1143 if (ast_test_flag(&conference->
b_profile, BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED)) {
1147 ao2_lock(conference);
1150 if (user->
chan == chan) {
1158 ao2_unlock(conference);
1162 }
else if (ast_test_flag(&conference->
b_profile, BRIDGE_OPT_VIDEO_SRC_LAST_MARKED)) {
1182 if (ast_test_flag(&conference->
b_profile, BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER)) {
1187 if (!ast_test_flag(&conference->
b_profile, BRIDGE_OPT_VIDEO_SRC_FIRST_MARKED) &&
1188 !ast_test_flag(&conference->
b_profile, BRIDGE_OPT_VIDEO_SRC_LAST_MARKED)) {
1193 ao2_lock(conference);
1195 if (user->
chan == chan) {
1198 if (ast_test_flag(&user->
u_profile, USER_OPT_MARKEDUSER)) {
1203 ao2_unlock(conference);
1236 ast_mutex_lock(&hangup->lock);
1238 ast_cond_signal(&hangup->cond);
1239 ast_mutex_unlock(&hangup->lock);
1246 ast_mutex_init(&hangup->lock);
1247 ast_cond_init(&hangup->cond, NULL);
1249 hangup->conference = conference;
1253 static void hangup_data_destroy(
struct hangup_data *hangup)
1255 ast_mutex_destroy(&hangup->lock);
1256 ast_cond_destroy(&hangup->cond);
1268 ast_debug(1,
"Destroying conference bridge '%s'\n", conference->
name);
1273 hangup_data_init(&hangup, conference);
1276 ast_mutex_lock(&hangup.lock);
1277 while (!hangup.hungup) {
1278 ast_cond_wait(&hangup.cond, &hangup.lock);
1280 ast_mutex_unlock(&hangup.lock);
1283 hangup_data_destroy(&hangup);
1292 if (conference->
bridge) {
1294 conference->
bridge = NULL;
1313 conference_event_fn handler;
1314 if (ast_test_flag(&user->
u_profile, USER_OPT_MARKEDUSER)) {
1316 }
else if (ast_test_flag(&user->
u_profile, USER_OPT_WAITMARKED)) {
1322 ast_assert(handler != NULL);
1342 conference_event_fn handler;
1343 if (ast_test_flag(&user->
u_profile, USER_OPT_MARKEDUSER)) {
1345 }
else if (ast_test_flag(&user->
u_profile, USER_OPT_WAITMARKED)) {
1351 ast_assert(handler != NULL);
1373 mute_user = user->
muted;
1382 && ast_test_flag(&user->
u_profile, USER_OPT_WAITMARKED));
1384 mute_effective = mute_user || mute_system;
1386 ast_debug(1,
"User %s is %s: user:%d system:%d.\n",
1387 ast_channel_name(user->
chan), mute_effective ?
"muted" :
"unmuted",
1388 mute_user, mute_system);
1392 "Conference: %s\r\n"
1394 mute_effective ?
"muted" :
"unmuted",
1396 ast_channel_name(user->
chan));
1406 user->
muted = mute ? 1 : 0;
1410 "Message: participant %s %s\r\n"
1411 "Conference: %s\r\n"
1413 ast_channel_name(user->
chan),
1414 mute ?
"muted" :
"unmuted",
1416 ast_channel_name(user->
chan));
1418 send_mute_event(user, conference);
1420 send_unmute_event(user, conference);
1522 if (!ast_test_flag(&user->
u_profile, USER_OPT_QUIET | USER_OPT_NOONLYPERSON)) {
1535 if (!(action =
ast_calloc(1,
sizeof(*action)))) {
1538 action->func = func;
1554 if (ast_test_flag(&first_user->
u_profile, USER_OPT_MUSICONHOLD)) {
1566 send_conf_end_event(conference);
1567 if (!ast_strlen_zero(conference->
b_profile.regcontext) &&
1568 pbx_find_extension(NULL, NULL, &q, conference->
b_profile.regcontext,
1569 conference->
name, 1, NULL,
"", E_MATCH)) {
1571 conference->
name, 1, NULL);
1573 ao2_lock(conference);
1574 conf_stop_record(conference);
1575 ao2_unlock(conference);
1594 conference->
name, NULL);
1605 ast_debug(1,
"Created announcer channel '%s' to conference bridge '%s'\n",
1609 "Confbridge/%s", conference->
name);
1638 static void confbridge_unlock_and_unref(
void *obj)
1645 ao2_unlock(conference);
1653 char *confbr_name = NULL;
1665 new_snapshot = msg->
target;
1673 ast_log(LOG_ERROR,
"Could not determine proper channels\n");
1688 ast_log(LOG_ERROR,
"Channel '%s' didn't have app data set\n", old_snapshot->
base->
name);
1692 comma = strchr(confbr_name,
',');
1699 conference = ao2_find(conference_bridges, confbr_name,
OBJ_SEARCH_KEY);
1701 ast_log(LOG_ERROR,
"Conference bridge '%s' not found\n", confbr_name);
1704 ao2_lock(conference);
1711 if (strcasecmp(ast_channel_name(user->
chan), old_snapshot->
base->
name) == 0) {
1722 if (strcasecmp(ast_channel_name(user->
chan), old_snapshot->
base->
name) == 0) {
1730 ast_log(LOG_ERROR,
"Unable to find user profile for channel '%s' in bridge '%s'\n",
1731 old_snapshot->
base->
name, confbr_name);
1739 "admin", ast_test_flag(&user->
u_profile, USER_OPT_ADMIN)
1745 send_conf_stasis_snapshots(conference, old_snapshot, confbridge_leave_type(), json_object);
1749 "admin", ast_test_flag(&user->
u_profile, USER_OPT_ADMIN),
1750 "muted", user->
muted);
1754 send_conf_stasis_snapshots(conference, new_snapshot, confbridge_join_type(), json_object);
1770 int max_members_reached = 0;
1773 ao2_lock(conference_bridges);
1775 ast_debug(1,
"Trying to find conference bridge '%s'\n", conference_name);
1778 conference = ao2_find(conference_bridges, conference_name,
OBJ_KEY);
1784 if (conference && (max_members_reached || conference->
locked) && !ast_test_flag(&user->
u_profile, USER_OPT_ADMIN)) {
1785 ao2_unlock(conference_bridges);
1786 ast_debug(1,
"Conference '%s' is locked and caller is not an admin\n", conference_name);
1798 ao2_unlock(conference_bridges);
1799 ast_log(LOG_ERROR,
"Conference '%s' could not be created.\n", conference_name);
1807 ao2_unlock(conference_bridges);
1818 app, conference_name, NULL);
1819 if (!conference->
bridge) {
1821 ao2_unlock(conference_bridges);
1822 ast_log(LOG_ERROR,
"Conference '%s' mixing bridge could not be created.\n", conference_name);
1834 if (ast_test_flag(&conference->
b_profile, BRIDGE_OPT_VIDEO_SRC_FOLLOW_TALKER)) {
1836 }
else if (ast_test_flag(&conference->
b_profile, BRIDGE_OPT_VIDEO_SRC_SFU)) {
1839 if (ast_test_flag(&conference->
b_profile, BRIDGE_OPT_REMB_BEHAVIOR_AVERAGE)) {
1841 }
else if (ast_test_flag(&conference->
b_profile, BRIDGE_OPT_REMB_BEHAVIOR_LOWEST)) {
1843 }
else if (ast_test_flag(&conference->
b_profile, BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST)) {
1845 }
else if (ast_test_flag(&conference->
b_profile, BRIDGE_OPT_REMB_BEHAVIOR_AVERAGE_ALL)) {
1847 }
else if (ast_test_flag(&conference->
b_profile, BRIDGE_OPT_REMB_BEHAVIOR_LOWEST_ALL)) {
1849 }
else if (ast_test_flag(&conference->
b_profile, BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST_ALL)) {
1851 }
else if (ast_test_flag(&conference->
b_profile, BRIDGE_OPT_REMB_BEHAVIOR_FORCE)) {
1860 if (ast_test_flag(&conference->
b_profile, BRIDGE_OPT_ENABLE_EVENTS)) {
1865 if (!
ao2_link(conference_bridges, conference)) {
1867 ao2_unlock(conference_bridges);
1869 "Conference '%s' could not be added to the conferences list.\n", conference_name);
1876 if (alloc_playback_chan(conference)) {
1879 ao2_unlock(conference_bridges);
1880 ast_log(LOG_ERROR,
"Could not allocate announcer channel for conference '%s'\n", conference_name);
1887 ao2_unlock(conference_bridges);
1888 ast_log(LOG_ERROR,
"Could not add announcer channel for conference '%s' bridge\n", conference_name);
1892 if (ast_test_flag(&conference->
b_profile, BRIDGE_OPT_RECORD_CONFERENCE)) {
1893 ao2_lock(conference);
1894 conf_start_record(conference);
1895 ao2_unlock(conference);
1898 send_conf_start_event(conference);
1900 if (!ast_strlen_zero(conference->
b_profile.regcontext)) {
1906 ast_debug(1,
"Created conference '%s' and linked to container.\n", conference_name);
1909 ao2_unlock(conference_bridges);
1914 ao2_lock(conference);
1917 if (ast_test_flag(&user->
u_profile, USER_OPT_STARTMUTED)
1918 || (!ast_test_flag(&user->
u_profile, USER_OPT_ADMIN) && conference->
muted)) {
1932 ao2_unlock(conference);
1939 ao2_unlock(conference);
1944 ao2_unlock(conference);
1947 if (!ast_strlen_zero(user->
u_profile.announcement)) {
1956 if (ast_test_flag(&user->
u_profile, USER_OPT_ANNOUNCEUSERCOUNT)) {
1963 if (ast_test_flag(&user->
u_profile, USER_OPT_ANNOUNCEUSERCOUNTALL) &&
1974 if (user_count_res) {
2012 static void playback_common(
struct confbridge_conference *conference,
const char *filename,
int say_number)
2022 if (!ast_strlen_zero(filename)) {
2024 }
else if (say_number >= 0) {
2034 const char *filename;
2036 int playback_finished;
2058 playback_common(ptd->conference, ptd->filename, ptd->say_number);
2060 ast_mutex_lock(&ptd->lock);
2061 ptd->playback_finished = 1;
2062 ast_cond_signal(&ptd->cond);
2063 ast_mutex_unlock(&ptd->lock);
2069 const char *filename,
int say_number)
2071 ast_mutex_init(&ptd->lock);
2072 ast_cond_init(&ptd->cond, NULL);
2074 ptd->filename = filename;
2075 ptd->say_number = say_number;
2076 ptd->conference = conference;
2077 ptd->playback_finished = 0;
2082 ast_mutex_destroy(&ptd->lock);
2083 ast_cond_destroy(&ptd->cond);
2086 static int play_sound_helper(
struct confbridge_conference *conference,
const char *filename,
int say_number)
2091 if (ast_strlen_zero(filename)) {
2092 if (say_number < 0) {
2095 }
else if (!sound_file_exists(filename)) {
2099 playback_task_data_init(&ptd, conference, filename, say_number);
2101 if (!ast_strlen_zero(filename)) {
2102 ast_log(LOG_WARNING,
"Unable to play file '%s' to conference %s\n",
2103 filename, conference->
name);
2105 ast_log(LOG_WARNING,
"Unable to say number '%d' to conference %s\n",
2106 say_number, conference->
name);
2108 playback_task_data_destroy(&ptd);
2113 ast_mutex_lock(&ptd.lock);
2114 while (!ptd.playback_finished) {
2115 ast_cond_wait(&ptd.cond, &ptd.lock);
2117 ast_mutex_unlock(&ptd.lock);
2119 playback_task_data_destroy(&ptd);
2126 return play_sound_helper(conference, filename, -1);
2142 static void async_datastore_data_destroy(
void *data)
2146 ast_mutex_destroy(&add->lock);
2147 ast_cond_destroy(&add->cond);
2170 .
type =
"Confbridge async playback",
2171 .destroy = async_datastore_data_destroy,
2183 ast_mutex_init(&add->lock);
2184 ast_cond_init(&add->cond, NULL);
2206 if (async_datastore) {
2209 add = async_datastore->
data;
2215 async_datastore = ast_datastore_alloc(&async_datastore_info, NULL);
2216 if (!async_datastore) {
2220 async_datastore->
data = async_datastore_data_alloc();
2221 if (!async_datastore->
data) {
2236 aptd =
ast_malloc(
sizeof(*aptd) + strlen(filename) + 1);
2242 strcpy(aptd->filename, filename);
2243 aptd->say_number = say_number;
2259 aptd->conference = conference;
2261 aptd->initiator = initiator;
2264 ast_channel_lock(aptd->initiator);
2270 ast_channel_unlock(aptd->initiator);
2295 ast_channel_lock(initiator);
2297 ast_channel_unlock(initiator);
2299 if (!async_datastore) {
2303 add = async_datastore->
data;
2305 ast_mutex_lock(&add->lock);
2307 ast_cond_wait(&add->cond, &add->lock);
2309 ast_mutex_unlock(&add->lock);
2327 if (aptd->initiator) {
2331 playback_common(aptd->conference, aptd->filename, aptd->say_number);
2333 async_playback_task_data_destroy(aptd);
2338 const char *filename,
int say_number,
struct ast_channel *initiator)
2343 if (ast_strlen_zero(filename)) {
2344 if (say_number < 0) {
2347 }
else if (!sound_file_exists(filename)) {
2351 aptd = async_playback_task_data_alloc(conference, filename, say_number, initiator);
2357 if (!ast_strlen_zero(filename)) {
2358 ast_log(LOG_WARNING,
"Unable to play file '%s' to conference '%s'\n",
2359 filename, conference->
name);
2361 ast_log(LOG_WARNING,
"Unable to say number '%d' to conference '%s'\n",
2362 say_number, conference->
name);
2364 async_playback_task_data_destroy(aptd);
2372 const char *filename,
struct ast_channel *initiator)
2374 return async_play_sound_helper(conference, filename, -1, initiator);
2382 ast_channel_lock(chan);
2384 ast_channel_unlock(chan);
2385 if (!async_datastore) {
2389 add = async_datastore->
data;
2391 ast_mutex_lock(&add->lock);
2393 ast_cond_signal(&add->cond);
2394 ast_mutex_unlock(&add->lock);
2408 return play_sound_helper(conference, NULL, say_number);
2411 static int conf_handle_talker_cb(
struct ast_bridge_channel *bridge_channel,
void *hook_pvt,
int talking)
2423 ao2_lock(conference);
2425 ao2_unlock(conference);
2428 "talking_status", talking ?
"on" :
"off",
2429 "admin", ast_test_flag(&user->
u_profile, USER_OPT_ADMIN));
2430 if (!talking_extras) {
2434 send_conf_stasis(conference, bridge_channel->
chan, confbridge_talking_type(), talking_extras, 0);
2441 char pin_guess[MAX_PIN+1] = { 0, };
2443 char *tmp = pin_guess;
2445 unsigned int len = MAX_PIN;
2453 for (i = 0; i < 3; i++) {
2456 tmp, len, 0) >= 0) {
2457 if (!strcasecmp(pin, pin_guess)) {
2463 ast_channel_language(chan));
2469 pin_guess[1] =
'\0';
2470 tmp = pin_guess + 1;
2488 static int conf_rec_name(
struct confbridge_user *user,
const char *conf_name)
2490 char destdir[PATH_MAX];
2494 snprintf(destdir,
sizeof(destdir),
"%s/confbridge", ast_config_AST_SPOOL_DIR);
2497 ast_log(LOG_WARNING,
"mkdir '%s' failed: %s\n", destdir, strerror(errno));
2501 "%s/confbridge-name-%s-%s", destdir,
2502 conf_name, ast_channel_uniqueid(user->
chan));
2504 if (!(ast_test_flag(&user->
u_profile, USER_OPT_ANNOUNCE_JOIN_LEAVE_REVIEW))) {
2543 atd =
ast_malloc(
sizeof(*atd) + strlen(filename) + 1);
2549 strcpy(atd->filename, filename);
2550 atd->conference = conference;
2574 ast_log(LOG_DEBUG,
"Conference '%s' removed user name file '%s'\n",
2575 atd->conference->
name, atd->filename);
2577 async_delete_name_rec_task_data_destroy(atd);
2582 const char *filename)
2586 if (ast_strlen_zero(filename)) {
2588 }
else if (!sound_file_exists(filename)) {
2592 atd = async_delete_name_rec_task_data_alloc(conference, filename);
2598 ast_log(LOG_WARNING,
"Conference '%s' was unable to remove user name file '%s'\n",
2599 conference->
name, filename);
2600 async_delete_name_rec_task_data_destroy(atd);
2619 static int send_event_hook_callback(
struct ast_bridge_channel *bridge_channel,
void *data)
2623 if (hook_data->hook_type == AST_BRIDGE_HOOK_TYPE_JOIN) {
2624 send_join_event(hook_data->user, hook_data->conference);
2626 send_leave_event(hook_data->user, hook_data->conference);
2635 int res = 0, volume_adjustments[2];
2637 int async_delete_task_pushed = 0;
2639 const char *b_profile_name = NULL;
2640 const char *u_profile_name = NULL;
2641 const char *menu_profile_name = NULL;
2645 .tech_args.talking_threshold = DEFAULT_TALKING_THRESHOLD,
2647 .tech_args.drop_silence = 0,
2662 goto confbridge_cleanup;
2670 if (ast_strlen_zero(args.conf_name)) {
2672 ast_log(LOG_WARNING,
"%s requires an argument (conference name[,options])\n",
app);
2674 goto confbridge_cleanup;
2677 if (strlen(args.conf_name) >= MAX_CONF_NAME) {
2679 ast_log(LOG_WARNING,
"%s does not accept conference names longer than %d\n",
app, MAX_CONF_NAME - 1);
2681 goto confbridge_cleanup;
2685 if (args.argc > 1 && !ast_strlen_zero(args.b_profile_name)) {
2686 b_profile_name = args.b_profile_name;
2690 ast_log(LOG_WARNING,
"Conference bridge profile %s does not exist\n", b_profile_name ?
2691 b_profile_name : DEFAULT_BRIDGE_PROFILE);
2693 goto confbridge_cleanup;
2697 if (args.argc > 2 && !ast_strlen_zero(args.u_profile_name)) {
2698 u_profile_name = args.u_profile_name;
2702 ast_log(LOG_WARNING,
"Conference user profile %s does not exist\n", u_profile_name ?
2703 u_profile_name : DEFAULT_USER_PROFILE);
2705 goto confbridge_cleanup;
2713 quiet = ast_test_flag(&user.
u_profile, USER_OPT_QUIET);
2717 if (!ast_strlen_zero(user.
u_profile.pin)) {
2718 if (conf_get_pin(chan, &user)) {
2721 goto confbridge_cleanup;
2727 (ast_test_flag(&user.
u_profile, USER_OPT_ANNOUNCE_JOIN_LEAVE) ||
2728 (ast_test_flag(&user.
u_profile, USER_OPT_ANNOUNCE_JOIN_LEAVE_REVIEW)))) {
2729 if (conf_rec_name(&user, args.conf_name)) {
2732 goto confbridge_cleanup;
2737 if (args.argc > 3 && !ast_strlen_zero(args.menu_profile_name)) {
2738 menu_profile_name = args.menu_profile_name;
2743 ast_log(LOG_WARNING,
"Conference menu profile %s does not exist\n", menu_profile_name ?
2744 menu_profile_name : DEFAULT_MENU_PROFILE);
2746 goto confbridge_cleanup;
2750 if (ast_test_flag(&user.
u_profile, USER_OPT_DTMF_PASS)) {
2757 if (ast_test_flag(&user.
u_profile, USER_OPT_TEXT_MESSAGING)) {
2772 if (ast_test_flag(&user.
u_profile, USER_OPT_TALKER_DETECT)) {
2777 goto confbridge_cleanup;
2785 goto confbridge_cleanup;
2792 if (ast_test_flag(&user.
u_profile, USER_OPT_DROP_SILENCE)) {
2796 if (ast_test_flag(&user.
u_profile, USER_OPT_JITTERBUFFER)) {
2800 if (ast_test_flag(&user.
u_profile, USER_OPT_DENOISE)) {
2817 if (ast_test_flag(&user.
u_profile, USER_OPT_HEAR_OWN_JOIN_SOUND) ) {
2845 handle_video_on_join(conference, user.
chan, ast_test_flag(&user.
u_profile, USER_OPT_MARKEDUSER));
2847 conf_moh_unsuspend(&user);
2849 join_hook_data =
ast_malloc(
sizeof(*join_hook_data));
2850 if (!join_hook_data) {
2852 goto confbridge_cleanup;
2854 join_hook_data->user = &user;
2855 join_hook_data->conference = conference;
2856 join_hook_data->hook_type = AST_BRIDGE_HOOK_TYPE_JOIN;
2860 ast_free(join_hook_data);
2861 ast_log(LOG_ERROR,
"Couldn't add bridge join hook for channel '%s'\n", ast_channel_name(chan));
2862 goto confbridge_cleanup;
2865 leave_hook_data =
ast_malloc(
sizeof(*leave_hook_data));
2866 if (!leave_hook_data) {
2869 goto confbridge_cleanup;
2871 leave_hook_data->user = &user;
2872 leave_hook_data->conference = conference;
2873 leave_hook_data->hook_type = AST_BRIDGE_HOOK_TYPE_LEAVE;
2878 ast_free(leave_hook_data);
2879 ast_log(LOG_ERROR,
"Couldn't add bridge leave hook for channel '%s'\n", ast_channel_name(chan));
2880 goto confbridge_cleanup;
2913 goto confbridge_cleanup;
2917 handle_video_on_exit(conference, user.
chan);
2925 async_delete_task_pushed = 1;
2935 if (!quiet && user.
kicked) {
2946 if (volume_adjustments[0]) {
2949 if (volume_adjustments[1]) {
2969 mute = !user->
muted;
2970 generic_mute_unmute_user(conference, user, mute);
2981 unsigned int binaural;
2986 return play_file(bridge_channel, NULL, (binaural ?
2994 const char *sound_to_play;
2997 ao2_lock(conference);
3000 mute = !conference->
muted;
3001 conference->
muted = mute;
3004 if (!ast_test_flag(&cur_user->
u_profile, USER_OPT_ADMIN)) {
3006 cur_user->
muted = mute;
3011 ao2_unlock(conference);
3014 mute ? CONF_SOUND_PARTICIPANTS_MUTED : CONF_SOUND_PARTICIPANTS_UNMUTED,
3033 static int action_playback(
struct ast_bridge_channel *bridge_channel,
const char *playback_file)
3040 ast_log(LOG_WARNING,
"Failed to playback file %s to channel\n", file);
3051 const char *playback_file,
3052 const char *cur_dtmf,
3064 ast_log(LOG_WARNING,
"Failed to playback file %s to channel\n", file);
3072 }
else if (digit == -1) {
3094 dtmf[i] = cur_dtmf[i];
3096 dtmf[i] = (char) digit;
3109 execute_menu_entry(conference,
3112 &new_menu_entry, menu);
3123 int isadmin = ast_test_flag(&user->
u_profile, USER_OPT_ADMIN);
3128 ast_log(LOG_WARNING,
"Only admin users can use the kick_last menu action. Channel %s of conf %s is not an admin.\n",
3129 ast_channel_name(bridge_channel->
chan),
3134 ao2_lock(conference);
3137 ao2_unlock(conference);
3141 if (last_user == user || ast_test_flag(&last_user->
u_profile, USER_OPT_ADMIN)) {
3142 ao2_unlock(conference);
3145 }
else if (!last_user->
kicked) {
3149 ao2_unlock(conference);
3164 memset(&args, 0,
sizeof(args));
3165 args.no_hangup_chan = 1;
3167 ast_channel_lock(bridge_channel->
chan);
3172 priority = ast_channel_priority(bridge_channel->
chan);
3173 pbx = ast_channel_pbx(bridge_channel->
chan);
3174 ast_channel_pbx_set(bridge_channel->
chan, NULL);
3177 ast_channel_exten_set(bridge_channel->
chan, menu_action->data.dialplan_args.exten);
3178 ast_channel_context_set(bridge_channel->
chan, menu_action->data.dialplan_args.context);
3179 ast_channel_priority_set(bridge_channel->
chan, menu_action->data.dialplan_args.priority);
3181 ast_channel_unlock(bridge_channel->
chan);
3187 ast_channel_lock(bridge_channel->
chan);
3189 ast_channel_exten_set(bridge_channel->
chan, exten);
3190 ast_channel_context_set(bridge_channel->
chan, context);
3191 ast_channel_priority_set(bridge_channel->
chan, priority);
3192 ast_channel_pbx_set(bridge_channel->
chan, pbx);
3194 ast_channel_unlock(bridge_channel->
chan);
3206 int isadmin = ast_test_flag(&user->
u_profile, USER_OPT_ADMIN);
3207 int stop_prompts = 0;
3211 switch (menu_action->id) {
3212 case MENU_ACTION_TOGGLE_MUTE:
3213 res |= action_toggle_mute(conference, user, bridge_channel);
3215 case MENU_ACTION_TOGGLE_BINAURAL:
3216 action_toggle_binaural(conference, user, bridge_channel);
3218 case MENU_ACTION_ADMIN_TOGGLE_MUTE_PARTICIPANTS:
3222 action_toggle_mute_participants(conference, user);
3224 case MENU_ACTION_PARTICIPANT_COUNT:
3227 case MENU_ACTION_PLAYBACK:
3228 if (!stop_prompts) {
3229 res |= action_playback(bridge_channel, menu_action->data.playback_file);
3231 "Message: %s\r\nChannel: %s",
3232 menu_action->data.playback_file, ast_channel_name(bridge_channel->
chan));
3235 case MENU_ACTION_RESET_LISTENING:
3238 case MENU_ACTION_RESET_TALKING:
3241 case MENU_ACTION_INCREASE_LISTENING:
3245 case MENU_ACTION_DECREASE_LISTENING:
3249 case MENU_ACTION_INCREASE_TALKING:
3253 case MENU_ACTION_DECREASE_TALKING:
3257 case MENU_ACTION_PLAYBACK_AND_CONTINUE:
3258 if (!(stop_prompts)) {
3259 res |= action_playback_and_continue(conference,
3263 menu_action->data.playback_file,
3268 case MENU_ACTION_DIALPLAN_EXEC:
3269 res |= action_dialplan_exec(bridge_channel, menu_action);
3271 case MENU_ACTION_ADMIN_TOGGLE_LOCK:
3278 conference->
locked ? CONF_SOUND_LOCKED_NOW : CONF_SOUND_UNLOCKED_NOW,
3281 case MENU_ACTION_ADMIN_KICK_LAST:
3282 res |= action_kick_last(conference, bridge_channel, user);
3284 case MENU_ACTION_LEAVE:
3286 ao2_lock(conference);
3290 ast_channel_name(bridge_channel->
chan));
3291 ao2_unlock(conference);
3293 case MENU_ACTION_NOOP:
3295 case MENU_ACTION_SET_SINGLE_VIDEO_SRC:
3296 ao2_lock(conference);
3297 if (!ast_test_flag(&conference->
b_profile, BRIDGE_OPT_VIDEO_SRC_SFU)) {
3300 ao2_unlock(conference);
3302 case MENU_ACTION_RELEASE_SINGLE_VIDEO_SRC:
3303 handle_video_on_exit(conference, bridge_channel->
chan);
3316 conf_moh_suspend(user);
3319 execute_menu_entry(user->
conference, user, bridge_channel, menu_entry, menu);
3322 conf_moh_unsuspend(user);
3330 const char *channel)
3335 int all = !strcasecmp(
"all", channel);
3336 int participants = !strcasecmp(
"participants", channel);
3344 match = !strcasecmp(channel, ast_channel_name(user->
chan));
3346 || (participants && !ast_test_flag(&user->
u_profile, USER_OPT_ADMIN))) {
3360 match = !strcasecmp(channel, ast_channel_name(user->
chan));
3362 || (participants && !ast_test_flag(&user->
u_profile, USER_OPT_ADMIN))) {
3376 static char *complete_confbridge_name(
const char *line,
const char *word,
int pos,
int state)
3381 int wordlen = strlen(word);
3385 while ((conference = ao2_iterator_next(&iter))) {
3386 if (!strncasecmp(conference->
name, word, wordlen) && ++which > state) {
3398 static char *complete_confbridge_participant(
const char *conference_name,
const char *line,
const char *word,
int pos,
int state)
3404 int wordlen = strlen(word);
3406 conference = ao2_find(conference_bridges, conference_name,
OBJ_KEY);
3411 if (!strncasecmp(
"all", word, wordlen) && ++which > state) {
3415 if (!strncasecmp(
"participants", word, wordlen) && ++which > state) {
3422 if (!strncasecmp(ast_channel_name(user->
chan), word, wordlen) && ++which > state) {
3428 if (!strncasecmp(ast_channel_name(user->
chan), word, wordlen) && ++which > state) {
3445 e->
command =
"confbridge kick";
3447 "Usage: confbridge kick <conference> <channel>\n"
3448 " Kicks a channel out of the conference bridge.\n"
3449 " (all to kick everyone, participants to kick non-admins).\n";
3453 return complete_confbridge_name(a->line, a->word, a->pos, a->n);
3456 return complete_confbridge_participant(a->argv[2], a->line, a->word, a->pos, a->n);
3462 return CLI_SHOWUSAGE;
3465 conference = ao2_find(conference_bridges, a->argv[2],
OBJ_KEY);
3467 ast_cli(a->fd,
"No conference bridge named '%s' found!\n", a->argv[2]);
3470 not_found = kick_conference_participant(conference, a->argv[3]);
3473 if (!strcasecmp(
"all", a->argv[3]) || !strcasecmp(
"participants", a->argv[3])) {
3474 ast_cli(a->fd,
"No participants found!\n");
3476 ast_cli(a->fd,
"No participant named '%s' found!\n", a->argv[3]);
3480 ast_cli(a->fd,
"Kicked '%s' out of conference '%s'\n", a->argv[3], a->argv[2]);
3486 char flag_str[6 + 1];
3490 if (ast_test_flag(&user->
u_profile, USER_OPT_ADMIN)) {
3491 flag_str[pos++] =
'A';
3493 if (ast_test_flag(&user->
u_profile, USER_OPT_MARKEDUSER)) {
3494 flag_str[pos++] =
'M';
3496 if (ast_test_flag(&user->
u_profile, USER_OPT_WAITMARKED)) {
3497 flag_str[pos++] =
'W';
3499 if (ast_test_flag(&user->
u_profile, USER_OPT_ENDMARKED)) {
3500 flag_str[pos++] =
'E';
3503 flag_str[pos++] =
'm';
3506 flag_str[pos++] =
'w';
3508 flag_str[pos] =
'\0';
3510 ast_cli(a->fd,
"%-30s %-6s %-16s %-16s %-16s %s\n",
3511 ast_channel_name(user->
chan),
3526 e->
command =
"confbridge list";
3528 "Usage: confbridge list [<name>]\n"
3529 " Lists all currently active conference bridges or a specific conference bridge.\n"
3531 " When a conference bridge name is provided, flags may be shown for users. Below\n"
3532 " are the flags and what they represent.\n"
3535 " A - The user is an admin\n"
3536 " M - The user is a marked user\n"
3537 " W - The user must wait for a marked user to join\n"
3538 " E - The user will be kicked after the last marked user leaves the conference\n"
3539 " m - The user is muted\n"
3540 " w - The user is waiting for a marked user to join\n";
3544 return complete_confbridge_name(a->line, a->word, a->pos, a->n);
3552 ast_cli(a->fd,
"Conference Bridge Name Users Marked Locked Muted\n");
3553 ast_cli(a->fd,
"================================ ====== ====== ====== =====\n");
3555 while ((conference = ao2_iterator_next(&iter))) {
3556 ast_cli(a->fd,
"%-32s %6u %6u %-6s %s\n",
3571 conference = ao2_find(conference_bridges, a->argv[2],
OBJ_KEY);
3573 ast_cli(a->fd,
"No conference bridge named '%s' found!\n", a->argv[2]);
3576 ast_cli(a->fd,
"Channel Flags User Profile Bridge Profile Menu CallerID\n");
3577 ast_cli(a->fd,
"============================== ====== ================ ================ ================ ================\n");
3578 ao2_lock(conference);
3580 handle_cli_confbridge_list_item(a, user, 0);
3583 handle_cli_confbridge_list_item(a, user, 1);
3585 ao2_unlock(conference);
3590 return CLI_SHOWUSAGE;
3599 static int generic_lock_unlock_helper(
int lock,
const char *conference_name)
3604 conference = ao2_find(conference_bridges, conference_name,
OBJ_KEY);
3608 ao2_lock(conference);
3611 ao2_unlock(conference);
3624 static int generic_mute_unmute_helper(
int mute,
const char *conference_name,
3625 const char *chan_name)
3629 int all = !strcasecmp(
"all", chan_name);
3630 int participants = !strcasecmp(
"participants", chan_name);
3633 conference = ao2_find(conference_bridges, conference_name,
OBJ_KEY);
3641 int match = !strncasecmp(chan_name, ast_channel_name(user->
chan),
3644 || (participants && !ast_test_flag(&user->
u_profile, USER_OPT_ADMIN))) {
3645 generic_mute_unmute_user(conference, user, mute);
3654 int match = !strncasecmp(chan_name, ast_channel_name(user->
chan),
3657 || (participants && !ast_test_flag(&user->
u_profile, USER_OPT_ADMIN))) {
3658 generic_mute_unmute_user(conference, user, mute);
3670 static int cli_mute_unmute_helper(
int mute,
struct ast_cli_args *a)
3672 int res = generic_mute_unmute_helper(mute, a->argv[2], a->argv[3]);
3675 ast_cli(a->fd,
"No conference bridge named '%s' found!\n", a->argv[2]);
3677 }
else if (res == -2) {
3678 if (!strcasecmp(
"all", a->argv[3]) || !strcasecmp(
"participants", a->argv[3])) {
3679 ast_cli(a->fd,
"No participants found in conference %s\n", a->argv[2]);
3681 ast_cli(a->fd,
"No channel named '%s' found in conference %s\n", a->argv[3], a->argv[2]);
3685 ast_cli(a->fd,
"%s %s from confbridge %s\n", mute ?
"Muting" :
"Unmuting", a->argv[3], a->argv[2]);
3693 e->
command =
"confbridge mute";
3695 "Usage: confbridge mute <conference> <channel>\n"
3696 " Mute a channel in a conference.\n"
3697 " (all to mute everyone, participants to mute non-admins)\n"
3698 " If the specified channel is a prefix,\n"
3699 " the action will be taken on the first\n"
3700 " matching channel.\n";
3704 return complete_confbridge_name(a->line, a->word, a->pos, a->n);
3707 return complete_confbridge_participant(a->argv[2], a->line, a->word, a->pos, a->n);
3712 return CLI_SHOWUSAGE;
3715 cli_mute_unmute_helper(1, a);
3724 e->
command =
"confbridge unmute";
3726 "Usage: confbridge unmute <conference> <channel>\n"
3727 " Unmute a channel in a conference.\n"
3728 " (all to unmute everyone, participants to unmute non-admins)\n"
3729 " If the specified channel is a prefix,\n"
3730 " the action will be taken on the first\n"
3731 " matching channel.\n";
3735 return complete_confbridge_name(a->line, a->word, a->pos, a->n);
3738 return complete_confbridge_participant(a->argv[2], a->line, a->word, a->pos, a->n);
3743 return CLI_SHOWUSAGE;
3746 cli_mute_unmute_helper(0, a);
3755 e->
command =
"confbridge lock";
3757 "Usage: confbridge lock <conference>\n"
3758 " Lock a conference. While locked, no new non-admins\n"
3759 " may join the conference.\n";
3763 return complete_confbridge_name(a->line, a->word, a->pos, a->n);
3768 return CLI_SHOWUSAGE;
3770 if (generic_lock_unlock_helper(1, a->argv[2])) {
3771 ast_cli(a->fd,
"Conference %s is not found\n", a->argv[2]);
3773 ast_cli(a->fd,
"Conference %s is locked.\n", a->argv[2]);
3782 e->
command =
"confbridge unlock";
3784 "Usage: confbridge unlock <conference>\n"
3785 " Unlock a previously locked conference.\n";
3789 return complete_confbridge_name(a->line, a->word, a->pos, a->n);
3794 return CLI_SHOWUSAGE;
3796 if (generic_lock_unlock_helper(0, a->argv[2])) {
3797 ast_cli(a->fd,
"Conference %s is not found\n", a->argv[2]);
3799 ast_cli(a->fd,
"Conference %s is unlocked.\n", a->argv[2]);
3806 const char *rec_file = NULL;
3811 e->
command =
"confbridge record start";
3813 "Usage: confbridge record start <conference> <file>\n"
3814 " <file> is optional, Otherwise the bridge profile\n"
3815 " record file will be used. If the bridge profile\n"
3816 " has no record file specified, a file will automatically\n"
3817 " be generated in the monitor directory\n";
3821 return complete_confbridge_name(a->line, a->word, a->pos, a->n);
3826 return CLI_SHOWUSAGE;
3829 rec_file = a->argv[4];
3832 conference = ao2_find(conference_bridges, a->argv[3],
OBJ_KEY);
3834 ast_cli(a->fd,
"Conference not found.\n");
3837 ao2_lock(conference);
3838 if (conf_is_recording(conference)) {
3839 ast_cli(a->fd,
"Conference is already being recorded.\n");
3840 ao2_unlock(conference);
3844 if (!ast_strlen_zero(rec_file)) {
3848 if (conf_start_record(conference)) {
3849 ast_cli(a->fd,
"Could not start recording due to internal error.\n");
3850 ao2_unlock(conference);
3854 ao2_unlock(conference);
3856 ast_cli(a->fd,
"Recording started\n");
3868 e->
command =
"confbridge record stop";
3870 "Usage: confbridge record stop <conference>\n"
3871 " Stop a previously started recording.\n";
3875 return complete_confbridge_name(a->line, a->word, a->pos, a->n);
3880 return CLI_SHOWUSAGE;
3883 conference = ao2_find(conference_bridges, a->argv[3],
OBJ_KEY);
3885 ast_cli(a->fd,
"Conference not found.\n");
3888 ao2_lock(conference);
3889 ret = conf_stop_record(conference);
3890 ao2_unlock(conference);
3891 ast_cli(a->fd,
"Recording %sstopped.\n", ret ?
"could not be " :
"");
3897 AST_CLI_DEFINE(handle_cli_confbridge_list,
"List conference bridges and participants."),
3898 AST_CLI_DEFINE(handle_cli_confbridge_kick,
"Kick participants out of conference bridges."),
3899 AST_CLI_DEFINE(handle_cli_confbridge_mute,
"Mute participants."),
3900 AST_CLI_DEFINE(handle_cli_confbridge_unmute,
"Unmute participants."),
3901 AST_CLI_DEFINE(handle_cli_confbridge_lock,
"Lock a conference."),
3902 AST_CLI_DEFINE(handle_cli_confbridge_unlock,
"Unlock a conference."),
3903 AST_CLI_DEFINE(handle_cli_confbridge_start_record,
"Start recording a conference"),
3904 AST_CLI_DEFINE(handle_cli_confbridge_stop_record,
"Stop recording a conference."),
3907 .
name =
"CONFBRIDGE",
3908 .write = func_confbridge_helper,
3911 static int func_confbridge_info(
struct ast_channel *chan,
const char *cmd,
char *data,
char *buf,
size_t len);
3913 .
name =
"CONFBRIDGE_INFO",
3914 .read = func_confbridge_info,
3917 static int func_confbridge_channels(
struct ast_channel *chan,
const char *cmd,
char *data,
char *buf,
size_t len)
3919 char *parse, *outbuf;
3922 int bytes, count = 0;
3930 if (ast_strlen_zero(data)) {
3935 if (ast_strlen_zero(args.confno) || ast_strlen_zero(args.type)) {
3936 ast_log(LOG_WARNING,
"Usage: %s(category,confno)", cmd);
3939 conference = ao2_find(conference_bridges, args.confno,
OBJ_KEY);
3941 ast_debug(1,
"No such conference: %s\n", args.confno);
3948 ao2_lock(conference);
3949 if (!strcasecmp(args.type,
"parties")) {
3951 bytes = snprintf(outbuf, outlen,
"%s%s", count++ ?
"," :
"", ast_channel_name(user->
chan));
3956 bytes = snprintf(outbuf, outlen,
"%s%s", count++ ?
"," :
"", ast_channel_name(user->
chan));
3960 }
else if (!strcasecmp(args.type,
"active")) {
3962 bytes = snprintf(outbuf, outlen,
"%s%s", count++ ?
"," :
"", ast_channel_name(user->
chan));
3966 }
else if (!strcasecmp(args.type,
"waiting")) {
3968 bytes = snprintf(outbuf, outlen,
"%s%s", count++ ?
"," :
"", ast_channel_name(user->
chan));
3972 }
else if (!strcasecmp(args.type,
"admins")) {
3974 if (ast_test_flag(&user->
u_profile, USER_OPT_ADMIN)) {
3975 bytes = snprintf(outbuf, outlen,
"%s%s", count++ ?
"," :
"", ast_channel_name(user->
chan));
3980 }
else if (!strcasecmp(args.type,
"marked")) {
3982 if (ast_test_flag(&user->
u_profile, USER_OPT_MARKEDUSER)) {
3983 bytes = snprintf(outbuf, outlen,
"%s%s", count++ ?
"," :
"", ast_channel_name(user->
chan));
3989 ast_log(LOG_ERROR,
"Invalid keyword '%s' passed to %s.\n", args.type, cmd);
3991 ao2_unlock(conference);
3997 .
name =
"CONFBRIDGE_CHANNELS",
3998 .read = func_confbridge_channels,
4018 "Event: ConfbridgeList\r\n"
4020 "Conference: %s\r\n"
4022 "MarkedUser: %s\r\n"
4023 "WaitMarked: %s\r\n"
4025 "EndMarkedAny: %s\r\n"
4029 "AnsweredTime: %d\r\n"
4061 if (!ast_strlen_zero(actionid)) {
4062 snprintf(id_text,
sizeof(id_text),
"ActionID: %s\r\n", actionid);
4064 if (ast_strlen_zero(conference_name)) {
4072 conference = ao2_find(conference_bridges, conference_name,
OBJ_KEY);
4080 ao2_lock(conference);
4082 total += action_confbridgelist_item(s, id_text, conference, user, 0);
4085 total += action_confbridgelist_item(s, id_text, conference, user, 1);
4087 ao2_unlock(conference);
4096 static int action_confbridgelistrooms(
struct mansession *s,
const struct message *m)
4101 char id_text[512] =
"";
4104 if (!ast_strlen_zero(actionid)) {
4105 snprintf(id_text,
sizeof(id_text),
"ActionID: %s\r\n", actionid);
4117 while ((conference = ao2_iterator_next(&iter))) {
4120 ao2_lock(conference);
4122 "Event: ConfbridgeListRooms\r\n"
4124 "Conference: %s\r\n"
4136 ao2_unlock(conference);
4148 static int action_mute_unmute_helper(
struct mansession *s,
const struct message *m,
int mute)
4154 if (ast_strlen_zero(conference_name)) {
4158 if (ast_strlen_zero(channel_name)) {
4167 res = generic_mute_unmute_helper(mute, conference_name, channel_name);
4172 }
else if (res == -2) {
4181 static int action_confbridgeunmute(
struct mansession *s,
const struct message *m)
4183 return action_mute_unmute_helper(s, m, 0);
4187 return action_mute_unmute_helper(s, m, 1);
4190 static int action_lock_unlock_helper(
struct mansession *s,
const struct message *m,
int lock)
4195 if (ast_strlen_zero(conference_name)) {
4203 if ((res = generic_lock_unlock_helper(lock, conference_name))) {
4207 astman_send_ack(s, m, lock ?
"Conference locked" :
"Conference unlocked");
4210 static int action_confbridgeunlock(
struct mansession *s,
const struct message *m)
4212 return action_lock_unlock_helper(s, m, 0);
4216 return action_lock_unlock_helper(s, m, 1);
4226 if (ast_strlen_zero(conference_name)) {
4235 conference = ao2_find(conference_bridges, conference_name,
OBJ_KEY);
4241 found = !kick_conference_participant(conference, channel);
4245 astman_send_ack(s, m, !strcmp(
"all", channel) ?
"All participants kicked" :
"User kicked");
4252 static int action_confbridgestartrecord(
struct mansession *s,
const struct message *m)
4258 if (ast_strlen_zero(conference_name)) {
4267 conference = ao2_find(conference_bridges, conference_name,
OBJ_KEY);
4273 ao2_lock(conference);
4274 if (conf_is_recording(conference)) {
4276 ao2_unlock(conference);
4281 if (!ast_strlen_zero(recordfile)) {
4285 if (conf_start_record(conference)) {
4287 ao2_unlock(conference);
4291 ao2_unlock(conference);
4297 static int action_confbridgestoprecord(
struct mansession *s,
const struct message *m)
4302 if (ast_strlen_zero(conference_name)) {
4311 conference = ao2_find(conference_bridges, conference_name,
OBJ_KEY);
4317 ao2_lock(conference);
4318 if (conf_stop_record(conference)) {
4319 ao2_unlock(conference);
4324 ao2_unlock(conference);
4331 static int action_confbridgesetsinglevideosrc(
struct mansession *s,
const struct message *m)
4338 if (ast_strlen_zero(conference_name)) {
4342 if (ast_strlen_zero(channel)) {
4351 conference = ao2_find(conference_bridges, conference_name,
OBJ_KEY);
4358 ao2_lock(conference);
4360 if (!strncmp(channel, ast_channel_name(user->
chan), strlen(channel))) {
4365 ao2_unlock(conference);
4378 static int func_confbridge_info(
struct ast_channel *chan,
const char *cmd,
char *data,
char *buf,
size_t len)
4390 if (ast_strlen_zero(data)) {
4395 if (ast_strlen_zero(args.confno) || ast_strlen_zero(args.type)) {
4398 conference = ao2_find(conference_bridges, args.confno,
OBJ_KEY);
4400 snprintf(buf, len,
"0");
4405 ao2_lock(conference);
4406 if (!strcasecmp(args.type,
"parties")) {
4413 }
else if (!strcasecmp(args.type,
"admins")) {
4415 if (ast_test_flag(&user->
u_profile, USER_OPT_ADMIN)) {
4419 }
else if (!strcasecmp(args.type,
"marked")) {
4421 if (ast_test_flag(&user->
u_profile, USER_OPT_MARKEDUSER)) {
4425 }
else if (!strcasecmp(args.type,
"locked")) {
4426 count = conference->
locked;
4427 }
else if (!strcasecmp(args.type,
"muted")) {
4428 count = conference->
muted;
4430 ast_log(LOG_ERROR,
"Invalid keyword '%s' passed to CONFBRIDGE_INFO.\n", args.type);
4432 snprintf(buf, len,
"%d", count);
4433 ao2_unlock(conference);
4438 static int confkick_exec(
struct ast_channel *chan,
const char *data)
4449 if (ast_strlen_zero(data)) {
4450 ast_log(LOG_WARNING,
"No conference bridge specified.\n");
4458 conference = ao2_find(conference_bridges, args.confbridge,
OBJ_KEY);
4460 ast_log(LOG_WARNING,
"No conference bridge named '%s' found!\n", args.confbridge);
4464 if (ast_strlen_zero(args.channel)) {
4465 not_found = kick_conference_participant(conference,
"all");
4467 not_found = kick_conference_participant(conference, args.channel);
4472 if (ast_strlen_zero(args.channel) || !strcasecmp(
"all", args.channel) || !strcasecmp(
"participants", args.channel)) {
4473 ast_log(LOG_WARNING,
"No participants found in conference bridge '%s'!\n", args.confbridge);
4475 ast_log(LOG_WARNING,
"No participant named '%s' found in conference bridge '%s'!\n", args.channel, args.confbridge);
4480 ast_debug(1,
"Kicked '%s' out of conference '%s'\n", args.channel, args.confbridge);
4522 if (ast_test_flag(&only_user->
u_profile, USER_OPT_MUSICONHOLD)) {
4565 ast_log(LOG_ERROR,
"Unable to register channel technology %s(%s).\n",
4566 tech->type, tech->description);
4599 ao2_cleanup(conference_bridges);
4600 conference_bridges = NULL;
4625 ast_log(LOG_ERROR,
"Unable to load config. Not loading module.\n");
4639 if (!conference_bridges) {
4665 res |=
ast_manager_register_xml(
"ConfbridgeSetSingleVideoSrc", EVENT_FLAG_CALL, action_confbridgesetsinglevideosrc);
4674 static int reload(
void)
4679 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER,
"Conference Bridge Application",
4680 .support_level = AST_MODULE_SUPPORT_CORE,
4685 .optional_modules =
"codec_speex,func_jitterbuffer",
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.
int ast_audiohook_volume_set(struct ast_channel *chan, enum ast_audiohook_direction direction, int volume)
Adjust the volume on frames read from or written to a channel.
void ast_bridge_set_sfu_video_mode(struct ast_bridge *bridge)
Set the bridge to be a selective forwarding unit.
const ast_string_field data
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.
Options for ast_pbx_run()
Main Channel structure associated with a channel.
int ast_bridge_remove(struct ast_bridge *bridge, struct ast_channel *chan)
Remove a channel from a 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.
enum ast_getdata_result ast_app_getdata(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout)
Plays a stream and gets DTMF data from a channel.
void ast_bridge_features_cleanup(struct ast_bridge_features *features)
Clean up the contents of a bridge features structure.
conference_event_fn join_unmarked
int conf_add_post_join_action(struct confbridge_user *user, int(*func)(struct confbridge_user *user))
Queue a function to run with the given conference bridge user as an argument once the state transitio...
char * str
Subscriber phone number (Malloced)
void ast_bridge_set_mixing_interval(struct ast_bridge *bridge, unsigned int mixing_interval)
Adjust the internal mixing interval of a bridge used during multimix mode.
void ast_taskprocessor_build_name(char *buf, unsigned int size, const char *format,...)
Build a taskprocessor name with a sequence number on the end.
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
struct ast_channel_snapshot_base * base
Asterisk locking-related definitions:
void astman_append(struct mansession *s, const char *fmt,...)
Asterisk main include file. File version handling, generic pbx functions.
int ast_shutting_down(void)
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
void conf_remove_user_active(struct confbridge_conference *conference, struct confbridge_user *user)
Remove a conference bridge user from the unmarked active conference users in the conference.
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
int manager_confbridge_init(void)
register stasis message routers to handle manager events for confbridge messages
void ast_bridge_set_binaural_active(struct ast_bridge *bridge, unsigned int binaural_active)
Activates the use of binaural signals in a conference bridge.
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
struct ast_channel * chan
int ast_audiohook_volume_get(struct ast_channel *chan, enum ast_audiohook_direction direction)
Retrieve the volume adjustment value on frames read from or written to a channel. ...
int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data)
Execute an application.
void ast_bridge_set_maximum_sample_rate(struct ast_bridge *bridge, unsigned int sample_rate)
Adjust the maximum mixing sample rate of a bridge used during multimix mode.
Message representing attended transfer.
int ast_bridge_leave_hook(struct ast_bridge_features *features, ast_bridge_hook_callback callback, void *hook_pvt, ast_bridge_hook_pvt_destructor destructor, enum ast_bridge_hook_remove_flags remove_flags)
Attach a bridge channel leave hook to a bridge features structure.
Structure that contains features information.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
#define ast_channel_unref(c)
Decrease channel reference count.
struct confbridge_conference * conference
The arg parameter is a search key, but is not an object.
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 wait_for_initiator(struct ast_channel *initiator)
Wait for the initiator of an async playback to be ready.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
void ast_channel_unregister(const struct ast_channel_tech *tech)
Unregister a channel technology.
static int play_sound_number(struct confbridge_conference *conference, int say_number)
Play number into the conference bridge.
int ast_bridge_join_hook(struct ast_bridge_features *features, ast_bridge_hook_callback callback, void *hook_pvt, ast_bridge_hook_pvt_destructor destructor, enum ast_bridge_hook_remove_flags remove_flags)
Attach a bridge channel join hook to a bridge features structure.
static int playback_task(void *data)
Play an announcement into a confbridge.
unsigned int talking_threshold
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
int ast_json_object_update(struct ast_json *object, struct ast_json *other)
Update object with all of the fields of other.
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
descriptor for a cli entry.
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 const int DEFAULT_SILENCE_THRESHOLD
The default silence threshold we will use if an alternate configured value is not present or is inval...
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
int ast_bridge_unsuspend(struct ast_bridge *bridge, struct ast_channel *chan)
Unsuspend a channel from a bridge.
int ast_bridge_features_init(struct ast_bridge_features *features)
Initialize bridge features structure.
struct ast_taskprocessor * ast_taskprocessor_get(const char *name, enum ast_tps_options create)
Get a reference to a taskprocessor with the specified name and create the taskprocessor if necessary...
int ast_bridge_talk_detector_hook(struct ast_bridge_features *features, ast_bridge_talking_indicate_callback callback, void *hook_pvt, ast_bridge_hook_pvt_destructor destructor, enum ast_bridge_hook_remove_flags remove_flags)
Attach a bridge channel talk detection hook to a bridge features structure.
struct confbridge_user::@93 post_join_list
Structure that contains a snapshot of information about a bridge.
const struct user_profile * conf_find_user_profile(struct ast_channel *chan, const char *user_profile_name, struct user_profile *result)
find a user profile given a user profile's name and store that profile in result structure.
static int load_module(void)
Load the module.
static struct confbridge_conference * join_conference_bridge(const char *conference_name, struct confbridge_user *user)
Join a conference bridge.
Structure representing a snapshot of channel state.
struct stasis_message * ast_bridge_blob_create_from_snapshots(struct stasis_message_type *message_type, struct ast_bridge_snapshot *bridge_snapshot, struct ast_channel_snapshot *chan_snapshot, struct ast_json *blob)
Creates a ast_bridge_blob message from snapshots.
return a reference to a taskprocessor, create one if it does not exist
unsigned int suspended_moh
void ast_bridge_channel_feature_digit_add(struct ast_bridge_channel *bridge_channel, int digit)
Add a DTMF digit to the collected digits.
void conf_menu_entry_destroy(struct conf_menu_entry *menu_entry)
Destroys and frees all the actions stored in a menu_entry structure.
Structure for a data store type.
ast_channel_state
ast_channel states
struct ast_channel_snapshot * target
void conf_mute_only_active(struct confbridge_conference *conference)
Attempt to mute/play MOH to the only user in the conference if they require it.
int ast_bridge_destroy(struct ast_bridge *bridge, int cause)
Destroy a bridge.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
#define ast_cli_register_multiple(e, len)
Register multiple commands.
void conf_update_user_mute(struct confbridge_user *user)
Update the actual mute status of the user and set it on the bridge.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
int ast_channel_get_up_time(struct ast_channel *chan)
Obtain how long it has been since the channel was answered.
struct confbridge_state * CONF_STATE_EMPTY
Conference state with no active or waiting users.
unsigned int silence_threshold
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
unsigned int binaural_suspended
int ast_channel_register(const struct ast_channel_tech *tech)
Register a channel technology (a new channel driver) Called by a channel module to register the kind ...
#define ast_strdup(str)
A wrapper for strdup()
Structure for a data store object.
struct confbridge_user::@94 list
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
void confbridge_handle_atxfer(struct ast_attended_transfer_message *msg)
Create join/leave events for attended transfers.
conference_event_fn leave_unmarked
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.
struct ast_channel * record_chan
#define CONFERENCE_BRIDGE_BUCKETS
Out-of-call text message support.
int ast_filedelete(const char *filename, const char *fmt)
Deletes a file.
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
#define AST_TASKPROCESSOR_MAX_NAME
Suggested maximum taskprocessor name length (less null terminator).
struct ast_str * orig_rec_file
int ast_unregister_application(const char *app)
Unregister an application.
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
void ast_free_ptr(void *ptr)
free() wrapper
struct ast_channel_snapshot_dialplan * dialplan
struct ast_bridge_channel_snapshot_pair to_transferee
void ast_bridge_features_destroy(struct ast_bridge_features *features)
Destroy an allocated bridge features struct.
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
static int hangup_playback(void *data)
Hang up the announcer channel.
conference_event_fn join_marked
struct ast_bridge * bridge
Bridge this channel is participating in.
void async_play_sound_ready(struct ast_channel *chan)
Indicate the initiator of an async sound file is ready for it to play.
struct confbridge_conference::@90 active_list
struct ast_taskprocessor * playback_queue
int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
Simply remove extension from context.
void ast_bridge_set_remb_estimated_bitrate(struct ast_bridge *bridge, float estimated_bitrate)
Force the REMB report estimated bitrate to a specific max value.
unsigned int silence_threshold
struct bridge_profile b_profile
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
static void destroy_conference_bridge(void *obj)
Destroy a conference bridge.
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...
struct ast_channel_tech * conf_record_get_tech(void)
Get ConfBridge record channel technology struct.
struct ast_channel * ast_request(const char *type, struct ast_format_cap *request_cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int *cause)
Requests a channel.
void conf_handle_second_active(struct confbridge_conference *conference)
Handle when a conference moves to having more than one active participant.
unsigned int waitingusers
static int setup_async_playback_datastore(struct ast_channel *initiator)
Prepare the async playback datastore.
int ast_record_review(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, const char *path)
Allow to record message and have a review option.
void conf_bridge_profile_copy(struct bridge_profile *dst, struct bridge_profile *src)
copies a bridge profile
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
struct ast_party_id id
Caller party ID.
struct ast_bridge_channel_snapshot_pair to_transfer_target
#define ast_custom_function_register_escalating(acf, escalation)
Register a custom function which requires escalated privileges.
struct ast_flags feature_flags
unsigned int text_messaging
void ast_bridge_remove_video_src(struct ast_bridge *bridge, struct ast_channel *chan)
remove a channel as a source of video for the bridge.
void ast_bridge_set_send_sdp_label(struct ast_bridge *bridge, unsigned int send_sdp_label)
Controls whether to send a "label" attribute in each stream in an SDP.
conference_event_fn leave_marked
static struct ast_datastore_info async_datastore_info
Datastore used for timing of async announcement playback.
struct ast_bridge_channel * bridge_channel
int conf_announce_channel_push(struct ast_channel *ast)
Push the announcer channel into the conference.
int async_play_sound_file(struct confbridge_conference *conference, const char *filename, struct ast_channel *initiator)
Play sound file into conference bridge asynchronously.
int ast_devstate_changed(enum ast_device_state state, enum ast_devstate_cache cachable, const char *fmt,...)
Tells Asterisk the State for Device is changed.
int ast_bridge_impart(struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap, struct ast_bridge_features *features, enum ast_bridge_impart_flags flags) attribute_warn_unused_result
Impart a channel to a bridge (non-blocking)
void ast_brige_set_remb_behavior(struct ast_bridge *bridge, enum ast_bridge_video_sfu_remb_behavior behavior)
Set the REMB report generation behavior on a bridge.
General Asterisk PBX channel definitions.
Asterisk JSON abstraction layer.
Asterisk file paths, configured in asterisk.conf.
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
const ast_string_field appl
#define ast_strdupa(s)
duplicate a string in memory from the stack
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...
Data structure associated with a custom dialplan function.
struct ast_channel_snapshot * transferee
enum ast_pbx_result ast_pbx_run_args(struct ast_channel *c, struct ast_pbx_args *args)
Execute the PBX in the current thread.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
void conf_bridge_profile_destroy(struct bridge_profile *b_profile)
Destroy a bridge profile found by 'conf_find_bridge_profile'.
void conf_handle_first_join(struct confbridge_conference *conference)
Callback to execute any time we transition from zero to one active users.
#define ast_channel_cleanup(c)
Cleanup a channel reference.
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
int conf_reload_config(void)
reload confbridge.conf file
In case you didn't read that giant block of text above the mansession_session struct, the mansession is named this solely to keep the API the same in Asterisk. This structure really represents data that is different from Manager action to Manager action. The mansession_session pointer contained within points to session-specific data.
struct ast_channel_tech * conf_announce_get_tech(void)
Get ConfBridge announce channel technology struct.
int ast_bridge_interval_hook(struct ast_bridge_features *features, enum ast_bridge_hook_timer_option flags, unsigned int interval, ast_bridge_hook_callback callback, void *hook_pvt, ast_bridge_hook_pvt_destructor destructor, enum ast_bridge_hook_remove_flags remove_flags)
Attach an interval hook to a bridge features structure.
char * ast_strsep(char **s, const char sep, uint32_t flags)
Act like strsep but ignore separators inside quotes.
#define ast_malloc(len)
A wrapper for malloc()
#define MAXIMUM_DTMF_FEATURE_STRING
Maximum length of a DTMF feature string.
#define ast_debug(level,...)
Log a DEBUG message.
struct ao2_container * conference_bridges
Container to hold all conference bridges in progress.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
char language[MAX_LANGUAGE]
struct ast_bridge * ast_bridge_base_new(uint32_t capabilities, unsigned int flags, const char *creator, const char *name, const char *id)
Create a new base class bridge.
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
unsigned int maximum_sample_rate
struct ast_str * ast_manager_build_channel_state_string(const struct ast_channel_snapshot *snapshot)
Generate the AMI message body from a channel snapshot.
Structure to describe a channel "technology", ie a channel driver See for examples: ...
Core PBX routines and definitions.
unsigned int internal_sample_rate
int ast_queue_frame(struct ast_channel *chan, struct ast_frame *f)
Queue one or more frames to a channel's frame queue.
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
void ast_bridge_set_video_update_discard(struct ast_bridge *bridge, unsigned int video_update_discard)
Set the amount of time to discard subsequent video updates after a video update has been sent...
struct confbridge_state * state
#define ast_test_suite_event_notify(s, f,...)
struct stasis_topic * ast_channel_topic(struct ast_channel *chan)
A topic which publishes the events for a particular channel.
unsigned int dtmf_passthrough
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
void conf_moh_start(struct confbridge_user *user)
Start MOH for the conference user.
unsigned int video_update_discard
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Support for dynamic strings.
#define RECORD_FILENAME_INITIAL_SPACE
void conf_destroy_config(void)
destroy the information loaded from the confbridge.conf file
#define ao2_unlink(container, obj)
Remove an object from a container.
int conf_handle_only_person(struct confbridge_user *user)
Handle actions whenever an user joins an empty conference.
static int async_playback_task(void *data)
Play an announcement into a confbridge asynchronously.
int ast_bridge_is_video_src(struct ast_bridge *bridge, struct ast_channel *chan)
Determine if a channel is a video src for the bridge.
int ast_play_and_record(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime_sec, const char *fmt, int *duration, int *sound_duration, int silencethreshold, int maxsilence_ms, const char *path)
Record a file based on input from a channel. Use default accept and cancel DTMF. This function will p...
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
void ast_bridge_set_remb_send_interval(struct ast_bridge *bridge, unsigned int remb_send_interval)
Set the interval at which a combined REMB frame will be sent to video sources.
#define AST_LIST_LAST(head)
Returns the last entry contained in a list.
void ast_bridge_channel_leave_bridge(struct ast_bridge_channel *bridge_channel, enum bridge_channel_state new_state, int cause)
Set bridge channel state to leave bridge (if not leaving already).
void conf_moh_stop(struct confbridge_user *user)
Stop MOH for the conference user.
struct ast_format_cap * capabilities
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
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.
unsigned int talking_threshold
void manager_confbridge_shutdown(void)
unregister stasis message routers to handle manager events for confbridge messages ...
#define ast_bridge_unlock(bridge)
Unlock the bridge.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
int conf_set_menu_to_user(struct ast_channel *chan, struct confbridge_user *user, const char *menu_profile_name)
find a menu profile given a menu profile's name and apply the menu in DTMF hooks. ...
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
#define ast_calloc(num, len)
A wrapper for calloc()
conference_event_fn join_waitmarked
struct ast_bridge_snapshot * ast_bridge_snapshot_create(struct ast_bridge *bridge)
Generate a snapshot of the bridge state. This is an ao2 object, so ao2_cleanup() to deallocate...
int ast_stream_and_wait(struct ast_channel *chan, const char *file, const char *digits)
stream file until digit If the file name is non-empty, try to play it.
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
void ast_bridge_set_talker_src_video_mode(struct ast_bridge *bridge)
Set the bridge to pick the strongest talker supporting video as the single source video feed...
struct bridge_profile b_profile
struct ast_bridge_features features
static int push_announcer(struct confbridge_conference *conference)
Push the announcer channel into the bridge.
The structure that represents a conference bridge.
Module has failed to load, may be in an inconsistent state.
int ast_audiohook_volume_adjust(struct ast_channel *chan, enum ast_audiohook_direction direction, int volume)
Adjust the volume on frames read from or written to a channel.
An API for managing task processing threads that can be shared across modules.
int conf_handle_inactive_waitmarked(struct confbridge_user *user)
Handle actions every time a waitmarked user joins w/o a marked user present.
int conf_find_menu_entry_by_sequence(const char *dtmf_sequence, struct conf_menu *menu, struct conf_menu_entry *result)
Finds a menu_entry in a menu structure matched by DTMF sequence.
void conf_send_event_to_participants(struct confbridge_conference *conference, struct ast_channel *chan, struct stasis_message *msg)
Send events to bridge participants.
structure to hold users read from users.conf
int ast_bridge_join(struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap, struct ast_bridge_features *features, struct ast_bridge_tech_optimizations *tech_args, enum ast_bridge_join_flags flags)
Join a channel to a bridge (blocking)
void conf_invalid_event_fn(struct confbridge_user *user)
A handler for join/leave events that are invalid in a particular state.
void ast_bridge_set_single_src_video_mode(struct ast_bridge *bridge, struct ast_channel *video_src_chan)
Set a bridge to feed a single video source to all participants.
struct stasis_topic * ast_bridge_topic(struct ast_bridge *bridge)
A topic which publishes the events for a particular bridge.
char name_rec_location[PATH_MAX]
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
struct ast_bridge_features * ast_bridge_features_new(void)
Allocate a new bridge features struct.
#define ast_bridge_lock(bridge)
Lock the bridge.
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
#define AST_YESNO(x)
return Yes or No depending on the argument.
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
static int unload_module(void)
Called when module is being unloaded.
static int conference_bridge_hash_cb(const void *obj, const int flags)
Hashing function used for conference bridges container.
struct ast_channel * chan
Structure that contains information regarding a channel in a bridge.
int ast_taskprocessor_push(struct ast_taskprocessor *tps, int(*task_exe)(void *datap), void *datap) attribute_warn_unused_result
Push a task into the specified taskprocessor queue and signal the taskprocessor thread.
char menu_name[MAX_PROFILE_NAME]
#define ast_channel_ref(c)
Increase channel reference count.
conference_event_fn leave_waitmarked
int ast_add_extension(const char *context, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar)
Add and extension to an extension context.
struct ast_channel_snapshot * ast_channel_snapshot_get_latest(const char *uniqueid)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object...
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
int ast_say_number(struct ast_channel *chan, int num, const char *ints, const char *lang, const char *options)
says a number
Standard Command Line Interface.
void ast_bridge_channel_lock_bridge(struct ast_bridge_channel *bridge_channel)
Lock the bridge associated with the bridge channel.
int ast_bridge_suspend(struct ast_bridge *bridge, struct ast_channel *chan)
Suspend a channel temporarily from a bridge.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
ast_app: A registered application
static int async_delete_name_rec_task(void *data)
Delete user's name file asynchronously.
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
int ast_answer(struct ast_channel *chan)
Answer a channel.
unsigned int remb_estimated_bitrate
struct confbridge_conference * conf_find_bridge(const char *conference_name)
Find a confbridge by name.
struct ast_channel * playback_chan
Data structure associated with a single frame of data.
Abstract JSON element (object, array, string, int, ...).
The structure that represents a conference bridge user.
struct confbridge_conference::@91 waiting_list
void conf_ended(struct confbridge_conference *conference)
Callback to be called when the conference has become empty.
struct ast_str * record_filename
char * ast_str_set_substr(struct ast_str **buf, ssize_t maxlen, const char *src, size_t maxsrc)
Set a dynamic string to a non-NULL terminated substring.
static int conference_bridge_cmp_cb(void *obj, void *arg, int flags)
Comparison function used for conference bridges container.
static int play_file(struct ast_bridge_channel *bridge_channel, struct ast_channel *channel, const char *filename)
Playback the given filename and monitor for any dtmf interrupts.
unsigned int drop_silence
int conf_load_config(void)
load confbridge.conf file
int play_sound_file(struct confbridge_conference *conference, const char *filename)
Play sound file into conference bridge.
struct user_profile u_profile
#define AST_CLI_YESNO(x)
Return Yes or No depending on the argument.
static int play_prompt_to_user(struct confbridge_user *user, const char *filename)
Play back an audio file to a channel.
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...
struct ast_app * pbx_findapp(const char *app)
Look up an application.
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Say numbers and dates (maybe words one day too)
#define ASTERISK_GPL_KEY
The text the key() function should return.
unsigned int remb_send_interval
int ast_dsp_get_threshold_from_settings(enum threshold which)
Get silence threshold from dsp.conf.
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Asterisk module definitions.
struct stasis_message * ast_bridge_blob_create(struct stasis_message_type *message_type, struct ast_bridge *bridge, struct ast_channel *chan, struct ast_json *blob)
Creates a ast_bridge_blob message.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
unsigned int mix_interval
int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
executes a write operation on a function
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
unsigned char valid
TRUE if the number information is valid/present.
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ast_custom_function_register(acf)
Register a custom function.
int ast_stopstream(struct ast_channel *c)
Stops a stream.
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Structure for mutex and tracking information.
static force_inline int attribute_pure ast_str_case_hash(const char *str)
Compute a hash value on a case-insensitive string.
static int confbridge_exec(struct ast_channel *chan, const char *data)
The ConfBridge application.
struct ast_bridge_tech_optimizations tech_args
void ast_bridge_set_internal_sample_rate(struct ast_bridge *bridge, unsigned int sample_rate)
Adjust the internal mixing sample rate of a bridge used during multimix mode.
const ast_string_field name
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
#define AST_APP_ARG(name)
Define an application argument.
static void leave_conference(struct confbridge_user *user)
Leave a conference.
struct ast_bridge * bridge
int ast_mkdir(const char *path, int mode)
Recursively create directory path.
const struct bridge_profile * conf_find_bridge_profile(struct ast_channel *chan, const char *bridge_profile_name, struct bridge_profile *result)
Find a bridge profile given a bridge profile's name and store that profile in result structure...
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
struct ast_party_number number
Subscriber phone number.
#define ao2_link(container, obj)
Add an object to a container.