Asterisk - The Open Source Telephony Project GIT-master-66c01d8
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 135 of file app_broadcast.c.

135 {
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),
141 OPTION_REVERSE_FEED = (1 << 5),
142 OPTION_ANSWER_WARN = (1 << 6), /* Internal flag, not set by user */
143};
@ 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 290 of file app_broadcast.c.

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}
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:10590
#define ast_channel_ref(c)
Increase channel reference count.
Definition: channel.h:2995
int ast_channel_is_bridged(const struct ast_channel *chan)
Determine if a channel is in a bridge.
Definition: channel.c:10571
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:3006
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition: channel.h:3017
static const char name[]
Definition: format_mp3.c:68
#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, and start_whispering().

Referenced by do_broadcast().

◆ broadcast_exec()

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

Definition at line 581 of file app_broadcast.c.

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}
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:5820
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 373 of file app_broadcast.c.

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}
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
char * strsep(char **str, const char *delims)
#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: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_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
void ast_deactivate_generator(struct ast_channel *chan)
Definition: channel.c:2921
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4274
void ast_channel_set_flag(struct ast_channel *chan, unsigned int flag)
Set a flag on a channel.
Definition: channel.c:11053
@ 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:1481
#define ESS(x)
Definition: cli.h:59
#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:803
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 638 of file app_broadcast.c.

639{
641}
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 330 of file app_broadcast.c.

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}
#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 174 of file app_broadcast.c.

175{
176 return data; /* just store the data pointer in the channel structure */
177}

◆ spy_generate()

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

Definition at line 184 of file app_broadcast.c.

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}
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:5161
union ast_frame::@228 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 179 of file app_broadcast.c.

180{
181 return; /* nothing to do */
182}

◆ 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 248 of file app_broadcast.c.

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}
@ 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 271 of file app_broadcast.c.

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}

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 633 of file app_broadcast.c.

634{
636}
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 133 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 152 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 242 of file app_broadcast.c.

Referenced by do_broadcast().