Asterisk - The Open Source Telephony Project  GIT-master-a24979a
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"
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,
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;
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);
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) {
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 
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 {
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,
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);
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  if (!(play_channel = prepare_bridge_media_channel("Announcer"))) {
430  response, 500, "Internal Error", "Could not create playback channel");
431  return;
432  }
433  ast_debug(1, "Created announcer channel '%s'\n", ast_channel_name(play_channel));
434 
435  bridge_topic = ast_bridge_topic(bridge);
436  channel_topic = ast_channel_topic(play_channel);
437 
438  /* Forward messages from the playback channel topic to the bridge topic so that anything listening for
439  * messages on the bridge topic will receive the playback start/stop messages. Other messages that would
440  * go to this channel will be suppressed since the channel is marked as internal.
441  */
442  if (!bridge_topic || !channel_topic || !(channel_forward = stasis_forward_all(channel_topic, bridge_topic))) {
444  response, 500, "Internal Error", "Could not forward playback channel stasis messages to bridge topic");
445  return;
446  }
447 
448  if (ast_unreal_channel_push_to_bridge(play_channel, bridge,
451  response, 500, "Internal Error", "Failed to put playback channel into the bridge");
452  return;
453  }
454 
455  control = stasis_app_control_create(play_channel);
456  if (control == NULL) {
458  return;
459  }
460 
461  ao2_lock(control);
462  if (ari_bridges_play_helper(args_media, args_media_count, args_lang,
463  args_offset_ms, args_skipms, args_playback_id, response, bridge,
464  control, &json, &playback_url)) {
466  return;
467  }
469 
470  if (stasis_app_bridge_playback_channel_add(bridge, play_channel, control)) {
472  return;
473  }
474 
475  /* Give play_channel and control reference to the thread data */
476  thread_data = ast_malloc(sizeof(*thread_data) + strlen(bridge->uniqueid) + 1);
477  if (!thread_data) {
480  return;
481  }
482 
483  thread_data->bridge_channel = play_channel;
484  thread_data->control = control;
485  thread_data->forward = channel_forward;
486  /* Safe */
487  strcpy(thread_data->bridge_id, bridge->uniqueid);
488 
489  if (ast_pthread_create_detached(&threadid, NULL, bridge_channel_control_thread, thread_data)) {
492  ast_free(thread_data);
493  return;
494  }
495 
496  /* These are owned by the other thread now, so we don't want RAII_VAR disposing of them. */
497  play_channel = NULL;
498  control = NULL;
499  channel_forward = NULL;
500 
501  ast_ari_response_created(response, playback_url, ast_json_ref(json));
502 }
503 
508 };
509 
510 /*!
511  * \brief Performs common setup for a bridge playback operation
512  * with both new controls and when existing controls are found.
513  *
514  * \param args_media medias to play
515  * \param args_media_count number of media items in \c media
516  * \param args_lang language string split from arguments
517  * \param args_offset_ms milliseconds offset split from arguments
518  * \param args_skipms
519  * \param args_playback_id string to use for playback split from
520  * arguments (null valid)
521  * \param response ARI response being built
522  * \param bridge Bridge the playback is being performed on
523  * \param found_channel The channel that was found controlling playback
524  *
525  * \retval PLAY_FOUND_SUCCESS The operation was successful
526  * \retval PLAY_FOUND_FAILURE The operation failed (terminal failure)
527  * \retval PLAY_FOUND_CHANNEL_UNAVAILABLE The operation failed because
528  * the channel requested to playback with is breaking down.
529  */
530 static enum play_found_result ari_bridges_play_found(const char **args_media,
531  size_t args_media_count,
532  const char *args_lang,
533  int args_offset_ms,
534  int args_skipms,
535  const char *args_playback_id,
536  struct ast_ari_response *response,
537  struct ast_bridge *bridge,
538  struct ast_channel *found_channel)
539 {
540  RAII_VAR(struct ast_channel *, play_channel, found_channel, ao2_cleanup);
542  RAII_VAR(char *, playback_url, NULL, ast_free);
543  RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
544 
546  if (!control) {
548  }
549 
550  ao2_lock(control);
552  /* We failed to queue the action. Bailout and return that we aren't terminal. */
555  }
556 
557  if (ari_bridges_play_helper(args_media, args_media_count,
558  args_lang, args_offset_ms, args_skipms, args_playback_id,
559  response, bridge, control, &json, &playback_url)) {
561  return PLAY_FOUND_FAILURE;
562  }
564 
565  ast_ari_response_created(response, playback_url, ast_json_ref(json));
566  return PLAY_FOUND_SUCCESS;
567 }
568 
570  const char *args_bridge_id,
571  const char **args_media,
572  size_t args_media_count,
573  const char *args_lang,
574  int args_offset_ms,
575  int args_skipms,
576  const char *args_playback_id,
577  struct ast_ari_response *response)
578 {
579  RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args_bridge_id), ao2_cleanup);
580  struct ast_channel *play_channel;
581 
582  ast_assert(response != NULL);
583 
584  if (!bridge) {
585  return;
586  }
587 
588  while ((play_channel = stasis_app_bridge_playback_channel_find(bridge))) {
589  /* If ari_bridges_play_found fails because the channel is unavailable for
590  * playback, The channel will be removed from the playback list soon. We
591  * can keep trying to get channels from the list until we either get one
592  * that will work or else there isn't a channel for this bridge anymore,
593  * in which case we'll revert to ari_bridges_play_new.
594  */
595  if (ari_bridges_play_found(args_media, args_media_count, args_lang,
596  args_offset_ms, args_skipms, args_playback_id, response,bridge,
597  play_channel) == PLAY_FOUND_CHANNEL_UNAVAILABLE) {
598  continue;
599  }
600  return;
601  }
602 
603  ari_bridges_play_new(args_media, args_media_count, args_lang, args_offset_ms,
604  args_skipms, args_playback_id, response, bridge);
605 }
606 
607 
608 void ast_ari_bridges_play(struct ast_variable *headers,
610  struct ast_ari_response *response)
611 {
612  ari_bridges_handle_play(args->bridge_id,
613  args->media,
614  args->media_count,
615  args->lang,
616  args->offsetms,
617  args->skipms,
618  args->playback_id,
619  response);
620 }
621 
624  struct ast_ari_response *response)
625 {
626  ari_bridges_handle_play(args->bridge_id,
627  args->media,
628  args->media_count,
629  args->lang,
630  args->offsetms,
631  args->skipms,
632  args->playback_id,
633  response);
634 }
635 
638  struct ast_ari_response *response)
639 {
640  RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
641  RAII_VAR(struct ast_channel *, record_channel, NULL, ast_hangup);
642  RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
643  RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup);
644  RAII_VAR(char *, recording_url, NULL, ast_free);
645  RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
647  RAII_VAR(char *, uri_encoded_name, NULL, ast_free);
649 
650  struct stasis_topic *channel_topic;
651  struct stasis_topic *bridge_topic;
652  size_t uri_name_maxlen;
653  struct bridge_channel_control_thread_data *thread_data;
654  pthread_t threadid;
655 
656  ast_assert(response != NULL);
657 
658  if (bridge == NULL) {
659  return;
660  }
661 
662  if (!(record_channel = prepare_bridge_media_channel("Recorder"))) {
664  response, 500, "Internal Server Error", "Failed to create recording channel");
665  return;
666  }
667 
668  bridge_topic = ast_bridge_topic(bridge);
669  channel_topic = ast_channel_topic(record_channel);
670 
671  /* Forward messages from the recording channel topic to the bridge topic so that anything listening for
672  * messages on the bridge topic will receive the recording start/stop messages. Other messages that would
673  * go to this channel will be suppressed since the channel is marked as internal.
674  */
675  if (!bridge_topic || !channel_topic || !(channel_forward = stasis_forward_all(channel_topic, bridge_topic))) {
677  response, 500, "Internal Error", "Could not forward record channel stasis messages to bridge topic");
678  return;
679  }
680 
681  if (ast_unreal_channel_push_to_bridge(record_channel, bridge,
684  response, 500, "Internal Error", "Failed to put recording channel into the bridge");
685  return;
686  }
687 
688  control = stasis_app_control_create(record_channel);
689  if (control == NULL) {
691  return;
692  }
693 
695  if (options == NULL) {
697  return;
698  }
699 
700  ast_string_field_build(options, target, "bridge:%s", args->bridge_id);
701  options->max_silence_seconds = args->max_silence_seconds;
702  options->max_duration_seconds = args->max_duration_seconds;
703  options->terminate_on =
705  options->if_exists =
707  options->beep = args->beep;
708 
709  if (options->terminate_on == STASIS_APP_RECORDING_TERMINATE_INVALID) {
711  response, 400, "Bad Request",
712  "terminateOn invalid");
713  return;
714  }
715 
716  if (options->if_exists == AST_RECORD_IF_EXISTS_ERROR) {
718  response, 400, "Bad Request",
719  "ifExists invalid");
720  return;
721  }
722 
723  if (!ast_get_format_for_file_ext(options->format)) {
725  response, 422, "Unprocessable Entity",
726  "specified format is unknown on this system");
727  return;
728  }
729 
731  if (recording == NULL) {
732  switch(errno) {
733  case EINVAL:
734  /* While the arguments are invalid, we should have
735  * caught them prior to calling record.
736  */
738  response, 500, "Internal Server Error",
739  "Error parsing request");
740  break;
741  case EEXIST:
742  ast_ari_response_error(response, 409, "Conflict",
743  "Recording '%s' already exists and can not be overwritten",
744  args->name);
745  break;
746  case ENOMEM:
748  break;
749  case EPERM:
751  response, 400, "Bad Request",
752  "Recording name invalid");
753  break;
754  default:
756  "Unrecognized recording error: %s\n",
757  strerror(errno));
759  response, 500, "Internal Server Error",
760  "Internal Server Error");
761  break;
762  }
763  return;
764  }
765 
766  uri_name_maxlen = strlen(args->name) * 3;
767  uri_encoded_name = ast_malloc(uri_name_maxlen);
768  if (!uri_encoded_name) {
770  return;
771  }
772  ast_uri_encode(args->name, uri_encoded_name, uri_name_maxlen, ast_uri_http);
773 
774  if (ast_asprintf(&recording_url, "/recordings/live/%s",
775  uri_encoded_name) == -1) {
776  recording_url = NULL;
778  return;
779  }
780 
781  json = stasis_app_recording_to_json(recording);
782  if (!json) {
784  return;
785  }
786 
787  thread_data = ast_calloc(1, sizeof(*thread_data));
788  if (!thread_data) {
790  return;
791  }
792 
793  thread_data->bridge_channel = record_channel;
794  thread_data->control = control;
795  thread_data->forward = channel_forward;
796 
797  if (ast_pthread_create_detached(&threadid, NULL, bridge_channel_control_thread, thread_data)) {
799  ast_free(thread_data);
800  return;
801  }
802 
803  /* These are owned by the other thread now, so we don't want RAII_VAR disposing of them. */
804  record_channel = NULL;
805  control = NULL;
806  channel_forward = NULL;
807 
808  ast_ari_response_created(response, recording_url, ast_json_ref(json));
809 }
810 
813  struct ast_ari_response *response)
814 {
815  RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
816  struct ast_channel *moh_channel;
817  const char *moh_class = args->moh_class;
818 
819  if (!bridge) {
820  /* The response is provided by find_bridge() */
821  return;
822  }
823 
824  moh_channel = stasis_app_bridge_moh_channel(bridge);
825  if (!moh_channel) {
827  return;
828  }
829 
830  ast_moh_start(moh_channel, moh_class, NULL);
831  ast_channel_cleanup(moh_channel);
832 
833  ast_ari_response_no_content(response);
834 
835 }
836 
839  struct ast_ari_response *response)
840 {
841  RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
842 
843  if (!bridge) {
844  /* the response is provided by find_bridge() */
845  return;
846  }
847 
850  response, 409, "Conflict",
851  "Bridge isn't playing music");
852  return;
853  }
854 
855  ast_ari_response_no_content(response);
856 }
857 
858 void ast_ari_bridges_get(struct ast_variable *headers,
860  struct ast_ari_response *response)
861 {
863  if (!snapshot) {
865  response, 404, "Not Found",
866  "Bridge not found");
867  return;
868  }
869 
870  ast_ari_response_ok(response,
872 }
873 
876  struct ast_ari_response *response)
877 {
878  RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
879  if (!bridge) {
880  return;
881  }
882 
883  stasis_app_bridge_destroy(args->bridge_id);
884  ast_ari_response_no_content(response);
885 }
886 
887 void ast_ari_bridges_list(struct ast_variable *headers,
889  struct ast_ari_response *response)
890 {
892  RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
893  struct ao2_iterator i;
894  struct ast_bridge *bridge;
895 
896  bridges = ast_bridges();
897  if (!bridges) {
899  return;
900  }
901 
902  json = ast_json_array_create();
903  if (!json) {
905  return;
906  }
907 
908  i = ao2_iterator_init(bridges, 0);
909  while ((bridge = ao2_iterator_next(&i))) {
910  struct ast_bridge_snapshot *snapshot;
911  struct ast_json *json_bridge = NULL;
912 
913  /* Invisible bridges don't get shown externally and have no snapshot */
915  ao2_ref(bridge, -1);
916  continue;
917  }
918 
919  snapshot = ast_bridge_get_snapshot(bridge);
920  if (snapshot) {
921  json_bridge = ast_bridge_snapshot_to_json(snapshot, stasis_app_get_sanitizer());
922  ao2_ref(snapshot, -1);
923  }
924 
925  ao2_ref(bridge, -1);
926 
927  if (!json_bridge || ast_json_array_append(json, json_bridge)) {
930  return;
931  }
932  }
934 
935  ast_ari_response_ok(response, ast_json_ref(json));
936 }
937 
940  struct ast_ari_response *response)
941 {
942  RAII_VAR(struct ast_bridge *, bridge, stasis_app_bridge_create(args->type, args->name, args->bridge_id), ao2_cleanup);
943  RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
944 
945  if (!bridge) {
947  response, 500, "Internal Error",
948  "Unable to create bridge");
949  return;
950  }
951 
952  ast_bridge_lock(bridge);
953  snapshot = ast_bridge_snapshot_create(bridge);
954  ast_bridge_unlock(bridge);
955 
956  if (!snapshot) {
958  response, 500, "Internal Error",
959  "Unable to create snapshot for new bridge");
960  return;
961  }
962 
963  ast_ari_response_ok(response,
965 }
966 
969  struct ast_ari_response *response)
970 {
971  RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
972  RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
973 
974  if (bridge) {
975  /* update */
976  if (!ast_strlen_zero(args->name)
977  && strcmp(args->name, bridge->name)) {
979  response, 500, "Internal Error",
980  "Changing bridge name is not implemented");
981  return;
982  }
983  if (!ast_strlen_zero(args->type)) {
985  response, 500, "Internal Error",
986  "Supplying a bridge type when updating a bridge is not allowed.");
987  return;
988  }
989  ast_ari_response_ok(response,
991  return;
992  }
993 
994  bridge = stasis_app_bridge_create(args->type, args->name, args->bridge_id);
995  if (!bridge) {
997  response, 500, "Internal Error",
998  "Unable to create bridge");
999  return;
1000  }
1001 
1002  ast_bridge_lock(bridge);
1003  snapshot = ast_bridge_snapshot_create(bridge);
1004  ast_bridge_unlock(bridge);
1005 
1006  if (!snapshot) {
1008  response, 500, "Internal Error",
1009  "Unable to create snapshot for new bridge");
1010  return;
1011  }
1012 
1013  ast_ari_response_ok(response,
1015 }
1016 
1018  struct ast_channel *chan, void *data)
1019 {
1020  struct ast_bridge *bridge = data;
1021 
1022  ast_bridge_lock(bridge);
1024  ast_bridge_unlock(bridge);
1025 
1026  return 0;
1027 }
1028 
1031 {
1032  struct ast_bridge *bridge;
1033  struct stasis_app_control *control;
1034 
1035  bridge = find_bridge(response, args->bridge_id);
1036  if (!bridge) {
1037  return;
1038  }
1039 
1040  control = find_channel_control(response, args->channel_id);
1041  if (!control) {
1042  ao2_ref(bridge, -1);
1043  return;
1044  }
1045 
1046  if (stasis_app_get_bridge(control) != bridge) {
1047  ast_ari_response_error(response, 422,
1048  "Unprocessable Entity",
1049  "Channel not in this bridge");
1050  ao2_ref(bridge, -1);
1051  ao2_ref(control, -1);
1052  return;
1053  }
1054 
1057 
1058  ao2_ref(bridge, -1);
1059  ao2_ref(control, -1);
1060 
1061  ast_ari_response_no_content(response);
1062 }
1063 
1066 {
1067  struct ast_bridge *bridge;
1068 
1069  bridge = find_bridge(response, args->bridge_id);
1070  if (!bridge) {
1071  return;
1072  }
1073 
1074  ast_bridge_lock(bridge);
1076  ast_bridge_unlock(bridge);
1077 
1078  ao2_ref(bridge, -1);
1079  ast_ari_response_no_content(response);
1080 }
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
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
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
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_response_no_content(struct ast_ari_response *response)
Fill in a No Content (204) ast_ari_response.
Definition: res_ari.c:284
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:123
Bridging API.
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
#define ast_bridge_unlock(bridge)
Unlock the bridge.
Definition: bridge.h:481
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
#define ast_bridge_lock(bridge)
Lock the bridge.
Definition: bridge.h:470
struct ao2_container * ast_bridges(void)
Returns the global bridges container.
Definition: bridge.c:174
@ 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_alsa.c:121
static const char type[]
Definition: chan_ooh323.c:109
General Asterisk PBX channel definitions.
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2542
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:6432
ast_callid ast_channel_callid(const struct ast_channel *chan)
const char * ast_channel_name(const struct ast_channel *chan)
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition: channel.h:2969
struct stasis_topic * ast_channel_topic(struct ast_channel *chan)
A topic which publishes the events for a particular channel.
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.
Definition: core_unreal.c:928
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:1979
Media Format Cache API.
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
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
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,...
@ AST_RECORD_IF_EXISTS_ERROR
#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:2070
unsigned int ast_callid
#define LOG_DEBUG
#define LOG_WARNING
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Definition: json.c:67
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:368
struct ast_json * ast_json_array_create(void)
Create a empty JSON array.
Definition: json.c:352
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:7849
#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.
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_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 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.
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.
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 int check_add_remove_channel(struct ast_ari_response *response, struct stasis_app_control *control, enum stasis_app_control_channel_result result)
static struct control_list * control_list_create(struct ast_ari_response *response, size_t count, const char **channels)
static void ari_bridges_play_new(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)
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...
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.
static void * bridge_channel_control_thread(void *data)
static struct ast_channel * prepare_bridge_media_channel(const char *type)
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_record(struct ast_variable *headers, struct ast_ari_bridges_record_args *args, struct ast_ari_response *response)
Start a recording.
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.
static void ari_bridges_handle_play(const char *args_bridge_id, 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)
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_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:1580
struct stasis_forward * stasis_forward_cancel(struct stasis_forward *forward)
Definition: stasis.c:1550
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:1470
struct ast_bridge * stasis_app_get_bridge(struct stasis_app_control *control)
Gets the bridge currently associated with a control object.
Definition: control.c:931
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_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_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:860
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:1383
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:338
void stasis_app_bridge_destroy(const char *bridge_id)
Destroy the bridge.
Definition: res_stasis.c:861
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
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:1464
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:1250
struct stasis_message_sanitizer * stasis_app_get_sanitizer(void)
Get the Stasis message sanitizer for app_stasis applications.
Definition: res_stasis.c:2264
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:1430
void stasis_app_control_flush_queue(struct stasis_app_control *control)
Flush the control command queue.
Definition: res_stasis.c:1278
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:316
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:2288
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:1476
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
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:1420
int stasis_app_control_bridge_features_init(struct stasis_app_control *control)
Initialize bridge features into a channel control.
Definition: control.c:1451
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:851
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
int stasis_app_control_is_done(struct stasis_app_control *control)
Check if a control is marked as done.
Definition: res_stasis.c:1273
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_bridge * stasis_app_bridge_find_by_id(const char *bridge_id)
Returns the bridge with the given id.
Definition: res_stasis.c:774
stasis_app_control_channel_result
Result codes used when adding/removing channels to/from bridges.
Definition: stasis_app.h:776
@ STASIS_APP_CHANNEL_RECORDING
Definition: stasis_app.h:780
@ STASIS_APP_CHANNEL_OKAY
Definition: stasis_app.h:778
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:649
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:898
Stasis Application Playback API. See StasisApplication API" for detailed documentation.
@ STASIS_PLAYBACK_TARGET_BRIDGE
const char * stasis_app_playback_get_id(struct stasis_app_playback *playback)
Gets the unique id of a playback object.
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.
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.
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
struct ast_json * stasis_app_recording_to_json(const struct stasis_app_recording *recording)
Construct a JSON model of a recording.
char stasis_app_recording_termination_parse(const char *str)
Parse a string into the recording termination enum.
struct stasis_app_recording * stasis_app_control_record(struct stasis_app_control *control, struct stasis_app_recording_options *options)
Record media from a channel.
struct ast_bridge_snapshot * ast_bridge_get_snapshot(struct ast_bridge *bridge)
Returns the current snapshot for the bridge.
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 stasis_topic * ast_bridge_topic(struct ast_bridge *bridge)
A topic which publishes the events for a particular 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 ast_bridge_snapshot * ast_bridge_get_snapshot_by_uniqueid(const char *bridge_id)
Returns the current snapshot for the bridge.
#define ast_string_field_build(x, field, fmt, args...)
Set a field to a complex (built) value.
Definition: stringfields.h:555
#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 a snapshot of information about a bridge.
Definition: bridge.h:314
Structure that contains information about a bridge.
Definition: bridge.h:349
const ast_string_field uniqueid
Definition: bridge.h:401
const ast_string_field name
Definition: bridge.h:401
struct ast_flags feature_flags
Definition: bridge.h:369
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
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:64
Forwarding information.
Definition: stasis.c:1533
const char * args
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:936
#define ast_assert(a)
Definition: utils.h:734
char * ast_uri_encode(const char *string, char *outbuf, int buflen, struct ast_flags spec)
Turn text string to URI-encoded XX version.
Definition: main/utils.c:723
const struct ast_flags ast_uri_http
Definition: main/utils.c:719
#define ast_pthread_create_detached(a, b, c, d)
Definition: utils.h:583