Index: apps/confbridge/include/confbridge.h =================================================================== --- apps/confbridge/include/confbridge.h (revision 368946) +++ apps/confbridge/include/confbridge.h (working copy) @@ -57,6 +57,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_MOH_IMPLIES_MUTE = (1 << 16), /*!< Ensures that the user is muted whenever MoH is enabled. */ }; enum bridge_profile_flags { @@ -135,6 +136,8 @@ unsigned int talking_threshold; /*! The time in ms of silence before a user is considered to be silent by the dsp. */ unsigned int silence_threshold; + /*! Causes muting to follow when MoH is enabled. */ + unsigned int moh_implies_mute; int delme; }; @@ -229,6 +232,7 @@ struct ast_bridge_tech_optimizations tech_args; /*!< Bridge technology optimizations for talk detection */ unsigned int kicked:1; /*!< User has been kicked from the conference */ unsigned int playing_moh:1; /*!< MOH is currently being played to the user */ + unsigned int mute_forced:1; /*!< The user has been explicitly muted and should not be subject to automatic toggles */ AST_LIST_ENTRY(conference_bridge_user) list; /*!< Linked list information */ }; Index: apps/confbridge/conf_config_parser.c =================================================================== --- apps/confbridge/conf_config_parser.c (revision 368946) +++ apps/confbridge/conf_config_parser.c (working copy) @@ -207,6 +207,8 @@ } } else if (!strcasecmp(name, "jitterbuffer")) { ast_set2_flag(u_profile, ast_true(value), USER_OPT_JITTERBUFFER); + } else if (!strcasecmp(name, "moh_implies_mute")) { + ast_set2_flag(u_profile, ast_true(value), USER_OPT_MOH_IMPLIES_MUTE); } else { return -1; } @@ -862,6 +864,9 @@ ast_cli(a->fd,"MOH When Empty: %s\n", u_profile.flags & USER_OPT_MUSICONHOLD ? "enabled" : "disabled"); + ast_cli(a->fd,"MOH implies mute: %s\n", + u_profile.flags & USER_OPT_MOH_IMPLIES_MUTE ? + "yes" : "no"); ast_cli(a->fd,"MOH Class: %s\n", ast_strlen_zero(u_profile.moh_class) ? "default" : u_profile.moh_class); Index: apps/app_confbridge.c =================================================================== --- apps/app_confbridge.c (revision 368946) +++ apps/app_confbridge.c (working copy) @@ -731,19 +731,7 @@ return 0; } - /* Iterate through every participant stopping MOH on them if need be */ - AST_LIST_TRAVERSE(&conference_bridge->users_list, other_conference_bridge_user, list) { - if (other_conference_bridge_user == conference_bridge_user) { - continue; - } - if (other_conference_bridge_user->playing_moh && !ast_bridge_suspend(conference_bridge->bridge, other_conference_bridge_user->chan)) { - other_conference_bridge_user->playing_moh = 0; - ast_moh_stop(other_conference_bridge_user->chan); - ast_bridge_unsuspend(conference_bridge->bridge, other_conference_bridge_user->chan); - } - } - - /* Next play the audio file stating they are going to be placed into the conference */ + /* Play the audio file stating they are going to be placed into the conference */ if (!ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_QUIET)) { if (play_prompt_to_channel(conference_bridge, conference_bridge_user->chan, @@ -753,13 +741,18 @@ } } - /* Finally iterate through and unmute them all */ + /* Finally iterate through and unmute/stop MoH on them all */ AST_LIST_TRAVERSE(&conference_bridge->users_list, other_conference_bridge_user, list) { if (other_conference_bridge_user == conference_bridge_user) { continue; } - /* only unmute them if they are not supposed to start muted */ - if (!ast_test_flag(&other_conference_bridge_user->u_profile, USER_OPT_STARTMUTED)) { + if (other_conference_bridge_user->playing_moh && !ast_bridge_suspend(conference_bridge->bridge, other_conference_bridge_user->chan)) { + other_conference_bridge_user->playing_moh = 0; + ast_moh_stop(other_conference_bridge_user->chan); + ast_bridge_unsuspend(conference_bridge->bridge, other_conference_bridge_user->chan); + } + /* Only unmute them if they are not supposed to be muted */ + if (!other_conference_bridge_user->mute_forced) { other_conference_bridge_user->features.mute = 0; } } @@ -768,8 +761,7 @@ if (conference_bridge->markedusers) { return 0; } - /* Be sure we are muted so we can't talk to anybody else waiting */ - conference_bridge_user->features.mute = 1; + /* If we have not been quieted play back that they are waiting for the leader */ if (!ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_QUIET)) { if (play_prompt_to_channel(conference_bridge, @@ -783,9 +775,14 @@ /* We need to recheck the markedusers value here. play_prompt_to_channel unlocks the conference bridge, potentially * allowing a marked user to enter while the prompt was playing */ - if (!conference_bridge->markedusers && ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_MUSICONHOLD)) { - ast_moh_start(conference_bridge_user->chan, conference_bridge_user->u_profile.moh_class, NULL); - conference_bridge_user->playing_moh = 1; + if (!conference_bridge->markedusers) { + if (ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_MUSICONHOLD)) { + ast_moh_start(conference_bridge_user->chan, conference_bridge_user->u_profile.moh_class, NULL); + conference_bridge_user->playing_moh = 1; + if (ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_MOH_IMPLIES_MUTE)){ + conference_bridge_user->features.mute = 1; + } + } } } return 0; @@ -801,6 +798,7 @@ */ static int post_join_unmarked(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user) { + if(conference_bridge_user->features.mute)ast_verb(1, "muted\n"); /* Play back audio prompt and start MOH if need be if we are the first participant */ if (conference_bridge->users == 1) { /* If audio prompts have not been quieted or this prompt quieted play it on out */ @@ -819,6 +817,9 @@ if (conference_bridge->users == 1 && ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_MUSICONHOLD)) { ast_moh_start(conference_bridge_user->chan, conference_bridge_user->u_profile.moh_class, NULL); conference_bridge_user->playing_moh = 1; + if (ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_MOH_IMPLIES_MUTE)) { + conference_bridge_user->features.mute = 1; + } } return 0; } @@ -842,6 +843,9 @@ first_participant->playing_moh = 0; ast_moh_stop(first_participant->chan); ast_bridge_unsuspend(conference_bridge->bridge, first_participant->chan); + if (ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_MOH_IMPLIES_MUTE) && !conference_bridge_user->mute_forced) { + conference_bridge_user->features.mute = 0; + } } } @@ -1084,10 +1088,18 @@ if (ast_test_flag(&other_participant->u_profile, USER_OPT_ENDMARKED)) { other_participant->kicked = 1; ast_bridge_remove(conference_bridge->bridge, other_participant->chan); - } else if (ast_test_flag(&other_participant->u_profile, USER_OPT_MUSICONHOLD) && !ast_bridge_suspend(conference_bridge->bridge, other_participant->chan)) { + } else if (ast_test_flag(&other_participant->u_profile, USER_OPT_MUSICONHOLD) && !other_participant->playing_moh && !ast_bridge_suspend(conference_bridge->bridge, other_participant->chan)) { ast_moh_start(other_participant->chan, other_participant->u_profile.moh_class, NULL); other_participant->playing_moh = 1; ast_bridge_unsuspend(conference_bridge->bridge, other_participant->chan); + if (ast_test_flag(&other_participant->u_profile, USER_OPT_MOH_IMPLIES_MUTE)) { + other_participant->features.mute = 1; + } + } else { + /* If users are left in the conference that don't require a marked user and aren't muted, be sure to unmute them */ + if (!ast_test_flag(&other_participant->u_profile, USER_OPT_WAITMARKED) && !other_participant->mute_forced) { + other_participant->features.mute = 0; + } } } } else if (conference_bridge->users == 1) { @@ -1098,6 +1110,9 @@ ast_moh_start(first_participant->chan, first_participant->u_profile.moh_class, NULL); first_participant->playing_moh = 1; ast_bridge_unsuspend(conference_bridge->bridge, first_participant->chan); + if (ast_test_flag(&first_participant->u_profile, USER_OPT_MOH_IMPLIES_MUTE)) { + first_participant->features.mute = 1; + } } } } else { @@ -1321,6 +1336,12 @@ return 0; } +static void user_set_mute_forced(int mute, struct conference_bridge_user *conference_bridge_user) +{ + conference_bridge_user->features.mute = mute; + conference_bridge_user->mute_forced = mute; +} + /*! \brief The ConfBridge application */ static int confbridge_exec(struct ast_channel *chan, const char *data) { @@ -1444,7 +1465,7 @@ /* If the caller should be joined already muted, make it so */ if (ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_STARTMUTED)) { - conference_bridge_user.features.mute = 1; + user_set_mute_forced(1, &conference_bridge_user); } if (ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_DROP_SILENCE)) { @@ -1567,6 +1588,7 @@ /* Mute or unmute yourself, note we only allow manipulation if they aren't waiting for a marked user or if marked users exist */ if (!ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_WAITMARKED) || conference_bridge->markedusers) { conference_bridge_user->features.mute = (!conference_bridge_user->features.mute ? 1 : 0); + user_set_mute_forced(!conference_bridge_user->features.mute, conference_bridge_user); ast_test_suite_event_notify("CONF_MUTE", "Message: participant %s %s\r\nConference: %s\r\nChannel: %s", ast_channel_name(chan), conference_bridge_user->features.mute ? "muted" : "unmuted", conference_bridge_user->b_profile.name, ast_channel_name(chan)); } return ast_stream_and_wait(chan, (conference_bridge_user->features.mute ? @@ -1590,6 +1612,7 @@ AST_LIST_TRAVERSE(&conference_bridge->users_list, participant, list) { if (!ast_test_flag(&participant->u_profile, USER_OPT_ADMIN)) { participant->features.mute = conference_bridge->muted; + user_set_mute_forced(!participant->features.mute, participant); } } @@ -2057,7 +2080,7 @@ } /* \internal - * \brief finds a conference user by channel name and mutes/unmutes them. + * \brief finds a conference user by channel name and forcibly mutes/unmutes them. * * \retval 0 success * \retval -1 conference not found @@ -2081,7 +2104,7 @@ } } if (participant) { - participant->features.mute = mute; + user_set_mute_forced(mute, participant); ast_test_suite_event_notify("CONF_MUTE", "Message: participant %s %s\r\nConference: %s\r\nChannel: %s", ast_channel_name(participant->chan), participant->features.mute ? "muted" : "unmuted", bridge->b_profile.name, ast_channel_name(participant->chan)); } else { res = -2;;