]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
confbridge: Separate user muting from system muting overrides. 18/2118/1
authorRichard Mudgett <rmudgett@digium.com>
Sat, 2 Nov 2013 02:11:03 +0000 (02:11 +0000)
committerRichard Mudgett <rmudgett@digium.com>
Wed, 27 Jan 2016 23:21:48 +0000 (17:21 -0600)
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 <conference>" 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

apps/app_confbridge.c
apps/confbridge/conf_state.c
apps/confbridge/conf_state_inactive.c
apps/confbridge/conf_state_multi.c
apps/confbridge/conf_state_multi_marked.c
apps/confbridge/conf_state_single.c
apps/confbridge/conf_state_single_marked.c
apps/confbridge/include/confbridge.h

index b08af5368aa922828076d14df8ca62e71ec4be48..ef27a2eefcf9f2a58c162330af84281bbd60c5a8 100644 (file)
@@ -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, "<unknown>"));
-       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, "<unknown>"),
+               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, "<no name>"),
                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)
index ea5ab10f0810c8e8f6879b0041567b00823a49a6..5b3893f24d23de0d11fb39ea8dfdc949cffa903e 100644 (file)
@@ -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)
index 80210fcb82ed01f6228c00bd2a2fb234cd963833..31cc6f17019290db4e750d7802646e67c7d1f6e1 100644 (file)
@@ -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);
 }
index 5dcd8f4129b8994308b5f5980110f98490afcee7..689db8a34dc0a2617ebcc5bf2d600bd82b436459 100644 (file)
@@ -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);
 }
index ff4b38d4ae9fc8d406926205522ad7d6eee97bac..6089ac6f02575ff6f7ac67e0624bcdd7b434c0ee 100644 (file)
@@ -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;
 }
index 806ed637bec65d117e277bf436753f7f9570dc33..4dd8d564c21423c3cfdf11bf5ba792daa39ecb57 100644 (file)
@@ -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);
 }
index a7ac57816ea9f22cb796b79622fc19785f7285b3..3a64a74d009d2a2e5c0b64b1812b71f05f27b336 100644 (file)
@@ -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);
 }
index f9fc93d9008c6f8ae8f02f4649c0283581eef444..50e223e2dec5199fb3e580985aea4fdf577c1712 100644 (file)
@@ -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.
  *