confbridge_manager.c 15 KB

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