Asterisk - The Open Source Telephony Project GIT-master-91e368c
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 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 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_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)
}
 

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 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)
 
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. More...
 
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. More...
 
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 = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .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 }, [ '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 }, }
 
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 355 of file app_mixmonitor.c.

◆ SAMPLES_PER_FRAME

#define SAMPLES_PER_FRAME   160

Definition at line 612 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_ARRAY_SIZE 

Definition at line 420 of file app_mixmonitor.c.

420 {
431 OPT_ARG_ARRAY_SIZE, /* Always last element of the enum */
432};
@ 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 

Definition at line 400 of file app_mixmonitor.c.

400 {
401 MUXFLAG_APPEND = (1 << 1),
402 MUXFLAG_BRIDGED = (1 << 2),
403 MUXFLAG_VOLUME = (1 << 3),
404 MUXFLAG_READVOLUME = (1 << 4),
405 MUXFLAG_WRITEVOLUME = (1 << 5),
406 MUXFLAG_READ = (1 << 6),
407 MUXFLAG_WRITE = (1 << 7),
408 MUXFLAG_COMBINED = (1 << 8),
409 MUXFLAG_UID = (1 << 9),
410 MUXFLAG_VMRECIPIENTS = (1 << 10),
411 MUXFLAG_BEEP = (1 << 11),
412 MUXFLAG_BEEP_START = (1 << 12),
413 MUXFLAG_BEEP_STOP = (1 << 13),
414 MUXFLAG_DEPRECATED_RWSYNC = (1 << 14),
415 MUXFLAG_NO_RWSYNC = (1 << 15),
416 MUXFLAG_AUTO_DELETE = (1 << 16),
417 MUXFLAG_REAL_CALLERID = (1 << 17),
418};
@ MUXFLAG_VMRECIPIENTS
@ MUXFLAG_READ
@ MUXFLAG_AUTO_DELETE
@ MUXFLAG_DEPRECATED_RWSYNC
@ MUXFLAG_REAL_CALLERID
@ MUXFLAG_WRITEVOLUME
@ 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 1800 of file app_mixmonitor.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1800 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 554 of file app_mixmonitor.c.

555{
556 /* recipients are in a single string with a format format resembling "mailbox@context/INBOX,mailbox2@context2,mailbox3@context3/Work" */
557 char *cur_mailbox = ast_strdupa(vm_recipients);
558 char *cur_context;
559 char *cur_folder;
560 char *next;
561 int elements_processed = 0;
562
563 while (!ast_strlen_zero(cur_mailbox)) {
564 ast_debug(3, "attempting to add next element %d from %s\n", elements_processed, cur_mailbox);
565 if ((next = strchr(cur_mailbox, ',')) || (next = strchr(cur_mailbox, '&'))) {
566 *(next++) = '\0';
567 }
568
569 if ((cur_folder = strchr(cur_mailbox, '/'))) {
570 *(cur_folder++) = '\0';
571 } else {
572 cur_folder = "INBOX";
573 }
574
575 if ((cur_context = strchr(cur_mailbox, '@'))) {
576 *(cur_context++) = '\0';
577 } else {
578 cur_context = "default";
579 }
580
581 if (!ast_strlen_zero(cur_mailbox) && !ast_strlen_zero(cur_context)) {
582 struct vm_recipient *recipient;
583 if (!(recipient = ast_malloc(sizeof(*recipient)))) {
584 ast_log(LOG_ERROR, "Failed to allocate recipient. Aborting function.\n");
585 return;
586 }
587 ast_copy_string(recipient->context, cur_context, sizeof(recipient->context));
588 ast_copy_string(recipient->mailbox, cur_mailbox, sizeof(recipient->mailbox));
589 ast_copy_string(recipient->folder, cur_folder, sizeof(recipient->folder));
590
591 /* Add to list */
592 ast_verb(4, "Adding %s@%s to recipient list\n", recipient->mailbox, recipient->context);
594 } else {
595 ast_log(LOG_ERROR, "Failed to properly parse extension and/or context from element %d of recipient string: %s\n", elements_processed, vm_recipients);
596 }
597
598 cur_mailbox = next;
599 elements_processed++;
600 }
601}
#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.
Definition: linkedlists.h:711
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::@42 recipient_list
char mailbox[AST_MAX_CONTEXT]
char context[AST_MAX_EXTENSION]
struct vm_recipient * next
char folder[80]
struct vm_recipient::@41 list

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 1800 of file app_mixmonitor.c.

◆ clear_mixmonitor_methods()

static int clear_mixmonitor_methods ( void  )
static

Definition at line 1758 of file app_mixmonitor.c.

1759{
1761}
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 603 of file app_mixmonitor.c.

604{
605 struct vm_recipient *current;
607 /* Clear list element data */
609 }
610}
#define ast_free(a)
Definition: astmm.h:180
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
size_t current
Definition: main/cli.c:113

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 646 of file app_mixmonitor.c.

647{
648 struct vm_recipient *recipient = NULL;
649 struct ast_vm_recording_data recording_data;
650 if (ast_string_field_init(&recording_data, 512)) {
651 ast_log(LOG_ERROR, "Failed to string_field_init, skipping copy_to_voicemail\n");
652 return;
653 }
654
655 /* Copy strings to stringfields that will be used for all recipients */
656 ast_string_field_set(&recording_data, recording_file, filename);
657 ast_string_field_set(&recording_data, recording_ext, ext);
662 /* and call_priority gets copied too */
663 recording_data.call_priority = mixmonitor->call_priority;
664
665 AST_LIST_TRAVERSE(&mixmonitor->recipient_list, recipient, list) {
666 /* context, mailbox, and folder need to be set per recipient */
667 ast_string_field_set(&recording_data, context, recipient->context);
668 ast_string_field_set(&recording_data, mailbox, recipient->mailbox);
669 ast_string_field_set(&recording_data, folder, recipient->folder);
670
671 ast_verb(4, "MixMonitor attempting to send voicemail copy to %s@%s\n", recording_data.mailbox,
672 recording_data.context);
673 ast_app_copy_recording_to_vm(&recording_data);
674 }
675
676 /* Free the string fields for recording_data before exiting the function. */
677 ast_string_field_free_memory(&recording_data);
678}
const char * ext
Definition: http.c:150
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.
Definition: linkedlists.h:491
#define NULL
Definition: resample.c:96
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
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 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 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, ast_vm_recording_data::call_priority, vm_recipient::context, voicemailpwcheck::context, ast_vm_recording_data::context, ext, vm_recipient::folder, ast_vm_recording_data::folder, LOG_ERROR, vm_recipient::mailbox, voicemailpwcheck::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 525 of file app_mixmonitor.c.

526{
531 }
532 /* kill the audiohook.*/
537}
#define ast_audiohook_lock(ah)
Lock an audiohook.
Definition: audiohook.h:313
int ast_audiohook_detach(struct ast_audiohook *audiohook)
Detach audiohook from channel.
Definition: audiohook.c:550
int ast_audiohook_destroy(struct ast_audiohook *audiohook)
Destroys an audiohook structure.
Definition: audiohook.c:124
#define ast_audiohook_unlock(ah)
Unlock an audiohook.
Definition: audiohook.h:318
#define ast_mutex_unlock(a)
Definition: lock.h:190
#define ast_mutex_lock(a)
Definition: lock.h:189
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 1114 of file app_mixmonitor.c.

1115{
1116 char *slash;
1117 char *ext;
1118
1119 ast_assert(len > 0);
1120
1121 if (ast_strlen_zero(filename)) {
1122 ast_log(LOG_WARNING, "No file name was provided for a file save option.\n");
1123 buffer[0] = 0;
1124 return buffer;
1125 }
1126
1127 /* If we don't have an absolute path, make one */
1128 if (*filename != '/') {
1129 char *build = ast_alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(filename) + 3);
1130 sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, filename);
1131 filename = build;
1132 }
1133
1134 ast_copy_string(buffer, filename, len);
1135
1136 /* If the provided filename has a .wav49 extension, we need to convert it to .WAV to
1137 match the behavior of build_filename in main/file.c. Otherwise MIXMONITOR_FILENAME
1138 ends up referring to a file that does not/will not exist */
1139 ext = strrchr(buffer, '.');
1140 if (ext && !strcmp(ext, ".wav49")) {
1141 /* Change to WAV - we know we have at least 6 writeable bytes where 'ext' points,
1142 * so this is safe */
1143 memcpy(ext, ".WAV", sizeof(".WAV"));
1144 }
1145
1146 if ((slash = strrchr(filename, '/'))) {
1147 *slash = '\0';
1148 }
1149 ast_mkdir(filename, 0777);
1150
1151 return buffer;
1152}
#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:155
#define ast_assert(a)
Definition: utils.h:739
int ast_mkdir(const char *path, int mode)
Recursively create directory path.
Definition: utils.c:2477

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().

◆ 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 1701 of file app_mixmonitor.c.

1703{
1704 struct ast_datastore *datastore;
1705 struct mixmonitor_ds *ds_data;
1707 AST_APP_ARG(id);
1708 AST_APP_ARG(key);
1709 );
1710
1712
1713 if (ast_strlen_zero(args.id) || ast_strlen_zero(args.key)) {
1714 ast_log(LOG_WARNING, "Not enough arguments provided to %s. "
1715 "An ID and key must be provided\n", cmd);
1716 return -1;
1717 }
1718
1719 ast_channel_lock(chan);
1720 datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, args.id);
1721 ast_channel_unlock(chan);
1722
1723 if (!datastore) {
1724 ast_log(LOG_WARNING, "Could not find MixMonitor with ID %s\n", args.id);
1725 return -1;
1726 }
1727
1728 ds_data = datastore->data;
1729
1730 if (!strcasecmp(args.key, "filename")) {
1731 ast_copy_string(buf, ds_data->filename, len);
1732 } else {
1733 ast_log(LOG_WARNING, "Unrecognized %s option %s\n", cmd, args.key);
1734 return -1;
1735 }
1736 return 0;
1737}
static const struct ast_datastore_info mixmonitor_ds_info
#define ast_channel_lock(chan)
Definition: channel.h:2922
#define ast_channel_unlock(chan)
Definition: channel.h:2923
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:2393
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.
Structure for a data store object.
Definition: datastore.h:64
void * data
Definition: datastore.h:66
const char * args

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 1376 of file app_mixmonitor.c.

1377{
1378 struct ast_channel *chan;
1379 struct ast_datastore *datastore = NULL;
1381
1382 switch (cmd) {
1383 case CLI_INIT:
1384 e->command = "mixmonitor {start|stop|list}";
1385 e->usage =
1386 "Usage: mixmonitor start <chan_name> [args]\n"
1387 " The optional arguments are passed to the MixMonitor application.\n"
1388 " mixmonitor stop <chan_name> [args]\n"
1389 " The optional arguments are passed to the StopMixMonitor application.\n"
1390 " mixmonitor list <chan_name>\n";
1391 return NULL;
1392 case CLI_GENERATE:
1393 return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
1394 }
1395
1396 if (a->argc < 3) {
1397 return CLI_SHOWUSAGE;
1398 }
1399
1400 if (!(chan = ast_channel_get_by_name_prefix(a->argv[2], strlen(a->argv[2])))) {
1401 ast_cli(a->fd, "No channel matching '%s' found.\n", a->argv[2]);
1402 /* Technically this is a failure, but we don't want 2 errors printing out */
1403 return CLI_SUCCESS;
1404 }
1405
1406 if (!strcasecmp(a->argv[1], "start")) {
1407 mixmonitor_exec(chan, (a->argc >= 4) ? a->argv[3] : "");
1408 } else if (!strcasecmp(a->argv[1], "stop")){
1409 stop_mixmonitor_exec(chan, (a->argc >= 4) ? a->argv[3] : "");
1410 } else if (!strcasecmp(a->argv[1], "list")) {
1411 ast_cli(a->fd, "MixMonitor ID\tFile\tReceive File\tTransmit File\n");
1412 ast_cli(a->fd, "=========================================================================\n");
1413 ast_channel_lock(chan);
1415 if (datastore->info == &mixmonitor_ds_info) {
1416 char *filename = "";
1417 char *filename_read = "";
1418 char *filename_write = "";
1419
1420 mixmonitor_ds = datastore->data;
1421 if (mixmonitor_ds->fs) {
1423 }
1424 if (mixmonitor_ds->fs_read) {
1425 filename_read = mixmonitor_ds->fs_read->filename;
1426 }
1427 if (mixmonitor_ds->fs_write) {
1428 filename_write = mixmonitor_ds->fs_write->filename;
1429 }
1430 ast_cli(a->fd, "%p\t%s\t%s\t%s\n", mixmonitor_ds, filename, filename_read, filename_write);
1431 }
1432 }
1433 ast_channel_unlock(chan);
1434 } else {
1435 chan = ast_channel_unref(chan);
1436 return CLI_SHOWUSAGE;
1437 }
1438
1439 chan = ast_channel_unref(chan);
1440
1441 return CLI_SUCCESS;
1442}
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:1428
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2958
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:1862
@ 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
char * filename
Definition: mod_format.h:107
Definition: search.h:40
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 
)
static

Definition at line 956 of file app_mixmonitor.c.

961{
962 pthread_t thread;
963 struct mixmonitor *mixmonitor;
964 char postprocess2[1024] = "";
965 char *datastore_id = NULL;
966
967 postprocess2[0] = 0;
968 /* If a post process system command is given attach it to the structure */
970 char *p1, *p2;
971
973 for (p2 = p1; *p2; p2++) {
974 if (*p2 == '^' && *(p2+1) == '{') {
975 *p2 = '$';
976 }
977 }
978 ast_channel_lock(chan);
979 pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1);
980 ast_channel_unlock(chan);
981 }
982
983 /* Pre-allocate mixmonitor structure and spy */
984 if (!(mixmonitor = ast_calloc(1, sizeof(*mixmonitor)))) {
985 return -1;
986 }
987
988 /* Now that the struct has been calloced, go ahead and initialize the string fields. */
991 return -1;
992 }
993
994 /* Setup the actual spy before creating our thread */
997 return -1;
998 }
999
1000 /* Copy over flags and channel name */
1002 if (!(mixmonitor->autochan = ast_autochan_setup(chan))) {
1004 return -1;
1005 }
1006
1007 if (!ast_strlen_zero(filename)) {
1009 }
1010
1013 }
1014
1017 }
1018
1019 if (setup_mixmonitor_ds(mixmonitor, chan, &datastore_id, beep_id)) {
1022 ast_free(datastore_id);
1023 return -1;
1024 }
1025
1026 if (!ast_strlen_zero(uid_channel_var)) {
1027 if (datastore_id) {
1028 pbx_builtin_setvar_helper(chan, uid_channel_var, datastore_id);
1029 }
1030 }
1031
1033
1034 if (!ast_strlen_zero(postprocess2)) {
1035 mixmonitor->post_process = ast_strdup(postprocess2);
1036 }
1037
1038 if (!ast_strlen_zero(recipients)) {
1039 char callerid[256];
1040
1041 ast_channel_lock(chan);
1042
1043 /* We use the connected line of the invoking channel for caller ID,
1044 * unless we've been told to use the Caller ID.
1045 * The initial use for this relied on Connected Line to get the
1046 * actual number for recording with Digium phones,
1047 * but in generic use the Caller ID is likely what people want.
1048 */
1049
1051 struct ast_party_caller *caller;
1052 caller = ast_channel_caller(chan);
1053 ast_debug(3, "Caller ID = %d - %s : %d - %s\n", caller->id.name.valid,
1054 caller->id.name.str, caller->id.number.valid,
1055 caller->id.number.str);
1056 ast_callerid_merge(callerid, sizeof(callerid),
1057 S_COR(caller->id.name.valid, caller->id.name.str, NULL),
1058 S_COR(caller->id.number.valid, caller->id.number.str, NULL),
1059 "Unknown");
1060 } else {
1063 ast_debug(3, "Connected Line CID = %d - %s : %d - %s\n", connected->id.name.valid,
1064 connected->id.name.str, connected->id.number.valid,
1065 connected->id.number.str);
1066 ast_callerid_merge(callerid, sizeof(callerid),
1067 S_COR(connected->id.name.valid, connected->id.name.str, NULL),
1068 S_COR(connected->id.number.valid, connected->id.number.str, NULL),
1069 "Unknown");
1070 }
1071
1073 ast_string_field_set(mixmonitor, call_extension, ast_channel_exten(chan));
1074 ast_string_field_set(mixmonitor, call_callerchan, ast_channel_name(chan));
1075 ast_string_field_set(mixmonitor, call_callerid, callerid);
1077
1078 ast_channel_unlock(chan);
1079
1081 }
1082
1086 }
1087
1088 if (readvol)
1090 if (writevol)
1092
1093 if (startmon(chan, &mixmonitor->audiohook)) {
1094 ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n",
1096 mixmonitor_ds_remove_and_free(chan, datastore_id);
1097 ast_free(datastore_id);
1101 return -1;
1102 }
1103
1104 ast_free(datastore_id);
1105
1106 /* reference be released at mixmonitor destruction */
1108
1110}
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:329
#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:1174
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)
char connected
Definition: eagi_proxy.c:82
ast_callid ast_read_threadstorage_callid(void)
extracts the callerid from the thread
Definition: logger.c:2048
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:418
struct ast_party_id id
Caller party ID.
Definition: channel.h:420
Connected Line/Party information.
Definition: channel.h:456
struct ast_party_name name
Subscriber name.
Definition: channel.h:340
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:342
unsigned char valid
TRUE if the name information is valid/present.
Definition: channel.h:279
char * str
Subscriber name (Malloced)
Definition: channel.h:264
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:297
char * str
Subscriber phone number (Malloced)
Definition: channel.h:291
char * filename_write
ast_callid callid
struct ast_autochan * autochan
char * post_process
char * filename_read
unsigned int flags
char * filename
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define ast_pthread_create_detached_background(a, b, c, d)
Definition: utils.h:597
#define ast_set_flag(p, flag)
Definition: utils.h:70

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(), 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 1779 of file app_mixmonitor.c.

1780{
1781 int res;
1782
1790 res |= set_mixmonitor_methods();
1791
1792 return res;
1793}
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:191
#define EVENT_FLAG_CALL
Definition: manager.h:76
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1558
#define ARRAY_LEN(a)
Definition: utils.h:666

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(), stop_app, and stop_mixmonitor_exec().

◆ manager_mixmonitor()

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

Definition at line 1597 of file app_mixmonitor.c.

1598{
1599 struct ast_channel *c;
1600 const char *name = astman_get_header(m, "Channel");
1601 const char *id = astman_get_header(m, "ActionID");
1602 const char *file = astman_get_header(m, "File");
1603 const char *options = astman_get_header(m, "Options");
1604 const char *command = astman_get_header(m, "Command");
1605 char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
1606 struct ast_flags flags = { 0 };
1607 char *uid_channel_var = NULL;
1608 const char *mixmonitor_id = NULL;
1609 int res;
1610 char args[PATH_MAX];
1611
1612 if (ast_strlen_zero(name)) {
1613 astman_send_error(s, m, "No channel specified");
1614 return AMI_SUCCESS;
1615 }
1616
1618 if (!c) {
1619 astman_send_error(s, m, "No such channel");
1620 return AMI_SUCCESS;
1621 }
1622
1623 if (!ast_strlen_zero(options)) {
1625 }
1626
1627 snprintf(args, sizeof(args), "%s,%s,%s", file, options, command);
1628
1629 res = mixmonitor_exec(c, args);
1630
1632 uid_channel_var = opts[OPT_ARG_UID];
1634 mixmonitor_id = pbx_builtin_getvar_helper(c, uid_channel_var);
1635 mixmonitor_id = ast_strdupa(S_OR(mixmonitor_id, ""));
1637 }
1638
1639 if (res) {
1641 astman_send_error(s, m, "Could not start monitoring channel");
1642 return AMI_SUCCESS;
1643 }
1644
1645 astman_append(s, "Response: Success\r\n");
1646
1647 if (!ast_strlen_zero(id)) {
1648 astman_append(s, "ActionID: %s\r\n", id);
1649 }
1650
1651 if (!ast_strlen_zero(mixmonitor_id)) {
1652 astman_append(s, "MixMonitorID: %s\r\n", mixmonitor_id);
1653 }
1654
1655 astman_append(s, "\r\n");
1656
1658
1659 return AMI_SUCCESS;
1660}
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 *name)
Find a channel by name.
Definition: channel.c:1448
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:3280
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:2941
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3201
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition: main/app.c:3056
#define 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:199
unsigned int flags
Definition: utils.h:200
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, make_ari_stubs::file, 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 1489 of file app_mixmonitor.c.

1490{
1491 struct ast_channel *c;
1492 const char *name = astman_get_header(m, "Channel");
1493 const char *id = astman_get_header(m, "ActionID");
1494 const char *state = astman_get_header(m, "State");
1495 const char *direction = astman_get_header(m,"Direction");
1496 const char *mixmonitor_id = astman_get_header(m, "MixMonitorID");
1497 int clearmute = 1, mutedcount = 0;
1500 RAII_VAR(struct ast_json *, stasis_message_blob, NULL, ast_json_unref);
1501
1503 astman_send_error(s, m, "No direction specified. Must be read, write or both");
1504 return AMI_SUCCESS;
1505 }
1506
1507 if (!strcasecmp(direction, "read")) {
1509 } else if (!strcasecmp(direction, "write")) {
1511 } else if (!strcasecmp(direction, "both")) {
1513 } else {
1514 astman_send_error(s, m, "Invalid direction specified. Must be read, write or both");
1515 return AMI_SUCCESS;
1516 }
1517
1518 if (ast_strlen_zero(name)) {
1519 astman_send_error(s, m, "No channel specified");
1520 return AMI_SUCCESS;
1521 }
1522
1523 if (ast_strlen_zero(state)) {
1524 astman_send_error(s, m, "No state specified");
1525 return AMI_SUCCESS;
1526 }
1527
1528 clearmute = ast_false(state);
1529
1531 if (!c) {
1532 astman_send_error(s, m, "No such channel");
1533 return AMI_SUCCESS;
1534 }
1535
1536 if (ast_strlen_zero(mixmonitor_id)) {
1537 mutedcount = ast_audiohook_set_mute_all(c, mixmonitor_spy_type, flag, clearmute);
1538 if (mutedcount < 0) {
1540 astman_send_error(s, m, "Cannot set mute flag");
1541 return AMI_SUCCESS;
1542 }
1543 } else {
1544 if (mute_mixmonitor_instance(c, mixmonitor_id, flag, clearmute)) {
1546 astman_send_error(s, m, "Cannot set mute flag");
1547 return AMI_SUCCESS;
1548 }
1549 mutedcount = 1;
1550 }
1551
1552
1553 stasis_message_blob = ast_json_pack("{s: s, s: b, s: s, s: i}",
1554 "direction", direction,
1555 "state", ast_true(state),
1556 "mixmonitorid", mixmonitor_id,
1557 "count", mutedcount);
1558
1560 ast_channel_mixmonitor_mute_type(), stasis_message_blob);
1561
1562 if (stasis_message) {
1564 }
1565
1566 astman_append(s, "Response: Success\r\n");
1567
1568 if (!ast_strlen_zero(id)) {
1569 astman_append(s, "ActionID: %s\r\n", id);
1570 }
1571
1572 astman_append(s, "\r\n");
1573
1575
1576 return AMI_SUCCESS;
1577}
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:1380
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
direction
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:602
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
Definition: stasis.c:1511
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:2197
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:2214
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:941

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 1662 of file app_mixmonitor.c.

1663{
1664 struct ast_channel *c;
1665 const char *name = astman_get_header(m, "Channel");
1666 const char *id = astman_get_header(m, "ActionID");
1667 const char *mixmonitor_id = astman_get_header(m, "MixMonitorID");
1668 int res;
1669
1670 if (ast_strlen_zero(name)) {
1671 astman_send_error(s, m, "No channel specified");
1672 return AMI_SUCCESS;
1673 }
1674
1676 if (!c) {
1677 astman_send_error(s, m, "No such channel");
1678 return AMI_SUCCESS;
1679 }
1680
1681 res = stop_mixmonitor_full(c, mixmonitor_id);
1682 if (res) {
1684 astman_send_error(s, m, "Could not stop monitoring channel");
1685 return AMI_SUCCESS;
1686 }
1687
1688 astman_append(s, "Response: Success\r\n");
1689
1690 if (!ast_strlen_zero(id)) {
1691 astman_append(s, "ActionID: %s\r\n", id);
1692 }
1693
1694 astman_append(s, "\r\n");
1695
1697
1698 return AMI_SUCCESS;
1699}
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 709 of file app_mixmonitor.c.

710{
711 int is_bridged;
712
714 is_bridged = ast_channel_is_bridged(autochan->chan);
716 return is_bridged;
717}
#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:10537
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 477 of file app_mixmonitor.c.

478{
479 unsigned char quitting = 0;
480
481 if (mixmonitor_ds->fs) {
482 quitting = 1;
485 ast_verb(2, "MixMonitor close filestream (mixed)\n");
486 }
487
488 if (mixmonitor_ds->fs_read) {
489 quitting = 1;
492 ast_verb(2, "MixMonitor close filestream (read)\n");
493 }
494
495 if (mixmonitor_ds->fs_write) {
496 quitting = 1;
499 ast_verb(2, "MixMonitor close filestream (write)\n");
500 }
501
502 if (quitting) {
504 }
505}
int ast_closestream(struct ast_filestream *f)
Closes a stream.
Definition: file.c:1111

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 938 of file app_mixmonitor.c.

939{
940 struct ast_datastore *datastore;
941
942 ast_channel_lock(chan);
943
944 datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, datastore_id);
945
946 /*
947 * Currently the one place this function is called from guarantees a
948 * datastore is present, thus return checks can be avoided here.
949 */
950 ast_channel_datastore_remove(chan, datastore);
951 ast_datastore_free(datastore);
952
953 ast_channel_unlock(chan);
954}
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2388
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 1154 of file app_mixmonitor.c.

1155{
1156 int x, readvol = 0, writevol = 0;
1157 char *filename_read = NULL;
1158 char *filename_write = NULL;
1159 char filename_buffer[1024] = "";
1160 char *uid_channel_var = NULL;
1161 char beep_id[64] = "";
1162
1163 struct ast_flags flags = { 0 };
1164 char *recipients = NULL;
1165 char *parse;
1168 AST_APP_ARG(filename);
1170 AST_APP_ARG(post_process);
1171 );
1172
1173 if (ast_strlen_zero(data)) {
1174 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename or ,t(filename) and/or r(filename)\n");
1175 return -1;
1176 }
1177
1178 parse = ast_strdupa(data);
1179
1181
1182 if (args.options) {
1183 char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
1184
1186
1188 ast_log(LOG_NOTICE, "The synchronization behavior enabled by the 'S' option is now the default"
1189 " and does not need to be specified.\n");
1190 }
1191
1194 ast_log(LOG_WARNING, "No volume level was provided for the heard volume ('v') option.\n");
1195 } else if ((sscanf(opts[OPT_ARG_READVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
1196 ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_READVOLUME]);
1197 } else {
1198 readvol = get_volfactor(x);
1199 }
1200 }
1201
1204 ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n");
1205 } else if ((sscanf(opts[OPT_ARG_WRITEVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
1206 ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_WRITEVOLUME]);
1207 } else {
1208 writevol = get_volfactor(x);
1209 }
1210 }
1211
1213 if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) {
1214 ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n");
1215 } else if ((sscanf(opts[OPT_ARG_VOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
1216 ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]);
1217 } else {
1218 readvol = writevol = get_volfactor(x);
1219 }
1220 }
1221
1224 ast_log(LOG_WARNING, "No voicemail recipients were specified for the vm copy ('m') option.\n");
1225 } else {
1226 recipients = ast_strdupa(opts[OPT_ARG_VMRECIPIENTS]);
1227 }
1228 }
1229
1231 filename_write = ast_strdupa(filename_parse(opts[OPT_ARG_WRITENAME], filename_buffer, sizeof(filename_buffer)));
1232 }
1233
1235 filename_read = ast_strdupa(filename_parse(opts[OPT_ARG_READNAME], filename_buffer, sizeof(filename_buffer)));
1236 }
1237
1239 uid_channel_var = opts[OPT_ARG_UID];
1240 }
1241
1243 const char *interval_str = S_OR(opts[OPT_ARG_BEEP_INTERVAL], "15");
1244 unsigned int interval = 15;
1245
1246 if (sscanf(interval_str, "%30u", &interval) != 1) {
1247 ast_log(LOG_WARNING, "Invalid interval '%s' for periodic beep. Using default of %u\n",
1248 interval_str, interval);
1249 }
1250
1251 if (ast_beep_start(chan, interval, beep_id, sizeof(beep_id))) {
1252 ast_log(LOG_WARNING, "Unable to enable periodic beep, please ensure func_periodic_hook is loaded.\n");
1253 return -1;
1254 }
1255 }
1256 }
1257 /* If there are no file writing arguments/options for the mix monitor, send a warning message and return -1 */
1258
1260 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n");
1261 return -1;
1262 }
1263
1264 /* If filename exists, try to create directories for it */
1265 if (!(ast_strlen_zero(args.filename))) {
1266 args.filename = ast_strdupa(filename_parse(args.filename, filename_buffer, sizeof(filename_buffer)));
1267 }
1268
1269 pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename);
1270
1271 /* If launch_monitor_thread works, the module reference must not be released until it is finished. */
1273 if (launch_monitor_thread(chan,
1274 args.filename,
1275 flags.flags,
1276 readvol,
1277 writevol,
1278 args.post_process,
1279 filename_write,
1280 filename_read,
1281 uid_channel_var,
1282 recipients,
1283 beep_id)) {
1285 }
1286
1289 if (message) {
1291 }
1292
1293 return 0;
1294}
static char * filename_parse(char *filename, char *buffer, size_t len)
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)
#define get_volfactor(x)
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:469
#define ast_module_ref(mod)
Hold a reference to the module.
Definition: module.h:443
struct ast_module * self
Definition: module.h:342

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, get_volfactor, launch_monitor_thread(), LOG_NOTICE, LOG_WARNING, mixmonitor_opts, MUXFLAG_BEEP, MUXFLAG_DEPRECATED_RWSYNC, MUXFLAG_READ, MUXFLAG_READVOLUME, 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_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 680 of file app_mixmonitor.c.

681{
682 /* Initialize the file if not already done so */
683 char *last_slash = NULL;
684 if (!ast_strlen_zero(filename)) {
685 if (!*fs && !*errflag && !mixmonitor->mixmonitor_ds->fs_quit) {
686 *oflags = O_CREAT | O_WRONLY;
687 *oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC;
688
689 last_slash = strrchr(filename, '/');
690
691 if ((*ext = strrchr(filename, '.')) && (*ext > last_slash)) {
692 **ext = '\0';
693 *ext = *ext + 1;
694 } else {
695 *ext = "raw";
696 }
697
698 if (!(*fs = ast_writefile(filename, *ext, NULL, *oflags, 0, 0666))) {
699 ast_log(LOG_ERROR, "Cannot open %s.%s\n", filename, *ext);
700 *errflag = 1;
701 } else {
702 struct ast_filestream *tmp = *fs;
704 }
705 }
706 }
707}
static int tmp()
Definition: bt_open.c:389
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:1423
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
unsigned int samp_rate
#define MAX(a, b)
Definition: utils.h:233

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

Referenced by mixmonitor_thread().

◆ mixmonitor_thread()

static void * mixmonitor_thread ( void *  obj)
static

Definition at line 719 of file app_mixmonitor.c.

720{
721 struct mixmonitor *mixmonitor = obj;
722 char *fs_ext = "";
723 char *fs_read_ext = "";
724 char *fs_write_ext = "";
725
726 struct ast_filestream **fs = NULL;
727 struct ast_filestream **fs_read = NULL;
728 struct ast_filestream **fs_write = NULL;
729
730 unsigned int oflags;
731 int errflag = 0;
732 struct ast_format *format_slin;
733
734 /* Keep callid association before any log messages */
735 if (mixmonitor->callid) {
737 }
738
739 ast_verb(2, "Begin MixMonitor Recording %s\n", mixmonitor->name);
740
742 fs_read = &mixmonitor->mixmonitor_ds->fs_read;
743 fs_write = &mixmonitor->mixmonitor_ds->fs_write;
744
746 mixmonitor_save_prep(mixmonitor, mixmonitor->filename, fs, &oflags, &errflag, &fs_ext);
747 mixmonitor_save_prep(mixmonitor, mixmonitor->filename_read, fs_read, &oflags, &errflag, &fs_read_ext);
748 mixmonitor_save_prep(mixmonitor, mixmonitor->filename_write, fs_write, &oflags, &errflag, &fs_write_ext);
749
751
753
754 /* The audiohook must enter and exit the loop locked */
757 struct ast_frame *fr = NULL;
758 struct ast_frame *fr_read = NULL;
759 struct ast_frame *fr_write = NULL;
760
762 &fr_read, &fr_write))) {
764
766 break;
767 }
768 continue;
769 }
770
771 /* audiohook lock is not required for the next block.
772 * Unlock it, but remember to lock it before looping or exiting */
774
778
779 /* Write out the frame(s) */
780 if ((*fs_read) && (fr_read)) {
781 struct ast_frame *cur;
782
783 for (cur = fr_read; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
784 ast_writestream(*fs_read, cur);
785 }
786 }
787
788 if ((*fs_write) && (fr_write)) {
789 struct ast_frame *cur;
790
791 for (cur = fr_write; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
792 ast_writestream(*fs_write, cur);
793 }
794 }
795
796 if ((*fs) && (fr)) {
797 struct ast_frame *cur;
798
799 for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
800 ast_writestream(*fs, cur);
801 }
802 }
804 }
805 /* All done! free it. */
806 if (fr) {
807 ast_frame_free(fr, 0);
808 }
809 if (fr_read) {
810 ast_frame_free(fr_read, 0);
811 }
812 if (fr_write) {
813 ast_frame_free(fr_write, 0);
814 }
815
816 fr = NULL;
817 fr_write = NULL;
818 fr_read = NULL;
819
821 }
822
824
829 }
830
832
833 /* Datastore cleanup. close the filestream and wait for ds destruction */
838 }
840
841 /* kill the audiohook */
843
845 ast_verb(2, "Executing [%s]\n", mixmonitor->post_process);
847 }
848
849 ast_verb(2, "End MixMonitor Recording %s\n", mixmonitor->name);
850 ast_test_suite_event_notify("MIXMONITOR_END", "File: %s\r\n", mixmonitor->filename);
851
853 if (ast_strlen_zero(fs_ext)) {
854 ast_log(LOG_ERROR, "No file extension set for Mixmonitor %s. Skipping copy to voicemail.\n",
855 mixmonitor -> name);
856 } else {
857 ast_verb(3, "Copying recordings for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
859 }
860 if (!ast_strlen_zero(fs_read_ext)) {
861 ast_verb(3, "Copying read recording for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
863 }
864 if (!ast_strlen_zero(fs_write_ext)) {
865 ast_verb(3, "Copying write recording for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
867 }
868 } else {
869 ast_debug(3, "No recipients to forward monitor to, moving on.\n");
870 }
871
873 ast_debug(3, "Deleting our copies of recording files\n");
874 if (!ast_strlen_zero(fs_ext)) {
876 }
877 if (!ast_strlen_zero(fs_read_ext)) {
879 }
880 if (!ast_strlen_zero(fs_write_ext)) {
882 }
883 }
884
886
888 return NULL;
889}
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)
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:451
void ast_audiohook_trigger_wait(struct ast_audiohook *audiohook)
Wait for audiohook trigger to be triggered.
Definition: audiohook.c:1094
@ AST_AUDIOHOOK_STATUS_RUNNING
Definition: audiohook.h:43
int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
Writes a frame to a stream.
Definition: file.c:244
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:1877
int ast_filedelete(const char *filename, const char *fmt)
Deletes a file.
Definition: file.c:1141
struct ast_format * ast_format_cache_get_slin_by_rate(unsigned int rate)
Retrieve the best signed linear format given a sample rate.
Definition: format_cache.c:512
int ast_safe_system(const char *s)
Safely spawn an OS shell command while closing file descriptors.
Definition: extconf.c:829
void ast_frame_free(struct ast_frame *frame, int cache)
Frees a frame or list of frames.
Definition: main/frame.c:176
int ast_callid_threadassoc_add(ast_callid callid)
Adds a known callid to thread storage of the calling thread.
Definition: logger.c:2070
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:450
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:439
#define ast_cond_wait(cond, mutex)
Definition: lock.h:205
enum ast_audiohook_status status
Definition: audiohook.h:108
Definition of a media format.
Definition: format.c:43
Data structure associated with a single frame of data.
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:189

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_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_verb, ast_writestream(), mixmonitor::audiohook, mixmonitor::autochan, mixmonitor::callid, ast_autochan::chan, copy_to_voicemail(), destroy_monitor_audiohook(), mixmonitor_ds::destruction_condition, mixmonitor_ds::destruction_ok, mixmonitor::filename, mixmonitor::filename_read, mixmonitor::filename_write, 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, name, mixmonitor::name, NULL, mixmonitor::post_process, mixmonitor::recipient_list, mixmonitor_ds::samp_rate, SAMPLES_PER_FRAME, ast_module_info::self, and ast_audiohook::status.

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 1445 of file app_mixmonitor.c.

1447{
1448 struct ast_datastore *datastore = NULL;
1449 char *parse = "";
1451
1453 AST_APP_ARG(mixmonid);
1454 );
1455
1456 if (!ast_strlen_zero(data)) {
1457 parse = ast_strdupa(data);
1458 }
1459
1461
1462 ast_channel_lock(chan);
1463
1465 S_OR(args.mixmonid, NULL));
1466 if (!datastore) {
1467 ast_channel_unlock(chan);
1468 return -1;
1469 }
1470 mixmonitor_ds = datastore->data;
1471
1473
1474 if (mixmonitor_ds->audiohook) {
1475 if (clearmute) {
1477 } else {
1479 }
1480 }
1481
1483 ast_channel_unlock(chan);
1484
1485 return 0;
1486}
#define ast_clear_flag(p, flag)
Definition: utils.h:77

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 1748 of file app_mixmonitor.c.

1749{
1753 };
1754
1756}
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 891 of file app_mixmonitor.c.

892{
893 struct ast_datastore *datastore = NULL;
895
896 if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) {
897 return -1;
898 }
899
900 if (ast_asprintf(datastore_id, "%p", mixmonitor_ds) == -1) {
901 ast_log(LOG_ERROR, "Failed to allocate memory for MixMonitor ID.\n");
903 return -1;
904 }
905
908
909 if (!(datastore = ast_datastore_alloc(&mixmonitor_ds_info, *datastore_id))) {
913 return -1;
914 }
915
920 }
921
922 mixmonitor_ds->samp_rate = 8000;
925 if (!ast_strlen_zero(beep_id)) {
927 }
928 datastore->data = mixmonitor_ds;
929
930 ast_channel_lock(chan);
931 ast_channel_datastore_add(chan, datastore);
932 ast_channel_unlock(chan);
933
935 return 0;
936}
#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:2379
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:85
#define ast_cond_init(cond, attr)
Definition: lock.h:201
#define ast_mutex_init(pmutex)
Definition: lock.h:186

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 1579 of file app_mixmonitor.c.

1580{
1581 char args[PATH_MAX];
1582
1583 if (ast_strlen_zero(options)) {
1584 snprintf(args, sizeof(args), "%s", filename);
1585 } else {
1586 snprintf(args, sizeof(args), "%s,%s", filename, options);
1587 }
1588
1589 return mixmonitor_exec(chan, args);
1590}

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 539 of file app_mixmonitor.c.

540{
541 if (!chan) {
542 return -1;
543 }
544
545 return ast_audiohook_attach(chan, audiohook);
546}
int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
Attach audiohook to channel.
Definition: audiohook.c:484

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 1592 of file app_mixmonitor.c.

1593{
1594 return stop_mixmonitor_full(chan, mixmonitor_id);
1595}

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 1370 of file app_mixmonitor.c.

1371{
1372 stop_mixmonitor_full(chan, data);
1373 return 0;
1374}

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 1296 of file app_mixmonitor.c.

1297{
1298 struct ast_datastore *datastore = NULL;
1299 char *parse = "";
1301 const char *beep_id = NULL;
1303
1305 AST_APP_ARG(mixmonid);
1306 );
1307
1308 if (!ast_strlen_zero(data)) {
1309 parse = ast_strdupa(data);
1310 }
1311
1313
1314 ast_channel_lock(chan);
1315
1317 S_OR(args.mixmonid, NULL));
1318 if (!datastore) {
1319 ast_channel_unlock(chan);
1320 return -1;
1321 }
1322 mixmonitor_ds = datastore->data;
1323
1325
1326 /* closing the filestream here guarantees the file is available to the dialplan
1327 * after calling StopMixMonitor */
1329
1330 /* The mixmonitor thread may be waiting on the audiohook trigger.
1331 * In order to exit from the mixmonitor loop before waiting on channel
1332 * destruction, poke the audiohook trigger. */
1333 if (mixmonitor_ds->audiohook) {
1336 }
1341 }
1342
1345 }
1346
1348
1349 /* Remove the datastore so the monitor thread can exit */
1350 if (!ast_channel_datastore_remove(chan, datastore)) {
1351 ast_datastore_free(datastore);
1352 }
1353
1354 ast_channel_unlock(chan);
1355
1356 if (!ast_strlen_zero(beep_id)) {
1357 ast_beep_stop(chan, beep_id);
1358 }
1359
1362 NULL);
1363 if (message) {
1365 }
1366
1367 return 0;
1368}
void ast_audiohook_update_status(struct ast_audiohook *audiohook, enum ast_audiohook_status status)
Update audiohook's status.
Definition: audiohook.c:540
@ 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 1763 of file app_mixmonitor.c.

1764{
1765 int res;
1766
1770 res |= ast_manager_unregister("MixMonitorMute");
1771 res |= ast_manager_unregister("MixMonitor");
1772 res |= ast_manager_unregister("StopMixMonitor");
1774 res |= clear_mixmonitor_methods();
1775
1776 return res;
1777}
static int clear_mixmonitor_methods(void)
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7887
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
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, 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 = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .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 1800 of file app_mixmonitor.c.

◆ app

const char* const app = "MixMonitor"
static

Definition at line 357 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 1800 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 1744 of file app_mixmonitor.c.

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 520 of file app_mixmonitor.c.

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 1739 of file app_mixmonitor.c.

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 }, [ '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 }, }
static

Definition at line 451 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 359 of file app_mixmonitor.c.

Referenced by load_module(), and unload_module().