Asterisk - The Open Source Telephony Project GIT-master-754dea3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
app_bridgewait.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2013, Digium, Inc.
5 *
6 * Mark Spencer <markster@digium.com>
7 *
8 * Author: Jonathan Rose <jrose@digium.com>
9 *
10 * See http://www.asterisk.org for more information about
11 * the Asterisk project. Please do not directly contact
12 * any of the maintainers of this project for assistance;
13 * the project provides a web site, mailing lists and IRC
14 * channels for your use.
15 *
16 * This program is free software, distributed under the terms of
17 * the GNU General Public License Version 2. See the LICENSE file
18 * at the top of the source tree.
19 */
20
21/*! \file
22 *
23 * \brief Application to place the channel into a holding Bridge
24 *
25 * \author Jonathan Rose <jrose@digium.com>
26 *
27 * \ingroup applications
28 */
29
30/*** MODULEINFO
31 <depend>bridge_holding</depend>
32 <support_level>core</support_level>
33 ***/
34
35#include "asterisk.h"
36
37#include "asterisk/file.h"
38#include "asterisk/channel.h"
39#include "asterisk/pbx.h"
40#include "asterisk/module.h"
41#include "asterisk/features.h"
42#include "asterisk/say.h"
43#include "asterisk/lock.h"
44#include "asterisk/utils.h"
45#include "asterisk/app.h"
46#include "asterisk/bridge.h"
48#include "asterisk/astobj2.h"
49#include "asterisk/causes.h"
50
51/*** DOCUMENTATION
52 <application name="BridgeWait" language="en_US">
53 <since>
54 <version>12.0.0</version>
55 </since>
56 <synopsis>
57 Put a call into the holding bridge.
58 </synopsis>
59 <syntax>
60 <parameter name="name">
61 <para>Name of the holding bridge to join. This is a handle for <literal>BridgeWait</literal>
62 only and does not affect the actual bridges that are created. If not provided,
63 the reserved name <literal>default</literal> will be used.
64 </para>
65 </parameter>
66 <parameter name="role" required="false">
67 <para>Defines the channel's purpose for entering the holding bridge. Values are case sensitive.
68 </para>
69 <enumlist>
70 <enum name="participant">
71 <para>The channel will enter the holding bridge to be placed on hold
72 until it is removed from the bridge for some reason. (default)</para>
73 </enum>
74 <enum name="announcer">
75 <para>The channel will enter the holding bridge to make announcements
76 to channels that are currently in the holding bridge. While an
77 announcer is present, holding for the participants will be
78 suspended.</para>
79 </enum>
80 </enumlist>
81 </parameter>
82 <parameter name="options">
83 <optionlist>
84 <option name="m">
85 <argument name="class" required="true" />
86 <para>The specified MOH class will be used/suggested for
87 music on hold operations. This option will only be useful for
88 entertainment modes that use it (m and h).</para>
89 </option>
90 <option name="e">
91 <para>Which entertainment mechanism should be used while on hold
92 in the holding bridge. Only the first letter is read.</para>
93 <enumlist>
94 <enum name="m"><para>Play music on hold (default)</para></enum>
95 <enum name="r"><para>Ring without pause</para></enum>
96 <enum name="s"><para>Generate silent audio</para></enum>
97 <enum name="h"><para>Put the channel on hold</para></enum>
98 <enum name="n"><para>No entertainment</para></enum>
99 </enumlist>
100 </option>
101 <option name="S">
102 <argument name="duration" required="true" />
103 <para>Automatically exit the bridge and return to the PBX after
104 <emphasis>duration</emphasis> seconds.</para>
105 </option>
106 <option name="n">
107 <para>Do not automatically answer the channel.</para>
108 </option>
109 </optionlist>
110 </parameter>
111 </syntax>
112 <description>
113 <para>This application places the incoming channel into a holding bridge.
114 The channel will then wait in the holding bridge until some event occurs
115 which removes it from the holding bridge.</para>
116 <note><para>This application will answer calls which haven't already
117 been answered, unless the n option is provided.</para></note>
118 </description>
119 </application>
120 ***/
121
122#define APP_NAME "BridgeWait"
123#define DEFAULT_BRIDGE_NAME "default"
124
126
128 struct ast_bridge *bridge; /*!< Bridge being wrapped by this wrapper */
129 char name[0]; /*!< Name of the holding bridge wrapper */
130};
131
132static void wait_bridge_wrapper_destructor(void *obj)
133{
134 struct wait_bridge_wrapper *wrapper = obj;
135
136 if (wrapper->bridge) {
137 ast_bridge_destroy(wrapper->bridge, 0);
138 }
139}
140
141static struct wait_bridge_wrapper *wait_bridge_wrapper_find_by_name(const char *bridge_name)
142{
143 return ao2_find(wait_bridge_wrappers, bridge_name, OBJ_KEY);
144}
145
146static int wait_bridge_hash_fn(const void *obj, const int flags)
147{
148 const struct wait_bridge_wrapper *entry;
149 const char *key;
150
151 switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
152 case OBJ_KEY:
153 key = obj;
154 return ast_str_hash(key);
155 case OBJ_POINTER:
156 entry = obj;
157 return ast_str_hash(entry->name);
158 default:
159 /* Hash can only work on something with a full key. */
160 ast_assert(0);
161 return 0;
162 }
163}
164
165static int wait_bridge_sort_fn(const void *obj_left, const void *obj_right, const int flags)
166{
167 const struct wait_bridge_wrapper *left = obj_left;
168 const struct wait_bridge_wrapper *right = obj_right;
169 const char *right_key = obj_right;
170 int cmp;
171
172 switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
173 case OBJ_POINTER:
174 right_key = right->name;
175 /* Fall through */
176 case OBJ_KEY:
177 cmp = strcmp(left->name, right_key);
178 break;
179 case OBJ_PARTIAL_KEY:
180 cmp = strncmp(left->name, right_key, strlen(right_key));
181 break;
182 default:
183 /* Sort can only work on something with a full or partial key. */
184 ast_assert(0);
185 cmp = 0;
186 break;
187 }
188 return cmp;
189}
190
194 MUXFLAG_TIMEOUT = (1 << 2),
196};
197
202 OPT_ARG_ARRAY_SIZE, /* Always the last element of the enum */
203};
204
210});
211
212static int bridgewait_timeout_callback(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
213{
214 ast_verb(3, "Channel %s timed out.\n", ast_channel_name(bridge_channel->chan));
217 return -1;
218}
219
220static int apply_option_timeout(struct ast_bridge_features *features, char *duration_arg)
221{
222 unsigned int duration;
223
224 if (ast_strlen_zero(duration_arg)) {
225 ast_log(LOG_ERROR, "Timeout option 'S': No value provided.\n");
226 return -1;
227 }
228 if (sscanf(duration_arg, "%u", &duration) != 1 || duration == 0) {
229 ast_log(LOG_ERROR, "Timeout option 'S': Invalid value provided '%s'.\n",
230 duration_arg);
231 return -1;
232 }
233
234 duration *= 1000;
235 if (ast_bridge_interval_hook(features, 0, duration, bridgewait_timeout_callback,
237 ast_log(LOG_ERROR, "Timeout option 'S': Could not create timer.\n");
238 return -1;
239 }
240
241 return 0;
242}
243
244static int apply_option_moh(struct ast_channel *chan, const char *class_arg)
245{
246 return ast_channel_set_bridge_role_option(chan, "holding_participant", "moh_class", class_arg);
247}
248
249static int apply_option_entertainment(struct ast_channel *chan, const char *entertainment_arg)
250{
251 char entertainment = entertainment_arg[0];
252
253 switch (entertainment) {
254 case 'm':
255 return ast_channel_set_bridge_role_option(chan, "holding_participant", "idle_mode", "musiconhold");
256 case 'r':
257 return ast_channel_set_bridge_role_option(chan, "holding_participant", "idle_mode", "ringing");
258 case 's':
259 return ast_channel_set_bridge_role_option(chan, "holding_participant", "idle_mode", "silence");
260 case 'h':
261 return ast_channel_set_bridge_role_option(chan, "holding_participant", "idle_mode", "hold");
262 case 'n':
263 return ast_channel_set_bridge_role_option(chan, "holding_participant", "idle_mode", "none");
264 default:
265 ast_log(LOG_ERROR, "Invalid argument for BridgeWait entertainment '%s'\n", entertainment_arg);
266 return -1;
267 }
268}
269
274};
275
276static int process_options(struct ast_channel *chan, struct ast_flags *flags, char **opts, struct ast_bridge_features *features, enum wait_bridge_roles role)
277{
278 if (ast_test_flag(flags, MUXFLAG_TIMEOUT)) {
279 if (apply_option_timeout(features, opts[OPT_ARG_TIMEOUT])) {
280 return -1;
281 }
282 }
283
284 switch (role) {
285 case ROLE_PARTICIPANT:
286 if (ast_channel_add_bridge_role(chan, "holding_participant")) {
287 return -1;
288 }
289
290 if (ast_test_flag(flags, MUXFLAG_MOHCLASS)) {
291 if (apply_option_moh(chan, opts[OPT_ARG_MOHCLASS])) {
292 return -1;
293 }
294 }
295
298 return -1;
299 }
300 }
301
302 break;
303 case ROLE_ANNOUNCER:
304 if (ast_channel_add_bridge_role(chan, "announcer")) {
305 return -1;
306 }
307 break;
308 case ROLE_INVALID:
309 ast_assert(0);
310 return -1;
311 }
312
313 return 0;
314}
315
316/*!
317 * \internal
318 * \since 12.0.0
319 * \brief Allocate a new holding bridge wrapper with the given bridge name and bridge ID.
320 *
321 * \param bridge_name name of the bridge wrapper
322 * \param bridge the bridge being wrapped
323 *
324 * \retval Pointer to the newly allocated holding bridge wrapper
325 * \retval NULL if allocation failed. The bridge will be destroyed if this function fails.
326 */
327static struct wait_bridge_wrapper *wait_bridge_wrapper_alloc(const char *bridge_name, struct ast_bridge *bridge)
328{
329 struct wait_bridge_wrapper *bridge_wrapper;
330
331 bridge_wrapper = ao2_alloc_options(sizeof(*bridge_wrapper) + strlen(bridge_name) + 1,
333 if (!bridge_wrapper) {
335 return NULL;
336 }
337
338 strcpy(bridge_wrapper->name, bridge_name);
339 bridge_wrapper->bridge = bridge;
340
341 if (!ao2_link(wait_bridge_wrappers, bridge_wrapper)) {
342 ao2_cleanup(bridge_wrapper);
343 return NULL;
344 }
345
346 return bridge_wrapper;
347}
348
349static struct wait_bridge_wrapper *get_wait_bridge_wrapper(const char *bridge_name)
350{
351 struct wait_bridge_wrapper * wrapper;
352 struct ast_bridge *bridge = NULL;
353
355
356 if ((wrapper = wait_bridge_wrapper_find_by_name(bridge_name))) {
357 return wrapper;
358 }
359
360 /*
361 * Holding bridges can allow local channel move/swap
362 * optimization to the bridge. However, we cannot allow it for
363 * this holding bridge because the call will lose the channel
364 * roles and dialplan location as a result.
365 */
370
371 if (!bridge) {
372 return NULL;
373 }
374
375 /* The bridge reference is unconditionally passed. */
376 return wait_bridge_wrapper_alloc(bridge_name, bridge);
377}
378
379/*!
380 * \internal
381 * \since 12.0.0
382 * \brief If we are down to the last reference of a wrapper and it's still contained within the list, remove it from the list.
383 *
384 * \param wrapper reference to wait bridge wrapper being checked for list culling - will be cleared on exit
385 */
386static void wait_wrapper_removal(struct wait_bridge_wrapper *wrapper)
387{
388 if (!wrapper) {
389 return;
390 }
391
393 if (ao2_ref(wrapper, 0) == 2) {
394 /* Either we have the only real reference or else wrapper isn't in the container anyway. */
396 }
398
399 ao2_cleanup(wrapper);
400}
401
402static enum wait_bridge_roles validate_role(const char *role)
403{
404 if (!strcmp(role, "participant")) {
405 return ROLE_PARTICIPANT;
406 } else if (!strcmp(role, "announcer")) {
407 return ROLE_ANNOUNCER;
408 } else {
409 return ROLE_INVALID;
410 }
411}
412
413/*!
414 * \internal
415 * \since 12.0.0
416 * \brief Application callback for the bridgewait application
417 *
418 * \param chan channel running the application
419 * \param data Arguments to the application
420 *
421 * \retval 0 Ran successfully and the call didn't hang up
422 * \retval -1 Failed or the call was hung up by the time the channel exited the holding bridge
423 */
424static int bridgewait_exec(struct ast_channel *chan, const char *data)
425{
426 char *bridge_name = DEFAULT_BRIDGE_NAME;
427 struct ast_bridge_features chan_features;
428 struct ast_flags flags = { 0 };
429 char *parse;
431 char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
432 struct wait_bridge_wrapper *bridge_wrapper;
433 int res;
434
437 AST_APP_ARG(role);
439 AST_APP_ARG(other); /* Any remaining unused arguments */
440 );
441
442 parse = ast_strdupa(data);
444
445 if (!ast_strlen_zero(args.name)) {
446 bridge_name = args.name;
447 }
448
449 if (!ast_strlen_zero(args.role)) {
450 role = validate_role(args.role);
451 if (role == ROLE_INVALID) {
452 ast_log(LOG_ERROR, "Requested waiting bridge role '%s' is invalid.\n", args.role);
453 return -1;
454 }
455 }
456
457 if (ast_bridge_features_init(&chan_features)) {
458 ast_bridge_features_cleanup(&chan_features);
459 ast_log(LOG_ERROR, "'%s' failed to enter the waiting bridge - could not set up channel features\n",
460 ast_channel_name(chan));
461 return -1;
462 }
463
464 if (args.options) {
465 ast_app_parse_options(bridgewait_opts, &flags, opts, args.options);
466 }
467
468 /* Answer the channel if needed */
470 ast_answer(chan);
471 }
472
473 if (process_options(chan, &flags, opts, &chan_features, role)) {
474 ast_bridge_features_cleanup(&chan_features);
475 return -1;
476 }
477
478 bridge_wrapper = get_wait_bridge_wrapper(bridge_name);
479 if (!bridge_wrapper) {
480 ast_log(LOG_WARNING, "Failed to find or create waiting bridge '%s' for '%s'.\n", bridge_name, ast_channel_name(chan));
481 ast_bridge_features_cleanup(&chan_features);
482 return -1;
483 }
484
485 ast_verb(3, "%s is entering waiting bridge %s:%s\n", ast_channel_name(chan), bridge_name, bridge_wrapper->bridge->uniqueid);
486 res = ast_bridge_join(bridge_wrapper->bridge, chan, NULL, &chan_features, NULL, 0);
487 wait_wrapper_removal(bridge_wrapper);
488 ast_bridge_features_cleanup(&chan_features);
489
490 if (res) {
491 /* For the lifetime of the bridge wrapper the bridge itself will be valid, if an error occurs it is because
492 * of extreme situations.
493 */
494 ast_log(LOG_WARNING, "Failed to join waiting bridge '%s' for '%s'.\n", bridge_name, ast_channel_name(chan));
495 }
496
497 return (res || ast_check_hangup_locked(chan)) ? -1 : 0;
498}
499
500static int unload_module(void)
501{
503
505}
506
507static int load_module(void)
508{
512
514 return -1;
515 }
516
518}
519
520AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Place the channel into a holding bridge application");
static enum wait_bridge_roles validate_role(const char *role)
static int apply_option_timeout(struct ast_bridge_features *features, char *duration_arg)
static int apply_option_moh(struct ast_channel *chan, const char *class_arg)
static int wait_bridge_hash_fn(const void *obj, const int flags)
static int apply_option_entertainment(struct ast_channel *chan, const char *entertainment_arg)
static int bridgewait_exec(struct ast_channel *chan, const char *data)
bridgewait_args
@ OPT_ARG_MOHCLASS
@ OPT_ARG_ENTERTAINMENT
@ OPT_ARG_TIMEOUT
@ OPT_ARG_ARRAY_SIZE
#define DEFAULT_BRIDGE_NAME
static int process_options(struct ast_channel *chan, struct ast_flags *flags, char **opts, struct ast_bridge_features *features, enum wait_bridge_roles role)
wait_bridge_roles
@ ROLE_ANNOUNCER
@ ROLE_INVALID
@ ROLE_PARTICIPANT
static const struct ast_app_option bridgewait_opts[128]
static struct wait_bridge_wrapper * wait_bridge_wrapper_find_by_name(const char *bridge_name)
static void wait_bridge_wrapper_destructor(void *obj)
bridgewait_flags
@ MUXFLAG_ENTERTAINMENT
@ MUXFLAG_NOANSWER
@ MUXFLAG_TIMEOUT
@ MUXFLAG_MOHCLASS
static int bridgewait_timeout_callback(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
static struct wait_bridge_wrapper * get_wait_bridge_wrapper(const char *bridge_name)
static struct ao2_container * wait_bridge_wrappers
static int load_module(void)
static int unload_module(void)
static int wait_bridge_sort_fn(const void *obj_left, const void *obj_right, const int flags)
static struct wait_bridge_wrapper * wait_bridge_wrapper_alloc(const char *bridge_name, struct ast_bridge *bridge)
#define APP_NAME
static void wait_wrapper_removal(struct wait_bridge_wrapper *wrapper)
ast_mutex_t lock
Definition: app_sla.c:337
Asterisk main include file. File version handling, generic pbx functions.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_log
Definition: astobj2.c:42
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
#define OBJ_KEY
Definition: astobj2.h:1151
#define OBJ_POINTER
Definition: astobj2.h:1150
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
#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
#define OBJ_PARTIAL_KEY
Definition: astobj2.h:1152
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:404
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1303
@ AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT
Reject objects with duplicate keys in container.
Definition: astobj2.h:1188
Bridging API.
struct ast_bridge * ast_bridge_base_new(uint32_t capabilities, unsigned int flags, const char *creator, const char *name, const char *id)
Create a new base class bridge.
Definition: bridge.c:999
int ast_bridge_join(struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap, struct ast_bridge_features *features, struct ast_bridge_tech_optimizations *tech_args, enum ast_bridge_join_flags flags)
Join a channel to a bridge (blocking)
Definition: bridge.c:1690
int ast_bridge_destroy(struct ast_bridge *bridge, int cause)
Destroy a bridge.
Definition: bridge.c:1009
@ AST_BRIDGE_CAPABILITY_HOLDING
Definition: bridge.h:90
@ BRIDGE_CHANNEL_STATE_END
void ast_bridge_channel_leave_bridge(struct ast_bridge_channel *bridge_channel, enum bridge_channel_state new_state, int cause)
Set bridge channel state to leave bridge (if not leaving already).
int ast_bridge_features_init(struct ast_bridge_features *features)
Initialize bridge features structure.
Definition: bridge.c:3689
int ast_bridge_interval_hook(struct ast_bridge_features *features, enum ast_bridge_hook_timer_option flags, unsigned int interval, ast_bridge_hook_callback callback, void *hook_pvt, ast_bridge_hook_pvt_destructor destructor, enum ast_bridge_hook_remove_flags remove_flags)
Attach an interval hook to a bridge features structure.
Definition: bridge.c:3388
@ AST_BRIDGE_HOOK_REMOVE_ON_PULL
@ AST_BRIDGE_FLAG_SWAP_INHIBIT_TO
@ AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM
@ AST_BRIDGE_FLAG_TRANSFER_PROHIBITED
@ AST_BRIDGE_FLAG_MERGE_INHIBIT_TO
@ AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM
void ast_bridge_features_cleanup(struct ast_bridge_features *features)
Clean up the contents of a bridge features structure.
Definition: bridge.c:3722
int ast_channel_set_bridge_role_option(struct ast_channel *channel, const char *role_name, const char *option, const char *value)
Set a role option on a channel.
Definition: bridge_roles.c:375
int ast_channel_add_bridge_role(struct ast_channel *chan, const char *role_name)
Adds a bridge role to a channel.
Definition: bridge_roles.c:313
Internal Asterisk hangup causes.
#define AST_CAUSE_NORMAL_CLEARING
Definition: causes.h:106
General Asterisk PBX channel definitions.
const char * ast_channel_name(const struct ast_channel *chan)
int ast_check_hangup_locked(struct ast_channel *chan)
Definition: channel.c:459
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2834
ast_channel_state
ast_channel states
Definition: channelstate.h:35
@ AST_STATE_UP
Definition: channelstate.h:42
Call Parking and Pickup API Includes code and algorithms from the Zapata library.
Generic File Format Support. Should be included by clients of the file handling routines....
static const char name[]
Definition: format_mp3.c:68
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#define AST_APP_ARG(name)
Define an application argument.
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
#define AST_APP_OPTION_ARG(option, flagno, argno)
Declares an application option that accepts an argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition: main/app.c:3066
#define LOG_ERROR
#define ast_verb(level,...)
#define LOG_WARNING
Asterisk locking-related definitions:
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
Definition: lock.h:608
Asterisk module definitions.
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:581
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:640
Music on hold handling.
Core PBX routines and definitions.
#define NULL
Definition: resample.c:96
Say numbers and dates (maybe words one day too)
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1259
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
Generic container type.
Structure that contains information regarding a channel in a bridge.
struct ast_channel * chan
Structure that contains features information.
Structure that contains information about a bridge.
Definition: bridge.h:353
const ast_string_field uniqueid
Definition: bridge.h:405
Main Channel structure associated with a channel.
Structure used to handle boolean flags.
Definition: utils.h:199
unsigned int flags
Definition: utils.h:200
struct ast_bridge * bridge
const char * args
static struct test_options options
Utility functions.
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define ast_assert(a)
Definition: utils.h:739