confbridge_manager.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2013, Digium, Inc.
  5. *
  6. * Jonathan Rose <jrose@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. /*! \file
  19. *
  20. * \brief Confbridge manager events for stasis messages
  21. *
  22. * \author Jonathan Rose <jrose@digium.com>
  23. */
  24. #include "asterisk.h"
  25. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  26. #include "asterisk/channel.h"
  27. #include "asterisk/bridge.h"
  28. #include "asterisk/stasis.h"
  29. #include "asterisk/stasis_channels.h"
  30. #include "asterisk/stasis_bridges.h"
  31. #include "asterisk/manager.h"
  32. #include "asterisk/stasis_message_router.h"
  33. #include "include/confbridge.h"
  34. /*** DOCUMENTATION
  35. <managerEvent language="en_US" name="ConfbridgeStart">
  36. <managerEventInstance class="EVENT_FLAG_CALL">
  37. <synopsis>Raised when a conference starts.</synopsis>
  38. <syntax>
  39. <parameter name="Conference">
  40. <para>The name of the Confbridge conference.</para>
  41. </parameter>
  42. <bridge_snapshot/>
  43. </syntax>
  44. <see-also>
  45. <ref type="managerEvent">ConfbridgeEnd</ref>
  46. <ref type="application">ConfBridge</ref>
  47. </see-also>
  48. </managerEventInstance>
  49. </managerEvent>
  50. <managerEvent language="en_US" name="ConfbridgeEnd">
  51. <managerEventInstance class="EVENT_FLAG_CALL">
  52. <synopsis>Raised when a conference ends.</synopsis>
  53. <syntax>
  54. <parameter name="Conference">
  55. <para>The name of the Confbridge conference.</para>
  56. </parameter>
  57. <bridge_snapshot/>
  58. </syntax>
  59. <see-also>
  60. <ref type="managerEvent">ConfbridgeStart</ref>
  61. <ref type="application">ConfBridge</ref>
  62. </see-also>
  63. </managerEventInstance>
  64. </managerEvent>
  65. <managerEvent language="en_US" name="ConfbridgeJoin">
  66. <managerEventInstance class="EVENT_FLAG_CALL">
  67. <synopsis>Raised when a channel joins a Confbridge conference.</synopsis>
  68. <syntax>
  69. <parameter name="Conference">
  70. <para>The name of the Confbridge conference.</para>
  71. </parameter>
  72. <bridge_snapshot/>
  73. <channel_snapshot/>
  74. <parameter name="Admin">
  75. <para>Identifies this user as an admin user.</para>
  76. <enumlist>
  77. <enum name="Yes"/>
  78. <enum name="No"/>
  79. </enumlist>
  80. </parameter>
  81. <parameter name="Muted">
  82. <para>The joining mute status.</para>
  83. <enumlist>
  84. <enum name="Yes"/>
  85. <enum name="No"/>
  86. </enumlist>
  87. </parameter>
  88. </syntax>
  89. <see-also>
  90. <ref type="managerEvent">ConfbridgeLeave</ref>
  91. <ref type="application">ConfBridge</ref>
  92. </see-also>
  93. </managerEventInstance>
  94. </managerEvent>
  95. <managerEvent language="en_US" name="ConfbridgeLeave">
  96. <managerEventInstance class="EVENT_FLAG_CALL">
  97. <synopsis>Raised when a channel leaves a Confbridge conference.</synopsis>
  98. <syntax>
  99. <parameter name="Conference">
  100. <para>The name of the Confbridge conference.</para>
  101. </parameter>
  102. <bridge_snapshot/>
  103. <channel_snapshot/>
  104. <parameter name="Admin">
  105. <para>Identifies this user as an admin user.</para>
  106. <enumlist>
  107. <enum name="Yes"/>
  108. <enum name="No"/>
  109. </enumlist>
  110. </parameter>
  111. </syntax>
  112. <see-also>
  113. <ref type="managerEvent">ConfbridgeJoin</ref>
  114. <ref type="application">ConfBridge</ref>
  115. </see-also>
  116. </managerEventInstance>
  117. </managerEvent>
  118. <managerEvent language="en_US" name="ConfbridgeRecord">
  119. <managerEventInstance class="EVENT_FLAG_CALL">
  120. <synopsis>Raised when a conference starts recording.</synopsis>
  121. <syntax>
  122. <parameter name="Conference">
  123. <para>The name of the Confbridge conference.</para>
  124. </parameter>
  125. <bridge_snapshot/>
  126. </syntax>
  127. <see-also>
  128. <ref type="managerEvent">ConfbridgeStopRecord</ref>
  129. <ref type="application">ConfBridge</ref>
  130. </see-also>
  131. </managerEventInstance>
  132. </managerEvent>
  133. <managerEvent language="en_US" name="ConfbridgeStopRecord">
  134. <managerEventInstance class="EVENT_FLAG_CALL">
  135. <synopsis>Raised when a conference that was recording stops recording.</synopsis>
  136. <syntax>
  137. <parameter name="Conference">
  138. <para>The name of the Confbridge conference.</para>
  139. </parameter>
  140. <bridge_snapshot/>
  141. </syntax>
  142. <see-also>
  143. <ref type="managerEvent">ConfbridgeRecord</ref>
  144. <ref type="application">ConfBridge</ref>
  145. </see-also>
  146. </managerEventInstance>
  147. </managerEvent>
  148. <managerEvent language="en_US" name="ConfbridgeMute">
  149. <managerEventInstance class="EVENT_FLAG_CALL">
  150. <synopsis>Raised when a Confbridge participant mutes.</synopsis>
  151. <syntax>
  152. <parameter name="Conference">
  153. <para>The name of the Confbridge conference.</para>
  154. </parameter>
  155. <bridge_snapshot/>
  156. <channel_snapshot/>
  157. <parameter name="Admin">
  158. <para>Identifies this user as an admin user.</para>
  159. <enumlist>
  160. <enum name="Yes"/>
  161. <enum name="No"/>
  162. </enumlist>
  163. </parameter>
  164. </syntax>
  165. <see-also>
  166. <ref type="managerEvent">ConfbridgeUnmute</ref>
  167. <ref type="application">ConfBridge</ref>
  168. </see-also>
  169. </managerEventInstance>
  170. </managerEvent>
  171. <managerEvent language="en_US" name="ConfbridgeUnmute">
  172. <managerEventInstance class="EVENT_FLAG_CALL">
  173. <synopsis>Raised when a confbridge participant unmutes.</synopsis>
  174. <syntax>
  175. <parameter name="Conference">
  176. <para>The name of the Confbridge conference.</para>
  177. </parameter>
  178. <bridge_snapshot/>
  179. <channel_snapshot/>
  180. <parameter name="Admin">
  181. <para>Identifies this user as an admin user.</para>
  182. <enumlist>
  183. <enum name="Yes"/>
  184. <enum name="No"/>
  185. </enumlist>
  186. </parameter>
  187. </syntax>
  188. <see-also>
  189. <ref type="managerEvent">ConfbridgeMute</ref>
  190. <ref type="application">ConfBridge</ref>
  191. </see-also>
  192. </managerEventInstance>
  193. </managerEvent>
  194. <managerEvent language="en_US" name="ConfbridgeTalking">
  195. <managerEventInstance class="EVENT_FLAG_CALL">
  196. <synopsis>Raised when a confbridge participant begins or ends talking.</synopsis>
  197. <syntax>
  198. <parameter name="Conference">
  199. <para>The name of the Confbridge conference.</para>
  200. </parameter>
  201. <bridge_snapshot/>
  202. <channel_snapshot/>
  203. <parameter name="TalkingStatus">
  204. <enumlist>
  205. <enum name="on"/>
  206. <enum name="off"/>
  207. </enumlist>
  208. </parameter>
  209. <parameter name="Admin">
  210. <para>Identifies this user as an admin user.</para>
  211. <enumlist>
  212. <enum name="Yes"/>
  213. <enum name="No"/>
  214. </enumlist>
  215. </parameter>
  216. </syntax>
  217. <see-also>
  218. <ref type="application">ConfBridge</ref>
  219. </see-also>
  220. </managerEventInstance>
  221. </managerEvent>
  222. ***/
  223. static struct stasis_message_router *bridge_state_router;
  224. static struct stasis_message_router *channel_state_router;
  225. static void confbridge_publish_manager_event(
  226. struct stasis_message *message,
  227. const char *event,
  228. struct ast_str *extra_text)
  229. {
  230. struct ast_bridge_blob *blob = stasis_message_data(message);
  231. const char *conference_name;
  232. RAII_VAR(struct ast_str *, bridge_text, NULL, ast_free);
  233. RAII_VAR(struct ast_str *, channel_text, NULL, ast_free);
  234. ast_assert(blob != NULL);
  235. ast_assert(event != NULL);
  236. bridge_text = ast_manager_build_bridge_state_string(blob->bridge);
  237. if (!bridge_text) {
  238. return;
  239. }
  240. conference_name = ast_json_string_get(ast_json_object_get(blob->blob, "conference"));
  241. ast_assert(conference_name != NULL);
  242. if (blob->channel) {
  243. channel_text = ast_manager_build_channel_state_string(blob->channel);
  244. }
  245. manager_event(EVENT_FLAG_CALL, event,
  246. "Conference: %s\r\n"
  247. "%s"
  248. "%s"
  249. "%s",
  250. conference_name,
  251. ast_str_buffer(bridge_text),
  252. channel_text ? ast_str_buffer(channel_text) : "",
  253. extra_text ? ast_str_buffer(extra_text) : "");
  254. }
  255. static int get_bool_header(struct ast_str **extra_text, struct stasis_message *message,
  256. const char *json_key, const char *ami_header)
  257. {
  258. const struct ast_bridge_blob *blob = stasis_message_data(message);
  259. const struct ast_json *obj;
  260. obj = ast_json_object_get(blob->blob, json_key);
  261. if (!obj) {
  262. return -1;
  263. }
  264. return ast_str_append_event_header(extra_text, ami_header,
  265. AST_YESNO(ast_json_is_true(obj)));
  266. }
  267. static int get_admin_header(struct ast_str **extra_text, struct stasis_message *message)
  268. {
  269. return get_bool_header(extra_text, message, "admin", "Admin");
  270. }
  271. static int get_muted_header(struct ast_str **extra_text, struct stasis_message *message)
  272. {
  273. return get_bool_header(extra_text, message, "muted", "Muted");
  274. }
  275. static void confbridge_start_cb(void *data, struct stasis_subscription *sub,
  276. struct stasis_message *message)
  277. {
  278. confbridge_publish_manager_event(message, "ConfbridgeStart", NULL);
  279. }
  280. static void confbridge_end_cb(void *data, struct stasis_subscription *sub,
  281. struct stasis_message *message)
  282. {
  283. confbridge_publish_manager_event(message, "ConfbridgeEnd", NULL);
  284. }
  285. static void confbridge_leave_cb(void *data, struct stasis_subscription *sub,
  286. struct stasis_message *message)
  287. {
  288. struct ast_str *extra_text = NULL;
  289. if (!get_admin_header(&extra_text, message)) {
  290. confbridge_publish_manager_event(message, "ConfbridgeLeave", extra_text);
  291. }
  292. ast_free(extra_text);
  293. }
  294. static void confbridge_join_cb(void *data, struct stasis_subscription *sub,
  295. struct stasis_message *message)
  296. {
  297. struct ast_str *extra_text = NULL;
  298. if (!get_admin_header(&extra_text, message)
  299. && !get_muted_header(&extra_text, message)) {
  300. confbridge_publish_manager_event(message, "ConfbridgeJoin", extra_text);
  301. }
  302. ast_free(extra_text);
  303. }
  304. static void confbridge_start_record_cb(void *data, struct stasis_subscription *sub,
  305. struct stasis_message *message)
  306. {
  307. confbridge_publish_manager_event(message, "ConfbridgeRecord", NULL);
  308. }
  309. static void confbridge_stop_record_cb(void *data, struct stasis_subscription *sub,
  310. struct stasis_message *message)
  311. {
  312. confbridge_publish_manager_event(message, "ConfbridgeStopRecord", NULL);
  313. }
  314. static void confbridge_mute_cb(void *data, struct stasis_subscription *sub,
  315. struct stasis_message *message)
  316. {
  317. struct ast_str *extra_text = NULL;
  318. if (!get_admin_header(&extra_text, message)) {
  319. confbridge_publish_manager_event(message, "ConfbridgeMute", extra_text);
  320. }
  321. ast_free(extra_text);
  322. }
  323. static void confbridge_unmute_cb(void *data, struct stasis_subscription *sub,
  324. struct stasis_message *message)
  325. {
  326. struct ast_str *extra_text = NULL;
  327. if (!get_admin_header(&extra_text, message)) {
  328. confbridge_publish_manager_event(message, "ConfbridgeUnmute", extra_text);
  329. }
  330. ast_free(extra_text);
  331. }
  332. static void confbridge_talking_cb(void *data, struct stasis_subscription *sub,
  333. struct stasis_message *message)
  334. {
  335. RAII_VAR(struct ast_str *, extra_text, NULL, ast_free);
  336. const struct ast_bridge_blob *blob = stasis_message_data(message);
  337. const char *talking_status = ast_json_string_get(ast_json_object_get(blob->blob, "talking_status"));
  338. if (!talking_status) {
  339. return;
  340. }
  341. ast_str_append_event_header(&extra_text, "TalkingStatus", talking_status);
  342. if (!extra_text) {
  343. return;
  344. }
  345. if (!get_admin_header(&extra_text, message)) {
  346. confbridge_publish_manager_event(message, "ConfbridgeTalking", extra_text);
  347. }
  348. }
  349. STASIS_MESSAGE_TYPE_DEFN(confbridge_start_type);
  350. STASIS_MESSAGE_TYPE_DEFN(confbridge_end_type);
  351. STASIS_MESSAGE_TYPE_DEFN(confbridge_join_type);
  352. STASIS_MESSAGE_TYPE_DEFN(confbridge_leave_type);
  353. STASIS_MESSAGE_TYPE_DEFN(confbridge_start_record_type);
  354. STASIS_MESSAGE_TYPE_DEFN(confbridge_stop_record_type);
  355. STASIS_MESSAGE_TYPE_DEFN(confbridge_mute_type);
  356. STASIS_MESSAGE_TYPE_DEFN(confbridge_unmute_type);
  357. STASIS_MESSAGE_TYPE_DEFN(confbridge_talking_type);
  358. void manager_confbridge_shutdown(void) {
  359. STASIS_MESSAGE_TYPE_CLEANUP(confbridge_start_type);
  360. STASIS_MESSAGE_TYPE_CLEANUP(confbridge_end_type);
  361. STASIS_MESSAGE_TYPE_CLEANUP(confbridge_join_type);
  362. STASIS_MESSAGE_TYPE_CLEANUP(confbridge_leave_type);
  363. STASIS_MESSAGE_TYPE_CLEANUP(confbridge_start_record_type);
  364. STASIS_MESSAGE_TYPE_CLEANUP(confbridge_stop_record_type);
  365. STASIS_MESSAGE_TYPE_CLEANUP(confbridge_mute_type);
  366. STASIS_MESSAGE_TYPE_CLEANUP(confbridge_unmute_type);
  367. STASIS_MESSAGE_TYPE_CLEANUP(confbridge_talking_type);
  368. if (bridge_state_router) {
  369. stasis_message_router_unsubscribe(bridge_state_router);
  370. bridge_state_router = NULL;
  371. }
  372. if (channel_state_router) {
  373. stasis_message_router_unsubscribe(channel_state_router);
  374. channel_state_router = NULL;
  375. }
  376. }
  377. int manager_confbridge_init(void)
  378. {
  379. STASIS_MESSAGE_TYPE_INIT(confbridge_start_type);
  380. STASIS_MESSAGE_TYPE_INIT(confbridge_end_type);
  381. STASIS_MESSAGE_TYPE_INIT(confbridge_join_type);
  382. STASIS_MESSAGE_TYPE_INIT(confbridge_leave_type);
  383. STASIS_MESSAGE_TYPE_INIT(confbridge_start_record_type);
  384. STASIS_MESSAGE_TYPE_INIT(confbridge_stop_record_type);
  385. STASIS_MESSAGE_TYPE_INIT(confbridge_mute_type);
  386. STASIS_MESSAGE_TYPE_INIT(confbridge_unmute_type);
  387. STASIS_MESSAGE_TYPE_INIT(confbridge_talking_type);
  388. bridge_state_router = stasis_message_router_create(
  389. ast_bridge_topic_all_cached());
  390. if (!bridge_state_router) {
  391. return -1;
  392. }
  393. if (stasis_message_router_add(bridge_state_router,
  394. confbridge_start_type(),
  395. confbridge_start_cb,
  396. NULL)) {
  397. manager_confbridge_shutdown();
  398. return -1;
  399. }
  400. if (stasis_message_router_add(bridge_state_router,
  401. confbridge_end_type(),
  402. confbridge_end_cb,
  403. NULL)) {
  404. manager_confbridge_shutdown();
  405. return -1;
  406. }
  407. if (stasis_message_router_add(bridge_state_router,
  408. confbridge_join_type(),
  409. confbridge_join_cb,
  410. NULL)) {
  411. manager_confbridge_shutdown();
  412. return -1;
  413. }
  414. if (stasis_message_router_add(bridge_state_router,
  415. confbridge_leave_type(),
  416. confbridge_leave_cb,
  417. NULL)) {
  418. manager_confbridge_shutdown();
  419. return -1;
  420. }
  421. if (stasis_message_router_add(bridge_state_router,
  422. confbridge_start_record_type(),
  423. confbridge_start_record_cb,
  424. NULL)) {
  425. manager_confbridge_shutdown();
  426. return -1;
  427. }
  428. if (stasis_message_router_add(bridge_state_router,
  429. confbridge_stop_record_type(),
  430. confbridge_stop_record_cb,
  431. NULL)) {
  432. manager_confbridge_shutdown();
  433. return -1;
  434. }
  435. if (stasis_message_router_add(bridge_state_router,
  436. confbridge_mute_type(),
  437. confbridge_mute_cb,
  438. NULL)) {
  439. manager_confbridge_shutdown();
  440. return -1;
  441. }
  442. if (stasis_message_router_add(bridge_state_router,
  443. confbridge_unmute_type(),
  444. confbridge_unmute_cb,
  445. NULL)) {
  446. manager_confbridge_shutdown();
  447. return -1;
  448. }
  449. if (stasis_message_router_add(bridge_state_router,
  450. confbridge_talking_type(),
  451. confbridge_talking_cb,
  452. NULL)) {
  453. manager_confbridge_shutdown();
  454. return -1;
  455. }
  456. channel_state_router = stasis_message_router_create(
  457. ast_channel_topic_all_cached());
  458. if (!channel_state_router) {
  459. manager_confbridge_shutdown();
  460. return -1;
  461. }
  462. if (stasis_message_router_add(channel_state_router,
  463. confbridge_start_type(),
  464. confbridge_start_cb,
  465. NULL)) {
  466. manager_confbridge_shutdown();
  467. return -1;
  468. }
  469. if (stasis_message_router_add(channel_state_router,
  470. confbridge_end_type(),
  471. confbridge_end_cb,
  472. NULL)) {
  473. manager_confbridge_shutdown();
  474. return -1;
  475. }
  476. if (stasis_message_router_add(channel_state_router,
  477. confbridge_join_type(),
  478. confbridge_join_cb,
  479. NULL)) {
  480. manager_confbridge_shutdown();
  481. return -1;
  482. }
  483. if (stasis_message_router_add(channel_state_router,
  484. confbridge_leave_type(),
  485. confbridge_leave_cb,
  486. NULL)) {
  487. manager_confbridge_shutdown();
  488. return -1;
  489. }
  490. if (stasis_message_router_add(channel_state_router,
  491. confbridge_start_record_type(),
  492. confbridge_start_record_cb,
  493. NULL)) {
  494. manager_confbridge_shutdown();
  495. return -1;
  496. }
  497. if (stasis_message_router_add(channel_state_router,
  498. confbridge_stop_record_type(),
  499. confbridge_stop_record_cb,
  500. NULL)) {
  501. manager_confbridge_shutdown();
  502. return -1;
  503. }
  504. if (stasis_message_router_add(channel_state_router,
  505. confbridge_mute_type(),
  506. confbridge_mute_cb,
  507. NULL)) {
  508. manager_confbridge_shutdown();
  509. return -1;
  510. }
  511. if (stasis_message_router_add(channel_state_router,
  512. confbridge_unmute_type(),
  513. confbridge_unmute_cb,
  514. NULL)) {
  515. manager_confbridge_shutdown();
  516. return -1;
  517. }
  518. if (stasis_message_router_add(channel_state_router,
  519. confbridge_talking_type(),
  520. confbridge_talking_cb,
  521. NULL)) {
  522. manager_confbridge_shutdown();
  523. return -1;
  524. }
  525. return 0;
  526. }