Asterisk - The Open Source Telephony Project GIT-master-27fb039
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 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) , MUXFLAG_INTERLEAVED = (1 << 18)
}
 

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.
 
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 }, }
 
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 394 of file app_mixmonitor.c.

◆ SAMPLES_PER_FRAME

#define SAMPLES_PER_FRAME   160

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

460 {
471 OPT_ARG_ARRAY_SIZE, /* Always last element of the enum */
472};
@ 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 

Definition at line 439 of file app_mixmonitor.c.

439 {
440 MUXFLAG_APPEND = (1 << 1),
441 MUXFLAG_BRIDGED = (1 << 2),
442 MUXFLAG_VOLUME = (1 << 3),
443 MUXFLAG_READVOLUME = (1 << 4),
444 MUXFLAG_WRITEVOLUME = (1 << 5),
445 MUXFLAG_READ = (1 << 6),
446 MUXFLAG_WRITE = (1 << 7),
447 MUXFLAG_COMBINED = (1 << 8),
448 MUXFLAG_UID = (1 << 9),
449 MUXFLAG_VMRECIPIENTS = (1 << 10),
450 MUXFLAG_BEEP = (1 << 11),
451 MUXFLAG_BEEP_START = (1 << 12),
452 MUXFLAG_BEEP_STOP = (1 << 13),
453 MUXFLAG_DEPRECATED_RWSYNC = (1 << 14),
454 MUXFLAG_NO_RWSYNC = (1 << 15),
455 MUXFLAG_AUTO_DELETE = (1 << 16),
456 MUXFLAG_REAL_CALLERID = (1 << 17),
457 MUXFLAG_INTERLEAVED = (1 << 18),
458};
@ 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 1881 of file app_mixmonitor.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

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

596{
597 /* recipients are in a single string with a format format resembling "mailbox@context/INBOX,mailbox2@context2,mailbox3@context3/Work" */
598 char *cur_mailbox = ast_strdupa(vm_recipients);
599 char *cur_context;
600 char *cur_folder;
601 char *next;
602 int elements_processed = 0;
603
604 while (!ast_strlen_zero(cur_mailbox)) {
605 ast_debug(3, "attempting to add next element %d from %s\n", elements_processed, cur_mailbox);
606 if ((next = strchr(cur_mailbox, ',')) || (next = strchr(cur_mailbox, '&'))) {
607 *(next++) = '\0';
608 }
609
610 if ((cur_folder = strchr(cur_mailbox, '/'))) {
611 *(cur_folder++) = '\0';
612 } else {
613 cur_folder = "INBOX";
614 }
615
616 if ((cur_context = strchr(cur_mailbox, '@'))) {
617 *(cur_context++) = '\0';
618 } else {
619 cur_context = "default";
620 }
621
622 if (!ast_strlen_zero(cur_mailbox) && !ast_strlen_zero(cur_context)) {
623 struct vm_recipient *recipient;
624 if (!(recipient = ast_malloc(sizeof(*recipient)))) {
625 ast_log(LOG_ERROR, "Failed to allocate recipient. Aborting function.\n");
626 return;
627 }
628 ast_copy_string(recipient->context, cur_context, sizeof(recipient->context));
629 ast_copy_string(recipient->mailbox, cur_mailbox, sizeof(recipient->mailbox));
630 ast_copy_string(recipient->folder, cur_folder, sizeof(recipient->folder));
631
632 /* Add to list */
633 ast_verb(4, "Adding %s@%s to recipient list\n", recipient->mailbox, recipient->context);
635 } else {
636 ast_log(LOG_ERROR, "Failed to properly parse extension and/or context from element %d of recipient string: %s\n", elements_processed, vm_recipients);
637 }
638
639 cur_mailbox = next;
640 elements_processed++;
641 }
642}
#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 1881 of file app_mixmonitor.c.

◆ clear_mixmonitor_methods()

static int clear_mixmonitor_methods ( void  )
static

Definition at line 1839 of file app_mixmonitor.c.

1840{
1842}
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 644 of file app_mixmonitor.c.

645{
646 struct vm_recipient *current;
648 /* Clear list element data */
650 }
651}
#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 687 of file app_mixmonitor.c.

688{
689 struct vm_recipient *recipient = NULL;
692 ast_log(LOG_ERROR, "Failed to string_field_init, skipping copy_to_voicemail\n");
693 return;
694 }
695
696 /* Copy strings to stringfields that will be used for all recipients */
703 /* and call_priority gets copied too */
704 recording_data.call_priority = mixmonitor->call_priority;
705
706 AST_LIST_TRAVERSE(&mixmonitor->recipient_list, recipient, list) {
707 /* context, mailbox, and folder need to be set per recipient */
711
712 ast_verb(4, "MixMonitor attempting to send voicemail copy to %s@%s\n", recording_data.mailbox,
713 recording_data.context);
715 }
716
717 /* Free the string fields for recording_data before exiting the function. */
719}
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.
#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 566 of file app_mixmonitor.c.

567{
572 }
573 /* kill the audiohook.*/
578}
#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: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:318
#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 1195 of file app_mixmonitor.c.

1196{
1197 char *slash;
1198 char *ext;
1199
1200 ast_assert(len > 0);
1201
1202 if (ast_strlen_zero(filename)) {
1203 ast_log(LOG_WARNING, "No file name was provided for a file save option.\n");
1204 buffer[0] = 0;
1205 return buffer;
1206 }
1207
1208 /* If we don't have an absolute path, make one */
1209 if (*filename != '/') {
1210 char *build = ast_alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(filename) + 3);
1211 sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, filename);
1212 filename = build;
1213 }
1214
1215 ast_copy_string(buffer, filename, len);
1216
1217 /* If the provided filename has a .wav49 extension, we need to convert it to .WAV to
1218 match the behavior of build_filename in main/file.c. Otherwise MIXMONITOR_FILENAME
1219 ends up referring to a file that does not/will not exist */
1220 ext = strrchr(buffer, '.');
1221 if (ext && !strcmp(ext, ".wav49")) {
1222 /* Change to WAV - we know we have at least 6 writeable bytes where 'ext' points,
1223 * so this is safe */
1224 memcpy(ext, ".WAV", sizeof(".WAV"));
1225 }
1226
1227 if ((slash = strrchr(filename, '/'))) {
1228 *slash = '\0';
1229 }
1230 ast_mkdir(filename, 0777);
1231
1232 return buffer;
1233}
#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:2515

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

1784{
1785 struct ast_datastore *datastore;
1786 struct mixmonitor_ds *ds_data;
1788 AST_APP_ARG(id);
1789 AST_APP_ARG(key);
1790 );
1791
1793
1794 if (ast_strlen_zero(args.id) || ast_strlen_zero(args.key)) {
1795 ast_log(LOG_WARNING, "Not enough arguments provided to %s. "
1796 "An ID and key must be provided\n", cmd);
1797 return -1;
1798 }
1799
1800 ast_channel_lock(chan);
1801 datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, args.id);
1802 ast_channel_unlock(chan);
1803
1804 if (!datastore) {
1805 ast_log(LOG_WARNING, "Could not find MixMonitor with ID %s\n", args.id);
1806 return -1;
1807 }
1808
1809 ds_data = datastore->data;
1810
1811 if (!strcasecmp(args.key, "filename")) {
1812 ast_copy_string(buf, ds_data->filename, len);
1813 } else {
1814 ast_log(LOG_WARNING, "Unrecognized %s option %s\n", cmd, args.key);
1815 return -1;
1816 }
1817 return 0;
1818}
static const struct ast_datastore_info mixmonitor_ds_info
#define ast_channel_lock(chan)
Definition channel.h:2982
#define ast_channel_unlock(chan)
Definition channel.h:2983
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:2389
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 @519 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 1457 of file app_mixmonitor.c.

1458{
1459 struct ast_channel *chan;
1460 struct ast_datastore *datastore = NULL;
1462
1463 switch (cmd) {
1464 case CLI_INIT:
1465 e->command = "mixmonitor {start|stop|list}";
1466 e->usage =
1467 "Usage: mixmonitor start <chan_name> [args]\n"
1468 " The optional arguments are passed to the MixMonitor application.\n"
1469 " mixmonitor stop <chan_name> [args]\n"
1470 " The optional arguments are passed to the StopMixMonitor application.\n"
1471 " mixmonitor list <chan_name>\n";
1472 return NULL;
1473 case CLI_GENERATE:
1474 return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
1475 }
1476
1477 if (a->argc < 3) {
1478 return CLI_SHOWUSAGE;
1479 }
1480
1481 if (!(chan = ast_channel_get_by_name_prefix(a->argv[2], strlen(a->argv[2])))) {
1482 ast_cli(a->fd, "No channel matching '%s' found.\n", a->argv[2]);
1483 /* Technically this is a failure, but we don't want 2 errors printing out */
1484 return CLI_SUCCESS;
1485 }
1486
1487 if (!strcasecmp(a->argv[1], "start")) {
1488 mixmonitor_exec(chan, (a->argc >= 4) ? a->argv[3] : "");
1489 } else if (!strcasecmp(a->argv[1], "stop")){
1490 stop_mixmonitor_exec(chan, (a->argc >= 4) ? a->argv[3] : "");
1491 } else if (!strcasecmp(a->argv[1], "list")) {
1492 ast_cli(a->fd, "MixMonitor ID\tFile\tReceive File\tTransmit File\n");
1493 ast_cli(a->fd, "=========================================================================\n");
1494 ast_channel_lock(chan);
1495 AST_LIST_TRAVERSE(ast_channel_datastores(chan), datastore, entry) {
1496 if (datastore->info == &mixmonitor_ds_info) {
1497 char *filename = "";
1498 char *filename_read = "";
1499 char *filename_write = "";
1500
1501 mixmonitor_ds = datastore->data;
1502 if (mixmonitor_ds->fs) {
1504 }
1505 if (mixmonitor_ds->fs_read) {
1506 filename_read = mixmonitor_ds->fs_read->filename;
1507 }
1508 if (mixmonitor_ds->fs_write) {
1509 filename_write = mixmonitor_ds->fs_write->filename;
1510 }
1511 ast_cli(a->fd, "%p\t%s\t%s\t%s\n", mixmonitor_ds, filename, filename_read, filename_write);
1512 }
1513 }
1514 ast_channel_unlock(chan);
1515 } else {
1516 chan = ast_channel_unref(chan);
1517 return CLI_SHOWUSAGE;
1518 }
1519
1520 chan = ast_channel_unref(chan);
1521
1522 return CLI_SUCCESS;
1523}
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:1399
#define ast_channel_unref(c)
Decrease channel reference count.
Definition channel.h:3018
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:1842
@ 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 
)
static

Definition at line 1037 of file app_mixmonitor.c.

1042{
1043 pthread_t thread;
1044 struct mixmonitor *mixmonitor;
1045 char postprocess2[1024] = "";
1046 char *datastore_id = NULL;
1047
1048 postprocess2[0] = 0;
1049 /* If a post process system command is given attach it to the structure */
1051 char *p1, *p2;
1052
1054 for (p2 = p1; *p2; p2++) {
1055 if (*p2 == '^' && *(p2+1) == '{') {
1056 *p2 = '$';
1057 }
1058 }
1059 ast_channel_lock(chan);
1060 pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1);
1061 ast_channel_unlock(chan);
1062 }
1063
1064 /* Pre-allocate mixmonitor structure and spy */
1065 if (!(mixmonitor = ast_calloc(1, sizeof(*mixmonitor)))) {
1066 return -1;
1067 }
1068
1069 /* Now that the struct has been calloced, go ahead and initialize the string fields. */
1072 return -1;
1073 }
1074
1075 /* Setup the actual spy before creating our thread */
1078 return -1;
1079 }
1080
1081 /* Copy over flags and channel name */
1083 if (!(mixmonitor->autochan = ast_autochan_setup(chan))) {
1085 return -1;
1086 }
1087
1088 if (!ast_strlen_zero(filename)) {
1090 }
1091
1094 }
1095
1098 }
1099
1100 if (setup_mixmonitor_ds(mixmonitor, chan, &datastore_id, beep_id)) {
1103 ast_free(datastore_id);
1104 return -1;
1105 }
1106
1107 if (!ast_strlen_zero(uid_channel_var)) {
1108 if (datastore_id) {
1109 pbx_builtin_setvar_helper(chan, uid_channel_var, datastore_id);
1110 }
1111 }
1112
1114
1115 if (!ast_strlen_zero(postprocess2)) {
1116 mixmonitor->post_process = ast_strdup(postprocess2);
1117 }
1118
1119 if (!ast_strlen_zero(recipients)) {
1120 char callerid[256];
1121
1122 ast_channel_lock(chan);
1123
1124 /* We use the connected line of the invoking channel for caller ID,
1125 * unless we've been told to use the Caller ID.
1126 * The initial use for this relied on Connected Line to get the
1127 * actual number for recording with Digium phones,
1128 * but in generic use the Caller ID is likely what people want.
1129 */
1130
1132 struct ast_party_caller *caller;
1133 caller = ast_channel_caller(chan);
1134 ast_debug(3, "Caller ID = %d - %s : %d - %s\n", caller->id.name.valid,
1135 caller->id.name.str, caller->id.number.valid,
1136 caller->id.number.str);
1137 ast_callerid_merge(callerid, sizeof(callerid),
1138 S_COR(caller->id.name.valid, caller->id.name.str, NULL),
1139 S_COR(caller->id.number.valid, caller->id.number.str, NULL),
1140 "Unknown");
1141 } else {
1144 ast_debug(3, "Connected Line CID = %d - %s : %d - %s\n", connected->id.name.valid,
1145 connected->id.name.str, connected->id.number.valid,
1146 connected->id.number.str);
1147 ast_callerid_merge(callerid, sizeof(callerid),
1148 S_COR(connected->id.name.valid, connected->id.name.str, NULL),
1149 S_COR(connected->id.number.valid, connected->id.number.str, NULL),
1150 "Unknown");
1151 }
1152
1154 ast_string_field_set(mixmonitor, call_extension, ast_channel_exten(chan));
1155 ast_string_field_set(mixmonitor, call_callerchan, ast_channel_name(chan));
1156 ast_string_field_set(mixmonitor, call_callerid, callerid);
1158
1159 ast_channel_unlock(chan);
1160
1162 }
1163
1167 }
1168
1169 if (readvol)
1171 if (writevol)
1173
1174 if (startmon(chan, &mixmonitor->audiohook)) {
1175 ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n",
1177 mixmonitor_ds_remove_and_free(chan, datastore_id);
1178 ast_free(datastore_id);
1182 return -1;
1183 }
1184
1185 ast_free(datastore_id);
1186
1187 /* reference be released at mixmonitor destruction */
1189
1191}
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
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(), 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 1860 of file app_mixmonitor.c.

1861{
1862 int res;
1863
1871 res |= set_mixmonitor_methods();
1872
1873 return res;
1874}
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:192
#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:1562
#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 1678 of file app_mixmonitor.c.

1679{
1680 struct ast_channel *c;
1681 const char *name = astman_get_header(m, "Channel");
1682 const char *id = astman_get_header(m, "ActionID");
1683 const char *file = astman_get_header(m, "File");
1684 const char *options = astman_get_header(m, "Options");
1685 const char *command = astman_get_header(m, "Command");
1686 char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
1687 struct ast_flags flags = { 0 };
1688 char *uid_channel_var = NULL;
1689 const char *mixmonitor_id = NULL;
1690 int res;
1691 char args[PATH_MAX];
1692
1693 if (ast_strlen_zero(name)) {
1694 astman_send_error(s, m, "No channel specified");
1695 return AMI_SUCCESS;
1696 }
1697
1699 if (!c) {
1700 astman_send_error(s, m, "No such channel");
1701 return AMI_SUCCESS;
1702 }
1703
1704 if (!ast_strlen_zero(options)) {
1706 }
1707
1708 snprintf(args, sizeof(args), "%s,%s,%s", file, options, command);
1709
1710 res = mixmonitor_exec(c, args);
1711
1713 uid_channel_var = opts[OPT_ARG_UID];
1715 mixmonitor_id = pbx_builtin_getvar_helper(c, uid_channel_var);
1716 mixmonitor_id = ast_strdupa(S_OR(mixmonitor_id, ""));
1718 }
1719
1720 if (res) {
1722 astman_send_error(s, m, "Could not start monitoring channel");
1723 return AMI_SUCCESS;
1724 }
1725
1726 astman_append(s, "Response: Success\r\n");
1727
1728 if (!ast_strlen_zero(id)) {
1729 astman_append(s, "ActionID: %s\r\n", id);
1730 }
1731
1732 if (!ast_strlen_zero(mixmonitor_id)) {
1733 astman_append(s, "MixMonitorID: %s\r\n", mixmonitor_id);
1734 }
1735
1736 astman_append(s, "\r\n");
1737
1739
1740 return AMI_SUCCESS;
1741}
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:1416
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:1982
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition manager.c:1643
void astman_append(struct mansession *s, const char *fmt,...)
Definition manager.c:1903
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition main/app.c:3066
#define 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 1570 of file app_mixmonitor.c.

1571{
1572 struct ast_channel *c;
1573 const char *name = astman_get_header(m, "Channel");
1574 const char *id = astman_get_header(m, "ActionID");
1575 const char *state = astman_get_header(m, "State");
1576 const char *direction = astman_get_header(m,"Direction");
1577 const char *mixmonitor_id = astman_get_header(m, "MixMonitorID");
1578 int clearmute = 1, mutedcount = 0;
1581 RAII_VAR(struct ast_json *, stasis_message_blob, NULL, ast_json_unref);
1582
1584 astman_send_error(s, m, "No direction specified. Must be read, write or both");
1585 return AMI_SUCCESS;
1586 }
1587
1588 if (!strcasecmp(direction, "read")) {
1590 } else if (!strcasecmp(direction, "write")) {
1592 } else if (!strcasecmp(direction, "both")) {
1594 } else {
1595 astman_send_error(s, m, "Invalid direction specified. Must be read, write or both");
1596 return AMI_SUCCESS;
1597 }
1598
1599 if (ast_strlen_zero(name)) {
1600 astman_send_error(s, m, "No channel specified");
1601 return AMI_SUCCESS;
1602 }
1603
1604 if (ast_strlen_zero(state)) {
1605 astman_send_error(s, m, "No state specified");
1606 return AMI_SUCCESS;
1607 }
1608
1609 clearmute = ast_false(state);
1610
1612 if (!c) {
1613 astman_send_error(s, m, "No such channel");
1614 return AMI_SUCCESS;
1615 }
1616
1617 if (ast_strlen_zero(mixmonitor_id)) {
1618 mutedcount = ast_audiohook_set_mute_all(c, mixmonitor_spy_type, flag, clearmute);
1619 if (mutedcount < 0) {
1621 astman_send_error(s, m, "Cannot set mute flag");
1622 return AMI_SUCCESS;
1623 }
1624 } else {
1625 if (mute_mixmonitor_instance(c, mixmonitor_id, flag, clearmute)) {
1627 astman_send_error(s, m, "Cannot set mute flag");
1628 return AMI_SUCCESS;
1629 }
1630 mutedcount = 1;
1631 }
1632
1633
1634 stasis_message_blob = ast_json_pack("{s: s, s: b, s: s, s: i}",
1635 "direction", direction,
1636 "state", ast_true(state),
1637 "mixmonitorid", mixmonitor_id,
1638 "count", mutedcount);
1639
1641 ast_channel_mixmonitor_mute_type(), stasis_message_blob);
1642
1643 if (stasis_message) {
1645 }
1646
1647 astman_append(s, "Response: Success\r\n");
1648
1649 if (!ast_strlen_zero(id)) {
1650 astman_append(s, "ActionID: %s\r\n", id);
1651 }
1652
1653 astman_append(s, "\r\n");
1654
1656
1657 return AMI_SUCCESS;
1658}
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
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:612
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
Definition stasis.c:1578
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:2235
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:2252
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 1743 of file app_mixmonitor.c.

1744{
1745 struct ast_channel *c;
1746 const char *name = astman_get_header(m, "Channel");
1747 const char *id = astman_get_header(m, "ActionID");
1748 const char *mixmonitor_id = astman_get_header(m, "MixMonitorID");
1749 int res;
1750
1751 if (ast_strlen_zero(name)) {
1752 astman_send_error(s, m, "No channel specified");
1753 return AMI_SUCCESS;
1754 }
1755
1757 if (!c) {
1758 astman_send_error(s, m, "No such channel");
1759 return AMI_SUCCESS;
1760 }
1761
1762 res = stop_mixmonitor_full(c, mixmonitor_id);
1763 if (res) {
1765 astman_send_error(s, m, "Could not stop monitoring channel");
1766 return AMI_SUCCESS;
1767 }
1768
1769 astman_append(s, "Response: Success\r\n");
1770
1771 if (!ast_strlen_zero(id)) {
1772 astman_append(s, "ActionID: %s\r\n", id);
1773 }
1774
1775 astman_append(s, "\r\n");
1776
1778
1779 return AMI_SUCCESS;
1780}
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 750 of file app_mixmonitor.c.

751{
752 int is_bridged;
753
755 is_bridged = ast_channel_is_bridged(autochan->chan);
757 return is_bridged;
758}
#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:10589
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 518 of file app_mixmonitor.c.

519{
520 unsigned char quitting = 0;
521
522 if (mixmonitor_ds->fs) {
523 quitting = 1;
526 ast_verb(2, "MixMonitor close filestream (mixed)\n");
527 }
528
529 if (mixmonitor_ds->fs_read) {
530 quitting = 1;
533 ast_verb(2, "MixMonitor close filestream (read)\n");
534 }
535
536 if (mixmonitor_ds->fs_write) {
537 quitting = 1;
540 ast_verb(2, "MixMonitor close filestream (write)\n");
541 }
542
543 if (quitting) {
545 }
546}
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 1019 of file app_mixmonitor.c.

1020{
1021 struct ast_datastore *datastore;
1022
1023 ast_channel_lock(chan);
1024
1025 datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, datastore_id);
1026
1027 /*
1028 * Currently the one place this function is called from guarantees a
1029 * datastore is present, thus return checks can be avoided here.
1030 */
1031 ast_channel_datastore_remove(chan, datastore);
1032 ast_datastore_free(datastore);
1033
1034 ast_channel_unlock(chan);
1035}
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition channel.c:2384
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 1235 of file app_mixmonitor.c.

1236{
1237 int x, readvol = 0, writevol = 0;
1238 char *filename_read = NULL;
1239 char *filename_write = NULL;
1240 char filename_buffer[1024] = "";
1241 char *uid_channel_var = NULL;
1242 char beep_id[64] = "";
1243
1244 struct ast_flags flags = { 0 };
1245 char *recipients = NULL;
1246 char *parse;
1249 AST_APP_ARG(filename);
1251 AST_APP_ARG(post_process);
1252 );
1253
1254 if (ast_strlen_zero(data)) {
1255 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename or ,t(filename) and/or r(filename)\n");
1256 return -1;
1257 }
1258
1259 parse = ast_strdupa(data);
1260
1262
1263 if (args.options) {
1264 char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
1265
1267
1269 ast_log(LOG_NOTICE, "The synchronization behavior enabled by the 'S' option is now the default"
1270 " and does not need to be specified.\n");
1271 }
1272
1275 ast_log(LOG_WARNING, "No volume level was provided for the heard volume ('v') option.\n");
1276 } else if ((sscanf(opts[OPT_ARG_READVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
1277 ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_READVOLUME]);
1278 } else {
1279 readvol = get_volfactor(x);
1280 }
1281 }
1282
1285 ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n");
1286 } else if ((sscanf(opts[OPT_ARG_WRITEVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
1287 ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_WRITEVOLUME]);
1288 } else {
1289 writevol = get_volfactor(x);
1290 }
1291 }
1292
1294 if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) {
1295 ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n");
1296 } else if ((sscanf(opts[OPT_ARG_VOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
1297 ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]);
1298 } else {
1299 readvol = writevol = get_volfactor(x);
1300 }
1301 }
1302
1305 ast_log(LOG_WARNING, "No voicemail recipients were specified for the vm copy ('m') option.\n");
1306 } else {
1307 recipients = ast_strdupa(opts[OPT_ARG_VMRECIPIENTS]);
1308 }
1309 }
1310
1312 filename_write = ast_strdupa(filename_parse(opts[OPT_ARG_WRITENAME], filename_buffer, sizeof(filename_buffer)));
1313 }
1314
1316 filename_read = ast_strdupa(filename_parse(opts[OPT_ARG_READNAME], filename_buffer, sizeof(filename_buffer)));
1317 }
1318
1320 uid_channel_var = opts[OPT_ARG_UID];
1321 }
1322
1324 const char *interval_str = S_OR(opts[OPT_ARG_BEEP_INTERVAL], "15");
1325 unsigned int interval = 15;
1326
1327 if (sscanf(interval_str, "%30u", &interval) != 1) {
1328 ast_log(LOG_WARNING, "Invalid interval '%s' for periodic beep. Using default of %u\n",
1329 interval_str, interval);
1330 }
1331
1332 if (ast_beep_start(chan, interval, beep_id, sizeof(beep_id))) {
1333 ast_log(LOG_WARNING, "Unable to enable periodic beep, please ensure func_periodic_hook is loaded.\n");
1334 return -1;
1335 }
1336 }
1337 }
1338 /* If there are no file writing arguments/options for the mix monitor, send a warning message and return -1 */
1339
1341 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n");
1342 return -1;
1343 }
1344
1345 /* If filename exists, try to create directories for it */
1346 if (!(ast_strlen_zero(args.filename))) {
1347 args.filename = ast_strdupa(filename_parse(args.filename, filename_buffer, sizeof(filename_buffer)));
1348 }
1349
1350 pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename);
1351
1352 /* If launch_monitor_thread works, the module reference must not be released until it is finished. */
1354 if (launch_monitor_thread(chan,
1355 args.filename,
1356 flags.flags,
1357 readvol,
1358 writevol,
1359 args.post_process,
1360 filename_write,
1361 filename_read,
1362 uid_channel_var,
1363 recipients,
1364 beep_id)) {
1366 }
1367
1370 if (message) {
1372 }
1373
1374 return 0;
1375}
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: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, 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 721 of file app_mixmonitor.c.

722{
723 /* Initialize the file if not already done so */
724 char *last_slash = NULL;
725 if (!ast_strlen_zero(filename)) {
726 if (!*fs && !*errflag && !mixmonitor->mixmonitor_ds->fs_quit) {
727 *oflags = O_CREAT | O_WRONLY;
728 *oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC;
729
730 last_slash = strrchr(filename, '/');
731
732 if ((*ext = strrchr(filename, '.')) && (*ext > last_slash)) {
733 **ext = '\0';
734 *ext = *ext + 1;
735 } else {
736 *ext = "raw";
737 }
738
739 if (!(*fs = ast_writefile(filename, *ext, NULL, *oflags, 0, 0666))) {
740 ast_log(LOG_ERROR, "Cannot open %s.%s\n", filename, *ext);
741 *errflag = 1;
742 } else {
743 struct ast_filestream *tmp = *fs;
745 }
746 }
747 }
748}
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 760 of file app_mixmonitor.c.

761{
762 struct mixmonitor *mixmonitor = obj;
763 char *fs_ext = "";
764 char *fs_read_ext = "";
765 char *fs_write_ext = "";
766
767 struct ast_filestream **fs = NULL;
768 struct ast_filestream **fs_read = NULL;
769 struct ast_filestream **fs_write = NULL;
770
771 unsigned int oflags;
772 int errflag = 0;
773 struct ast_format *format_slin;
774
775 /* Keep callid association before any log messages */
776 if (mixmonitor->callid) {
778 }
779
780 ast_verb(2, "Begin MixMonitor Recording %s\n", mixmonitor->name);
781
783 fs_read = &mixmonitor->mixmonitor_ds->fs_read;
784 fs_write = &mixmonitor->mixmonitor_ds->fs_write;
785
787 mixmonitor_save_prep(mixmonitor, mixmonitor->filename, fs, &oflags, &errflag, &fs_ext);
788 mixmonitor_save_prep(mixmonitor, mixmonitor->filename_read, fs_read, &oflags, &errflag, &fs_read_ext);
789 mixmonitor_save_prep(mixmonitor, mixmonitor->filename_write, fs_write, &oflags, &errflag, &fs_write_ext);
790
792
794
795 /* The audiohook must enter and exit the loop locked */
798 struct ast_frame *fr = NULL;
799 struct ast_frame *fr_read = NULL;
800 struct ast_frame *fr_write = NULL;
801
803 &fr_read, &fr_write))) {
805
807 break;
808 }
809 continue;
810 }
811
812 /* audiohook lock is not required for the next block.
813 * Unlock it, but remember to lock it before looping or exiting */
815
819
820 /* Write out the frame(s) */
821 if ((*fs_read) && (fr_read)) {
822 struct ast_frame *cur;
823
824 for (cur = fr_read; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
825 ast_writestream(*fs_read, cur);
826 }
827 }
828
829 if ((*fs_write) && (fr_write)) {
830 struct ast_frame *cur;
831
832 for (cur = fr_write; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
833 ast_writestream(*fs_write, cur);
834 }
835 }
836
838 /* The 'D' option is set, so mix the frame as an interleaved dual channel frame */
839 int i;
840 short read_buf[SAMPLES_PER_FRAME];
842 short stereo_buf[SAMPLES_PER_FRAME * 2];
843 struct ast_frame stereo_frame = {
845 .datalen = sizeof(stereo_buf),
847 };
848
849 if (fr) {
850 ast_frame_free(fr, 0);
851 fr = NULL;
852 }
853
854 if (fr_read) {
855 memcpy(read_buf, fr_read->data.ptr, sizeof(read_buf));
856 } else {
857 memset(read_buf, 0, sizeof(read_buf));
858 }
859
860 if (fr_write) {
861 memcpy(write_buf, fr_write->data.ptr, sizeof(write_buf));
862 } else {
863 memset(write_buf, 0, sizeof(write_buf));
864 }
865
866 for (i = 0; i < SAMPLES_PER_FRAME; i++) {
867 stereo_buf[i * 2] = read_buf[i];
868 stereo_buf[i * 2 + 1] = write_buf[i];
869 }
870
871 stereo_frame.data.ptr = stereo_buf;
873
874 fr = ast_frdup(&stereo_frame);
875 }
876
877 if ((*fs) && (fr)) {
878 struct ast_frame *cur;
879
880 for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
881 ast_writestream(*fs, cur);
882 }
883 }
885 }
886 /* All done! free it. */
887 if (fr) {
888 ast_frame_free(fr, 0);
889 }
890 if (fr_read) {
891 ast_frame_free(fr_read, 0);
892 }
893 if (fr_write) {
894 ast_frame_free(fr_write, 0);
895 }
896
897 fr = NULL;
898 fr_write = NULL;
899 fr_read = NULL;
900
902 }
903
905
910 }
911
913
914 /* Datastore cleanup. close the filestream and wait for ds destruction */
919 }
921
922 /* kill the audiohook */
924
926 ast_verb(2, "Executing [%s]\n", mixmonitor->post_process);
928 }
929
930 ast_verb(2, "End MixMonitor Recording %s\n", mixmonitor->name);
931 ast_test_suite_event_notify("MIXMONITOR_END", "File: %s\r\n", mixmonitor->filename);
932
934 if (ast_strlen_zero(fs_ext)) {
935 ast_log(LOG_ERROR, "No file extension set for Mixmonitor %s. Skipping copy to voicemail.\n",
936 mixmonitor -> name);
937 } else {
938 ast_verb(3, "Copying recordings for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
940 }
941 if (!ast_strlen_zero(fs_read_ext)) {
942 ast_verb(3, "Copying read recording for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
944 }
945 if (!ast_strlen_zero(fs_write_ext)) {
946 ast_verb(3, "Copying write recording for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
948 }
949 } else {
950 ast_debug(3, "No recipients to forward monitor to, moving on.\n");
951 }
952
954 ast_debug(3, "Deleting our copies of recording files\n");
955 if (!ast_strlen_zero(fs_ext)) {
957 }
958 if (!ast_strlen_zero(fs_read_ext)) {
960 }
961 if (!ast_strlen_zero(fs_write_ext)) {
963 }
964 }
965
967
969 return NULL;
970}
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: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
void ast_frame_free(struct ast_frame *frame, int cache)
Frees a frame or list of frames.
Definition main/frame.c:176
#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
struct ast_format * format
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
enum ast_frame_type frametype
union ast_frame::@239 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_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_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, 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, 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 1526 of file app_mixmonitor.c.

1528{
1529 struct ast_datastore *datastore = NULL;
1530 char *parse = "";
1532
1534 AST_APP_ARG(mixmonid);
1535 );
1536
1537 if (!ast_strlen_zero(data)) {
1538 parse = ast_strdupa(data);
1539 }
1540
1542
1543 ast_channel_lock(chan);
1544
1546 S_OR(args.mixmonid, NULL));
1547 if (!datastore) {
1548 ast_channel_unlock(chan);
1549 return -1;
1550 }
1551 mixmonitor_ds = datastore->data;
1552
1554
1555 if (mixmonitor_ds->audiohook) {
1556 if (clearmute) {
1558 } else {
1560 }
1561 }
1562
1564 ast_channel_unlock(chan);
1565
1566 return 0;
1567}
#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 1829 of file app_mixmonitor.c.

1830{
1834 };
1835
1837}
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 972 of file app_mixmonitor.c.

973{
974 struct ast_datastore *datastore = NULL;
976
977 if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) {
978 return -1;
979 }
980
981 if (ast_asprintf(datastore_id, "%p", mixmonitor_ds) == -1) {
982 ast_log(LOG_ERROR, "Failed to allocate memory for MixMonitor ID.\n");
984 return -1;
985 }
986
989
990 if (!(datastore = ast_datastore_alloc(&mixmonitor_ds_info, *datastore_id))) {
994 return -1;
995 }
996
1001 }
1002
1003 mixmonitor_ds->samp_rate = 8000;
1006 if (!ast_strlen_zero(beep_id)) {
1008 }
1009 datastore->data = mixmonitor_ds;
1010
1011 ast_channel_lock(chan);
1012 ast_channel_datastore_add(chan, datastore);
1013 ast_channel_unlock(chan);
1014
1016 return 0;
1017}
#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:2375
#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 1660 of file app_mixmonitor.c.

1661{
1662 char args[PATH_MAX];
1663
1664 if (ast_strlen_zero(options)) {
1665 snprintf(args, sizeof(args), "%s", filename);
1666 } else {
1667 snprintf(args, sizeof(args), "%s,%s", filename, options);
1668 }
1669
1670 return mixmonitor_exec(chan, args);
1671}

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

581{
582 if (!chan) {
583 return -1;
584 }
585
586 return ast_audiohook_attach(chan, audiohook);
587}
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 1673 of file app_mixmonitor.c.

1674{
1675 return stop_mixmonitor_full(chan, mixmonitor_id);
1676}

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

1452{
1453 stop_mixmonitor_full(chan, data);
1454 return 0;
1455}

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

1378{
1379 struct ast_datastore *datastore = NULL;
1380 char *parse = "";
1382 const char *beep_id = NULL;
1384
1386 AST_APP_ARG(mixmonid);
1387 );
1388
1389 if (!ast_strlen_zero(data)) {
1390 parse = ast_strdupa(data);
1391 }
1392
1394
1395 ast_channel_lock(chan);
1396
1398 S_OR(args.mixmonid, NULL));
1399 if (!datastore) {
1400 ast_channel_unlock(chan);
1401 return -1;
1402 }
1403 mixmonitor_ds = datastore->data;
1404
1406
1407 /* closing the filestream here guarantees the file is available to the dialplan
1408 * after calling StopMixMonitor */
1410
1411 /* The mixmonitor thread may be waiting on the audiohook trigger.
1412 * In order to exit from the mixmonitor loop before waiting on channel
1413 * destruction, poke the audiohook trigger. */
1414 if (mixmonitor_ds->audiohook) {
1417 }
1422 }
1423
1426 }
1427
1429
1430 /* Remove the datastore so the monitor thread can exit */
1431 if (!ast_channel_datastore_remove(chan, datastore)) {
1432 ast_datastore_free(datastore);
1433 }
1434
1435 ast_channel_unlock(chan);
1436
1437 if (!ast_strlen_zero(beep_id)) {
1438 ast_beep_stop(chan, beep_id);
1439 }
1440
1443 NULL);
1444 if (message) {
1446 }
1447
1448 return 0;
1449}
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 1844 of file app_mixmonitor.c.

1845{
1846 int res;
1847
1851 res |= ast_manager_unregister("MixMonitorMute");
1852 res |= ast_manager_unregister("MixMonitor");
1853 res |= ast_manager_unregister("StopMixMonitor");
1855 res |= clear_mixmonitor_methods();
1856
1857 return res;
1858}
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:7698
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, 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 1881 of file app_mixmonitor.c.

◆ app

const char* const app = "MixMonitor"
static

Definition at line 396 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 1881 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 1825 of file app_mixmonitor.c.

1825 {
1826 AST_CLI_DEFINE(handle_cli_mixmonitor, "Execute a MixMonitor command")
1827};
#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 561 of file app_mixmonitor.c.

561 {
562 .type = "mixmonitor",
563 .destroy = mixmonitor_ds_destroy,
564};

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

1820 {
1821 .name = "MIXMONITOR",
1822 .read = func_mixmonitor_read,
1823};

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

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

Referenced by load_module(), and unload_module().