summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--main/asterisk/APKBUILD6
-rw-r--r--main/asterisk/ASTERISK-19107.patch60
-rw-r--r--main/asterisk/ASTERISK-19109.patch449
3 files changed, 514 insertions, 1 deletions
diff --git a/main/asterisk/APKBUILD b/main/asterisk/APKBUILD
index e6419e228a2..c0e2e5c64f8 100644
--- a/main/asterisk/APKBUILD
+++ b/main/asterisk/APKBUILD
@@ -2,7 +2,7 @@
# Maintainer: Timo Teras <timo.teras@iki.fi>
pkgname=asterisk
pkgver=10.0.0
-pkgrel=2
+pkgrel=3
pkgdesc="Asterisk: A Module Open Source PBX System"
url="http://www.asterisk.org/"
arch="all"
@@ -25,6 +25,8 @@ source="http://downloads.asterisk.org/pub/telephony/asterisk/releases/asterisk-$
ASTERISK-18994.patch
ASTERISK-18995.patch
ASTERISK-19106.patch
+ ASTERISK-19107.patch
+ ASTERISK-19109.patch
asterisk.initd
asterisk.confd
asterisk.logrotate"
@@ -173,6 +175,8 @@ da5a3c500192dee4275aae5235d25f97 ASTERISK-18976.patch
0af5e797f0a99d0f81f95e3710baf5b6 ASTERISK-18994.patch
bc6713f5434e07b79d3afdd155461d72 ASTERISK-18995.patch
fee11ba2f6518462ea6dde4039f9d8fa ASTERISK-19106.patch
+90e6c516b55245f4ff4a995b6f36a6b7 ASTERISK-19107.patch
+a59d61843a44d5a72da401218dcf6588 ASTERISK-19109.patch
86c7589e906102869d67f7f8bc82ca4b asterisk.initd
ed31d7ba37bcf8b0346dcf8593c395f0 asterisk.confd
3e65172275684373e1a25c8a11224411 asterisk.logrotate"
diff --git a/main/asterisk/ASTERISK-19107.patch b/main/asterisk/ASTERISK-19107.patch
new file mode 100644
index 00000000000..cb43615b24e
--- /dev/null
+++ b/main/asterisk/ASTERISK-19107.patch
@@ -0,0 +1,60 @@
+diff --git a/main/config.c b/main/config.c
+index 498ae99..0f5f0e2 100644
+--- a/main/config.c
++++ b/main/config.c
+@@ -1199,9 +1199,11 @@ static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
+ if (newcat)
+ ast_category_append(cfg, *cat);
+ } else if (cur[0] == '#') { /* A directive - #include or #exec */
++ struct ast_config *res;
+ char *cur2;
+ char real_inclusion_name[256];
+ int do_include = 0; /* otherwise, it is exec */
++ int quiet = 0;
+
+ cur++;
+ c = cur;
+@@ -1221,6 +1223,9 @@ static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
+ }
+ if (!strcasecmp(cur, "include")) {
+ do_include = 1;
++ } else if (!strcasecmp(cur, "-include")) {
++ do_include = 1;
++ quiet = 1;
+ } else if (!strcasecmp(cur, "exec")) {
+ if (!ast_opt_exec_includes) {
+ ast_log(LOG_WARNING, "Cannot perform #exec unless execincludes option is enabled in asterisk.conf (options section)!\n");
+@@ -1233,7 +1238,7 @@ static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
+
+ if (c == NULL) {
+ ast_log(LOG_WARNING, "Directive '#%s' needs an argument (%s) at line %d of %s\n",
+- do_include ? "include" : "exec",
++ cur,
+ do_include ? "filename" : "/path/to/executable",
+ lineno,
+ configfile);
+@@ -1275,10 +1280,13 @@ static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
+ /* record this inclusion */
+ ast_include_new(cfg, cfg->include_level == 1 ? "" : configfile, cur, !do_include, cur2, lineno, real_inclusion_name, sizeof(real_inclusion_name));
+
+- do_include = ast_config_internal_load(cur, cfg, flags, real_inclusion_name, who_asked) ? 1 : 0;
++ res = ast_config_internal_load(cur, cfg, flags, real_inclusion_name, who_asked);
+ if (!ast_strlen_zero(exec_file))
+ unlink(exec_file);
+- if (!do_include) {
++ if (res == CONFIG_STATUS_FILEINVALID) {
++ ast_log(LOG_ERROR, "The file '%s' was listed as a #include but it failed to load.\n", cur);
++ return -1;
++ } else if (res == CONFIG_STATUS_FILEMISSING && !quiet) {
+ ast_log(LOG_ERROR, "The file '%s' was listed as a #include but it does not exist.\n", cur);
+ return -1;
+ }
+@@ -1643,7 +1651,7 @@ static struct ast_config *config_text_file_load(const char *database, const char
+ }
+
+ if (count == 0)
+- return NULL;
++ return CONFIG_STATUS_FILEMISSING;
+
+ return cfg;
+ }
diff --git a/main/asterisk/ASTERISK-19109.patch b/main/asterisk/ASTERISK-19109.patch
new file mode 100644
index 00000000000..21fe3cb2242
--- /dev/null
+++ b/main/asterisk/ASTERISK-19109.patch
@@ -0,0 +1,449 @@
+diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c
+index 42c0a4c..ae26518 100644
+--- a/apps/app_confbridge.c
++++ b/apps/app_confbridge.c
+@@ -184,6 +184,31 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+ <description>
+ </description>
+ </manager>
++ <manager name="ConfbridgeDeafen" language="en_US">
++ <synopsis>
++ Deafen a Confbridge user.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Conference" required="true" />
++ <parameter name="Channel" required="true" />
++ </syntax>
++ <description>
++ </description>
++ </manager>
++ <manager name="ConfbridgeUndeafen" language="en_US">
++ <synopsis>
++ Un
++ Undefaen a Confbridge user.
++ </synopsis>
++ <syntax>
++ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
++ <parameter name="Conference" required="true" />
++ <parameter name="Channel" required="true" />
++ </syntax>
++ <description>
++ </description>
++ </manager>
+ <manager name="ConfbridgeKick" language="en_US">
+ <synopsis>
+ Kick a Confbridge user.
+@@ -310,6 +335,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:
+@@ -1416,10 +1445,13 @@ 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(&conference_bridge_user.u_profile, USER_OPT_STARTMUTED)) {
+ conference_bridge_user.features.mute = 1;
+ }
++ if (ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_STARTDEAF)) {
++ conference_bridge_user.features.deaf = 1;
++ }
+
+ if (ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_DROP_SILENCE)) {
+ conference_bridge_user.tech_args.drop_silence = 1;
+@@ -1548,6 +1580,19 @@ static int action_toggle_mute(struct conference_bridge *conference_bridge,
+ "");
+ }
+
++static int action_toggle_deaf(struct conference_bridge *conference_bridge,
++ struct conference_bridge_user *conference_bridge_user,
++ struct ast_channel *chan)
++{
++ /* Deafen or undeafen yourself */
++ conference_bridge_user->features.deaf = (!conference_bridge_user->features.deaf ? 1 : 0);
++
++ return ast_stream_and_wait(chan, (conference_bridge_user->features.deaf ?
++ conf_get_sound(CONF_SOUND_DEAFENED, conference_bridge_user->b_profile.sounds) :
++ conf_get_sound(CONF_SOUND_UNDEAFENED, conference_bridge_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);
+@@ -1727,6 +1772,11 @@ static int execute_menu_entry(struct conference_bridge *conference_bridge,
+ conference_bridge_user,
+ bridge_channel->chan);
+ break;
++ case MENU_ACTION_TOGGLE_DEAF:
++ res |= action_toggle_deaf(conference_bridge,
++ conference_bridge_user,
++ bridge_channel->chan);
++ break;
+ case MENU_ACTION_PLAYBACK:
+ if (!stop_prompts) {
+ res |= action_playback(bridge_channel, menu_action->data.playback_file);
+@@ -1988,13 +2038,13 @@ static int generic_lock_unlock_helper(int lock, const char *conference)
+ }
+
+ /* \internal
+- * \brief finds a conference user by channel name and mutes/unmutes them.
++ * \brief finds a conference user by channel name and mutes/unmutes and deafens/undeafens them.
+ *
+ * \retval 0 success
+ * \retval -1 conference not found
+ * \retval -2 user not found
+ */
+-static int generic_mute_unmute_helper(int mute, const char *conference, const char *user)
++static int generic_mute_deafen_helper(int mute, int deaf, const char *conference, const char *user)
+ {
+ struct conference_bridge *bridge = NULL;
+ struct conference_bridge tmp;
+@@ -2012,9 +2062,14 @@ static int generic_mute_unmute_helper(int mute, const char *conference, const ch
+ }
+ }
+ if (participant) {
+- participant->features.mute = mute;
++ if (mute >= 0) {
++ participant->features.mute = mute;
++ }
++ if (deaf >= 0) {
++ participant->features.deaf = deaf;
++ }
+ } else {
+- res = -2;;
++ res = -2;
+ }
+ ao2_unlock(bridge);
+ ao2_ref(bridge, -1);
+@@ -2022,9 +2077,10 @@ static int generic_mute_unmute_helper(int mute, const char *conference, const ch
+ return res;
+ }
+
+-static int cli_mute_unmute_helper(int mute, struct ast_cli_args *a)
++static int cli_mute_deafen_helper(int mute, int deaf, struct ast_cli_args *a)
+ {
+- int res = generic_mute_unmute_helper(mute, a->argv[2], a->argv[3]);
++ const char *verb;
++ int res = generic_mute_deafen_helper(mute, deaf, a->argv[2], a->argv[3]);
+
+ if (res == -1) {
+ ast_cli(a->fd, "No conference bridge named '%s' found!\n", a->argv[2]);
+@@ -2033,7 +2089,16 @@ 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]);
++ if (mute == 1) {
++ verb = "Muting";
++ } else if (mute == 0) {
++ verb = "Unmuting";
++ } else if (deaf == 1) {
++ verb = "Deafening";
++ } else {
++ verb = "Undeafening";
++ }
++ ast_cli(a->fd, "%s %s from confbridge %s\n", verb, a->argv[3], a->argv[2]);
+ return 0;
+ }
+
+@@ -2055,7 +2120,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_mute_deafen_helper(1, -1, a);
+
+ return CLI_SUCCESS;
+ }
+@@ -2078,7 +2143,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_mute_deafen_helper(0, -1, 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 <conference> <channel>\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_mute_deafen_helper(-1, 1, 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 <conference> <channel>\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_mute_deafen_helper(-1, 0, a);
+
+ return CLI_SUCCESS;
+ }
+@@ -2226,6 +2337,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"),
+@@ -2360,10 +2473,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_mute_deafen_helper(struct mansession *s, const struct message *m, int mute, int deaf)
+ {
+ const char *conference = astman_get_header(m, "Conference");
+ const char *channel = astman_get_header(m, "Channel");
++ char *verb;
+ int res = 0;
+
+ if (ast_strlen_zero(conference)) {
+@@ -2379,7 +2493,7 @@ static int action_mute_unmute_helper(struct mansession *s, const struct message
+ return 0;
+ }
+
+- res = generic_mute_unmute_helper(mute, conference, channel);
++ res = generic_mute_deafen_helper(mute, deaf, conference, channel);
+
+ if (res == -1) {
+ astman_send_error(s, m, "No Conference by that name found.");
+@@ -2389,17 +2503,35 @@ static int action_mute_unmute_helper(struct mansession *s, const struct message
+ return 0;
+ }
+
+- astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
++ if (mute == 1) {
++ verb = "User muted";
++ } else if (mute == 0) {
++ verb = "User unmuted";
++ } else if (deaf == 1) {
++ verb = "User deafened";
++ } else {
++ verb = "User undeafened";
++ }
++
++ 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_mute_deafen_helper(s, m, 0, -1);
+ }
+ static int action_confbridgemute(struct mansession *s, const struct message *m)
+ {
+- return action_mute_unmute_helper(s, m, 1);
++ return action_mute_deafen_helper(s, m, 1, -1);
++}
++static int action_confbridgeundeafen(struct mansession *s, const struct message *m)
++{
++ return action_mute_deafen_helper(s, m, -1, 0);
++}
++static int action_confbridgedeafen(struct mansession *s, const struct message *m)
++{
++ return action_mute_deafen_helper(s, m, -1, 1);
+ }
+
+ static int action_lock_unlock_helper(struct mansession *s, const struct message *m, int lock)
+@@ -2685,6 +2817,8 @@ static int unload_module(void)
+ res |= ast_manager_unregister("ConfbridgeListRooms");
+ res |= ast_manager_unregister("ConfbridgeMute");
+ res |= ast_manager_unregister("ConfbridgeUnmute");
++ res |= ast_manager_unregister("ConfbridgeDeafen");
++ res |= ast_manager_unregister("ConfbridgeUndeafen");
+ res |= ast_manager_unregister("ConfbridgeKick");
+ res |= ast_manager_unregister("ConfbridgeUnlock");
+ res |= ast_manager_unregister("ConfbridgeLock");
+@@ -2726,6 +2860,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 d11b825..df1997a 100644
+--- a/apps/confbridge/conf_config_parser.c
++++ b/apps/confbridge/conf_config_parser.c
+@@ -153,6 +153,8 @@ static int set_user_option(const char *name, const char *value, struct user_prof
+ ast_set2_flag(u_profile, ast_true(value), USER_OPT_MARKEDUSER);
+ } else if (!strcasecmp(name, "startmuted")) {
+ ast_set2_flag(u_profile, ast_true(value), USER_OPT_STARTMUTED);
++ } else if (!strcasecmp(name, "startdeaf")) {
++ ast_set2_flag(u_profile, ast_true(value), USER_OPT_STARTDEAF);
+ } else if (!strcasecmp(name, "music_on_hold_when_empty")) {
+ ast_set2_flag(u_profile, ast_true(value), USER_OPT_MUSICONHOLD);
+ } else if (!strcasecmp(name, "quiet")) {
+@@ -229,6 +231,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")) {
+@@ -533,6 +539,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:
+@@ -1015,6 +1022,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));
+@@ -1124,6 +1133,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;
+diff --git a/apps/confbridge/include/confbridge.h b/apps/confbridge/include/confbridge.h
+index ab4a8c4..f733b49 100644
+--- a/apps/confbridge/include/confbridge.h
++++ b/apps/confbridge/include/confbridge.h
+@@ -57,6 +57,7 @@ enum user_profile_flags {
+ USER_OPT_DTMF_PASS = (1 << 13), /*!< Sets if dtmf should be passed into the conference or not */
+ 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_STARTDEAF = (1 << 16), /*!< Set if the caller should be initially set deaf */
+ };
+
+ enum bridge_profile_flags {
+@@ -68,6 +69,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,
+@@ -141,6 +143,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,
+@@ -165,6 +169,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);
+diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c
+index 7632f36..103e3be 100644
+--- a/bridges/bridge_softmix.c
++++ b/bridges/bridge_softmix.c
+@@ -850,16 +850,23 @@ static int softmix_bridge_thread(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->features.deaf ||
++ (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, &bridge_channel->chan->rawwriteformat, 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, &bridge_channel->chan->rawwriteformat, sc);
+
+ /* The frame is now ready for use... */
+ sc->have_frame = 1;
+diff --git a/include/asterisk/bridging_features.h b/include/asterisk/bridging_features.h
+index e377ca6..5ce3d56 100644
+--- a/include/asterisk/bridging_features.h
++++ b/include/asterisk/bridging_features.h
+@@ -127,6 +127,8 @@ struct ast_bridge_features {
+ unsigned int usable:1;
+ /*! Bit to indicate whether the channel/bridge is muted or not */
+ unsigned int mute:1;
++ /*! Bit to indicate whether the channel/bridge is deaf or not */
++ unsigned int deaf:1;
+ /*! Bit to indicate whether DTMF should be passed into the bridge tech or not. */
+ unsigned int dtmf_passthrough:1;
+