From: Richard Mudgett Date: Sat, 2 Nov 2013 02:11:03 +0000 (+0000) Subject: confbridge: Separate user muting from system muting overrides. X-Git-Tag: certified/11.6-cert13~10^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=53e23608d1d2a0472c8c99efa85dbfe0e8e964bd;p=thirdparty%2Fasterisk.git confbridge: Separate user muting from system muting overrides. The system overrides the user muting requests when MOH is playing or a waitmarked user is waiting for a marked user to join. System muting overrides interfere with what the user may wish the muting to be when the system override ends. * User muting requests are now independent of the system muting overrides. The effective muting is now the logical or of the user request and system override. * Added a Muted column to the CLI "confbridge list " command. * Added a Muted header to the AMI ConfbridgeList action ConfbridgeList event. (closes issue AST-1102) Reported by: John Bigelow Review: https://reviewboard.asterisk.org/r/2960/ Cherry-picked to support ASTERISK-20987 Change-Id: Iec7bd77736847af6a5f70b8d279f85c6e2082ee2 --- diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c index b08af5368a..ef27a2eefc 100644 --- a/apps/app_confbridge.c +++ b/apps/app_confbridge.c @@ -960,6 +960,32 @@ static int handle_conf_user_leave(struct conference_bridge_user *cbu) return 0; } +void conf_update_user_mute(struct conference_bridge_user *user) +{ + int mute_user; + int mute_system; + int mute_effective; + + /* User level mute request. */ + mute_user = user->muted; + + /* System level mute request. */ + mute_system = user->playing_moh + /* + * Do not allow waitmarked users to talk to anyone unless there + * is a marked user present. + */ + || (!user->conference_bridge->markedusers + && ast_test_flag(&user->u_profile, USER_OPT_WAITMARKED)); + + mute_effective = mute_user || mute_system; + + ast_debug(1, "User %s is %s: user:%d system:%d.\n", + ast_channel_name(user->chan), mute_effective ? "muted" : "unmuted", + mute_user, mute_system); + user->features.mute = mute_effective; +} + void conf_moh_stop(struct conference_bridge_user *user) { user->playing_moh = 0; @@ -1105,9 +1131,7 @@ void conf_handle_second_active(struct conference_bridge *conference_bridge) if (ast_test_flag(&first_participant->u_profile, USER_OPT_MUSICONHOLD)) { conf_moh_stop(first_participant); } - if (!ast_test_flag(&first_participant->u_profile, USER_OPT_STARTMUTED)) { - first_participant->features.mute = 0; - } + conf_update_user_mute(first_participant); } void conf_ended(struct conference_bridge *conference_bridge) @@ -1652,7 +1676,8 @@ static int confbridge_exec(struct ast_channel *chan, const char *data) /* 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; + /* Set user level mute request. */ + conference_bridge_user.muted = 1; } if (ast_test_flag(&conference_bridge_user.u_profile, USER_OPT_DROP_SILENCE)) { @@ -1769,12 +1794,23 @@ static int action_toggle_mute(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user, struct ast_channel *chan) { - /* 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); - 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 ? + int mute; + + /* Toggle user level mute request. */ + mute = !conference_bridge_user->muted; + conference_bridge_user->muted = mute; + + conf_update_user_mute(conference_bridge_user); + ast_test_suite_event_notify("CONF_MUTE", + "Message: participant %s %s\r\n" + "Conference: %s\r\n" + "Channel: %s", + ast_channel_name(chan), + mute ? "muted" : "unmuted", + conference_bridge_user->b_profile.name, + ast_channel_name(chan)); + + return ast_stream_and_wait(chan, (mute ? conf_get_sound(CONF_SOUND_MUTED, conference_bridge_user->b_profile.sounds) : conf_get_sound(CONF_SOUND_UNMUTED, conference_bridge_user->b_profile.sounds)), ""); @@ -1784,22 +1820,27 @@ static int action_toggle_mute_participants(struct conference_bridge *conference_ { struct conference_bridge_user *participant = NULL; const char *sound_to_play; + int mute; ao2_lock(conference_bridge); - /* If already muted, then unmute */ - conference_bridge->muted = conference_bridge->muted ? 0 : 1; - sound_to_play = conf_get_sound((conference_bridge->muted ? CONF_SOUND_PARTICIPANTS_MUTED : CONF_SOUND_PARTICIPANTS_UNMUTED), - conference_bridge_user->b_profile.sounds); + /* Toggle bridge level mute request. */ + mute = !conference_bridge->muted; + conference_bridge->muted = mute; AST_LIST_TRAVERSE(&conference_bridge->active_list, participant, list) { if (!ast_test_flag(&participant->u_profile, USER_OPT_ADMIN)) { - participant->features.mute = conference_bridge->muted; + /* Set user level to bridge level mute request. */ + participant->muted = mute; + conf_update_user_mute(participant); } } ao2_unlock(conference_bridge); + sound_to_play = conf_get_sound((mute ? CONF_SOUND_PARTICIPANTS_MUTED : CONF_SOUND_PARTICIPANTS_UNMUTED), + conference_bridge_user->b_profile.sounds); + /* The host needs to hear it seperately, as they don't get the audio from play_sound_helper */ ast_stream_and_wait(conference_bridge_user->chan, sound_to_play, ""); @@ -2219,12 +2260,14 @@ static char *handle_cli_confbridge_kick(struct ast_cli_entry *e, int cmd, struct static void handle_cli_confbridge_list_item(struct ast_cli_args *a, struct conference_bridge_user *participant) { - ast_cli(a->fd, "%-29s ", ast_channel_name(participant->chan)); - ast_cli(a->fd, "%-17s", participant->u_profile.name); - ast_cli(a->fd, "%-17s", participant->b_profile.name); - ast_cli(a->fd, "%-17s", participant->menu_name); - ast_cli(a->fd, "%-17s", S_COR(ast_channel_caller(participant->chan)->id.number.valid, ast_channel_caller(participant->chan)->id.number.str, "")); - ast_cli(a->fd, "\n"); + ast_cli(a->fd, "%-30s %-16s %-16s %-16s %-16s %s\n", + ast_channel_name(participant->chan), + participant->u_profile.name, + participant->b_profile.name, + participant->menu_name, + S_COR(ast_channel_caller(participant->chan)->id.number.valid, + ast_channel_caller(participant->chan)->id.number.str, ""), + AST_CLI_YESNO(participant->muted)); } static char *handle_cli_confbridge_list(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) @@ -2267,8 +2310,8 @@ static char *handle_cli_confbridge_list(struct ast_cli_entry *e, int cmd, struct ast_cli(a->fd, "No conference bridge named '%s' found!\n", a->argv[2]); return CLI_SUCCESS; } - ast_cli(a->fd, "Channel User Profile Bridge Profile Menu CallerID\n"); - ast_cli(a->fd, "============================= ================ ================ ================ ================\n"); + ast_cli(a->fd, "Channel User Profile Bridge Profile Menu CallerID Muted\n"); + ast_cli(a->fd, "============================== ================ ================ ================ ================ =====\n"); ao2_lock(bridge); AST_LIST_TRAVERSE(&bridge->active_list, participant, list) { handle_cli_confbridge_list_item(a, participant); @@ -2335,8 +2378,18 @@ static int generic_mute_unmute_helper(int mute, const char *conference, const ch } } if (participant) { - participant->features.mute = mute; - 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)); + /* 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)); } else { res = -2;; } @@ -2596,6 +2649,7 @@ static void action_confbridgelist_item(struct mansession *s, const char *id_text "Channel: %s\r\n" "Admin: %s\r\n" "MarkedUser: %s\r\n" + "Muted: %s\r\n" "\r\n", id_text, bridge->name, @@ -2603,7 +2657,8 @@ static void action_confbridgelist_item(struct mansession *s, const char *id_text S_COR(ast_channel_caller(participant->chan)->id.name.valid, ast_channel_caller(participant->chan)->id.name.str, ""), ast_channel_name(participant->chan), ast_test_flag(&participant->u_profile, USER_OPT_ADMIN) ? "Yes" : "No", - ast_test_flag(&participant->u_profile, USER_OPT_MARKEDUSER) ? "Yes" : "No"); + ast_test_flag(&participant->u_profile, USER_OPT_MARKEDUSER) ? "Yes" : "No", + participant->muted ? "Yes" : "No"); } static int action_confbridgelist(struct mansession *s, const struct message *m) @@ -3051,11 +3106,11 @@ void conf_mute_only_active(struct conference_bridge *conference_bridge) { struct conference_bridge_user *only_participant = AST_LIST_FIRST(&conference_bridge->active_list); - /* Turn on MOH/mute if the single participant is set up for it */ + /* Turn on MOH if the single participant is set up for it */ if (ast_test_flag(&only_participant->u_profile, USER_OPT_MUSICONHOLD)) { - only_participant->features.mute = 1; conf_moh_start(only_participant); } + conf_update_user_mute(only_participant); } void conf_remove_user_waiting(struct conference_bridge *conference_bridge, struct conference_bridge_user *cbu) diff --git a/apps/confbridge/conf_state.c b/apps/confbridge/conf_state.c index ea5ab10f08..5b3893f24d 100644 --- a/apps/confbridge/conf_state.c +++ b/apps/confbridge/conf_state.c @@ -57,12 +57,11 @@ void conf_invalid_event_fn(struct conference_bridge_user *cbu) */ static void conf_mute_moh_inactive_waitmarked(struct conference_bridge_user *user) { - /* Be sure we are muted so we can't talk to anybody else waiting */ - user->features.mute = 1; /* Start music on hold if needed */ if (ast_test_flag(&user->u_profile, USER_OPT_MUSICONHOLD)) { conf_moh_start(user); } + conf_update_user_mute(user); } void conf_default_join_waitmarked(struct conference_bridge_user *cbu) diff --git a/apps/confbridge/conf_state_inactive.c b/apps/confbridge/conf_state_inactive.c index 80210fcb82..31cc6f1701 100644 --- a/apps/confbridge/conf_state_inactive.c +++ b/apps/confbridge/conf_state_inactive.c @@ -61,7 +61,7 @@ static void join_unmarked(struct conference_bridge_user *cbu) static void join_marked(struct conference_bridge_user *cbu) { conf_add_user_marked(cbu->conference_bridge, cbu); - conf_handle_second_active(cbu->conference_bridge); + conf_update_user_mute(cbu); conf_change_state(cbu, CONF_STATE_MULTI_MARKED); } diff --git a/apps/confbridge/conf_state_multi.c b/apps/confbridge/conf_state_multi.c index 5dcd8f4129..689db8a34d 100644 --- a/apps/confbridge/conf_state_multi.c +++ b/apps/confbridge/conf_state_multi.c @@ -54,11 +54,13 @@ struct conference_state *CONF_STATE_MULTI = &STATE_MULTI; static void join_unmarked(struct conference_bridge_user *cbu) { conf_add_user_active(cbu->conference_bridge, cbu); + conf_update_user_mute(cbu); } static void join_marked(struct conference_bridge_user *cbu) { conf_add_user_marked(cbu->conference_bridge, cbu); + conf_update_user_mute(cbu); conf_change_state(cbu, CONF_STATE_MULTI_MARKED); } diff --git a/apps/confbridge/conf_state_multi_marked.c b/apps/confbridge/conf_state_multi_marked.c index ff4b38d4ae..6089ac6f02 100644 --- a/apps/confbridge/conf_state_multi_marked.c +++ b/apps/confbridge/conf_state_multi_marked.c @@ -60,11 +60,13 @@ struct conference_state *CONF_STATE_MULTI_MARKED = &STATE_MULTI_MARKED; static void join_active(struct conference_bridge_user *cbu) { conf_add_user_active(cbu->conference_bridge, cbu); + conf_update_user_mute(cbu); } static void join_marked(struct conference_bridge_user *cbu) { conf_add_user_marked(cbu->conference_bridge, cbu); + conf_update_user_mute(cbu); } static void leave_active(struct conference_bridge_user *cbu) @@ -88,8 +90,8 @@ static void leave_marked(struct conference_bridge_user *cbu) AST_LIST_TRAVERSE_SAFE_BEGIN(&cbu->conference_bridge->active_list, cbu_iter, list) { /* Kick ENDMARKED cbu_iters */ if (ast_test_flag(&cbu_iter->u_profile, USER_OPT_ENDMARKED) && !cbu_iter->kicked) { - if (ast_test_flag(&cbu_iter->u_profile, USER_OPT_WAITMARKED) && - !ast_test_flag(&cbu_iter->u_profile, USER_OPT_MARKEDUSER)) { + if (ast_test_flag(&cbu_iter->u_profile, USER_OPT_WAITMARKED) + && !ast_test_flag(&cbu_iter->u_profile, USER_OPT_MARKEDUSER)) { AST_LIST_REMOVE_CURRENT(list); cbu_iter->conference_bridge->activeusers--; AST_LIST_INSERT_TAIL(&cbu_iter->conference_bridge->waiting_list, cbu_iter, list); @@ -97,17 +99,18 @@ static void leave_marked(struct conference_bridge_user *cbu) } cbu_iter->kicked = 1; ast_bridge_remove(cbu_iter->conference_bridge->bridge, cbu_iter->chan); - } else if (ast_test_flag(&cbu_iter->u_profile, USER_OPT_WAITMARKED) && - !ast_test_flag(&cbu_iter->u_profile, USER_OPT_MARKEDUSER)) { + } else if (ast_test_flag(&cbu_iter->u_profile, USER_OPT_WAITMARKED) + && !ast_test_flag(&cbu_iter->u_profile, USER_OPT_MARKEDUSER)) { AST_LIST_REMOVE_CURRENT(list); cbu_iter->conference_bridge->activeusers--; AST_LIST_INSERT_TAIL(&cbu_iter->conference_bridge->waiting_list, cbu_iter, list); cbu_iter->conference_bridge->waitingusers++; - /* Handle muting/moh of cbu_iter if necessary */ + + /* Handle moh of cbu_iter if necessary */ if (ast_test_flag(&cbu_iter->u_profile, USER_OPT_MUSICONHOLD)) { - cbu_iter->features.mute = 1; conf_moh_start(cbu_iter); } + conf_update_user_mute(cbu_iter); } } AST_LIST_TRAVERSE_SAFE_END; @@ -175,7 +178,7 @@ static void transition_to_marked(struct conference_bridge_user *cbu) conf_handle_first_marked_common(cbu); } - /* Move all waiting users to active, stopping MOH and umuting if necessary */ + /* Move all waiting users to active, stopping MOH and unmuting if necessary */ AST_LIST_TRAVERSE_SAFE_BEGIN(&cbu->conference_bridge->waiting_list, cbu_iter, list) { AST_LIST_REMOVE_CURRENT(list); cbu->conference_bridge->waitingusers--; @@ -184,10 +187,7 @@ static void transition_to_marked(struct conference_bridge_user *cbu) if (cbu_iter->playing_moh) { conf_moh_stop(cbu_iter); } - /* only unmute them if they are not supposed to start muted */ - if (!ast_test_flag(&cbu_iter->u_profile, USER_OPT_STARTMUTED)) { - cbu_iter->features.mute = 0; - } + conf_update_user_mute(cbu_iter); } AST_LIST_TRAVERSE_SAFE_END; } diff --git a/apps/confbridge/conf_state_single.c b/apps/confbridge/conf_state_single.c index 806ed637be..4dd8d564c2 100644 --- a/apps/confbridge/conf_state_single.c +++ b/apps/confbridge/conf_state_single.c @@ -55,6 +55,7 @@ static void join_unmarked(struct conference_bridge_user *cbu) { conf_add_user_active(cbu->conference_bridge, cbu); conf_handle_second_active(cbu->conference_bridge); + conf_update_user_mute(cbu); conf_change_state(cbu, CONF_STATE_MULTI); } @@ -63,6 +64,7 @@ static void join_marked(struct conference_bridge_user *cbu) { conf_add_user_marked(cbu->conference_bridge, cbu); conf_handle_second_active(cbu->conference_bridge); + conf_update_user_mute(cbu); conf_change_state(cbu, CONF_STATE_MULTI_MARKED); } diff --git a/apps/confbridge/conf_state_single_marked.c b/apps/confbridge/conf_state_single_marked.c index a7ac57816e..3a64a74d00 100644 --- a/apps/confbridge/conf_state_single_marked.c +++ b/apps/confbridge/conf_state_single_marked.c @@ -54,6 +54,7 @@ static void join_active(struct conference_bridge_user *cbu) { conf_add_user_active(cbu->conference_bridge, cbu); conf_handle_second_active(cbu->conference_bridge); + conf_update_user_mute(cbu); conf_change_state(cbu, CONF_STATE_MULTI_MARKED); } @@ -62,6 +63,7 @@ static void join_marked(struct conference_bridge_user *cbu) { conf_add_user_marked(cbu->conference_bridge, cbu); conf_handle_second_active(cbu->conference_bridge); + conf_update_user_mute(cbu); conf_change_state(cbu, CONF_STATE_MULTI_MARKED); } diff --git a/apps/confbridge/include/confbridge.h b/apps/confbridge/include/confbridge.h index f9fc93d900..50e223e2de 100644 --- a/apps/confbridge/include/confbridge.h +++ b/apps/confbridge/include/confbridge.h @@ -210,7 +210,7 @@ struct conference_bridge { unsigned int markedusers; /*!< Number of marked users present */ unsigned int waitingusers; /*!< Number of waiting users present */ unsigned int locked:1; /*!< Is this conference bridge locked? */ - unsigned int muted:1; /*!< Is this conference bridge muted? */ + unsigned int muted:1; /*!< Is this conference bridge muted? */ unsigned int record_state:2; /*!< Whether recording is started, stopped, or should exit */ struct ast_channel *playback_chan; /*!< Channel used for playback into the conference bridge */ struct ast_channel *record_chan; /*!< Channel used for recording the conference */ @@ -238,6 +238,7 @@ struct conference_bridge_user { struct ast_bridge_features features; /*!< Bridge features structure */ struct ast_bridge_tech_optimizations tech_args; /*!< Bridge technology optimizations for talk detection */ unsigned int suspended_moh; /*!< Count of active suspended MOH actions. */ + unsigned int muted:1; /*!< Has the user requested to be muted? */ unsigned int kicked:1; /*!< User has been kicked from the conference */ unsigned int playing_moh:1; /*!< MOH is currently being played to the user */ AST_LIST_HEAD_NOLOCK(, post_join_action) post_join_list; /*!< List of sounds to play after joining */; @@ -363,6 +364,15 @@ int play_sound_file(struct conference_bridge *conference_bridge, const char *fil */ void conf_ended(struct conference_bridge *conference_bridge); +/*! + * \brief Update the actual mute status of the user and set it on the bridge. + * + * \param user User to update the mute status. + * + * \return Nothing + */ +void conf_update_user_mute(struct conference_bridge_user *user); + /*! * \brief Stop MOH for the conference user. *