Asterisk - The Open Source Telephony Project GIT-master-f36a736
Data Structures | Enumerations | Functions | Variables
app_broadcast.c File Reference

Channel audio broadcasting. More...

#include "asterisk.h"
#include <ctype.h>
#include <errno.h>
#include "asterisk/channel.h"
#include "asterisk/audiohook.h"
#include "asterisk/app.h"
#include "asterisk/utils.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/lock.h"
#include "asterisk/options.h"
#include "asterisk/autochan.h"
#include "asterisk/format_cache.h"
#include "asterisk/cli.h"
Include dependency graph for app_broadcast.c:

Go to the source code of this file.

Data Structures

struct  multi_autochan
 
struct  multi_autochan_list
 
struct  multi_spy
 

Enumerations

enum  {
  OPTION_READONLY = (1 << 0) , OPTION_BARGE = (1 << 1) , OPTION_LONG_QUEUE = (1 << 2) , OPTION_WHISPER = (1 << 3) ,
  OPTION_SPY = (1 << 4) , OPTION_REVERSE_FEED = (1 << 5) , OPTION_ANSWER_WARN = (1 << 6)
}
 

Functions

 AST_MODULE_INFO_STANDARD_EXTENDED (ASTERISK_GPL_KEY, "Channel Audio Broadcasting")
 
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 broadcast_exec (struct ast_channel *chan, const char *data)
 
static int do_broadcast (struct ast_channel *chan, struct ast_flags *flags, const char *channels)
 
static int load_module (void)
 
static void multi_autochan_free (struct multi_autochan *mac)
 
static void * spy_alloc (struct ast_channel *chan, void *data)
 
static int spy_generate (struct ast_channel *chan, void *data, int len, int samples)
 
static void spy_release (struct ast_channel *chan, void *data)
 
static int start_spying (struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook, struct ast_flags *flags)
 
static int start_whispering (struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook, struct ast_flags *flags)
 
static int unload_module (void)
 

Variables

static const char app_broadcast [] = "Broadcast"
 
static const struct ast_app_option spy_opts [128] = { [ 'b' ] = { .flag = OPTION_BARGE }, [ 'l' ] = { .flag = OPTION_LONG_QUEUE }, [ 'o' ] = { .flag = OPTION_READONLY }, [ 'r' ] = { .flag = OPTION_REVERSE_FEED }, [ 's' ] = { .flag = OPTION_SPY }, [ 'w' ] = { .flag = OPTION_WHISPER }, }
 
static struct ast_generator spygen
 

Detailed Description

Channel audio broadcasting.

Author
Naveen Albert aster.nosp@m.isk@.nosp@m.phrea.nosp@m.knet.nosp@m..org

Definition in file app_broadcast.c.

Enumeration Type Documentation

◆ anonymous enum

anonymous enum
Enumerator
OPTION_READONLY 
OPTION_BARGE 
OPTION_LONG_QUEUE 
OPTION_WHISPER 
OPTION_SPY 
OPTION_REVERSE_FEED 
OPTION_ANSWER_WARN 

Definition at line 131 of file app_broadcast.c.

131 {
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),
137 OPTION_REVERSE_FEED = (1 << 5),
138 OPTION_ANSWER_WARN = (1 << 6), /* Internal flag, not set by user */
139};
@ OPTION_ANSWER_WARN
@ OPTION_REVERSE_FEED
@ OPTION_WHISPER
@ OPTION_READONLY
@ OPTION_BARGE
@ OPTION_SPY
@ OPTION_LONG_QUEUE

Function Documentation

◆ AST_MODULE_INFO_STANDARD_EXTENDED()

AST_MODULE_INFO_STANDARD_EXTENDED ( ASTERISK_GPL_KEY  ,
"Channel Audio Broadcasting"   
)

◆ attach_barge()

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

Definition at line 286 of file app_broadcast.c.

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}
static int start_whispering(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook, struct ast_flags *flags)
#define ast_log
Definition: astobj2.c:42
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
@ AST_AUDIOHOOK_TYPE_WHISPER
Definition: audiohook.h:37
struct ast_autochan * ast_autochan_setup(struct ast_channel *chan)
set up a new ast_autochan structure
Definition: autochan.c:38
#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
const char * ast_channel_name(const struct ast_channel *chan)
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
#define ast_channel_ref(c)
Increase channel reference count.
Definition: channel.h:2993
int ast_channel_is_bridged(const struct ast_channel *chan)
Determine if a channel is in a bridge.
Definition: channel.c:10567
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:3004
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition: channel.h:3015
static const char name[]
Definition: format_mp3.c:68
static ENTRY retval
Definition: hsearch.c:50
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_WARNING
#define NULL
Definition: resample.c:96
struct ast_channel * chan
Definition: autochan.h:33
Main Channel structure associated with a channel.
struct ast_flags flags
#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

References ast_audiohook_init(), AST_AUDIOHOOK_TYPE_WHISPER, ast_autochan_channel_lock, ast_autochan_channel_unlock, ast_autochan_setup(), ast_channel_bridge_peer(), ast_channel_cleanup, ast_channel_is_bridged(), ast_channel_name(), ast_channel_ref, ast_channel_unref, ast_clear_flag, ast_debug, ast_log, ast_test_flag, ast_autochan::chan, ast_channel::flags, LOG_WARNING, name, NULL, OPTION_ANSWER_WARN, RAII_VAR, retval, and start_whispering().

Referenced by do_broadcast().

◆ broadcast_exec()

static int broadcast_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 577 of file app_broadcast.c.

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}
static int do_broadcast(struct ast_channel *chan, struct ast_flags *flags, const char *channels)
static const struct ast_app_option spy_opts[128]
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#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
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
static struct channel_usage channels
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
#define AST_APP_ARG(name)
Define an application 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.
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
static void * cleanup(void *unused)
Definition: pbx_realtime.c:124
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
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
const char * args
static struct test_options options
#define AST_FLAGS_ALL
Definition: utils.h:196

References ao2_bump, ao2_ref, args, AST_APP_ARG, ast_app_parse_options(), ast_channel_name(), ast_channel_writeformat(), ast_clear_flag, AST_DECLARE_APP_ARGS, AST_FLAGS_ALL, ast_format_slin, ast_log, ast_set_write_format(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, channels, cleanup(), do_broadcast(), ast_flags::flags, LOG_ERROR, LOG_WARNING, NULL, OPTION_BARGE, OPTION_SPY, OPTION_WHISPER, options, and spy_opts.

Referenced by load_module().

◆ do_broadcast()

static int do_broadcast ( struct ast_channel chan,
struct ast_flags flags,
const char *  channels 
)
static

Definition at line 369 of file app_broadcast.c.

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}
static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook, struct ast_flags *flags)
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 void multi_autochan_free(struct multi_autochan *mac)
static struct ast_generator spygen
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
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
#define ast_audiohook_lock(ah)
Lock an audiohook.
Definition: audiohook.h:313
#define ast_audiohook_unlock(ah)
Unlock an audiohook.
Definition: audiohook.h:318
@ AST_AUDIOHOOK_TYPE_SPY
Definition: audiohook.h:36
@ AST_AUDIOHOOK_STATUS_RUNNING
Definition: audiohook.h:43
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_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
void ast_deactivate_generator(struct ast_channel *chan)
Definition: channel.c:2912
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4276
void ast_channel_set_flag(struct ast_channel *chan, unsigned int flag)
Set a flag on a channel.
Definition: channel.c:11049
@ AST_FLAG_SPYING
Definition: channel.h:1013
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1473
#define ESS(x)
Definition: cli.h:59
char * strsep(char **str, const char *delims)
#define ast_frfree(fr)
@ AST_FRAME_VOICE
#define ast_verb(level,...)
#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_RWLIST_TRAVERSE_SAFE_END
Definition: linkedlists.h:617
#define AST_RWLIST_INSERT_TAIL
Definition: linkedlists.h:741
enum ast_audiohook_status status
Definition: audiohook.h:108
Data structure associated with a single frame of data.
enum ast_frame_type frametype
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
unsigned int connected
struct ast_audiohook spy_audiohook
unsigned int bridge_connected
struct ast_autochan * bridge_autochan
#define ast_set_flag(p, flag)
Definition: utils.h:70

References ast_activate_generator(), AST_AUDIOHOOK_DIRECTION_READ, AST_AUDIOHOOK_DIRECTION_WRITE, ast_audiohook_init(), ast_audiohook_lock, AST_AUDIOHOOK_STATUS_RUNNING, AST_AUDIOHOOK_TYPE_SPY, AST_AUDIOHOOK_TYPE_WHISPER, ast_audiohook_unlock, ast_audiohook_write_frame(), ast_autochan_setup(), ast_calloc, ast_channel_clear_flag(), ast_channel_get_by_name(), ast_channel_name(), ast_channel_set_flag(), ast_channel_start_silence_generator(), ast_channel_stop_silence_generator(), ast_channel_unref, ast_deactivate_generator(), ast_debug, AST_FLAG_SPYING, AST_FRAME_VOICE, ast_frfree, ast_log, ast_read(), AST_RWLIST_HEAD_INIT, AST_RWLIST_INSERT_TAIL, AST_RWLIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_set_flag, ast_strdup, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_verb, ast_waitfor(), attach_barge(), multi_autochan::autochan, multi_autochan::bridge_autochan, multi_autochan::bridge_connected, multi_autochan::bridge_whisper_audiohook, multi_spy::chanlist, channels, multi_autochan::connected, ESS, ast_channel::flags, ast_frame::frametype, LOG_WARNING, multi_autochan_free(), multi_autochan::name, multi_autochan::next, NULL, OPTION_ANSWER_WARN, OPTION_BARGE, OPTION_READONLY, OPTION_REVERSE_FEED, OPTION_SPY, OPTION_WHISPER, multi_spy::readonly, multi_autochan::spy_audiohook, spygen, multi_autochan::spying, start_spying(), start_whispering(), ast_audiohook::status, strsep(), and multi_autochan::whisper_audiohook.

Referenced by broadcast_exec().

◆ load_module()

static int load_module ( void  )
static

Definition at line 634 of file app_broadcast.c.

635{
637}
static int broadcast_exec(struct ast_channel *chan, const char *data)
static const char app_broadcast[]
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:640

References app_broadcast, ast_register_application_xml, and broadcast_exec().

◆ multi_autochan_free()

static void multi_autochan_free ( struct multi_autochan mac)
static

Definition at line 326 of file app_broadcast.c.

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}
#define ast_free(a)
Definition: astmm.h:180
int ast_audiohook_detach(struct ast_audiohook *audiohook)
Detach audiohook from channel.
Definition: audiohook.c:578
int ast_audiohook_destroy(struct ast_audiohook *audiohook)
Destroys an audiohook structure.
Definition: audiohook.c:124
void ast_autochan_destroy(struct ast_autochan *autochan)
destroy an ast_autochan structure
Definition: autochan.c:64
static int total
Definition: res_adsi.c:970

References ast_audiohook_destroy(), ast_audiohook_detach(), ast_audiohook_lock, AST_AUDIOHOOK_STATUS_RUNNING, ast_audiohook_unlock, ast_autochan_destroy(), ast_debug, ast_free, multi_autochan::autochan, multi_autochan::bridge_autochan, multi_autochan::bridge_connected, multi_autochan::bridge_whisper_audiohook, multi_autochan::connected, ESS, multi_autochan::name, multi_autochan::spy_audiohook, multi_autochan::spying, ast_audiohook::status, total, and multi_autochan::whisper_audiohook.

Referenced by do_broadcast().

◆ spy_alloc()

static void * spy_alloc ( struct ast_channel chan,
void *  data 
)
static

Definition at line 170 of file app_broadcast.c.

171{
172 return data; /* just store the data pointer in the channel structure */
173}

◆ spy_generate()

static int spy_generate ( struct ast_channel chan,
void *  data,
int  len,
int  samples 
)
static

Definition at line 180 of file app_broadcast.c.

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}
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
@ AST_AUDIOHOOK_DIRECTION_BOTH
Definition: audiohook.h:51
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
union ast_frame::@226 data
struct multi_autochan_list * chanlist
unsigned int readonly
static force_inline void ast_slinear_saturated_add(short *input, short *value)
Definition: utils.h:450

References AST_AUDIOHOOK_DIRECTION_BOTH, AST_AUDIOHOOK_DIRECTION_READ, ast_audiohook_lock, ast_audiohook_read_frame(), AST_AUDIOHOOK_STATUS_RUNNING, ast_audiohook_unlock, ast_format_slin, AST_FRAME_VOICE, ast_frfree, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_slinear_saturated_add(), ast_write(), multi_spy::chanlist, ast_frame::data, ast_frame::frametype, ast_frame::ptr, multi_spy::readonly, ast_frame::samples, multi_autochan::spy_audiohook, and ast_audiohook::status.

◆ spy_release()

static void spy_release ( struct ast_channel chan,
void *  data 
)
static

Definition at line 175 of file app_broadcast.c.

176{
177 return; /* nothing to do */
178}

◆ start_spying()

static int start_spying ( struct ast_autochan autochan,
const char *  spychan_name,
struct ast_audiohook audiohook,
struct ast_flags flags 
)
static

Definition at line 244 of file app_broadcast.c.

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}
@ 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_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
Attach audiohook to channel.
Definition: audiohook.c:512
int ast_audiohook_set_frame_feed_direction(struct ast_audiohook *audiohook, enum ast_audiohook_direction direction)
Sets direction on audiohook.
Definition: audiohook.c:150

References ast_audiohook_attach(), AST_AUDIOHOOK_DIRECTION_READ, AST_AUDIOHOOK_MUTE_WRITE, ast_audiohook_set_frame_feed_direction(), AST_AUDIOHOOK_SMALL_QUEUE, AST_AUDIOHOOK_TRIGGER_SYNC, ast_autochan_channel_lock, ast_autochan_channel_unlock, ast_channel_name(), ast_debug, ast_set_flag, ast_test_flag, ast_autochan::chan, OPTION_LONG_QUEUE, and OPTION_READONLY.

Referenced by do_broadcast().

◆ start_whispering()

static int start_whispering ( struct ast_autochan autochan,
const char *  spychan_name,
struct ast_audiohook audiohook,
struct ast_flags flags 
)
static

Definition at line 267 of file app_broadcast.c.

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}

References ast_audiohook_attach(), AST_AUDIOHOOK_SMALL_QUEUE, AST_AUDIOHOOK_TRIGGER_SYNC, ast_autochan_channel_lock, ast_autochan_channel_unlock, ast_channel_name(), ast_debug, ast_set_flag, ast_test_flag, ast_verb, ast_autochan::chan, and OPTION_LONG_QUEUE.

Referenced by attach_barge(), and do_broadcast().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 629 of file app_broadcast.c.

630{
632}
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392

References app_broadcast, and ast_unregister_application().

Variable Documentation

◆ app_broadcast

const char app_broadcast[] = "Broadcast"
static

Definition at line 129 of file app_broadcast.c.

Referenced by load_module(), and unload_module().

◆ spy_opts

const struct ast_app_option spy_opts[128] = { [ 'b' ] = { .flag = OPTION_BARGE }, [ 'l' ] = { .flag = OPTION_LONG_QUEUE }, [ 'o' ] = { .flag = OPTION_READONLY }, [ 'r' ] = { .flag = OPTION_REVERSE_FEED }, [ 's' ] = { .flag = OPTION_SPY }, [ 'w' ] = { .flag = OPTION_WHISPER }, }
static

Definition at line 148 of file app_broadcast.c.

Referenced by broadcast_exec().

◆ spygen

struct ast_generator spygen
static
Initial value:
= {
.alloc = spy_alloc,
.release = spy_release,
.generate = spy_generate,
}
static void * spy_alloc(struct ast_channel *chan, void *data)
static void spy_release(struct ast_channel *chan, void *data)
static int spy_generate(struct ast_channel *chan, void *data, int len, int samples)

Definition at line 238 of file app_broadcast.c.

Referenced by do_broadcast().