Asterisk - The Open Source Telephony Project GIT-master-754dea3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
app_broadcast.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2022, Naveen Albert
5 *
6 * See http://www.asterisk.org for more information about
7 * the Asterisk project. Please do not directly contact
8 * any of the maintainers of this project for assistance;
9 * the project provides a web site, mailing lists and IRC
10 * channels for your use.
11 *
12 * This program is free software, distributed under the terms of
13 * the GNU General Public License Version 2. See the LICENSE file
14 * at the top of the source tree.
15 */
16
17/*! \file
18 *
19 * \brief Channel audio broadcasting
20 *
21 * \author Naveen Albert <asterisk@phreaknet.org>
22 *
23 * \ingroup applications
24 */
25
26/*** MODULEINFO
27 <support_level>extended</support_level>
28 ***/
29
30#include "asterisk.h"
31
32#include <ctype.h>
33#include <errno.h>
34
35#include "asterisk/channel.h"
36#include "asterisk/audiohook.h"
37#include "asterisk/app.h"
38#include "asterisk/utils.h"
39#include "asterisk/pbx.h"
40#include "asterisk/module.h"
41#include "asterisk/lock.h"
42#include "asterisk/options.h"
43#include "asterisk/autochan.h"
45#include "asterisk/cli.h" /* use ESS macro */
46
47/*** DOCUMENTATION
48 <application name="Broadcast" language="en_US">
49 <since>
50 <version>18.17.0</version>
51 <version>20.2.0</version>
52 </since>
53 <synopsis>
54 Transmit or receive audio to or from multiple channels simultaneously
55 </synopsis>
56 <syntax>
57 <parameter name="options">
58 <optionlist>
59 <option name="b">
60 <para>In addition to broadcasting to target channels, also
61 broadcast to any channels to which target channels are bridged.</para>
62 </option>
63 <option name="l">
64 <para>Allow usage of a long queue to store audio frames.</para>
65 <note><para>This may introduce some delay in the received audio feed, but will improve the audio quality.</para></note>
66 </option>
67 <option name="o">
68 <para>Do not mix streams when combining audio from target channels (only applies with s option).</para>
69 </option>
70 <option name="r">
71 <para>Feed frames to barge channels in "reverse" by injecting them into the primary channel's read queue instead.</para>
72 <para>This option is required for barge to work in a n-party bridge (but not for 2-party bridges). Alternately, you
73 can add an intermediate channel by using a non-optimized Local channel, so that the target channel is bridged with
74 a single channel that is connected to the bridge, but it is recommended this option be used instead.</para>
75 <para>Note that this option will always feed injected audio to the other party, regardless of whether the target
76 channel is bridged or not.</para>
77 </option>
78 <option name="s">
79 <para>Rather than broadcast audio to a bunch of channels, receive the combined audio from the target channels.</para>
80 </option>
81 <option name="w">
82 <para>Broadcast audio received on this channel to other channels.</para>
83 </option>
84 </optionlist>
85 </parameter>
86 <parameter name="channels" required="true" argsep=",">
87 <para>List of channels for broadcast targets.</para>
88 <para>Channel names must be the full channel names, not merely device names.</para>
89 <para>Broadcasting will continue until the broadcasting channel hangs up or all target channels have hung up.</para>
90 </parameter>
91 </syntax>
92 <description>
93 <para>This application can be used to broadcast audio to multiple channels at once.
94 Any audio received on this channel will be transmitted to all of the specified channels and, optionally, their bridged peers.</para>
95 <para>It can also be used to aggregate audio from multiple channels at once.
96 Any audio on any of the specified channels, and optionally their bridged peers, will be transmitted to this channel.</para>
97 <para>Execution of the application continues until either the broadcasting channel hangs up
98 or all specified channels have hung up.</para>
99 <para>This application is used for one-to-many and many-to-one audio applications where
100 bridge mixing cannot be done synchronously on all the involved channels.
101 This is primarily useful for injecting the same audio stream into multiple channels at once,
102 or doing the reverse, combining the audio from multiple channels into a single stream.
103 This contrasts with using a separate injection channel for each target channel and/or
104 using a conference bridge.</para>
105 <para>The channel running the Broadcast application must do so synchronously. The specified channels,
106 however, may be doing other things.</para>
107 <example title="Broadcast received audio to three channels and their bridged peers">
108 same => n,Broadcast(wb,DAHDI/1,DAHDI/3,PJSIP/doorphone)
109 </example>
110 <example title="Broadcast received audio to three channels, only">
111 same => n,Broadcast(w,DAHDI/1,DAHDI/3,PJSIP/doorphone)
112 </example>
113 <example title="Combine audio from three channels and their bridged peers to us">
114 same => n,Broadcast(s,DAHDI/1,DAHDI/3,PJSIP/doorphone)
115 </example>
116 <example title="Combine audio from three channels to us">
117 same => n,Broadcast(so,DAHDI/1,DAHDI/3,PJSIP/doorphone)
118 </example>
119 <example title="Two-way audio with a bunch of channels">
120 same => n,Broadcast(wbso,DAHDI/1,DAHDI/3,PJSIP/doorphone)
121 </example>
122 <para>Note that in the last example above, this is NOT the same as a conference bridge.
123 The specified channels are not audible to each other, only to the channel running the
124 Broadcast application. The two-way audio is only between the broadcasting channel and
125 each of the specified channels, individually.</para>
126 </description>
127 <see-also>
128 <ref type="application">ChanSpy</ref>
129 </see-also>
130 </application>
131 ***/
132
133static const char app_broadcast[] = "Broadcast";
134
135enum {
136 OPTION_READONLY = (1 << 0), /* Don't mix the two channels */
137 OPTION_BARGE = (1 << 1), /* Barge mode (whisper to both channels) */
138 OPTION_LONG_QUEUE = (1 << 2), /* Allow usage of a long queue to store audio frames. */
139 OPTION_WHISPER = (1 << 3),
140 OPTION_SPY = (1 << 4),
142 OPTION_ANSWER_WARN = (1 << 6), /* Internal flag, not set by user */
143};
144
152});
153
155 char *name;
161 unsigned int connected:1;
162 unsigned int bridge_connected:1;
163 unsigned int spying:1;
164 AST_LIST_ENTRY(multi_autochan) entry; /*!< Next record */
165};
166
168
169struct multi_spy {
171 unsigned int readonly:1;
172};
173
174static void *spy_alloc(struct ast_channel *chan, void *data)
175{
176 return data; /* just store the data pointer in the channel structure */
177}
178
179static void spy_release(struct ast_channel *chan, void *data)
180{
181 return; /* nothing to do */
182}
183
184static int spy_generate(struct ast_channel *chan, void *data, int len, int samples)
185{
186 struct multi_spy *multispy = data;
187 struct multi_autochan_list *chanlist = multispy->chanlist;
188 struct multi_autochan *mac;
189 struct ast_frame *f;
190 short *data1, *data2;
191 int res, i;
192
193 /* All the frames we get are slin, so they will all have the same number of samples. */
194 static const int num_samples = 160;
195 short combine_buf[num_samples];
196 struct ast_frame wf = {
198 .offset = 0,
199 .subclass.format = ast_format_slin,
200 .datalen = num_samples * 2,
201 .samples = num_samples,
202 .src = __FUNCTION__,
203 };
204
205 memset(&combine_buf, 0, sizeof(combine_buf));
206 wf.data.ptr = combine_buf;
207
212 ast_audiohook_unlock(&mac->spy_audiohook); /* Channel is already gone more than likely, the broadcasting channel will clean this up. */
213 continue;
214 }
215
216 if (multispy->readonly) { /* Option 'o' was set, so don't mix channel audio */
218 } else {
220 }
222
223 if (!f) {
224 continue; /* No frame? No problem. */
225 }
226
227 /* Mix the samples. */
228 for (i = 0, data1 = combine_buf, data2 = f->data.ptr; i < num_samples; i++, data1++, data2++) {
229 ast_slinear_saturated_add(data1, data2);
230 }
231 ast_frfree(f);
232 }
235
236 res = ast_write(chan, &wf);
237 ast_frfree(&wf);
238
239 return res;
240}
241
242static struct ast_generator spygen = {
243 .alloc = spy_alloc,
244 .release = spy_release,
245 .generate = spy_generate,
246};
247
248static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook, struct ast_flags *flags)
249{
250 int res;
251
253 ast_debug(1, "Attaching spy channel %s to %s\n", spychan_name, ast_channel_name(autochan->chan));
254
255 if (ast_test_flag(flags, OPTION_READONLY)) {
258 } else {
260 }
261 if (ast_test_flag(flags, OPTION_LONG_QUEUE)) {
262 ast_debug(2, "Using a long queue to store audio frames in spy audiohook\n");
263 } else {
265 }
266 res = ast_audiohook_attach(autochan->chan, audiohook);
268 return res;
269}
270
271static int start_whispering(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook, struct ast_flags *flags)
272{
273 int res;
274
276 ast_verb(3, "Attaching spy channel %s to %s\n",
277 spychan_name, ast_channel_name(autochan->chan));
278
280 if (ast_test_flag(flags, OPTION_LONG_QUEUE)) {
281 ast_debug(9, "Using a long queue to store audio frames in whisper audiohook\n");
282 } else {
284 }
285 res = ast_audiohook_attach(autochan->chan, audiohook);
287 return res;
288}
289
290static int attach_barge(struct ast_autochan *spyee_autochan, struct ast_autochan **spyee_bridge_autochan,
291 struct ast_audiohook *bridge_whisper_audiohook, const char *spyer_name, const char *name, struct ast_flags *flags)
292{
293 int retval = 0;
294 struct ast_autochan *internal_bridge_autochan;
295 struct ast_channel *spyee_chan;
296 RAII_VAR(struct ast_channel *, bridged, NULL, ast_channel_cleanup);
297
298 ast_autochan_channel_lock(spyee_autochan);
299 spyee_chan = ast_channel_ref(spyee_autochan->chan);
300 ast_autochan_channel_unlock(spyee_autochan);
301
302 /* Note that ast_channel_bridge_peer only returns non-NULL for 2-party bridges, not n-party bridges (e.g. ConfBridge) */
303 bridged = ast_channel_bridge_peer(spyee_chan);
304 ast_channel_unref(spyee_chan);
305 if (!bridged) {
306 ast_debug(9, "Channel %s is not yet bridged, unable to setup barge\n", ast_channel_name(spyee_chan));
307 /* If we're bridged, but it's not a 2-party bridge, then we probably should have used OPTION_REVERSE_FEED. */
309 ast_clear_flag(flags, OPTION_ANSWER_WARN); /* Don't warn more than once. */
310 ast_log(LOG_WARNING, "Barge failed: channel is bridged, but not to a 2-party bridge. Use the 'r' option.\n");
311 }
312 return -1;
313 }
314
315 ast_audiohook_init(bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Broadcast", 0);
316 internal_bridge_autochan = ast_autochan_setup(bridged);
317 if (!internal_bridge_autochan) {
318 return -1;
319 }
320
321 if (start_whispering(internal_bridge_autochan, spyer_name, bridge_whisper_audiohook, flags)) {
322 ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee '%s'. Barge mode disabled.\n", name);
323 retval = -1;
324 }
325
326 *spyee_bridge_autochan = internal_bridge_autochan;
327 return retval;
328}
329
330static void multi_autochan_free(struct multi_autochan *mac)
331{
332 if (mac->connected) {
334 ast_debug(2, "Whisper audiohook no longer running\n");
335 }
340 }
341 if (mac->bridge_connected) {
343 ast_debug(2, "Whisper (bridged) audiohook no longer running\n");
344 }
349 }
350 if (mac->spying) {
352 ast_debug(2, "Spy audiohook no longer running\n");
353 }
358 }
359 if (mac->name) {
360 int total = mac->connected + mac->bridge_connected + mac->spying;
361 ast_debug(1, "Removing channel %s from target list (%d hook%s)\n", mac->name, total, ESS(total));
362 ast_free(mac->name);
363 }
364 if (mac->autochan) {
366 }
367 if (mac->bridge_autochan) {
369 }
370 ast_free(mac);
371}
372
373static int do_broadcast(struct ast_channel *chan, struct ast_flags *flags, const char *channels)
374{
375 int res = 0;
376 struct ast_frame *f;
377 struct ast_silence_generator *silgen = NULL;
378 struct multi_spy multispy;
380 struct multi_autochan *mac;
381 int numchans = 0;
382 int readonly = ast_test_flag(flags, OPTION_READONLY) ? 1 : 0;
383 char *next, *chansdup = ast_strdupa(channels);
384
387
388 ast_set_flag(flags, OPTION_ANSWER_WARN); /* Initialize answer warn to 1 */
389
390 /* Hey, look ma, no list lock needed! Sometimes, it's nice to not have to share... */
391
392 /* Build a list of targets */
393 while ((next = strsep(&chansdup, ","))) {
394 struct ast_channel *ochan;
395 if (ast_strlen_zero(next)) {
396 continue;
397 }
398 if (!strcmp(next, ast_channel_name(chan))) {
399 ast_log(LOG_WARNING, "Refusing to broadcast to ourself: %s\n", next);
400 continue;
401 }
402 ochan = ast_channel_get_by_name(next);
403 if (!ochan) {
404 ast_log(LOG_WARNING, "No such channel: %s\n", next);
405 continue;
406 }
407 /* Append to end of list. */
408 if (!(mac = ast_calloc(1, sizeof(*mac)))) {
409 ast_log(LOG_WARNING, "Multi autochan allocation failure\n");
410 continue;
411 }
412 mac->name = ast_strdup(next);
413 mac->autochan = ast_autochan_setup(ochan);
414 if (!mac->name || !mac->autochan) {
416 continue;
417 }
419 mac->connected = 1;
421 /* Inject audio from our channel to this target. */
422 if (start_whispering(mac->autochan, next, &mac->whisper_audiohook, flags)) {
423 ast_log(LOG_WARNING, "Unable to attach whisper audiohook to %s\n", next);
425 continue;
426 }
427 }
429 mac->spying = 1;
431 if (start_spying(mac->autochan, next, &mac->spy_audiohook, flags)) {
432 ast_log(LOG_WARNING, "Unable to attach spy audiohook to %s\n", next);
434 continue;
435 }
436 }
437 AST_RWLIST_INSERT_TAIL(&chanlist, mac, entry);
438 numchans++;
439 ochan = ast_channel_unref(ochan);
440 }
441
442 ast_verb(4, "Broadcasting to %d channel%s on %s\n", numchans, ESS(numchans), ast_channel_name(chan));
443 ast_debug(1, "Broadcasting: (TX->1) whisper=%d, (TX->2) barge=%d, (RX<-%d) spy=%d (%s)\n",
446 readonly ? 1 : 2,
448 readonly ? "single" : "both");
449
451 multispy.chanlist = &chanlist;
452 multispy.readonly = readonly;
453 ast_activate_generator(chan, &spygen, &multispy);
454 } else {
455 /* We're not expecting to read any audio, just broadcast audio to a bunch of other channels. */
457 }
458
459 while (numchans && ast_waitfor(chan, -1) > 0) {
460 int fres = 0;
461 f = ast_read(chan);
462 if (!f) {
463 ast_debug(1, "Channel %s must have hung up\n", ast_channel_name(chan));
464 res = -1;
465 break;
466 }
467 if (f->frametype != AST_FRAME_VOICE) { /* Ignore any non-voice frames */
468 ast_frfree(f);
469 continue;
470 }
471 /* Write the frame to all our targets. */
474 /* Note that if no media is received, execution is suspended, but assuming continuous or
475 * or frequent audio on the broadcasting channel, we'll quickly enough detect hung up targets.
476 * This isn't really an issue, just something that might be confusing at first, but this is
477 * due to the limitation with audiohooks of using the channel for timing. */
481 /* Even if we're spying only and not actually broadcasting audio, we need to detect channel hangup. */
483 ast_debug(2, "Looks like %s has hung up\n", mac->name);
485 numchans--;
486 ast_debug(2, "%d channel%s remaining in broadcast on %s\n", numchans, ESS(numchans), ast_channel_name(chan));
487 continue;
488 }
489
494 }
495
497 /* This hook lets us inject audio into the channel that the spyee is currently
498 * bridged with. If the spyee isn't bridged with anything yet, nothing will
499 * be attached and we'll need to continue attempting to attach the barge
500 * audio hook.
501 * The exception to this is if we are emulating barge by doing it "directly",
502 * that is injecting the frames onto this channel's read queue, rather than
503 * its bridged peer's write queue, then skip this. We only do one or the other. */
506 ast_debug(2, "Attached barge channel for %s\n", mac->name);
507 mac->bridge_connected = 1;
508 }
509
510 if (mac->bridge_connected) {
515 /* So, this is really clever...
516 * If we're connected to an n-party bridge instead of a 2-party bridge,
517 * attach_barge will ALWAYS fail because we're connected to a bridge, not
518 * a single peer channel.
519 * Recall that the objective is for injected audio to be audible to both
520 * sides of the channel. So really, the typical way of doing this by
521 * directly injecting frames separately onto both channels is kind of
522 * bizarre to begin with, when you think about it.
523 *
524 * In other words, this is how ChanSpy and this module by default work:
525 * We have audio F to inject onto channels A and B, which are <= bridged =>:
526 * READ <- A -> WRITE <==> READ <- B -> WRITE
527 * F --^ F --^
528 *
529 * So that makes the same audio audible to both channels A and B, but
530 * in kind of a roundabout way. What if the bridged peer changes at
531 * some point, for example?
532 *
533 * While that method works for 2-party bridges, it doesn't work at all
534 * for an n-party bridge, so we do the thing that seems obvious to begin with:
535 * dump the frames onto THIS channel's read queue, and the channels will
536 * make their way into the bridge like any other audio from this channel,
537 * and everything just works perfectly, no matter what kind of bridging
538 * scenario is being used. At that point, we don't even care if we're
539 * bridged or not, and really, why should we?
540 *
541 * In other words, we do this:
542 * READ <- A -> WRITE <==> READ <- B -> WRITE
543 * F --^ F --^
544 */
548 }
549 }
550 if (fres) {
551 ast_log(LOG_WARNING, "Failed to write to audiohook for %s\n", mac->name);
552 fres = 0;
553 }
554 }
557 ast_frfree(f);
558 }
559
560 if (!numchans) {
561 ast_debug(1, "Exiting due to all target channels having left the broadcast\n");
562 }
563
566 } else {
568 }
569
570 /* Cleanup any remaining targets */
574 }
576
578 return res;
579}
580
581static int broadcast_exec(struct ast_channel *chan, const char *data)
582{
583 struct ast_flags flags;
584 struct ast_format *write_format;
585 int res = -1;
588 AST_APP_ARG(channels); /* Channel list last, so we can have multiple */
589 );
590 char *parse = NULL;
591
592 if (ast_strlen_zero(data)) {
593 ast_log(LOG_WARNING, "Broadcast requires at least one channel\n");
594 return -1;
595 }
596
597 parse = ast_strdupa(data);
599
600 if (ast_strlen_zero(args.channels)) {
601 ast_log(LOG_WARNING, "Must specify at least one channel for broadcast\n");
602 return -1;
603 }
604 if (args.options) {
605 ast_app_parse_options(spy_opts, &flags, NULL, args.options);
606 } else {
608 }
609
610 if (!ast_test_flag(&flags, OPTION_BARGE) && !ast_test_flag(&flags, OPTION_SPY) && !ast_test_flag(&flags, OPTION_WHISPER)) {
611 ast_log(LOG_WARNING, "At least one of the b, s, or w option must be specified (provided options have no effect)\n");
612 return -1;
613 }
614
615 write_format = ao2_bump(ast_channel_writeformat(chan));
616 if (ast_set_write_format(chan, ast_format_slin) < 0) {
617 ast_log(LOG_ERROR, "Failed to set write format to slin.\n");
618 goto cleanup;
619 }
620
621 res = do_broadcast(chan, &flags, args.channels);
622
623 /* Restore previous write format */
624 if (ast_set_write_format(chan, write_format)) {
625 ast_log(LOG_ERROR, "Failed to restore write format for channel %s\n", ast_channel_name(chan));
626 }
627
628cleanup:
629 ao2_ref(write_format, -1);
630 return res;
631}
632
633static int unload_module(void)
634{
636}
637
638static int load_module(void)
639{
641}
642
static int do_broadcast(struct ast_channel *chan, struct ast_flags *flags, const char *channels)
static void * spy_alloc(struct ast_channel *chan, void *data)
AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Channel Audio Broadcasting")
static int broadcast_exec(struct ast_channel *chan, const char *data)
static const struct ast_app_option spy_opts[128]
static int start_whispering(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook, struct ast_flags *flags)
static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook, struct ast_flags *flags)
@ OPTION_ANSWER_WARN
@ OPTION_REVERSE_FEED
@ OPTION_WHISPER
@ OPTION_READONLY
@ OPTION_BARGE
@ OPTION_SPY
@ OPTION_LONG_QUEUE
static int load_module(void)
static int attach_barge(struct ast_autochan *spyee_autochan, struct ast_autochan **spyee_bridge_autochan, struct ast_audiohook *bridge_whisper_audiohook, const char *spyer_name, const char *name, struct ast_flags *flags)
static int unload_module(void)
static const char app_broadcast[]
static void spy_release(struct ast_channel *chan, void *data)
static void multi_autochan_free(struct multi_autochan *mac)
static int spy_generate(struct ast_channel *chan, void *data, int len, int samples)
static struct ast_generator spygen
char * strsep(char **str, const char *delims)
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_log
Definition: astobj2.c:42
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
Audiohooks Architecture.
int ast_audiohook_init(struct ast_audiohook *audiohook, enum ast_audiohook_type type, const char *source, enum ast_audiohook_init_flags flags)
Initialize an audiohook structure.
Definition: audiohook.c:100
struct ast_frame * ast_audiohook_read_frame(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, struct ast_format *format)
Reads a frame in from the audiohook structure.
Definition: audiohook.c:474
int ast_audiohook_write_frame(struct ast_audiohook *audiohook, enum ast_audiohook_direction direction, struct ast_frame *frame)
Writes a frame into the audiohook structure.
Definition: audiohook.c:167
@ AST_AUDIOHOOK_DIRECTION_READ
Definition: audiohook.h:49
@ AST_AUDIOHOOK_DIRECTION_WRITE
Definition: audiohook.h:50
@ AST_AUDIOHOOK_DIRECTION_BOTH
Definition: audiohook.h:51
#define ast_audiohook_lock(ah)
Lock an audiohook.
Definition: audiohook.h:313
@ AST_AUDIOHOOK_MUTE_WRITE
Definition: audiohook.h:65
@ AST_AUDIOHOOK_SMALL_QUEUE
Definition: audiohook.h:63
@ AST_AUDIOHOOK_TRIGGER_SYNC
Definition: audiohook.h:59
int ast_audiohook_detach(struct ast_audiohook *audiohook)
Detach audiohook from channel.
Definition: audiohook.c:578
int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
Attach audiohook to channel.
Definition: audiohook.c:512
int ast_audiohook_destroy(struct ast_audiohook *audiohook)
Destroys an audiohook structure.
Definition: audiohook.c:124
#define ast_audiohook_unlock(ah)
Unlock an audiohook.
Definition: audiohook.h:318
@ AST_AUDIOHOOK_TYPE_SPY
Definition: audiohook.h:36
@ AST_AUDIOHOOK_TYPE_WHISPER
Definition: audiohook.h:37
@ AST_AUDIOHOOK_STATUS_RUNNING
Definition: audiohook.h:43
int ast_audiohook_set_frame_feed_direction(struct ast_audiohook *audiohook, enum ast_audiohook_direction direction)
Sets direction on audiohook.
Definition: audiohook.c:150
"smart" channels that update automatically if a channel is masqueraded
struct ast_autochan * ast_autochan_setup(struct ast_channel *chan)
set up a new ast_autochan structure
Definition: autochan.c:38
void ast_autochan_destroy(struct ast_autochan *autochan)
destroy an ast_autochan structure
Definition: autochan.c:64
#define ast_autochan_channel_lock(autochan)
Lock the autochan's channel lock.
Definition: autochan.h:75
#define ast_autochan_channel_unlock(autochan)
Definition: autochan.h:84
General Asterisk PBX channel definitions.
const char * ast_channel_name(const struct ast_channel *chan)
int ast_activate_generator(struct ast_channel *chan, struct ast_generator *gen, void *params)
Definition: channel.c:2979
void ast_channel_clear_flag(struct ast_channel *chan, unsigned int flag)
Clear a flag on a channel.
Definition: channel.c:11060
struct ast_channel * ast_channel_bridge_peer(struct ast_channel *chan)
Get the channel's bridge peer only if the bridge is two-party.
Definition: channel.c:10590
struct ast_silence_generator * ast_channel_start_silence_generator(struct ast_channel *chan)
Starts a silence generator on the given channel.
Definition: channel.c:8190
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3190
void ast_channel_stop_silence_generator(struct ast_channel *chan, struct ast_silence_generator *state)
Stops a previously-started silence generator on the given channel.
Definition: channel.c:8236
#define ast_channel_ref(c)
Increase channel reference count.
Definition: channel.h:2995
void ast_deactivate_generator(struct ast_channel *chan)
Definition: channel.c:2921
int ast_write(struct ast_channel *chan, struct ast_frame *frame)
Write a frame to a channel This function writes the given frame to the indicated channel.
Definition: channel.c:5161
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4274
int ast_channel_is_bridged(const struct ast_channel *chan)
Determine if a channel is in a bridge.
Definition: channel.c:10571
void ast_channel_set_flag(struct ast_channel *chan, unsigned int flag)
Set a flag on a channel.
Definition: channel.c:11053
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:3006
struct ast_format * ast_channel_writeformat(struct ast_channel *chan)
@ AST_FLAG_SPYING
Definition: channel.h:1013
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Definition: channel.c:5820
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition: channel.h:3017
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1481
Standard Command Line Interface.
#define ESS(x)
Definition: cli.h:59
static struct channel_usage channels
Media Format Cache API.
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
static const char name[]
Definition: format_mp3.c:68
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
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_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 ast_frfree(fr)
@ AST_FRAME_VOICE
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define ast_verb(level,...)
#define LOG_WARNING
#define AST_RWLIST_REMOVE_CURRENT
Definition: linkedlists.h:570
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
Definition: linkedlists.h:545
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:52
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:151
#define AST_RWLIST_HEAD_INIT(head)
Initializes an rwlist head structure.
Definition: linkedlists.h:639
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:410
#define AST_RWLIST_TRAVERSE_SAFE_END
Definition: linkedlists.h:617
#define AST_RWLIST_HEAD(name, type)
Defines a structure to be used to hold a read/write list of specified type.
Definition: linkedlists.h:199
#define AST_RWLIST_INSERT_TAIL
Definition: linkedlists.h:741
Asterisk locking-related definitions:
Asterisk module definitions.
#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
Options provided by main asterisk program.
Core PBX routines and definitions.
static void * cleanup(void *unused)
Definition: pbx_realtime.c:124
static int total
Definition: res_adsi.c:970
#define NULL
Definition: resample.c:96
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
enum ast_audiohook_status status
Definition: audiohook.h:108
struct ast_channel * chan
Definition: autochan.h:33
Main Channel structure associated with a channel.
const char * data
struct ast_flags flags
Structure used to handle boolean flags.
Definition: utils.h:199
unsigned int flags
Definition: utils.h:200
Definition of a media format.
Definition: format.c:43
Data structure associated with a single frame of data.
union ast_frame::@228 data
enum ast_frame_type frametype
void *(* alloc)(struct ast_channel *chan, void *params)
Definition: channel.h:228
List of channel drivers.
Definition: app_dial.c:803
struct multi_autochan * next
struct ast_audiohook bridge_whisper_audiohook
unsigned int spying
struct ast_audiohook whisper_audiohook
struct ast_autochan * autochan
struct multi_autochan::@9 entry
unsigned int connected
struct ast_audiohook spy_audiohook
unsigned int bridge_connected
struct ast_autochan * bridge_autochan
struct multi_autochan_list * chanlist
unsigned int readonly
const char * args
static struct test_options options
Utility functions.
#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:941
#define ast_clear_flag(p, flag)
Definition: utils.h:77
static force_inline void ast_slinear_saturated_add(short *input, short *value)
Definition: utils.h:450
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define AST_FLAGS_ALL
Definition: utils.h:196