Asterisk - The Open Source Telephony Project GIT-master-6144b6b
Loading...
Searching...
No Matches
Data Structures | Macros | Enumerations | Functions | Variables
app_mixmonitor.c File Reference

MixMonitor() - Record a call and mix the audio during the recording. More...

#include "asterisk.h"
#include "asterisk/paths.h"
#include "asterisk/stringfields.h"
#include "asterisk/file.h"
#include "asterisk/audiohook.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/cli.h"
#include "asterisk/app.h"
#include "asterisk/channel.h"
#include "asterisk/autochan.h"
#include "asterisk/manager.h"
#include "asterisk/stasis.h"
#include "asterisk/stasis_channels.h"
#include "asterisk/callerid.h"
#include "asterisk/mod_format.h"
#include "asterisk/linkedlists.h"
#include "asterisk/test.h"
#include "asterisk/mixmonitor.h"
#include "asterisk/format_cache.h"
#include "asterisk/beep.h"
#include "asterisk/translate.h"
Include dependency graph for app_mixmonitor.c:

Go to the source code of this file.

Data Structures

struct  mixmonitor
 
struct  mixmonitor_ds
 
struct  vm_recipient
 

Macros

#define get_volfactor(x)   x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0
 
#define MIN_SKIP_SECONDS   1
 
#define SAMPLES_PER_FRAME   160
 

Enumerations

enum  mixmonitor_args {
  OPT_ARG_READVOLUME = 0 , OPT_ARG_WRITEVOLUME , OPT_ARG_VOLUME , OPT_ARG_WRITENAME ,
  OPT_ARG_READNAME , OPT_ARG_UID , OPT_ARG_VMRECIPIENTS , OPT_ARG_BEEP_INTERVAL ,
  OPT_ARG_DEPRECATED_RWSYNC , OPT_ARG_NO_RWSYNC , OPT_ARG_SKIP , OPT_ARG_ARRAY_SIZE
}
 
enum  mixmonitor_flags {
  MUXFLAG_APPEND = (1 << 1) , MUXFLAG_BRIDGED = (1 << 2) , MUXFLAG_VOLUME = (1 << 3) , MUXFLAG_READVOLUME = (1 << 4) ,
  MUXFLAG_WRITEVOLUME = (1 << 5) , MUXFLAG_READ = (1 << 6) , MUXFLAG_WRITE = (1 << 7) , MUXFLAG_COMBINED = (1 << 8) ,
  MUXFLAG_UID = (1 << 9) , MUXFLAG_VMRECIPIENTS = (1 << 10) , MUXFLAG_BEEP = (1 << 11) , MUXFLAG_BEEP_START = (1 << 12) ,
  MUXFLAG_BEEP_STOP = (1 << 13) , MUXFLAG_DEPRECATED_RWSYNC = (1 << 14) , MUXFLAG_NO_RWSYNC = (1 << 15) , MUXFLAG_AUTO_DELETE = (1 << 16) ,
  MUXFLAG_REAL_CALLERID = (1 << 17) , MUXFLAG_INTERLEAVED = (1 << 18) , MUXFLAG_SKIP = (1 << 19)
}
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
static void add_vm_recipients_from_string (struct mixmonitor *mixmonitor, const char *vm_recipients)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static int clear_mixmonitor_methods (void)
 
static void clear_mixmonitor_recipient_list (struct mixmonitor *mixmonitor)
 
static void copy_to_voicemail (struct mixmonitor *mixmonitor, const char *ext, const char *filename)
 
static void destroy_monitor_audiohook (struct mixmonitor *mixmonitor)
 
static char * filename_parse (char *filename, char *buffer, size_t len)
 
static void fill_frame_buffer (struct ast_frame *source_frame, struct ast_format *target_format, struct ast_format **last_source_format, struct ast_trans_pvt **translator_path, short *dest_buf, size_t dest_buf_size, const char *direction)
 
static int func_mixmonitor_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 
static char * handle_cli_mixmonitor (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static int launch_monitor_thread (struct ast_channel *chan, const char *filename, unsigned int flags, int readvol, int writevol, const char *post_process, const char *filename_write, char *filename_read, const char *uid_channel_var, const char *recipients, const char *beep_id, double skip_seconds)
 
static int load_module (void)
 
static int manager_mixmonitor (struct mansession *s, const struct message *m)
 
static int manager_mute_mixmonitor (struct mansession *s, const struct message *m)
 Mute / unmute a MixMonitor channel.
 
static int manager_stop_mixmonitor (struct mansession *s, const struct message *m)
 
static int mixmonitor_autochan_is_bridged (struct ast_autochan *autochan)
 
static void mixmonitor_ds_close_fs (struct mixmonitor_ds *mixmonitor_ds)
 
static void mixmonitor_ds_destroy (void *data)
 
static void mixmonitor_ds_remove_and_free (struct ast_channel *chan, const char *datastore_id)
 
static int mixmonitor_exec (struct ast_channel *chan, const char *data)
 
static void mixmonitor_free (struct mixmonitor *mixmonitor)
 
static void mixmonitor_save_prep (struct mixmonitor *mixmonitor, char *filename, struct ast_filestream **fs, unsigned int *oflags, int *errflag, char **ext)
 
static void * mixmonitor_thread (void *obj)
 
static int mute_mixmonitor_instance (struct ast_channel *chan, const char *data, enum ast_audiohook_flags flag, int clearmute)
 Mute / unmute an individual MixMonitor by id.
 
static int set_mixmonitor_methods (void)
 
static int setup_mixmonitor_ds (struct mixmonitor *mixmonitor, struct ast_channel *chan, char **datastore_id, const char *beep_id)
 
static int start_mixmonitor_callback (struct ast_channel *chan, const char *filename, const char *options)
 
static int startmon (struct ast_channel *chan, struct ast_audiohook *audiohook)
 
static int stop_mixmonitor_callback (struct ast_channel *chan, const char *mixmonitor_id)
 
static int stop_mixmonitor_exec (struct ast_channel *chan, const char *data)
 
static int stop_mixmonitor_full (struct ast_channel *chan, const char *data)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Mixed Audio Monitoring Application" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .optional_modules = "func_periodic_hook", }
 
static const char *const app = "MixMonitor"
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static struct ast_cli_entry cli_mixmonitor []
 
static const struct ast_datastore_info mixmonitor_ds_info
 
static struct ast_custom_function mixmonitor_function
 
static const struct ast_app_option mixmonitor_opts [128] = { [ 'a' ] = { .flag = MUXFLAG_APPEND }, [ 'b' ] = { .flag = MUXFLAG_BRIDGED }, [ 'B' ] = { .flag = MUXFLAG_BEEP , .arg_index = OPT_ARG_BEEP_INTERVAL + 1 }, [ 'c' ] = { .flag = MUXFLAG_REAL_CALLERID }, [ 'd' ] = { .flag = MUXFLAG_AUTO_DELETE }, [ 'p' ] = { .flag = MUXFLAG_BEEP_START }, [ 'P' ] = { .flag = MUXFLAG_BEEP_STOP }, [ 'v' ] = { .flag = MUXFLAG_READVOLUME , .arg_index = OPT_ARG_READVOLUME + 1 }, [ 'V' ] = { .flag = MUXFLAG_WRITEVOLUME , .arg_index = OPT_ARG_WRITEVOLUME + 1 }, [ 'W' ] = { .flag = MUXFLAG_VOLUME , .arg_index = OPT_ARG_VOLUME + 1 }, [ 'r' ] = { .flag = MUXFLAG_READ , .arg_index = OPT_ARG_READNAME + 1 }, [ 't' ] = { .flag = MUXFLAG_WRITE , .arg_index = OPT_ARG_WRITENAME + 1 }, [ 'D' ] = { .flag = MUXFLAG_INTERLEAVED }, [ 'i' ] = { .flag = MUXFLAG_UID , .arg_index = OPT_ARG_UID + 1 }, [ 'm' ] = { .flag = MUXFLAG_VMRECIPIENTS , .arg_index = OPT_ARG_VMRECIPIENTS + 1 }, [ 'S' ] = { .flag = MUXFLAG_DEPRECATED_RWSYNC , .arg_index = OPT_ARG_DEPRECATED_RWSYNC + 1 }, [ 'n' ] = { .flag = MUXFLAG_NO_RWSYNC , .arg_index = OPT_ARG_NO_RWSYNC + 1 }, [ 's' ] = { .flag = MUXFLAG_SKIP , .arg_index = OPT_ARG_SKIP + 1 }, }
 
static const char *const mixmonitor_spy_type = "MixMonitor"
 
static const char *const stop_app = "StopMixMonitor"
 

Detailed Description

MixMonitor() - Record a call and mix the audio during the recording.

Author
Mark Spencer marks.nosp@m.ter@.nosp@m.digiu.nosp@m.m.co.nosp@m.m
Kevin P. Fleming kpfle.nosp@m.ming.nosp@m.@digi.nosp@m.um.c.nosp@m.om
Note
Based on app_muxmon.c provided by Anthony Minessale II anthm.nosp@m.ct@y.nosp@m.ahoo..nosp@m.com

Definition in file app_mixmonitor.c.

Macro Definition Documentation

◆ get_volfactor

#define get_volfactor (   x)    x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0

Definition at line 402 of file app_mixmonitor.c.

◆ MIN_SKIP_SECONDS

#define MIN_SKIP_SECONDS   1

Definition at line 404 of file app_mixmonitor.c.

◆ SAMPLES_PER_FRAME

#define SAMPLES_PER_FRAME   160

Definition at line 669 of file app_mixmonitor.c.

Enumeration Type Documentation

◆ mixmonitor_args

Enumerator
OPT_ARG_READVOLUME 
OPT_ARG_WRITEVOLUME 
OPT_ARG_VOLUME 
OPT_ARG_WRITENAME 
OPT_ARG_READNAME 
OPT_ARG_UID 
OPT_ARG_VMRECIPIENTS 
OPT_ARG_BEEP_INTERVAL 
OPT_ARG_DEPRECATED_RWSYNC 
OPT_ARG_NO_RWSYNC 
OPT_ARG_SKIP 
OPT_ARG_ARRAY_SIZE 

Definition at line 474 of file app_mixmonitor.c.

474 {
486 OPT_ARG_ARRAY_SIZE, /* Always last element of the enum */
487};
@ OPT_ARG_SKIP
@ OPT_ARG_WRITEVOLUME
@ OPT_ARG_UID
@ OPT_ARG_VMRECIPIENTS
@ OPT_ARG_DEPRECATED_RWSYNC
@ OPT_ARG_NO_RWSYNC
@ OPT_ARG_WRITENAME
@ OPT_ARG_READNAME
@ OPT_ARG_BEEP_INTERVAL
@ OPT_ARG_READVOLUME
@ OPT_ARG_VOLUME
@ OPT_ARG_ARRAY_SIZE

◆ mixmonitor_flags

Enumerator
MUXFLAG_APPEND 
MUXFLAG_BRIDGED 
MUXFLAG_VOLUME 
MUXFLAG_READVOLUME 
MUXFLAG_WRITEVOLUME 
MUXFLAG_READ 
MUXFLAG_WRITE 
MUXFLAG_COMBINED 
MUXFLAG_UID 
MUXFLAG_VMRECIPIENTS 
MUXFLAG_BEEP 
MUXFLAG_BEEP_START 
MUXFLAG_BEEP_STOP 
MUXFLAG_DEPRECATED_RWSYNC 
MUXFLAG_NO_RWSYNC 
MUXFLAG_AUTO_DELETE 
MUXFLAG_REAL_CALLERID 
MUXFLAG_INTERLEAVED 
MUXFLAG_SKIP 

Definition at line 452 of file app_mixmonitor.c.

452 {
453 MUXFLAG_APPEND = (1 << 1),
454 MUXFLAG_BRIDGED = (1 << 2),
455 MUXFLAG_VOLUME = (1 << 3),
456 MUXFLAG_READVOLUME = (1 << 4),
457 MUXFLAG_WRITEVOLUME = (1 << 5),
458 MUXFLAG_READ = (1 << 6),
459 MUXFLAG_WRITE = (1 << 7),
460 MUXFLAG_COMBINED = (1 << 8),
461 MUXFLAG_UID = (1 << 9),
462 MUXFLAG_VMRECIPIENTS = (1 << 10),
463 MUXFLAG_BEEP = (1 << 11),
464 MUXFLAG_BEEP_START = (1 << 12),
465 MUXFLAG_BEEP_STOP = (1 << 13),
466 MUXFLAG_DEPRECATED_RWSYNC = (1 << 14),
467 MUXFLAG_NO_RWSYNC = (1 << 15),
468 MUXFLAG_AUTO_DELETE = (1 << 16),
469 MUXFLAG_REAL_CALLERID = (1 << 17),
470 MUXFLAG_INTERLEAVED = (1 << 18),
471 MUXFLAG_SKIP = (1 << 19),
472};
@ MUXFLAG_SKIP
@ MUXFLAG_VMRECIPIENTS
@ MUXFLAG_READ
@ MUXFLAG_AUTO_DELETE
@ MUXFLAG_DEPRECATED_RWSYNC
@ MUXFLAG_REAL_CALLERID
@ MUXFLAG_WRITEVOLUME
@ MUXFLAG_INTERLEAVED
@ MUXFLAG_NO_RWSYNC
@ MUXFLAG_VOLUME
@ MUXFLAG_BEEP_STOP
@ MUXFLAG_UID
@ MUXFLAG_APPEND
@ MUXFLAG_BEEP_START
@ MUXFLAG_WRITE
@ MUXFLAG_COMBINED
@ MUXFLAG_BEEP
@ MUXFLAG_BRIDGED
@ MUXFLAG_READVOLUME

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 2033 of file app_mixmonitor.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 2033 of file app_mixmonitor.c.

◆ add_vm_recipients_from_string()

static void add_vm_recipients_from_string ( struct mixmonitor mixmonitor,
const char *  vm_recipients 
)
static

Definition at line 611 of file app_mixmonitor.c.

612{
613 /* recipients are in a single string with a format format resembling "mailbox@context/INBOX,mailbox2@context2,mailbox3@context3/Work" */
614 char *cur_mailbox = ast_strdupa(vm_recipients);
615 char *cur_context;
616 char *cur_folder;
617 char *next;
618 int elements_processed = 0;
619
620 while (!ast_strlen_zero(cur_mailbox)) {
621 ast_debug(3, "attempting to add next element %d from %s\n", elements_processed, cur_mailbox);
622 if ((next = strchr(cur_mailbox, ',')) || (next = strchr(cur_mailbox, '&'))) {
623 *(next++) = '\0';
624 }
625
626 if ((cur_folder = strchr(cur_mailbox, '/'))) {
627 *(cur_folder++) = '\0';
628 } else {
629 cur_folder = "INBOX";
630 }
631
632 if ((cur_context = strchr(cur_mailbox, '@'))) {
633 *(cur_context++) = '\0';
634 } else {
635 cur_context = "default";
636 }
637
638 if (!ast_strlen_zero(cur_mailbox) && !ast_strlen_zero(cur_context)) {
639 struct vm_recipient *recipient;
640 if (!(recipient = ast_malloc(sizeof(*recipient)))) {
641 ast_log(LOG_ERROR, "Failed to allocate recipient. Aborting function.\n");
642 return;
643 }
644 ast_copy_string(recipient->context, cur_context, sizeof(recipient->context));
645 ast_copy_string(recipient->mailbox, cur_mailbox, sizeof(recipient->mailbox));
646 ast_copy_string(recipient->folder, cur_folder, sizeof(recipient->folder));
647
648 /* Add to list */
649 ast_verb(4, "Adding %s@%s to recipient list\n", recipient->mailbox, recipient->context);
651 } else {
652 ast_log(LOG_ERROR, "Failed to properly parse extension and/or context from element %d of recipient string: %s\n", elements_processed, vm_recipients);
653 }
654
655 cur_mailbox = next;
656 elements_processed++;
657 }
658}
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
#define ast_malloc(len)
A wrapper for malloc()
Definition astmm.h:191
#define ast_log
Definition astobj2.c:42
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define ast_verb(level,...)
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition strings.h:425
struct mixmonitor::@43 recipient_list
char mailbox[AST_MAX_CONTEXT]
char context[AST_MAX_EXTENSION]
struct vm_recipient::@42 list
struct vm_recipient * next

References ast_copy_string(), ast_debug, AST_LIST_INSERT_HEAD, ast_log, ast_malloc, ast_strdupa, ast_strlen_zero(), ast_verb, vm_recipient::context, vm_recipient::folder, vm_recipient::list, LOG_ERROR, vm_recipient::mailbox, vm_recipient::next, and mixmonitor::recipient_list.

Referenced by launch_monitor_thread().

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 2033 of file app_mixmonitor.c.

◆ clear_mixmonitor_methods()

static int clear_mixmonitor_methods ( void  )
static

Definition at line 1991 of file app_mixmonitor.c.

1992{
1994}
int ast_clear_mixmonitor_methods(void)
Clear the MixMonitor virtual methods table. Use this to cleanup function pointers provided by a modul...
Definition mixmonitor.c:59

References ast_clear_mixmonitor_methods().

Referenced by unload_module().

◆ clear_mixmonitor_recipient_list()

static void clear_mixmonitor_recipient_list ( struct mixmonitor mixmonitor)
static

Definition at line 660 of file app_mixmonitor.c.

661{
662 struct vm_recipient *current;
664 /* Clear list element data */
666 }
667}
#define ast_free(a)
Definition astmm.h:180
size_t current
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.

References ast_free, AST_LIST_REMOVE_HEAD, current, vm_recipient::list, and mixmonitor::recipient_list.

Referenced by mixmonitor_free().

◆ copy_to_voicemail()

static void copy_to_voicemail ( struct mixmonitor mixmonitor,
const char *  ext,
const char *  filename 
)
static

Definition at line 778 of file app_mixmonitor.c.

779{
780 struct vm_recipient *recipient = NULL;
783 ast_log(LOG_ERROR, "Failed to string_field_init, skipping copy_to_voicemail\n");
784 return;
785 }
786
787 /* Copy strings to stringfields that will be used for all recipients */
794 /* and call_priority gets copied too */
795 recording_data.call_priority = mixmonitor->call_priority;
796
797 AST_LIST_TRAVERSE(&mixmonitor->recipient_list, recipient, list) {
798 /* context, mailbox, and folder need to be set per recipient */
802
803 ast_verb(4, "MixMonitor attempting to send voicemail copy to %s@%s\n", recording_data.mailbox,
804 recording_data.context);
806 }
807
808 /* Free the string fields for recording_data before exiting the function. */
810}
const char * ext
Definition http.c:151
int ast_app_copy_recording_to_vm(struct ast_vm_recording_data *vm_rec_data)
param[in] vm_rec_data Contains data needed to make the recording. retval 0 voicemail successfully cre...
Definition main/app.c:596
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define NULL
Definition resample.c:96
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Structure used for ast_copy_recording_to_vm in order to cleanly supply data needed for making the rec...
const ast_string_field recording_file
const ast_string_field call_callerchan
const ast_string_field context
const ast_string_field folder
const ast_string_field call_callerid
const ast_string_field call_context
const ast_string_field recording_ext
const ast_string_field call_extension
const ast_string_field mailbox
const ast_string_field call_callerchan
const ast_string_field call_callerid
const ast_string_field call_context
const ast_string_field call_extension

References ast_app_copy_recording_to_vm(), AST_LIST_TRAVERSE, ast_log, ast_string_field_free_memory, ast_string_field_init, ast_string_field_set, ast_verb, mixmonitor::call_callerchan, ast_vm_recording_data::call_callerchan, mixmonitor::call_callerid, ast_vm_recording_data::call_callerid, mixmonitor::call_context, ast_vm_recording_data::call_context, mixmonitor::call_extension, ast_vm_recording_data::call_extension, mixmonitor::call_priority, vm_recipient::context, ast_vm_recording_data::context, ext, vm_recipient::folder, ast_vm_recording_data::folder, LOG_ERROR, vm_recipient::mailbox, ast_vm_recording_data::mailbox, NULL, mixmonitor::recipient_list, ast_vm_recording_data::recording_ext, and ast_vm_recording_data::recording_file.

Referenced by mixmonitor_thread().

◆ destroy_monitor_audiohook()

static void destroy_monitor_audiohook ( struct mixmonitor mixmonitor)
static

Definition at line 582 of file app_mixmonitor.c.

583{
588 }
589 /* kill the audiohook.*/
594}
#define ast_audiohook_lock(ah)
Lock an audiohook.
Definition audiohook.h:316
int ast_audiohook_detach(struct ast_audiohook *audiohook)
Detach audiohook from channel.
Definition audiohook.c:587
int ast_audiohook_destroy(struct ast_audiohook *audiohook)
Destroys an audiohook structure.
Definition audiohook.c:124
#define ast_audiohook_unlock(ah)
Unlock an audiohook.
Definition audiohook.h:321
#define ast_mutex_unlock(a)
Definition lock.h:197
#define ast_mutex_lock(a)
Definition lock.h:196
struct ast_audiohook * audiohook
ast_mutex_t lock
struct ast_audiohook audiohook
struct mixmonitor_ds * mixmonitor_ds

References ast_audiohook_destroy(), ast_audiohook_detach(), ast_audiohook_lock, ast_audiohook_unlock, ast_mutex_lock, ast_mutex_unlock, mixmonitor::audiohook, mixmonitor_ds::audiohook, mixmonitor_ds::lock, mixmonitor::mixmonitor_ds, and NULL.

Referenced by mixmonitor_thread().

◆ filename_parse()

static char * filename_parse ( char *  filename,
char *  buffer,
size_t  len 
)
static

Definition at line 1329 of file app_mixmonitor.c.

1330{
1331 char *slash;
1332 char *ext;
1333
1334 ast_assert(len > 0);
1335
1336 if (ast_strlen_zero(filename)) {
1337 ast_log(LOG_WARNING, "No file name was provided for a file save option.\n");
1338 buffer[0] = 0;
1339 return buffer;
1340 }
1341
1342 /* If we don't have an absolute path, make one */
1343 if (*filename != '/') {
1344 char *build = ast_alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(filename) + 3);
1345 sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, filename);
1346 filename = build;
1347 }
1348
1349 ast_copy_string(buffer, filename, len);
1350
1351 /* If the provided filename has a .wav49 extension, we need to convert it to .WAV to
1352 match the behavior of build_filename in main/file.c. Otherwise MIXMONITOR_FILENAME
1353 ends up referring to a file that does not/will not exist */
1354 ext = strrchr(buffer, '.');
1355 if (ext && !strcmp(ext, ".wav49")) {
1356 /* Change to WAV - we know we have at least 6 writeable bytes where 'ext' points,
1357 * so this is safe */
1358 memcpy(ext, ".WAV", sizeof(".WAV"));
1359 }
1360
1361 if ((slash = strrchr(filename, '/'))) {
1362 *slash = '\0';
1363 }
1364 ast_mkdir(filename, 0777);
1365
1366 return buffer;
1367}
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition astmm.h:288
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define LOG_WARNING
const char * ast_config_AST_MONITOR_DIR
Definition options.c:156
#define ast_assert(a)
Definition utils.h:779
int ast_mkdir(const char *path, int mode)
Recursively create directory path.
Definition utils.c:2513

References ast_alloca, ast_assert, ast_config_AST_MONITOR_DIR, ast_copy_string(), ast_log, ast_mkdir(), ast_strlen_zero(), ext, len(), and LOG_WARNING.

Referenced by mixmonitor_exec().

◆ fill_frame_buffer()

static void fill_frame_buffer ( struct ast_frame source_frame,
struct ast_format target_format,
struct ast_format **  last_source_format,
struct ast_trans_pvt **  translator_path,
short *  dest_buf,
size_t  dest_buf_size,
const char *  direction 
)
static

Definition at line 672 of file app_mixmonitor.c.

679{
680 struct ast_frame *converted_frame = NULL;
681
682 if (!source_frame) {
683 memset(dest_buf, 0, dest_buf_size);
684 return;
685 }
686
687 /*
688 * We only need to worry about translating if the frame format does not match
689 * the expected format of the frame we are writing.
690 */
691 if (ast_format_cmp(target_format, source_frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
692 /*
693 * If the format changed from the last frame or if this is the first frame
694 * that does not match the native format, we need to set up a new
695 * translator path.
696 */
697 if (ast_format_cmp(*last_source_format, source_frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL
698 || !*translator_path) {
699 ast_debug(3, "%s frame format changed from %s to %s, building translator path to %s\n",
700 direction,
701 *last_source_format ? ast_format_get_name(*last_source_format) : "none",
702 ast_format_get_name(source_frame->subclass.format),
703 ast_format_get_name(target_format));
704
705 if (*translator_path) {
707 }
708
709 *translator_path = ast_translator_build_path(target_format, source_frame->subclass.format);
710 }
711
712 if (*translator_path) {
713 converted_frame = ast_translate(*translator_path, source_frame, 0);
714 }
715
716 /*
717 * If creating the translated frame or translator path failed, write silence for this frame. We will
718 * try rebuilding the translator path later if it is still needed.
719 */
720 if (converted_frame) {
721 memcpy(dest_buf, converted_frame->data.ptr, dest_buf_size);
722 ast_frame_free(converted_frame, 1);
723 } else {
724 memset(dest_buf, 0, dest_buf_size);
725 }
726 } else {
727 memcpy(dest_buf, source_frame->data.ptr, dest_buf_size);
728
729 /*
730 * If we are doing native frame copying, we can free the translator path if
731 * it exists. We will create a new one later if needed.
732 */
733 if (*translator_path) {
736 ast_debug(3, "%s frame format changed from %s to %s, translator path no longer needed\n",
737 direction,
738 *last_source_format ? ast_format_get_name(*last_source_format) : "none",
739 ast_format_get_name(source_frame->subclass.format));
740 }
741 }
742
743 *last_source_format = source_frame->subclass.format;
744}
enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
Compare two formats.
Definition format.c:201
@ AST_FORMAT_CMP_NOT_EQUAL
Definition format.h:38
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition format.c:334
direction
void ast_frame_free(struct ast_frame *frame, int cache)
Frees a frame or list of frames.
Definition main/frame.c:176
struct ast_format * format
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
union ast_frame::@237 data
struct ast_frame * ast_translate(struct ast_trans_pvt *tr, struct ast_frame *f, int consume)
translates one or more frames Apply an input frame into the translator and receive zero or one output...
Definition translate.c:623
void ast_translator_free_path(struct ast_trans_pvt *tr)
Frees a translator path Frees the given translator path structure.
Definition translate.c:533
struct ast_trans_pvt * ast_translator_build_path(struct ast_format *dest, struct ast_format *source)
Builds a translator path Build a path (possibly NULL) from source to dest.
Definition translate.c:543

References ast_debug, ast_format_cmp(), AST_FORMAT_CMP_NOT_EQUAL, ast_format_get_name(), ast_frame_free(), ast_translate(), ast_translator_build_path(), ast_translator_free_path(), ast_frame::data, ast_frame_subclass::format, NULL, ast_frame::ptr, and ast_frame::subclass.

Referenced by mixmonitor_thread().

◆ func_mixmonitor_read()

static int func_mixmonitor_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
)
static

Definition at line 1934 of file app_mixmonitor.c.

1936{
1937 struct ast_datastore *datastore;
1938 struct mixmonitor_ds *ds_data;
1940 AST_APP_ARG(id);
1941 AST_APP_ARG(key);
1942 );
1943
1945
1946 if (ast_strlen_zero(args.id) || ast_strlen_zero(args.key)) {
1947 ast_log(LOG_WARNING, "Not enough arguments provided to %s. "
1948 "An ID and key must be provided\n", cmd);
1949 return -1;
1950 }
1951
1952 ast_channel_lock(chan);
1953 datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, args.id);
1954 ast_channel_unlock(chan);
1955
1956 if (!datastore) {
1957 ast_log(LOG_WARNING, "Could not find MixMonitor with ID %s\n", args.id);
1958 return -1;
1959 }
1960
1961 ds_data = datastore->data;
1962
1963 if (!strcasecmp(args.key, "filename")) {
1964 ast_copy_string(buf, ds_data->filename, len);
1965 } else {
1966 ast_log(LOG_WARNING, "Unrecognized %s option %s\n", cmd, args.key);
1967 return -1;
1968 }
1969 return 0;
1970}
static const struct ast_datastore_info mixmonitor_ds_info
#define ast_channel_lock(chan)
Definition channel.h:2983
#define ast_channel_unlock(chan)
Definition channel.h:2984
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition channel.c:2390
char buf[BUFSIZE]
Definition eagi_proxy.c:66
#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.
static struct @522 args
Structure for a data store object.
Definition datastore.h:64
void * data
Definition datastore.h:66

References args, AST_APP_ARG, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_copy_string(), AST_DECLARE_APP_ARGS, ast_log, AST_STANDARD_APP_ARGS, ast_strlen_zero(), buf, ast_datastore::data, mixmonitor_ds::filename, len(), LOG_WARNING, and mixmonitor_ds_info.

◆ handle_cli_mixmonitor()

static char * handle_cli_mixmonitor ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 1609 of file app_mixmonitor.c.

1610{
1611 struct ast_channel *chan;
1612 struct ast_datastore *datastore = NULL;
1614
1615 switch (cmd) {
1616 case CLI_INIT:
1617 e->command = "mixmonitor {start|stop|list}";
1618 e->usage =
1619 "Usage: mixmonitor start <chan_name> [args]\n"
1620 " The optional arguments are passed to the MixMonitor application.\n"
1621 " mixmonitor stop <chan_name> [args]\n"
1622 " The optional arguments are passed to the StopMixMonitor application.\n"
1623 " mixmonitor list <chan_name>\n";
1624 return NULL;
1625 case CLI_GENERATE:
1626 return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
1627 }
1628
1629 if (a->argc < 3) {
1630 return CLI_SHOWUSAGE;
1631 }
1632
1633 if (!(chan = ast_channel_get_by_name_prefix(a->argv[2], strlen(a->argv[2])))) {
1634 ast_cli(a->fd, "No channel matching '%s' found.\n", a->argv[2]);
1635 /* Technically this is a failure, but we don't want 2 errors printing out */
1636 return CLI_SUCCESS;
1637 }
1638
1639 if (!strcasecmp(a->argv[1], "start")) {
1640 mixmonitor_exec(chan, (a->argc >= 4) ? a->argv[3] : "");
1641 } else if (!strcasecmp(a->argv[1], "stop")){
1642 stop_mixmonitor_exec(chan, (a->argc >= 4) ? a->argv[3] : "");
1643 } else if (!strcasecmp(a->argv[1], "list")) {
1644 ast_cli(a->fd, "MixMonitor ID\tFile\tReceive File\tTransmit File\n");
1645 ast_cli(a->fd, "=========================================================================\n");
1646 ast_channel_lock(chan);
1647 AST_LIST_TRAVERSE(ast_channel_datastores(chan), datastore, entry) {
1648 if (datastore->info == &mixmonitor_ds_info) {
1649 char *filename = "";
1650 char *filename_read = "";
1651 char *filename_write = "";
1652
1653 mixmonitor_ds = datastore->data;
1654 if (mixmonitor_ds->fs) {
1656 }
1657 if (mixmonitor_ds->fs_read) {
1658 filename_read = mixmonitor_ds->fs_read->filename;
1659 }
1660 if (mixmonitor_ds->fs_write) {
1661 filename_write = mixmonitor_ds->fs_write->filename;
1662 }
1663 ast_cli(a->fd, "%p\t%s\t%s\t%s\n", mixmonitor_ds, filename, filename_read, filename_write);
1664 }
1665 }
1666 ast_channel_unlock(chan);
1667 } else {
1668 chan = ast_channel_unref(chan);
1669 return CLI_SHOWUSAGE;
1670 }
1671
1672 chan = ast_channel_unref(chan);
1673
1674 return CLI_SUCCESS;
1675}
static int mixmonitor_exec(struct ast_channel *chan, const char *data)
static int stop_mixmonitor_exec(struct ast_channel *chan, const char *data)
struct ast_channel * ast_channel_get_by_name_prefix(const char *name, size_t name_len)
Find a channel by a name prefix.
Definition channel.c:1400
#define ast_channel_unref(c)
Decrease channel reference count.
Definition channel.h:3019
struct ast_datastore_list * ast_channel_datastores(struct ast_channel *chan)
#define CLI_SHOWUSAGE
Definition cli.h:45
#define CLI_SUCCESS
Definition cli.h:44
void ast_cli(int fd, const char *fmt,...)
Definition clicompat.c:6
char * ast_complete_channels(const char *line, const char *word, int pos, int state, int rpos)
Command completion for the list of active channels.
Definition main/cli.c:1950
@ CLI_INIT
Definition cli.h:152
@ CLI_GENERATE
Definition cli.h:153
Main Channel structure associated with a channel.
char * command
Definition cli.h:186
const char * usage
Definition cli.h:177
const struct ast_datastore_info * info
Definition datastore.h:67
struct ast_filestream * fs_read
struct ast_filestream * fs_write
struct ast_filestream * fs
static struct test_val a

References a, ast_channel_datastores(), ast_channel_get_by_name_prefix(), ast_channel_lock, ast_channel_unlock, ast_channel_unref, ast_cli(), ast_complete_channels(), AST_LIST_TRAVERSE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_datastore::data, mixmonitor_ds::filename, ast_filestream::filename, mixmonitor_ds::fs, mixmonitor_ds::fs_read, mixmonitor_ds::fs_write, ast_datastore::info, mixmonitor_ds_info, mixmonitor_exec(), NULL, stop_mixmonitor_exec(), and ast_cli_entry::usage.

◆ launch_monitor_thread()

static int launch_monitor_thread ( struct ast_channel chan,
const char *  filename,
unsigned int  flags,
int  readvol,
int  writevol,
const char *  post_process,
const char *  filename_write,
char *  filename_read,
const char *  uid_channel_var,
const char *  recipients,
const char *  beep_id,
double  skip_seconds 
)
static

Definition at line 1170 of file app_mixmonitor.c.

1175{
1176 pthread_t thread;
1177 struct mixmonitor *mixmonitor;
1178 char postprocess2[1024] = "";
1179 char *datastore_id = NULL;
1180
1181 postprocess2[0] = 0;
1182 /* If a post process system command is given attach it to the structure */
1184 char *p1, *p2;
1185
1187 for (p2 = p1; *p2; p2++) {
1188 if (*p2 == '^' && *(p2+1) == '{') {
1189 *p2 = '$';
1190 }
1191 }
1192 ast_channel_lock(chan);
1193 pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1);
1194 ast_channel_unlock(chan);
1195 }
1196
1197 /* Pre-allocate mixmonitor structure and spy */
1198 if (!(mixmonitor = ast_calloc(1, sizeof(*mixmonitor)))) {
1199 return -1;
1200 }
1201
1202 /* Now that the struct has been calloced, go ahead and initialize the string fields. */
1205 return -1;
1206 }
1207
1208 /* Setup the actual spy before creating our thread */
1211 return -1;
1212 }
1213
1214 /* Copy over flags and channel name */
1217 if (!(mixmonitor->autochan = ast_autochan_setup(chan))) {
1219 return -1;
1220 }
1221
1222 if (!ast_strlen_zero(filename)) {
1224 }
1225
1228 }
1229
1232 }
1233
1234 if (setup_mixmonitor_ds(mixmonitor, chan, &datastore_id, beep_id)) {
1237 ast_free(datastore_id);
1238 return -1;
1239 }
1240
1241 if (!ast_strlen_zero(uid_channel_var)) {
1242 if (datastore_id) {
1243 pbx_builtin_setvar_helper(chan, uid_channel_var, datastore_id);
1244 }
1245 }
1246
1248
1249 if (!ast_strlen_zero(postprocess2)) {
1250 mixmonitor->post_process = ast_strdup(postprocess2);
1251 }
1252
1253 if (!ast_strlen_zero(recipients)) {
1254 char callerid[256];
1255
1256 ast_channel_lock(chan);
1257
1258 /* We use the connected line of the invoking channel for caller ID,
1259 * unless we've been told to use the Caller ID.
1260 * The initial use for this relied on Connected Line to get the
1261 * actual number for recording with Digium phones,
1262 * but in generic use the Caller ID is likely what people want.
1263 */
1264
1266 struct ast_party_caller *caller;
1267 caller = ast_channel_caller(chan);
1268 ast_debug(3, "Caller ID = %d - %s : %d - %s\n", caller->id.name.valid,
1269 caller->id.name.str, caller->id.number.valid,
1270 caller->id.number.str);
1271 ast_callerid_merge(callerid, sizeof(callerid),
1272 S_COR(caller->id.name.valid, caller->id.name.str, NULL),
1273 S_COR(caller->id.number.valid, caller->id.number.str, NULL),
1274 "Unknown");
1275 } else {
1278 ast_debug(3, "Connected Line CID = %d - %s : %d - %s\n", connected->id.name.valid,
1279 connected->id.name.str, connected->id.number.valid,
1280 connected->id.number.str);
1281 ast_callerid_merge(callerid, sizeof(callerid),
1282 S_COR(connected->id.name.valid, connected->id.name.str, NULL),
1283 S_COR(connected->id.number.valid, connected->id.number.str, NULL),
1284 "Unknown");
1285 }
1286
1288 ast_string_field_set(mixmonitor, call_extension, ast_channel_exten(chan));
1289 ast_string_field_set(mixmonitor, call_callerchan, ast_channel_name(chan));
1290 ast_string_field_set(mixmonitor, call_callerid, callerid);
1292
1293 ast_channel_unlock(chan);
1294
1296 }
1297
1301 }
1302
1303 if (readvol)
1305 if (writevol)
1307
1308 if (startmon(chan, &mixmonitor->audiohook)) {
1309 ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n",
1311 mixmonitor_ds_remove_and_free(chan, datastore_id);
1312 ast_free(datastore_id);
1316 return -1;
1317 }
1318
1319 ast_free(datastore_id);
1320
1321 /* reference be released at mixmonitor destruction */
1323
1325}
static void mixmonitor_free(struct mixmonitor *mixmonitor)
static void * mixmonitor_thread(void *obj)
static void mixmonitor_ds_remove_and_free(struct ast_channel *chan, const char *datastore_id)
static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel *chan, char **datastore_id, const char *beep_id)
static int startmon(struct ast_channel *chan, struct ast_audiohook *audiohook)
static const char *const mixmonitor_spy_type
static void add_vm_recipients_from_string(struct mixmonitor *mixmonitor, const char *vm_recipients)
pthread_t thread
Definition app_sla.c:335
#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_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_SUBSTITUTE_SILENCE
Definition audiohook.h:68
@ AST_AUDIOHOOK_TRIGGER_SYNC
Definition audiohook.h:59
@ AST_AUDIOHOOK_TYPE_SPY
Definition audiohook.h:36
struct ast_autochan * ast_autochan_setup(struct ast_channel *chan)
set up a new ast_autochan structure
Definition autochan.c:38
void ast_autochan_destroy(struct ast_autochan *autochan)
destroy an ast_autochan structure
Definition autochan.c:64
char * ast_callerid_merge(char *buf, int bufsiz, const char *name, const char *num, const char *unknown)
Definition callerid.c:1273
static int connected
Definition cdr_pgsql.c:73
const char * ast_channel_name(const struct ast_channel *chan)
int ast_channel_priority(const struct ast_channel *chan)
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
const char * ast_channel_context(const struct ast_channel *chan)
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
const char * ast_channel_exten(const struct ast_channel *chan)
ast_callid ast_read_threadstorage_callid(void)
extracts the callid from the thread
Definition logger.c:2268
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
Definition ael_main.c:211
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition strings.h:87
struct ast_audiohook_options options
Definition audiohook.h:119
Caller Party information.
Definition channel.h:420
struct ast_party_id id
Caller party ID.
Definition channel.h:422
Connected Line/Party information.
Definition channel.h:458
struct ast_party_name name
Subscriber name.
Definition channel.h:342
struct ast_party_number number
Subscriber phone number.
Definition channel.h:344
unsigned char valid
TRUE if the name information is valid/present.
Definition channel.h:281
char * str
Subscriber name (Malloced)
Definition channel.h:266
unsigned char valid
TRUE if the number information is valid/present.
Definition channel.h:299
char * str
Subscriber phone number (Malloced)
Definition channel.h:293
char * filename_write
ast_callid callid
struct ast_autochan * autochan
char * post_process
char * filename_read
double skip_seconds
unsigned int flags
#define ast_test_flag(p, flag)
Definition utils.h:64
#define ast_pthread_create_detached_background(a, b, c, d)
Definition utils.h:637
#define ast_set_flag(p, flag)
Definition utils.h:71

References add_vm_recipients_from_string(), ast_audiohook_destroy(), ast_audiohook_init(), AST_AUDIOHOOK_SUBSTITUTE_SILENCE, AST_AUDIOHOOK_TRIGGER_SYNC, AST_AUDIOHOOK_TYPE_SPY, ast_autochan_destroy(), ast_autochan_setup(), ast_callerid_merge(), ast_calloc, ast_channel_caller(), ast_channel_connected(), ast_channel_context(), ast_channel_exten(), ast_channel_lock, ast_channel_name(), ast_channel_priority(), ast_channel_unlock, ast_debug, ast_free, ast_log, ast_pthread_create_detached_background, ast_read_threadstorage_callid(), ast_set_flag, ast_strdup, ast_strdupa, ast_string_field_init, ast_string_field_set, ast_strlen_zero(), ast_test_flag, mixmonitor::audiohook, mixmonitor::autochan, mixmonitor::call_priority, mixmonitor::callid, connected, mixmonitor::filename, mixmonitor::filename_read, mixmonitor::filename_write, mixmonitor::flags, ast_party_caller::id, LOG_WARNING, mixmonitor_ds_remove_and_free(), mixmonitor_free(), mixmonitor_spy_type, mixmonitor_thread(), MUXFLAG_NO_RWSYNC, MUXFLAG_REAL_CALLERID, mixmonitor::name, ast_party_id::name, NULL, ast_party_id::number, ast_audiohook::options, pbx_builtin_setvar_helper(), pbx_substitute_variables_helper(), mixmonitor::post_process, ast_audiohook_options::read_volume, S_COR, setup_mixmonitor_ds(), mixmonitor::skip_seconds, startmon(), ast_party_name::str, ast_party_number::str, thread, ast_party_name::valid, ast_party_number::valid, and ast_audiohook_options::write_volume.

Referenced by mixmonitor_exec().

◆ load_module()

static int load_module ( void  )
static

Definition at line 2012 of file app_mixmonitor.c.

2013{
2014 int res;
2015
2023 res |= set_mixmonitor_methods();
2024
2025 return res;
2026}
static int manager_stop_mixmonitor(struct mansession *s, const struct message *m)
static struct ast_cli_entry cli_mixmonitor[]
static struct ast_custom_function mixmonitor_function
static int set_mixmonitor_methods(void)
static const char *const app
static int manager_mute_mixmonitor(struct mansession *s, const struct message *m)
Mute / unmute a MixMonitor channel.
static const char *const stop_app
static int manager_mixmonitor(struct mansession *s, const struct message *m)
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition cli.h:265
#define EVENT_FLAG_SYSTEM
Definition manager.h:75
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition manager.h:193
#define EVENT_FLAG_CALL
Definition manager.h:76
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition module.h:640
#define ast_custom_function_register(acf)
Register a custom function.
Definition pbx.h:1563
#define ARRAY_LEN(a)
Definition utils.h:706

References app, ARRAY_LEN, ast_cli_register_multiple, ast_custom_function_register, ast_manager_register_xml, ast_register_application_xml, cli_mixmonitor, EVENT_FLAG_CALL, EVENT_FLAG_SYSTEM, manager_mixmonitor(), manager_mute_mixmonitor(), manager_stop_mixmonitor(), mixmonitor_exec(), mixmonitor_function, set_mixmonitor_methods(), ast_mixmonitor_methods::start, stop_app, and stop_mixmonitor_exec().

◆ manager_mixmonitor()

static int manager_mixmonitor ( struct mansession s,
const struct message m 
)
static

Definition at line 1830 of file app_mixmonitor.c.

1831{
1832 struct ast_channel *c;
1833 const char *name = astman_get_header(m, "Channel");
1834 const char *id = astman_get_header(m, "ActionID");
1835 const char *file = astman_get_header(m, "File");
1836 const char *options = astman_get_header(m, "Options");
1837 const char *command = astman_get_header(m, "Command");
1838 char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
1839 struct ast_flags flags = { 0 };
1840 char *uid_channel_var = NULL;
1841 const char *mixmonitor_id = NULL;
1842 int res;
1843 char args[PATH_MAX];
1844
1845 if (ast_strlen_zero(name)) {
1846 astman_send_error(s, m, "No channel specified");
1847 return AMI_SUCCESS;
1848 }
1849
1851 if (!c) {
1852 astman_send_error(s, m, "No such channel");
1853 return AMI_SUCCESS;
1854 }
1855
1856 if (!ast_strlen_zero(options)) {
1858 }
1859
1860 snprintf(args, sizeof(args), "%s,%s,%s", file, options, command);
1861
1862 res = mixmonitor_exec(c, args);
1863
1865 uid_channel_var = opts[OPT_ARG_UID];
1867 mixmonitor_id = pbx_builtin_getvar_helper(c, uid_channel_var);
1868 mixmonitor_id = ast_strdupa(S_OR(mixmonitor_id, ""));
1870 }
1871
1872 if (res) {
1874 astman_send_error(s, m, "Could not start monitoring channel");
1875 return AMI_SUCCESS;
1876 }
1877
1878 astman_append(s, "Response: Success\r\n");
1879
1880 if (!ast_strlen_zero(id)) {
1881 astman_append(s, "ActionID: %s\r\n", id);
1882 }
1883
1884 if (!ast_strlen_zero(mixmonitor_id)) {
1885 astman_append(s, "MixMonitorID: %s\r\n", mixmonitor_id);
1886 }
1887
1888 astman_append(s, "\r\n");
1889
1891
1892 return AMI_SUCCESS;
1893}
static const struct ast_app_option mixmonitor_opts[128]
#define PATH_MAX
Definition asterisk.h:40
struct ast_channel * ast_channel_get_by_name(const char *search)
Find a channel by name or uniqueid.
Definition channel.c:1417
static const char name[]
Definition format_mp3.c:68
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition manager.c:2000
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition manager.c:1661
void astman_append(struct mansession *s, const char *fmt,...)
Definition manager.c:1921
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:3067
#define AMI_SUCCESS
Definition manager.h:66
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition strings.h:80
Structure used to handle boolean flags.
Definition utils.h:220
unsigned int flags
Definition utils.h:221
static struct test_options options
static struct test_val c

References AMI_SUCCESS, args, ast_app_parse_options(), ast_channel_get_by_name(), ast_channel_lock, ast_channel_unlock, ast_channel_unref, ast_strdupa, ast_strlen_zero(), ast_test_flag, astman_append(), astman_get_header(), astman_send_error(), c, ast_flags::flags, mixmonitor_exec(), mixmonitor_opts, MUXFLAG_UID, name, NULL, OPT_ARG_ARRAY_SIZE, OPT_ARG_UID, options, PATH_MAX, pbx_builtin_getvar_helper(), and S_OR.

Referenced by load_module().

◆ manager_mute_mixmonitor()

static int manager_mute_mixmonitor ( struct mansession s,
const struct message m 
)
static

Mute / unmute a MixMonitor channel.

Definition at line 1722 of file app_mixmonitor.c.

1723{
1724 struct ast_channel *c;
1725 const char *name = astman_get_header(m, "Channel");
1726 const char *id = astman_get_header(m, "ActionID");
1727 const char *state = astman_get_header(m, "State");
1728 const char *direction = astman_get_header(m,"Direction");
1729 const char *mixmonitor_id = astman_get_header(m, "MixMonitorID");
1730 int clearmute = 1, mutedcount = 0;
1733 RAII_VAR(struct ast_json *, stasis_message_blob, NULL, ast_json_unref);
1734
1736 astman_send_error(s, m, "No direction specified. Must be read, write or both");
1737 return AMI_SUCCESS;
1738 }
1739
1740 if (!strcasecmp(direction, "read")) {
1742 } else if (!strcasecmp(direction, "write")) {
1744 } else if (!strcasecmp(direction, "both")) {
1746 } else {
1747 astman_send_error(s, m, "Invalid direction specified. Must be read, write or both");
1748 return AMI_SUCCESS;
1749 }
1750
1751 if (ast_strlen_zero(name)) {
1752 astman_send_error(s, m, "No channel specified");
1753 return AMI_SUCCESS;
1754 }
1755
1756 if (ast_strlen_zero(state)) {
1757 astman_send_error(s, m, "No state specified");
1758 return AMI_SUCCESS;
1759 }
1760
1761 clearmute = ast_false(state);
1762
1764 if (!c) {
1765 astman_send_error(s, m, "No such channel");
1766 return AMI_SUCCESS;
1767 }
1768
1769 if (ast_strlen_zero(mixmonitor_id)) {
1770 mutedcount = ast_audiohook_set_mute_all(c, mixmonitor_spy_type, flag, clearmute);
1771 if (mutedcount < 0) {
1773 astman_send_error(s, m, "Cannot set mute flag");
1774 return AMI_SUCCESS;
1775 }
1776 } else {
1777 if (mute_mixmonitor_instance(c, mixmonitor_id, flag, clearmute)) {
1779 astman_send_error(s, m, "Cannot set mute flag");
1780 return AMI_SUCCESS;
1781 }
1782 mutedcount = 1;
1783 }
1784
1785
1786 stasis_message_blob = ast_json_pack("{s: s, s: b, s: s, s: i}",
1787 "direction", direction,
1788 "state", ast_true(state),
1789 "mixmonitorid", mixmonitor_id,
1790 "count", mutedcount);
1791
1793 ast_channel_mixmonitor_mute_type(), stasis_message_blob);
1794
1795 if (stasis_message) {
1797 }
1798
1799 astman_append(s, "Response: Success\r\n");
1800
1801 if (!ast_strlen_zero(id)) {
1802 astman_append(s, "ActionID: %s\r\n", id);
1803 }
1804
1805 astman_append(s, "\r\n");
1806
1808
1809 return AMI_SUCCESS;
1810}
static int mute_mixmonitor_instance(struct ast_channel *chan, const char *data, enum ast_audiohook_flags flag, int clearmute)
Mute / unmute an individual MixMonitor by id.
#define ao2_cleanup(obj)
Definition astobj2.h:1934
int ast_audiohook_set_mute_all(struct ast_channel *chan, const char *source, enum ast_audiohook_flags flag, int clear)
Mute frames read from or written for all audiohooks on a channel.
Definition audiohook.c:1432
ast_audiohook_flags
Definition audiohook.h:54
@ AST_AUDIOHOOK_MUTE_READ
Definition audiohook.h:64
@ AST_AUDIOHOOK_MUTE_WRITE
Definition audiohook.h:65
struct stasis_topic * ast_channel_topic(struct ast_channel *chan)
A topic which publishes the events for a particular channel.
const char * ast_channel_uniqueid(const struct ast_channel *chan)
long int flag
Definition f2c.h:83
struct stasis_message_type * ast_channel_mixmonitor_mute_type(void)
Message type for muting or unmuting mixmonitor on a channel.
struct stasis_message * ast_channel_blob_create_from_cache(const char *uniqueid, struct stasis_message_type *type, struct ast_json *blob)
Create a ast_channel_blob message, pulling channel state from the cache.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition json.c:73
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition json.c:612
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
Definition stasis.c:1589
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition utils.c:2233
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"....
Definition utils.c:2250
Abstract JSON element (object, array, string, int, ...).
#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:981

References AMI_SUCCESS, ao2_cleanup, AST_AUDIOHOOK_MUTE_READ, AST_AUDIOHOOK_MUTE_WRITE, ast_audiohook_set_mute_all(), ast_channel_blob_create_from_cache(), ast_channel_get_by_name(), ast_channel_mixmonitor_mute_type(), ast_channel_topic(), ast_channel_uniqueid(), ast_channel_unref, ast_false(), ast_json_pack(), ast_json_unref(), ast_strlen_zero(), ast_true(), astman_append(), astman_get_header(), astman_send_error(), c, mixmonitor_spy_type, mute_mixmonitor_instance(), name, NULL, RAII_VAR, and stasis_publish().

Referenced by load_module().

◆ manager_stop_mixmonitor()

static int manager_stop_mixmonitor ( struct mansession s,
const struct message m 
)
static

Definition at line 1895 of file app_mixmonitor.c.

1896{
1897 struct ast_channel *c;
1898 const char *name = astman_get_header(m, "Channel");
1899 const char *id = astman_get_header(m, "ActionID");
1900 const char *mixmonitor_id = astman_get_header(m, "MixMonitorID");
1901 int res;
1902
1903 if (ast_strlen_zero(name)) {
1904 astman_send_error(s, m, "No channel specified");
1905 return AMI_SUCCESS;
1906 }
1907
1909 if (!c) {
1910 astman_send_error(s, m, "No such channel");
1911 return AMI_SUCCESS;
1912 }
1913
1914 res = stop_mixmonitor_full(c, mixmonitor_id);
1915 if (res) {
1917 astman_send_error(s, m, "Could not stop monitoring channel");
1918 return AMI_SUCCESS;
1919 }
1920
1921 astman_append(s, "Response: Success\r\n");
1922
1923 if (!ast_strlen_zero(id)) {
1924 astman_append(s, "ActionID: %s\r\n", id);
1925 }
1926
1927 astman_append(s, "\r\n");
1928
1930
1931 return AMI_SUCCESS;
1932}
static int stop_mixmonitor_full(struct ast_channel *chan, const char *data)

References AMI_SUCCESS, ast_channel_get_by_name(), ast_channel_unref, ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_error(), c, name, and stop_mixmonitor_full().

Referenced by load_module().

◆ mixmonitor_autochan_is_bridged()

static int mixmonitor_autochan_is_bridged ( struct ast_autochan autochan)
static

Definition at line 841 of file app_mixmonitor.c.

842{
843 int is_bridged;
844
846 is_bridged = ast_channel_is_bridged(autochan->chan);
848 return is_bridged;
849}
#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
int ast_channel_is_bridged(const struct ast_channel *chan)
Determine if a channel is in a bridge.
Definition channel.c:10725
struct ast_channel * chan
Definition autochan.h:33

References ast_autochan_channel_lock, ast_autochan_channel_unlock, ast_channel_is_bridged(), and ast_autochan::chan.

Referenced by mixmonitor_thread().

◆ mixmonitor_ds_close_fs()

static void mixmonitor_ds_close_fs ( struct mixmonitor_ds mixmonitor_ds)
static

Definition at line 534 of file app_mixmonitor.c.

535{
536 unsigned char quitting = 0;
537
538 if (mixmonitor_ds->fs) {
539 quitting = 1;
542 ast_verb(2, "MixMonitor close filestream (mixed)\n");
543 }
544
545 if (mixmonitor_ds->fs_read) {
546 quitting = 1;
549 ast_verb(2, "MixMonitor close filestream (read)\n");
550 }
551
552 if (mixmonitor_ds->fs_write) {
553 quitting = 1;
556 ast_verb(2, "MixMonitor close filestream (write)\n");
557 }
558
559 if (quitting) {
561 }
562}
int ast_closestream(struct ast_filestream *f)
Closes a stream.
Definition file.c:1130

References ast_closestream(), ast_verb, mixmonitor_ds::fs, mixmonitor_ds::fs_quit, mixmonitor_ds::fs_read, mixmonitor_ds::fs_write, and NULL.

Referenced by mixmonitor_thread(), and stop_mixmonitor_full().

◆ mixmonitor_ds_destroy()

static void mixmonitor_ds_destroy ( void *  data)
static

◆ mixmonitor_ds_remove_and_free()

static void mixmonitor_ds_remove_and_free ( struct ast_channel chan,
const char *  datastore_id 
)
static

Definition at line 1154 of file app_mixmonitor.c.

1155{
1156 struct ast_datastore *datastore;
1157
1158 ast_channel_lock(chan);
1159
1160 datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, datastore_id);
1161
1162 if (datastore) {
1163 ast_channel_datastore_remove(chan, datastore);
1164 ast_datastore_free(datastore);
1165 }
1166
1167 ast_channel_unlock(chan);
1168}
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition channel.c:2385
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition datastore.c:68

References ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_unlock, ast_datastore_free(), and mixmonitor_ds_info.

Referenced by launch_monitor_thread().

◆ mixmonitor_exec()

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

Definition at line 1369 of file app_mixmonitor.c.

1370{
1371 int x, readvol = 0, writevol = 0;
1372 double skip_seconds = 0.0;
1373 char *filename_read = NULL;
1374 char *filename_write = NULL;
1375 char filename_buffer[1024] = "";
1376 char *uid_channel_var = NULL;
1377 char beep_id[64] = "";
1378
1379 struct ast_flags flags = { 0 };
1380 char *recipients = NULL;
1381 char *parse;
1384 AST_APP_ARG(filename);
1386 AST_APP_ARG(post_process);
1387 );
1388
1389 if (ast_strlen_zero(data)) {
1390 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename or ,t(filename) and/or r(filename)\n");
1391 return -1;
1392 }
1393
1394 parse = ast_strdupa(data);
1395
1397
1398 if (args.options) {
1399 char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
1400
1402
1404 ast_log(LOG_NOTICE, "The synchronization behavior enabled by the 'S' option is now the default"
1405 " and does not need to be specified.\n");
1406 }
1407
1410 ast_log(LOG_WARNING, "No volume level was provided for the heard volume ('v') option.\n");
1411 } else if ((sscanf(opts[OPT_ARG_READVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
1412 ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_READVOLUME]);
1413 } else {
1414 readvol = get_volfactor(x);
1415 }
1416 }
1417
1420 ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n");
1421 } else if ((sscanf(opts[OPT_ARG_WRITEVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
1422 ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_WRITEVOLUME]);
1423 } else {
1424 writevol = get_volfactor(x);
1425 }
1426 }
1427
1429 if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) {
1430 ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n");
1431 } else if ((sscanf(opts[OPT_ARG_VOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
1432 ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]);
1433 } else {
1434 readvol = writevol = get_volfactor(x);
1435 }
1436 }
1437
1440 ast_log(LOG_WARNING, "No voicemail recipients were specified for the vm copy ('m') option.\n");
1441 } else {
1442 recipients = ast_strdupa(opts[OPT_ARG_VMRECIPIENTS]);
1443 }
1444 }
1445
1447 filename_write = ast_strdupa(filename_parse(opts[OPT_ARG_WRITENAME], filename_buffer, sizeof(filename_buffer)));
1448 }
1449
1451 filename_read = ast_strdupa(filename_parse(opts[OPT_ARG_READNAME], filename_buffer, sizeof(filename_buffer)));
1452 }
1453
1455 uid_channel_var = opts[OPT_ARG_UID];
1456 }
1457
1459 const char *interval_str = S_OR(opts[OPT_ARG_BEEP_INTERVAL], "15");
1460 unsigned int interval = 15;
1461
1462 if (sscanf(interval_str, "%30u", &interval) != 1) {
1463 ast_log(LOG_WARNING, "Invalid interval '%s' for periodic beep. Using default of %u\n",
1464 interval_str, interval);
1465 }
1466
1467 if (ast_beep_start(chan, interval, beep_id, sizeof(beep_id))) {
1468 ast_log(LOG_WARNING, "Unable to enable periodic beep, please ensure func_periodic_hook is loaded.\n");
1469 return -1;
1470 }
1471 }
1472
1474 if (ast_strlen_zero(opts[OPT_ARG_SKIP])) {
1475 ast_log(LOG_WARNING, "No skip value provided for the 's' (skip) option; skipping will be ignored as no default exists.\n");
1476 } else {
1477 char *endptr = NULL;
1478 double val = strtod(opts[OPT_ARG_SKIP], &endptr);
1479 if (endptr == opts[OPT_ARG_SKIP] || *endptr != '\0') {
1480 ast_log(LOG_WARNING, "Skip value '%s' is not a valid number; ignoring skip.\n", opts[OPT_ARG_SKIP]);
1481 } else if (val < (double) MIN_SKIP_SECONDS) {
1482 ast_log(LOG_WARNING, "Skip value %.3f is below minimum %d; ignoring skip.\n", val, MIN_SKIP_SECONDS);
1483 } else {
1484 skip_seconds = val;
1485 }
1486 }
1487 }
1488 }
1489 /* If there are no file writing arguments/options for the mix monitor, send a warning message and return -1 */
1490
1492 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n");
1493 return -1;
1494 }
1495
1496 /* If filename exists, try to create directories for it */
1497 if (!(ast_strlen_zero(args.filename))) {
1498 args.filename = ast_strdupa(filename_parse(args.filename, filename_buffer, sizeof(filename_buffer)));
1499 }
1500
1501 pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename);
1502
1503 /* If launch_monitor_thread works, the module reference must not be released until it is finished. */
1505 if (launch_monitor_thread(chan,
1506 args.filename,
1507 flags.flags,
1508 readvol,
1509 writevol,
1510 args.post_process,
1511 filename_write,
1512 filename_read,
1513 uid_channel_var,
1514 recipients,
1515 beep_id,
1516 skip_seconds)) {
1518 }
1519
1522 if (message) {
1524 }
1525
1526 return 0;
1527}
static char * filename_parse(char *filename, char *buffer, size_t len)
#define get_volfactor(x)
#define MIN_SKIP_SECONDS
static int launch_monitor_thread(struct ast_channel *chan, const char *filename, unsigned int flags, int readvol, int writevol, const char *post_process, const char *filename_write, char *filename_read, const char *uid_channel_var, const char *recipients, const char *beep_id, double skip_seconds)
int AST_OPTIONAL_API_NAME() ast_beep_start(struct ast_channel *chan, unsigned int interval, char *beep_id, size_t len)
struct stasis_message_type * ast_channel_mixmonitor_start_type(void)
Message type for starting mixmonitor on a channel.
#define LOG_NOTICE
#define ast_module_unref(mod)
Release a reference to the module.
Definition module.h:483
#define ast_module_ref(mod)
Hold a reference to the module.
Definition module.h:457
struct ast_module * self
Definition module.h:356

References ao2_cleanup, args, AST_APP_ARG, ast_app_parse_options(), ast_beep_start(), ast_channel_blob_create_from_cache(), ast_channel_mixmonitor_start_type(), ast_channel_topic(), ast_channel_uniqueid(), AST_DECLARE_APP_ARGS, ast_log, ast_module_ref, ast_module_unref, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, filename_parse(), ast_flags::flags, ast_channel::flags, get_volfactor, launch_monitor_thread(), LOG_NOTICE, LOG_WARNING, MIN_SKIP_SECONDS, mixmonitor_opts, MUXFLAG_BEEP, MUXFLAG_DEPRECATED_RWSYNC, MUXFLAG_READ, MUXFLAG_READVOLUME, MUXFLAG_SKIP, MUXFLAG_UID, MUXFLAG_VMRECIPIENTS, MUXFLAG_VOLUME, MUXFLAG_WRITE, MUXFLAG_WRITEVOLUME, NULL, OPT_ARG_ARRAY_SIZE, OPT_ARG_BEEP_INTERVAL, OPT_ARG_READNAME, OPT_ARG_READVOLUME, OPT_ARG_SKIP, OPT_ARG_UID, OPT_ARG_VMRECIPIENTS, OPT_ARG_VOLUME, OPT_ARG_WRITENAME, OPT_ARG_WRITEVOLUME, options, pbx_builtin_setvar_helper(), RAII_VAR, S_OR, ast_module_info::self, and stasis_publish().

Referenced by handle_cli_mixmonitor(), load_module(), manager_mixmonitor(), and start_mixmonitor_callback().

◆ mixmonitor_free()

static void mixmonitor_free ( struct mixmonitor mixmonitor)
static

◆ mixmonitor_save_prep()

static void mixmonitor_save_prep ( struct mixmonitor mixmonitor,
char *  filename,
struct ast_filestream **  fs,
unsigned int *  oflags,
int *  errflag,
char **  ext 
)
static

Definition at line 812 of file app_mixmonitor.c.

813{
814 /* Initialize the file if not already done so */
815 char *last_slash = NULL;
816 if (!ast_strlen_zero(filename)) {
817 if (!*fs && !*errflag && !mixmonitor->mixmonitor_ds->fs_quit) {
818 *oflags = O_CREAT | O_WRONLY;
819 *oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC;
820
821 last_slash = strrchr(filename, '/');
822
823 if ((*ext = strrchr(filename, '.')) && (*ext > last_slash)) {
824 **ext = '\0';
825 *ext = *ext + 1;
826 } else {
827 *ext = "raw";
828 }
829
830 if (!(*fs = ast_writefile(filename, *ext, NULL, *oflags, 0, 0666))) {
831 ast_log(LOG_ERROR, "Cannot open %s.%s\n", filename, *ext);
832 *errflag = 1;
833 } else {
834 struct ast_filestream *tmp = *fs;
836 }
837 }
838 }
839}
struct ast_filestream * ast_writefile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
Starts writing a file.
Definition file.c:1457
unsigned int ast_format_get_sample_rate(const struct ast_format *format)
Get the sample rate of a media format.
Definition format.c:379
This structure is allocated by file.c in one chunk, together with buf_size and desc_size bytes of mem...
Definition mod_format.h:101
struct ast_format_def * fmt
Definition mod_format.h:103
struct ast_format * format
Definition mod_format.h:48
unsigned int samp_rate
#define MAX(a, b)
Definition utils.h:254

References ast_format_get_sample_rate(), ast_log, ast_strlen_zero(), ast_test_flag, ast_writefile(), ext, ast_filestream::fmt, ast_format_def::format, mixmonitor_ds::fs_quit, LOG_ERROR, MAX, mixmonitor::mixmonitor_ds, MUXFLAG_APPEND, NULL, and mixmonitor_ds::samp_rate.

Referenced by mixmonitor_thread().

◆ mixmonitor_thread()

static void * mixmonitor_thread ( void *  obj)
static

Definition at line 851 of file app_mixmonitor.c.

852{
853 struct mixmonitor *mixmonitor = obj;
854 char *fs_ext = "";
855 char *fs_read_ext = "";
856 char *fs_write_ext = "";
857
858 struct ast_filestream **fs = NULL;
859 struct ast_filestream **fs_read = NULL;
860 struct ast_filestream **fs_write = NULL;
861
862 struct ast_format *last_format_read = NULL;
863 struct ast_format *last_format_write = NULL;
864 struct ast_trans_pvt *trans_pvt_read = NULL;
865 struct ast_trans_pvt *trans_pvt_write = NULL;
866
867 unsigned int oflags;
868 int errflag = 0;
869 struct ast_format *format_slin;
870
871 struct timeval skip_start = ast_tvnow();
872
873 /* Keep callid association before any log messages */
874 if (mixmonitor->callid) {
876 }
877
878 ast_verb(2, "Begin MixMonitor Recording %s\n", mixmonitor->name);
879
881 fs_read = &mixmonitor->mixmonitor_ds->fs_read;
882 fs_write = &mixmonitor->mixmonitor_ds->fs_write;
883
885 mixmonitor_save_prep(mixmonitor, mixmonitor->filename, fs, &oflags, &errflag, &fs_ext);
886 mixmonitor_save_prep(mixmonitor, mixmonitor->filename_read, fs_read, &oflags, &errflag, &fs_read_ext);
887 mixmonitor_save_prep(mixmonitor, mixmonitor->filename_write, fs_write, &oflags, &errflag, &fs_write_ext);
888
890
892
893 if (mixmonitor->skip_seconds > 0.0) {
894 ast_debug(3, "%s skipping initial %.3f seconds\n",
896 }
897
898 /* The audiohook must enter and exit the loop locked */
901 struct ast_frame *fr = NULL;
902 struct ast_frame *fr_read = NULL;
903 struct ast_frame *fr_write = NULL;
904
906 &fr_read, &fr_write))) {
908
910 break;
911 }
912 continue;
913 }
914
915 /* audiohook lock is not required for the next block.
916 * Unlock it, but remember to lock it before looping or exiting */
918
922
923 /* Skip writing audio for the first N seconds */
924 if (mixmonitor->skip_seconds > 0.0) {
925 struct timeval now = ast_tvnow();
926 double elapsed = ast_tvdiff_ms(now, skip_start) / 1000.0;
927
928 if (elapsed < mixmonitor->skip_seconds) {
930 /* Skip this frame and continue */
931 goto frame_cleanup;
932 } else {
933 ast_debug(3, "%s skip period %.3f seconds elapsed; starting to write audio\n",
936 }
937 }
938
939 /* Write out the frame(s) */
940 if ((*fs_read) && (fr_read)) {
941 struct ast_frame *cur;
942
943 for (cur = fr_read; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
944 ast_writestream(*fs_read, cur);
945 }
946 }
947
948 if ((*fs_write) && (fr_write)) {
949 struct ast_frame *cur;
950
951 for (cur = fr_write; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
952 ast_writestream(*fs_write, cur);
953 }
954 }
955
957 /* The 'D' option is set, so mix the frame as an interleaved dual channel frame */
958 int i;
959 /*
960 * We are fed by a call to ast_audiohook_read_frame_all specifying format_slin. However
961 * we may get frames back in a different format. Either way, we we will translate them
962 * to the format with the correct frame size before writing into these buffers.
963 */
964 short read_buf[SAMPLES_PER_FRAME];
966 short stereo_buf[SAMPLES_PER_FRAME * 2];
967 struct ast_frame stereo_frame = {
969 .datalen = sizeof(stereo_buf),
971 };
972
973 if (fr) {
974 ast_frame_free(fr, 0);
975 fr = NULL;
976 }
977
978 /*
979 * Depending on the input codec's rate (which may change during the call) we may get frames in
980 * a slin format that does not match the native format_slin of the mixmonitor. In that case
981 * we need to translate.
982 */
983 fill_frame_buffer(fr_read, format_slin, &last_format_read, &trans_pvt_read,
984 read_buf, sizeof(read_buf), "Read");
985
986 fill_frame_buffer(fr_write, format_slin, &last_format_write, &trans_pvt_write,
987 write_buf, sizeof(write_buf), "Write");
988
989 for (i = 0; i < SAMPLES_PER_FRAME; i++) {
990 stereo_buf[i * 2] = read_buf[i];
991 stereo_buf[i * 2 + 1] = write_buf[i];
992 }
993
994 stereo_frame.data.ptr = stereo_buf;
995 stereo_frame.subclass.format = format_slin;
996
997 fr = ast_frdup(&stereo_frame);
998 }
999
1000 if ((*fs) && (fr)) {
1001 struct ast_frame *cur;
1002
1003 for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
1004 ast_writestream(*fs, cur);
1005 }
1006 }
1008 }
1009
1010frame_cleanup:
1011 /* All done! free it. */
1012 if (fr) {
1013 ast_frame_free(fr, 0);
1014 }
1015 if (fr_read) {
1016 ast_frame_free(fr_read, 0);
1017 }
1018 if (fr_write) {
1019 ast_frame_free(fr_write, 0);
1020 }
1021
1022 fr = NULL;
1023 fr_write = NULL;
1024 fr_read = NULL;
1025
1027 }
1028
1030
1035 }
1036
1038
1039 /* Datastore cleanup. close the filestream and wait for ds destruction */
1044 }
1046
1047 /* Free the translate paths */
1048 if (trans_pvt_read) {
1049 ast_translator_free_path(trans_pvt_read);
1050 trans_pvt_read = NULL;
1051 }
1052 if (trans_pvt_write) {
1053 ast_translator_free_path(trans_pvt_write);
1054 trans_pvt_write = NULL;
1055 }
1056
1057 /* kill the audiohook */
1059
1060 if (mixmonitor->post_process) {
1061 ast_verb(2, "Executing [%s]\n", mixmonitor->post_process);
1063 }
1064
1065 ast_verb(2, "End MixMonitor Recording %s\n", mixmonitor->name);
1066 ast_test_suite_event_notify("MIXMONITOR_END", "File: %s\r\n", mixmonitor->filename);
1067
1069 if (ast_strlen_zero(fs_ext)) {
1070 ast_log(LOG_ERROR, "No file extension set for Mixmonitor %s. Skipping copy to voicemail.\n",
1071 mixmonitor -> name);
1072 } else {
1073 ast_verb(3, "Copying recordings for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
1075 }
1076 if (!ast_strlen_zero(fs_read_ext)) {
1077 ast_verb(3, "Copying read recording for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
1079 }
1080 if (!ast_strlen_zero(fs_write_ext)) {
1081 ast_verb(3, "Copying write recording for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
1083 }
1084 } else {
1085 ast_debug(3, "No recipients to forward monitor to, moving on.\n");
1086 }
1087
1089 ast_debug(3, "Deleting our copies of recording files\n");
1090 if (!ast_strlen_zero(fs_ext)) {
1092 }
1093 if (!ast_strlen_zero(fs_read_ext)) {
1095 }
1096 if (!ast_strlen_zero(fs_write_ext)) {
1098 }
1099 }
1100
1102
1104 return NULL;
1105}
static void destroy_monitor_audiohook(struct mixmonitor *mixmonitor)
static void mixmonitor_save_prep(struct mixmonitor *mixmonitor, char *filename, struct ast_filestream **fs, unsigned int *oflags, int *errflag, char **ext)
static int mixmonitor_autochan_is_bridged(struct ast_autochan *autochan)
static void copy_to_voicemail(struct mixmonitor *mixmonitor, const char *ext, const char *filename)
#define SAMPLES_PER_FRAME
static void mixmonitor_ds_close_fs(struct mixmonitor_ds *mixmonitor_ds)
static void fill_frame_buffer(struct ast_frame *source_frame, struct ast_format *target_format, struct ast_format **last_source_format, struct ast_trans_pvt **translator_path, short *dest_buf, size_t dest_buf_size, const char *direction)
struct ast_frame * ast_audiohook_read_frame_all(struct ast_audiohook *audiohook, size_t samples, struct ast_format *format, struct ast_frame **read_frame, struct ast_frame **write_frame)
Reads a frame in from the audiohook structure in mixed audio mode and copies read and write frame dat...
Definition audiohook.c:488
void ast_audiohook_trigger_wait(struct ast_audiohook *audiohook)
Wait for audiohook trigger to be triggered.
Definition audiohook.c:1131
@ AST_AUDIOHOOK_STATUS_RUNNING
Definition audiohook.h:43
void write_buf(int file, char *buffer, int num)
Definition eagi_proxy.c:312
int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
Writes a frame to a stream.
Definition file.c:255
int ast_stream_and_wait(struct ast_channel *chan, const char *file, const char *digits)
stream file until digit If the file name is non-empty, try to play it.
Definition file.c:1912
int ast_filedelete(const char *filename, const char *fmt)
Deletes a file.
Definition file.c:1160
struct ast_format * ast_format_cache_get_slin_by_rate(unsigned int rate)
Retrieve the best signed linear format given a sample rate.
int ast_safe_system(const char *s)
Safely spawn an OS shell command while closing file descriptors.
Definition extconf.c:827
#define ast_frdup(fr)
Copies a frame.
int ast_callid_threadassoc_add(ast_callid callid)
Adds a known callid to thread storage of the calling thread.
Definition logger.c:2290
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
#define ast_cond_wait(cond, mutex)
Definition lock.h:212
enum ast_audiohook_status status
Definition audiohook.h:108
Definition of a media format.
Definition format.c:43
enum ast_frame_type frametype
Default structure for translators, with the basic fields and buffers, all allocated as part of the sa...
Definition translate.h:213
#define ast_test_suite_event_notify(s, f,...)
Definition test.h:189
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition time.h:159

References ast_audiohook_lock, ast_audiohook_read_frame_all(), AST_AUDIOHOOK_STATUS_RUNNING, ast_audiohook_trigger_wait(), ast_audiohook_unlock, ast_autochan_channel_lock, ast_autochan_channel_unlock, ast_autochan_destroy(), ast_callid_threadassoc_add(), ast_cond_wait, ast_debug, ast_filedelete(), ast_format_cache_get_slin_by_rate(), ast_frame_free(), AST_FRAME_VOICE, ast_frdup, AST_LIST_EMPTY, AST_LIST_NEXT, ast_log, ast_module_unref, ast_mutex_lock, ast_mutex_unlock, ast_safe_system(), ast_stream_and_wait(), ast_strlen_zero(), ast_test_flag, ast_test_suite_event_notify, ast_translator_free_path(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, ast_writestream(), mixmonitor::audiohook, mixmonitor::autochan, mixmonitor::callid, ast_autochan::chan, copy_to_voicemail(), ast_frame::data, destroy_monitor_audiohook(), mixmonitor_ds::destruction_condition, mixmonitor_ds::destruction_ok, mixmonitor::filename, mixmonitor::filename_read, mixmonitor::filename_write, fill_frame_buffer(), ast_frame_subclass::format, ast_frame::frametype, mixmonitor_ds::fs, mixmonitor_ds::fs_quit, mixmonitor_ds::fs_read, mixmonitor_ds::fs_write, mixmonitor_ds::lock, LOG_ERROR, mixmonitor_autochan_is_bridged(), mixmonitor::mixmonitor_ds, mixmonitor_ds_close_fs(), mixmonitor_free(), mixmonitor_save_prep(), MUXFLAG_AUTO_DELETE, MUXFLAG_BEEP_STOP, MUXFLAG_BRIDGED, MUXFLAG_INTERLEAVED, name, mixmonitor::name, NULL, mixmonitor::post_process, ast_frame::ptr, mixmonitor::recipient_list, mixmonitor_ds::samp_rate, ast_frame::samples, SAMPLES_PER_FRAME, ast_module_info::self, mixmonitor::skip_seconds, ast_audiohook::status, ast_frame::subclass, and write_buf().

Referenced by launch_monitor_thread().

◆ mute_mixmonitor_instance()

static int mute_mixmonitor_instance ( struct ast_channel chan,
const char *  data,
enum ast_audiohook_flags  flag,
int  clearmute 
)
static

Mute / unmute an individual MixMonitor by id.

Definition at line 1678 of file app_mixmonitor.c.

1680{
1681 struct ast_datastore *datastore = NULL;
1682 char *parse = "";
1684
1686 AST_APP_ARG(mixmonid);
1687 );
1688
1689 if (!ast_strlen_zero(data)) {
1690 parse = ast_strdupa(data);
1691 }
1692
1694
1695 ast_channel_lock(chan);
1696
1698 S_OR(args.mixmonid, NULL));
1699 if (!datastore) {
1700 ast_channel_unlock(chan);
1701 return -1;
1702 }
1703 mixmonitor_ds = datastore->data;
1704
1706
1707 if (mixmonitor_ds->audiohook) {
1708 if (clearmute) {
1710 } else {
1712 }
1713 }
1714
1716 ast_channel_unlock(chan);
1717
1718 return 0;
1719}
#define ast_clear_flag(p, flag)
Definition utils.h:78

References args, AST_APP_ARG, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_clear_flag, AST_DECLARE_APP_ARGS, ast_mutex_lock, ast_mutex_unlock, ast_set_flag, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), mixmonitor_ds::audiohook, ast_datastore::data, mixmonitor_ds::lock, mixmonitor_ds_info, NULL, and S_OR.

Referenced by manager_mute_mixmonitor().

◆ set_mixmonitor_methods()

static int set_mixmonitor_methods ( void  )
static

Definition at line 1981 of file app_mixmonitor.c.

1982{
1986 };
1987
1989}
static int start_mixmonitor_callback(struct ast_channel *chan, const char *filename, const char *options)
static int stop_mixmonitor_callback(struct ast_channel *chan, const char *mixmonitor_id)
static struct ast_mixmonitor_methods mixmonitor_methods
Definition mixmonitor.c:40
int ast_set_mixmonitor_methods(struct ast_mixmonitor_methods *vmethod_table)
Setup MixMonitor virtual methods table. Use this to provide the MixMonitor functionality from a loada...
Definition mixmonitor.c:43
MixMonitor virtual methods table definition.
Definition mixmonitor.h:58
ast_mixmonitor_start_fn start
Definition mixmonitor.h:59

References ast_set_mixmonitor_methods(), mixmonitor_methods, ast_mixmonitor_methods::start, start_mixmonitor_callback(), and stop_mixmonitor_callback().

Referenced by load_module().

◆ setup_mixmonitor_ds()

static int setup_mixmonitor_ds ( struct mixmonitor mixmonitor,
struct ast_channel chan,
char **  datastore_id,
const char *  beep_id 
)
static

Definition at line 1107 of file app_mixmonitor.c.

1108{
1109 struct ast_datastore *datastore = NULL;
1111
1112 if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) {
1113 return -1;
1114 }
1115
1116 if (ast_asprintf(datastore_id, "%p", mixmonitor_ds) == -1) {
1117 ast_log(LOG_ERROR, "Failed to allocate memory for MixMonitor ID.\n");
1119 return -1;
1120 }
1121
1124
1125 if (!(datastore = ast_datastore_alloc(&mixmonitor_ds_info, *datastore_id))) {
1129 return -1;
1130 }
1131
1136 }
1137
1138 mixmonitor_ds->samp_rate = 8000;
1141 if (!ast_strlen_zero(beep_id)) {
1143 }
1144 datastore->data = mixmonitor_ds;
1145
1146 ast_channel_lock(chan);
1147 ast_channel_datastore_add(chan, datastore);
1148 ast_channel_unlock(chan);
1149
1151 return 0;
1152}
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition astmm.h:267
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition channel.c:2376
#define ast_datastore_alloc(info, uid)
Definition datastore.h:85
#define ast_cond_init(cond, attr)
Definition lock.h:208
#define ast_mutex_init(pmutex)
Definition lock.h:193

References ast_asprintf, ast_autochan_channel_lock, ast_autochan_channel_unlock, ast_calloc, ast_channel_datastore_add(), ast_channel_lock, ast_channel_unlock, ast_cond_destroy, ast_cond_init, ast_datastore_alloc, ast_free, ast_log, ast_mutex_destroy, ast_mutex_init, ast_strdup, ast_stream_and_wait(), ast_strlen_zero(), ast_test_flag, mixmonitor::audiohook, mixmonitor_ds::audiohook, mixmonitor::autochan, mixmonitor_ds::beep_id, ast_autochan::chan, ast_datastore::data, mixmonitor_ds::destruction_condition, mixmonitor::filename, mixmonitor_ds::filename, mixmonitor_ds::lock, LOG_ERROR, mixmonitor::mixmonitor_ds, mixmonitor_ds_info, MUXFLAG_BEEP_START, NULL, and mixmonitor_ds::samp_rate.

Referenced by launch_monitor_thread().

◆ start_mixmonitor_callback()

static int start_mixmonitor_callback ( struct ast_channel chan,
const char *  filename,
const char *  options 
)
static

Definition at line 1812 of file app_mixmonitor.c.

1813{
1814 char args[PATH_MAX];
1815
1816 if (ast_strlen_zero(options)) {
1817 snprintf(args, sizeof(args), "%s", filename);
1818 } else {
1819 snprintf(args, sizeof(args), "%s,%s", filename, options);
1820 }
1821
1822 return mixmonitor_exec(chan, args);
1823}

References args, ast_strlen_zero(), mixmonitor_exec(), options, and PATH_MAX.

Referenced by set_mixmonitor_methods().

◆ startmon()

static int startmon ( struct ast_channel chan,
struct ast_audiohook audiohook 
)
static

Definition at line 596 of file app_mixmonitor.c.

597{
598 if (!chan) {
599 return -1;
600 }
601
602 return ast_audiohook_attach(chan, audiohook);
603}
int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
Attach audiohook to channel.
Definition audiohook.c:521

References ast_audiohook_attach().

Referenced by launch_monitor_thread().

◆ stop_mixmonitor_callback()

static int stop_mixmonitor_callback ( struct ast_channel chan,
const char *  mixmonitor_id 
)
static

Definition at line 1825 of file app_mixmonitor.c.

1826{
1827 return stop_mixmonitor_full(chan, mixmonitor_id);
1828}

References stop_mixmonitor_full().

Referenced by set_mixmonitor_methods().

◆ stop_mixmonitor_exec()

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

Definition at line 1603 of file app_mixmonitor.c.

1604{
1605 stop_mixmonitor_full(chan, data);
1606 return 0;
1607}

References stop_mixmonitor_full().

Referenced by handle_cli_mixmonitor(), and load_module().

◆ stop_mixmonitor_full()

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

Definition at line 1529 of file app_mixmonitor.c.

1530{
1531 struct ast_datastore *datastore = NULL;
1532 char *parse = "";
1534 const char *beep_id = NULL;
1536
1538 AST_APP_ARG(mixmonid);
1539 );
1540
1541 if (!ast_strlen_zero(data)) {
1542 parse = ast_strdupa(data);
1543 }
1544
1546
1547 ast_channel_lock(chan);
1548
1550 S_OR(args.mixmonid, NULL));
1551 if (!datastore) {
1552 ast_channel_unlock(chan);
1553 return -1;
1554 }
1555 mixmonitor_ds = datastore->data;
1556
1558
1559 /* closing the filestream here guarantees the file is available to the dialplan
1560 * after calling StopMixMonitor */
1562
1563 /* The mixmonitor thread may be waiting on the audiohook trigger.
1564 * In order to exit from the mixmonitor loop before waiting on channel
1565 * destruction, poke the audiohook trigger. */
1566 if (mixmonitor_ds->audiohook) {
1569 }
1574 }
1575
1578 }
1579
1581
1582 /* Remove the datastore so the monitor thread can exit */
1583 if (!ast_channel_datastore_remove(chan, datastore)) {
1584 ast_datastore_free(datastore);
1585 }
1586
1587 ast_channel_unlock(chan);
1588
1589 if (!ast_strlen_zero(beep_id)) {
1590 ast_beep_stop(chan, beep_id);
1591 }
1592
1595 NULL);
1596 if (message) {
1598 }
1599
1600 return 0;
1601}
void ast_audiohook_update_status(struct ast_audiohook *audiohook, enum ast_audiohook_status status)
Update audiohook's status.
Definition audiohook.c:577
@ AST_AUDIOHOOK_STATUS_DONE
Definition audiohook.h:45
@ AST_AUDIOHOOK_STATUS_SHUTDOWN
Definition audiohook.h:44
int AST_OPTIONAL_API_NAME() ast_beep_stop(struct ast_channel *chan, const char *beep_id)
struct stasis_message_type * ast_channel_mixmonitor_stop_type(void)
Message type for stopping mixmonitor on a channel.
ast_cond_t trigger
Definition audiohook.h:106

References ao2_cleanup, args, AST_APP_ARG, ast_audiohook_lock, AST_AUDIOHOOK_STATUS_DONE, AST_AUDIOHOOK_STATUS_SHUTDOWN, ast_audiohook_unlock, ast_audiohook_update_status(), ast_beep_stop(), ast_channel_blob_create_from_cache(), ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_mixmonitor_stop_type(), ast_channel_topic(), ast_channel_uniqueid(), ast_channel_unlock, ast_cond_signal, ast_datastore_free(), AST_DECLARE_APP_ARGS, ast_mutex_lock, ast_mutex_unlock, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), mixmonitor_ds::audiohook, mixmonitor_ds::beep_id, ast_datastore::data, mixmonitor_ds::lock, mixmonitor_ds_close_fs(), mixmonitor_ds_info, NULL, RAII_VAR, S_OR, stasis_publish(), ast_audiohook::status, and ast_audiohook::trigger.

Referenced by manager_stop_mixmonitor(), stop_mixmonitor_callback(), and stop_mixmonitor_exec().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 1996 of file app_mixmonitor.c.

1997{
1998 int res;
1999
2003 res |= ast_manager_unregister("MixMonitorMute");
2004 res |= ast_manager_unregister("MixMonitor");
2005 res |= ast_manager_unregister("StopMixMonitor");
2007 res |= clear_mixmonitor_methods();
2008
2009 return res;
2010}
void ast_cli_unregister_multiple(void)
Definition ael_main.c:408
static int clear_mixmonitor_methods(void)
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition manager.c:7716
int ast_unregister_application(const char *app)
Unregister an application.
Definition pbx_app.c:404
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.

References app, ARRAY_LEN, ast_cli_unregister_multiple(), ast_custom_function_unregister(), ast_manager_unregister(), ast_unregister_application(), clear_mixmonitor_methods(), cli_mixmonitor, mixmonitor_function, ast_mixmonitor_methods::start, and stop_app.

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Mixed Audio Monitoring Application" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .optional_modules = "func_periodic_hook", }
static

Definition at line 2033 of file app_mixmonitor.c.

◆ app

const char* const app = "MixMonitor"
static

Definition at line 406 of file app_mixmonitor.c.

Referenced by load_module(), and unload_module().

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 2033 of file app_mixmonitor.c.

◆ cli_mixmonitor

struct ast_cli_entry cli_mixmonitor[]
static
Initial value:
= {
{ .handler = handle_cli_mixmonitor , .summary = "Execute a MixMonitor command" ,}
}
static char * handle_cli_mixmonitor(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)

Definition at line 1977 of file app_mixmonitor.c.

1977 {
1978 AST_CLI_DEFINE(handle_cli_mixmonitor, "Execute a MixMonitor command")
1979};
#define AST_CLI_DEFINE(fn, txt,...)
Definition cli.h:197

Referenced by load_module(), and unload_module().

◆ mixmonitor_ds_info

const struct ast_datastore_info mixmonitor_ds_info
static
Initial value:
= {
.type = "mixmonitor",
}
static void mixmonitor_ds_destroy(void *data)

Definition at line 577 of file app_mixmonitor.c.

577 {
578 .type = "mixmonitor",
579 .destroy = mixmonitor_ds_destroy,
580};

Referenced by func_mixmonitor_read(), handle_cli_mixmonitor(), mixmonitor_ds_remove_and_free(), mute_mixmonitor_instance(), setup_mixmonitor_ds(), and stop_mixmonitor_full().

◆ mixmonitor_function

struct ast_custom_function mixmonitor_function
static
Initial value:
= {
.name = "MIXMONITOR",
}
static int func_mixmonitor_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)

Definition at line 1972 of file app_mixmonitor.c.

1972 {
1973 .name = "MIXMONITOR",
1974 .read = func_mixmonitor_read,
1975};

Referenced by load_module(), and unload_module().

◆ mixmonitor_opts

const struct ast_app_option mixmonitor_opts[128] = { [ 'a' ] = { .flag = MUXFLAG_APPEND }, [ 'b' ] = { .flag = MUXFLAG_BRIDGED }, [ 'B' ] = { .flag = MUXFLAG_BEEP , .arg_index = OPT_ARG_BEEP_INTERVAL + 1 }, [ 'c' ] = { .flag = MUXFLAG_REAL_CALLERID }, [ 'd' ] = { .flag = MUXFLAG_AUTO_DELETE }, [ 'p' ] = { .flag = MUXFLAG_BEEP_START }, [ 'P' ] = { .flag = MUXFLAG_BEEP_STOP }, [ 'v' ] = { .flag = MUXFLAG_READVOLUME , .arg_index = OPT_ARG_READVOLUME + 1 }, [ 'V' ] = { .flag = MUXFLAG_WRITEVOLUME , .arg_index = OPT_ARG_WRITEVOLUME + 1 }, [ 'W' ] = { .flag = MUXFLAG_VOLUME , .arg_index = OPT_ARG_VOLUME + 1 }, [ 'r' ] = { .flag = MUXFLAG_READ , .arg_index = OPT_ARG_READNAME + 1 }, [ 't' ] = { .flag = MUXFLAG_WRITE , .arg_index = OPT_ARG_WRITENAME + 1 }, [ 'D' ] = { .flag = MUXFLAG_INTERLEAVED }, [ 'i' ] = { .flag = MUXFLAG_UID , .arg_index = OPT_ARG_UID + 1 }, [ 'm' ] = { .flag = MUXFLAG_VMRECIPIENTS , .arg_index = OPT_ARG_VMRECIPIENTS + 1 }, [ 'S' ] = { .flag = MUXFLAG_DEPRECATED_RWSYNC , .arg_index = OPT_ARG_DEPRECATED_RWSYNC + 1 }, [ 'n' ] = { .flag = MUXFLAG_NO_RWSYNC , .arg_index = OPT_ARG_NO_RWSYNC + 1 }, [ 's' ] = { .flag = MUXFLAG_SKIP , .arg_index = OPT_ARG_SKIP + 1 }, }
static

Definition at line 508 of file app_mixmonitor.c.

Referenced by manager_mixmonitor(), and mixmonitor_exec().

◆ mixmonitor_spy_type

const char* const mixmonitor_spy_type = "MixMonitor"
static

◆ stop_app

const char* const stop_app = "StopMixMonitor"
static

Definition at line 408 of file app_mixmonitor.c.

Referenced by load_module(), and unload_module().