Index: apps/app_confbridge.c
===================================================================
--- apps/app_confbridge.c	(revision 366036)
+++ apps/app_confbridge.c	(working copy)
@@ -709,6 +709,36 @@
 }
 
 /*!
+ * \brief Turns off MoH for a marked user when participants join
+ *
+ * \param conference_bridge Conference bridge being used
+ *
+ * \return Returns 0 on success or no-op, -1 on failure
+ */
+static int turn_off_marked_moh(struct conference_bridge *conference_bridge)
+{
+	/* Deal with the case where a marked user has hold-music while the conference is empty,
+	 * triggered by the departure and subsequent joining of other users. */
+	struct conference_bridge_user *first_participant = AST_LIST_FIRST(&conference_bridge->users_list);
+	if (conference_bridge->users == 2) {
+		/* Temporarily suspend the above participant from the bridge, if it's a marked user who can
+		 * be on hold, so we can turn off MoH if needed. */
+		if (ast_test_flag(&first_participant->u_profile, USER_OPT_MARKEDUSER) && ast_test_flag(&first_participant->u_profile, USER_OPT_MUSICONHOLD)) {
+			if (first_participant->playing_moh) {
+				if (!ast_bridge_suspend(conference_bridge->bridge, first_participant->chan)) {
+					first_participant->playing_moh = 0;
+					ast_moh_stop(first_participant->chan);
+					ast_bridge_unsuspend(conference_bridge->bridge, first_participant->chan);
+				} else {
+					return -1;
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+/*!
  * \brief Perform post-joining marked specific actions
  *
  * \param conference_bridge Conference bridge being joined
@@ -718,6 +748,8 @@
  */
 static int post_join_marked(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user)
 {
+	turn_off_marked_moh(conference_bridge);
+
 	if (ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_MARKEDUSER)) {
 		struct conference_bridge_user *other_conference_bridge_user = NULL;
 
@@ -732,7 +764,11 @@
 			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)) {
+			if (
+				other_conference_bridge_user->playing_moh &&
+				ast_test_flag(&other_conference_bridge_user->u_profile, USER_OPT_MUSICONHOLD) &&
+				!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);
@@ -775,15 +811,20 @@
 				return -1;
 			}
 		}
-		/* Start music on hold if needed */
-		/* 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;
-		}
 	}
+
+	/* Start music on hold if needed: MoH is enabled, the user waits for a marked user, and there are no marked users or the marked user is alone */
+	/* 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 (ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_MUSICONHOLD) &&
+		((ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_WAITMARKED) && !conference_bridge->markedusers) || conference_bridge->users == 1)) {
+			if (!conference_bridge_user->playing_moh) {
+				ast_moh_start(conference_bridge_user->chan, conference_bridge_user->u_profile.moh_class, NULL);
+				conference_bridge_user->playing_moh = 1;
+			}
+	}
+
 	return 0;
 }
 
@@ -797,7 +838,12 @@
  */
 static int post_join_unmarked(struct conference_bridge *conference_bridge, struct conference_bridge_user *conference_bridge_user)
 {
-	/* Play back audio prompt and start MOH if need be if we are the first participant */
+	/* If there are any other users without WAITMARKED set, but with MUSICONHOLD, take them off-hold
+	 * now. */
+	int nonwaiting_participants = 0; /* The number of other participants free of marked-user restrictions */
+	struct conference_bridge_user *other_conference_bridge_user = NULL;
+
+	/* Play back audio prompt 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 */
 		if (!ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_QUIET | USER_OPT_NOONLYPERSON)) {
@@ -808,16 +854,30 @@
 				return -1;
 			}
 		}
-		/* If we need to start music on hold on the channel do so now */
-		/* We need to re-check the number of users in the conference bridge here because another conference bridge
-		 * participant could have joined while the above prompt was playing for the first user.
-		 */
-		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;
+	}
+
+	AST_LIST_TRAVERSE(&conference_bridge->users_list, other_conference_bridge_user, list) {
+		if (other_conference_bridge_user == conference_bridge_user) {
+			continue;
 		}
-		return 0;
+		if (!ast_test_flag(&other_conference_bridge_user->u_profile, USER_OPT_WAITMARKED) ||
+			ast_test_flag(&other_conference_bridge_user->u_profile, USER_OPT_MARKEDUSER)) {
+				nonwaiting_participants += 1;
+				if (other_conference_bridge_user->playing_moh &&
+					ast_test_flag(&other_conference_bridge_user->u_profile, USER_OPT_MUSICONHOLD) &&
+					!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);
+				}
+		}
 	}
+	/* If there are no other unblocked users and if this user has MUSICONHOLD, turn on MoH. */
+	if (!nonwaiting_participants && 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;
+		return 0; /* No point in announcing participant-count if the user is on hold */
+	}
 
 	/* Announce number of users if need be */
 	if (ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_ANNOUNCEUSERCOUNT)) {
@@ -829,18 +889,6 @@
 		ao2_lock(conference_bridge);
 	}
 
-	/* If we are the second participant we may need to stop music on hold on the first */
-	if (conference_bridge->users == 2) {
-		struct conference_bridge_user *first_participant = AST_LIST_FIRST(&conference_bridge->users_list);
-
-		/* Temporarily suspend the above participant from the bridge so we have control to stop MOH if needed */
-		if (ast_test_flag(&first_participant->u_profile, USER_OPT_MUSICONHOLD) && !ast_bridge_suspend(conference_bridge->bridge, first_participant->chan)) {
-			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_ANNOUNCEUSERCOUNTALL) &&
 		(conference_bridge->users > conference_bridge_user->u_profile.announce_user_count_all_after)) {
 		ao2_unlock(conference_bridge);
@@ -1046,13 +1094,16 @@
 
 	/* If there are still users in the conference bridge we may need to do things (such as start MOH on them) */
 	if (conference_bridge->users) {
+		int nonwaiting_participants = 0; /* The number of participants not blocking on the presence of a marked user */
+		struct conference_bridge_user *other_participant = NULL;
+
 		if (ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_MARKEDUSER) && !conference_bridge->markedusers) {
-			struct conference_bridge_user *other_participant = NULL;
-
-			/* Start out with muting everyone */
+			/* Start out with muting everyone with WAITMARKED */
 			AST_LIST_TRAVERSE(&conference_bridge->users_list, other_participant, list) {
-				other_participant->features.mute = 1;
-			}
+				if (ast_test_flag(&other_participant->u_profile, USER_OPT_WAITMARKED)) {
+					other_participant->features.mute = 1;
+				}
+        		}
 
 			/* Play back the audio prompt saying the leader has left the conference */
 			if (!ast_test_flag(&conference_bridge_user->u_profile, USER_OPT_QUIET)) {
@@ -1064,27 +1115,40 @@
 				ao2_lock(conference_bridge);
 			}
 
-			/* Now on to starting MOH or kick if needed */
+			/* Now on kicking participants, if needed */
 			AST_LIST_TRAVERSE(&conference_bridge->users_list, other_participant, list) {
 				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)) {
-					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);
 				}
 			}
-		} else if (conference_bridge->users == 1) {
-			/* Of course if there is one other person in here we may need to start up MOH on them */
-			struct conference_bridge_user *first_participant = AST_LIST_FIRST(&conference_bridge->users_list);
+		}
 
-			if (ast_test_flag(&first_participant->u_profile, USER_OPT_MUSICONHOLD) && !ast_bridge_suspend(conference_bridge->bridge, first_participant->chan)) {
-				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);
+		/* For anyone left, MoH may need to be turned on, so gather statistics */
+		if (!conference_bridge->markedusers) { /* Only count them if there are no marked users */
+			AST_LIST_TRAVERSE(&conference_bridge->users_list, other_participant, list) {
+				if (!other_participant->kicked && !ast_test_flag(&other_participant->u_profile, USER_OPT_WAITMARKED)) {
+					nonwaiting_participants += 1;
+				}
 			}
 		}
+		/* Enable MoH for anyone who should hear it */
+		AST_LIST_TRAVERSE(&conference_bridge->users_list, other_participant, list) {
+			if (!other_participant->kicked && ast_test_flag(&other_participant->u_profile, USER_OPT_MUSICONHOLD)) {
+				if (conference_bridge->users > 1) { /* If there's only one user, hold music can't be skipped */
+					if (!ast_test_flag(&other_participant->u_profile, USER_OPT_WAITMARKED) && (conference_bridge->markedusers || nonwaiting_participants >= 2)) {
+						continue; /* All conditions needed to enable speech are satisfied */
+					} else if (ast_test_flag(&other_participant->u_profile, USER_OPT_WAITMARKED) && conference_bridge->markedusers) {
+						continue; /* Waiting for marked user and one's already here */
+					}
+				}
+				if (!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);
+			        }
+			}
+		}
 	} else {
 		/* Set device state to "not in use" */
 		ast_devstate_changed(AST_DEVICE_NOT_INUSE, "confbridge:%s", conference_bridge->name);

