bridge_channel: Support the lonely flag and make ARI use it.
[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_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");
307                 return;
308         }
309
310         control = stasis_app_control_create(play_channel);
311         if (control == NULL) {
312                 ast_ari_response_alloc_failed(response);
313                 return;
314         }
315
316         snapshot = stasis_app_control_get_snapshot(control);
317         if (!snapshot) {
318                 ast_ari_response_error(
319                         response, 500, "Internal Error", "Failed to get control snapshot");
320                 return;
321         }
322
323         language = S_OR(args->lang, snapshot->language);
324
325         playback = stasis_app_control_play_uri(control, args->media, language,
326                 args->bridge_id, STASIS_PLAYBACK_TARGET_BRIDGE, args->skipms,
327                 args->offsetms);
328
329         if (!playback) {
330                 ast_ari_response_alloc_failed(response);
331                 return;
332         }
333
334         ast_asprintf(&playback_url, "/playback/%s",
335                 stasis_app_playback_get_id(playback));
336
337         if (!playback_url) {
338                 ast_ari_response_alloc_failed(response);
339                 return;
340         }
341
342         json = stasis_app_playback_to_json(playback);
343         if (!json) {
344                 ast_ari_response_alloc_failed(response);
345                 return;
346         }
347
348         /* Give play_channel and control reference to the thread data */
349         thread_data = ast_calloc(1, sizeof(*thread_data));
350         if (!thread_data) {
351                 ast_ari_response_alloc_failed(response);
352                 return;
353         }
354
355         thread_data->bridge_channel = play_channel;
356         thread_data->control = control;
357
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);
361                 return;
362         }
363
364         /* These are owned by the other thread now, so we don't want RAII_VAR disposing of them. */
365         play_channel = NULL;
366         control = NULL;
367
368         ast_ari_response_created(response, playback_url, json);
369 }
370
371 void ast_ari_record_bridge(struct ast_variable *headers, struct ast_record_bridge_args *args, struct ast_ari_response *response)
372 {
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);
381
382         size_t uri_name_maxlen;
383         struct bridge_channel_control_thread_data *thread_data;
384         pthread_t threadid;
385
386         ast_assert(response != NULL);
387
388         if (bridge == NULL) {
389                 return;
390         }
391
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");
395                 return;
396         }
397
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");
402                 return;
403         }
404
405         control = stasis_app_control_create(record_channel);
406         if (control == NULL) {
407                 ast_ari_response_alloc_failed(response);
408                 return;
409         }
410
411         options = stasis_app_recording_options_create(args->name, args->format);
412         if (options == NULL) {
413                 ast_ari_response_alloc_failed(response);
414                 return;
415         }
416
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);
421         options->if_exists =
422                 stasis_app_recording_if_exists_parse(args->if_exists);
423         options->beep = args->beep;
424
425         recording = stasis_app_control_record(control, options);
426         if (recording == NULL) {
427                 switch(errno) {
428                 case EINVAL:
429                         /* While the arguments are invalid, we should have
430                          * caught them prior to calling record.
431                          */
432                         ast_ari_response_error(
433                                 response, 500, "Internal Server Error",
434                                 "Error parsing request");
435                         break;
436                 case EEXIST:
437                         ast_ari_response_error(response, 409, "Conflict",
438                                 "Recording '%s' already in progress",
439                                 args->name);
440                         break;
441                 case ENOMEM:
442                         ast_ari_response_alloc_failed(response);
443                         break;
444                 case EPERM:
445                         ast_ari_response_error(
446                                 response, 400, "Bad Request",
447                                 "Recording name invalid");
448                         break;
449                 default:
450                         ast_log(LOG_WARNING,
451                                 "Unrecognized recording error: %s\n",
452                                 strerror(errno));
453                         ast_ari_response_error(
454                                 response, 500, "Internal Server Error",
455                                 "Internal Server Error");
456                         break;
457                 }
458                 return;
459         }
460
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);
465                 return;
466         }
467         ast_uri_encode(args->name, uri_encoded_name, uri_name_maxlen, ast_uri_http);
468
469         ast_asprintf(&recording_url, "/recordings/live/%s", uri_encoded_name);
470         if (!recording_url) {
471                 ast_ari_response_alloc_failed(response);
472                 return;
473         }
474
475         json = stasis_app_recording_to_json(recording);
476         if (!json) {
477                 ast_ari_response_alloc_failed(response);
478                 return;
479         }
480
481         thread_data = ast_calloc(1, sizeof(*thread_data));
482         if (!thread_data) {
483                 ast_ari_response_alloc_failed(response);
484                 return;
485         }
486
487         thread_data->bridge_channel = record_channel;
488         thread_data->control = control;
489
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);
493                 return;
494         }
495
496         /* These are owned by the other thread now, so we don't want RAII_VAR disposing of them. */
497         record_channel = NULL;
498         control = NULL;
499
500         ast_ari_response_created(response, recording_url, json);
501 }
502
503 void ast_ari_get_bridge(struct ast_variable *headers, struct ast_get_bridge_args *args, struct ast_ari_response *response)
504 {
505         RAII_VAR(struct ast_bridge_snapshot *, snapshot, ast_bridge_snapshot_get_latest(args->bridge_id), ao2_cleanup);
506         if (!snapshot) {
507                 ast_ari_response_error(
508                         response, 404, "Not Found",
509                         "Bridge not found");
510                 return;
511         }
512
513         ast_ari_response_ok(response,
514                 ast_bridge_snapshot_to_json(snapshot));
515 }
516
517 void ast_ari_delete_bridge(struct ast_variable *headers, struct ast_delete_bridge_args *args, struct ast_ari_response *response)
518 {
519         RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
520         if (!bridge) {
521                 return;
522         }
523
524         stasis_app_bridge_destroy(args->bridge_id);
525         ast_ari_response_no_content(response);
526 }
527
528 void ast_ari_get_bridges(struct ast_variable *headers, struct ast_get_bridges_args *args, struct ast_ari_response *response)
529 {
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;
534         void *obj;
535
536         cache = ast_bridge_cache();
537         if (!cache) {
538                 ast_ari_response_error(
539                         response, 500, "Internal Server Error",
540                         "Message bus not initialized");
541                 return;
542         }
543         ao2_ref(cache, +1);
544
545         snapshots = stasis_cache_dump(cache, ast_bridge_snapshot_type());
546         if (!snapshots) {
547                 ast_ari_response_alloc_failed(response);
548                 return;
549         }
550
551         json = ast_json_array_create();
552         if (!json) {
553                 ast_ari_response_alloc_failed(response);
554                 return;
555         }
556
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);
563                         return;
564                 }
565         }
566         ao2_iterator_destroy(&i);
567
568         ast_ari_response_ok(response, ast_json_ref(json));
569 }
570
571 void ast_ari_new_bridge(struct ast_variable *headers, struct ast_new_bridge_args *args, struct ast_ari_response *response)
572 {
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);
575
576         if (!bridge) {
577                 ast_ari_response_error(
578                         response, 500, "Internal Error",
579                         "Unable to create bridge");
580                 return;
581         }
582
583         snapshot = ast_bridge_snapshot_create(bridge);
584         if (!snapshot) {
585                 ast_ari_response_error(
586                         response, 500, "Internal Error",
587                         "Unable to create snapshot for new bridge");
588                 return;
589         }
590
591         ast_ari_response_ok(response,
592                 ast_bridge_snapshot_to_json(snapshot));
593 }