7730d0cd9d1c8607ba465ad97b72b82ffe6ef96a
[asterisk/asterisk.git] / res / ari / resource_bridges.c
1 /* -*- C -*-
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 void ast_ari_add_channel_to_bridge(struct ast_variable *headers, struct ast_add_channel_to_bridge_args *args, struct ast_ari_response *response)
111 {
112         RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
113         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
114         if (!bridge) {
115                 return;
116         }
117
118         control = find_channel_control(response, args->channel);
119         if (!control) {
120                 return;
121         }
122
123         stasis_app_control_add_channel_to_bridge(control, bridge);
124         ast_ari_response_no_content(response);
125 }
126
127 void ast_ari_remove_channel_from_bridge(struct ast_variable *headers, struct ast_remove_channel_from_bridge_args *args, struct ast_ari_response *response)
128 {
129         RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
130         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
131         if (!bridge) {
132                 return;
133         }
134
135         control = find_channel_control(response, args->channel);
136         if (!control) {
137                 return;
138         }
139
140         /* BUGBUG this should make sure the bridge requested for removal is actually
141          * the bridge the channel is in. This will be possible once the bridge uniqueid
142          * is added to the channel snapshot. A 409 response should be issued if the bridge
143          * uniqueids don't match */
144         if (stasis_app_control_remove_channel_from_bridge(control, bridge)) {
145                 ast_ari_response_error(response, 500, "Internal Error",
146                         "Could not remove channel from bridge");
147                 return;
148         }
149
150         ast_ari_response_no_content(response);
151 }
152
153 struct bridge_channel_control_thread_data {
154         struct ast_channel *bridge_channel;
155         struct stasis_app_control *control;
156 };
157
158 static void *bridge_channel_control_thread(void *data)
159 {
160         struct bridge_channel_control_thread_data *thread_data = data;
161         struct ast_channel *bridge_channel = thread_data->bridge_channel;
162         struct stasis_app_control *control = thread_data->control;
163
164         RAII_VAR(struct ast_callid *, callid, ast_channel_callid(bridge_channel), ast_callid_cleanup);
165
166         if (callid) {
167                 ast_callid_threadassoc_add(callid);
168         }
169
170         ast_free(thread_data);
171         thread_data = NULL;
172
173         stasis_app_control_execute_until_exhausted(bridge_channel, control);
174
175         ast_hangup(bridge_channel);
176         ao2_cleanup(control);
177         return NULL;
178 }
179
180 static struct ast_channel *prepare_bridge_media_channel(const char *type)
181 {
182         RAII_VAR(struct ast_format_cap *, cap, NULL, ast_format_cap_destroy);
183         struct ast_format format;
184
185         cap = ast_format_cap_alloc_nolock();
186         if (!cap) {
187                 return NULL;
188         }
189
190         ast_format_cap_add(cap, ast_format_set(&format, AST_FORMAT_SLINEAR, 0));
191
192         if (!cap) {
193                 return NULL;
194         }
195
196         return ast_request(type, cap, NULL, "ARI", NULL);
197 }
198
199 void ast_ari_play_on_bridge(struct ast_variable *headers, struct ast_play_on_bridge_args *args, struct ast_ari_response *response)
200 {
201         RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
202         RAII_VAR(struct ast_channel *, play_channel, NULL, ast_hangup);
203         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
204         RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
205         RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
206         RAII_VAR(char *, playback_url, NULL, ast_free);
207         RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
208
209         struct bridge_channel_control_thread_data *thread_data;
210         const char *language;
211         pthread_t threadid;
212
213         ast_assert(response != NULL);
214
215         if (!bridge) {
216                 return;
217         }
218
219         if (!(play_channel = prepare_bridge_media_channel("Announcer"))) {
220                 ast_ari_response_error(
221                         response, 500, "Internal Error", "Could not create playback channel");
222                 return;
223         }
224         ast_debug(1, "Created announcer channel '%s'\n", ast_channel_name(play_channel));
225
226         if (ast_unreal_channel_push_to_bridge(play_channel, bridge)) {
227                 ast_ari_response_error(
228                         response, 500, "Internal Error", "Failed to put playback channel into the bridge");
229                 return;
230         }
231
232         control = stasis_app_control_create(play_channel);
233         if (control == NULL) {
234                 ast_ari_response_alloc_failed(response);
235                 return;
236         }
237
238         snapshot = stasis_app_control_get_snapshot(control);
239         if (!snapshot) {
240                 ast_ari_response_error(
241                         response, 500, "Internal Error", "Failed to get control snapshot");
242                 return;
243         }
244
245         language = S_OR(args->lang, snapshot->language);
246
247         playback = stasis_app_control_play_uri(control, args->media, language,
248                 args->bridge_id, STASIS_PLAYBACK_TARGET_BRIDGE, args->skipms,
249                 args->offsetms);
250
251         if (!playback) {
252                 ast_ari_response_alloc_failed(response);
253                 return;
254         }
255
256         ast_asprintf(&playback_url, "/playback/%s",
257                 stasis_app_playback_get_id(playback));
258
259         if (!playback_url) {
260                 ast_ari_response_alloc_failed(response);
261                 return;
262         }
263
264         json = stasis_app_playback_to_json(playback);
265         if (!json) {
266                 ast_ari_response_alloc_failed(response);
267                 return;
268         }
269
270         /* Give play_channel and control reference to the thread data */
271         thread_data = ast_calloc(1, sizeof(*thread_data));
272         if (!thread_data) {
273                 ast_ari_response_alloc_failed(response);
274                 return;
275         }
276
277         thread_data->bridge_channel = play_channel;
278         thread_data->control = control;
279
280         if (ast_pthread_create_detached(&threadid, NULL, bridge_channel_control_thread, thread_data)) {
281                 ast_ari_response_alloc_failed(response);
282                 ast_free(thread_data);
283                 return;
284         }
285
286         /* These are owned by the other thread now, so we don't want RAII_VAR disposing of them. */
287         play_channel = NULL;
288         control = NULL;
289
290         ast_ari_response_created(response, playback_url, json);
291 }
292
293 void ast_ari_record_bridge(struct ast_variable *headers, struct ast_record_bridge_args *args, struct ast_ari_response *response)
294 {
295         RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
296         RAII_VAR(struct ast_channel *, record_channel, NULL, ast_hangup);
297         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
298         RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup);
299         RAII_VAR(char *, recording_url, NULL, ast_free);
300         RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
301         RAII_VAR(struct stasis_app_recording_options *, options, NULL, ao2_cleanup);
302         RAII_VAR(char *, uri_encoded_name, NULL, ast_free);
303
304         size_t uri_name_maxlen;
305         struct bridge_channel_control_thread_data *thread_data;
306         pthread_t threadid;
307
308         ast_assert(response != NULL);
309
310         if (bridge == NULL) {
311                 return;
312         }
313
314         if (!(record_channel = prepare_bridge_media_channel("Recorder"))) {
315                 ast_ari_response_error(
316                         response, 500, "Internal Server Error", "Failed to create recording channel");
317                 return;
318         }
319
320         if (ast_unreal_channel_push_to_bridge(record_channel, bridge)) {
321                 ast_ari_response_error(
322                         response, 500, "Internal Error", "Failed to put recording channel into the bridge");
323                 return;
324         }
325
326         control = stasis_app_control_create(record_channel);
327         if (control == NULL) {
328                 ast_ari_response_alloc_failed(response);
329                 return;
330         }
331
332         options = stasis_app_recording_options_create(args->name, args->format);
333         if (options == NULL) {
334                 ast_ari_response_alloc_failed(response);
335                 return;
336         }
337
338         options->max_silence_seconds = args->max_silence_seconds;
339         options->max_duration_seconds = args->max_duration_seconds;
340         options->terminate_on =
341                 stasis_app_recording_termination_parse(args->terminate_on);
342         options->if_exists =
343                 stasis_app_recording_if_exists_parse(args->if_exists);
344         options->beep = args->beep;
345
346         recording = stasis_app_control_record(control, options);
347         if (recording == NULL) {
348                 switch(errno) {
349                 case EINVAL:
350                         /* While the arguments are invalid, we should have
351                          * caught them prior to calling record.
352                          */
353                         ast_ari_response_error(
354                                 response, 500, "Internal Server Error",
355                                 "Error parsing request");
356                         break;
357                 case EEXIST:
358                         ast_ari_response_error(response, 409, "Conflict",
359                                 "Recording '%s' already in progress",
360                                 args->name);
361                         break;
362                 case ENOMEM:
363                         ast_ari_response_alloc_failed(response);
364                         break;
365                 case EPERM:
366                         ast_ari_response_error(
367                                 response, 400, "Bad Request",
368                                 "Recording name invalid");
369                         break;
370                 default:
371                         ast_log(LOG_WARNING,
372                                 "Unrecognized recording error: %s\n",
373                                 strerror(errno));
374                         ast_ari_response_error(
375                                 response, 500, "Internal Server Error",
376                                 "Internal Server Error");
377                         break;
378                 }
379                 return;
380         }
381
382         uri_name_maxlen = strlen(args->name) * 3;
383         uri_encoded_name = ast_malloc(uri_name_maxlen);
384         if (!uri_encoded_name) {
385                 ast_ari_response_alloc_failed(response);
386                 return;
387         }
388         ast_uri_encode(args->name, uri_encoded_name, uri_name_maxlen, ast_uri_http);
389
390         ast_asprintf(&recording_url, "/recordings/live/%s", uri_encoded_name);
391         if (!recording_url) {
392                 ast_ari_response_alloc_failed(response);
393                 return;
394         }
395
396         json = stasis_app_recording_to_json(recording);
397         if (!json) {
398                 ast_ari_response_alloc_failed(response);
399                 return;
400         }
401
402         thread_data = ast_calloc(1, sizeof(*thread_data));
403         if (!thread_data) {
404                 ast_ari_response_alloc_failed(response);
405                 return;
406         }
407
408         thread_data->bridge_channel = record_channel;
409         thread_data->control = control;
410
411         if (ast_pthread_create_detached(&threadid, NULL, bridge_channel_control_thread, thread_data)) {
412                 ast_ari_response_alloc_failed(response);
413                 ast_free(thread_data);
414                 return;
415         }
416
417         /* These are owned by the other thread now, so we don't want RAII_VAR disposing of them. */
418         record_channel = NULL;
419         control = NULL;
420
421         ast_ari_response_created(response, recording_url, json);
422 }
423
424 void ast_ari_get_bridge(struct ast_variable *headers, struct ast_get_bridge_args *args, struct ast_ari_response *response)
425 {
426         RAII_VAR(struct ast_bridge_snapshot *, snapshot, ast_bridge_snapshot_get_latest(args->bridge_id), ao2_cleanup);
427         if (!snapshot) {
428                 ast_ari_response_error(
429                         response, 404, "Not Found",
430                         "Bridge not found");
431                 return;
432         }
433
434         ast_ari_response_ok(response,
435                 ast_bridge_snapshot_to_json(snapshot));
436 }
437
438 void ast_ari_delete_bridge(struct ast_variable *headers, struct ast_delete_bridge_args *args, struct ast_ari_response *response)
439 {
440         RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
441         if (!bridge) {
442                 return;
443         }
444
445         stasis_app_bridge_destroy(args->bridge_id);
446         ast_ari_response_no_content(response);
447 }
448
449 void ast_ari_get_bridges(struct ast_variable *headers, struct ast_get_bridges_args *args, struct ast_ari_response *response)
450 {
451         RAII_VAR(struct stasis_cache *, cache, NULL, ao2_cleanup);
452         RAII_VAR(struct ao2_container *, snapshots, NULL, ao2_cleanup);
453         RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
454         struct ao2_iterator i;
455         void *obj;
456
457         cache = ast_bridge_cache();
458         if (!cache) {
459                 ast_ari_response_error(
460                         response, 500, "Internal Server Error",
461                         "Message bus not initialized");
462                 return;
463         }
464         ao2_ref(cache, +1);
465
466         snapshots = stasis_cache_dump(cache, ast_bridge_snapshot_type());
467         if (!snapshots) {
468                 ast_ari_response_alloc_failed(response);
469                 return;
470         }
471
472         json = ast_json_array_create();
473         if (!json) {
474                 ast_ari_response_alloc_failed(response);
475                 return;
476         }
477
478         i = ao2_iterator_init(snapshots, 0);
479         while ((obj = ao2_iterator_next(&i))) {
480                 RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup);
481                 struct ast_bridge_snapshot *snapshot = stasis_message_data(msg);
482                 if (ast_json_array_append(json, ast_bridge_snapshot_to_json(snapshot))) {
483                         ast_ari_response_alloc_failed(response);
484                         return;
485                 }
486         }
487         ao2_iterator_destroy(&i);
488
489         ast_ari_response_ok(response, ast_json_ref(json));
490 }
491
492 void ast_ari_new_bridge(struct ast_variable *headers, struct ast_new_bridge_args *args, struct ast_ari_response *response)
493 {
494         RAII_VAR(struct ast_bridge *, bridge, stasis_app_bridge_create(args->type), ao2_cleanup);
495         RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
496
497         if (!bridge) {
498                 ast_ari_response_error(
499                         response, 500, "Internal Error",
500                         "Unable to create bridge");
501                 return;
502         }
503
504         snapshot = ast_bridge_snapshot_create(bridge);
505         if (!snapshot) {
506                 ast_ari_response_error(
507                         response, 500, "Internal Error",
508                         "Unable to create snapshot for new bridge");
509                 return;
510         }
511
512         ast_ari_response_ok(response,
513                 ast_bridge_snapshot_to_json(snapshot));
514 }