diff --git a/CHANGES b/CHANGES
index 665d008..97761f8 100644
--- a/CHANGES
+++ b/CHANGES
@@ -40,6 +40,9 @@ ConfBridge
be asked if they want to confirm or re-record the recording of their
name when entering the conference
+ * Added support for deaf participants with CLI commands, manager actions
+ and ConfBridge DTMF actions to toggle the deaf state
+
Directory
--------------------------
* At exit, the Directory application now sets a channel variable
diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c
index 10cfb09..cb33c63 100644
--- a/apps/app_confbridge.c
+++ b/apps/app_confbridge.c
@@ -229,6 +229,30 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+
+ Deafen a Confbridge user.
+
+
+
+
+
+
+
+
+
+
+
+ Undeafen a Confbridge user.
+
+
+
+
+
+
+
+
+
Kick a Confbridge user.
@@ -325,6 +349,13 @@ enum {
CONF_RECORD_STOP,
};
+enum confbridge_feature_action {
+ CONFBRIDGE_FEATURE_MUTE,
+ CONFBRIDGE_FEATURE_UNMUTE,
+ CONFBRIDGE_FEATURE_DEAFEN,
+ CONFBRIDGE_FEATURE_UNDEAFEN
+};
+
/*! \brief Container to hold all conference bridges in progress */
struct ao2_container *conference_bridges;
@@ -396,6 +427,10 @@ const char *conf_get_sound(enum conf_sounds sound, struct bridge_profile_sounds
return S_OR(custom_sounds->muted, "conf-muted");
case CONF_SOUND_UNMUTED:
return S_OR(custom_sounds->unmuted, "conf-unmuted");
+ case CONF_SOUND_DEAFENED:
+ return S_OR(custom_sounds->deafened, "conf-deafened");
+ case CONF_SOUND_UNDEAFENED:
+ return S_OR(custom_sounds->undeafened, "conf-undeafened");
case CONF_SOUND_ONLY_ONE:
return S_OR(custom_sounds->onlyone, "conf-onlyone");
case CONF_SOUND_THERE_ARE:
@@ -509,6 +544,16 @@ static void send_unmute_event(struct ast_channel *chan, struct confbridge_confer
send_conf_stasis(conference, chan, confbridge_unmute_type(), NULL, 1);
}
+static void send_deafen_event(struct ast_channel *chan, struct confbridge_conference *conference)
+{
+ send_conf_stasis(conference, chan, confbridge_deafen_type(), NULL, 1);
+}
+
+static void send_undeafen_event(struct ast_channel *chan, struct confbridge_conference *conference)
+{
+ send_conf_stasis(conference, chan, confbridge_undeafen_type(), NULL, 1);
+}
+
static void set_rec_filename(struct confbridge_conference *conference, struct ast_str **filename, int is_new)
{
char *rec_file = conference->b_profile.rec_file;
@@ -1694,11 +1739,14 @@ static int confbridge_exec(struct ast_channel *chan, const char *data)
volume_adjustments[0] = ast_audiohook_volume_get(chan, AST_AUDIOHOOK_DIRECTION_READ);
volume_adjustments[1] = ast_audiohook_volume_get(chan, AST_AUDIOHOOK_DIRECTION_WRITE);
- /* If the caller should be joined already muted, make it so */
+ /* If the caller should be joined already muted or deaf, make it so */
if (ast_test_flag(&user.u_profile, USER_OPT_STARTMUTED)) {
/* Set user level mute request. */
user.muted = 1;
}
+ if (ast_test_flag(&user.u_profile, USER_OPT_STARTDEAF)) {
+ user.features.deaf = 1;
+ }
if (ast_test_flag(&user.u_profile, USER_OPT_DROP_SILENCE)) {
user.tech_args.drop_silence = 1;
@@ -1883,6 +1931,30 @@ static int action_toggle_mute_participants(struct confbridge_conference *confere
return 0;
}
+static int action_toggle_deaf(struct confbridge_conference *conference,
+ struct confbridge_user *user, struct ast_channel *chan)
+{
+ /* Deafen or undeafen yourself */
+ user->features.deaf = !user->features.deaf;
+ ast_test_suite_event_notify("CONF_DEAF",
+ "Message: participant %s %s\r\n"
+ "Conference: %s\r\n"
+ "Channel: %s",
+ ast_channel_name(chan),
+ user->features.deaf ? "deafened" : "undeafened",
+ user->b_profile.name,
+ ast_channel_name(chan));
+ if (user->features.deaf) {
+ send_deafen_event(chan, conference);
+ } else {
+ send_undeafen_event(chan, conference);
+ }
+ return ast_stream_and_wait(chan, (user->features.deaf ?
+ conf_get_sound(CONF_SOUND_DEAFENED, user->b_profile.sounds) :
+ conf_get_sound(CONF_SOUND_UNDEAFENED, user->b_profile.sounds)),
+ "");
+}
+
static int action_playback(struct ast_bridge_channel *bridge_channel, const char *playback_file)
{
char *file_copy = ast_strdupa(playback_file);
@@ -2072,6 +2144,11 @@ static int execute_menu_entry(struct confbridge_conference *conference,
case MENU_ACTION_PARTICIPANT_COUNT:
announce_user_count(conference, user);
break;
+ case MENU_ACTION_TOGGLE_DEAF:
+ res |= action_toggle_deaf(conference,
+ user,
+ bridge_channel->chan);
+ break;
case MENU_ACTION_PLAYBACK:
if (!stop_prompts) {
res |= action_playback(bridge_channel, menu_action->data.playback_file);
@@ -2429,14 +2506,29 @@ static int generic_lock_unlock_helper(int lock, const char *conference_name)
return res;
}
+static void test_suite_feature_action_event_notify(
+ struct confbridge_conference *conference,
+ struct confbridge_user *user,
+ const char *state, const char *verb)
+{
+ ast_test_suite_event_notify(state,
+ "Message: participant %s %s\r\n"
+ "Conference: %s\r\n"
+ "Channel: %s",
+ ast_channel_name(user->chan),
+ verb,
+ conference->b_profile.name,
+ ast_channel_name(user->chan));
+}
+
/* \internal
- * \brief finds a conference user by channel name and mutes/unmutes them.
+ * \brief finds a conference user by channel name and changes feature bits on it.
*
* \retval 0 success
* \retval -1 conference not found
* \retval -2 user not found
*/
-static int generic_mute_unmute_helper(int mute, const char *conference_name, const char *chan_name)
+static int generic_feature_action_helper(enum confbridge_feature_action action, const char *conference_name, const char *chan_name)
{
struct confbridge_conference *conference;
struct confbridge_user *user;
@@ -2453,25 +2545,33 @@ static int generic_mute_unmute_helper(int mute, const char *conference_name, con
}
}
if (user) {
- /* Set user level mute request. */
- user->muted = mute ? 1 : 0;
-
- conf_update_user_mute(user);
- ast_test_suite_event_notify("CONF_MUTE",
- "Message: participant %s %s\r\n"
- "Conference: %s\r\n"
- "Channel: %s",
- ast_channel_name(user->chan),
- mute ? "muted" : "unmuted",
- conference->b_profile.name,
- ast_channel_name(user->chan));
- if (mute) {
+ switch (action) {
+ case CONFBRIDGE_FEATURE_DEAFEN:
+ user->features.deaf = 1;
+ test_suite_feature_action_event_notify(conference, user, "CONF_DEAF", "deafened");
+ send_deafen_event(user->chan, conference);
+ break;
+ case CONFBRIDGE_FEATURE_UNDEAFEN:
+ user->features.deaf = 0;
+ test_suite_feature_action_event_notify(conference, user, "CONF_DEAF", "undeafened");
+ send_undeafen_event(user->chan, conference);
+ break;
+ case CONFBRIDGE_FEATURE_MUTE:
+ user->muted = 1;
+ conf_update_user_mute(user);
+ test_suite_feature_action_event_notify(conference, user, "CONF_MUTE", "muted");
send_mute_event(user->chan, conference);
- } else {
+ break;
+ case CONFBRIDGE_FEATURE_UNMUTE:
+ default:
+ user->muted = 0;
+ conf_update_user_mute(user);
+ test_suite_feature_action_event_notify(conference, user, "CONF_MUTE", "unmuted");
send_unmute_event(user->chan, conference);
+ break;
}
} else {
- res = -2;;
+ res = -2;
}
ao2_unlock(conference);
ao2_ref(conference, -1);
@@ -2479,9 +2579,10 @@ static int generic_mute_unmute_helper(int mute, const char *conference_name, con
return res;
}
-static int cli_mute_unmute_helper(int mute, struct ast_cli_args *a)
+static int cli_feature_action_helper(enum confbridge_feature_action action, struct ast_cli_args *a)
{
- int res = generic_mute_unmute_helper(mute, a->argv[2], a->argv[3]);
+ const char *verb;
+ int res = generic_feature_action_helper(action, a->argv[2], a->argv[3]);
if (res == -1) {
ast_cli(a->fd, "No conference bridge named '%s' found!\n", a->argv[2]);
@@ -2490,7 +2591,24 @@ static int cli_mute_unmute_helper(int mute, struct ast_cli_args *a)
ast_cli(a->fd, "No channel named '%s' found in conference %s\n", a->argv[3], a->argv[2]);
return -1;
}
- ast_cli(a->fd, "%s %s from confbridge %s\n", mute ? "Muting" : "Unmuting", a->argv[3], a->argv[2]);
+
+ switch (action) {
+ case CONFBRIDGE_FEATURE_DEAFEN:
+ verb = "Deafening";
+ break;
+ case CONFBRIDGE_FEATURE_UNDEAFEN:
+ verb = "Undeafening";
+ break;
+ case CONFBRIDGE_FEATURE_MUTE:
+ verb = "Muting";
+ break;
+ case CONFBRIDGE_FEATURE_UNMUTE:
+ default:
+ verb = "Unmuting";
+ break;
+ }
+
+ ast_cli(a->fd, "%s %s from confbridge %s\n", verb, a->argv[3], a->argv[2]);
return 0;
}
@@ -2519,7 +2637,7 @@ static char *handle_cli_confbridge_mute(struct ast_cli_entry *e, int cmd, struct
return CLI_SHOWUSAGE;
}
- cli_mute_unmute_helper(1, a);
+ cli_feature_action_helper(CONFBRIDGE_FEATURE_MUTE, a);
return CLI_SUCCESS;
}
@@ -2549,7 +2667,53 @@ static char *handle_cli_confbridge_unmute(struct ast_cli_entry *e, int cmd, stru
return CLI_SHOWUSAGE;
}
- cli_mute_unmute_helper(0, a);
+ cli_feature_action_helper(CONFBRIDGE_FEATURE_UNMUTE, a);
+
+ return CLI_SUCCESS;
+}
+
+static char *handle_cli_confbridge_deafen(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "confbridge deafen";
+ e->usage =
+ "Usage: confbridge deafen \n";
+ return NULL;
+ case CLI_GENERATE:
+ if (a->pos == 2) {
+ return complete_confbridge_name(a->line, a->word, a->pos, a->n);
+ }
+ return NULL;
+ }
+ if (a->argc != 4) {
+ return CLI_SHOWUSAGE;
+ }
+
+ cli_feature_action_helper(CONFBRIDGE_FEATURE_DEAFEN, a);
+
+ return CLI_SUCCESS;
+}
+
+static char *handle_cli_confbridge_undeafen(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "confbridge undeafen";
+ e->usage =
+ "Usage: confbridge undeafen \n";
+ return NULL;
+ case CLI_GENERATE:
+ if (a->pos == 2) {
+ return complete_confbridge_name(a->line, a->word, a->pos, a->n);
+ }
+ return NULL;
+ }
+ if (a->argc != 4) {
+ return CLI_SHOWUSAGE;
+ }
+
+ cli_feature_action_helper(CONFBRIDGE_FEATURE_UNDEAFEN, a);
return CLI_SUCCESS;
}
@@ -2704,6 +2868,8 @@ static struct ast_cli_entry cli_confbridge[] = {
AST_CLI_DEFINE(handle_cli_confbridge_kick, "Kick participants out of conference bridges."),
AST_CLI_DEFINE(handle_cli_confbridge_mute, "Mute a participant."),
AST_CLI_DEFINE(handle_cli_confbridge_unmute, "Unmute a participant."),
+ AST_CLI_DEFINE(handle_cli_confbridge_deafen, "Deafen a participant."),
+ AST_CLI_DEFINE(handle_cli_confbridge_undeafen, "Undeafen a participant."),
AST_CLI_DEFINE(handle_cli_confbridge_lock, "Lock a conference."),
AST_CLI_DEFINE(handle_cli_confbridge_unlock, "Unlock a conference."),
AST_CLI_DEFINE(handle_cli_confbridge_start_record, "Start recording a conference"),
@@ -2854,10 +3020,11 @@ static int action_confbridgelistrooms(struct mansession *s, const struct message
return 0;
}
-static int action_mute_unmute_helper(struct mansession *s, const struct message *m, int mute)
+static int action_feature_action_helper(struct mansession *s, const struct message *m, enum confbridge_feature_action action)
{
const char *conference_name = astman_get_header(m, "Conference");
const char *channel_name = astman_get_header(m, "Channel");
+ char *verb;
int res = 0;
if (ast_strlen_zero(conference_name)) {
@@ -2873,7 +3040,7 @@ static int action_mute_unmute_helper(struct mansession *s, const struct message
return 0;
}
- res = generic_mute_unmute_helper(mute, conference_name, channel_name);
+ res = generic_feature_action_helper(action, conference_name, channel_name);
if (res == -1) {
astman_send_error(s, m, "No Conference by that name found.");
@@ -2883,17 +3050,41 @@ static int action_mute_unmute_helper(struct mansession *s, const struct message
return 0;
}
- astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
+ switch (action) {
+ case CONFBRIDGE_FEATURE_DEAFEN:
+ verb = "User deafened";
+ break;
+ case CONFBRIDGE_FEATURE_UNDEAFEN:
+ verb = "User undeafened";
+ break;
+ case CONFBRIDGE_FEATURE_MUTE:
+ verb = "User muted";
+ break;
+ case CONFBRIDGE_FEATURE_UNMUTE:
+ default:
+ verb = "User unmuted";
+ break;
+ }
+
+ astman_send_ack(s, m, verb);
return 0;
}
static int action_confbridgeunmute(struct mansession *s, const struct message *m)
{
- return action_mute_unmute_helper(s, m, 0);
+ return action_feature_action_helper(s, m, CONFBRIDGE_FEATURE_UNMUTE);
}
static int action_confbridgemute(struct mansession *s, const struct message *m)
{
- return action_mute_unmute_helper(s, m, 1);
+ return action_feature_action_helper(s, m, CONFBRIDGE_FEATURE_MUTE);
+}
+static int action_confbridgeundeafen(struct mansession *s, const struct message *m)
+{
+ return action_feature_action_helper(s, m, CONFBRIDGE_FEATURE_UNDEAFEN);
+}
+static int action_confbridgedeafen(struct mansession *s, const struct message *m)
+{
+ return action_feature_action_helper(s, m, CONFBRIDGE_FEATURE_DEAFEN);
}
static int action_lock_unlock_helper(struct mansession *s, const struct message *m, int lock)
@@ -3246,6 +3437,8 @@ static int unload_module(void)
ast_manager_unregister("ConfbridgeListRooms");
ast_manager_unregister("ConfbridgeMute");
ast_manager_unregister("ConfbridgeUnmute");
+ ast_manager_unregister("ConfbridgeDeafen");
+ ast_manager_unregister("ConfbridgeUndeafen");
ast_manager_unregister("ConfbridgeKick");
ast_manager_unregister("ConfbridgeUnlock");
ast_manager_unregister("ConfbridgeLock");
@@ -3315,6 +3508,8 @@ static int load_module(void)
res |= ast_manager_register_xml("ConfbridgeListRooms", EVENT_FLAG_REPORTING, action_confbridgelistrooms);
res |= ast_manager_register_xml("ConfbridgeMute", EVENT_FLAG_CALL, action_confbridgemute);
res |= ast_manager_register_xml("ConfbridgeUnmute", EVENT_FLAG_CALL, action_confbridgeunmute);
+ res |= ast_manager_register_xml("ConfbridgeDeafen", EVENT_FLAG_CALL, action_confbridgedeafen);
+ res |= ast_manager_register_xml("ConfbridgeUndeafen", EVENT_FLAG_CALL, action_confbridgeundeafen);
res |= ast_manager_register_xml("ConfbridgeKick", EVENT_FLAG_CALL, action_confbridgekick);
res |= ast_manager_register_xml("ConfbridgeUnlock", EVENT_FLAG_CALL, action_confbridgeunlock);
res |= ast_manager_register_xml("ConfbridgeLock", EVENT_FLAG_CALL, action_confbridgelock);
diff --git a/apps/confbridge/conf_config_parser.c b/apps/confbridge/conf_config_parser.c
index 0e81e7e..cd6b8ba 100644
--- a/apps/confbridge/conf_config_parser.c
+++ b/apps/confbridge/conf_config_parser.c
@@ -869,6 +869,10 @@ static int set_sound(const char *sound_name, const char *sound_file, struct brid
ast_string_field_set(sounds, muted, sound_file);
} else if (!strcasecmp(sound_name, "sound_unmuted")) {
ast_string_field_set(sounds, unmuted, sound_file);
+ } else if (!strcasecmp(sound_name, "sound_deafened")) {
+ ast_string_field_set(sounds, deafened, sound_file);
+ } else if (!strcasecmp(sound_name, "sound_undeafened")) {
+ ast_string_field_set(sounds, undeafened, sound_file);
} else if (!strcasecmp(sound_name, "sound_there_are")) {
ast_string_field_set(sounds, thereare, sound_file);
} else if (!strcasecmp(sound_name, "sound_other_in_party")) {
@@ -1063,6 +1067,7 @@ static int add_action_to_menu_entry(struct conf_menu_entry *menu_entry, enum con
switch (id) {
case MENU_ACTION_NOOP:
case MENU_ACTION_TOGGLE_MUTE:
+ case MENU_ACTION_TOGGLE_DEAF:
case MENU_ACTION_INCREASE_LISTENING:
case MENU_ACTION_DECREASE_LISTENING:
case MENU_ACTION_INCREASE_TALKING:
@@ -1353,6 +1358,9 @@ static char *handle_cli_confbridge_show_user_profile(struct ast_cli_entry *e, in
ast_cli(a->fd,"Start Muted: %s\n",
u_profile.flags & USER_OPT_STARTMUTED?
"true" : "false");
+ ast_cli(a->fd,"Start Deaf: %s\n",
+ u_profile.flags & USER_OPT_STARTDEAF?
+ "true" : "false");
ast_cli(a->fd,"MOH When Empty: %s\n",
u_profile.flags & USER_OPT_MUSICONHOLD ?
"enabled" : "disabled");
@@ -1557,6 +1565,8 @@ static char *handle_cli_confbridge_show_bridge_profile(struct ast_cli_entry *e,
ast_cli(a->fd,"sound_kicked: %s\n", conf_get_sound(CONF_SOUND_KICKED, b_profile.sounds));
ast_cli(a->fd,"sound_muted: %s\n", conf_get_sound(CONF_SOUND_MUTED, b_profile.sounds));
ast_cli(a->fd,"sound_unmuted: %s\n", conf_get_sound(CONF_SOUND_UNMUTED, b_profile.sounds));
+ ast_cli(a->fd,"sound_deafened: %s\n", conf_get_sound(CONF_SOUND_DEAFENED, b_profile.sounds));
+ ast_cli(a->fd,"sound_undeafened: %s\n", conf_get_sound(CONF_SOUND_UNDEAFENED, b_profile.sounds));
ast_cli(a->fd,"sound_there_are: %s\n", conf_get_sound(CONF_SOUND_THERE_ARE, b_profile.sounds));
ast_cli(a->fd,"sound_other_in_party: %s\n", conf_get_sound(CONF_SOUND_OTHER_IN_PARTY, b_profile.sounds));
ast_cli(a->fd,"sound_place_into_conference: %s\n", conf_get_sound(CONF_SOUND_PLACE_IN_CONF, b_profile.sounds));
@@ -1685,6 +1695,9 @@ static char *handle_cli_confbridge_show_menu(struct ast_cli_entry *e, int cmd, s
case MENU_ACTION_TOGGLE_MUTE:
ast_cli(a->fd, "toggle_mute");
break;
+ case MENU_ACTION_TOGGLE_DEAF:
+ ast_cli(a->fd, "toggle_deaf");
+ break;
case MENU_ACTION_NOOP:
ast_cli(a->fd, "no_op");
break;
@@ -2058,6 +2071,7 @@ int conf_load_config(void)
aco_option_register(&cfg_info, "admin", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_ADMIN);
aco_option_register(&cfg_info, "marked", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_MARKEDUSER);
aco_option_register(&cfg_info, "startmuted", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_STARTMUTED);
+ aco_option_register(&cfg_info, "startdeaf", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_STARTDEAF);
aco_option_register(&cfg_info, "music_on_hold_when_empty", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_MUSICONHOLD);
aco_option_register(&cfg_info, "quiet", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_QUIET);
aco_option_register_custom(&cfg_info, "announce_user_count_all", ACO_EXACT, user_types, "no", announce_user_count_all_handler, 0);
diff --git a/apps/confbridge/confbridge_manager.c b/apps/confbridge/confbridge_manager.c
index 1b8eab2..ec76f19 100644
--- a/apps/confbridge/confbridge_manager.c
+++ b/apps/confbridge/confbridge_manager.c
@@ -161,6 +161,38 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+
+ Raised when a Confbridge participant deafens.
+
+
+ The name of the Confbridge conference.
+
+
+
+
+
+ [ConfbridgeUndeafen]
+ [ConfBridge]
+
+
+
+
+
+ Raised when a confbridge participant undeafens.
+
+
+ The name of the Confbridge conference.
+
+
+
+
+
+ [ConfbridgeMute]
+ [ConfBridge]
+
+
+
Raised when a confbridge participant unmutes.
@@ -271,6 +303,18 @@ static void confbridge_unmute_cb(void *data, struct stasis_subscription *sub,
confbridge_publish_manager_event(message, "ConfbridgeUnmute", NULL);
}
+static void confbridge_deafen_cb(void *data, struct stasis_subscription *sub,
+ struct stasis_message *message)
+{
+ confbridge_publish_manager_event(message, "ConfbridgeDeafen", NULL);
+}
+
+static void confbridge_undeafen_cb(void *data, struct stasis_subscription *sub,
+ struct stasis_message *message)
+{
+ confbridge_publish_manager_event(message, "ConfbridgeUndeafen", NULL);
+}
+
static void confbridge_talking_cb(void *data, struct stasis_subscription *sub,
struct stasis_message *message)
{
@@ -297,6 +341,8 @@ STASIS_MESSAGE_TYPE_DEFN(confbridge_start_record_type);
STASIS_MESSAGE_TYPE_DEFN(confbridge_stop_record_type);
STASIS_MESSAGE_TYPE_DEFN(confbridge_mute_type);
STASIS_MESSAGE_TYPE_DEFN(confbridge_unmute_type);
+STASIS_MESSAGE_TYPE_DEFN(confbridge_deafen_type);
+STASIS_MESSAGE_TYPE_DEFN(confbridge_undeafen_type);
STASIS_MESSAGE_TYPE_DEFN(confbridge_talking_type);
void manager_confbridge_shutdown(void) {
@@ -308,6 +354,8 @@ void manager_confbridge_shutdown(void) {
STASIS_MESSAGE_TYPE_CLEANUP(confbridge_stop_record_type);
STASIS_MESSAGE_TYPE_CLEANUP(confbridge_mute_type);
STASIS_MESSAGE_TYPE_CLEANUP(confbridge_unmute_type);
+ STASIS_MESSAGE_TYPE_CLEANUP(confbridge_deafen_type);
+ STASIS_MESSAGE_TYPE_CLEANUP(confbridge_undeafen_type);
STASIS_MESSAGE_TYPE_CLEANUP(confbridge_talking_type);
if (bridge_state_router) {
@@ -331,6 +379,8 @@ int manager_confbridge_init(void)
STASIS_MESSAGE_TYPE_INIT(confbridge_stop_record_type);
STASIS_MESSAGE_TYPE_INIT(confbridge_mute_type);
STASIS_MESSAGE_TYPE_INIT(confbridge_unmute_type);
+ STASIS_MESSAGE_TYPE_INIT(confbridge_deafen_type);
+ STASIS_MESSAGE_TYPE_INIT(confbridge_undeafen_type);
STASIS_MESSAGE_TYPE_INIT(confbridge_talking_type);
bridge_state_router = stasis_message_router_create(
@@ -397,6 +447,20 @@ int manager_confbridge_init(void)
return -1;
}
if (stasis_message_router_add(bridge_state_router,
+ confbridge_deafen_type(),
+ confbridge_deafen_cb,
+ NULL)) {
+ manager_confbridge_shutdown();
+ return -1;
+ }
+ if (stasis_message_router_add(bridge_state_router,
+ confbridge_undeafen_type(),
+ confbridge_undeafen_cb,
+ NULL)) {
+ manager_confbridge_shutdown();
+ return -1;
+ }
+ if (stasis_message_router_add(bridge_state_router,
confbridge_talking_type(),
confbridge_talking_cb,
NULL)) {
@@ -469,6 +533,20 @@ int manager_confbridge_init(void)
return -1;
}
if (stasis_message_router_add(channel_state_router,
+ confbridge_deafen_type(),
+ confbridge_deafen_cb,
+ NULL)) {
+ manager_confbridge_shutdown();
+ return -1;
+ }
+ if (stasis_message_router_add(channel_state_router,
+ confbridge_undeafen_type(),
+ confbridge_undeafen_cb,
+ NULL)) {
+ manager_confbridge_shutdown();
+ return -1;
+ }
+ if (stasis_message_router_add(channel_state_router,
confbridge_talking_type(),
confbridge_talking_cb,
NULL)) {
diff --git a/apps/confbridge/include/confbridge.h b/apps/confbridge/include/confbridge.h
index ce62537..b18ed4f 100644
--- a/apps/confbridge/include/confbridge.h
+++ b/apps/confbridge/include/confbridge.h
@@ -60,6 +60,7 @@ enum user_profile_flags {
USER_OPT_ANNOUNCEUSERCOUNTALL = (1 << 14), /*!< Sets if the number of users should be announced to everyone. */
USER_OPT_JITTERBUFFER = (1 << 15), /*!< Places a jitterbuffer on the user. */
USER_OPT_ANNOUNCE_JOIN_LEAVE_REVIEW = (1 << 16), /*!< modifies ANNOUNCE_JOIN_LEAVE - user reviews the recording before continuing */
+ USER_OPT_STARTDEAF = (1 << 17), /*!< Set if the caller should be initially set deaf */
};
enum bridge_profile_flags {
@@ -72,6 +73,7 @@ enum bridge_profile_flags {
enum conf_menu_action_id {
MENU_ACTION_TOGGLE_MUTE = 1,
+ MENU_ACTION_TOGGLE_DEAF,
MENU_ACTION_PLAYBACK,
MENU_ACTION_PLAYBACK_AND_CONTINUE,
MENU_ACTION_INCREASE_LISTENING,
@@ -146,6 +148,8 @@ enum conf_sounds {
CONF_SOUND_KICKED,
CONF_SOUND_MUTED,
CONF_SOUND_UNMUTED,
+ CONF_SOUND_DEAFENED,
+ CONF_SOUND_UNDEAFENED,
CONF_SOUND_ONLY_ONE,
CONF_SOUND_THERE_ARE,
CONF_SOUND_OTHER_IN_PARTY,
@@ -173,6 +177,8 @@ struct bridge_profile_sounds {
AST_STRING_FIELD(kicked);
AST_STRING_FIELD(muted);
AST_STRING_FIELD(unmuted);
+ AST_STRING_FIELD(deafened);
+ AST_STRING_FIELD(undeafened);
AST_STRING_FIELD(onlyone);
AST_STRING_FIELD(thereare);
AST_STRING_FIELD(otherinparty);
@@ -365,6 +371,8 @@ int conf_handle_dtmf(
struct conf_menu_entry *menu_entry,
struct conf_menu *menu);
+struct stasis_message_type *confbridge_deafen_type(void);
+struct stasis_message_type *confbridge_undeafen_type(void);
/*! \brief Looks to see if sound file is stored in bridge profile sounds, if not
* default sound is provided.*/
diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c
index 271f856..d4f943d 100644
--- a/bridges/bridge_softmix.c
+++ b/bridges/bridge_softmix.c
@@ -923,16 +923,23 @@ static int softmix_mixing_loop(struct ast_bridge *bridge)
ast_mutex_lock(&sc->lock);
- /* Make SLINEAR write frame from local buffer */
- if (sc->write_frame.subclass.format.id != cur_slin_id) {
- ast_format_set(&sc->write_frame.subclass.format, cur_slin_id, 0);
+ if (bridge_channel->features && bridge_channel->features->deaf) {
+ /* For deaf channels post a null frame */
+ sc->write_frame.frametype = AST_FRAME_NULL;
+ } else {
+ /* Make SLINEAR write frame from local buffer */
+ sc->write_frame.frametype = AST_FRAME_VOICE;
+ if (sc->write_frame.subclass.format.id != cur_slin_id) {
+ ast_format_set(&sc->write_frame.subclass.format, cur_slin_id, 0);
+ }
+ sc->write_frame.datalen = softmix_datalen;
+ sc->write_frame.samples = softmix_samples;
+ memcpy(sc->final_buf, buf, softmix_datalen);
+
+ /* process the softmix channel's new write audio */
+ softmix_process_write_audio(&trans_helper,
+ ast_channel_rawwriteformat(bridge_channel->chan), sc);
}
- sc->write_frame.datalen = softmix_datalen;
- sc->write_frame.samples = softmix_samples;
- memcpy(sc->final_buf, buf, softmix_datalen);
-
- /* process the softmix channel's new write audio */
- softmix_process_write_audio(&trans_helper, ast_channel_rawwriteformat(bridge_channel->chan), sc);
ast_mutex_unlock(&sc->lock);
diff --git a/configs/confbridge.conf.sample b/configs/confbridge.conf.sample
index 860f1cb..065e0c7 100644
--- a/configs/confbridge.conf.sample
+++ b/configs/confbridge.conf.sample
@@ -20,6 +20,7 @@ type=user
;admin=yes ; Sets if the user is an admin or not. Off by default.
;marked=yes ; Sets if this is a marked user or not. Off by default.
;startmuted=yes; Sets if all users should start out muted. Off by default
+;startdeaf=yes ; Sets if all users should start out deaf. Off by default.
;music_on_hold_when_empty=yes ; Sets whether MOH should be played when only
; one person is in the conference or when the
; the user is waiting on a marked user to enter
@@ -222,6 +223,8 @@ type=bridge
;sound_kicked ; The sound played to a user who has been kicked from the conference.
;sound_muted ; The sound played when the mute option it toggled on.
;sound_unmuted ; The sound played when the mute option it toggled off.
+;sound_deafened ; The sound played when the deaf option is toggled on.
+;sound_undeafened ; The sound played when the deaf option is toggled off.
;sound_only_person ; The sound played when the user is the only person in the conference.
;sound_only_one ; The sound played to a user when there is only one other
; person is in the conference.
@@ -283,6 +286,8 @@ type=bridge
; using the '&' character as a delimiter.
; toggle_mute ; Toggle turning on and off mute. Mute will make the user silent
; to everyone else, but the user will still be able to listen in.
+; toggle_deaf ; Toggle turning on and off deaf. Deaf will make the user to hear
+ ; only silence, but the user will still be able to talk.
; no_op ; This action does nothing (No Operation). Its only real purpose exists for
; being able to reserve a sequence in the config as a menu exit sequence.
diff --git a/include/asterisk/bridge_features.h b/include/asterisk/bridge_features.h
index 2f89be9..41311e7 100644
--- a/include/asterisk/bridge_features.h
+++ b/include/asterisk/bridge_features.h
@@ -253,6 +253,8 @@ struct ast_bridge_features {
unsigned int usable:1;
/*! TRUE if the channel/bridge is muted. */
unsigned int mute:1;
+ /*! TRUE if the channel/bridge is deaf. */
+ unsigned int deaf:1;
/*! TRUE if DTMF should be passed into the bridge tech. */
unsigned int dtmf_passthrough:1;
};
diff --git a/main/bridge_channel.c b/main/bridge_channel.c
index ae33cd0..7e51163 100644
--- a/main/bridge_channel.c
+++ b/main/bridge_channel.c
@@ -549,7 +549,21 @@ int ast_bridge_channel_queue_frame(struct ast_bridge_channel *bridge_channel, st
return 0;
}
- dup = ast_frdup(fr);
+ if (fr->frametype == AST_FRAME_VOICE &&
+ (bridge_channel->features && bridge_channel->features->deaf)) {
+ short buf[fr->samples];
+ struct ast_frame sframe = {
+ .frametype = AST_FRAME_VOICE,
+ .data.ptr = buf,
+ .samples = fr->samples,
+ .datalen = sizeof(buf),
+ };
+ ast_format_set(&sframe.subclass.format, AST_FORMAT_SLINEAR, 0);
+ memset(buf, 0, sizeof(buf));
+ dup = ast_frdup(&sframe);
+ } else {
+ dup = ast_frdup(fr);
+ }
if (!dup) {
return -1;
}