Asterisk - The Open Source Telephony Project GIT-master-a63eec2
Loading...
Searching...
No Matches
resource_bridges.c
Go to the documentation of this file.
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#include "resource_bridges.h"
33#include "asterisk/stasis.h"
35#include "asterisk/stasis_app.h"
41#include "asterisk/channel.h"
42#include "asterisk/bridge.h"
43#include "asterisk/format_cap.h"
44#include "asterisk/file.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 * \retval NULL if bridge does not exist.
56 */
57static 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,
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 * \retval NULL if control object does not exist.
91 */
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,
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
124 size_t count;
126};
127
128static 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
138static 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) {
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
175static int check_add_remove_channel(struct ast_ari_response *response,
176 struct stasis_app_control *control,
178{
179 switch (result) {
182 response, 409, "Conflict", "Channel %s currently recording",
184 return -1;
186 return 0;
187 }
188 return 0;
189}
190
193 struct ast_ari_response *response)
194{
195 RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
196 RAII_VAR(struct control_list *, list, NULL, ao2_cleanup);
197 size_t i;
198 int has_error = 0;
199
200 if (!bridge) {
201 /* Response filled in by find_bridge() */
202 return;
203 }
204
205 list = control_list_create(response, args->channel_count, args->channel);
206 if (!list) {
207 /* Response filled in by control_list_create() */
208 return;
209 }
210
211 for (i = 0; i < list->count; ++i) {
212 stasis_app_control_clear_roles(list->controls[i]);
213 if (!ast_strlen_zero(args->role)) {
214 if (stasis_app_control_add_role(list->controls[i], args->role)) {
216 return;
217 }
218 }
219
220 /* Apply bridge features to each of the channel controls */
221 if (!stasis_app_control_bridge_features_init(list->controls[i])) {
222 stasis_app_control_absorb_dtmf_in_bridge(list->controls[i], args->absorb_dtmf);
223 stasis_app_control_mute_in_bridge(list->controls[i], args->mute);
224 stasis_app_control_inhibit_colp_in_bridge(list->controls[i], args->inhibit_connected_line_updates);
225 }
226 }
227
228 for (i = 0; i < list->count; ++i) {
229 if ((has_error = check_add_remove_channel(response, list->controls[i],
231 list->controls[i], bridge)))) {
232 break;
233 }
234 }
235
236 if (!has_error) {
238 }
239}
240
243 struct ast_ari_response *response)
244{
245 RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
246 RAII_VAR(struct control_list *, list, NULL, ao2_cleanup);
247 size_t i;
248
249 if (!bridge) {
250 /* Response filled in by find_bridge() */
251 return;
252 }
253
254 list = control_list_create(response, args->channel_count, args->channel);
255 if (!list) {
256 /* Response filled in by control_list_create() */
257 return;
258 }
259
260 /* Make sure all of the channels are in this bridge */
261 for (i = 0; i < list->count; ++i) {
262 if (stasis_app_get_bridge(list->controls[i]) != bridge) {
263 ast_log(LOG_WARNING, "Channel %s not in bridge %s\n",
264 args->channel[i], args->bridge_id);
265 ast_ari_response_error(response, 422,
266 "Unprocessable Entity",
267 "Channel not in this bridge");
268 return;
269 }
270 }
271
272 /* Now actually remove it */
273 for (i = 0; i < list->count; ++i) {
275 bridge);
276 }
277
279}
280
287
288static void *bridge_channel_control_thread(void *data)
289{
290 struct bridge_channel_control_thread_data *thread_data = data;
291 struct ast_channel *bridge_channel = thread_data->bridge_channel;
292 struct stasis_app_control *control = thread_data->control;
293 struct stasis_forward *forward = thread_data->forward;
294 ast_callid callid = ast_channel_callid(bridge_channel);
295 char *bridge_id = ast_strdupa(thread_data->bridge_id);
296
297 if (callid) {
299 }
300
301 ast_free(thread_data);
302 thread_data = NULL;
303
304 stasis_app_control_execute_until_exhausted(bridge_channel, control);
306
308 stasis_forward_cancel(forward);
309 ao2_cleanup(control);
310 ast_hangup(bridge_channel);
311 return NULL;
312}
313
315 struct ast_format *channel_format)
316{
317 RAII_VAR(struct ast_format_cap *, cap, NULL, ao2_cleanup);
318 struct ast_channel *chan;
319
321 if (!cap) {
322 return NULL;
323 }
324
325 /* This bumps the format's refcount */
326 ast_format_cap_append(cap, channel_format, 0);
327
328 chan = ast_request(type, cap, NULL, NULL, "ARI", NULL);
329 if (!chan) {
330 return NULL;
331 }
332
335 return NULL;
336 }
337 return chan;
338}
339
340/*!
341 * \brief Performs common setup for a bridge playback operation
342 * with both new controls and when existing controls are found.
343 *
344 * \param args_media medias to play
345 * \param args_media_count number of media items in \c media
346 * \param args_lang language string split from arguments
347 * \param args_offset_ms milliseconds offset split from arguments
348 * \param args_skipms
349 * \param args_playback_id string to use for playback split from
350 * arguments (null valid)
351 * \param response ARI response being built
352 * \param bridge Bridge the playback is being performed on
353 * \param control Control being used for the playback channel
354 * \param json contents of the response to ARI
355 * \param playback_url stores playback URL for use with response
356 *
357 * \retval -1 operation failed
358 * \return operation was successful
359 */
360static int ari_bridges_play_helper(const char **args_media,
361 size_t args_media_count,
362 const char *args_lang,
363 int args_offset_ms,
364 int args_skipms,
365 const char *args_playback_id,
366 struct ast_ari_response *response,
367 struct ast_bridge *bridge,
368 struct stasis_app_control *control,
369 struct ast_json **json,
370 char **playback_url)
371{
373 RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
374
375 const char *language;
376
378 if (!snapshot) {
380 response, 500, "Internal Error", "Failed to get control snapshot");
381 return -1;
382 }
383
384 language = S_OR(args_lang, snapshot->base->language);
385
386 playback = stasis_app_control_play_uri(control, args_media, args_media_count,
388 args_offset_ms, args_playback_id);
389
390 if (!playback) {
392 return -1;
393 }
394
395 if (ast_asprintf(playback_url, "/playbacks/%s",
396 stasis_app_playback_get_id(playback)) == -1) {
398 return -1;
399 }
400
401 *json = stasis_app_playback_to_json(playback);
402 if (!*json) {
404 return -1;
405 }
406
407 return 0;
408}
409
410static void ari_bridges_play_new(const char **args_media,
411 size_t args_media_count,
412 const char *args_format,
413 const char *args_lang,
414 int args_offset_ms,
415 int args_skipms,
416 const char *args_playback_id,
417 struct ast_ari_response *response,
418 struct ast_bridge *bridge)
419{
420 RAII_VAR(struct ast_channel *, play_channel, NULL, ast_hangup);
421 RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
422 RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
424 RAII_VAR(char *, playback_url, NULL, ast_free);
425
426 struct stasis_topic *channel_topic;
427 struct stasis_topic *bridge_topic;
428 struct bridge_channel_control_thread_data *thread_data;
429 pthread_t threadid;
430 struct ast_format *channel_format = NULL;
431
432 struct ast_frame prog = {
434 .subclass.integer = AST_CONTROL_PROGRESS,
435 };
436
437 /*
438 * Determine the format for the playback channel.
439 * If a format was specified, use that if it's valid.
440 * Otherwise, if the bridge is empty, use slin.
441 * If the bridge has one channel, use that channel's raw write format.
442 * If the bridge has multiple channels, use the slin format that
443 * will handle the highest sample rate of the raw write format of all the channels.
444 */
445 if (!ast_strlen_zero(args_format)) {
446 channel_format = ast_format_cache_get(args_format);
447 if (!channel_format) {
449 response, 422, "Unprocessable Entity",
450 "specified announcer_format is unknown on this system");
451 return;
452 }
453 /*
454 * ast_format_cache_get() bumps the refcount but the other calls
455 * to retrieve formats don't so we'll drop this reference.
456 * It'll be bumped again in the prepare_bridge_media_channel() call below.
457 */
458 ao2_ref(channel_format, -1);
459 } else {
460 ast_bridge_lock(bridge);
461 if (bridge->num_channels == 0) {
462 channel_format = ast_format_slin;
463 } else if (bridge->num_channels == 1) {
464 struct ast_bridge_channel *bc = NULL;
466 if (bc) {
467 channel_format = ast_channel_rawwriteformat(bc->chan);
468 }
469 } else {
470 struct ast_bridge_channel *bc = NULL;
471 unsigned int max_sample_rate = 0;
473 struct ast_format *fmt = ast_channel_rawwriteformat(bc->chan);
474 max_sample_rate = MAX(ast_format_get_sample_rate(fmt), max_sample_rate);
475 }
476 channel_format = ast_format_cache_get_slin_by_rate(max_sample_rate);
477 }
478 ast_bridge_unlock(bridge);
479 }
480
481 if (!channel_format) {
482 channel_format = ast_format_slin;
483 }
484
485 play_channel = prepare_bridge_media_channel("Announcer", channel_format);
486 ao2_cleanup(channel_format);
487 if (!play_channel) {
489 response, 500, "Internal Error", "Could not create playback channel");
490 return;
491 }
492 ast_debug(1, "Created announcer channel '%s'\n", ast_channel_name(play_channel));
493
494 bridge_topic = ast_bridge_topic(bridge);
495 channel_topic = ast_channel_topic(play_channel);
496
497 /* Forward messages from the playback channel topic to the bridge topic so that anything listening for
498 * messages on the bridge topic will receive the playback start/stop messages. Other messages that would
499 * go to this channel will be suppressed since the channel is marked as internal.
500 */
501 if (!bridge_topic || !channel_topic || !(channel_forward = stasis_forward_all(channel_topic, bridge_topic))) {
503 response, 500, "Internal Error", "Could not forward playback channel stasis messages to bridge topic");
504 return;
505 }
506
507 if (ast_unreal_channel_push_to_bridge(play_channel, bridge,
510 response, 500, "Internal Error", "Failed to put playback channel into the bridge");
511 return;
512 }
513
514 control = stasis_app_control_create(play_channel);
515 if (control == NULL) {
517 return;
518 }
519
520 ao2_lock(control);
521 if (ari_bridges_play_helper(args_media, args_media_count, args_lang,
522 args_offset_ms, args_skipms, args_playback_id, response, bridge,
523 control, &json, &playback_url)) {
524 ao2_unlock(control);
525 return;
526 }
527 ao2_unlock(control);
528
529 if (stasis_app_bridge_playback_channel_add(bridge, play_channel, control)) {
531 return;
532 }
533
534 ast_bridge_queue_everyone_else(bridge, NULL, &prog);
535
536 /* Give play_channel and control reference to the thread data */
537 thread_data = ast_malloc(sizeof(*thread_data) + strlen(bridge->uniqueid) + 1);
538 if (!thread_data) {
539 stasis_app_bridge_playback_channel_remove((char *)bridge->uniqueid, control);
541 return;
542 }
543
544 thread_data->bridge_channel = play_channel;
545 thread_data->control = control;
546 thread_data->forward = channel_forward;
547 /* Safe */
548 strcpy(thread_data->bridge_id, bridge->uniqueid);
549
550 if (ast_pthread_create_detached(&threadid, NULL, bridge_channel_control_thread, thread_data)) {
551 stasis_app_bridge_playback_channel_remove((char *)bridge->uniqueid, control);
553 ast_free(thread_data);
554 return;
555 }
556
557 /* These are owned by the other thread now, so we don't want RAII_VAR disposing of them. */
558 play_channel = NULL;
559 control = NULL;
560 channel_forward = NULL;
561
562 ast_ari_response_created(response, playback_url, ast_json_ref(json));
563}
564
570
571/*!
572 * \brief Performs common setup for a bridge playback operation
573 * with both new controls and when existing controls are found.
574 *
575 * \param args_media medias to play
576 * \param args_media_count number of media items in \c media
577 * \param args_lang language string split from arguments
578 * \param args_offset_ms milliseconds offset split from arguments
579 * \param args_skipms
580 * \param args_playback_id string to use for playback split from
581 * arguments (null valid)
582 * \param response ARI response being built
583 * \param bridge Bridge the playback is being performed on
584 * \param found_channel The channel that was found controlling playback
585 *
586 * \retval PLAY_FOUND_SUCCESS The operation was successful
587 * \retval PLAY_FOUND_FAILURE The operation failed (terminal failure)
588 * \retval PLAY_FOUND_CHANNEL_UNAVAILABLE The operation failed because
589 * the channel requested to playback with is breaking down.
590 */
591static enum play_found_result ari_bridges_play_found(const char **args_media,
592 size_t args_media_count,
593 const char *args_lang,
594 int args_offset_ms,
595 int args_skipms,
596 const char *args_playback_id,
597 struct ast_ari_response *response,
598 struct ast_bridge *bridge,
599 struct ast_channel *found_channel)
600{
601 RAII_VAR(struct ast_channel *, play_channel, found_channel, ao2_cleanup);
602 RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
603 RAII_VAR(char *, playback_url, NULL, ast_free);
604 RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
605
606 control = stasis_app_control_find_by_channel(play_channel);
607 if (!control) {
609 }
610
611 ao2_lock(control);
612 if (stasis_app_control_is_done(control)) {
613 /* We failed to queue the action. Bailout and return that we aren't terminal. */
614 ao2_unlock(control);
616 }
617
618 if (ari_bridges_play_helper(args_media, args_media_count,
619 args_lang, args_offset_ms, args_skipms, args_playback_id,
620 response, bridge, control, &json, &playback_url)) {
621 ao2_unlock(control);
622 return PLAY_FOUND_FAILURE;
623 }
624 ao2_unlock(control);
625
626 ast_ari_response_created(response, playback_url, ast_json_ref(json));
627 return PLAY_FOUND_SUCCESS;
628}
629
631 const char *args_bridge_id,
632 const char **args_media,
633 size_t args_media_count,
634 const char *args_format,
635 const char *args_lang,
636 int args_offset_ms,
637 int args_skipms,
638 const char *args_playback_id,
639 struct ast_ari_response *response)
640{
641 RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args_bridge_id), ao2_cleanup);
642 struct ast_channel *play_channel;
643
644 ast_assert(response != NULL);
645
646 if (!bridge) {
647 return;
648 }
649
650 while ((play_channel = stasis_app_bridge_playback_channel_find(bridge))) {
651 /* If ari_bridges_play_found fails because the channel is unavailable for
652 * playback, The channel will be removed from the playback list soon. We
653 * can keep trying to get channels from the list until we either get one
654 * that will work or else there isn't a channel for this bridge anymore,
655 * in which case we'll revert to ari_bridges_play_new.
656 */
657 if (ari_bridges_play_found(args_media, args_media_count, args_lang,
658 args_offset_ms, args_skipms, args_playback_id, response,bridge,
659 play_channel) == PLAY_FOUND_CHANNEL_UNAVAILABLE) {
660 continue;
661 }
662 return;
663 }
664
665 ari_bridges_play_new(args_media, args_media_count, args_format, args_lang, args_offset_ms,
666 args_skipms, args_playback_id, response, bridge);
667}
668
669
672 struct ast_ari_response *response)
673{
674 ari_bridges_handle_play(args->bridge_id,
675 args->media,
676 args->media_count,
677 args->announcer_format,
678 args->lang,
679 args->offsetms,
680 args->skipms,
681 args->playback_id,
682 response);
683}
684
687 struct ast_ari_response *response)
688{
689 ari_bridges_handle_play(args->bridge_id,
690 args->media,
691 args->media_count,
692 args->announcer_format,
693 args->lang,
694 args->offsetms,
695 args->skipms,
696 args->playback_id,
697 response);
698}
699
702 struct ast_ari_response *response)
703{
704 RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
705 RAII_VAR(struct ast_channel *, record_channel, NULL, ast_hangup);
706 RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
707 RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup);
708 RAII_VAR(char *, recording_url, NULL, ast_free);
709 RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
711 RAII_VAR(char *, uri_encoded_name, NULL, ast_free);
713
714 struct stasis_topic *channel_topic;
715 struct stasis_topic *bridge_topic;
716 size_t uri_name_maxlen;
717 struct bridge_channel_control_thread_data *thread_data;
718 pthread_t threadid;
719 struct ast_format *file_format = NULL;
720 struct ast_format *channel_format = NULL;
721
722 ast_assert(response != NULL);
723
724 if (bridge == NULL) {
725 return;
726 }
727
729 if (!file_format) {
731 response, 422, "Unprocessable Entity",
732 "specified format is unknown on this system");
733 return;
734 }
735
736 if (!ast_strlen_zero(args->recorder_format)) {
737 channel_format = ast_format_cache_get(args->recorder_format);
738 if (!channel_format) {
740 response, 422, "Unprocessable Entity",
741 "specified recorder_format is unknown on this system");
742 return;
743 }
744 /*
745 * ast_format_cache_get() bumps the refcount but the other calls
746 * to retrieve formats don't so we'll drop this reference.
747 * It'll be bumped again in the prepare_bridge_media_channel() call below.
748 */
749 ao2_ref(channel_format, -1);
750
751 } else {
752 channel_format = file_format;
753 }
754
755 if (!(record_channel = prepare_bridge_media_channel("Recorder", channel_format))) {
757 response, 500, "Internal Server Error", "Failed to create recording channel");
758 return;
759 }
760
761 bridge_topic = ast_bridge_topic(bridge);
762 channel_topic = ast_channel_topic(record_channel);
763
764 /* Forward messages from the recording channel topic to the bridge topic so that anything listening for
765 * messages on the bridge topic will receive the recording start/stop messages. Other messages that would
766 * go to this channel will be suppressed since the channel is marked as internal.
767 */
768 if (!bridge_topic || !channel_topic || !(channel_forward = stasis_forward_all(channel_topic, bridge_topic))) {
770 response, 500, "Internal Error", "Could not forward record channel stasis messages to bridge topic");
771 return;
772 }
773
774 if (ast_unreal_channel_push_to_bridge(record_channel, bridge,
777 response, 500, "Internal Error", "Failed to put recording channel into the bridge");
778 return;
779 }
780
781 control = stasis_app_control_create(record_channel);
782 if (control == NULL) {
784 return;
785 }
786
788 if (options == NULL) {
790 return;
791 }
792
793 ast_string_field_build(options, target, "bridge:%s", args->bridge_id);
794 options->max_silence_seconds = args->max_silence_seconds;
795 options->max_duration_seconds = args->max_duration_seconds;
796 options->terminate_on =
798 options->if_exists =
800 options->beep = args->beep;
801
802 if (options->terminate_on == STASIS_APP_RECORDING_TERMINATE_INVALID) {
804 response, 400, "Bad Request",
805 "terminateOn invalid");
806 return;
807 }
808
809 if (options->if_exists == AST_RECORD_IF_EXISTS_ERROR) {
811 response, 400, "Bad Request",
812 "ifExists invalid");
813 return;
814 }
815
816 recording = stasis_app_control_record(control, options);
817 if (recording == NULL) {
818 switch(errno) {
819 case EINVAL:
820 /* While the arguments are invalid, we should have
821 * caught them prior to calling record.
822 */
824 response, 500, "Internal Server Error",
825 "Error parsing request");
826 break;
827 case EEXIST:
828 ast_ari_response_error(response, 409, "Conflict",
829 "Recording '%s' already exists and can not be overwritten",
830 args->name);
831 break;
832 case ENOMEM:
834 break;
835 case EPERM:
837 response, 400, "Bad Request",
838 "Recording name invalid");
839 break;
840 default:
842 "Unrecognized recording error: %s\n",
843 strerror(errno));
845 response, 500, "Internal Server Error",
846 "Internal Server Error");
847 break;
848 }
849 return;
850 }
851
852 uri_name_maxlen = strlen(args->name) * 3;
853 uri_encoded_name = ast_malloc(uri_name_maxlen);
854 if (!uri_encoded_name) {
856 return;
857 }
858 ast_uri_encode(args->name, uri_encoded_name, uri_name_maxlen, ast_uri_http);
859
860 if (ast_asprintf(&recording_url, "/recordings/live/%s",
861 uri_encoded_name) == -1) {
862 recording_url = NULL;
864 return;
865 }
866
867 json = stasis_app_recording_to_json(recording);
868 if (!json) {
870 return;
871 }
872
873 thread_data = ast_calloc(1, sizeof(*thread_data));
874 if (!thread_data) {
876 return;
877 }
878
879 thread_data->bridge_channel = record_channel;
880 thread_data->control = control;
881 thread_data->forward = channel_forward;
882
883 if (ast_pthread_create_detached(&threadid, NULL, bridge_channel_control_thread, thread_data)) {
885 ast_free(thread_data);
886 return;
887 }
888
889 /* These are owned by the other thread now, so we don't want RAII_VAR disposing of them. */
890 record_channel = NULL;
891 control = NULL;
892 channel_forward = NULL;
893
894 ast_ari_response_created(response, recording_url, ast_json_ref(json));
895}
896
899 struct ast_ari_response *response)
900{
901 RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
902 struct ast_channel *moh_channel;
903 const char *moh_class = args->moh_class;
904
905 if (!bridge) {
906 /* The response is provided by find_bridge() */
907 return;
908 }
909
911 if (!moh_channel) {
913 return;
914 }
915
916 ast_moh_start(moh_channel, moh_class, NULL);
917 ast_channel_cleanup(moh_channel);
918
920
921}
922
925 struct ast_ari_response *response)
926{
927 RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
928
929 if (!bridge) {
930 /* the response is provided by find_bridge() */
931 return;
932 }
933
936 response, 409, "Conflict",
937 "Bridge isn't playing music");
938 return;
939 }
940
942}
943
946 struct ast_ari_response *response)
947{
949 if (!snapshot) {
951 response, 404, "Not Found",
952 "Bridge not found");
953 return;
954 }
955
956 ast_ari_response_ok(response,
958}
959
962 struct ast_ari_response *response)
963{
964 RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
965 if (!bridge) {
966 return;
967 }
968
971}
972
975 struct ast_ari_response *response)
976{
978 RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
979 struct ao2_iterator i;
980 struct ast_bridge *bridge;
981
983 if (!bridges) {
985 return;
986 }
987
988 json = ast_json_array_create();
989 if (!json) {
991 return;
992 }
993
995 while ((bridge = ao2_iterator_next(&i))) {
996 struct ast_bridge_snapshot *snapshot;
997 struct ast_json *json_bridge = NULL;
998
999 /* Invisible bridges don't get shown externally and have no snapshot */
1001 ao2_ref(bridge, -1);
1002 continue;
1003 }
1004
1005 snapshot = ast_bridge_get_snapshot(bridge);
1006 if (snapshot) {
1007 json_bridge = ast_bridge_snapshot_to_json(snapshot, stasis_app_get_sanitizer());
1008 ao2_ref(snapshot, -1);
1009 }
1010
1011 ao2_ref(bridge, -1);
1012
1013 if (!json_bridge || ast_json_array_append(json, json_bridge)) {
1016 return;
1017 }
1018 }
1020
1021 ast_ari_response_ok(response, ast_json_ref(json));
1022}
1023
1026 struct ast_ari_response *response)
1027{
1028 RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
1029 RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
1030
1031 if (ast_bridge_topic_exists(args->bridge_id)) {
1033 response, 409, "Conflict",
1034 "Bridge with id '%s' already exists", args->bridge_id);
1035 return;
1036 }
1037
1038 bridge = stasis_app_bridge_create(args->type, args->name, args->bridge_id);
1039 if (!bridge) {
1041 response, 500, "Internal Error",
1042 "Unable to create bridge. Possible duplicate bridge id '%s'", args->bridge_id);
1043 return;
1044 }
1045
1046 ast_bridge_lock(bridge);
1047 snapshot = ast_bridge_snapshot_create(bridge);
1048 ast_bridge_unlock(bridge);
1049
1050 if (!snapshot) {
1052 response, 500, "Internal Error",
1053 "Unable to create snapshot for new bridge");
1054 return;
1055 }
1056
1057 ast_ari_response_ok(response,
1059}
1060
1063 struct ast_ari_response *response)
1064{
1065 RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
1066 RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
1067
1068 if (ast_bridge_topic_exists(args->bridge_id)) {
1070 response, 409, "Conflict",
1071 "Bridge with id '%s' already exists", args->bridge_id);
1072 return;
1073 }
1074
1075 bridge = stasis_app_bridge_create(args->type, args->name, args->bridge_id);
1076 if (!bridge) {
1078 response, 500, "Internal Error",
1079 "Unable to create bridge");
1080 return;
1081 }
1082
1083 ast_bridge_lock(bridge);
1084 snapshot = ast_bridge_snapshot_create(bridge);
1085 ast_bridge_unlock(bridge);
1086
1087 if (!snapshot) {
1089 response, 500, "Internal Error",
1090 "Unable to create snapshot for new bridge");
1091 return;
1092 }
1093
1094 ast_ari_response_ok(response,
1096}
1097
1099 struct ast_channel *chan, void *data)
1100{
1101 struct ast_bridge *bridge = data;
1102
1103 ast_bridge_lock(bridge);
1105 ast_bridge_unlock(bridge);
1106
1107 return 0;
1108}
1109
1112{
1113 struct ast_bridge *bridge;
1114 struct stasis_app_control *control;
1115
1116 bridge = find_bridge(response, args->bridge_id);
1117 if (!bridge) {
1118 return;
1119 }
1120
1121 control = find_channel_control(response, args->channel_id);
1122 if (!control) {
1123 ao2_ref(bridge, -1);
1124 return;
1125 }
1126
1127 if (stasis_app_get_bridge(control) != bridge) {
1128 ast_ari_response_error(response, 422,
1129 "Unprocessable Entity",
1130 "Channel not in this bridge");
1131 ao2_ref(bridge, -1);
1132 ao2_ref(control, -1);
1133 return;
1134 }
1135
1138
1139 ao2_ref(bridge, -1);
1140 ao2_ref(control, -1);
1141
1143}
1144
1147{
1148 struct ast_bridge *bridge;
1149
1150 bridge = find_bridge(response, args->bridge_id);
1151 if (!bridge) {
1152 return;
1153 }
1154
1155 ast_bridge_lock(bridge);
1157 ast_bridge_unlock(bridge);
1158
1159 ao2_ref(bridge, -1);
1161}
void ast_ari_response_created(struct ast_ari_response *response, const char *url, struct ast_json *message)
Fill in a Created (201) ast_ari_response.
Definition res_ari.c:258
void ast_ari_response_error(struct ast_ari_response *response, int response_code, const char *response_text, const char *message_fmt,...)
Fill in an error ast_ari_response.
Definition res_ari.c:212
void ast_ari_response_ok(struct ast_ari_response *response, struct ast_json *message)
Fill in an OK (200) ast_ari_response.
Definition res_ari.c:229
void ast_ari_response_alloc_failed(struct ast_ari_response *response)
Fill in response with a 500 message for allocation failures.
Definition res_ari.c:251
void ast_ari_response_no_content(struct ast_ari_response *response)
Fill in a No Content (204) ast_ari_response.
Definition res_ari.c:237
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition astmm.h:180
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition astmm.h:267
#define ast_calloc(num, len)
A wrapper for calloc()
Definition astmm.h:202
#define ast_malloc(len)
A wrapper for malloc()
Definition astmm.h:191
#define ast_log
Definition astobj2.c:42
#define ao2_iterator_next(iter)
Definition astobj2.h:1911
#define ao2_cleanup(obj)
Definition astobj2.h:1934
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_unlock(a)
Definition astobj2.h:729
#define ao2_lock(a)
Definition astobj2.h:717
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
void __ao2_cleanup(void *obj)
Definition astobj2.c:677
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition astobj2.h:480
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ao2_alloc(data_size, destructor_fn)
Definition astobj2.h:409
static struct ao2_container * bridges
Definition bridge.c:132
Bridging API.
struct ao2_container * ast_bridges(void)
Returns the global bridges container.
Definition bridge.c:185
void ast_bridge_set_talker_src_video_mode(struct ast_bridge *bridge)
Set the bridge to pick the strongest talker supporting video as the single source video feed.
Definition bridge.c:3845
#define ast_bridge_unlock(bridge)
Unlock the bridge.
Definition bridge.h:485
void ast_bridge_set_single_src_video_mode(struct ast_bridge *bridge, struct ast_channel *video_src_chan)
Set a bridge to feed a single video source to all participants.
Definition bridge.c:3828
#define ast_bridge_lock(bridge)
Lock the bridge.
Definition bridge.h:474
int ast_bridge_queue_everyone_else(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
Queue the given frame to everyone else.
@ AST_BRIDGE_FLAG_INVISIBLE
@ AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE
@ AST_BRIDGE_CHANNEL_FLAG_LONELY
static PGresult * result
Definition cel_pgsql.c:84
static char language[MAX_LANGUAGE]
Definition chan_iax2.c:348
static const char type[]
General Asterisk PBX channel definitions.
const char * ast_channel_name(const struct ast_channel *chan)
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition channel.c:2511
struct stasis_topic * ast_channel_topic(struct ast_channel *chan)
A topic which publishes the events for a particular channel.
ast_callid ast_channel_callid(const struct ast_channel *chan)
struct ast_format * ast_channel_rawwriteformat(struct ast_channel *chan)
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition channel.h:3019
struct ast_channel * ast_request(const char *type, struct ast_format_cap *request_cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int *cause)
Requests a channel.
Definition channel.c:6322
static struct channel_usage channels
Unreal channel derivative framework.
int ast_unreal_channel_push_to_bridge(struct ast_channel *ast, struct ast_bridge *bridge, unsigned int flags)
Push the semi2 unreal channel into a bridge from either member of the unreal pair.
Generic File Format Support. Should be included by clients of the file handling routines....
struct ast_format * ast_get_format_for_file_ext(const char *file_ext)
Get the ast_format associated with the given file extension.
Definition file.c:2040
unsigned int ast_format_get_sample_rate(const struct ast_format *format)
Get the sample rate of a media format.
Definition format.c:379
Media Format Cache API.
#define ast_format_cache_get(name)
Retrieve a named format from the cache.
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
struct ast_format * ast_format_cache_get_slin_by_rate(unsigned int rate)
Retrieve the best signed linear format given a sample rate.
Format Capabilities API.
@ AST_FORMAT_CAP_FLAG_DEFAULT
Definition format_cap.h:38
#define ast_format_cap_append(cap, format, framing)
Add format capability to capabilities structure.
Definition format_cap.h:99
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition format_cap.h:49
file_format
Definition func_env.c:440
struct ast_channel_snapshot * ast_channel_snapshot_get_latest(const char *uniqueid)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object,...
#define bc
@ AST_RECORD_IF_EXISTS_ERROR
@ AST_FRAME_CONTROL
@ AST_CONTROL_PROGRESS
#define ast_debug(level,...)
Log a DEBUG message.
int ast_callid_threadassoc_add(ast_callid callid)
Adds a known callid to thread storage of the calling thread.
Definition logger.c:2290
unsigned int ast_callid
#define LOG_DEBUG
#define LOG_WARNING
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition json.c:73
int ast_json_array_append(struct ast_json *array, struct ast_json *value)
Append to an array.
Definition json.c:378
struct ast_json * ast_json_array_create(void)
Create a empty JSON array.
Definition json.c:362
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Definition json.c:67
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
int errno
Music on hold handling.
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
Definition channel.c:7748
static struct @519 args
#define NULL
Definition resample.c:96
void ast_ari_bridges_add_channel(struct ast_variable *headers, struct ast_ari_bridges_add_channel_args *args, struct ast_ari_response *response)
Add a channel to a bridge.
void ast_ari_bridges_clear_video_source(struct ast_variable *headers, struct ast_ari_bridges_clear_video_source_args *args, struct ast_ari_response *response)
Removes any explicit video source in a multi-party mixing bridge. This operation has no effect on bri...
void ast_ari_bridges_get(struct ast_variable *headers, struct ast_ari_bridges_get_args *args, struct ast_ari_response *response)
Get bridge details.
static void ari_bridges_play_new(const char **args_media, size_t args_media_count, const char *args_format, const char *args_lang, int args_offset_ms, int args_skipms, const char *args_playback_id, struct ast_ari_response *response, struct ast_bridge *bridge)
static struct stasis_app_control * find_channel_control(struct ast_ari_response *response, const char *channel_id)
Finds the control object for a channel, filling the response with an error, if appropriate.
void ast_ari_bridges_play_with_id(struct ast_variable *headers, struct ast_ari_bridges_play_with_id_args *args, struct ast_ari_response *response)
Start playback of media on a bridge.
static struct control_list * control_list_create(struct ast_ari_response *response, size_t count, const char **channels)
void ast_ari_bridges_play(struct ast_variable *headers, struct ast_ari_bridges_play_args *args, struct ast_ari_response *response)
Start playback of media on a bridge.
static void control_list_dtor(void *obj)
static struct ast_bridge * find_bridge(struct ast_ari_response *response, const char *bridge_id)
Finds a bridge, filling the response with an error, if appropriate.
static int bridge_set_video_source_cb(struct stasis_app_control *control, struct ast_channel *chan, void *data)
void ast_ari_bridges_destroy(struct ast_variable *headers, struct ast_ari_bridges_destroy_args *args, struct ast_ari_response *response)
Shut down a bridge.
play_found_result
@ PLAY_FOUND_CHANNEL_UNAVAILABLE
@ PLAY_FOUND_SUCCESS
@ PLAY_FOUND_FAILURE
void ast_ari_bridges_remove_channel(struct ast_variable *headers, struct ast_ari_bridges_remove_channel_args *args, struct ast_ari_response *response)
Remove a channel from a bridge.
void ast_ari_bridges_create(struct ast_variable *headers, struct ast_ari_bridges_create_args *args, struct ast_ari_response *response)
Create a new bridge.
static void ari_bridges_handle_play(const char *args_bridge_id, const char **args_media, size_t args_media_count, const char *args_format, const char *args_lang, int args_offset_ms, int args_skipms, const char *args_playback_id, struct ast_ari_response *response)
void ast_ari_bridges_create_with_id(struct ast_variable *headers, struct ast_ari_bridges_create_with_id_args *args, struct ast_ari_response *response)
Create a new bridge.
static int ari_bridges_play_helper(const char **args_media, size_t args_media_count, const char *args_lang, int args_offset_ms, int args_skipms, const char *args_playback_id, struct ast_ari_response *response, struct ast_bridge *bridge, struct stasis_app_control *control, struct ast_json **json, char **playback_url)
Performs common setup for a bridge playback operation with both new controls and when existing contro...
static void * bridge_channel_control_thread(void *data)
static int check_add_remove_channel(struct ast_ari_response *response, struct stasis_app_control *control, enum stasis_app_control_channel_result result)
void ast_ari_bridges_set_video_source(struct ast_variable *headers, struct ast_ari_bridges_set_video_source_args *args, struct ast_ari_response *response)
Set a channel as the video source in a multi-party mixing bridge. This operation has no effect on bri...
static enum play_found_result ari_bridges_play_found(const char **args_media, size_t args_media_count, const char *args_lang, int args_offset_ms, int args_skipms, const char *args_playback_id, struct ast_ari_response *response, struct ast_bridge *bridge, struct ast_channel *found_channel)
Performs common setup for a bridge playback operation with both new controls and when existing contro...
void ast_ari_bridges_record(struct ast_variable *headers, struct ast_ari_bridges_record_args *args, struct ast_ari_response *response)
Start a recording.
static struct ast_channel * prepare_bridge_media_channel(const char *type, struct ast_format *channel_format)
void ast_ari_bridges_start_moh(struct ast_variable *headers, struct ast_ari_bridges_start_moh_args *args, struct ast_ari_response *response)
Play music on hold to a bridge or change the MOH class that is playing.
void ast_ari_bridges_stop_moh(struct ast_variable *headers, struct ast_ari_bridges_stop_moh_args *args, struct ast_ari_response *response)
Stop playing music on hold to a bridge.
void ast_ari_bridges_list(struct ast_variable *headers, struct ast_ari_bridges_list_args *args, struct ast_ari_response *response)
List all active bridges in Asterisk.
Generated file - declares stubs to be implemented in res/ari/resource_bridges.c.
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
struct stasis_forward * stasis_forward_cancel(struct stasis_forward *forward)
Definition stasis.c:1615
struct stasis_forward * stasis_forward_all(struct stasis_topic *from_topic, struct stasis_topic *to_topic)
Create a subscription which forwards all messages from one topic to another.
Definition stasis.c:1645
Stasis Application API. See Stasis Application API for detailed documentation.
void stasis_app_control_mute_in_bridge(struct stasis_app_control *control, int mute)
Set whether audio from the channel is muted instead of passing through to the bridge.
Definition control.c:1515
void stasis_app_bridge_playback_channel_remove(char *bridge_id, struct stasis_app_control *control)
remove channel from list of ARI playback channels for bridges.
Definition res_stasis.c:769
struct stasis_message_sanitizer * stasis_app_get_sanitizer(void)
Get the Stasis message sanitizer for app_stasis applications.
const char * stasis_app_control_get_channel_id(const struct stasis_app_control *control)
Returns the uniqueid of the channel associated with this control.
Definition control.c:1475
int stasis_app_control_add_channel_to_bridge(struct stasis_app_control *control, struct ast_bridge *bridge)
Add a channel to the bridge.
Definition control.c:1428
void stasis_app_control_clear_roles(struct stasis_app_control *control)
Clear bridge roles currently applied to a channel controlled by a stasis app control.
Definition control.c:353
void stasis_app_bridge_destroy(const char *bridge_id)
Destroy the bridge.
Definition res_stasis.c:901
struct ast_bridge * stasis_app_bridge_find_by_id(const char *bridge_id)
Returns the bridge with the given id.
Definition res_stasis.c:800
struct ast_bridge * stasis_app_bridge_create(const char *type, const char *name, const char *id)
Create a bridge of the specified type.
Definition res_stasis.c:891
void stasis_app_control_absorb_dtmf_in_bridge(struct stasis_app_control *control, int absorb)
Set whether DTMF from the channel is absorbed instead of passing through to the bridge.
Definition control.c:1509
void stasis_app_control_execute_until_exhausted(struct ast_channel *chan, struct stasis_app_control *control)
Act on a stasis app control queue until it is empty.
struct ast_channel * stasis_app_bridge_moh_channel(struct ast_bridge *bridge)
Finds or creates an announcer channel in a bridge that can play music on hold.
Definition res_stasis.c:655
void stasis_app_control_flush_queue(struct stasis_app_control *control)
Flush the control command queue.
int stasis_app_control_add_role(struct stasis_app_control *control, const char *role)
Apply a bridge role to a channel controlled by a stasis app control.
Definition control.c:331
int stasis_app_channel_unreal_set_internal(struct ast_channel *chan)
Mark this unreal channel and it's other half as being internal to Stasis.
void stasis_app_control_inhibit_colp_in_bridge(struct stasis_app_control *control, int inhibit_colp)
Set whether COLP frames should be generated when joining the bridge.
Definition control.c:1521
int stasis_app_control_remove_channel_from_bridge(struct stasis_app_control *control, struct ast_bridge *bridge)
Remove a channel from the bridge.
Definition control.c:1465
struct ast_bridge * stasis_app_get_bridge(struct stasis_app_control *control)
Gets the bridge currently associated with a control object.
Definition control.c:972
int stasis_app_control_bridge_features_init(struct stasis_app_control *control)
Initialize bridge features into a channel control.
Definition control.c:1496
int stasis_app_bridge_playback_channel_add(struct ast_bridge *bridge, struct ast_channel *chan, struct stasis_app_control *control)
Adds a channel to the list of ARI playback channels for bridges.
Definition res_stasis.c:731
struct stasis_app_control * stasis_app_control_find_by_channel_id(const char *channel_id)
Returns the handler for the channel with the given id.
Definition res_stasis.c:349
struct ast_channel * stasis_app_bridge_playback_channel_find(struct ast_bridge *bridge)
Finds an existing ARI playback channel in a bridge.
Definition res_stasis.c:785
int stasis_app_control_is_done(struct stasis_app_control *control)
Check if a control is marked as done.
struct ast_channel_snapshot * stasis_app_control_get_snapshot(const struct stasis_app_control *control)
Returns the most recent snapshot for the associated channel.
Definition control.c:901
stasis_app_control_channel_result
Result codes used when adding/removing channels to/from bridges.
Definition stasis_app.h:810
@ STASIS_APP_CHANNEL_RECORDING
Definition stasis_app.h:814
@ STASIS_APP_CHANNEL_OKAY
Definition stasis_app.h:812
struct stasis_app_control * stasis_app_control_find_by_channel(const struct ast_channel *chan)
Returns the handler for the given channel.
Definition res_stasis.c:338
struct stasis_app_control * stasis_app_control_create(struct ast_channel *chan)
Creates a control handler for a channel that isn't in a stasis app.
Definition res_stasis.c:333
int stasis_app_bridge_moh_stop(struct ast_bridge *bridge)
Breaks down MOH channels playing on the bridge created by stasis_app_bridge_moh_channel.
Definition res_stasis.c:675
Backend API for implementing components of res_stasis.
int stasis_app_send_command(struct stasis_app_control *control, stasis_app_command_cb command, void *data, command_data_destructor_fn data_destructor)
Invokes a command on a control's channel.
Definition control.c:939
Stasis Application Playback API. See StasisApplication API" for detailed documentation.
@ STASIS_PLAYBACK_TARGET_BRIDGE
struct stasis_app_playback * stasis_app_control_play_uri(struct stasis_app_control *control, const char **media, size_t media_count, const char *language, const char *target_id, enum stasis_app_playback_target_type target_type, int skipms, long offsetms, const char *id)
Play a file to the control's channel.
struct ast_json * stasis_app_playback_to_json(const struct stasis_app_playback *playback)
Convert a playback to its JSON representation.
const char * stasis_app_playback_get_id(struct stasis_app_playback *playback)
Gets the unique id of a playback object.
Stasis Application Recording API. See StasisApplication API" for detailed documentation.
struct stasis_app_recording_options * stasis_app_recording_options_create(const char *name, const char *format)
Allocate a recording options object.
struct ast_json * stasis_app_recording_to_json(const struct stasis_app_recording *recording)
Construct a JSON model of a recording.
struct stasis_app_recording * stasis_app_control_record(struct stasis_app_control *control, struct stasis_app_recording_options *options)
Record media from a channel.
enum ast_record_if_exists stasis_app_recording_if_exists_parse(const char *str)
Parse a string into the if_exists enum.
#define STASIS_APP_RECORDING_TERMINATE_INVALID
char stasis_app_recording_termination_parse(const char *str)
Parse a string into the recording termination enum.
int ast_bridge_topic_exists(const char *uniqueid)
Check if a stasis topic exists for a bridge uniqueid.
struct ast_json * ast_bridge_snapshot_to_json(const struct ast_bridge_snapshot *snapshot, const struct stasis_message_sanitizer *sanitize)
Build a JSON object from a ast_bridge_snapshot.
struct ast_bridge_snapshot * ast_bridge_get_snapshot(struct ast_bridge *bridge)
Returns the current snapshot for the bridge.
struct ast_bridge_snapshot * ast_bridge_get_snapshot_by_uniqueid(const char *bridge_id)
Returns the current snapshot for the bridge.
struct ast_bridge_snapshot * ast_bridge_snapshot_create(struct ast_bridge *bridge)
Generate a snapshot of the bridge state. This is an ao2 object, so ao2_cleanup() to deallocate.
struct stasis_topic * ast_bridge_topic(struct ast_bridge *bridge)
A topic which publishes the events for a particular bridge.
#define ast_string_field_build(x, field, fmt, args...)
Set a field to a complex (built) value.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition strings.h:80
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition astobj2.h:1821
Structure that contains information regarding a channel in a bridge.
struct ast_bridge * bridge
Bridge this channel is participating in.
struct ast_bridge_channel::@204 entry
Structure that contains a snapshot of information about a bridge.
Definition bridge.h:318
Structure that contains information about a bridge.
Definition bridge.h:353
const ast_string_field uniqueid
Definition bridge.h:405
struct ast_bridge_channels_list channels
Definition bridge.h:367
unsigned int num_channels
Definition bridge.h:377
struct ast_flags feature_flags
Definition bridge.h:373
const ast_string_field language
Structure representing a snapshot of channel state.
struct ast_channel_snapshot_base * base
Main Channel structure associated with a channel.
struct ast_bridge_channel * bridge_channel
struct ast_channel_snapshot * snapshot
struct ast_bridge * bridge
struct stasis_forward * channel_forward
Format capabilities structure, holds formats + preference order + etc.
Definition format_cap.c:54
Definition of a media format.
Definition format.c:43
Data structure associated with a single frame of data.
enum ast_frame_type frametype
Abstract JSON element (object, array, string, int, ...).
Structure for variables, used for configurations and for channel variables.
struct stasis_app_control * control
struct stasis_app_control * controls[]
struct ast_bridge * bridge
Definition control.c:67
Forwarding information.
Definition stasis.c:1598
static struct test_options options
#define ast_test_flag(p, flag)
Definition utils.h:63
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition utils.h:978
#define ast_assert(a)
Definition utils.h:776
char * ast_uri_encode(const char *string, char *outbuf, int buflen, struct ast_flags spec)
Turn text string to URI-encoded XX version.
Definition utils.c:723
const struct ast_flags ast_uri_http
Definition utils.c:719
#define ast_pthread_create_detached(a, b, c, d)
Definition utils.h:625
#define MAX(a, b)
Definition utils.h:251