2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2012 - 2013, Digium, Inc.
6 * David M. Lee, II <dlee@digium.com>
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.
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.
21 * \brief Implementation for ARI stubs.
23 * \author David M. Lee, II <dlee@digium.com>
27 <support_level>core</support_level>
32 ASTERISK_REGISTER_FILE()
34 #include "resource_bridges.h"
35 #include "asterisk/stasis.h"
36 #include "asterisk/stasis_bridges.h"
37 #include "asterisk/stasis_app.h"
38 #include "asterisk/stasis_app_playback.h"
39 #include "asterisk/stasis_app_recording.h"
40 #include "asterisk/stasis_channels.h"
41 #include "asterisk/core_unreal.h"
42 #include "asterisk/channel.h"
43 #include "asterisk/bridge.h"
44 #include "asterisk/format_cap.h"
45 #include "asterisk/file.h"
46 #include "asterisk/musiconhold.h"
47 #include "asterisk/format_cache.h"
50 * \brief Finds a bridge, filling the response with an error, if appropriate.
52 * \param[out] response Response to fill with an error if control is not found.
53 * \param bridge_id ID of the bridge to lookup.
56 * \return \c NULL if bridge does not exist.
58 static struct ast_bridge *find_bridge(
59 struct ast_ari_response *response,
60 const char *bridge_id)
62 RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
64 ast_assert(response != NULL);
66 bridge = stasis_app_bridge_find_by_id(bridge_id);
68 RAII_VAR(struct ast_bridge_snapshot *, snapshot,
69 ast_bridge_snapshot_get_latest(bridge_id), ao2_cleanup);
71 ast_ari_response_error(response, 404, "Not found",
76 ast_ari_response_error(response, 409, "Conflict",
77 "Bridge not in Stasis application");
86 * \brief Finds the control object for a channel, filling the response with an
87 * error, if appropriate.
88 * \param[out] response Response to fill with an error if control is not found.
89 * \param channel_id ID of the channel to lookup.
90 * \return Channel control object.
91 * \return \c NULL if control object does not exist.
93 static struct stasis_app_control *find_channel_control(
94 struct ast_ari_response *response,
95 const char *channel_id)
97 RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
99 ast_assert(response != NULL);
101 control = stasis_app_control_find_by_channel_id(channel_id);
102 if (control == NULL) {
103 /* Distinguish between 400 and 422 errors */
104 RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL,
106 snapshot = ast_channel_snapshot_get_latest(channel_id);
107 if (snapshot == NULL) {
108 ast_log(LOG_DEBUG, "Couldn't find '%s'\n", channel_id);
109 ast_ari_response_error(response, 400, "Bad Request",
110 "Channel not found");
114 ast_log(LOG_DEBUG, "Found non-stasis '%s'\n", channel_id);
115 ast_ari_response_error(response, 422, "Unprocessable Entity",
116 "Channel not in Stasis application");
120 ao2_ref(control, +1);
124 struct control_list {
126 struct stasis_app_control *controls[];
129 static void control_list_dtor(void *obj) {
130 struct control_list *list = obj;
133 for (i = 0; i < list->count; ++i) {
134 ao2_cleanup(list->controls[i]);
135 list->controls[i] = NULL;
139 static struct control_list *control_list_create(struct ast_ari_response *response, size_t count, const char **channels) {
140 RAII_VAR(struct control_list *, list, NULL, ao2_cleanup);
143 if (count == 0 || !channels) {
144 ast_ari_response_error(response, 400, "Bad Request", "Missing parameter channel");
148 list = ao2_alloc(sizeof(*list) + count * sizeof(list->controls[0]), control_list_dtor);
150 ast_ari_response_alloc_failed(response);
154 for (i = 0; i < count; ++i) {
155 if (ast_strlen_zero(channels[i])) {
158 list->controls[list->count] =
159 find_channel_control(response, channels[i]);
160 if (!list->controls[list->count]) {
161 /* response filled in by find_channel_control() */
167 if (list->count == 0) {
168 ast_ari_response_error(response, 400, "Bad Request", "Missing parameter channel");
176 static int check_add_remove_channel(struct ast_ari_response *response,
177 struct stasis_app_control *control,
178 enum stasis_app_control_channel_result result)
181 case STASIS_APP_CHANNEL_RECORDING :
182 ast_ari_response_error(
183 response, 409, "Conflict", "Channel %s currently recording",
184 stasis_app_control_get_channel_id(control));
186 case STASIS_APP_CHANNEL_OKAY:
192 void ast_ari_bridges_add_channel(struct ast_variable *headers,
193 struct ast_ari_bridges_add_channel_args *args,
194 struct ast_ari_response *response)
196 RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
197 RAII_VAR(struct control_list *, list, NULL, ao2_cleanup);
202 /* Response filled in by find_bridge() */
206 list = control_list_create(response, args->channel_count, args->channel);
208 /* Response filled in by control_list_create() */
212 for (i = 0; i < list->count; ++i) {
213 stasis_app_control_clear_roles(list->controls[i]);
214 if (!ast_strlen_zero(args->role)) {
215 if (stasis_app_control_add_role(list->controls[i], args->role)) {
216 ast_ari_response_alloc_failed(response);
222 for (i = 0; i < list->count; ++i) {
223 if ((has_error = check_add_remove_channel(response, list->controls[i],
224 stasis_app_control_add_channel_to_bridge(
225 list->controls[i], bridge)))) {
231 ast_ari_response_no_content(response);
235 void ast_ari_bridges_remove_channel(struct ast_variable *headers,
236 struct ast_ari_bridges_remove_channel_args *args,
237 struct ast_ari_response *response)
239 RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
240 RAII_VAR(struct control_list *, list, NULL, ao2_cleanup);
244 /* Response filled in by find_bridge() */
248 list = control_list_create(response, args->channel_count, args->channel);
250 /* Response filled in by control_list_create() */
254 /* Make sure all of the channels are in this bridge */
255 for (i = 0; i < list->count; ++i) {
256 if (stasis_app_get_bridge(list->controls[i]) != bridge) {
257 ast_log(LOG_WARNING, "Channel %s not in bridge %s\n",
258 args->channel[i], args->bridge_id);
259 ast_ari_response_error(response, 422,
260 "Unprocessable Entity",
261 "Channel not in this bridge");
266 /* Now actually remove it */
267 for (i = 0; i < list->count; ++i) {
268 stasis_app_control_remove_channel_from_bridge(list->controls[i],
272 ast_ari_response_no_content(response);
275 struct bridge_channel_control_thread_data {
276 struct ast_channel *bridge_channel;
277 struct stasis_app_control *control;
278 struct stasis_forward *forward;
281 static void *bridge_channel_control_thread(void *data)
283 struct bridge_channel_control_thread_data *thread_data = data;
284 struct ast_channel *bridge_channel = thread_data->bridge_channel;
285 struct stasis_app_control *control = thread_data->control;
286 struct stasis_forward *forward = thread_data->forward;
287 ast_callid callid = ast_channel_callid(bridge_channel);
290 ast_callid_threadassoc_add(callid);
293 ast_free(thread_data);
296 stasis_app_control_execute_until_exhausted(bridge_channel, control);
298 ast_hangup(bridge_channel);
299 ao2_cleanup(control);
300 stasis_forward_cancel(forward);
304 static struct ast_channel *prepare_bridge_media_channel(const char *type)
306 RAII_VAR(struct ast_format_cap *, cap, NULL, ao2_cleanup);
307 struct ast_channel *chan;
309 cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
314 ast_format_cap_append(cap, ast_format_slin, 0);
316 chan = ast_request(type, cap, NULL, NULL, "ARI", NULL);
321 if (stasis_app_channel_unreal_set_internal(chan)) {
322 ast_channel_cleanup(chan);
329 * \brief Performs common setup for a bridge playback operation
330 * with both new controls and when existing controls are found.
332 * \param args_media media string split from arguments
333 * \param args_lang language string split from arguments
334 * \param args_offset_ms milliseconds offset split from arguments
335 * \param args_playback_id string to use for playback split from
336 * arguments (null valid)
337 * \param response ARI response being built
338 * \param bridge Bridge the playback is being peformed on
339 * \param control Control being used for the playback channel
340 * \param json contents of the response to ARI
341 * \param playback_url stores playback URL for use with response
343 * \retval -1 operation failed
344 * \retval operation was successful
346 static int ari_bridges_play_helper(const char *args_media,
347 const char *args_lang,
350 const char *args_playback_id,
351 struct ast_ari_response *response,
352 struct ast_bridge *bridge,
353 struct stasis_app_control *control,
354 struct ast_json **json,
357 RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
358 RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
360 const char *language;
362 snapshot = stasis_app_control_get_snapshot(control);
364 ast_ari_response_error(
365 response, 500, "Internal Error", "Failed to get control snapshot");
369 language = S_OR(args_lang, snapshot->language);
371 playback = stasis_app_control_play_uri(control, args_media, language,
372 bridge->uniqueid, STASIS_PLAYBACK_TARGET_BRIDGE, args_skipms,
373 args_offset_ms, args_playback_id);
376 ast_ari_response_alloc_failed(response);
380 if (ast_asprintf(playback_url, "/playback/%s",
381 stasis_app_playback_get_id(playback)) == -1) {
383 ast_ari_response_alloc_failed(response);
387 *json = stasis_app_playback_to_json(playback);
389 ast_ari_response_alloc_failed(response);
396 static void ari_bridges_play_new(const char *args_media,
397 const char *args_lang,
400 const char *args_playback_id,
401 struct ast_ari_response *response,
402 struct ast_bridge *bridge)
404 RAII_VAR(struct ast_channel *, play_channel, NULL, ast_hangup);
405 RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
406 RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
407 RAII_VAR(struct stasis_forward *, channel_forward, NULL, stasis_forward_cancel);
408 RAII_VAR(char *, playback_url, NULL, ast_free);
410 struct stasis_topic *channel_topic;
411 struct stasis_topic *bridge_topic;
412 struct bridge_channel_control_thread_data *thread_data;
415 if (!(play_channel = prepare_bridge_media_channel("Announcer"))) {
416 ast_ari_response_error(
417 response, 500, "Internal Error", "Could not create playback channel");
420 ast_debug(1, "Created announcer channel '%s'\n", ast_channel_name(play_channel));
422 bridge_topic = ast_bridge_topic(bridge);
423 channel_topic = ast_channel_topic(play_channel);
425 /* Forward messages from the playback channel topic to the bridge topic so that anything listening for
426 * messages on the bridge topic will receive the playback start/stop messages. Other messages that would
427 * go to this channel will be suppressed since the channel is marked as internal.
429 if (!bridge_topic || !channel_topic || !(channel_forward = stasis_forward_all(channel_topic, bridge_topic))) {
430 ast_ari_response_error(
431 response, 500, "Internal Error", "Could not forward playback channel stasis messages to bridge topic");
435 if (ast_unreal_channel_push_to_bridge(play_channel, bridge,
436 AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE | AST_BRIDGE_CHANNEL_FLAG_LONELY)) {
437 ast_ari_response_error(
438 response, 500, "Internal Error", "Failed to put playback channel into the bridge");
442 control = stasis_app_control_create(play_channel);
443 if (control == NULL) {
444 ast_ari_response_alloc_failed(response);
449 if (ari_bridges_play_helper(args_media, args_lang, args_offset_ms,
450 args_skipms, args_playback_id, response, bridge, control,
451 &json, &playback_url)) {
457 if (stasis_app_bridge_playback_channel_add(bridge, play_channel, control)) {
458 ast_ari_response_alloc_failed(response);
462 /* Give play_channel and control reference to the thread data */
463 thread_data = ast_calloc(1, sizeof(*thread_data));
465 ast_ari_response_alloc_failed(response);
469 thread_data->bridge_channel = play_channel;
470 thread_data->control = control;
471 thread_data->forward = channel_forward;
473 if (ast_pthread_create_detached(&threadid, NULL, bridge_channel_control_thread, thread_data)) {
474 ast_ari_response_alloc_failed(response);
475 ast_free(thread_data);
479 /* These are owned by the other thread now, so we don't want RAII_VAR disposing of them. */
482 channel_forward = NULL;
484 ast_ari_response_created(response, playback_url, ast_json_ref(json));
487 enum play_found_result {
490 PLAY_FOUND_CHANNEL_UNAVAILABLE,
494 * \brief Performs common setup for a bridge playback operation
495 * with both new controls and when existing controls are found.
497 * \param args_media media string split from arguments
498 * \param args_lang language string split from arguments
499 * \param args_offset_ms milliseconds offset split from arguments
500 * \param args_playback_id string to use for playback split from
501 * arguments (null valid)
502 * \param response ARI response being built
503 * \param bridge Bridge the playback is being peformed on
504 * \param found_channel The channel that was found controlling playback
506 * \retval PLAY_FOUND_SUCCESS The operation was successful
507 * \retval PLAY_FOUND_FAILURE The operation failed (terminal failure)
508 * \retval PLAY_FOUND_CHANNEL_UNAVAILABLE The operation failed because
509 * the channel requested to playback with is breaking down.
511 static enum play_found_result ari_bridges_play_found(const char *args_media,
512 const char *args_lang,
515 const char *args_playback_id,
516 struct ast_ari_response *response,
517 struct ast_bridge *bridge,
518 struct ast_channel *found_channel)
520 RAII_VAR(struct ast_channel *, play_channel, found_channel, ao2_cleanup);
521 RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
522 RAII_VAR(char *, playback_url, NULL, ast_free);
523 RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
525 control = stasis_app_control_find_by_channel(play_channel);
527 ast_ari_response_error(
528 response, 500, "Internal Error", "Failed to get control snapshot");
529 return PLAY_FOUND_FAILURE;
533 if (stasis_app_control_is_done(control)) {
534 /* We failed to queue the action. Bailout and return that we aren't terminal. */
536 return PLAY_FOUND_CHANNEL_UNAVAILABLE;
539 if (ari_bridges_play_helper(args_media, args_lang, args_offset_ms,
540 args_skipms, args_playback_id, response, bridge, control,
541 &json, &playback_url)) {
543 return PLAY_FOUND_FAILURE;
547 ast_ari_response_created(response, playback_url, ast_json_ref(json));
548 return PLAY_FOUND_SUCCESS;
551 static void ari_bridges_handle_play(
552 const char *args_bridge_id,
553 const char *args_media,
554 const char *args_lang,
557 const char *args_playback_id,
558 struct ast_ari_response *response)
560 RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args_bridge_id), ao2_cleanup);
561 struct ast_channel *play_channel;
563 ast_assert(response != NULL);
569 while ((play_channel = stasis_app_bridge_playback_channel_find(bridge))) {
570 /* If ari_bridges_play_found fails because the channel is unavailable for
571 * playback, The channel will be removed from the playback list soon. We
572 * can keep trying to get channels from the list until we either get one
573 * that will work or else there isn't a channel for this bridge anymore,
574 * in which case we'll revert to ari_bridges_play_new.
576 if (ari_bridges_play_found(args_media, args_lang, args_offset_ms,
577 args_skipms, args_playback_id, response,bridge,
578 play_channel) == PLAY_FOUND_CHANNEL_UNAVAILABLE) {
584 ari_bridges_play_new(args_media, args_lang, args_offset_ms,
585 args_skipms, args_playback_id, response, bridge);
589 void ast_ari_bridges_play(struct ast_variable *headers,
590 struct ast_ari_bridges_play_args *args,
591 struct ast_ari_response *response)
593 ari_bridges_handle_play(args->bridge_id,
602 void ast_ari_bridges_play_with_id(struct ast_variable *headers,
603 struct ast_ari_bridges_play_with_id_args *args,
604 struct ast_ari_response *response)
606 ari_bridges_handle_play(args->bridge_id,
615 void ast_ari_bridges_record(struct ast_variable *headers,
616 struct ast_ari_bridges_record_args *args,
617 struct ast_ari_response *response)
619 RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
620 RAII_VAR(struct ast_channel *, record_channel, NULL, ast_hangup);
621 RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
622 RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup);
623 RAII_VAR(char *, recording_url, NULL, ast_free);
624 RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
625 RAII_VAR(struct stasis_app_recording_options *, options, NULL, ao2_cleanup);
626 RAII_VAR(char *, uri_encoded_name, NULL, ast_free);
627 RAII_VAR(struct stasis_forward *, channel_forward, NULL, stasis_forward_cancel);
629 struct stasis_topic *channel_topic;
630 struct stasis_topic *bridge_topic;
631 size_t uri_name_maxlen;
632 struct bridge_channel_control_thread_data *thread_data;
635 ast_assert(response != NULL);
637 if (bridge == NULL) {
641 if (!(record_channel = prepare_bridge_media_channel("Recorder"))) {
642 ast_ari_response_error(
643 response, 500, "Internal Server Error", "Failed to create recording channel");
647 bridge_topic = ast_bridge_topic(bridge);
648 channel_topic = ast_channel_topic(record_channel);
650 /* Forward messages from the recording channel topic to the bridge topic so that anything listening for
651 * messages on the bridge topic will receive the recording start/stop messages. Other messages that would
652 * go to this channel will be suppressed since the channel is marked as internal.
654 if (!bridge_topic || !channel_topic || !(channel_forward = stasis_forward_all(channel_topic, bridge_topic))) {
655 ast_ari_response_error(
656 response, 500, "Internal Error", "Could not forward record channel stasis messages to bridge topic");
660 if (ast_unreal_channel_push_to_bridge(record_channel, bridge,
661 AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE | AST_BRIDGE_CHANNEL_FLAG_LONELY)) {
662 ast_ari_response_error(
663 response, 500, "Internal Error", "Failed to put recording channel into the bridge");
667 control = stasis_app_control_create(record_channel);
668 if (control == NULL) {
669 ast_ari_response_alloc_failed(response);
673 options = stasis_app_recording_options_create(args->name, args->format);
674 if (options == NULL) {
675 ast_ari_response_alloc_failed(response);
679 ast_string_field_build(options, target, "bridge:%s", args->bridge_id);
680 options->max_silence_seconds = args->max_silence_seconds;
681 options->max_duration_seconds = args->max_duration_seconds;
682 options->terminate_on =
683 stasis_app_recording_termination_parse(args->terminate_on);
685 stasis_app_recording_if_exists_parse(args->if_exists);
686 options->beep = args->beep;
688 if (options->terminate_on == STASIS_APP_RECORDING_TERMINATE_INVALID) {
689 ast_ari_response_error(
690 response, 400, "Bad Request",
691 "terminateOn invalid");
695 if (options->if_exists == AST_RECORD_IF_EXISTS_ERROR) {
696 ast_ari_response_error(
697 response, 400, "Bad Request",
702 if (!ast_get_format_for_file_ext(options->format)) {
703 ast_ari_response_error(
704 response, 422, "Unprocessable Entity",
705 "specified format is unknown on this system");
709 recording = stasis_app_control_record(control, options);
710 if (recording == NULL) {
713 /* While the arguments are invalid, we should have
714 * caught them prior to calling record.
716 ast_ari_response_error(
717 response, 500, "Internal Server Error",
718 "Error parsing request");
721 ast_ari_response_error(response, 409, "Conflict",
722 "Recording '%s' already exists and can not be overwritten",
726 ast_ari_response_alloc_failed(response);
729 ast_ari_response_error(
730 response, 400, "Bad Request",
731 "Recording name invalid");
735 "Unrecognized recording error: %s\n",
737 ast_ari_response_error(
738 response, 500, "Internal Server Error",
739 "Internal Server Error");
745 uri_name_maxlen = strlen(args->name) * 3;
746 uri_encoded_name = ast_malloc(uri_name_maxlen);
747 if (!uri_encoded_name) {
748 ast_ari_response_alloc_failed(response);
751 ast_uri_encode(args->name, uri_encoded_name, uri_name_maxlen, ast_uri_http);
753 if (ast_asprintf(&recording_url, "/recordings/live/%s",
754 uri_encoded_name) == -1) {
755 recording_url = NULL;
756 ast_ari_response_alloc_failed(response);
760 json = stasis_app_recording_to_json(recording);
762 ast_ari_response_alloc_failed(response);
766 thread_data = ast_calloc(1, sizeof(*thread_data));
768 ast_ari_response_alloc_failed(response);
772 thread_data->bridge_channel = record_channel;
773 thread_data->control = control;
774 thread_data->forward = channel_forward;
776 if (ast_pthread_create_detached(&threadid, NULL, bridge_channel_control_thread, thread_data)) {
777 ast_ari_response_alloc_failed(response);
778 ast_free(thread_data);
782 /* These are owned by the other thread now, so we don't want RAII_VAR disposing of them. */
783 record_channel = NULL;
785 channel_forward = NULL;
787 ast_ari_response_created(response, recording_url, ast_json_ref(json));
790 void ast_ari_bridges_start_moh(struct ast_variable *headers,
791 struct ast_ari_bridges_start_moh_args *args,
792 struct ast_ari_response *response)
794 RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
795 struct ast_channel *moh_channel;
796 const char *moh_class = args->moh_class;
799 /* The response is provided by find_bridge() */
803 moh_channel = stasis_app_bridge_moh_channel(bridge);
805 ast_ari_response_alloc_failed(response);
809 ast_moh_start(moh_channel, moh_class, NULL);
811 ast_ari_response_no_content(response);
815 void ast_ari_bridges_stop_moh(struct ast_variable *headers,
816 struct ast_ari_bridges_stop_moh_args *args,
817 struct ast_ari_response *response)
819 RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
822 /* the response is provided by find_bridge() */
826 if (stasis_app_bridge_moh_stop(bridge)) {
827 ast_ari_response_error(
828 response, 409, "Conflict",
829 "Bridge isn't playing music");
833 ast_ari_response_no_content(response);
836 void ast_ari_bridges_get(struct ast_variable *headers,
837 struct ast_ari_bridges_get_args *args,
838 struct ast_ari_response *response)
840 RAII_VAR(struct ast_bridge_snapshot *, snapshot, ast_bridge_snapshot_get_latest(args->bridge_id), ao2_cleanup);
842 ast_ari_response_error(
843 response, 404, "Not Found",
848 ast_ari_response_ok(response,
849 ast_bridge_snapshot_to_json(snapshot, stasis_app_get_sanitizer()));
852 void ast_ari_bridges_destroy(struct ast_variable *headers,
853 struct ast_ari_bridges_destroy_args *args,
854 struct ast_ari_response *response)
856 RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
861 stasis_app_bridge_destroy(args->bridge_id);
862 ast_ari_response_no_content(response);
865 void ast_ari_bridges_list(struct ast_variable *headers,
866 struct ast_ari_bridges_list_args *args,
867 struct ast_ari_response *response)
869 RAII_VAR(struct stasis_cache *, cache, NULL, ao2_cleanup);
870 RAII_VAR(struct ao2_container *, snapshots, NULL, ao2_cleanup);
871 RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
872 struct ao2_iterator i;
875 cache = ast_bridge_cache();
877 ast_ari_response_error(
878 response, 500, "Internal Server Error",
879 "Message bus not initialized");
884 snapshots = stasis_cache_dump(cache, ast_bridge_snapshot_type());
886 ast_ari_response_alloc_failed(response);
890 json = ast_json_array_create();
892 ast_ari_response_alloc_failed(response);
896 i = ao2_iterator_init(snapshots, 0);
897 while ((obj = ao2_iterator_next(&i))) {
898 RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup);
899 struct ast_bridge_snapshot *snapshot = stasis_message_data(msg);
900 struct ast_json *json_bridge = ast_bridge_snapshot_to_json(snapshot, stasis_app_get_sanitizer());
902 if (!json_bridge || ast_json_array_append(json, json_bridge)) {
903 ao2_iterator_destroy(&i);
904 ast_ari_response_alloc_failed(response);
908 ao2_iterator_destroy(&i);
910 ast_ari_response_ok(response, ast_json_ref(json));
913 void ast_ari_bridges_create(struct ast_variable *headers,
914 struct ast_ari_bridges_create_args *args,
915 struct ast_ari_response *response)
917 RAII_VAR(struct ast_bridge *, bridge, stasis_app_bridge_create(args->type, args->name, args->bridge_id), ao2_cleanup);
918 RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
921 ast_ari_response_error(
922 response, 500, "Internal Error",
923 "Unable to create bridge");
927 ast_bridge_lock(bridge);
928 snapshot = ast_bridge_snapshot_create(bridge);
929 ast_bridge_unlock(bridge);
932 ast_ari_response_error(
933 response, 500, "Internal Error",
934 "Unable to create snapshot for new bridge");
938 ast_ari_response_ok(response,
939 ast_bridge_snapshot_to_json(snapshot, stasis_app_get_sanitizer()));
942 void ast_ari_bridges_create_with_id(struct ast_variable *headers,
943 struct ast_ari_bridges_create_with_id_args *args,
944 struct ast_ari_response *response)
946 RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
947 RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
951 if (!ast_strlen_zero(args->name)) {
952 if (!strcmp(args->name, bridge->name)) {
953 ast_ari_response_error(
954 response, 500, "Internal Error",
955 "Changing bridge name is not implemented");
959 if (!ast_strlen_zero(args->type)) {
960 ast_ari_response_error(
961 response, 500, "Internal Error",
962 "Supplying a bridge type when updating a bridge is not allowed.");
965 ast_ari_response_ok(response,
966 ast_bridge_snapshot_to_json(snapshot, stasis_app_get_sanitizer()));
970 bridge = stasis_app_bridge_create(args->type, args->name, args->bridge_id);
972 ast_ari_response_error(
973 response, 500, "Internal Error",
974 "Unable to create bridge");
978 ast_bridge_lock(bridge);
979 snapshot = ast_bridge_snapshot_create(bridge);
980 ast_bridge_unlock(bridge);
983 ast_ari_response_error(
984 response, 500, "Internal Error",
985 "Unable to create snapshot for new bridge");
989 ast_ari_response_ok(response,
990 ast_bridge_snapshot_to_json(snapshot, stasis_app_get_sanitizer()));