ARI recordings: Issue HTTP failures for recording requests with file conflicts
[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 #include "asterisk/musiconhold.h"
47
48 /*!
49  * \brief Finds a bridge, filling the response with an error, if appropriate.
50  *
51  * \param[out] response Response to fill with an error if control is not found.
52  * \param bridge_id ID of the bridge to lookup.
53  *
54  * \return Bridget.
55  * \return \c NULL if bridge does not exist.
56  */
57 static struct ast_bridge *find_bridge(
58         struct ast_ari_response *response,
59         const char *bridge_id)
60 {
61         RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
62
63         ast_assert(response != NULL);
64
65         bridge = stasis_app_bridge_find_by_id(bridge_id);
66         if (bridge == NULL) {
67                 RAII_VAR(struct ast_bridge_snapshot *, snapshot,
68                         ast_bridge_snapshot_get_latest(bridge_id), ao2_cleanup);
69                 if (!snapshot) {
70                         ast_ari_response_error(response, 404, "Not found",
71                                 "Bridge not found");
72                         return NULL;
73                 }
74
75                 ast_ari_response_error(response, 409, "Conflict",
76                         "Bridge not in Stasis application");
77                 return NULL;
78         }
79
80         ao2_ref(bridge, +1);
81         return bridge;
82 }
83
84 /*!
85  * \brief Finds the control object for a channel, filling the response with an
86  * error, if appropriate.
87  * \param[out] response Response to fill with an error if control is not found.
88  * \param channel_id ID of the channel to lookup.
89  * \return Channel control object.
90  * \return \c NULL if control object does not exist.
91  */
92 static struct stasis_app_control *find_channel_control(
93         struct ast_ari_response *response,
94         const char *channel_id)
95 {
96         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
97
98         ast_assert(response != NULL);
99
100         control = stasis_app_control_find_by_channel_id(channel_id);
101         if (control == NULL) {
102                 /* Distinguish between 400 and 422 errors */
103                 RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL,
104                         ao2_cleanup);
105                 snapshot = ast_channel_snapshot_get_latest(channel_id);
106                 if (snapshot == NULL) {
107                         ast_log(LOG_DEBUG, "Couldn't find '%s'\n", channel_id);
108                         ast_ari_response_error(response, 400, "Bad Request",
109                                 "Channel not found");
110                         return NULL;
111                 }
112
113                 ast_log(LOG_DEBUG, "Found non-stasis '%s'\n", channel_id);
114                 ast_ari_response_error(response, 422, "Unprocessable Entity",
115                         "Channel not in Stasis application");
116                 return NULL;
117         }
118
119         ao2_ref(control, +1);
120         return control;
121 }
122
123 struct control_list {
124         size_t count;
125         struct stasis_app_control *controls[];
126 };
127
128 static void control_list_dtor(void *obj) {
129         struct control_list *list = obj;
130         size_t i;
131
132         for (i = 0; i < list->count; ++i) {
133                 ao2_cleanup(list->controls[i]);
134                 list->controls[i] = NULL;
135         }
136 }
137
138 static struct control_list *control_list_create(struct ast_ari_response *response, size_t count, const char **channels) {
139         RAII_VAR(struct control_list *, list, NULL, ao2_cleanup);
140         size_t i;
141
142         if (count == 0 || !channels) {
143                 ast_ari_response_error(response, 400, "Bad Request", "Missing parameter channel");
144                 return NULL;
145         }
146
147         list = ao2_alloc(sizeof(*list) + count * sizeof(list->controls[0]), control_list_dtor);
148         if (!list) {
149                 ast_ari_response_alloc_failed(response);
150                 return NULL;
151         }
152
153         for (i = 0; i < count; ++i) {
154                 if (ast_strlen_zero(channels[i])) {
155                         continue;
156                 }
157                 list->controls[list->count] =
158                         find_channel_control(response, channels[i]);
159                 if (!list->controls[list->count]) {
160                         /* response filled in by find_channel_control() */
161                         return NULL;
162                 }
163                 ++list->count;
164         }
165
166         if (list->count == 0) {
167                 ast_ari_response_error(response, 400, "Bad Request", "Missing parameter channel");
168                 return NULL;
169         }
170
171         ao2_ref(list, +1);
172         return list;
173 }
174
175 void ast_ari_add_channel_to_bridge(struct ast_variable *headers, struct ast_add_channel_to_bridge_args *args, struct ast_ari_response *response)
176 {
177         RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
178         RAII_VAR(struct control_list *, list, NULL, ao2_cleanup);
179         size_t i;
180
181         if (!bridge) {
182                 /* Response filled in by find_bridge() */
183                 return;
184         }
185
186         list = control_list_create(response, args->channel_count, args->channel);
187         if (!list) {
188                 /* Response filled in by control_list_create() */
189                 return;
190         }
191
192         for (i = 0; i < list->count; ++i) {
193                 stasis_app_control_clear_roles(list->controls[i]);
194                 if (!ast_strlen_zero(args->role)) {
195                         if (stasis_app_control_add_role(list->controls[i], args->role)) {
196                                 ast_ari_response_alloc_failed(response);
197                                 return;
198                         }
199                 }
200         }
201
202         for (i = 0; i < list->count; ++i) {
203                 stasis_app_control_add_channel_to_bridge(list->controls[i], bridge);
204         }
205
206         ast_ari_response_no_content(response);
207 }
208
209 void ast_ari_remove_channel_from_bridge(struct ast_variable *headers, struct ast_remove_channel_from_bridge_args *args, struct ast_ari_response *response)
210 {
211         RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
212         RAII_VAR(struct control_list *, list, NULL, ao2_cleanup);
213         size_t i;
214
215         if (!bridge) {
216                 /* Response filled in by find_bridge() */
217                 return;
218         }
219
220         list = control_list_create(response, args->channel_count, args->channel);
221         if (!list) {
222                 /* Response filled in by control_list_create() */
223                 return;
224         }
225
226         /* Make sure all of the channels are in this bridge */
227         for (i = 0; i < list->count; ++i) {
228                 if (stasis_app_get_bridge(list->controls[i]) != bridge) {
229                         ast_log(LOG_WARNING, "Channel %s not in bridge %s\n",
230                                 args->channel[i], args->bridge_id);
231                         ast_ari_response_error(response, 422,
232                                 "Unprocessable Entity",
233                                 "Channel not in this bridge");
234                         return;
235                 }
236         }
237
238         /* Now actually remove it */
239         for (i = 0; i < list->count; ++i) {
240                 stasis_app_control_remove_channel_from_bridge(list->controls[i],
241                         bridge);
242         }
243
244         ast_ari_response_no_content(response);
245 }
246
247 struct bridge_channel_control_thread_data {
248         struct ast_channel *bridge_channel;
249         struct stasis_app_control *control;
250 };
251
252 static void *bridge_channel_control_thread(void *data)
253 {
254         struct bridge_channel_control_thread_data *thread_data = data;
255         struct ast_channel *bridge_channel = thread_data->bridge_channel;
256         struct stasis_app_control *control = thread_data->control;
257
258         RAII_VAR(struct ast_callid *, callid, ast_channel_callid(bridge_channel), ast_callid_cleanup);
259
260         if (callid) {
261                 ast_callid_threadassoc_add(callid);
262         }
263
264         ast_free(thread_data);
265         thread_data = NULL;
266
267         stasis_app_control_execute_until_exhausted(bridge_channel, control);
268
269         ast_hangup(bridge_channel);
270         ao2_cleanup(control);
271         return NULL;
272 }
273
274 static struct ast_channel *prepare_bridge_media_channel(const char *type)
275 {
276         RAII_VAR(struct ast_format_cap *, cap, NULL, ast_format_cap_destroy);
277         struct ast_format format;
278
279         cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK);
280         if (!cap) {
281                 return NULL;
282         }
283
284         ast_format_cap_add(cap, ast_format_set(&format, AST_FORMAT_SLINEAR, 0));
285
286         if (!cap) {
287                 return NULL;
288         }
289
290         return ast_request(type, cap, NULL, "ARI", NULL);
291 }
292
293 void ast_ari_play_on_bridge(struct ast_variable *headers, struct ast_play_on_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 *, play_channel, NULL, ast_hangup);
297         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
298         RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
299         RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
300         RAII_VAR(char *, playback_url, NULL, ast_free);
301         RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
302
303         struct bridge_channel_control_thread_data *thread_data;
304         const char *language;
305         pthread_t threadid;
306
307         ast_assert(response != NULL);
308
309         if (!bridge) {
310                 return;
311         }
312
313         if (!(play_channel = prepare_bridge_media_channel("Announcer"))) {
314                 ast_ari_response_error(
315                         response, 500, "Internal Error", "Could not create playback channel");
316                 return;
317         }
318         ast_debug(1, "Created announcer channel '%s'\n", ast_channel_name(play_channel));
319
320         if (ast_unreal_channel_push_to_bridge(play_channel, bridge,
321                 AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE | AST_BRIDGE_CHANNEL_FLAG_LONELY)) {
322                 ast_ari_response_error(
323                         response, 500, "Internal Error", "Failed to put playback channel into the bridge");
324                 return;
325         }
326
327         control = stasis_app_control_create(play_channel);
328         if (control == NULL) {
329                 ast_ari_response_alloc_failed(response);
330                 return;
331         }
332
333         snapshot = stasis_app_control_get_snapshot(control);
334         if (!snapshot) {
335                 ast_ari_response_error(
336                         response, 500, "Internal Error", "Failed to get control snapshot");
337                 return;
338         }
339
340         language = S_OR(args->lang, snapshot->language);
341
342         playback = stasis_app_control_play_uri(control, args->media, language,
343                 args->bridge_id, STASIS_PLAYBACK_TARGET_BRIDGE, args->skipms,
344                 args->offsetms);
345
346         if (!playback) {
347                 ast_ari_response_alloc_failed(response);
348                 return;
349         }
350
351         ast_asprintf(&playback_url, "/playback/%s",
352                 stasis_app_playback_get_id(playback));
353
354         if (!playback_url) {
355                 ast_ari_response_alloc_failed(response);
356                 return;
357         }
358
359         json = stasis_app_playback_to_json(playback);
360         if (!json) {
361                 ast_ari_response_alloc_failed(response);
362                 return;
363         }
364
365         /* Give play_channel and control reference to the thread data */
366         thread_data = ast_calloc(1, sizeof(*thread_data));
367         if (!thread_data) {
368                 ast_ari_response_alloc_failed(response);
369                 return;
370         }
371
372         thread_data->bridge_channel = play_channel;
373         thread_data->control = control;
374
375         if (ast_pthread_create_detached(&threadid, NULL, bridge_channel_control_thread, thread_data)) {
376                 ast_ari_response_alloc_failed(response);
377                 ast_free(thread_data);
378                 return;
379         }
380
381         /* These are owned by the other thread now, so we don't want RAII_VAR disposing of them. */
382         play_channel = NULL;
383         control = NULL;
384
385         ast_ari_response_created(response, playback_url, json);
386 }
387
388 void ast_ari_record_bridge(struct ast_variable *headers, struct ast_record_bridge_args *args, struct ast_ari_response *response)
389 {
390         RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
391         RAII_VAR(struct ast_channel *, record_channel, NULL, ast_hangup);
392         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
393         RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup);
394         RAII_VAR(char *, recording_url, NULL, ast_free);
395         RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
396         RAII_VAR(struct stasis_app_recording_options *, options, NULL, ao2_cleanup);
397         RAII_VAR(char *, uri_encoded_name, NULL, ast_free);
398
399         size_t uri_name_maxlen;
400         struct bridge_channel_control_thread_data *thread_data;
401         pthread_t threadid;
402
403         ast_assert(response != NULL);
404
405         if (bridge == NULL) {
406                 return;
407         }
408
409         if (!(record_channel = prepare_bridge_media_channel("Recorder"))) {
410                 ast_ari_response_error(
411                         response, 500, "Internal Server Error", "Failed to create recording channel");
412                 return;
413         }
414
415         if (ast_unreal_channel_push_to_bridge(record_channel, bridge,
416                 AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE | AST_BRIDGE_CHANNEL_FLAG_LONELY)) {
417                 ast_ari_response_error(
418                         response, 500, "Internal Error", "Failed to put recording channel into the bridge");
419                 return;
420         }
421
422         control = stasis_app_control_create(record_channel);
423         if (control == NULL) {
424                 ast_ari_response_alloc_failed(response);
425                 return;
426         }
427
428         options = stasis_app_recording_options_create(args->name, args->format);
429         if (options == NULL) {
430                 ast_ari_response_alloc_failed(response);
431                 return;
432         }
433
434         options->max_silence_seconds = args->max_silence_seconds;
435         options->max_duration_seconds = args->max_duration_seconds;
436         options->terminate_on =
437                 stasis_app_recording_termination_parse(args->terminate_on);
438         options->if_exists =
439                 stasis_app_recording_if_exists_parse(args->if_exists);
440         options->beep = args->beep;
441
442         recording = stasis_app_control_record(control, options);
443         if (recording == NULL) {
444                 switch(errno) {
445                 case EINVAL:
446                         /* While the arguments are invalid, we should have
447                          * caught them prior to calling record.
448                          */
449                         ast_ari_response_error(
450                                 response, 500, "Internal Server Error",
451                                 "Error parsing request");
452                         break;
453                 case EEXIST:
454                         ast_ari_response_error(response, 409, "Conflict",
455                                 "Recording '%s' already exists and can not be overwritten",
456                                 args->name);
457                         break;
458                 case ENOMEM:
459                         ast_ari_response_alloc_failed(response);
460                         break;
461                 case EPERM:
462                         ast_ari_response_error(
463                                 response, 400, "Bad Request",
464                                 "Recording name invalid");
465                         break;
466                 default:
467                         ast_log(LOG_WARNING,
468                                 "Unrecognized recording error: %s\n",
469                                 strerror(errno));
470                         ast_ari_response_error(
471                                 response, 500, "Internal Server Error",
472                                 "Internal Server Error");
473                         break;
474                 }
475                 return;
476         }
477
478         uri_name_maxlen = strlen(args->name) * 3;
479         uri_encoded_name = ast_malloc(uri_name_maxlen);
480         if (!uri_encoded_name) {
481                 ast_ari_response_alloc_failed(response);
482                 return;
483         }
484         ast_uri_encode(args->name, uri_encoded_name, uri_name_maxlen, ast_uri_http);
485
486         ast_asprintf(&recording_url, "/recordings/live/%s", uri_encoded_name);
487         if (!recording_url) {
488                 ast_ari_response_alloc_failed(response);
489                 return;
490         }
491
492         json = stasis_app_recording_to_json(recording);
493         if (!json) {
494                 ast_ari_response_alloc_failed(response);
495                 return;
496         }
497
498         thread_data = ast_calloc(1, sizeof(*thread_data));
499         if (!thread_data) {
500                 ast_ari_response_alloc_failed(response);
501                 return;
502         }
503
504         thread_data->bridge_channel = record_channel;
505         thread_data->control = control;
506
507         if (ast_pthread_create_detached(&threadid, NULL, bridge_channel_control_thread, thread_data)) {
508                 ast_ari_response_alloc_failed(response);
509                 ast_free(thread_data);
510                 return;
511         }
512
513         /* These are owned by the other thread now, so we don't want RAII_VAR disposing of them. */
514         record_channel = NULL;
515         control = NULL;
516
517         ast_ari_response_created(response, recording_url, json);
518 }
519
520 void ast_ari_moh_start_bridge(struct ast_variable *headers, struct ast_moh_start_bridge_args *args, struct ast_ari_response *response)
521 {
522         RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
523         struct ast_channel *moh_channel;
524         const char *moh_class = args->moh_class;
525
526         if (!bridge) {
527                 /* The response is provided by find_bridge() */
528                 return;
529         }
530
531         moh_channel = stasis_app_bridge_moh_channel(bridge);
532         if (!moh_channel) {
533                 ast_ari_response_alloc_failed(response);
534                 return;
535         }
536
537         ast_moh_start(moh_channel, moh_class, NULL);
538
539         ast_ari_response_no_content(response);
540
541 }
542
543 void ast_ari_moh_stop_bridge(struct ast_variable *headers, struct ast_moh_stop_bridge_args *args, struct ast_ari_response *response)
544 {
545         RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
546
547         if (!bridge) {
548                 /* the response is provided by find_bridge() */
549                 return;
550         }
551
552         if (stasis_app_bridge_moh_stop(bridge)) {
553                 ast_ari_response_error(
554                         response, 409, "Conflict",
555                         "Bridge isn't playing music");
556                 return;
557         }
558
559         ast_ari_response_no_content(response);
560 }
561
562 void ast_ari_get_bridge(struct ast_variable *headers, struct ast_get_bridge_args *args, struct ast_ari_response *response)
563 {
564         RAII_VAR(struct ast_bridge_snapshot *, snapshot, ast_bridge_snapshot_get_latest(args->bridge_id), ao2_cleanup);
565         if (!snapshot) {
566                 ast_ari_response_error(
567                         response, 404, "Not Found",
568                         "Bridge not found");
569                 return;
570         }
571
572         ast_ari_response_ok(response,
573                 ast_bridge_snapshot_to_json(snapshot));
574 }
575
576 void ast_ari_delete_bridge(struct ast_variable *headers, struct ast_delete_bridge_args *args, struct ast_ari_response *response)
577 {
578         RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
579         if (!bridge) {
580                 return;
581         }
582
583         stasis_app_bridge_destroy(args->bridge_id);
584         ast_ari_response_no_content(response);
585 }
586
587 void ast_ari_get_bridges(struct ast_variable *headers, struct ast_get_bridges_args *args, struct ast_ari_response *response)
588 {
589         RAII_VAR(struct stasis_cache *, cache, NULL, ao2_cleanup);
590         RAII_VAR(struct ao2_container *, snapshots, NULL, ao2_cleanup);
591         RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
592         struct ao2_iterator i;
593         void *obj;
594
595         cache = ast_bridge_cache();
596         if (!cache) {
597                 ast_ari_response_error(
598                         response, 500, "Internal Server Error",
599                         "Message bus not initialized");
600                 return;
601         }
602         ao2_ref(cache, +1);
603
604         snapshots = stasis_cache_dump(cache, ast_bridge_snapshot_type());
605         if (!snapshots) {
606                 ast_ari_response_alloc_failed(response);
607                 return;
608         }
609
610         json = ast_json_array_create();
611         if (!json) {
612                 ast_ari_response_alloc_failed(response);
613                 return;
614         }
615
616         i = ao2_iterator_init(snapshots, 0);
617         while ((obj = ao2_iterator_next(&i))) {
618                 RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup);
619                 struct ast_bridge_snapshot *snapshot = stasis_message_data(msg);
620                 if (ast_json_array_append(json, ast_bridge_snapshot_to_json(snapshot))) {
621                         ast_ari_response_alloc_failed(response);
622                         return;
623                 }
624         }
625         ao2_iterator_destroy(&i);
626
627         ast_ari_response_ok(response, ast_json_ref(json));
628 }
629
630 void ast_ari_new_bridge(struct ast_variable *headers, struct ast_new_bridge_args *args, struct ast_ari_response *response)
631 {
632         RAII_VAR(struct ast_bridge *, bridge, stasis_app_bridge_create(args->type), ao2_cleanup);
633         RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
634
635         if (!bridge) {
636                 ast_ari_response_error(
637                         response, 500, "Internal Error",
638                         "Unable to create bridge");
639                 return;
640         }
641
642         snapshot = ast_bridge_snapshot_create(bridge);
643         if (!snapshot) {
644                 ast_ari_response_error(
645                         response, 500, "Internal Error",
646                         "Unable to create snapshot for new bridge");
647                 return;
648         }
649
650         ast_ari_response_ok(response,
651                 ast_bridge_snapshot_to_json(snapshot));
652 }