diff -ru asterisk-11.8.0.orig/CHANGES asterisk-11.8.0/CHANGES --- asterisk-11.8.0.orig/CHANGES 2013-07-21 22:51:58.000000000 +0000 +++ asterisk-11.8.0/CHANGES 2014-03-04 14:06:21.737312433 +0000 @@ -67,6 +67,9 @@ file will be played to the user, and only the user, upon joining the conference bridge. + * Added support for deaf participants with CLI commands, manager actions + and ConfBridge DTMF actions to toggle the deaf state. + Dial ------------------- Only in asterisk-11.8.0: CHANGES.orig diff -ru asterisk-11.8.0.orig/apps/app_confbridge.c asterisk-11.8.0/apps/app_confbridge.c --- asterisk-11.8.0.orig/apps/app_confbridge.c 2014-01-09 15:41:31.000000000 +0000 +++ asterisk-11.8.0/apps/app_confbridge.c 2014-03-04 14:23:49.966297722 +0000 @@ -199,6 +199,30 @@ + + + Deafen a Confbridge user. + + + + + + + + + + + + Undeafen a Confbridge user. + + + + + + + + + Kick a Confbridge user. @@ -293,6 +317,13 @@ 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 */ static struct ao2_container *conference_bridges; @@ -331,6 +362,10 @@ 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: @@ -1679,6 +1714,9 @@ /* Set user level mute request. */ conference_bridge_user.muted = 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; @@ -1852,6 +1890,20 @@ return 0; } +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); + ast_test_suite_event_notify("CONF_DEAF", "Message: participant %s %s\r\nConference: %s\r\nChannel: %s", chan->name, conference_bridge_user->features.deaf ? "deafened" : "undeafened", conference_bridge_user->b_profile.name, chan->name); + + 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); @@ -2040,6 +2092,11 @@ case MENU_ACTION_PARTICIPANT_COUNT: announce_user_count(conference_bridge, conference_bridge_user); 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); @@ -2353,14 +2410,29 @@ return res; } +static void test_suite_feature_action_event_notify( + struct conference_bridge *conference, + struct conference_bridge_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, const char *user) +static int generic_feature_action_helper(enum confbridge_feature_action action, const char *conference, const char *user) { struct conference_bridge *bridge = NULL; struct conference_bridge tmp; @@ -2378,20 +2450,29 @@ } } if (participant) { - /* Set user level mute request. */ - participant->muted = mute ? 1 : 0; - - conf_update_user_mute(participant); - ast_test_suite_event_notify("CONF_MUTE", - "Message: participant %s %s\r\n" - "Conference: %s\r\n" - "Channel: %s", - ast_channel_name(participant->chan), - mute ? "muted" : "unmuted", - bridge->b_profile.name, - ast_channel_name(participant->chan)); + switch (action) { + case CONFBRIDGE_FEATURE_DEAFEN: + participant->features.deaf = 1; + test_suite_feature_action_event_notify(bridge, participant, "CONF_DEAF", "deafened"); + break; + case CONFBRIDGE_FEATURE_UNDEAFEN: + participant->features.deaf = 0; + test_suite_feature_action_event_notify(bridge, participant, "CONF_DEAF", "undeafened"); + break; + case CONFBRIDGE_FEATURE_MUTE: + participant->muted = 1; + conf_update_user_mute(participant); + test_suite_feature_action_event_notify(bridge, participant, "CONF_MUTE", "muted"); + break; + case CONFBRIDGE_FEATURE_UNMUTE: + default: + participant->muted = 0; + conf_update_user_mute(participant); + test_suite_feature_action_event_notify(bridge, participant, "CONF_MUTE", "unmuted"); + break; + } } else { - res = -2;; + res = -2; } ao2_unlock(bridge); ao2_ref(bridge, -1); @@ -2399,9 +2480,10 @@ 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]); @@ -2410,7 +2492,24 @@ 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; } @@ -2436,7 +2535,7 @@ return CLI_SHOWUSAGE; } - cli_mute_unmute_helper(1, a); + cli_feature_action_helper(CONFBRIDGE_FEATURE_MUTE, a); return CLI_SUCCESS; } @@ -2463,7 +2562,53 @@ 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; } @@ -2622,6 +2767,8 @@ 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"), @@ -2767,10 +2914,11 @@ 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 = astman_get_header(m, "Conference"); const char *channel = astman_get_header(m, "Channel"); + char *verb; int res = 0; if (ast_strlen_zero(conference)) { @@ -2786,7 +2934,7 @@ return 0; } - res = generic_mute_unmute_helper(mute, conference, channel); + res = generic_feature_action_helper(action, conference, channel); if (res == -1) { astman_send_error(s, m, "No Conference by that name found."); @@ -2796,17 +2944,41 @@ 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) @@ -3141,6 +3313,8 @@ 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"); @@ -3188,6 +3362,8 @@ 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); Only in asterisk-11.8.0/apps: app_confbridge.c.orig Only in asterisk-11.8.0/apps: app_confbridge.c.rej diff -ru asterisk-11.8.0.orig/apps/confbridge/conf_config_parser.c asterisk-11.8.0/apps/confbridge/conf_config_parser.c --- asterisk-11.8.0.orig/apps/confbridge/conf_config_parser.c 2013-10-08 20:14:14.000000000 +0000 +++ asterisk-11.8.0/apps/confbridge/conf_config_parser.c 2014-03-04 14:06:21.740645521 +0000 @@ -281,6 +281,10 @@ 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")) { @@ -420,6 +424,7 @@ 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: @@ -710,6 +715,9 @@ 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"); @@ -909,6 +917,8 @@ 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)); @@ -1036,6 +1046,9 @@ 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; @@ -1334,6 +1347,7 @@ 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); Only in asterisk-11.8.0/apps/confbridge: conf_config_parser.c.orig diff -ru asterisk-11.8.0.orig/apps/confbridge/include/confbridge.h asterisk-11.8.0/apps/confbridge/include/confbridge.h --- asterisk-11.8.0.orig/apps/confbridge/include/confbridge.h 2013-11-02 02:11:03.000000000 +0000 +++ asterisk-11.8.0/apps/confbridge/include/confbridge.h 2014-03-04 14:06:21.740645521 +0000 @@ -58,6 +58,7 @@ 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 { @@ -69,6 +70,7 @@ 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, @@ -143,6 +145,8 @@ 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, @@ -169,6 +173,8 @@ 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); Only in asterisk-11.8.0/apps/confbridge/include: confbridge.h.orig diff -ru asterisk-11.8.0.orig/bridges/bridge_multiplexed.c asterisk-11.8.0/bridges/bridge_multiplexed.c --- asterisk-11.8.0.orig/bridges/bridge_multiplexed.c 2012-04-06 16:33:24.000000000 +0000 +++ asterisk-11.8.0/bridges/bridge_multiplexed.c 2014-03-04 14:06:21.740645521 +0000 @@ -386,7 +386,7 @@ } if (other->state == AST_BRIDGE_CHANNEL_STATE_WAIT) { - ast_write(other->chan, frame); + ast_bridge_handle_channel_write(bridge, other, frame); } return AST_BRIDGE_WRITE_SUCCESS; diff -ru asterisk-11.8.0.orig/bridges/bridge_simple.c asterisk-11.8.0/bridges/bridge_simple.c --- asterisk-11.8.0.orig/bridges/bridge_simple.c 2012-02-24 00:32:20.000000000 +0000 +++ asterisk-11.8.0/bridges/bridge_simple.c 2014-03-04 14:06:21.740645521 +0000 @@ -81,7 +81,7 @@ /* Write the frame out if they are in the waiting state... don't worry about freeing it, the bridging core will take care of it */ if (other->state == AST_BRIDGE_CHANNEL_STATE_WAIT) { - ast_write(other->chan, frame); + ast_bridge_handle_channel_write(bridge, other, frame); } return AST_BRIDGE_WRITE_SUCCESS; diff -ru asterisk-11.8.0.orig/bridges/bridge_softmix.c asterisk-11.8.0/bridges/bridge_softmix.c --- asterisk-11.8.0.orig/bridges/bridge_softmix.c 2013-09-18 17:17:13.000000000 +0000 +++ asterisk-11.8.0/bridges/bridge_softmix.c 2014-03-04 14:06:21.740645521 +0000 @@ -440,7 +440,7 @@ if (tmp == bridge_channel) { continue; } - ast_write(tmp->chan, frame); + ast_bridge_handle_channel_write(bridge, tmp, frame); } } @@ -452,7 +452,7 @@ continue; } if (ast_bridge_is_video_src(bridge, tmp->chan) == 1) { - ast_write(tmp->chan, frame); + ast_bridge_handle_channel_write(bridge, tmp, frame); break; } } @@ -468,7 +468,7 @@ if ((tmp->chan == bridge_channel->chan) && !echo) { continue; } - ast_write(tmp->chan, frame); + ast_bridge_handle_channel_write(bridge, tmp, frame); } } @@ -568,7 +568,7 @@ /* If a frame is ready to be written out, do so */ if (sc->have_frame) { - ast_write(bridge_channel->chan, &sc->write_frame); + ast_bridge_handle_channel_write(bridge, bridge_channel, &sc->write_frame); sc->have_frame = 0; } @@ -587,7 +587,7 @@ * the conference to the channel. */ ast_mutex_lock(&sc->lock); if (sc->have_frame) { - ast_write(bridge_channel->chan, &sc->write_frame); + ast_bridge_handle_channel_write(bridge, bridge_channel, &sc->write_frame); sc->have_frame = 0; } ast_mutex_unlock(&sc->lock); @@ -603,7 +603,7 @@ ast_mutex_lock(&sc->lock); if (sc->have_frame) { - ast_write(bridge_channel->chan, &sc->write_frame); + ast_bridge_handle_channel_write(bridge, bridge_channel, &sc->write_frame); sc->have_frame = 0; } @@ -855,16 +855,24 @@ 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); - } - 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); + 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, + ast_channel_rawwriteformat(bridge_channel->chan), sc); + } /* The frame is now ready for use... */ sc->have_frame = 1; Only in asterisk-11.8.0/bridges: bridge_softmix.c.orig diff -ru asterisk-11.8.0.orig/configs/confbridge.conf.sample asterisk-11.8.0/configs/confbridge.conf.sample --- asterisk-11.8.0.orig/configs/confbridge.conf.sample 2013-11-01 23:52:45.000000000 +0000 +++ asterisk-11.8.0/configs/confbridge.conf.sample 2014-03-04 14:07:44.938817169 +0000 @@ -20,6 +20,7 @@ ;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 @@ -217,6 +218,8 @@ ;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. @@ -275,6 +278,8 @@ ; 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. Only in asterisk-11.8.0/configs: confbridge.conf.sample.orig Only in asterisk-11.8.0/configs: confbridge.conf.sample.rej diff -ru asterisk-11.8.0.orig/include/asterisk/bridging_features.h asterisk-11.8.0/include/asterisk/bridging_features.h --- asterisk-11.8.0.orig/include/asterisk/bridging_features.h 2013-04-15 15:18:54.000000000 +0000 +++ asterisk-11.8.0/include/asterisk/bridging_features.h 2014-03-04 14:06:21.740645521 +0000 @@ -127,6 +127,8 @@ 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; diff -ru asterisk-11.8.0.orig/include/asterisk/bridging_technology.h asterisk-11.8.0/include/asterisk/bridging_technology.h --- asterisk-11.8.0.orig/include/asterisk/bridging_technology.h 2013-04-15 15:18:54.000000000 +0000 +++ asterisk-11.8.0/include/asterisk/bridging_technology.h 2014-03-04 14:06:21.740645521 +0000 @@ -143,6 +143,21 @@ */ void ast_bridge_handle_trip(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_channel *chan, int outfd); +/*! \brief Used by bridging technologies to hand off a frame to be written to a bridge_channel. + * + * \param bridge The bridge that the channel is part of. + * \param bridge_channel The bridge channel to which the frame is written to. + * \param frame The frame to write. + * + * \retval 0 on success + * \retval -1 on failure + * + * \note This function is essentially a wrapper for ast_write(). The bridging core has some features associated with it + * that requires it to have control over how frames are written into a channel. For these features to be available, the bridging + * technology must use this wrapper function over ast_write when pushing a frame out a channel. + */ +int ast_bridge_handle_channel_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame); + /*! \brief Lets the bridging indicate when a bridge channel has stopped or started talking. * * \note All DSP functionality on the bridge has been pushed down to the lowest possible diff -ru asterisk-11.8.0.orig/main/bridging.c asterisk-11.8.0/main/bridging.c --- asterisk-11.8.0.orig/main/bridging.c 2012-07-06 15:31:52.000000000 +0000 +++ asterisk-11.8.0/main/bridging.c 2014-03-04 14:06:21.740645521 +0000 @@ -337,6 +337,28 @@ return; } +int ast_bridge_handle_channel_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame) +{ + if (frame->frametype == AST_FRAME_VOICE && + (bridge->features.deaf || + (bridge_channel->features && bridge_channel->features->deaf))) { + short buf[frame->samples]; + struct ast_frame sframe = { + .frametype = AST_FRAME_VOICE, + .data.ptr = buf, + .samples = frame->samples, + .datalen = sizeof(buf), + }; + ast_format_set(&sframe.subclass.format, AST_FORMAT_SLINEAR, 0); + memset(buf, 0, sizeof(buf)); + + return ast_write(bridge_channel->chan, &sframe); + } + + return ast_write(bridge_channel->chan, frame); +} + + /*! \brief Generic thread loop, TODO: Rethink this/improve it */ static int generic_thread_loop(struct ast_bridge *bridge) {