Asterisk - The Open Source Telephony Project  21.4.1
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"
34 #include "asterisk/stasis_bridges.h"
35 #include "asterisk/stasis_app.h"
39 #include "asterisk/stasis_channels.h"
40 #include "asterisk/core_unreal.h"
41 #include "asterisk/channel.h"
42 #include "asterisk/bridge.h"
43 #include "asterisk/format_cap.h"
44 #include "asterisk/file.h"
45 #include "asterisk/musiconhold.h"
46 #include "asterisk/format_cache.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  */
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_get_snapshot_by_uniqueid(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  * \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,
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) {
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 static 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);
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) {
237  ast_ari_response_no_content(response);
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 
278  ast_ari_response_no_content(response);
279 }
280 
282  struct ast_channel *bridge_channel;
283  struct stasis_app_control *control;
284  struct stasis_forward *forward;
285  char bridge_id[0];
286 };
287 
288 static 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 
307  stasis_app_bridge_playback_channel_remove(bridge_id, control);
308  stasis_forward_cancel(forward);
309  ao2_cleanup(control);
310  ast_hangup(bridge_channel);
311  return NULL;
312 }
313 
314 static struct ast_channel *prepare_bridge_media_channel(const char *type)
315 {
316  RAII_VAR(struct ast_format_cap *, cap, NULL, ao2_cleanup);
317  struct ast_channel *chan;
318 
320  if (!cap) {
321  return NULL;
322  }
323 
325 
326  chan = ast_request(type, cap, NULL, NULL, "ARI", NULL);
327  if (!chan) {
328  return NULL;
329  }
330 
332  ast_channel_cleanup(chan);
333  return NULL;
334  }
335  return chan;
336 }
337 
338 /*!
339  * \brief Performs common setup for a bridge playback operation
340  * with both new controls and when existing controls are found.
341  *
342  * \param args_media medias to play
343  * \param args_media_count number of media items in \c media
344  * \param args_lang language string split from arguments
345  * \param args_offset_ms milliseconds offset split from arguments
346  * \param args_skipms
347  * \param args_playback_id string to use for playback split from
348  * arguments (null valid)
349  * \param response ARI response being built
350  * \param bridge Bridge the playback is being performed on
351  * \param control Control being used for the playback channel
352  * \param json contents of the response to ARI
353  * \param playback_url stores playback URL for use with response
354  *
355  * \retval -1 operation failed
356  * \return operation was successful
357  */
358 static int ari_bridges_play_helper(const char **args_media,
359  size_t args_media_count,
360  const char *args_lang,
361  int args_offset_ms,
362  int args_skipms,
363  const char *args_playback_id,
364  struct ast_ari_response *response,
365  struct ast_bridge *bridge,
366  struct stasis_app_control *control,
367  struct ast_json **json,
368  char **playback_url)
369 {
370  RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
371  RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
372 
373  const char *language;
374 
376  if (!snapshot) {
378  response, 500, "Internal Error", "Failed to get control snapshot");
379  return -1;
380  }
381 
382  language = S_OR(args_lang, snapshot->base->language);
383 
384  playback = stasis_app_control_play_uri(control, args_media, args_media_count,
385  language, bridge->uniqueid, STASIS_PLAYBACK_TARGET_BRIDGE, args_skipms,
386  args_offset_ms, args_playback_id);
387 
388  if (!playback) {
390  return -1;
391  }
392 
393  if (ast_asprintf(playback_url, "/playbacks/%s",
394  stasis_app_playback_get_id(playback)) == -1) {
396  return -1;
397  }
398 
399  *json = stasis_app_playback_to_json(playback);
400  if (!*json) {
402  return -1;
403  }
404 
405  return 0;
406 }
407 
408 static void ari_bridges_play_new(const char **args_media,
409  size_t args_media_count,
410  const char *args_lang,
411  int args_offset_ms,
412  int args_skipms,
413  const char *args_playback_id,
414  struct ast_ari_response *response,
415  struct ast_bridge *bridge)
416 {
417  RAII_VAR(struct ast_channel *, play_channel, NULL, ast_hangup);
418  RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
419  RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
420  RAII_VAR(struct stasis_forward *, channel_forward, NULL, stasis_forward_cancel);
421  RAII_VAR(char *, playback_url, NULL, ast_free);
422 
423  struct stasis_topic *channel_topic;
424  struct stasis_topic *bridge_topic;
425  struct bridge_channel_control_thread_data *thread_data;
426  pthread_t threadid;
427 
428  struct ast_frame prog = {
430  .subclass.integer = AST_CONTROL_PROGRESS,
431  };
432 
433 
434  if (!(play_channel = prepare_bridge_media_channel("Announcer"))) {
436  response, 500, "Internal Error", "Could not create playback channel");
437  return;
438  }
439  ast_debug(1, "Created announcer channel '%s'\n", ast_channel_name(play_channel));
440 
441  bridge_topic = ast_bridge_topic(bridge);
442  channel_topic = ast_channel_topic(play_channel);
443 
444  /* Forward messages from the playback channel topic to the bridge topic so that anything listening for
445  * messages on the bridge topic will receive the playback start/stop messages. Other messages that would
446  * go to this channel will be suppressed since the channel is marked as internal.
447  */
448  if (!bridge_topic || !channel_topic || !(channel_forward = stasis_forward_all(channel_topic, bridge_topic))) {
450  response, 500, "Internal Error", "Could not forward playback channel stasis messages to bridge topic");
451  return;
452  }
453 
454  if (ast_unreal_channel_push_to_bridge(play_channel, bridge,
457  response, 500, "Internal Error", "Failed to put playback channel into the bridge");
458  return;
459  }
460 
461  control = stasis_app_control_create(play_channel);
462  if (control == NULL) {
464  return;
465  }
466 
467  ao2_lock(control);
468  if (ari_bridges_play_helper(args_media, args_media_count, args_lang,
469  args_offset_ms, args_skipms, args_playback_id, response, bridge,
470  control, &json, &playback_url)) {
471  ao2_unlock(control);
472  return;
473  }
474  ao2_unlock(control);
475 
476  if (stasis_app_bridge_playback_channel_add(bridge, play_channel, control)) {
478  return;
479  }
480 
481  ast_bridge_queue_everyone_else(bridge, NULL, &prog);
482 
483  /* Give play_channel and control reference to the thread data */
484  thread_data = ast_malloc(sizeof(*thread_data) + strlen(bridge->uniqueid) + 1);
485  if (!thread_data) {
486  stasis_app_bridge_playback_channel_remove((char *)bridge->uniqueid, control);
488  return;
489  }
490 
491  thread_data->bridge_channel = play_channel;
492  thread_data->control = control;
493  thread_data->forward = channel_forward;
494  /* Safe */
495  strcpy(thread_data->bridge_id, bridge->uniqueid);
496 
497  if (ast_pthread_create_detached(&threadid, NULL, bridge_channel_control_thread, thread_data)) {
498  stasis_app_bridge_playback_channel_remove((char *)bridge->uniqueid, control);
500  ast_free(thread_data);
501  return;
502  }
503 
504  /* These are owned by the other thread now, so we don't want RAII_VAR disposing of them. */
505  play_channel = NULL;
506  control = NULL;
507  channel_forward = NULL;
508 
509  ast_ari_response_created(response, playback_url, ast_json_ref(json));
510 }
511 
512 enum play_found_result {
513  PLAY_FOUND_SUCCESS,
514  PLAY_FOUND_FAILURE,
515  PLAY_FOUND_CHANNEL_UNAVAILABLE,
516 };
517 
518 /*!
519  * \brief Performs common setup for a bridge playback operation
520  * with both new controls and when existing controls are found.
521  *
522  * \param args_media medias to play
523  * \param args_media_count number of media items in \c media
524  * \param args_lang language string split from arguments
525  * \param args_offset_ms milliseconds offset split from arguments
526  * \param args_skipms
527  * \param args_playback_id string to use for playback split from
528  * arguments (null valid)
529  * \param response ARI response being built
530  * \param bridge Bridge the playback is being performed on
531  * \param found_channel The channel that was found controlling playback
532  *
533  * \retval PLAY_FOUND_SUCCESS The operation was successful
534  * \retval PLAY_FOUND_FAILURE The operation failed (terminal failure)
535  * \retval PLAY_FOUND_CHANNEL_UNAVAILABLE The operation failed because
536  * the channel requested to playback with is breaking down.
537  */
538 static enum play_found_result ari_bridges_play_found(const char **args_media,
539  size_t args_media_count,
540  const char *args_lang,
541  int args_offset_ms,
542  int args_skipms,
543  const char *args_playback_id,
544  struct ast_ari_response *response,
545  struct ast_bridge *bridge,
546  struct ast_channel *found_channel)
547 {
548  RAII_VAR(struct ast_channel *, play_channel, found_channel, ao2_cleanup);
549  RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
550  RAII_VAR(char *, playback_url, NULL, ast_free);
551  RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
552 
553  control = stasis_app_control_find_by_channel(play_channel);
554  if (!control) {
555  return PLAY_FOUND_CHANNEL_UNAVAILABLE;
556  }
557 
558  ao2_lock(control);
559  if (stasis_app_control_is_done(control)) {
560  /* We failed to queue the action. Bailout and return that we aren't terminal. */
561  ao2_unlock(control);
562  return PLAY_FOUND_CHANNEL_UNAVAILABLE;
563  }
564 
565  if (ari_bridges_play_helper(args_media, args_media_count,
566  args_lang, args_offset_ms, args_skipms, args_playback_id,
567  response, bridge, control, &json, &playback_url)) {
568  ao2_unlock(control);
569  return PLAY_FOUND_FAILURE;
570  }
571  ao2_unlock(control);
572 
573  ast_ari_response_created(response, playback_url, ast_json_ref(json));
574  return PLAY_FOUND_SUCCESS;
575 }
576 
577 static void ari_bridges_handle_play(
578  const char *args_bridge_id,
579  const char **args_media,
580  size_t args_media_count,
581  const char *args_lang,
582  int args_offset_ms,
583  int args_skipms,
584  const char *args_playback_id,
585  struct ast_ari_response *response)
586 {
587  RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args_bridge_id), ao2_cleanup);
588  struct ast_channel *play_channel;
589 
590  ast_assert(response != NULL);
591 
592  if (!bridge) {
593  return;
594  }
595 
596  while ((play_channel = stasis_app_bridge_playback_channel_find(bridge))) {
597  /* If ari_bridges_play_found fails because the channel is unavailable for
598  * playback, The channel will be removed from the playback list soon. We
599  * can keep trying to get channels from the list until we either get one
600  * that will work or else there isn't a channel for this bridge anymore,
601  * in which case we'll revert to ari_bridges_play_new.
602  */
603  if (ari_bridges_play_found(args_media, args_media_count, args_lang,
604  args_offset_ms, args_skipms, args_playback_id, response,bridge,
605  play_channel) == PLAY_FOUND_CHANNEL_UNAVAILABLE) {
606  continue;
607  }
608  return;
609  }
610 
611  ari_bridges_play_new(args_media, args_media_count, args_lang, args_offset_ms,
612  args_skipms, args_playback_id, response, bridge);
613 }
614 
615 
616 void ast_ari_bridges_play(struct ast_variable *headers,
617  struct ast_ari_bridges_play_args *args,
618  struct ast_ari_response *response)
619 {
620  ari_bridges_handle_play(args->bridge_id,
621  args->media,
622  args->media_count,
623  args->lang,
624  args->offsetms,
625  args->skipms,
626  args->playback_id,
627  response);
628 }
629 
632  struct ast_ari_response *response)
633 {
634  ari_bridges_handle_play(args->bridge_id,
635  args->media,
636  args->media_count,
637  args->lang,
638  args->offsetms,
639  args->skipms,
640  args->playback_id,
641  response);
642 }
643 
645  struct ast_ari_bridges_record_args *args,
646  struct ast_ari_response *response)
647 {
648  RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
649  RAII_VAR(struct ast_channel *, record_channel, NULL, ast_hangup);
650  RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
651  RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup);
652  RAII_VAR(char *, recording_url, NULL, ast_free);
653  RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
654  RAII_VAR(struct stasis_app_recording_options *, options, NULL, ao2_cleanup);
655  RAII_VAR(char *, uri_encoded_name, NULL, ast_free);
656  RAII_VAR(struct stasis_forward *, channel_forward, NULL, stasis_forward_cancel);
657 
658  struct stasis_topic *channel_topic;
659  struct stasis_topic *bridge_topic;
660  size_t uri_name_maxlen;
661  struct bridge_channel_control_thread_data *thread_data;
662  pthread_t threadid;
663 
664  ast_assert(response != NULL);
665 
666  if (bridge == NULL) {
667  return;
668  }
669 
670  if (!(record_channel = prepare_bridge_media_channel("Recorder"))) {
672  response, 500, "Internal Server Error", "Failed to create recording channel");
673  return;
674  }
675 
676  bridge_topic = ast_bridge_topic(bridge);
677  channel_topic = ast_channel_topic(record_channel);
678 
679  /* Forward messages from the recording channel topic to the bridge topic so that anything listening for
680  * messages on the bridge topic will receive the recording start/stop messages. Other messages that would
681  * go to this channel will be suppressed since the channel is marked as internal.
682  */
683  if (!bridge_topic || !channel_topic || !(channel_forward = stasis_forward_all(channel_topic, bridge_topic))) {
685  response, 500, "Internal Error", "Could not forward record channel stasis messages to bridge topic");
686  return;
687  }
688 
689  if (ast_unreal_channel_push_to_bridge(record_channel, bridge,
692  response, 500, "Internal Error", "Failed to put recording channel into the bridge");
693  return;
694  }
695 
696  control = stasis_app_control_create(record_channel);
697  if (control == NULL) {
699  return;
700  }
701 
702  options = stasis_app_recording_options_create(args->name, args->format);
703  if (options == NULL) {
705  return;
706  }
707 
708  ast_string_field_build(options, target, "bridge:%s", args->bridge_id);
709  options->max_silence_seconds = args->max_silence_seconds;
710  options->max_duration_seconds = args->max_duration_seconds;
711  options->terminate_on =
713  options->if_exists =
715  options->beep = args->beep;
716 
717  if (options->terminate_on == STASIS_APP_RECORDING_TERMINATE_INVALID) {
719  response, 400, "Bad Request",
720  "terminateOn invalid");
721  return;
722  }
723 
724  if (options->if_exists == AST_RECORD_IF_EXISTS_ERROR) {
726  response, 400, "Bad Request",
727  "ifExists invalid");
728  return;
729  }
730 
731  if (!ast_get_format_for_file_ext(options->format)) {
733  response, 422, "Unprocessable Entity",
734  "specified format is unknown on this system");
735  return;
736  }
737 
738  recording = stasis_app_control_record(control, options);
739  if (recording == NULL) {
740  switch(errno) {
741  case EINVAL:
742  /* While the arguments are invalid, we should have
743  * caught them prior to calling record.
744  */
746  response, 500, "Internal Server Error",
747  "Error parsing request");
748  break;
749  case EEXIST:
750  ast_ari_response_error(response, 409, "Conflict",
751  "Recording '%s' already exists and can not be overwritten",
752  args->name);
753  break;
754  case ENOMEM:
756  break;
757  case EPERM:
759  response, 400, "Bad Request",
760  "Recording name invalid");
761  break;
762  default:
763  ast_log(LOG_WARNING,
764  "Unrecognized recording error: %s\n",
765  strerror(errno));
767  response, 500, "Internal Server Error",
768  "Internal Server Error");
769  break;
770  }
771  return;
772  }
773 
774  uri_name_maxlen = strlen(args->name) * 3;
775  uri_encoded_name = ast_malloc(uri_name_maxlen);
776  if (!uri_encoded_name) {
778  return;
779  }
780  ast_uri_encode(args->name, uri_encoded_name, uri_name_maxlen, ast_uri_http);
781 
782  if (ast_asprintf(&recording_url, "/recordings/live/%s",
783  uri_encoded_name) == -1) {
784  recording_url = NULL;
786  return;
787  }
788 
789  json = stasis_app_recording_to_json(recording);
790  if (!json) {
792  return;
793  }
794 
795  thread_data = ast_calloc(1, sizeof(*thread_data));
796  if (!thread_data) {
798  return;
799  }
800 
801  thread_data->bridge_channel = record_channel;
802  thread_data->control = control;
803  thread_data->forward = channel_forward;
804 
805  if (ast_pthread_create_detached(&threadid, NULL, bridge_channel_control_thread, thread_data)) {
807  ast_free(thread_data);
808  return;
809  }
810 
811  /* These are owned by the other thread now, so we don't want RAII_VAR disposing of them. */
812  record_channel = NULL;
813  control = NULL;
814  channel_forward = NULL;
815 
816  ast_ari_response_created(response, recording_url, ast_json_ref(json));
817 }
818 
820  struct ast_ari_bridges_start_moh_args *args,
821  struct ast_ari_response *response)
822 {
823  RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
824  struct ast_channel *moh_channel;
825  const char *moh_class = args->moh_class;
826 
827  if (!bridge) {
828  /* The response is provided by find_bridge() */
829  return;
830  }
831 
832  moh_channel = stasis_app_bridge_moh_channel(bridge);
833  if (!moh_channel) {
835  return;
836  }
837 
838  ast_moh_start(moh_channel, moh_class, NULL);
839  ast_channel_cleanup(moh_channel);
840 
841  ast_ari_response_no_content(response);
842 
843 }
844 
846  struct ast_ari_bridges_stop_moh_args *args,
847  struct ast_ari_response *response)
848 {
849  RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
850 
851  if (!bridge) {
852  /* the response is provided by find_bridge() */
853  return;
854  }
855 
856  if (stasis_app_bridge_moh_stop(bridge)) {
858  response, 409, "Conflict",
859  "Bridge isn't playing music");
860  return;
861  }
862 
863  ast_ari_response_no_content(response);
864 }
865 
866 void ast_ari_bridges_get(struct ast_variable *headers,
867  struct ast_ari_bridges_get_args *args,
868  struct ast_ari_response *response)
869 {
871  if (!snapshot) {
873  response, 404, "Not Found",
874  "Bridge not found");
875  return;
876  }
877 
878  ast_ari_response_ok(response,
880 }
881 
883  struct ast_ari_bridges_destroy_args *args,
884  struct ast_ari_response *response)
885 {
886  RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
887  if (!bridge) {
888  return;
889  }
890 
892  ast_ari_response_no_content(response);
893 }
894 
895 void ast_ari_bridges_list(struct ast_variable *headers,
896  struct ast_ari_bridges_list_args *args,
897  struct ast_ari_response *response)
898 {
899  RAII_VAR(struct ao2_container *, bridges, NULL, ao2_cleanup);
900  RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
901  struct ao2_iterator i;
902  struct ast_bridge *bridge;
903 
904  bridges = ast_bridges();
905  if (!bridges) {
907  return;
908  }
909 
910  json = ast_json_array_create();
911  if (!json) {
913  return;
914  }
915 
916  i = ao2_iterator_init(bridges, 0);
917  while ((bridge = ao2_iterator_next(&i))) {
918  struct ast_bridge_snapshot *snapshot;
919  struct ast_json *json_bridge = NULL;
920 
921  /* Invisible bridges don't get shown externally and have no snapshot */
922  if (ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_INVISIBLE)) {
923  ao2_ref(bridge, -1);
924  continue;
925  }
926 
927  snapshot = ast_bridge_get_snapshot(bridge);
928  if (snapshot) {
929  json_bridge = ast_bridge_snapshot_to_json(snapshot, stasis_app_get_sanitizer());
930  ao2_ref(snapshot, -1);
931  }
932 
933  ao2_ref(bridge, -1);
934 
935  if (!json_bridge || ast_json_array_append(json, json_bridge)) {
938  return;
939  }
940  }
942 
943  ast_ari_response_ok(response, ast_json_ref(json));
944 }
945 
947  struct ast_ari_bridges_create_args *args,
948  struct ast_ari_response *response)
949 {
950  RAII_VAR(struct ast_bridge *, bridge, stasis_app_bridge_create(args->type, args->name, args->bridge_id), ao2_cleanup);
951  RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
952 
953  if (!bridge) {
955  response, 500, "Internal Error",
956  "Unable to create bridge");
957  return;
958  }
959 
960  ast_bridge_lock(bridge);
961  snapshot = ast_bridge_snapshot_create(bridge);
962  ast_bridge_unlock(bridge);
963 
964  if (!snapshot) {
966  response, 500, "Internal Error",
967  "Unable to create snapshot for new bridge");
968  return;
969  }
970 
971  ast_ari_response_ok(response,
973 }
974 
977  struct ast_ari_response *response)
978 {
979  RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
980  RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
981 
982  if (bridge) {
983  /* update */
984  if (!ast_strlen_zero(args->name)
985  && strcmp(args->name, bridge->name)) {
987  response, 500, "Internal Error",
988  "Changing bridge name is not implemented");
989  return;
990  }
991  if (!ast_strlen_zero(args->type)) {
993  response, 500, "Internal Error",
994  "Supplying a bridge type when updating a bridge is not allowed.");
995  return;
996  }
997  ast_ari_response_ok(response,
999  return;
1000  }
1001 
1002  bridge = stasis_app_bridge_create(args->type, args->name, args->bridge_id);
1003  if (!bridge) {
1005  response, 500, "Internal Error",
1006  "Unable to create bridge");
1007  return;
1008  }
1009 
1010  ast_bridge_lock(bridge);
1011  snapshot = ast_bridge_snapshot_create(bridge);
1012  ast_bridge_unlock(bridge);
1013 
1014  if (!snapshot) {
1016  response, 500, "Internal Error",
1017  "Unable to create snapshot for new bridge");
1018  return;
1019  }
1020 
1021  ast_ari_response_ok(response,
1023 }
1024 
1025 static int bridge_set_video_source_cb(struct stasis_app_control *control,
1026  struct ast_channel *chan, void *data)
1027 {
1028  struct ast_bridge *bridge = data;
1029 
1030  ast_bridge_lock(bridge);
1032  ast_bridge_unlock(bridge);
1033 
1034  return 0;
1035 }
1036 
1038  struct ast_ari_bridges_set_video_source_args *args, struct ast_ari_response *response)
1039 {
1040  struct ast_bridge *bridge;
1041  struct stasis_app_control *control;
1042 
1043  bridge = find_bridge(response, args->bridge_id);
1044  if (!bridge) {
1045  return;
1046  }
1047 
1048  control = find_channel_control(response, args->channel_id);
1049  if (!control) {
1050  ao2_ref(bridge, -1);
1051  return;
1052  }
1053 
1054  if (stasis_app_get_bridge(control) != bridge) {
1055  ast_ari_response_error(response, 422,
1056  "Unprocessable Entity",
1057  "Channel not in this bridge");
1058  ao2_ref(bridge, -1);
1059  ao2_ref(control, -1);
1060  return;
1061  }
1062 
1063  stasis_app_send_command(control, bridge_set_video_source_cb,
1064  ao2_bump(bridge), __ao2_cleanup);
1065 
1066  ao2_ref(bridge, -1);
1067  ao2_ref(control, -1);
1068 
1069  ast_ari_response_no_content(response);
1070 }
1071 
1073  struct ast_ari_bridges_clear_video_source_args *args, struct ast_ari_response *response)
1074 {
1075  struct ast_bridge *bridge;
1076 
1077  bridge = find_bridge(response, args->bridge_id);
1078  if (!bridge) {
1079  return;
1080  }
1081 
1082  ast_bridge_lock(bridge);
1084  ast_bridge_unlock(bridge);
1085 
1086  ao2_ref(bridge, -1);
1087  ast_ari_response_no_content(response);
1088 }
struct ast_bridge * stasis_app_get_bridge(struct stasis_app_control *control)
Gets the bridge currently associated with a control object.
Definition: control.c:953
Stasis Application Recording API. See StasisApplication API" for detailed documentation.
Main Channel structure associated with a channel.
Music on hold handling.
struct ao2_container * ast_bridges(void)
Returns the global bridges container.
Definition: bridge.c:174
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Definition: json.c:67
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:1486
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:338
int stasis_app_control_bridge_features_init(struct stasis_app_control *control)
Initialize bridge features into a channel control.
Definition: control.c:1473
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.
struct stasis_forward * channel_forward
int stasis_app_control_is_done(struct stasis_app_control *control)
Check if a control is marked as done.
Definition: res_stasis.c:1276
struct ast_channel_snapshot_base * base
Asterisk main include file. File version handling, generic pbx functions.
struct ast_flags feature_flags
Definition: bridge.h:369
const ast_string_field uniqueid
Definition: bridge.h:401
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.
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.
void ast_ari_bridges_get(struct ast_variable *headers, struct ast_ari_bridges_get_args *args, struct ast_ari_response *response)
Get bridge details.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
struct ast_bridge_snapshot * ast_bridge_get_snapshot_by_uniqueid(const char *uniqueid)
Returns the current snapshot for the bridge.
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
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_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:305
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
Structure that contains a snapshot of information about a bridge.
Definition: bridge.h:314
void __ao2_cleanup(void *obj)
Definition: astobj2.c:677
const ast_string_field name
Definition: bridge.h:401
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:1442
Structure for variables, used for configurations and for channel variables.
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
Structure representing a snapshot of channel state.
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:920
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 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:743
struct ast_json * stasis_app_playback_to_json(const struct stasis_app_playback *playback)
Convert a playback to its JSON representation.
int ast_callid_threadassoc_add(ast_callid callid)
Adds a known callid to thread storage of the calling thread.
Definition: logger.c:2320
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
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.
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
char stasis_app_recording_termination_parse(const char *str)
Parse a string into the recording termination enum.
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.
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:298
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.
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.
Definition: res_stasis.c:2295
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:267
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:6354
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
const char * stasis_app_playback_get_id(struct stasis_app_playback *playback)
Gets the unique id of a playback object.
struct ast_json * stasis_app_recording_to_json(const struct stasis_app_recording *recording)
Construct a JSON model of a recording.
struct ast_bridge_channel * bridge_channel
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.
General Asterisk PBX channel definitions.
stasis_app_control_channel_result
Result codes used when adding/removing channels to/from bridges.
Definition: stasis_app.h:776
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
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:276
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition: channel.h:2969
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.
Definition: core_unreal.c:928
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...
#define ast_format_cap_append(cap, format, framing)
Add format capability to capabilities structure.
Definition: format_cap.h:99
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
#define ast_debug(level,...)
Log a DEBUG message.
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition: format_cap.h:49
struct ast_json * ast_json_array_create(void)
Create a empty JSON array.
Definition: json.c:362
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.
int ast_json_array_append(struct ast_json *array, struct ast_json *value)
Append to an array.
Definition: json.c:378
Format Capabilities API.
void stasis_app_control_flush_queue(struct stasis_app_control *control)
Flush the control command queue.
Definition: res_stasis.c:1281
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.
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:1405
struct stasis_topic * ast_channel_topic(struct ast_channel *chan)
A topic which publishes the events for a particular channel.
struct ast_bridge_snapshot * ast_bridge_get_snapshot(struct ast_bridge *bridge)
Returns the current snapshot for the bridge.
Structure that contains information about a bridge.
Definition: bridge.h:349
Backend API for implementing components of res_stasis.
struct stasis_message_sanitizer * stasis_app_get_sanitizer(void)
Get the Stasis message sanitizer for app_stasis applications.
Definition: res_stasis.c:2271
enum ast_record_if_exists stasis_app_recording_if_exists_parse(const char *str)
Parse a string into the if_exists enum.
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
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:1452
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:649
struct ast_bridge * stasis_app_bridge_find_by_id(const char *bridge_id)
Returns the bridge with the given id.
Definition: res_stasis.c:774
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:7766
void stasis_app_bridge_destroy(const char *bridge_id)
Destroy the bridge.
Definition: res_stasis.c:864
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...
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:882
struct ast_bridge * bridge
static struct ao2_container * bridges
Definition: bridge.c:123
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.
#define ast_bridge_unlock(bridge)
Unlock the bridge.
Definition: bridge.h:481
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
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:259
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...
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...
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2541
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:3766
struct stasis_app_recording_options * stasis_app_recording_options_create(const char *name, const char *format)
Allocate a recording options object.
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 or updates an existing one.
void ast_ari_response_no_content(struct ast_ari_response *response)
Fill in a No Content (204) ast_ari_response.
Definition: res_ari.c:284
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:759
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:2006
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.
Definition: res_stasis.c:1253
#define ast_string_field_build(x, field, fmt, args...)
Set a field to a complex (built) value.
Definition: stringfields.h:555
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
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:1498
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:3749
struct stasis_topic * ast_bridge_topic(struct ast_bridge *bridge)
A topic which publishes the events for a particular bridge.
#define ast_bridge_lock(bridge)
Lock the bridge.
Definition: bridge.h:470
Generated file - declares stubs to be implemented in res/ari/resource_bridges.c.
const ast_string_field language
void ast_ari_bridges_record(struct ast_variable *headers, struct ast_ari_bridges_record_args *args, struct ast_ari_response *response)
Start a recording.
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:360
Stasis Application Playback API. See StasisApplication API" for detailed documentation.
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:705
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...
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
#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
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.
Data structure associated with a single frame of data.
Abstract JSON element (object, array, string, int, ...).
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.
Forwarding information.
Definition: stasis.c:1531
enum ast_frame_type frametype
Stasis Application API. See Stasis Application API for detailed documentation.
Generic container type.
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...
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:1578
Bridging API.
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
#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:941
struct ast_channel_snapshot * snapshot
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:629
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
const ast_string_field language
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:1492
struct stasis_app_recording * stasis_app_control_record(struct stasis_app_control *control, struct stasis_app_recording_options *options)
Record media from a channel.
Media Format Cache API.
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:854
Unreal channel derivative framework.
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