Asterisk - The Open Source Telephony Project GIT-master-1f1c5bb
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 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 266 of file app_broadcast.c.

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}
static int start_spying(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:10564
#define ast_channel_ref(c)
Increase channel reference count.
Definition: channel.h:2947
int ast_channel_is_bridged(const struct ast_channel *chan)
Determine if a channel is in a bridge.
Definition: channel.c:10545
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2958
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition: channel.h:2969
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_spying().

Referenced by do_broadcast().

◆ broadcast_exec()

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

Definition at line 557 of file app_broadcast.c.

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}
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:5803
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:3056
#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 349 of file app_broadcast.c.

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}
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: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_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
void ast_deactivate_generator(struct ast_channel *chan)
Definition: channel.c:2893
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4257
void ast_channel_set_flag(struct ast_channel *chan, unsigned int flag)
Set a flag on a channel.
Definition: channel.c:11027
@ AST_FLAG_SPYING
Definition: channel.h:993
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1454
#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(), ast_audiohook::status, strsep(), and multi_autochan::whisper_audiohook.

Referenced by broadcast_exec().

◆ load_module()

static int load_module ( void  )
static

Definition at line 614 of file app_broadcast.c.

615{
617}
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 306 of file app_broadcast.c.

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}
#define ast_free(a)
Definition: astmm.h:180
int ast_audiohook_detach(struct ast_audiohook *audiohook)
Detach audiohook from channel.
Definition: audiohook.c:550
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:446
@ 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:5144
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)) {
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}
@ 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:484

References ast_audiohook_attach(), AST_AUDIOHOOK_MUTE_WRITE, 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 attach_barge(), and do_broadcast().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 609 of file app_broadcast.c.

610{
612}
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().