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_FILE_VERSION(__FILE__, "$Revision$")
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"
48 * \brief Finds a bridge, filling the response with an error, if appropriate.
50 * \param[out] response Response to fill with an error if control is not found.
51 * \param bridge_id ID of the bridge to lookup.
54 * \return \c NULL if bridge does not exist.
56 static struct ast_bridge *find_bridge(
57 struct ast_ari_response *response,
58 const char *bridge_id)
60 RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
62 ast_assert(response != NULL);
64 bridge = stasis_app_bridge_find_by_id(bridge_id);
66 RAII_VAR(struct ast_bridge_snapshot *, snapshot,
67 ast_bridge_snapshot_get_latest(bridge_id), ao2_cleanup);
69 ast_ari_response_error(response, 404, "Not found",
74 ast_ari_response_error(response, 409, "Conflict",
75 "Bridge not in Stasis application");
84 * \brief Finds the control object for a channel, filling the response with an
85 * error, if appropriate.
86 * \param[out] response Response to fill with an error if control is not found.
87 * \param channel_id ID of the channel to lookup.
88 * \return Channel control object.
89 * \return \c NULL if control object does not exist.
91 static struct stasis_app_control *find_channel_control(
92 struct ast_ari_response *response,
93 const char *channel_id)
95 RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
97 ast_assert(response != NULL);
99 control = stasis_app_control_find_by_channel_id(channel_id);
100 if (control == NULL) {
101 ast_ari_response_error(response, 422, "Unprocessable Entity",
102 "Channel not in Stasis application");
106 ao2_ref(control, +1);
110 struct control_list {
112 struct stasis_app_control *controls[];
115 static void control_list_dtor(void *obj) {
116 struct control_list *list = obj;
119 for (i = 0; i < list->count; ++i) {
120 ao2_cleanup(list->controls[i]);
121 list->controls[i] = NULL;
125 static struct control_list *control_list_create(struct ast_ari_response *response, size_t count, const char **channels) {
126 RAII_VAR(struct control_list *, list, NULL, ao2_cleanup);
129 if (count == 0 || !channels) {
130 ast_ari_response_error(response, 400, "Bad Request", "Missing parameter channel");
134 list = ao2_alloc(sizeof(*list) + count * sizeof(list->controls[0]), control_list_dtor);
136 ast_ari_response_alloc_failed(response);
140 for (i = 0; i < count; ++i) {
141 if (ast_strlen_zero(channels[i])) {
144 list->controls[list->count] =
145 find_channel_control(response, channels[i]);
146 if (!list->controls[list->count]) {
152 if (list->count == 0) {
153 ast_ari_response_error(response, 400, "Bad Request", "Missing parameter channel");
161 void ast_ari_add_channel_to_bridge(struct ast_variable *headers, struct ast_add_channel_to_bridge_args *args, struct ast_ari_response *response)
163 RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
164 RAII_VAR(struct control_list *, list, NULL, ao2_cleanup);
168 /* Response filled in by find_bridge */
172 list = control_list_create(response, args->channel_count, args->channel);
174 /* Response filled in by control_list_create() */
178 for (i = 0; i < list->count; ++i) {
179 stasis_app_control_clear_roles(list->controls[i]);
180 if (!ast_strlen_zero(args->role)) {
181 if (stasis_app_control_add_role(list->controls[i], args->role)) {
182 ast_ari_response_alloc_failed(response);
188 for (i = 0; i < list->count; ++i) {
189 stasis_app_control_add_channel_to_bridge(list->controls[i], bridge);
192 ast_ari_response_no_content(response);
195 void ast_ari_remove_channel_from_bridge(struct ast_variable *headers, struct ast_remove_channel_from_bridge_args *args, struct ast_ari_response *response)
197 RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
198 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 /* BUGBUG this should make sure the bridge requested for removal is actually
213 * the bridge the channel is in. This will be possible once the bridge uniqueid
214 * is added to the channel snapshot. A 409 response should be issued if the bridge
215 * uniqueids don't match */
216 for (i = 0; i < list->count; ++i) {
217 if (stasis_app_control_remove_channel_from_bridge(list->controls[i], bridge)) {
218 ast_ari_response_error(response, 500, "Internal Error",
219 "Could not remove channel from bridge");
223 if (response->response_code) {
227 ast_ari_response_no_content(response);
230 struct bridge_channel_control_thread_data {
231 struct ast_channel *bridge_channel;
232 struct stasis_app_control *control;
235 static void *bridge_channel_control_thread(void *data)
237 struct bridge_channel_control_thread_data *thread_data = data;
238 struct ast_channel *bridge_channel = thread_data->bridge_channel;
239 struct stasis_app_control *control = thread_data->control;
241 RAII_VAR(struct ast_callid *, callid, ast_channel_callid(bridge_channel), ast_callid_cleanup);
244 ast_callid_threadassoc_add(callid);
247 ast_free(thread_data);
250 stasis_app_control_execute_until_exhausted(bridge_channel, control);
252 ast_hangup(bridge_channel);
253 ao2_cleanup(control);
257 static struct ast_channel *prepare_bridge_media_channel(const char *type)
259 RAII_VAR(struct ast_format_cap *, cap, NULL, ast_format_cap_destroy);
260 struct ast_format format;
262 cap = ast_format_cap_alloc_nolock();
267 ast_format_cap_add(cap, ast_format_set(&format, AST_FORMAT_SLINEAR, 0));
273 return ast_request(type, cap, NULL, "ARI", NULL);
276 void ast_ari_play_on_bridge(struct ast_variable *headers, struct ast_play_on_bridge_args *args, struct ast_ari_response *response)
278 RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
279 RAII_VAR(struct ast_channel *, play_channel, NULL, ast_hangup);
280 RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
281 RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
282 RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
283 RAII_VAR(char *, playback_url, NULL, ast_free);
284 RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
286 struct bridge_channel_control_thread_data *thread_data;
287 const char *language;
290 ast_assert(response != NULL);
296 if (!(play_channel = prepare_bridge_media_channel("Announcer"))) {
297 ast_ari_response_error(
298 response, 500, "Internal Error", "Could not create playback channel");
301 ast_debug(1, "Created announcer channel '%s'\n", ast_channel_name(play_channel));
303 if (ast_unreal_channel_push_to_bridge(play_channel, bridge,
304 AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE | AST_BRIDGE_CHANNEL_FLAG_LONELY)) {
305 ast_ari_response_error(
306 response, 500, "Internal Error", "Failed to put playback channel into the bridge");
310 control = stasis_app_control_create(play_channel);
311 if (control == NULL) {
312 ast_ari_response_alloc_failed(response);
316 snapshot = stasis_app_control_get_snapshot(control);
318 ast_ari_response_error(
319 response, 500, "Internal Error", "Failed to get control snapshot");
323 language = S_OR(args->lang, snapshot->language);
325 playback = stasis_app_control_play_uri(control, args->media, language,
326 args->bridge_id, STASIS_PLAYBACK_TARGET_BRIDGE, args->skipms,
330 ast_ari_response_alloc_failed(response);
334 ast_asprintf(&playback_url, "/playback/%s",
335 stasis_app_playback_get_id(playback));
338 ast_ari_response_alloc_failed(response);
342 json = stasis_app_playback_to_json(playback);
344 ast_ari_response_alloc_failed(response);
348 /* Give play_channel and control reference to the thread data */
349 thread_data = ast_calloc(1, sizeof(*thread_data));
351 ast_ari_response_alloc_failed(response);
355 thread_data->bridge_channel = play_channel;
356 thread_data->control = control;
358 if (ast_pthread_create_detached(&threadid, NULL, bridge_channel_control_thread, thread_data)) {
359 ast_ari_response_alloc_failed(response);
360 ast_free(thread_data);
364 /* These are owned by the other thread now, so we don't want RAII_VAR disposing of them. */
368 ast_ari_response_created(response, playback_url, json);
371 void ast_ari_record_bridge(struct ast_variable *headers, struct ast_record_bridge_args *args, struct ast_ari_response *response)
373 RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
374 RAII_VAR(struct ast_channel *, record_channel, NULL, ast_hangup);
375 RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
376 RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup);
377 RAII_VAR(char *, recording_url, NULL, ast_free);
378 RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
379 RAII_VAR(struct stasis_app_recording_options *, options, NULL, ao2_cleanup);
380 RAII_VAR(char *, uri_encoded_name, NULL, ast_free);
382 size_t uri_name_maxlen;
383 struct bridge_channel_control_thread_data *thread_data;
386 ast_assert(response != NULL);
388 if (bridge == NULL) {
392 if (!(record_channel = prepare_bridge_media_channel("Recorder"))) {
393 ast_ari_response_error(
394 response, 500, "Internal Server Error", "Failed to create recording channel");
398 if (ast_unreal_channel_push_to_bridge(record_channel, bridge,
399 AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE | AST_BRIDGE_CHANNEL_FLAG_LONELY)) {
400 ast_ari_response_error(
401 response, 500, "Internal Error", "Failed to put recording channel into the bridge");
405 control = stasis_app_control_create(record_channel);
406 if (control == NULL) {
407 ast_ari_response_alloc_failed(response);
411 options = stasis_app_recording_options_create(args->name, args->format);
412 if (options == NULL) {
413 ast_ari_response_alloc_failed(response);
417 options->max_silence_seconds = args->max_silence_seconds;
418 options->max_duration_seconds = args->max_duration_seconds;
419 options->terminate_on =
420 stasis_app_recording_termination_parse(args->terminate_on);
422 stasis_app_recording_if_exists_parse(args->if_exists);
423 options->beep = args->beep;
425 recording = stasis_app_control_record(control, options);
426 if (recording == NULL) {
429 /* While the arguments are invalid, we should have
430 * caught them prior to calling record.
432 ast_ari_response_error(
433 response, 500, "Internal Server Error",
434 "Error parsing request");
437 ast_ari_response_error(response, 409, "Conflict",
438 "Recording '%s' already in progress",
442 ast_ari_response_alloc_failed(response);
445 ast_ari_response_error(
446 response, 400, "Bad Request",
447 "Recording name invalid");
451 "Unrecognized recording error: %s\n",
453 ast_ari_response_error(
454 response, 500, "Internal Server Error",
455 "Internal Server Error");
461 uri_name_maxlen = strlen(args->name) * 3;
462 uri_encoded_name = ast_malloc(uri_name_maxlen);
463 if (!uri_encoded_name) {
464 ast_ari_response_alloc_failed(response);
467 ast_uri_encode(args->name, uri_encoded_name, uri_name_maxlen, ast_uri_http);
469 ast_asprintf(&recording_url, "/recordings/live/%s", uri_encoded_name);
470 if (!recording_url) {
471 ast_ari_response_alloc_failed(response);
475 json = stasis_app_recording_to_json(recording);
477 ast_ari_response_alloc_failed(response);
481 thread_data = ast_calloc(1, sizeof(*thread_data));
483 ast_ari_response_alloc_failed(response);
487 thread_data->bridge_channel = record_channel;
488 thread_data->control = control;
490 if (ast_pthread_create_detached(&threadid, NULL, bridge_channel_control_thread, thread_data)) {
491 ast_ari_response_alloc_failed(response);
492 ast_free(thread_data);
496 /* These are owned by the other thread now, so we don't want RAII_VAR disposing of them. */
497 record_channel = NULL;
500 ast_ari_response_created(response, recording_url, json);
503 void ast_ari_get_bridge(struct ast_variable *headers, struct ast_get_bridge_args *args, struct ast_ari_response *response)
505 RAII_VAR(struct ast_bridge_snapshot *, snapshot, ast_bridge_snapshot_get_latest(args->bridge_id), ao2_cleanup);
507 ast_ari_response_error(
508 response, 404, "Not Found",
513 ast_ari_response_ok(response,
514 ast_bridge_snapshot_to_json(snapshot));
517 void ast_ari_delete_bridge(struct ast_variable *headers, struct ast_delete_bridge_args *args, struct ast_ari_response *response)
519 RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
524 stasis_app_bridge_destroy(args->bridge_id);
525 ast_ari_response_no_content(response);
528 void ast_ari_get_bridges(struct ast_variable *headers, struct ast_get_bridges_args *args, struct ast_ari_response *response)
530 RAII_VAR(struct stasis_cache *, cache, NULL, ao2_cleanup);
531 RAII_VAR(struct ao2_container *, snapshots, NULL, ao2_cleanup);
532 RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
533 struct ao2_iterator i;
536 cache = ast_bridge_cache();
538 ast_ari_response_error(
539 response, 500, "Internal Server Error",
540 "Message bus not initialized");
545 snapshots = stasis_cache_dump(cache, ast_bridge_snapshot_type());
547 ast_ari_response_alloc_failed(response);
551 json = ast_json_array_create();
553 ast_ari_response_alloc_failed(response);
557 i = ao2_iterator_init(snapshots, 0);
558 while ((obj = ao2_iterator_next(&i))) {
559 RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup);
560 struct ast_bridge_snapshot *snapshot = stasis_message_data(msg);
561 if (ast_json_array_append(json, ast_bridge_snapshot_to_json(snapshot))) {
562 ast_ari_response_alloc_failed(response);
566 ao2_iterator_destroy(&i);
568 ast_ari_response_ok(response, ast_json_ref(json));
571 void ast_ari_new_bridge(struct ast_variable *headers, struct ast_new_bridge_args *args, struct ast_ari_response *response)
573 RAII_VAR(struct ast_bridge *, bridge, stasis_app_bridge_create(args->type), ao2_cleanup);
574 RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
577 ast_ari_response_error(
578 response, 500, "Internal Error",
579 "Unable to create bridge");
583 snapshot = ast_bridge_snapshot_create(bridge);
585 ast_ari_response_error(
586 response, 500, "Internal Error",
587 "Unable to create snapshot for new bridge");
591 ast_ari_response_ok(response,
592 ast_bridge_snapshot_to_json(snapshot));