Asterisk - The Open Source Telephony Project GIT-master-3dee037
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 <synopsis>
50 Transmit or receive audio to or from multiple channels simultaneously
51 </synopsis>
52 <syntax>
53 <parameter name="options">
54 <optionlist>
55 <option name="b">
56 <para>In addition to broadcasting to target channels, also
57 broadcast to any channels to which target channels are bridged.</para>
58 </option>
59 <option name="l">
60 <para>Allow usage of a long queue to store audio frames.</para>
61 <note><para>This may introduce some delay in the received audio feed, but will improve the audio quality.</para></note>
62 </option>
63 <option name="o">
64 <para>Do not mix streams when combining audio from target channels (only applies with s option).</para>
65 </option>
66 <option name="r">
67 <para>Feed frames to barge channels in "reverse" by injecting them into the primary channel's read queue instead.</para>
68 <para>This option is required for barge to work in a n-party bridge (but not for 2-party bridges). Alternately, you
69 can add an intermediate channel by using a non-optimized Local channel, so that the target channel is bridged with
70 a single channel that is connected to the bridge, but it is recommended this option be used instead.</para>
71 <para>Note that this option will always feed injected audio to the other party, regardless of whether the target
72 channel is bridged or not.</para>
73 </option>
74 <option name="s">
75 <para>Rather than broadcast audio to a bunch of channels, receive the combined audio from the target channels.</para>
76 </option>
77 <option name="w">
78 <para>Broadcast audio received on this channel to other channels.</para>
79 </option>
80 </optionlist>
81 </parameter>
82 <parameter name="channels" required="true" argsep=",">
83 <para>List of channels for broadcast targets.</para>
84 <para>Channel names must be the full channel names, not merely device names.</para>
85 <para>Broadcasting will continue until the broadcasting channel hangs up or all target channels have hung up.</para>
86 </parameter>
87 </syntax>
88 <description>
89 <para>This application can be used to broadcast audio to multiple channels at once.
90 Any audio received on this channel will be transmitted to all of the specified channels and, optionally, their bridged peers.</para>
91 <para>It can also be used to aggregate audio from multiple channels at once.
92 Any audio on any of the specified channels, and optionally their bridged peers, will be transmitted to this channel.</para>
93 <para>Execution of the application continues until either the broadcasting channel hangs up
94 or all specified channels have hung up.</para>
95 <para>This application is used for one-to-many and many-to-one audio applications where
96 bridge mixing cannot be done synchronously on all the involved channels.
97 This is primarily useful for injecting the same audio stream into multiple channels at once,
98 or doing the reverse, combining the audio from multiple channels into a single stream.
99 This contrasts with using a separate injection channel for each target channel and/or
100 using a conference bridge.</para>
101 <para>The channel running the Broadcast application must do so synchronously. The specified channels,
102 however, may be doing other things.</para>
103 <example title="Broadcast received audio to three channels and their bridged peers">
104 same => n,Broadcast(wb,DAHDI/1,DAHDI/3,PJSIP/doorphone)
105 </example>
106 <example title="Broadcast received audio to three channels, only">
107 same => n,Broadcast(w,DAHDI/1,DAHDI/3,PJSIP/doorphone)
108 </example>
109 <example title="Combine audio from three channels and their bridged peers to us">
110 same => n,Broadcast(s,DAHDI/1,DAHDI/3,PJSIP/doorphone)
111 </example>
112 <example title="Combine audio from three channels to us">
113 same => n,Broadcast(so,DAHDI/1,DAHDI/3,PJSIP/doorphone)
114 </example>
115 <example title="Two-way audio with a bunch of channels">
116 same => n,Broadcast(wbso,DAHDI/1,DAHDI/3,PJSIP/doorphone)
117 </example>
118 <para>Note that in the last example above, this is NOT the same as a conference bridge.
119 The specified channels are not audible to each other, only to the channel running the
120 Broadcast application. The two-way audio is only between the broadcasting channel and
121 each of the specified channels, individually.</para>
122 </description>
123 <see-also>
124 <ref type="application">ChanSpy</ref>
125 </see-also>
126 </application>
127 ***/
128
129static const char app_broadcast[] = "Broadcast";
130
131enum {
132 OPTION_READONLY = (1 << 0), /* Don't mix the two channels */
133 OPTION_BARGE = (1 << 1), /* Barge mode (whisper to both channels) */
134 OPTION_LONG_QUEUE = (1 << 2), /* Allow usage of a long queue to store audio frames. */
135 OPTION_WHISPER = (1 << 3),
136 OPTION_SPY = (1 << 4),
138 OPTION_ANSWER_WARN = (1 << 6), /* Internal flag, not set by user */
139};
140
148});
149
151 char *name;
157 unsigned int connected:1;
158 unsigned int bridge_connected:1;
159 unsigned int spying:1;
160 AST_LIST_ENTRY(multi_autochan) entry; /*!< Next record */
161};
162
164
165struct multi_spy {
167 unsigned int readonly:1;
168};
169
170static void *spy_alloc(struct ast_channel *chan, void *data)
171{
172 return data; /* just store the data pointer in the channel structure */
173}
174
175static void spy_release(struct ast_channel *chan, void *data)
176{
177 return; /* nothing to do */
178}
179
180static int spy_generate(struct ast_channel *chan, void *data, int len, int samples)
181{
182 struct multi_spy *multispy = data;
183 struct multi_autochan_list *chanlist = multispy->chanlist;
184 struct multi_autochan *mac;
185 struct ast_frame *f;
186 short *data1, *data2;
187 int res, i;
188
189 /* All the frames we get are slin, so they will all have the same number of samples. */
190 static const int num_samples = 160;
191 short combine_buf[num_samples];
192 struct ast_frame wf = {
194 .offset = 0,
195 .subclass.format = ast_format_slin,
196 .datalen = num_samples * 2,
197 .samples = num_samples,
198 .src = __FUNCTION__,
199 };
200
201 memset(&combine_buf, 0, sizeof(combine_buf));
202 wf.data.ptr = combine_buf;
203
208 ast_audiohook_unlock(&mac->spy_audiohook); /* Channel is already gone more than likely, the broadcasting channel will clean this up. */
209 continue;
210 }
211
212 if (multispy->readonly) { /* Option 'o' was set, so don't mix channel audio */
214 } else {
216 }
218
219 if (!f) {
220 continue; /* No frame? No problem. */
221 }
222
223 /* Mix the samples. */
224 for (i = 0, data1 = combine_buf, data2 = f->data.ptr; i < num_samples; i++, data1++, data2++) {
225 ast_slinear_saturated_add(data1, data2);
226 }
227 ast_frfree(f);
228 }
231
232 res = ast_write(chan, &wf);
233 ast_frfree(&wf);
234
235 return res;
236}
237
238static struct ast_generator spygen = {
239 .alloc = spy_alloc,
240 .release = spy_release,
241 .generate = spy_generate,
242};
243
244static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook, struct ast_flags *flags)
245{
246 int res;
247
249 ast_debug(1, "Attaching spy channel %s to %s\n", spychan_name, ast_channel_name(autochan->chan));
250
251 if (ast_test_flag(flags, OPTION_READONLY)) {
254 } else {
256 }
257 if (ast_test_flag(flags, OPTION_LONG_QUEUE)) {
258 ast_debug(2, "Using a long queue to store audio frames in spy audiohook\n");
259 } else {
261 }
262 res = ast_audiohook_attach(autochan->chan, audiohook);
264 return res;
265}
266
267static int start_whispering(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook, struct ast_flags *flags)
268{
269 int res;
270
272 ast_verb(3, "Attaching spy channel %s to %s\n",
273 spychan_name, ast_channel_name(autochan->chan));
274
276 if (ast_test_flag(flags, OPTION_LONG_QUEUE)) {
277 ast_debug(9, "Using a long queue to store audio frames in whisper audiohook\n");
278 } else {
280 }
281 res = ast_audiohook_attach(autochan->chan, audiohook);
283 return res;
284}
285
286static int attach_barge(struct ast_autochan *spyee_autochan, struct ast_autochan **spyee_bridge_autochan,
287 struct ast_audiohook *bridge_whisper_audiohook, const char *spyer_name, const char *name, struct ast_flags *flags)
288{
289 int retval = 0;
290 struct ast_autochan *internal_bridge_autochan;
291 struct ast_channel *spyee_chan;
292 RAII_VAR(struct ast_channel *, bridged, NULL, ast_channel_cleanup);
293
294 ast_autochan_channel_lock(spyee_autochan);
295 spyee_chan = ast_channel_ref(spyee_autochan->chan);
296 ast_autochan_channel_unlock(spyee_autochan);
297
298 /* Note that ast_channel_bridge_peer only returns non-NULL for 2-party bridges, not n-party bridges (e.g. ConfBridge) */
299 bridged = ast_channel_bridge_peer(spyee_chan);
300 ast_channel_unref(spyee_chan);
301 if (!bridged) {
302 ast_debug(9, "Channel %s is not yet bridged, unable to setup barge\n", ast_channel_name(spyee_chan));
303 /* If we're bridged, but it's not a 2-party bridge, then we probably should have used OPTION_REVERSE_FEED. */
305 ast_clear_flag(flags, OPTION_ANSWER_WARN); /* Don't warn more than once. */
306 ast_log(LOG_WARNING, "Barge failed: channel is bridged, but not to a 2-party bridge. Use the 'r' option.\n");
307 }
308 return -1;
309 }
310
311 ast_audiohook_init(bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Broadcast", 0);
312 internal_bridge_autochan = ast_autochan_setup(bridged);
313 if (!internal_bridge_autochan) {
314 return -1;
315 }
316
317 if (start_whispering(internal_bridge_autochan, spyer_name, bridge_whisper_audiohook, flags)) {
318 ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee '%s'. Barge mode disabled.\n", name);
319 retval = -1;
320 }
321
322 *spyee_bridge_autochan = internal_bridge_autochan;
323 return retval;
324}
325
326static void multi_autochan_free(struct multi_autochan *mac)
327{
328 if (mac->connected) {
330 ast_debug(2, "Whisper audiohook no longer running\n");
331 }
336 }
337 if (mac->bridge_connected) {
339 ast_debug(2, "Whisper (bridged) audiohook no longer running\n");
340 }
345 }
346 if (mac->spying) {
348 ast_debug(2, "Spy audiohook no longer running\n");
349 }
354 }
355 if (mac->name) {
356 int total = mac->connected + mac->bridge_connected + mac->spying;
357 ast_debug(1, "Removing channel %s from target list (%d hook%s)\n", mac->name, total, ESS(total));
358 ast_free(mac->name);
359 }
360 if (mac->autochan) {
362 }
363 if (mac->bridge_autochan) {
365 }
366 ast_free(mac);
367}
368
369static int do_broadcast(struct ast_channel *chan, struct ast_flags *flags, const char *channels)
370{
371 int res = 0;
372 struct ast_frame *f;
373 struct ast_silence_generator *silgen = NULL;
374 struct multi_spy multispy;
376 struct multi_autochan *mac;
377 int numchans = 0;
378 int readonly = ast_test_flag(flags, OPTION_READONLY) ? 1 : 0;
379 char *next, *chansdup = ast_strdupa(channels);
380
383
384 ast_set_flag(flags, OPTION_ANSWER_WARN); /* Initialize answer warn to 1 */
385
386 /* Hey, look ma, no list lock needed! Sometimes, it's nice to not have to share... */
387
388 /* Build a list of targets */
389 while ((next = strsep(&chansdup, ","))) {
390 struct ast_channel *ochan;
391 if (ast_strlen_zero(next)) {
392 continue;
393 }
394 if (!strcmp(next, ast_channel_name(chan))) {
395 ast_log(LOG_WARNING, "Refusing to broadcast to ourself: %s\n", next);
396 continue;
397 }
398 ochan = ast_channel_get_by_name(next);
399 if (!ochan) {
400 ast_log(LOG_WARNING, "No such channel: %s\n", next);
401 continue;
402 }
403 /* Append to end of list. */
404 if (!(mac = ast_calloc(1, sizeof(*mac)))) {
405 ast_log(LOG_WARNING, "Multi autochan allocation failure\n");
406 continue;
407 }
408 mac->name = ast_strdup(next);
409 mac->autochan = ast_autochan_setup(ochan);
410 if (!mac->name || !mac->autochan) {
412 continue;
413 }
415 mac->connected = 1;
417 /* Inject audio from our channel to this target. */
418 if (start_whispering(mac->autochan, next, &mac->whisper_audiohook, flags)) {
419 ast_log(LOG_WARNING, "Unable to attach whisper audiohook to %s\n", next);
421 continue;
422 }
423 }
425 mac->spying = 1;
427 if (start_spying(mac->autochan, next, &mac->spy_audiohook, flags)) {
428 ast_log(LOG_WARNING, "Unable to attach spy audiohook to %s\n", next);
430 continue;
431 }
432 }
434 numchans++;
435 ochan = ast_channel_unref(ochan);
436 }
437
438 ast_verb(4, "Broadcasting to %d channel%s on %s\n", numchans, ESS(numchans), ast_channel_name(chan));
439 ast_debug(1, "Broadcasting: (TX->1) whisper=%d, (TX->2) barge=%d, (RX<-%d) spy=%d (%s)\n",
442 readonly ? 1 : 2,
444 readonly ? "single" : "both");
445
447 multispy.chanlist = &chanlist;
448 multispy.readonly = readonly;
449 ast_activate_generator(chan, &spygen, &multispy);
450 } else {
451 /* We're not expecting to read any audio, just broadcast audio to a bunch of other channels. */
453 }
454
455 while (numchans && ast_waitfor(chan, -1) > 0) {
456 int fres = 0;
457 f = ast_read(chan);
458 if (!f) {
459 ast_debug(1, "Channel %s must have hung up\n", ast_channel_name(chan));
460 res = -1;
461 break;
462 }
463 if (f->frametype != AST_FRAME_VOICE) { /* Ignore any non-voice frames */
464 ast_frfree(f);
465 continue;
466 }
467 /* Write the frame to all our targets. */
470 /* Note that if no media is received, execution is suspended, but assuming continuous or
471 * or frequent audio on the broadcasting channel, we'll quickly enough detect hung up targets.
472 * This isn't really an issue, just something that might be confusing at first, but this is
473 * due to the limitation with audiohooks of using the channel for timing. */
477 /* Even if we're spying only and not actually broadcasting audio, we need to detect channel hangup. */
479 ast_debug(2, "Looks like %s has hung up\n", mac->name);
481 numchans--;
482 ast_debug(2, "%d channel%s remaining in broadcast on %s\n", numchans, ESS(numchans), ast_channel_name(chan));
483 continue;
484 }
485
490 }
491
493 /* This hook lets us inject audio into the channel that the spyee is currently
494 * bridged with. If the spyee isn't bridged with anything yet, nothing will
495 * be attached and we'll need to continue attempting to attach the barge
496 * audio hook.
497 * The exception to this is if we are emulating barge by doing it "directly",
498 * that is injecting the frames onto this channel's read queue, rather than
499 * its bridged peer's write queue, then skip this. We only do one or the other. */
502 ast_debug(2, "Attached barge channel for %s\n", mac->name);
503 mac->bridge_connected = 1;
504 }
505
506 if (mac->bridge_connected) {
511 /* So, this is really clever...
512 * If we're connected to an n-party bridge instead of a 2-party bridge,
513 * attach_barge will ALWAYS fail because we're connected to a bridge, not
514 * a single peer channel.
515 * Recall that the objective is for injected audio to be audible to both
516 * sides of the channel. So really, the typical way of doing this by
517 * directly injecting frames separately onto both channels is kind of
518 * bizarre to begin with, when you think about it.
519 *
520 * In other words, this is how ChanSpy and this module by default work:
521 * We have audio F to inject onto channels A and B, which are <= bridged =>:
522 * READ <- A -> WRITE <==> READ <- B -> WRITE
523 * F --^ F --^
524 *
525 * So that makes the same audio audible to both channels A and B, but
526 * in kind of a roundabout way. What if the bridged peer changes at
527 * some point, for example?
528 *
529 * While that method works for 2-party bridges, it doesn't work at all
530 * for an n-party bridge, so we do the thing that seems obvious to begin with:
531 * dump the frames onto THIS channel's read queue, and the channels will
532 * make their way into the bridge like any other audio from this channel,
533 * and everything just works perfectly, no matter what kind of bridging
534 * scenario is being used. At that point, we don't even care if we're
535 * bridged or not, and really, why should we?
536 *
537 * In other words, we do this:
538 * READ <- A -> WRITE <==> READ <- B -> WRITE
539 * F --^ F --^
540 */
544 }
545 }
546 if (fres) {
547 ast_log(LOG_WARNING, "Failed to write to audiohook for %s\n", mac->name);
548 fres = 0;
549 }
550 }
553 ast_frfree(f);
554 }
555
556 if (!numchans) {
557 ast_debug(1, "Exiting due to all target channels having left the broadcast\n");
558 }
559
562 } else {
564 }
565
566 /* Cleanup any remaining targets */
570 }
572
574 return res;
575}
576
577static int broadcast_exec(struct ast_channel *chan, const char *data)
578{
579 struct ast_flags flags;
580 struct ast_format *write_format;
581 int res = -1;
584 AST_APP_ARG(channels); /* Channel list last, so we can have multiple */
585 );
586 char *parse = NULL;
587
588 if (ast_strlen_zero(data)) {
589 ast_log(LOG_WARNING, "Broadcast requires at least one channel\n");
590 return -1;
591 }
592
593 parse = ast_strdupa(data);
595
596 if (ast_strlen_zero(args.channels)) {
597 ast_log(LOG_WARNING, "Must specify at least one channel for broadcast\n");
598 return -1;
599 }
600 if (args.options) {
601 ast_app_parse_options(spy_opts, &flags, NULL, args.options);
602 } else {
604 }
605
606 if (!ast_test_flag(&flags, OPTION_BARGE) && !ast_test_flag(&flags, OPTION_SPY) && !ast_test_flag(&flags, OPTION_WHISPER)) {
607 ast_log(LOG_WARNING, "At least one of the b, s, or w option must be specified (provided options have no effect)\n");
608 return -1;
609 }
610
611 write_format = ao2_bump(ast_channel_writeformat(chan));
612 if (ast_set_write_format(chan, ast_format_slin) < 0) {
613 ast_log(LOG_ERROR, "Failed to set write format to slin.\n");
614 goto cleanup;
615 }
616
617 res = do_broadcast(chan, &flags, args.channels);
618
619 /* Restore previous write format */
620 if (ast_set_write_format(chan, write_format)) {
621 ast_log(LOG_ERROR, "Failed to restore write format for channel %s\n", ast_channel_name(chan));
622 }
623
624cleanup:
625 ao2_ref(write_format, -1);
626 return res;
627}
628
629static int unload_module(void)
630{
632}
633
634static int load_module(void)
635{
637}
638
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
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:2970
void ast_channel_clear_flag(struct ast_channel *chan, unsigned int flag)
Clear a flag on a channel.
Definition: channel.c:11056
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:10586
struct ast_silence_generator * ast_channel_start_silence_generator(struct ast_channel *chan)
Starts a silence generator on the given channel.
Definition: channel.c:8186
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3181
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:8232
#define ast_channel_ref(c)
Increase channel reference count.
Definition: channel.h:2993
void ast_deactivate_generator(struct ast_channel *chan)
Definition: channel.c:2912
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:5163
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4276
int ast_channel_is_bridged(const struct ast_channel *chan)
Determine if a channel is in a bridge.
Definition: channel.c:10567
void ast_channel_set_flag(struct ast_channel *chan, unsigned int flag)
Set a flag on a channel.
Definition: channel.c:11049
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:3004
struct ast_format * ast_channel_writeformat(struct ast_channel *chan)
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Definition: channel.c:5822
@ AST_FLAG_SPYING
Definition: channel.h:1013
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition: channel.h:3015
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1473
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)
static ENTRY retval
Definition: hsearch.c:50
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
char * strsep(char **str, const char *delims)
#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::@226 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:797
Definition: search.h:40
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