resource_bridges.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2012 - 2013, Digium, Inc.
  5. *
  6. * David M. Lee, II <dlee@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 Implementation for ARI stubs.
  21. *
  22. * \author David M. Lee, II <dlee@digium.com>
  23. */
  24. /*** MODULEINFO
  25. <support_level>core</support_level>
  26. ***/
  27. #include "asterisk.h"
  28. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  29. #include "resource_bridges.h"
  30. #include "asterisk/stasis.h"
  31. #include "asterisk/stasis_bridges.h"
  32. #include "asterisk/stasis_app.h"
  33. #include "asterisk/stasis_app_playback.h"
  34. #include "asterisk/stasis_app_recording.h"
  35. #include "asterisk/stasis_channels.h"
  36. #include "asterisk/core_unreal.h"
  37. #include "asterisk/channel.h"
  38. #include "asterisk/bridge.h"
  39. #include "asterisk/format_cap.h"
  40. #include "asterisk/file.h"
  41. #include "asterisk/musiconhold.h"
  42. #include "asterisk/format_cache.h"
  43. /*!
  44. * \brief Finds a bridge, filling the response with an error, if appropriate.
  45. *
  46. * \param[out] response Response to fill with an error if control is not found.
  47. * \param bridge_id ID of the bridge to lookup.
  48. *
  49. * \return Bridget.
  50. * \return \c NULL if bridge does not exist.
  51. */
  52. static struct ast_bridge *find_bridge(
  53. struct ast_ari_response *response,
  54. const char *bridge_id)
  55. {
  56. RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
  57. ast_assert(response != NULL);
  58. bridge = stasis_app_bridge_find_by_id(bridge_id);
  59. if (bridge == NULL) {
  60. RAII_VAR(struct ast_bridge_snapshot *, snapshot,
  61. ast_bridge_snapshot_get_latest(bridge_id), ao2_cleanup);
  62. if (!snapshot) {
  63. ast_ari_response_error(response, 404, "Not found",
  64. "Bridge not found");
  65. return NULL;
  66. }
  67. ast_ari_response_error(response, 409, "Conflict",
  68. "Bridge not in Stasis application");
  69. return NULL;
  70. }
  71. ao2_ref(bridge, +1);
  72. return bridge;
  73. }
  74. /*!
  75. * \brief Finds the control object for a channel, filling the response with an
  76. * error, if appropriate.
  77. * \param[out] response Response to fill with an error if control is not found.
  78. * \param channel_id ID of the channel to lookup.
  79. * \return Channel control object.
  80. * \return \c NULL if control object does not exist.
  81. */
  82. static struct stasis_app_control *find_channel_control(
  83. struct ast_ari_response *response,
  84. const char *channel_id)
  85. {
  86. RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
  87. ast_assert(response != NULL);
  88. control = stasis_app_control_find_by_channel_id(channel_id);
  89. if (control == NULL) {
  90. /* Distinguish between 400 and 422 errors */
  91. RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL,
  92. ao2_cleanup);
  93. snapshot = ast_channel_snapshot_get_latest(channel_id);
  94. if (snapshot == NULL) {
  95. ast_log(LOG_DEBUG, "Couldn't find '%s'\n", channel_id);
  96. ast_ari_response_error(response, 400, "Bad Request",
  97. "Channel not found");
  98. return NULL;
  99. }
  100. ast_log(LOG_DEBUG, "Found non-stasis '%s'\n", channel_id);
  101. ast_ari_response_error(response, 422, "Unprocessable Entity",
  102. "Channel not in Stasis application");
  103. return NULL;
  104. }
  105. ao2_ref(control, +1);
  106. return control;
  107. }
  108. struct control_list {
  109. size_t count;
  110. struct stasis_app_control *controls[];
  111. };
  112. static void control_list_dtor(void *obj) {
  113. struct control_list *list = obj;
  114. size_t i;
  115. for (i = 0; i < list->count; ++i) {
  116. ao2_cleanup(list->controls[i]);
  117. list->controls[i] = NULL;
  118. }
  119. }
  120. static struct control_list *control_list_create(struct ast_ari_response *response, size_t count, const char **channels) {
  121. RAII_VAR(struct control_list *, list, NULL, ao2_cleanup);
  122. size_t i;
  123. if (count == 0 || !channels) {
  124. ast_ari_response_error(response, 400, "Bad Request", "Missing parameter channel");
  125. return NULL;
  126. }
  127. list = ao2_alloc(sizeof(*list) + count * sizeof(list->controls[0]), control_list_dtor);
  128. if (!list) {
  129. ast_ari_response_alloc_failed(response);
  130. return NULL;
  131. }
  132. for (i = 0; i < count; ++i) {
  133. if (ast_strlen_zero(channels[i])) {
  134. continue;
  135. }
  136. list->controls[list->count] =
  137. find_channel_control(response, channels[i]);
  138. if (!list->controls[list->count]) {
  139. /* response filled in by find_channel_control() */
  140. return NULL;
  141. }
  142. ++list->count;
  143. }
  144. if (list->count == 0) {
  145. ast_ari_response_error(response, 400, "Bad Request", "Missing parameter channel");
  146. return NULL;
  147. }
  148. ao2_ref(list, +1);
  149. return list;
  150. }
  151. static int check_add_remove_channel(struct ast_ari_response *response,
  152. struct stasis_app_control *control,
  153. enum stasis_app_control_channel_result result)
  154. {
  155. switch (result) {
  156. case STASIS_APP_CHANNEL_RECORDING :
  157. ast_ari_response_error(
  158. response, 409, "Conflict", "Channel %s currently recording",
  159. stasis_app_control_get_channel_id(control));
  160. return -1;
  161. case STASIS_APP_CHANNEL_OKAY:
  162. return 0;
  163. }
  164. return 0;
  165. }
  166. void ast_ari_bridges_add_channel(struct ast_variable *headers,
  167. struct ast_ari_bridges_add_channel_args *args,
  168. struct ast_ari_response *response)
  169. {
  170. RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
  171. RAII_VAR(struct control_list *, list, NULL, ao2_cleanup);
  172. size_t i;
  173. int has_error = 0;
  174. if (!bridge) {
  175. /* Response filled in by find_bridge() */
  176. return;
  177. }
  178. list = control_list_create(response, args->channel_count, args->channel);
  179. if (!list) {
  180. /* Response filled in by control_list_create() */
  181. return;
  182. }
  183. for (i = 0; i < list->count; ++i) {
  184. stasis_app_control_clear_roles(list->controls[i]);
  185. if (!ast_strlen_zero(args->role)) {
  186. if (stasis_app_control_add_role(list->controls[i], args->role)) {
  187. ast_ari_response_alloc_failed(response);
  188. return;
  189. }
  190. }
  191. }
  192. for (i = 0; i < list->count; ++i) {
  193. if ((has_error = check_add_remove_channel(response, list->controls[i],
  194. stasis_app_control_add_channel_to_bridge(
  195. list->controls[i], bridge)))) {
  196. break;
  197. }
  198. }
  199. if (!has_error) {
  200. ast_ari_response_no_content(response);
  201. }
  202. }
  203. void ast_ari_bridges_remove_channel(struct ast_variable *headers,
  204. struct ast_ari_bridges_remove_channel_args *args,
  205. struct ast_ari_response *response)
  206. {
  207. RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
  208. RAII_VAR(struct control_list *, list, NULL, ao2_cleanup);
  209. size_t i;
  210. if (!bridge) {
  211. /* Response filled in by find_bridge() */
  212. return;
  213. }
  214. list = control_list_create(response, args->channel_count, args->channel);
  215. if (!list) {
  216. /* Response filled in by control_list_create() */
  217. return;
  218. }
  219. /* Make sure all of the channels are in this bridge */
  220. for (i = 0; i < list->count; ++i) {
  221. if (stasis_app_get_bridge(list->controls[i]) != bridge) {
  222. ast_log(LOG_WARNING, "Channel %s not in bridge %s\n",
  223. args->channel[i], args->bridge_id);
  224. ast_ari_response_error(response, 422,
  225. "Unprocessable Entity",
  226. "Channel not in this bridge");
  227. return;
  228. }
  229. }
  230. /* Now actually remove it */
  231. for (i = 0; i < list->count; ++i) {
  232. stasis_app_control_remove_channel_from_bridge(list->controls[i],
  233. bridge);
  234. }
  235. ast_ari_response_no_content(response);
  236. }
  237. struct bridge_channel_control_thread_data {
  238. struct ast_channel *bridge_channel;
  239. struct stasis_app_control *control;
  240. struct stasis_forward *forward;
  241. };
  242. static void *bridge_channel_control_thread(void *data)
  243. {
  244. struct bridge_channel_control_thread_data *thread_data = data;
  245. struct ast_channel *bridge_channel = thread_data->bridge_channel;
  246. struct stasis_app_control *control = thread_data->control;
  247. struct stasis_forward *forward = thread_data->forward;
  248. RAII_VAR(struct ast_callid *, callid, ast_channel_callid(bridge_channel), ast_callid_cleanup);
  249. if (callid) {
  250. ast_callid_threadassoc_add(callid);
  251. }
  252. ast_free(thread_data);
  253. thread_data = NULL;
  254. stasis_app_control_execute_until_exhausted(bridge_channel, control);
  255. ast_hangup(bridge_channel);
  256. ao2_cleanup(control);
  257. stasis_forward_cancel(forward);
  258. return NULL;
  259. }
  260. static struct ast_channel *prepare_bridge_media_channel(const char *type)
  261. {
  262. RAII_VAR(struct ast_format_cap *, cap, NULL, ao2_cleanup);
  263. struct ast_channel *chan;
  264. cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
  265. if (!cap) {
  266. return NULL;
  267. }
  268. ast_format_cap_append(cap, ast_format_slin, 0);
  269. chan = ast_request(type, cap, NULL, NULL, "ARI", NULL);
  270. if (!chan) {
  271. return NULL;
  272. }
  273. if (stasis_app_channel_unreal_set_internal(chan)) {
  274. ast_channel_cleanup(chan);
  275. return NULL;
  276. }
  277. return chan;
  278. }
  279. /*!
  280. * \brief Performs common setup for a bridge playback operation
  281. * with both new controls and when existing controls are found.
  282. *
  283. * \param args_media media string split from arguments
  284. * \param args_lang language string split from arguments
  285. * \param args_offset_ms milliseconds offset split from arguments
  286. * \param args_playback_id string to use for playback split from
  287. * arguments (null valid)
  288. * \param response ARI response being built
  289. * \param bridge Bridge the playback is being peformed on
  290. * \param control Control being used for the playback channel
  291. * \param json contents of the response to ARI
  292. * \param playback_url stores playback URL for use with response
  293. *
  294. * \retval -1 operation failed
  295. * \retval operation was successful
  296. */
  297. static int ari_bridges_play_helper(const char *args_media,
  298. const char *args_lang,
  299. int args_offset_ms,
  300. int args_skipms,
  301. const char *args_playback_id,
  302. struct ast_ari_response *response,
  303. struct ast_bridge *bridge,
  304. struct stasis_app_control *control,
  305. struct ast_json **json,
  306. char **playback_url)
  307. {
  308. RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
  309. RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
  310. const char *language;
  311. snapshot = stasis_app_control_get_snapshot(control);
  312. if (!snapshot) {
  313. ast_ari_response_error(
  314. response, 500, "Internal Error", "Failed to get control snapshot");
  315. return -1;
  316. }
  317. language = S_OR(args_lang, snapshot->language);
  318. playback = stasis_app_control_play_uri(control, args_media, language,
  319. bridge->uniqueid, STASIS_PLAYBACK_TARGET_BRIDGE, args_skipms,
  320. args_offset_ms, args_playback_id);
  321. if (!playback) {
  322. ast_ari_response_alloc_failed(response);
  323. return -1;
  324. }
  325. if (ast_asprintf(playback_url, "/playback/%s",
  326. stasis_app_playback_get_id(playback)) == -1) {
  327. playback_url = NULL;
  328. ast_ari_response_alloc_failed(response);
  329. return -1;
  330. }
  331. *json = stasis_app_playback_to_json(playback);
  332. if (!*json) {
  333. ast_ari_response_alloc_failed(response);
  334. return -1;
  335. }
  336. return 0;
  337. }
  338. static void ari_bridges_play_new(const char *args_media,
  339. const char *args_lang,
  340. int args_offset_ms,
  341. int args_skipms,
  342. const char *args_playback_id,
  343. struct ast_ari_response *response,
  344. struct ast_bridge *bridge)
  345. {
  346. RAII_VAR(struct ast_channel *, play_channel, NULL, ast_hangup);
  347. RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
  348. RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
  349. RAII_VAR(struct stasis_forward *, channel_forward, NULL, stasis_forward_cancel);
  350. RAII_VAR(char *, playback_url, NULL, ast_free);
  351. struct stasis_topic *channel_topic;
  352. struct stasis_topic *bridge_topic;
  353. struct bridge_channel_control_thread_data *thread_data;
  354. pthread_t threadid;
  355. if (!(play_channel = prepare_bridge_media_channel("Announcer"))) {
  356. ast_ari_response_error(
  357. response, 500, "Internal Error", "Could not create playback channel");
  358. return;
  359. }
  360. ast_debug(1, "Created announcer channel '%s'\n", ast_channel_name(play_channel));
  361. bridge_topic = ast_bridge_topic(bridge);
  362. channel_topic = ast_channel_topic(play_channel);
  363. /* Forward messages from the playback channel topic to the bridge topic so that anything listening for
  364. * messages on the bridge topic will receive the playback start/stop messages. Other messages that would
  365. * go to this channel will be suppressed since the channel is marked as internal.
  366. */
  367. if (!bridge_topic || !channel_topic || !(channel_forward = stasis_forward_all(channel_topic, bridge_topic))) {
  368. ast_ari_response_error(
  369. response, 500, "Internal Error", "Could not forward playback channel stasis messages to bridge topic");
  370. return;
  371. }
  372. if (ast_unreal_channel_push_to_bridge(play_channel, bridge,
  373. AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE | AST_BRIDGE_CHANNEL_FLAG_LONELY)) {
  374. ast_ari_response_error(
  375. response, 500, "Internal Error", "Failed to put playback channel into the bridge");
  376. return;
  377. }
  378. control = stasis_app_control_create(play_channel);
  379. if (control == NULL) {
  380. ast_ari_response_alloc_failed(response);
  381. return;
  382. }
  383. ao2_lock(control);
  384. if (ari_bridges_play_helper(args_media, args_lang, args_offset_ms,
  385. args_skipms, args_playback_id, response, bridge, control,
  386. &json, &playback_url)) {
  387. ao2_unlock(control);
  388. return;
  389. }
  390. ao2_unlock(control);
  391. if (stasis_app_bridge_playback_channel_add(bridge, play_channel, control)) {
  392. ast_ari_response_alloc_failed(response);
  393. return;
  394. }
  395. /* Give play_channel and control reference to the thread data */
  396. thread_data = ast_calloc(1, sizeof(*thread_data));
  397. if (!thread_data) {
  398. ast_ari_response_alloc_failed(response);
  399. return;
  400. }
  401. thread_data->bridge_channel = play_channel;
  402. thread_data->control = control;
  403. thread_data->forward = channel_forward;
  404. if (ast_pthread_create_detached(&threadid, NULL, bridge_channel_control_thread, thread_data)) {
  405. ast_ari_response_alloc_failed(response);
  406. ast_free(thread_data);
  407. return;
  408. }
  409. /* These are owned by the other thread now, so we don't want RAII_VAR disposing of them. */
  410. play_channel = NULL;
  411. control = NULL;
  412. channel_forward = NULL;
  413. ast_ari_response_created(response, playback_url, ast_json_ref(json));
  414. }
  415. enum play_found_result {
  416. PLAY_FOUND_SUCCESS,
  417. PLAY_FOUND_FAILURE,
  418. PLAY_FOUND_CHANNEL_UNAVAILABLE,
  419. };
  420. /*!
  421. * \brief Performs common setup for a bridge playback operation
  422. * with both new controls and when existing controls are found.
  423. *
  424. * \param args_media media string split from arguments
  425. * \param args_lang language string split from arguments
  426. * \param args_offset_ms milliseconds offset split from arguments
  427. * \param args_playback_id string to use for playback split from
  428. * arguments (null valid)
  429. * \param response ARI response being built
  430. * \param bridge Bridge the playback is being peformed on
  431. * \param found_channel The channel that was found controlling playback
  432. *
  433. * \retval PLAY_FOUND_SUCCESS The operation was successful
  434. * \retval PLAY_FOUND_FAILURE The operation failed (terminal failure)
  435. * \retval PLAY_FOUND_CHANNEL_UNAVAILABLE The operation failed because
  436. * the channel requested to playback with is breaking down.
  437. */
  438. static enum play_found_result ari_bridges_play_found(const char *args_media,
  439. const char *args_lang,
  440. int args_offset_ms,
  441. int args_skipms,
  442. const char *args_playback_id,
  443. struct ast_ari_response *response,
  444. struct ast_bridge *bridge,
  445. struct ast_channel *found_channel)
  446. {
  447. RAII_VAR(struct ast_channel *, play_channel, found_channel, ao2_cleanup);
  448. RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
  449. RAII_VAR(char *, playback_url, NULL, ast_free);
  450. RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
  451. control = stasis_app_control_find_by_channel(play_channel);
  452. if (!control) {
  453. ast_ari_response_error(
  454. response, 500, "Internal Error", "Failed to get control snapshot");
  455. return PLAY_FOUND_FAILURE;
  456. }
  457. ao2_lock(control);
  458. if (stasis_app_control_is_done(control)) {
  459. /* We failed to queue the action. Bailout and return that we aren't terminal. */
  460. ao2_unlock(control);
  461. return PLAY_FOUND_CHANNEL_UNAVAILABLE;
  462. }
  463. if (ari_bridges_play_helper(args_media, args_lang, args_offset_ms,
  464. args_skipms, args_playback_id, response, bridge, control,
  465. &json, &playback_url)) {
  466. ao2_unlock(control);
  467. return PLAY_FOUND_FAILURE;
  468. }
  469. ao2_unlock(control);
  470. ast_ari_response_created(response, playback_url, ast_json_ref(json));
  471. return PLAY_FOUND_SUCCESS;
  472. }
  473. static void ari_bridges_handle_play(
  474. const char *args_bridge_id,
  475. const char *args_media,
  476. const char *args_lang,
  477. int args_offset_ms,
  478. int args_skipms,
  479. const char *args_playback_id,
  480. struct ast_ari_response *response)
  481. {
  482. RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args_bridge_id), ao2_cleanup);
  483. struct ast_channel *play_channel;
  484. ast_assert(response != NULL);
  485. if (!bridge) {
  486. return;
  487. }
  488. while ((play_channel = stasis_app_bridge_playback_channel_find(bridge))) {
  489. /* If ari_bridges_play_found fails because the channel is unavailable for
  490. * playback, The channel will be removed from the playback list soon. We
  491. * can keep trying to get channels from the list until we either get one
  492. * that will work or else there isn't a channel for this bridge anymore,
  493. * in which case we'll revert to ari_bridges_play_new.
  494. */
  495. if (ari_bridges_play_found(args_media, args_lang, args_offset_ms,
  496. args_skipms, args_playback_id, response,bridge,
  497. play_channel) == PLAY_FOUND_CHANNEL_UNAVAILABLE) {
  498. continue;
  499. }
  500. return;
  501. }
  502. ari_bridges_play_new(args_media, args_lang, args_offset_ms,
  503. args_skipms, args_playback_id, response, bridge);
  504. }
  505. void ast_ari_bridges_play(struct ast_variable *headers,
  506. struct ast_ari_bridges_play_args *args,
  507. struct ast_ari_response *response)
  508. {
  509. ari_bridges_handle_play(args->bridge_id,
  510. args->media,
  511. args->lang,
  512. args->offsetms,
  513. args->skipms,
  514. args->playback_id,
  515. response);
  516. }
  517. void ast_ari_bridges_play_with_id(struct ast_variable *headers,
  518. struct ast_ari_bridges_play_with_id_args *args,
  519. struct ast_ari_response *response)
  520. {
  521. ari_bridges_handle_play(args->bridge_id,
  522. args->media,
  523. args->lang,
  524. args->offsetms,
  525. args->skipms,
  526. args->playback_id,
  527. response);
  528. }
  529. void ast_ari_bridges_record(struct ast_variable *headers,
  530. struct ast_ari_bridges_record_args *args,
  531. struct ast_ari_response *response)
  532. {
  533. RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
  534. RAII_VAR(struct ast_channel *, record_channel, NULL, ast_hangup);
  535. RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
  536. RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup);
  537. RAII_VAR(char *, recording_url, NULL, ast_free);
  538. RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
  539. RAII_VAR(struct stasis_app_recording_options *, options, NULL, ao2_cleanup);
  540. RAII_VAR(char *, uri_encoded_name, NULL, ast_free);
  541. RAII_VAR(struct stasis_forward *, channel_forward, NULL, stasis_forward_cancel);
  542. struct stasis_topic *channel_topic;
  543. struct stasis_topic *bridge_topic;
  544. size_t uri_name_maxlen;
  545. struct bridge_channel_control_thread_data *thread_data;
  546. pthread_t threadid;
  547. ast_assert(response != NULL);
  548. if (bridge == NULL) {
  549. return;
  550. }
  551. if (!(record_channel = prepare_bridge_media_channel("Recorder"))) {
  552. ast_ari_response_error(
  553. response, 500, "Internal Server Error", "Failed to create recording channel");
  554. return;
  555. }
  556. bridge_topic = ast_bridge_topic(bridge);
  557. channel_topic = ast_channel_topic(record_channel);
  558. /* Forward messages from the recording channel topic to the bridge topic so that anything listening for
  559. * messages on the bridge topic will receive the recording start/stop messages. Other messages that would
  560. * go to this channel will be suppressed since the channel is marked as internal.
  561. */
  562. if (!bridge_topic || !channel_topic || !(channel_forward = stasis_forward_all(channel_topic, bridge_topic))) {
  563. ast_ari_response_error(
  564. response, 500, "Internal Error", "Could not forward record channel stasis messages to bridge topic");
  565. return;
  566. }
  567. if (ast_unreal_channel_push_to_bridge(record_channel, bridge,
  568. AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE | AST_BRIDGE_CHANNEL_FLAG_LONELY)) {
  569. ast_ari_response_error(
  570. response, 500, "Internal Error", "Failed to put recording channel into the bridge");
  571. return;
  572. }
  573. control = stasis_app_control_create(record_channel);
  574. if (control == NULL) {
  575. ast_ari_response_alloc_failed(response);
  576. return;
  577. }
  578. options = stasis_app_recording_options_create(args->name, args->format);
  579. if (options == NULL) {
  580. ast_ari_response_alloc_failed(response);
  581. return;
  582. }
  583. ast_string_field_build(options, target, "bridge:%s", args->bridge_id);
  584. options->max_silence_seconds = args->max_silence_seconds;
  585. options->max_duration_seconds = args->max_duration_seconds;
  586. options->terminate_on =
  587. stasis_app_recording_termination_parse(args->terminate_on);
  588. options->if_exists =
  589. stasis_app_recording_if_exists_parse(args->if_exists);
  590. options->beep = args->beep;
  591. if (options->terminate_on == STASIS_APP_RECORDING_TERMINATE_INVALID) {
  592. ast_ari_response_error(
  593. response, 400, "Bad Request",
  594. "terminateOn invalid");
  595. return;
  596. }
  597. if (options->if_exists == -1) {
  598. ast_ari_response_error(
  599. response, 400, "Bad Request",
  600. "ifExists invalid");
  601. return;
  602. }
  603. if (!ast_get_format_for_file_ext(options->format)) {
  604. ast_ari_response_error(
  605. response, 422, "Unprocessable Entity",
  606. "specified format is unknown on this system");
  607. return;
  608. }
  609. recording = stasis_app_control_record(control, options);
  610. if (recording == NULL) {
  611. switch(errno) {
  612. case EINVAL:
  613. /* While the arguments are invalid, we should have
  614. * caught them prior to calling record.
  615. */
  616. ast_ari_response_error(
  617. response, 500, "Internal Server Error",
  618. "Error parsing request");
  619. break;
  620. case EEXIST:
  621. ast_ari_response_error(response, 409, "Conflict",
  622. "Recording '%s' already exists and can not be overwritten",
  623. args->name);
  624. break;
  625. case ENOMEM:
  626. ast_ari_response_alloc_failed(response);
  627. break;
  628. case EPERM:
  629. ast_ari_response_error(
  630. response, 400, "Bad Request",
  631. "Recording name invalid");
  632. break;
  633. default:
  634. ast_log(LOG_WARNING,
  635. "Unrecognized recording error: %s\n",
  636. strerror(errno));
  637. ast_ari_response_error(
  638. response, 500, "Internal Server Error",
  639. "Internal Server Error");
  640. break;
  641. }
  642. return;
  643. }
  644. uri_name_maxlen = strlen(args->name) * 3;
  645. uri_encoded_name = ast_malloc(uri_name_maxlen);
  646. if (!uri_encoded_name) {
  647. ast_ari_response_alloc_failed(response);
  648. return;
  649. }
  650. ast_uri_encode(args->name, uri_encoded_name, uri_name_maxlen, ast_uri_http);
  651. if (ast_asprintf(&recording_url, "/recordings/live/%s",
  652. uri_encoded_name) == -1) {
  653. recording_url = NULL;
  654. ast_ari_response_alloc_failed(response);
  655. return;
  656. }
  657. json = stasis_app_recording_to_json(recording);
  658. if (!json) {
  659. ast_ari_response_alloc_failed(response);
  660. return;
  661. }
  662. thread_data = ast_calloc(1, sizeof(*thread_data));
  663. if (!thread_data) {
  664. ast_ari_response_alloc_failed(response);
  665. return;
  666. }
  667. thread_data->bridge_channel = record_channel;
  668. thread_data->control = control;
  669. thread_data->forward = channel_forward;
  670. if (ast_pthread_create_detached(&threadid, NULL, bridge_channel_control_thread, thread_data)) {
  671. ast_ari_response_alloc_failed(response);
  672. ast_free(thread_data);
  673. return;
  674. }
  675. /* These are owned by the other thread now, so we don't want RAII_VAR disposing of them. */
  676. record_channel = NULL;
  677. control = NULL;
  678. channel_forward = NULL;
  679. ast_ari_response_created(response, recording_url, ast_json_ref(json));
  680. }
  681. void ast_ari_bridges_start_moh(struct ast_variable *headers,
  682. struct ast_ari_bridges_start_moh_args *args,
  683. struct ast_ari_response *response)
  684. {
  685. RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
  686. struct ast_channel *moh_channel;
  687. const char *moh_class = args->moh_class;
  688. if (!bridge) {
  689. /* The response is provided by find_bridge() */
  690. return;
  691. }
  692. moh_channel = stasis_app_bridge_moh_channel(bridge);
  693. if (!moh_channel) {
  694. ast_ari_response_alloc_failed(response);
  695. return;
  696. }
  697. ast_moh_start(moh_channel, moh_class, NULL);
  698. ast_ari_response_no_content(response);
  699. }
  700. void ast_ari_bridges_stop_moh(struct ast_variable *headers,
  701. struct ast_ari_bridges_stop_moh_args *args,
  702. struct ast_ari_response *response)
  703. {
  704. RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
  705. if (!bridge) {
  706. /* the response is provided by find_bridge() */
  707. return;
  708. }
  709. if (stasis_app_bridge_moh_stop(bridge)) {
  710. ast_ari_response_error(
  711. response, 409, "Conflict",
  712. "Bridge isn't playing music");
  713. return;
  714. }
  715. ast_ari_response_no_content(response);
  716. }
  717. void ast_ari_bridges_get(struct ast_variable *headers,
  718. struct ast_ari_bridges_get_args *args,
  719. struct ast_ari_response *response)
  720. {
  721. RAII_VAR(struct ast_bridge_snapshot *, snapshot, ast_bridge_snapshot_get_latest(args->bridge_id), ao2_cleanup);
  722. if (!snapshot) {
  723. ast_ari_response_error(
  724. response, 404, "Not Found",
  725. "Bridge not found");
  726. return;
  727. }
  728. ast_ari_response_ok(response,
  729. ast_bridge_snapshot_to_json(snapshot, stasis_app_get_sanitizer()));
  730. }
  731. void ast_ari_bridges_destroy(struct ast_variable *headers,
  732. struct ast_ari_bridges_destroy_args *args,
  733. struct ast_ari_response *response)
  734. {
  735. RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
  736. if (!bridge) {
  737. return;
  738. }
  739. stasis_app_bridge_destroy(args->bridge_id);
  740. ast_ari_response_no_content(response);
  741. }
  742. void ast_ari_bridges_list(struct ast_variable *headers,
  743. struct ast_ari_bridges_list_args *args,
  744. struct ast_ari_response *response)
  745. {
  746. RAII_VAR(struct stasis_cache *, cache, NULL, ao2_cleanup);
  747. RAII_VAR(struct ao2_container *, snapshots, NULL, ao2_cleanup);
  748. RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
  749. struct ao2_iterator i;
  750. void *obj;
  751. cache = ast_bridge_cache();
  752. if (!cache) {
  753. ast_ari_response_error(
  754. response, 500, "Internal Server Error",
  755. "Message bus not initialized");
  756. return;
  757. }
  758. ao2_ref(cache, +1);
  759. snapshots = stasis_cache_dump(cache, ast_bridge_snapshot_type());
  760. if (!snapshots) {
  761. ast_ari_response_alloc_failed(response);
  762. return;
  763. }
  764. json = ast_json_array_create();
  765. if (!json) {
  766. ast_ari_response_alloc_failed(response);
  767. return;
  768. }
  769. i = ao2_iterator_init(snapshots, 0);
  770. while ((obj = ao2_iterator_next(&i))) {
  771. RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup);
  772. struct ast_bridge_snapshot *snapshot = stasis_message_data(msg);
  773. struct ast_json *json_bridge = ast_bridge_snapshot_to_json(snapshot, stasis_app_get_sanitizer());
  774. if (!json_bridge || ast_json_array_append(json, json_bridge)) {
  775. ao2_iterator_destroy(&i);
  776. ast_ari_response_alloc_failed(response);
  777. return;
  778. }
  779. }
  780. ao2_iterator_destroy(&i);
  781. ast_ari_response_ok(response, ast_json_ref(json));
  782. }
  783. void ast_ari_bridges_create(struct ast_variable *headers,
  784. struct ast_ari_bridges_create_args *args,
  785. struct ast_ari_response *response)
  786. {
  787. RAII_VAR(struct ast_bridge *, bridge, stasis_app_bridge_create(args->type, args->name, args->bridge_id), ao2_cleanup);
  788. RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
  789. if (!bridge) {
  790. ast_ari_response_error(
  791. response, 500, "Internal Error",
  792. "Unable to create bridge");
  793. return;
  794. }
  795. ast_bridge_lock(bridge);
  796. snapshot = ast_bridge_snapshot_create(bridge);
  797. ast_bridge_unlock(bridge);
  798. if (!snapshot) {
  799. ast_ari_response_error(
  800. response, 500, "Internal Error",
  801. "Unable to create snapshot for new bridge");
  802. return;
  803. }
  804. ast_ari_response_ok(response,
  805. ast_bridge_snapshot_to_json(snapshot, stasis_app_get_sanitizer()));
  806. }
  807. void ast_ari_bridges_create_or_update_with_id(struct ast_variable *headers,
  808. struct ast_ari_bridges_create_or_update_with_id_args *args,
  809. struct ast_ari_response *response)
  810. {
  811. RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
  812. RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
  813. if (bridge) {
  814. /* update */
  815. if (strcmp(args->name, bridge->name)) {
  816. ast_ari_response_error(
  817. response, 500, "Internal Error",
  818. "Changing bridge name is not implemented");
  819. return;
  820. }
  821. if (!ast_strlen_zero(args->type)) {
  822. ast_ari_response_error(
  823. response, 500, "Internal Error",
  824. "Changing bridge type is not implemented");
  825. return;
  826. }
  827. ast_ari_response_ok(response,
  828. ast_bridge_snapshot_to_json(snapshot, stasis_app_get_sanitizer()));
  829. return;
  830. }
  831. bridge = stasis_app_bridge_create(args->type, args->name, args->bridge_id);
  832. if (!bridge) {
  833. ast_ari_response_error(
  834. response, 500, "Internal Error",
  835. "Unable to create bridge");
  836. return;
  837. }
  838. ast_bridge_lock(bridge);
  839. snapshot = ast_bridge_snapshot_create(bridge);
  840. ast_bridge_unlock(bridge);
  841. if (!snapshot) {
  842. ast_ari_response_error(
  843. response, 500, "Internal Error",
  844. "Unable to create snapshot for new bridge");
  845. return;
  846. }
  847. ast_ari_response_ok(response,
  848. ast_bridge_snapshot_to_json(snapshot, stasis_app_get_sanitizer()));
  849. }