conf_state_multi_marked.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2012, Terry Wilson
  5. *
  6. * Terry Wilson <twilson@digium.com>
  7. *
  8. * See http://www.asterisk.org for more information about
  9. * the Asterisk project. Please do not directly contact
  10. * any of the maintainers of this project for assistance;
  11. * the project provides a web site, mailing lists and IRC
  12. * channels for your use.
  13. *
  14. * This program is free software, distributed under the terms of
  15. * the GNU General Public License Version 2. See the LICENSE file
  16. * at the top of the source tree.
  17. *
  18. * Please follow coding guidelines
  19. * http://svn.digium.com/view/asterisk/trunk/doc/CODING-GUIDELINES
  20. */
  21. /*! \file
  22. *
  23. * \brief Confbridge state handling for the MULTI_MARKED state
  24. *
  25. * \author\verbatim Terry Wilson <twilson@digium.com> \endverbatim
  26. *
  27. * \ingroup applications
  28. */
  29. /*** MODULEINFO
  30. <support_level>core</support_level>
  31. ***/
  32. #include "asterisk.h"
  33. #include "asterisk/utils.h"
  34. #include "asterisk/linkedlists.h"
  35. #include "include/confbridge.h"
  36. #include "asterisk/musiconhold.h"
  37. #include "include/conf_state.h"
  38. static void join_active(struct conference_bridge_user *cbu);
  39. static void join_marked(struct conference_bridge_user *cbu);
  40. static void leave_active(struct conference_bridge_user *cbu);
  41. static void leave_marked(struct conference_bridge_user *cbu);
  42. static void transition_to_marked(struct conference_bridge_user *cbu);
  43. static struct conference_state STATE_MULTI_MARKED = {
  44. .name = "MULTI_MARKED",
  45. .join_unmarked = join_active,
  46. .join_waitmarked = join_active,
  47. .join_marked = join_marked,
  48. .leave_unmarked = leave_active,
  49. .leave_waitmarked = leave_active,
  50. .leave_marked = leave_marked,
  51. .entry = transition_to_marked,
  52. };
  53. struct conference_state *CONF_STATE_MULTI_MARKED = &STATE_MULTI_MARKED;
  54. static void join_active(struct conference_bridge_user *cbu)
  55. {
  56. conf_add_user_active(cbu->conference_bridge, cbu);
  57. conf_update_user_mute(cbu);
  58. }
  59. static void join_marked(struct conference_bridge_user *cbu)
  60. {
  61. conf_add_user_marked(cbu->conference_bridge, cbu);
  62. conf_update_user_mute(cbu);
  63. }
  64. static void leave_active(struct conference_bridge_user *cbu)
  65. {
  66. conf_remove_user_active(cbu->conference_bridge, cbu);
  67. if (cbu->conference_bridge->activeusers == 1) {
  68. conf_change_state(cbu, CONF_STATE_SINGLE_MARKED);
  69. }
  70. }
  71. static void leave_marked(struct conference_bridge_user *cbu)
  72. {
  73. struct conference_bridge_user *cbu_iter;
  74. int need_prompt = 0;
  75. conf_remove_user_marked(cbu->conference_bridge, cbu);
  76. if (cbu->conference_bridge->markedusers == 0) {
  77. AST_LIST_TRAVERSE_SAFE_BEGIN(&cbu->conference_bridge->active_list, cbu_iter, list) {
  78. /* Kick ENDMARKED cbu_iters */
  79. if (ast_test_flag(&cbu_iter->u_profile, USER_OPT_ENDMARKED) && !cbu_iter->kicked) {
  80. if (ast_test_flag(&cbu_iter->u_profile, USER_OPT_WAITMARKED)
  81. && !ast_test_flag(&cbu_iter->u_profile, USER_OPT_MARKEDUSER)) {
  82. AST_LIST_REMOVE_CURRENT(list);
  83. cbu_iter->conference_bridge->activeusers--;
  84. AST_LIST_INSERT_TAIL(&cbu_iter->conference_bridge->waiting_list, cbu_iter, list);
  85. cbu_iter->conference_bridge->waitingusers++;
  86. }
  87. cbu_iter->kicked = 1;
  88. ast_bridge_remove(cbu_iter->conference_bridge->bridge, cbu_iter->chan);
  89. } else if (ast_test_flag(&cbu_iter->u_profile, USER_OPT_WAITMARKED)
  90. && !ast_test_flag(&cbu_iter->u_profile, USER_OPT_MARKEDUSER)) {
  91. need_prompt = 1;
  92. AST_LIST_REMOVE_CURRENT(list);
  93. cbu_iter->conference_bridge->activeusers--;
  94. AST_LIST_INSERT_TAIL(&cbu_iter->conference_bridge->waiting_list, cbu_iter, list);
  95. cbu_iter->conference_bridge->waitingusers++;
  96. } else {
  97. /* User is neither wait_marked nor end_marked; however, they
  98. * should still hear the prompt.
  99. */
  100. need_prompt = 1;
  101. }
  102. }
  103. AST_LIST_TRAVERSE_SAFE_END;
  104. }
  105. switch (cbu->conference_bridge->activeusers) {
  106. case 0:
  107. /* Implies markedusers == 0 */
  108. switch (cbu->conference_bridge->waitingusers) {
  109. case 0:
  110. conf_change_state(cbu, CONF_STATE_EMPTY);
  111. break;
  112. default:
  113. conf_change_state(cbu, CONF_STATE_INACTIVE);
  114. break;
  115. }
  116. break;
  117. case 1:
  118. switch (cbu->conference_bridge->markedusers) {
  119. case 0:
  120. conf_change_state(cbu, CONF_STATE_SINGLE);
  121. break;
  122. case 1:
  123. /* XXX I seem to remember doing this for a reason, but right now it escapes me
  124. * how we could possibly ever have a waiting user while we have a marked user */
  125. switch (cbu->conference_bridge->waitingusers) {
  126. case 0:
  127. conf_change_state(cbu, CONF_STATE_SINGLE_MARKED);
  128. break;
  129. case 1:
  130. break; /* Stay in marked */
  131. }
  132. break;
  133. }
  134. break;
  135. default:
  136. switch (cbu->conference_bridge->markedusers) {
  137. case 0:
  138. conf_change_state(cbu, CONF_STATE_MULTI);
  139. break;
  140. default:
  141. break; /* Stay in marked */
  142. }
  143. }
  144. if (need_prompt) {
  145. /* Play back the audio prompt saying the leader has left the conference */
  146. if (!ast_test_flag(&cbu->u_profile, USER_OPT_QUIET)) {
  147. ao2_unlock(cbu->conference_bridge);
  148. ast_autoservice_start(cbu->chan);
  149. play_sound_file(cbu->conference_bridge,
  150. conf_get_sound(CONF_SOUND_LEADER_HAS_LEFT, cbu->b_profile.sounds));
  151. ast_autoservice_stop(cbu->chan);
  152. ao2_lock(cbu->conference_bridge);
  153. }
  154. AST_LIST_TRAVERSE(&cbu->conference_bridge->waiting_list, cbu_iter, list) {
  155. if (cbu_iter->kicked) {
  156. continue;
  157. }
  158. if (ast_test_flag(&cbu_iter->u_profile, USER_OPT_MUSICONHOLD)) {
  159. conf_moh_start(cbu_iter);
  160. }
  161. conf_update_user_mute(cbu_iter);
  162. }
  163. }
  164. }
  165. static int post_join_play_begin(struct conference_bridge_user *cbu)
  166. {
  167. int res;
  168. ast_autoservice_start(cbu->chan);
  169. res = play_sound_file(cbu->conference_bridge,
  170. conf_get_sound(CONF_SOUND_BEGIN, cbu->b_profile.sounds));
  171. ast_autoservice_stop(cbu->chan);
  172. return res;
  173. }
  174. static void transition_to_marked(struct conference_bridge_user *cbu)
  175. {
  176. struct conference_bridge_user *cbu_iter;
  177. int waitmarked_moved = 0;
  178. /* Move all waiting users to active, stopping MOH and unmuting if necessary */
  179. AST_LIST_TRAVERSE_SAFE_BEGIN(&cbu->conference_bridge->waiting_list, cbu_iter, list) {
  180. AST_LIST_REMOVE_CURRENT(list);
  181. cbu->conference_bridge->waitingusers--;
  182. AST_LIST_INSERT_TAIL(&cbu->conference_bridge->active_list, cbu_iter, list);
  183. cbu->conference_bridge->activeusers++;
  184. if (cbu_iter->playing_moh) {
  185. conf_moh_stop(cbu_iter);
  186. }
  187. conf_update_user_mute(cbu_iter);
  188. waitmarked_moved++;
  189. }
  190. AST_LIST_TRAVERSE_SAFE_END;
  191. /* Play the audio file stating that the conference is beginning */
  192. if (cbu->conference_bridge->markedusers == 1
  193. && ast_test_flag(&cbu->u_profile, USER_OPT_MARKEDUSER)
  194. && !ast_test_flag(&cbu->u_profile, USER_OPT_QUIET)
  195. && waitmarked_moved) {
  196. conf_add_post_join_action(cbu, post_join_play_begin);
  197. }
  198. }