65fe8d79f7e201b524c7af4d59f243bec3a5ee5d
[asterisk/asterisk.git] / res / ari / resource_bridges.c
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
19 /*! \file
20  *
21  * \brief Implementation for ARI stubs.
22  *
23  * \author David M. Lee, II <dlee@digium.com>
24  */
25
26 /*** MODULEINFO
27         <support_level>core</support_level>
28  ***/
29
30 #include "asterisk.h"
31
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
33
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
47 /*!
48  * \brief Finds a bridge, filling the response with an error, if appropriate.
49  *
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.
52  *
53  * \return Bridget.
54  * \return \c NULL if bridge does not exist.
55  */
56 static struct ast_bridge *find_bridge(
57         struct ast_ari_response *response,
58         const char *bridge_id)
59 {
60         RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
61
62         ast_assert(response != NULL);
63
64         bridge = stasis_app_bridge_find_by_id(bridge_id);
65         if (bridge == NULL) {
66                 RAII_VAR(struct ast_bridge_snapshot *, snapshot,
67                         ast_bridge_snapshot_get_latest(bridge_id), ao2_cleanup);
68                 if (!snapshot) {
69                         ast_ari_response_error(response, 404, "Not found",
70                                 "Bridge not found");
71                         return NULL;
72                 }
73
74                 ast_ari_response_error(response, 409, "Conflict",
75                         "Bridge not in Stasis application");
76                 return NULL;
77         }
78
79         ao2_ref(bridge, +1);
80         return bridge;
81 }
82
83 /*!
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.
90  */
91 static struct stasis_app_control *find_channel_control(
92         struct ast_ari_response *response,
93         const char *channel_id)
94 {
95         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
96
97         ast_assert(response != NULL);
98
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");
103                 return NULL;
104         }
105
106         ao2_ref(control, +1);
107         return control;
108 }
109
110 struct control_list {
111         size_t count;
112         struct stasis_app_control *controls[];
113 };
114
115 static void control_list_dtor(void *obj) {
116         struct control_list *list = obj;
117         size_t i;
118
119         for (i = 0; i < list->count; ++i) {
120                 ao2_cleanup(list->controls[i]);
121                 list->controls[i] = NULL;
122         }
123 }
124
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);
127         size_t i;
128
129         if (count == 0 || !channels) {
130                 ast_ari_response_error(response, 400, "Bad Request", "Missing parameter channel");
131                 return NULL;
132         }
133
134         list = ao2_alloc(sizeof(*list) + count * sizeof(list->controls[0]), control_list_dtor);
135         if (!list) {
136                 ast_ari_response_alloc_failed(response);
137                 return NULL;
138         }
139
140         for (i = 0; i < count; ++i) {
141                 if (ast_strlen_zero(channels[i])) {
142                         continue;
143                 }
144                 list->controls[list->count] =
145                         find_channel_control(response, channels[i]);
146                 if (!list->controls[list->count]) {
147                         return NULL;
148                 }
149                 ++list->count;
150         }
151
152         if (list->count == 0) {
153                 ast_ari_response_error(response, 400, "Bad Request", "Missing parameter channel");
154                 return NULL;
155         }
156
157         ao2_ref(list, +1);
158         return list;
159 }
160
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)
162 {
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);
165         size_t i;
166
167         if (!bridge) {
168                 /* Response filled in by find_bridge */
169                 return;
170         }
171
172         list = control_list_create(response, args->channel_count, args->channel);
173         if (!list) {
174                 /* Response filled in by control_list_create() */
175                 return;
176         }
177
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);
183                                 return;
184                         }
185                 }
186         }
187
188         for (i = 0; i < list->count; ++i) {
189                 stasis_app_control_add_channel_to_bridge(list->controls[i], bridge);
190         }
191
192         ast_ari_response_no_content(response);
193 }
194
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)
196 {
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);
199         size_t i;
200
201         if (!bridge) {
202                 /* Response filled in by find_bridge */
203                 return;
204         }
205
206         list = control_list_create(response, args->channel_count, args->channel);
207         if (!list) {
208                 /* Response filled in by control_list_create() */
209                 return;
210         }
211
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");
220                 }
221         }
222
223         if (response->response_code) {
224                 return;
225         }
226
227         ast_ari_response_no_content(response);
228 }
229
230 struct bridge_channel_control_thread_data {
231         struct ast_channel *bridge_channel;
232         struct stasis_app_control *control;
233 };
234
235 static void *bridge_channel_control_thread(void *data)
236 {
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;
240
241         RAII_VAR(struct ast_callid *, callid, ast_channel_callid(bridge_channel), ast_callid_cleanup);
242
243         if (callid) {
244                 ast_callid_threadassoc_add(callid);
245         }
246
247         ast_free(thread_data);
248         thread_data = NULL;
249
250         stasis_app_control_execute_until_exhausted(bridge_channel, control);
251
252         ast_hangup(bridge_channel);
253         ao2_cleanup(control);
254         return NULL;
255 }
256
257 static struct ast_channel *prepare_bridge_media_channel(const char *type)
258 {
259         RAII_VAR(struct ast_format_cap *, cap, NULL, ast_format_cap_destroy);
260         struct ast_format format;
261
262         cap = ast_format_cap_alloc_nolock();
263         if (!cap) {
264                 return NULL;
265         }
266
267         ast_format_cap_add(cap, ast_format_set(&format, AST_FORMAT_SLINEAR, 0));
268
269         if (!cap) {
270                 return NULL;
271         }
272
273         return ast_request(type, cap, NULL, "ARI", NULL);
274 }
275
276 void ast_ari_play_on_bridge(struct ast_variable *headers, struct ast_play_on_bridge_args *args, struct ast_ari_response *response)
277 {
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);
285
286         struct bridge_channel_control_thread_data *thread_data;
287         const char *language;
288         pthread_t threadid;
289
290         ast_assert(response != NULL);
291
292         if (!bridge) {
293                 return;
294         }
295
296         if (!(play_channel = prepare_bridge_media_channel("Announcer"))) {
297                 ast_ari_response_error(
298                         response, 500, "Internal Error", "Could not create playback channel");
299                 return;
300         }
301         ast_debug(1, "Created announcer channel '%s'\n", ast_channel_name(play_channel));
302
303         if (ast_unreal_channel_push_to_bridge(play_channel, bridge)) {
304                 ast_ari_response_error(
305                         response, 500, "Internal Error", "Failed to put playback channel into the bridge");
306                 return;
307         }
308
309         control = stasis_app_control_create(play_channel);
310         if (control == NULL) {
311                 ast_ari_response_alloc_failed(response);
312                 return;
313         }
314
315         snapshot = stasis_app_control_get_snapshot(control);
316         if (!snapshot) {
317                 ast_ari_response_error(
318                         response, 500, "Internal Error", "Failed to get control snapshot");
319                 return;
320         }
321
322         language = S_OR(args->lang, snapshot->language);
323
324         playback = stasis_app_control_play_uri(control, args->media, language,
325                 args->bridge_id, STASIS_PLAYBACK_TARGET_BRIDGE, args->skipms,
326                 args->offsetms);
327
328         if (!playback) {
329                 ast_ari_response_alloc_failed(response);
330                 return;
331         }
332
333         ast_asprintf(&playback_url, "/playback/%s",
334                 stasis_app_playback_get_id(playback));
335
336         if (!playback_url) {
337                 ast_ari_response_alloc_failed(response);
338                 return;
339         }
340
341         json = stasis_app_playback_to_json(playback);
342         if (!json) {
343                 ast_ari_response_alloc_failed(response);
344                 return;
345         }
346
347         /* Give play_channel and control reference to the thread data */
348         thread_data = ast_calloc(1, sizeof(*thread_data));
349         if (!thread_data) {
350                 ast_ari_response_alloc_failed(response);
351                 return;
352         }
353
354         thread_data->bridge_channel = play_channel;
355         thread_data->control = control;
356
357         if (ast_pthread_create_detached(&threadid, NULL, bridge_channel_control_thread, thread_data)) {
358                 ast_ari_response_alloc_failed(response);
359                 ast_free(thread_data);
360                 return;
361         }
362
363         /* These are owned by the other thread now, so we don't want RAII_VAR disposing of them. */
364         play_channel = NULL;
365         control = NULL;
366
367         ast_ari_response_created(response, playback_url, json);
368 }
369
370 void ast_ari_record_bridge(struct ast_variable *headers, struct ast_record_bridge_args *args, struct ast_ari_response *response)
371 {
372         RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
373         RAII_VAR(struct ast_channel *, record_channel, NULL, ast_hangup);
374         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
375         RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup);
376         RAII_VAR(char *, recording_url, NULL, ast_free);
377         RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
378         RAII_VAR(struct stasis_app_recording_options *, options, NULL, ao2_cleanup);
379         RAII_VAR(char *, uri_encoded_name, NULL, ast_free);
380
381         size_t uri_name_maxlen;
382         struct bridge_channel_control_thread_data *thread_data;
383         pthread_t threadid;
384
385         ast_assert(response != NULL);
386
387         if (bridge == NULL) {
388                 return;
389         }
390
391         if (!(record_channel = prepare_bridge_media_channel("Recorder"))) {
392                 ast_ari_response_error(
393                         response, 500, "Internal Server Error", "Failed to create recording channel");
394                 return;
395         }
396
397         if (ast_unreal_channel_push_to_bridge(record_channel, bridge)) {
398                 ast_ari_response_error(
399                         response, 500, "Internal Error", "Failed to put recording channel into the bridge");
400                 return;
401         }
402
403         control = stasis_app_control_create(record_channel);
404         if (control == NULL) {
405                 ast_ari_response_alloc_failed(response);
406                 return;
407         }
408
409         options = stasis_app_recording_options_create(args->name, args->format);
410         if (options == NULL) {
411                 ast_ari_response_alloc_failed(response);
412                 return;
413         }
414
415         options->max_silence_seconds = args->max_silence_seconds;
416         options->max_duration_seconds = args->max_duration_seconds;
417         options->terminate_on =
418                 stasis_app_recording_termination_parse(args->terminate_on);
419         options->if_exists =
420                 stasis_app_recording_if_exists_parse(args->if_exists);
421         options->beep = args->beep;
422
423         recording = stasis_app_control_record(control, options);
424         if (recording == NULL) {
425                 switch(errno) {
426                 case EINVAL:
427                         /* While the arguments are invalid, we should have
428                          * caught them prior to calling record.
429                          */
430                         ast_ari_response_error(
431                                 response, 500, "Internal Server Error",
432                                 "Error parsing request");
433                         break;
434                 case EEXIST:
435                         ast_ari_response_error(response, 409, "Conflict",
436                                 "Recording '%s' already in progress",
437                                 args->name);
438                         break;
439                 case ENOMEM:
440                         ast_ari_response_alloc_failed(response);
441                         break;
442                 case EPERM:
443                         ast_ari_response_error(
444                                 response, 400, "Bad Request",
445                                 "Recording name invalid");
446                         break;
447                 default:
448                         ast_log(LOG_WARNING,
449                                 "Unrecognized recording error: %s\n",
450                                 strerror(errno));
451                         ast_ari_response_error(
452                                 response, 500, "Internal Server Error",
453                                 "Internal Server Error");
454                         break;
455                 }
456                 return;
457         }
458
459         uri_name_maxlen = strlen(args->name) * 3;
460         uri_encoded_name = ast_malloc(uri_name_maxlen);
461         if (!uri_encoded_name) {
462                 ast_ari_response_alloc_failed(response);
463                 return;
464         }
465         ast_uri_encode(args->name, uri_encoded_name, uri_name_maxlen, ast_uri_http);
466
467         ast_asprintf(&recording_url, "/recordings/live/%s", uri_encoded_name);
468         if (!recording_url) {
469                 ast_ari_response_alloc_failed(response);
470                 return;
471         }
472
473         json = stasis_app_recording_to_json(recording);
474         if (!json) {
475                 ast_ari_response_alloc_failed(response);
476                 return;
477         }
478
479         thread_data = ast_calloc(1, sizeof(*thread_data));
480         if (!thread_data) {
481                 ast_ari_response_alloc_failed(response);
482                 return;
483         }
484
485         thread_data->bridge_channel = record_channel;
486         thread_data->control = control;
487
488         if (ast_pthread_create_detached(&threadid, NULL, bridge_channel_control_thread, thread_data)) {
489                 ast_ari_response_alloc_failed(response);
490                 ast_free(thread_data);
491                 return;
492         }
493
494         /* These are owned by the other thread now, so we don't want RAII_VAR disposing of them. */
495         record_channel = NULL;
496         control = NULL;
497
498         ast_ari_response_created(response, recording_url, json);
499 }
500
501 void ast_ari_get_bridge(struct ast_variable *headers, struct ast_get_bridge_args *args, struct ast_ari_response *response)
502 {
503         RAII_VAR(struct ast_bridge_snapshot *, snapshot, ast_bridge_snapshot_get_latest(args->bridge_id), ao2_cleanup);
504         if (!snapshot) {
505                 ast_ari_response_error(
506                         response, 404, "Not Found",
507                         "Bridge not found");
508                 return;
509         }
510
511         ast_ari_response_ok(response,
512                 ast_bridge_snapshot_to_json(snapshot));
513 }
514
515 void ast_ari_delete_bridge(struct ast_variable *headers, struct ast_delete_bridge_args *args, struct ast_ari_response *response)
516 {
517         RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
518         if (!bridge) {
519                 return;
520         }
521
522         stasis_app_bridge_destroy(args->bridge_id);
523         ast_ari_response_no_content(response);
524 }
525
526 void ast_ari_get_bridges(struct ast_variable *headers, struct ast_get_bridges_args *args, struct ast_ari_response *response)
527 {
528         RAII_VAR(struct stasis_cache *, cache, NULL, ao2_cleanup);
529         RAII_VAR(struct ao2_container *, snapshots, NULL, ao2_cleanup);
530         RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
531         struct ao2_iterator i;
532         void *obj;
533
534         cache = ast_bridge_cache();
535         if (!cache) {
536                 ast_ari_response_error(
537                         response, 500, "Internal Server Error",
538                         "Message bus not initialized");
539                 return;
540         }
541         ao2_ref(cache, +1);
542
543         snapshots = stasis_cache_dump(cache, ast_bridge_snapshot_type());
544         if (!snapshots) {
545                 ast_ari_response_alloc_failed(response);
546                 return;
547         }
548
549         json = ast_json_array_create();
550         if (!json) {
551                 ast_ari_response_alloc_failed(response);
552                 return;
553         }
554
555         i = ao2_iterator_init(snapshots, 0);
556         while ((obj = ao2_iterator_next(&i))) {
557                 RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup);
558                 struct ast_bridge_snapshot *snapshot = stasis_message_data(msg);
559                 if (ast_json_array_append(json, ast_bridge_snapshot_to_json(snapshot))) {
560                         ast_ari_response_alloc_failed(response);
561                         return;
562                 }
563         }
564         ao2_iterator_destroy(&i);
565
566         ast_ari_response_ok(response, ast_json_ref(json));
567 }
568
569 void ast_ari_new_bridge(struct ast_variable *headers, struct ast_new_bridge_args *args, struct ast_ari_response *response)
570 {
571         RAII_VAR(struct ast_bridge *, bridge, stasis_app_bridge_create(args->type), ao2_cleanup);
572         RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
573
574         if (!bridge) {
575                 ast_ari_response_error(
576                         response, 500, "Internal Error",
577                         "Unable to create bridge");
578                 return;
579         }
580
581         snapshot = ast_bridge_snapshot_create(bridge);
582         if (!snapshot) {
583                 ast_ari_response_error(
584                         response, 500, "Internal Error",
585                         "Unable to create snapshot for new bridge");
586                 return;
587         }
588
589         ast_ari_response_ok(response,
590                 ast_bridge_snapshot_to_json(snapshot));
591 }