129 static const char app_broadcast[] =
"Broadcast";
132 OPTION_READONLY = (1 << 0),
133 OPTION_BARGE = (1 << 1),
134 OPTION_LONG_QUEUE = (1 << 2),
135 OPTION_WHISPER = (1 << 3),
136 OPTION_SPY = (1 << 4),
137 OPTION_REVERSE_FEED = (1 << 5),
138 OPTION_ANSWER_WARN = (1 << 6),
157 unsigned int connected:1;
158 unsigned int bridge_connected:1;
159 unsigned int spying:1;
167 unsigned int readonly:1;
170 static void *spy_alloc(
struct ast_channel *chan,
void *data)
175 static void spy_release(
struct ast_channel *chan,
void *data)
180 static int spy_generate(
struct ast_channel *chan,
void *data,
int len,
int samples)
186 short *data1, *data2;
190 static const int num_samples = 160;
191 short combine_buf[num_samples];
196 .datalen = num_samples * 2,
197 .samples = num_samples,
201 memset(&combine_buf, 0,
sizeof(combine_buf));
202 wf.
data.ptr = combine_buf;
205 AST_RWLIST_TRAVERSE_SAFE_BEGIN(chanlist, mac,
entry) {
212 if (multispy->readonly) {
224 for (i = 0, data1 = combine_buf, data2 = f->
data.ptr; i < num_samples; i++, data1++, data2++) {
225 ast_slinear_saturated_add(data1, data2);
229 AST_RWLIST_TRAVERSE_SAFE_END;
240 .release = spy_release,
241 .generate = spy_generate,
249 ast_debug(1,
"Attaching spy channel %s to %s\n", spychan_name, ast_channel_name(autochan->chan));
251 if (ast_test_flag(flags, OPTION_READONLY)) {
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");
262 ast_autochan_channel_unlock(autochan);
267 struct ast_audiohook *bridge_whisper_audiohook,
const char *spyer_name,
const char *name,
struct ast_flags *flags)
276 ast_autochan_channel_unlock(spyee_autochan);
282 ast_debug(9,
"Channel %s is not yet bridged, unable to setup barge\n", ast_channel_name(spyee_chan));
285 ast_clear_flag(flags, OPTION_ANSWER_WARN);
286 ast_log(LOG_WARNING,
"Barge failed: channel is bridged, but not to a 2-party bridge. Use the 'r' option.\n");
293 if (!internal_bridge_autochan) {
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);
302 *spyee_bridge_autochan = internal_bridge_autochan;
308 if (mac->connected) {
310 ast_debug(2,
"Whisper audiohook no longer running\n");
317 if (mac->bridge_connected) {
319 ast_debug(2,
"Whisper (bridged) audiohook no longer running\n");
328 ast_debug(2,
"Spy audiohook no longer running\n");
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));
343 if (mac->bridge_autochan) {
349 static int do_broadcast(
struct ast_channel *chan,
struct ast_flags *flags,
const char *channels)
358 int readonly = ast_test_flag(flags, OPTION_READONLY) ? 1 : 0;
364 ast_set_flag(flags, OPTION_ANSWER_WARN);
369 while ((next = strsep(&chansdup,
","))) {
371 if (ast_strlen_zero(next)) {
374 if (!strcmp(next, ast_channel_name(chan))) {
375 ast_log(LOG_WARNING,
"Refusing to broadcast to ourself: %s\n", next);
380 ast_log(LOG_WARNING,
"No such channel: %s\n", next);
385 ast_log(LOG_WARNING,
"Multi autochan allocation failure\n");
390 if (!mac->name || !mac->autochan) {
391 multi_autochan_free(mac);
394 if (ast_test_flag(flags, OPTION_WHISPER)) {
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);
400 multi_autochan_free(mac);
404 if (ast_test_flag(flags, OPTION_SPY)) {
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);
409 multi_autochan_free(mac);
413 AST_RWLIST_INSERT_TAIL(&chanlist, mac,
entry);
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",
420 ast_test_flag(flags, OPTION_WHISPER) ? 1 : 0,
421 ast_test_flag(flags, OPTION_BARGE) ? 1 : 0,
423 ast_test_flag(flags, OPTION_SPY) ? 1 : 0,
424 readonly ?
"single" :
"both");
426 if (ast_test_flag(flags, OPTION_SPY)) {
427 multispy.chanlist = &chanlist;
428 multispy.readonly = readonly;
439 ast_debug(1,
"Channel %s must have hung up\n", ast_channel_name(chan));
449 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&chanlist, mac,
entry) {
458 AST_RWLIST_REMOVE_CURRENT(
entry);
459 ast_debug(2,
"Looks like %s has hung up\n", mac->name);
460 multi_autochan_free(mac);
462 ast_debug(2,
"%d channel%s remaining in broadcast on %s\n", numchans,
ESS(numchans), ast_channel_name(chan));
466 if (ast_test_flag(flags, OPTION_WHISPER)) {
472 if (ast_test_flag(flags, OPTION_BARGE)) {
480 if (!ast_test_flag(flags, OPTION_REVERSE_FEED) && !mac->bridge_connected && !attach_barge(mac->autochan, &mac->bridge_autochan,
481 &mac->bridge_whisper_audiohook, ast_channel_name(chan), mac->name, flags)) {
482 ast_debug(2,
"Attached barge channel for %s\n", mac->name);
483 mac->bridge_connected = 1;
486 if (mac->bridge_connected) {
490 }
else if (ast_test_flag(flags, OPTION_REVERSE_FEED)) {
527 ast_log(LOG_WARNING,
"Failed to write to audiohook for %s\n", mac->name);
531 AST_RWLIST_TRAVERSE_SAFE_END;
537 ast_debug(1,
"Exiting due to all target channels having left the broadcast\n");
540 if (ast_test_flag(flags, OPTION_SPY)) {
547 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&chanlist, mac,
entry) {
548 AST_RWLIST_REMOVE_CURRENT(
entry);
549 multi_autochan_free(mac);
551 AST_RWLIST_TRAVERSE_SAFE_END;
557 static int broadcast_exec(
struct ast_channel *chan,
const char *data)
568 if (ast_strlen_zero(data)) {
569 ast_log(LOG_WARNING,
"Broadcast requires at least one channel\n");
576 if (ast_strlen_zero(args.channels)) {
577 ast_log(LOG_WARNING,
"Must specify at least one channel for broadcast\n");
583 ast_clear_flag(&flags, AST_FLAGS_ALL);
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");
591 write_format =
ao2_bump(ast_channel_writeformat(chan));
593 ast_log(LOG_ERROR,
"Failed to set write format to slin.\n");
597 res = do_broadcast(chan, &flags, args.channels);
601 ast_log(LOG_ERROR,
"Failed to restore write format for channel %s\n", ast_channel_name(chan));
609 static int unload_module(
void)
614 static int load_module(
void)
619 AST_MODULE_INFO_STANDARD_EXTENDED(
ASTERISK_GPL_KEY,
"Channel Audio Broadcasting");
Main Channel structure associated with a channel.
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
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.
#define ast_autochan_channel_lock(autochan)
Lock the autochan's channel lock.
#define ast_channel_unref(c)
Decrease channel reference count.
int ast_activate_generator(struct ast_channel *chan, struct ast_generator *gen, void *params)
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
void ast_channel_clear_flag(struct ast_channel *chan, unsigned int flag)
Clear a flag on a channel.
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
Attach audiohook to channel.
#define ast_strdup(str)
A wrapper for strdup()
#define AST_RWLIST_HEAD_INIT(head)
Initializes an rwlist head structure.
int ast_unregister_application(const char *app)
Unregister an application.
int ast_audiohook_destroy(struct ast_audiohook *audiohook)
Destroys an audiohook structure.
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
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.
#define ast_audiohook_unlock(ah)
Unlock an audiohook.
static void cleanup(void)
Clean up any old apps that we don't need any more.
General Asterisk PBX channel definitions.
#define ast_strdupa(s)
duplicate a string in memory from the stack
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
#define ast_channel_cleanup(c)
Cleanup a channel reference.
#define ast_debug(level,...)
Log a DEBUG message.
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
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.
Core PBX routines and definitions.
struct ast_silence_generator * ast_channel_start_silence_generator(struct ast_channel *chan)
Starts a silence generator on the given channel.
"smart" channels that update automatically if a channel is masqueraded
int ast_audiohook_detach(struct ast_audiohook *audiohook)
Detach audiohook from channel.
void ast_channel_set_flag(struct ast_channel *chan, unsigned int flag)
Set a flag on a channel.
int ast_channel_is_bridged(const struct ast_channel *chan)
Determine if a channel is in a bridge.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
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.
union ast_frame::@224 data
#define ast_calloc(num, len)
A wrapper for calloc()
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.
Structure used to handle boolean flags.
#define AST_RWLIST_HEAD(name, type)
Defines a structure to be used to hold a read/write list of specified type.
void ast_autochan_destroy(struct ast_autochan *autochan)
destroy an ast_autochan structure
struct ast_autochan * ast_autochan_setup(struct ast_channel *chan)
set up a new ast_autochan structure
void ast_deactivate_generator(struct ast_channel *chan)
struct multi_autochan::@9 entry
#define ast_channel_ref(c)
Increase channel reference count.
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Standard Command Line Interface.
struct ast_channel * ast_channel_bridge_peer(struct ast_channel *chan)
Get the channel's bridge peer only if the bridge is two-party.
Data structure associated with a single frame of data.
Options provided by main asterisk program.
enum ast_audiohook_status status
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
enum ast_frame_type frametype
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
#define ASTERISK_GPL_KEY
The text the key() function should return.
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
#define ast_audiohook_lock(ah)
Lock an audiohook.
Asterisk module definitions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
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.
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
#define AST_APP_ARG(name)
Define an application argument.