Asterisk - The Open Source Telephony Project GIT-master-7e7a603
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)) {
253 } else {
255 }
256 if (ast_test_flag(flags, OPTION_LONG_QUEUE)) {
257 ast_debug(2, "Using a long queue to store audio frames in spy audiohook\n");
258 } else {
260 }
261 res = ast_audiohook_attach(autochan->chan, audiohook);
263 return res;
264}
265
266static int attach_barge(struct ast_autochan *spyee_autochan, struct ast_autochan **spyee_bridge_autochan,
267 struct ast_audiohook *bridge_whisper_audiohook, const char *spyer_name, const char *name, struct ast_flags *flags)
268{
269 int retval = 0;
270 struct ast_autochan *internal_bridge_autochan;
271 struct ast_channel *spyee_chan;
272 RAII_VAR(struct ast_channel *, bridged, NULL, ast_channel_cleanup);
273
274 ast_autochan_channel_lock(spyee_autochan);
275 spyee_chan = ast_channel_ref(spyee_autochan->chan);
276 ast_autochan_channel_unlock(spyee_autochan);
277
278 /* Note that ast_channel_bridge_peer only returns non-NULL for 2-party bridges, not n-party bridges (e.g. ConfBridge) */
279 bridged = ast_channel_bridge_peer(spyee_chan);
280 ast_channel_unref(spyee_chan);
281 if (!bridged) {
282 ast_debug(9, "Channel %s is not yet bridged, unable to setup barge\n", ast_channel_name(spyee_chan));
283 /* If we're bridged, but it's not a 2-party bridge, then we probably should have used OPTION_REVERSE_FEED. */
285 ast_clear_flag(flags, OPTION_ANSWER_WARN); /* Don't warn more than once. */
286 ast_log(LOG_WARNING, "Barge failed: channel is bridged, but not to a 2-party bridge. Use the 'r' option.\n");
287 }
288 return -1;
289 }
290
291 ast_audiohook_init(bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Broadcast", 0);
292 internal_bridge_autochan = ast_autochan_setup(bridged);
293 if (!internal_bridge_autochan) {
294 return -1;
295 }
296
297 if (start_spying(internal_bridge_autochan, spyer_name, bridge_whisper_audiohook, flags)) {
298 ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee '%s'. Barge mode disabled.\n", name);
299 retval = -1;
300 }
301
302 *spyee_bridge_autochan = internal_bridge_autochan;
303 return retval;
304}
305
306static void multi_autochan_free(struct multi_autochan *mac)
307{
308 if (mac->connected) {
310 ast_debug(2, "Whisper audiohook no longer running\n");
311 }
316 }
317 if (mac->bridge_connected) {
319 ast_debug(2, "Whisper (bridged) audiohook no longer running\n");
320 }
325 }
326 if (mac->spying) {
328 ast_debug(2, "Spy audiohook no longer running\n");
329 }
334 }
335 if (mac->name) {
336 int total = mac->connected + mac->bridge_connected + mac->spying;
337 ast_debug(1, "Removing channel %s from target list (%d hook%s)\n", mac->name, total, ESS(total));
338 ast_free(mac->name);
339 }
340 if (mac->autochan) {
342 }
343 if (mac->bridge_autochan) {
345 }
346 ast_free(mac);
347}
348
349static int do_broadcast(struct ast_channel *chan, struct ast_flags *flags, const char *channels)
350{
351 int res = 0;
352 struct ast_frame *f;
353 struct ast_silence_generator *silgen = NULL;
354 struct multi_spy multispy;
356 struct multi_autochan *mac;
357 int numchans = 0;
358 int readonly = ast_test_flag(flags, OPTION_READONLY) ? 1 : 0;
359 char *next, *chansdup = ast_strdupa(channels);
360
363
364 ast_set_flag(flags, OPTION_ANSWER_WARN); /* Initialize answer warn to 1 */
365
366 /* Hey, look ma, no list lock needed! Sometimes, it's nice to not have to share... */
367
368 /* Build a list of targets */
369 while ((next = strsep(&chansdup, ","))) {
370 struct ast_channel *ochan;
371 if (ast_strlen_zero(next)) {
372 continue;
373 }
374 if (!strcmp(next, ast_channel_name(chan))) {
375 ast_log(LOG_WARNING, "Refusing to broadcast to ourself: %s\n", next);
376 continue;
377 }
378 ochan = ast_channel_get_by_name(next);
379 if (!ochan) {
380 ast_log(LOG_WARNING, "No such channel: %s\n", next);
381 continue;
382 }
383 /* Append to end of list. */
384 if (!(mac = ast_calloc(1, sizeof(*mac)))) {
385 ast_log(LOG_WARNING, "Multi autochan allocation failure\n");
386 continue;
387 }
388 mac->name = ast_strdup(next);
389 mac->autochan = ast_autochan_setup(ochan);
390 if (!mac->name || !mac->autochan) {
392 continue;
393 }
395 mac->connected = 1;
397 /* Inject audio from our channel to this target. */
398 if (start_spying(mac->autochan, next, &mac->whisper_audiohook, flags)) {
399 ast_log(LOG_WARNING, "Unable to attach whisper audiohook to %s\n", next);
401 continue;
402 }
403 }
405 mac->spying = 1;
407 if (start_spying(mac->autochan, next, &mac->spy_audiohook, flags)) {
408 ast_log(LOG_WARNING, "Unable to attach spy audiohook to %s\n", next);
410 continue;
411 }
412 }
414 numchans++;
415 ochan = ast_channel_unref(ochan);
416 }
417
418 ast_verb(4, "Broadcasting to %d channel%s on %s\n", numchans, ESS(numchans), ast_channel_name(chan));
419 ast_debug(1, "Broadcasting: (TX->1) whisper=%d, (TX->2) barge=%d, (RX<-%d) spy=%d (%s)\n",
422 readonly ? 1 : 2,
424 readonly ? "single" : "both");
425
427 multispy.chanlist = &chanlist;
428 multispy.readonly = readonly;
429 ast_activate_generator(chan, &spygen, &multispy);
430 } else {
431 /* We're not expecting to read any audio, just broadcast audio to a bunch of other channels. */
433 }
434
435 while (numchans && ast_waitfor(chan, -1) > 0) {
436 int fres = 0;
437 f = ast_read(chan);
438 if (!f) {
439 ast_debug(1, "Channel %s must have hung up\n", ast_channel_name(chan));
440 res = -1;
441 break;
442 }
443 if (f->frametype != AST_FRAME_VOICE) { /* Ignore any non-voice frames */
444 ast_frfree(f);
445 continue;
446 }
447 /* Write the frame to all our targets. */
450 /* Note that if no media is received, execution is suspended, but assuming continuous or
451 * or frequent audio on the broadcasting channel, we'll quickly enough detect hung up targets.
452 * This isn't really an issue, just something that might be confusing at first, but this is
453 * due to the limitation with audiohooks of using the channel for timing. */
457 /* Even if we're spying only and not actually broadcasting audio, we need to detect channel hangup. */
459 ast_debug(2, "Looks like %s has hung up\n", mac->name);
461 numchans--;
462 ast_debug(2, "%d channel%s remaining in broadcast on %s\n", numchans, ESS(numchans), ast_channel_name(chan));
463 continue;
464 }
465
470 }
471
473 /* This hook lets us inject audio into the channel that the spyee is currently
474 * bridged with. If the spyee isn't bridged with anything yet, nothing will
475 * be attached and we'll need to continue attempting to attach the barge
476 * audio hook.
477 * The exception to this is if we are emulating barge by doing it "directly",
478 * that is injecting the frames onto this channel's read queue, rather than
479 * its bridged peer's write queue, then skip this. We only do one or the other. */
482 ast_debug(2, "Attached barge channel for %s\n", mac->name);
483 mac->bridge_connected = 1;
484 }
485
486 if (mac->bridge_connected) {
491 /* So, this is really clever...
492 * If we're connected to an n-party bridge instead of a 2-party bridge,
493 * attach_barge will ALWAYS fail because we're connected to a bridge, not
494 * a single peer channel.
495 * Recall that the objective is for injected audio to be audible to both
496 * sides of the channel. So really, the typical way of doing this by
497 * directly injecting frames separately onto both channels is kind of
498 * bizarre to begin with, when you think about it.
499 *
500 * In other words, this is how ChanSpy and this module by default work:
501 * We have audio F to inject onto channels A and B, which are <= bridged =>:
502 * READ <- A -> WRITE <==> READ <- B -> WRITE
503 * F --^ F --^
504 *
505 * So that makes the same audio audible to both channels A and B, but
506 * in kind of a roundabout way. What if the bridged peer changes at
507 * some point, for example?
508 *
509 * While that method works for 2-party bridges, it doesn't work at all
510 * for an n-party bridge, so we do the thing that seems obvious to begin with:
511 * dump the frames onto THIS channel's read queue, and the channels will
512 * make their way into the bridge like any other audio from this channel,
513 * and everything just works perfectly, no matter what kind of bridging
514 * scenario is being used. At that point, we don't even care if we're
515 * bridged or not, and really, why should we?
516 *
517 * In other words, we do this:
518 * READ <- A -> WRITE <==> READ <- B -> WRITE
519 * F --^ F --^
520 */
524 }
525 }
526 if (fres) {
527 ast_log(LOG_WARNING, "Failed to write to audiohook for %s\n", mac->name);
528 fres = 0;
529 }
530 }
533 ast_frfree(f);
534 }
535
536 if (!numchans) {
537 ast_debug(1, "Exiting due to all target channels having left the broadcast\n");
538 }
539
542 } else {
544 }
545
546 /* Cleanup any remaining targets */
550 }
552
554 return res;
555}
556
557static int broadcast_exec(struct ast_channel *chan, const char *data)
558{
559 struct ast_flags flags;
560 struct ast_format *write_format;
561 int res = -1;
564 AST_APP_ARG(channels); /* Channel list last, so we can have multiple */
565 );
566 char *parse = NULL;
567
568 if (ast_strlen_zero(data)) {
569 ast_log(LOG_WARNING, "Broadcast requires at least one channel\n");
570 return -1;
571 }
572
573 parse = ast_strdupa(data);
575
576 if (ast_strlen_zero(args.channels)) {
577 ast_log(LOG_WARNING, "Must specify at least one channel for broadcast\n");
578 return -1;
579 }
580 if (args.options) {
581 ast_app_parse_options(spy_opts, &flags, NULL, args.options);
582 } else {
584 }
585
586 if (!ast_test_flag(&flags, OPTION_BARGE) && !ast_test_flag(&flags, OPTION_SPY) && !ast_test_flag(&flags, OPTION_WHISPER)) {
587 ast_log(LOG_WARNING, "At least one of the b, s, or w option must be specified (provided options have no effect)\n");
588 return -1;
589 }
590
591 write_format = ao2_bump(ast_channel_writeformat(chan));
592 if (ast_set_write_format(chan, ast_format_slin) < 0) {
593 ast_log(LOG_ERROR, "Failed to set write format to slin.\n");
594 goto cleanup;
595 }
596
597 res = do_broadcast(chan, &flags, args.channels);
598
599 /* Restore previous write format */
600 if (ast_set_write_format(chan, write_format)) {
601 ast_log(LOG_ERROR, "Failed to restore write format for channel %s\n", ast_channel_name(chan));
602 }
603
604cleanup:
605 ao2_ref(write_format, -1);
606 return res;
607}
608
609static int unload_module(void)
610{
612}
613
614static int load_module(void)
615{
617}
618
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_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:446
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:550
int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
Attach audiohook to channel.
Definition: audiohook.c:484
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
"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:2951
void ast_channel_clear_flag(struct ast_channel *chan, unsigned int flag)
Clear a flag on a channel.
Definition: channel.c:11034
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:10564
struct ast_silence_generator * ast_channel_start_silence_generator(struct ast_channel *chan)
Starts a silence generator on the given channel.
Definition: channel.c:8164
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3162
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:8210
#define ast_channel_ref(c)
Increase channel reference count.
Definition: channel.h:2947
void ast_deactivate_generator(struct ast_channel *chan)
Definition: channel.c:2893
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:5144
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4257
int ast_channel_is_bridged(const struct ast_channel *chan)
Determine if a channel is in a bridge.
Definition: channel.c:10545
void ast_channel_set_flag(struct ast_channel *chan, unsigned int flag)
Set a flag on a channel.
Definition: channel.c:11027
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2958
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:5803
@ AST_FLAG_SPYING
Definition: channel.h:993
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition: channel.h:2969
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1454
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:3056
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:626
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:226
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