Asterisk - The Open Source Telephony Project GIT-master-9647a4f
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 MIN_SKIP_SECONDS   1
 
#define SAMPLES_PER_FRAME   160
 

Enumerations

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

Functions

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

Variables

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

Detailed Description

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

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

Definition in file app_mixmonitor.c.

Macro Definition Documentation

◆ get_volfactor

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

Definition at line 401 of file app_mixmonitor.c.

◆ MIN_SKIP_SECONDS

#define MIN_SKIP_SECONDS   1

Definition at line 403 of file app_mixmonitor.c.

◆ SAMPLES_PER_FRAME

#define SAMPLES_PER_FRAME   160

Definition at line 668 of file app_mixmonitor.c.

Enumeration Type Documentation

◆ mixmonitor_args

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

Definition at line 473 of file app_mixmonitor.c.

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

◆ mixmonitor_flags

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

Definition at line 451 of file app_mixmonitor.c.

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

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 1940 of file app_mixmonitor.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

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

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

◆ clear_mixmonitor_methods()

static int clear_mixmonitor_methods ( void  )
static

Definition at line 1898 of file app_mixmonitor.c.

1899{
1901}
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 659 of file app_mixmonitor.c.

660{
661 struct vm_recipient *current;
663 /* Clear list element data */
665 }
666}
#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 702 of file app_mixmonitor.c.

703{
704 struct vm_recipient *recipient = NULL;
707 ast_log(LOG_ERROR, "Failed to string_field_init, skipping copy_to_voicemail\n");
708 return;
709 }
710
711 /* Copy strings to stringfields that will be used for all recipients */
718 /* and call_priority gets copied too */
719 recording_data.call_priority = mixmonitor->call_priority;
720
721 AST_LIST_TRAVERSE(&mixmonitor->recipient_list, recipient, list) {
722 /* context, mailbox, and folder need to be set per recipient */
726
727 ast_verb(4, "MixMonitor attempting to send voicemail copy to %s@%s\n", recording_data.mailbox,
728 recording_data.context);
730 }
731
732 /* Free the string fields for recording_data before exiting the function. */
734}
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 581 of file app_mixmonitor.c.

582{
587 }
588 /* kill the audiohook.*/
593}
#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 1236 of file app_mixmonitor.c.

1237{
1238 char *slash;
1239 char *ext;
1240
1241 ast_assert(len > 0);
1242
1243 if (ast_strlen_zero(filename)) {
1244 ast_log(LOG_WARNING, "No file name was provided for a file save option.\n");
1245 buffer[0] = 0;
1246 return buffer;
1247 }
1248
1249 /* If we don't have an absolute path, make one */
1250 if (*filename != '/') {
1251 char *build = ast_alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(filename) + 3);
1252 sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, filename);
1253 filename = build;
1254 }
1255
1256 ast_copy_string(buffer, filename, len);
1257
1258 /* If the provided filename has a .wav49 extension, we need to convert it to .WAV to
1259 match the behavior of build_filename in main/file.c. Otherwise MIXMONITOR_FILENAME
1260 ends up referring to a file that does not/will not exist */
1261 ext = strrchr(buffer, '.');
1262 if (ext && !strcmp(ext, ".wav49")) {
1263 /* Change to WAV - we know we have at least 6 writeable bytes where 'ext' points,
1264 * so this is safe */
1265 memcpy(ext, ".WAV", sizeof(".WAV"));
1266 }
1267
1268 if ((slash = strrchr(filename, '/'))) {
1269 *slash = '\0';
1270 }
1271 ast_mkdir(filename, 0777);
1272
1273 return buffer;
1274}
#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 1841 of file app_mixmonitor.c.

1843{
1844 struct ast_datastore *datastore;
1845 struct mixmonitor_ds *ds_data;
1847 AST_APP_ARG(id);
1848 AST_APP_ARG(key);
1849 );
1850
1852
1853 if (ast_strlen_zero(args.id) || ast_strlen_zero(args.key)) {
1854 ast_log(LOG_WARNING, "Not enough arguments provided to %s. "
1855 "An ID and key must be provided\n", cmd);
1856 return -1;
1857 }
1858
1859 ast_channel_lock(chan);
1860 datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, args.id);
1861 ast_channel_unlock(chan);
1862
1863 if (!datastore) {
1864 ast_log(LOG_WARNING, "Could not find MixMonitor with ID %s\n", args.id);
1865 return -1;
1866 }
1867
1868 ds_data = datastore->data;
1869
1870 if (!strcasecmp(args.key, "filename")) {
1871 ast_copy_string(buf, ds_data->filename, len);
1872 } else {
1873 ast_log(LOG_WARNING, "Unrecognized %s option %s\n", cmd, args.key);
1874 return -1;
1875 }
1876 return 0;
1877}
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 1516 of file app_mixmonitor.c.

1517{
1518 struct ast_channel *chan;
1519 struct ast_datastore *datastore = NULL;
1521
1522 switch (cmd) {
1523 case CLI_INIT:
1524 e->command = "mixmonitor {start|stop|list}";
1525 e->usage =
1526 "Usage: mixmonitor start <chan_name> [args]\n"
1527 " The optional arguments are passed to the MixMonitor application.\n"
1528 " mixmonitor stop <chan_name> [args]\n"
1529 " The optional arguments are passed to the StopMixMonitor application.\n"
1530 " mixmonitor list <chan_name>\n";
1531 return NULL;
1532 case CLI_GENERATE:
1533 return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
1534 }
1535
1536 if (a->argc < 3) {
1537 return CLI_SHOWUSAGE;
1538 }
1539
1540 if (!(chan = ast_channel_get_by_name_prefix(a->argv[2], strlen(a->argv[2])))) {
1541 ast_cli(a->fd, "No channel matching '%s' found.\n", a->argv[2]);
1542 /* Technically this is a failure, but we don't want 2 errors printing out */
1543 return CLI_SUCCESS;
1544 }
1545
1546 if (!strcasecmp(a->argv[1], "start")) {
1547 mixmonitor_exec(chan, (a->argc >= 4) ? a->argv[3] : "");
1548 } else if (!strcasecmp(a->argv[1], "stop")){
1549 stop_mixmonitor_exec(chan, (a->argc >= 4) ? a->argv[3] : "");
1550 } else if (!strcasecmp(a->argv[1], "list")) {
1551 ast_cli(a->fd, "MixMonitor ID\tFile\tReceive File\tTransmit File\n");
1552 ast_cli(a->fd, "=========================================================================\n");
1553 ast_channel_lock(chan);
1554 AST_LIST_TRAVERSE(ast_channel_datastores(chan), datastore, entry) {
1555 if (datastore->info == &mixmonitor_ds_info) {
1556 char *filename = "";
1557 char *filename_read = "";
1558 char *filename_write = "";
1559
1560 mixmonitor_ds = datastore->data;
1561 if (mixmonitor_ds->fs) {
1563 }
1564 if (mixmonitor_ds->fs_read) {
1565 filename_read = mixmonitor_ds->fs_read->filename;
1566 }
1567 if (mixmonitor_ds->fs_write) {
1568 filename_write = mixmonitor_ds->fs_write->filename;
1569 }
1570 ast_cli(a->fd, "%p\t%s\t%s\t%s\n", mixmonitor_ds, filename, filename_read, filename_write);
1571 }
1572 }
1573 ast_channel_unlock(chan);
1574 } else {
1575 chan = ast_channel_unref(chan);
1576 return CLI_SHOWUSAGE;
1577 }
1578
1579 chan = ast_channel_unref(chan);
1580
1581 return CLI_SUCCESS;
1582}
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,
double  skip_seconds 
)
static

Definition at line 1077 of file app_mixmonitor.c.

1082{
1083 pthread_t thread;
1084 struct mixmonitor *mixmonitor;
1085 char postprocess2[1024] = "";
1086 char *datastore_id = NULL;
1087
1088 postprocess2[0] = 0;
1089 /* If a post process system command is given attach it to the structure */
1091 char *p1, *p2;
1092
1094 for (p2 = p1; *p2; p2++) {
1095 if (*p2 == '^' && *(p2+1) == '{') {
1096 *p2 = '$';
1097 }
1098 }
1099 ast_channel_lock(chan);
1100 pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1);
1101 ast_channel_unlock(chan);
1102 }
1103
1104 /* Pre-allocate mixmonitor structure and spy */
1105 if (!(mixmonitor = ast_calloc(1, sizeof(*mixmonitor)))) {
1106 return -1;
1107 }
1108
1109 /* Now that the struct has been calloced, go ahead and initialize the string fields. */
1112 return -1;
1113 }
1114
1115 /* Setup the actual spy before creating our thread */
1118 return -1;
1119 }
1120
1121 /* Copy over flags and channel name */
1124 if (!(mixmonitor->autochan = ast_autochan_setup(chan))) {
1126 return -1;
1127 }
1128
1129 if (!ast_strlen_zero(filename)) {
1131 }
1132
1135 }
1136
1139 }
1140
1141 if (setup_mixmonitor_ds(mixmonitor, chan, &datastore_id, beep_id)) {
1144 ast_free(datastore_id);
1145 return -1;
1146 }
1147
1148 if (!ast_strlen_zero(uid_channel_var)) {
1149 if (datastore_id) {
1150 pbx_builtin_setvar_helper(chan, uid_channel_var, datastore_id);
1151 }
1152 }
1153
1155
1156 if (!ast_strlen_zero(postprocess2)) {
1157 mixmonitor->post_process = ast_strdup(postprocess2);
1158 }
1159
1160 if (!ast_strlen_zero(recipients)) {
1161 char callerid[256];
1162
1163 ast_channel_lock(chan);
1164
1165 /* We use the connected line of the invoking channel for caller ID,
1166 * unless we've been told to use the Caller ID.
1167 * The initial use for this relied on Connected Line to get the
1168 * actual number for recording with Digium phones,
1169 * but in generic use the Caller ID is likely what people want.
1170 */
1171
1173 struct ast_party_caller *caller;
1174 caller = ast_channel_caller(chan);
1175 ast_debug(3, "Caller ID = %d - %s : %d - %s\n", caller->id.name.valid,
1176 caller->id.name.str, caller->id.number.valid,
1177 caller->id.number.str);
1178 ast_callerid_merge(callerid, sizeof(callerid),
1179 S_COR(caller->id.name.valid, caller->id.name.str, NULL),
1180 S_COR(caller->id.number.valid, caller->id.number.str, NULL),
1181 "Unknown");
1182 } else {
1185 ast_debug(3, "Connected Line CID = %d - %s : %d - %s\n", connected->id.name.valid,
1186 connected->id.name.str, connected->id.number.valid,
1187 connected->id.number.str);
1188 ast_callerid_merge(callerid, sizeof(callerid),
1189 S_COR(connected->id.name.valid, connected->id.name.str, NULL),
1190 S_COR(connected->id.number.valid, connected->id.number.str, NULL),
1191 "Unknown");
1192 }
1193
1195 ast_string_field_set(mixmonitor, call_extension, ast_channel_exten(chan));
1196 ast_string_field_set(mixmonitor, call_callerchan, ast_channel_name(chan));
1197 ast_string_field_set(mixmonitor, call_callerid, callerid);
1199
1200 ast_channel_unlock(chan);
1201
1203 }
1204
1208 }
1209
1210 if (readvol)
1212 if (writevol)
1214
1215 if (startmon(chan, &mixmonitor->audiohook)) {
1216 ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n",
1218 mixmonitor_ds_remove_and_free(chan, datastore_id);
1219 ast_free(datastore_id);
1223 return -1;
1224 }
1225
1226 ast_free(datastore_id);
1227
1228 /* reference be released at mixmonitor destruction */
1230
1232}
static void mixmonitor_free(struct mixmonitor *mixmonitor)
static void * mixmonitor_thread(void *obj)
static void mixmonitor_ds_remove_and_free(struct ast_channel *chan, const char *datastore_id)
static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel *chan, char **datastore_id, const char *beep_id)
static int startmon(struct ast_channel *chan, struct ast_audiohook *audiohook)
static const char *const mixmonitor_spy_type
static void add_vm_recipients_from_string(struct mixmonitor *mixmonitor, const char *vm_recipients)
pthread_t thread
Definition app_sla.c:335
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
#define ast_calloc(num, len)
A wrapper for calloc()
Definition astmm.h:202
int ast_audiohook_init(struct ast_audiohook *audiohook, enum ast_audiohook_type type, const char *source, enum ast_audiohook_init_flags flags)
Initialize an audiohook structure.
Definition audiohook.c:100
@ AST_AUDIOHOOK_SUBSTITUTE_SILENCE
Definition audiohook.h:68
@ AST_AUDIOHOOK_TRIGGER_SYNC
Definition audiohook.h:59
@ AST_AUDIOHOOK_TYPE_SPY
Definition audiohook.h:36
struct ast_autochan * ast_autochan_setup(struct ast_channel *chan)
set up a new ast_autochan structure
Definition autochan.c:38
void ast_autochan_destroy(struct ast_autochan *autochan)
destroy an ast_autochan structure
Definition autochan.c:64
char * ast_callerid_merge(char *buf, int bufsiz, const char *name, const char *num, const char *unknown)
Definition callerid.c:1273
static int connected
Definition cdr_pgsql.c:73
const char * ast_channel_name(const struct ast_channel *chan)
int ast_channel_priority(const struct ast_channel *chan)
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
const char * ast_channel_context(const struct ast_channel *chan)
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
const char * ast_channel_exten(const struct ast_channel *chan)
ast_callid ast_read_threadstorage_callid(void)
extracts the callid from the thread
Definition logger.c:2268
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
Definition ael_main.c:211
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition strings.h:87
struct ast_audiohook_options options
Definition audiohook.h:119
Caller Party information.
Definition channel.h:420
struct ast_party_id id
Caller party ID.
Definition channel.h:422
Connected Line/Party information.
Definition channel.h:458
struct ast_party_name name
Subscriber name.
Definition channel.h:342
struct ast_party_number number
Subscriber phone number.
Definition channel.h:344
unsigned char valid
TRUE if the name information is valid/present.
Definition channel.h:281
char * str
Subscriber name (Malloced)
Definition channel.h:266
unsigned char valid
TRUE if the number information is valid/present.
Definition channel.h:299
char * str
Subscriber phone number (Malloced)
Definition channel.h:293
char * filename_write
ast_callid callid
struct ast_autochan * autochan
char * post_process
char * filename_read
double skip_seconds
unsigned int flags
#define ast_test_flag(p, flag)
Definition utils.h:64
#define ast_pthread_create_detached_background(a, b, c, d)
Definition utils.h:637
#define ast_set_flag(p, flag)
Definition utils.h:71

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

Referenced by mixmonitor_exec().

◆ load_module()

static int load_module ( void  )
static

Definition at line 1919 of file app_mixmonitor.c.

1920{
1921 int res;
1922
1930 res |= set_mixmonitor_methods();
1931
1932 return res;
1933}
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 1737 of file app_mixmonitor.c.

1738{
1739 struct ast_channel *c;
1740 const char *name = astman_get_header(m, "Channel");
1741 const char *id = astman_get_header(m, "ActionID");
1742 const char *file = astman_get_header(m, "File");
1743 const char *options = astman_get_header(m, "Options");
1744 const char *command = astman_get_header(m, "Command");
1745 char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
1746 struct ast_flags flags = { 0 };
1747 char *uid_channel_var = NULL;
1748 const char *mixmonitor_id = NULL;
1749 int res;
1750 char args[PATH_MAX];
1751
1752 if (ast_strlen_zero(name)) {
1753 astman_send_error(s, m, "No channel specified");
1754 return AMI_SUCCESS;
1755 }
1756
1758 if (!c) {
1759 astman_send_error(s, m, "No such channel");
1760 return AMI_SUCCESS;
1761 }
1762
1763 if (!ast_strlen_zero(options)) {
1765 }
1766
1767 snprintf(args, sizeof(args), "%s,%s,%s", file, options, command);
1768
1769 res = mixmonitor_exec(c, args);
1770
1772 uid_channel_var = opts[OPT_ARG_UID];
1774 mixmonitor_id = pbx_builtin_getvar_helper(c, uid_channel_var);
1775 mixmonitor_id = ast_strdupa(S_OR(mixmonitor_id, ""));
1777 }
1778
1779 if (res) {
1781 astman_send_error(s, m, "Could not start monitoring channel");
1782 return AMI_SUCCESS;
1783 }
1784
1785 astman_append(s, "Response: Success\r\n");
1786
1787 if (!ast_strlen_zero(id)) {
1788 astman_append(s, "ActionID: %s\r\n", id);
1789 }
1790
1791 if (!ast_strlen_zero(mixmonitor_id)) {
1792 astman_append(s, "MixMonitorID: %s\r\n", mixmonitor_id);
1793 }
1794
1795 astman_append(s, "\r\n");
1796
1798
1799 return AMI_SUCCESS;
1800}
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 1629 of file app_mixmonitor.c.

1630{
1631 struct ast_channel *c;
1632 const char *name = astman_get_header(m, "Channel");
1633 const char *id = astman_get_header(m, "ActionID");
1634 const char *state = astman_get_header(m, "State");
1635 const char *direction = astman_get_header(m,"Direction");
1636 const char *mixmonitor_id = astman_get_header(m, "MixMonitorID");
1637 int clearmute = 1, mutedcount = 0;
1640 RAII_VAR(struct ast_json *, stasis_message_blob, NULL, ast_json_unref);
1641
1643 astman_send_error(s, m, "No direction specified. Must be read, write or both");
1644 return AMI_SUCCESS;
1645 }
1646
1647 if (!strcasecmp(direction, "read")) {
1649 } else if (!strcasecmp(direction, "write")) {
1651 } else if (!strcasecmp(direction, "both")) {
1653 } else {
1654 astman_send_error(s, m, "Invalid direction specified. Must be read, write or both");
1655 return AMI_SUCCESS;
1656 }
1657
1658 if (ast_strlen_zero(name)) {
1659 astman_send_error(s, m, "No channel specified");
1660 return AMI_SUCCESS;
1661 }
1662
1663 if (ast_strlen_zero(state)) {
1664 astman_send_error(s, m, "No state specified");
1665 return AMI_SUCCESS;
1666 }
1667
1668 clearmute = ast_false(state);
1669
1671 if (!c) {
1672 astman_send_error(s, m, "No such channel");
1673 return AMI_SUCCESS;
1674 }
1675
1676 if (ast_strlen_zero(mixmonitor_id)) {
1677 mutedcount = ast_audiohook_set_mute_all(c, mixmonitor_spy_type, flag, clearmute);
1678 if (mutedcount < 0) {
1680 astman_send_error(s, m, "Cannot set mute flag");
1681 return AMI_SUCCESS;
1682 }
1683 } else {
1684 if (mute_mixmonitor_instance(c, mixmonitor_id, flag, clearmute)) {
1686 astman_send_error(s, m, "Cannot set mute flag");
1687 return AMI_SUCCESS;
1688 }
1689 mutedcount = 1;
1690 }
1691
1692
1693 stasis_message_blob = ast_json_pack("{s: s, s: b, s: s, s: i}",
1694 "direction", direction,
1695 "state", ast_true(state),
1696 "mixmonitorid", mixmonitor_id,
1697 "count", mutedcount);
1698
1700 ast_channel_mixmonitor_mute_type(), stasis_message_blob);
1701
1702 if (stasis_message) {
1704 }
1705
1706 astman_append(s, "Response: Success\r\n");
1707
1708 if (!ast_strlen_zero(id)) {
1709 astman_append(s, "ActionID: %s\r\n", id);
1710 }
1711
1712 astman_append(s, "\r\n");
1713
1715
1716 return AMI_SUCCESS;
1717}
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 1802 of file app_mixmonitor.c.

1803{
1804 struct ast_channel *c;
1805 const char *name = astman_get_header(m, "Channel");
1806 const char *id = astman_get_header(m, "ActionID");
1807 const char *mixmonitor_id = astman_get_header(m, "MixMonitorID");
1808 int res;
1809
1810 if (ast_strlen_zero(name)) {
1811 astman_send_error(s, m, "No channel specified");
1812 return AMI_SUCCESS;
1813 }
1814
1816 if (!c) {
1817 astman_send_error(s, m, "No such channel");
1818 return AMI_SUCCESS;
1819 }
1820
1821 res = stop_mixmonitor_full(c, mixmonitor_id);
1822 if (res) {
1824 astman_send_error(s, m, "Could not stop monitoring channel");
1825 return AMI_SUCCESS;
1826 }
1827
1828 astman_append(s, "Response: Success\r\n");
1829
1830 if (!ast_strlen_zero(id)) {
1831 astman_append(s, "ActionID: %s\r\n", id);
1832 }
1833
1834 astman_append(s, "\r\n");
1835
1837
1838 return AMI_SUCCESS;
1839}
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 765 of file app_mixmonitor.c.

766{
767 int is_bridged;
768
770 is_bridged = ast_channel_is_bridged(autochan->chan);
772 return is_bridged;
773}
#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:10593
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 533 of file app_mixmonitor.c.

534{
535 unsigned char quitting = 0;
536
537 if (mixmonitor_ds->fs) {
538 quitting = 1;
541 ast_verb(2, "MixMonitor close filestream (mixed)\n");
542 }
543
544 if (mixmonitor_ds->fs_read) {
545 quitting = 1;
548 ast_verb(2, "MixMonitor close filestream (read)\n");
549 }
550
551 if (mixmonitor_ds->fs_write) {
552 quitting = 1;
555 ast_verb(2, "MixMonitor close filestream (write)\n");
556 }
557
558 if (quitting) {
560 }
561}
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 1059 of file app_mixmonitor.c.

1060{
1061 struct ast_datastore *datastore;
1062
1063 ast_channel_lock(chan);
1064
1065 datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, datastore_id);
1066
1067 /*
1068 * Currently the one place this function is called from guarantees a
1069 * datastore is present, thus return checks can be avoided here.
1070 */
1071 ast_channel_datastore_remove(chan, datastore);
1072 ast_datastore_free(datastore);
1073
1074 ast_channel_unlock(chan);
1075}
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 1276 of file app_mixmonitor.c.

1277{
1278 int x, readvol = 0, writevol = 0;
1279 double skip_seconds = 0.0;
1280 char *filename_read = NULL;
1281 char *filename_write = NULL;
1282 char filename_buffer[1024] = "";
1283 char *uid_channel_var = NULL;
1284 char beep_id[64] = "";
1285
1286 struct ast_flags flags = { 0 };
1287 char *recipients = NULL;
1288 char *parse;
1291 AST_APP_ARG(filename);
1293 AST_APP_ARG(post_process);
1294 );
1295
1296 if (ast_strlen_zero(data)) {
1297 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename or ,t(filename) and/or r(filename)\n");
1298 return -1;
1299 }
1300
1301 parse = ast_strdupa(data);
1302
1304
1305 if (args.options) {
1306 char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
1307
1309
1311 ast_log(LOG_NOTICE, "The synchronization behavior enabled by the 'S' option is now the default"
1312 " and does not need to be specified.\n");
1313 }
1314
1317 ast_log(LOG_WARNING, "No volume level was provided for the heard volume ('v') option.\n");
1318 } else if ((sscanf(opts[OPT_ARG_READVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
1319 ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_READVOLUME]);
1320 } else {
1321 readvol = get_volfactor(x);
1322 }
1323 }
1324
1327 ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n");
1328 } else if ((sscanf(opts[OPT_ARG_WRITEVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
1329 ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_WRITEVOLUME]);
1330 } else {
1331 writevol = get_volfactor(x);
1332 }
1333 }
1334
1336 if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) {
1337 ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n");
1338 } else if ((sscanf(opts[OPT_ARG_VOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
1339 ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]);
1340 } else {
1341 readvol = writevol = get_volfactor(x);
1342 }
1343 }
1344
1347 ast_log(LOG_WARNING, "No voicemail recipients were specified for the vm copy ('m') option.\n");
1348 } else {
1349 recipients = ast_strdupa(opts[OPT_ARG_VMRECIPIENTS]);
1350 }
1351 }
1352
1354 filename_write = ast_strdupa(filename_parse(opts[OPT_ARG_WRITENAME], filename_buffer, sizeof(filename_buffer)));
1355 }
1356
1358 filename_read = ast_strdupa(filename_parse(opts[OPT_ARG_READNAME], filename_buffer, sizeof(filename_buffer)));
1359 }
1360
1362 uid_channel_var = opts[OPT_ARG_UID];
1363 }
1364
1366 const char *interval_str = S_OR(opts[OPT_ARG_BEEP_INTERVAL], "15");
1367 unsigned int interval = 15;
1368
1369 if (sscanf(interval_str, "%30u", &interval) != 1) {
1370 ast_log(LOG_WARNING, "Invalid interval '%s' for periodic beep. Using default of %u\n",
1371 interval_str, interval);
1372 }
1373
1374 if (ast_beep_start(chan, interval, beep_id, sizeof(beep_id))) {
1375 ast_log(LOG_WARNING, "Unable to enable periodic beep, please ensure func_periodic_hook is loaded.\n");
1376 return -1;
1377 }
1378 }
1379
1381 if (ast_strlen_zero(opts[OPT_ARG_SKIP])) {
1382 ast_log(LOG_WARNING, "No skip value provided for the 's' (skip) option; skipping will be ignored as no default exists.\n");
1383 } else {
1384 char *endptr = NULL;
1385 double val = strtod(opts[OPT_ARG_SKIP], &endptr);
1386 if (endptr == opts[OPT_ARG_SKIP] || *endptr != '\0') {
1387 ast_log(LOG_WARNING, "Skip value '%s' is not a valid number; ignoring skip.\n", opts[OPT_ARG_SKIP]);
1388 } else if (val < (double) MIN_SKIP_SECONDS) {
1389 ast_log(LOG_WARNING, "Skip value %.3f is below minimum %d; ignoring skip.\n", val, MIN_SKIP_SECONDS);
1390 } else {
1391 skip_seconds = val;
1392 }
1393 }
1394 }
1395 }
1396 /* If there are no file writing arguments/options for the mix monitor, send a warning message and return -1 */
1397
1399 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n");
1400 return -1;
1401 }
1402
1403 /* If filename exists, try to create directories for it */
1404 if (!(ast_strlen_zero(args.filename))) {
1405 args.filename = ast_strdupa(filename_parse(args.filename, filename_buffer, sizeof(filename_buffer)));
1406 }
1407
1408 pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename);
1409
1410 /* If launch_monitor_thread works, the module reference must not be released until it is finished. */
1412 if (launch_monitor_thread(chan,
1413 args.filename,
1414 flags.flags,
1415 readvol,
1416 writevol,
1417 args.post_process,
1418 filename_write,
1419 filename_read,
1420 uid_channel_var,
1421 recipients,
1422 beep_id,
1423 skip_seconds)) {
1425 }
1426
1429 if (message) {
1431 }
1432
1433 return 0;
1434}
static char * filename_parse(char *filename, char *buffer, size_t len)
#define get_volfactor(x)
#define MIN_SKIP_SECONDS
static int launch_monitor_thread(struct ast_channel *chan, const char *filename, unsigned int flags, int readvol, int writevol, const char *post_process, const char *filename_write, char *filename_read, const char *uid_channel_var, const char *recipients, const char *beep_id, double skip_seconds)
int AST_OPTIONAL_API_NAME() ast_beep_start(struct ast_channel *chan, unsigned int interval, char *beep_id, size_t len)
struct stasis_message_type * ast_channel_mixmonitor_start_type(void)
Message type for starting mixmonitor on a channel.
#define LOG_NOTICE
#define ast_module_unref(mod)
Release a reference to the module.
Definition module.h:483
#define ast_module_ref(mod)
Hold a reference to the module.
Definition module.h:457
struct ast_module * self
Definition module.h:356

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

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

◆ mixmonitor_free()

static void mixmonitor_free ( struct mixmonitor mixmonitor)
static

◆ mixmonitor_save_prep()

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

Definition at line 736 of file app_mixmonitor.c.

737{
738 /* Initialize the file if not already done so */
739 char *last_slash = NULL;
740 if (!ast_strlen_zero(filename)) {
741 if (!*fs && !*errflag && !mixmonitor->mixmonitor_ds->fs_quit) {
742 *oflags = O_CREAT | O_WRONLY;
743 *oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC;
744
745 last_slash = strrchr(filename, '/');
746
747 if ((*ext = strrchr(filename, '.')) && (*ext > last_slash)) {
748 **ext = '\0';
749 *ext = *ext + 1;
750 } else {
751 *ext = "raw";
752 }
753
754 if (!(*fs = ast_writefile(filename, *ext, NULL, *oflags, 0, 0666))) {
755 ast_log(LOG_ERROR, "Cannot open %s.%s\n", filename, *ext);
756 *errflag = 1;
757 } else {
758 struct ast_filestream *tmp = *fs;
760 }
761 }
762 }
763}
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 775 of file app_mixmonitor.c.

776{
777 struct mixmonitor *mixmonitor = obj;
778 char *fs_ext = "";
779 char *fs_read_ext = "";
780 char *fs_write_ext = "";
781
782 struct ast_filestream **fs = NULL;
783 struct ast_filestream **fs_read = NULL;
784 struct ast_filestream **fs_write = NULL;
785
786 unsigned int oflags;
787 int errflag = 0;
788 struct ast_format *format_slin;
789
790 struct timeval skip_start = ast_tvnow();
791
792 /* Keep callid association before any log messages */
793 if (mixmonitor->callid) {
795 }
796
797 ast_verb(2, "Begin MixMonitor Recording %s\n", mixmonitor->name);
798
800 fs_read = &mixmonitor->mixmonitor_ds->fs_read;
801 fs_write = &mixmonitor->mixmonitor_ds->fs_write;
802
804 mixmonitor_save_prep(mixmonitor, mixmonitor->filename, fs, &oflags, &errflag, &fs_ext);
805 mixmonitor_save_prep(mixmonitor, mixmonitor->filename_read, fs_read, &oflags, &errflag, &fs_read_ext);
806 mixmonitor_save_prep(mixmonitor, mixmonitor->filename_write, fs_write, &oflags, &errflag, &fs_write_ext);
807
809
811
812 if (mixmonitor->skip_seconds > 0.0) {
813 ast_debug(3, "%s skipping initial %.3f seconds\n",
815 }
816
817 /* The audiohook must enter and exit the loop locked */
820 struct ast_frame *fr = NULL;
821 struct ast_frame *fr_read = NULL;
822 struct ast_frame *fr_write = NULL;
823
825 &fr_read, &fr_write))) {
827
829 break;
830 }
831 continue;
832 }
833
834 /* audiohook lock is not required for the next block.
835 * Unlock it, but remember to lock it before looping or exiting */
837
841
842 /* Skip writing audio for the first N seconds */
843 if (mixmonitor->skip_seconds > 0.0) {
844 struct timeval now = ast_tvnow();
845 double elapsed = ast_tvdiff_ms(now, skip_start) / 1000.0;
846
847 if (elapsed < mixmonitor->skip_seconds) {
849 /* Skip this frame and continue */
850 goto frame_cleanup;
851 } else {
852 ast_debug(3, "%s skip period %.3f seconds elapsed; starting to write audio\n",
855 }
856 }
857
858 /* Write out the frame(s) */
859 if ((*fs_read) && (fr_read)) {
860 struct ast_frame *cur;
861
862 for (cur = fr_read; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
863 ast_writestream(*fs_read, cur);
864 }
865 }
866
867 if ((*fs_write) && (fr_write)) {
868 struct ast_frame *cur;
869
870 for (cur = fr_write; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
871 ast_writestream(*fs_write, cur);
872 }
873 }
874
876 /* The 'D' option is set, so mix the frame as an interleaved dual channel frame */
877 int i;
878 short read_buf[SAMPLES_PER_FRAME];
880 short stereo_buf[SAMPLES_PER_FRAME * 2];
881 struct ast_frame stereo_frame = {
883 .datalen = sizeof(stereo_buf),
885 };
886
887 if (fr) {
888 ast_frame_free(fr, 0);
889 fr = NULL;
890 }
891
892 if (fr_read) {
893 memcpy(read_buf, fr_read->data.ptr, sizeof(read_buf));
894 } else {
895 memset(read_buf, 0, sizeof(read_buf));
896 }
897
898 if (fr_write) {
899 memcpy(write_buf, fr_write->data.ptr, sizeof(write_buf));
900 } else {
901 memset(write_buf, 0, sizeof(write_buf));
902 }
903
904 for (i = 0; i < SAMPLES_PER_FRAME; i++) {
905 stereo_buf[i * 2] = read_buf[i];
906 stereo_buf[i * 2 + 1] = write_buf[i];
907 }
908
909 stereo_frame.data.ptr = stereo_buf;
911
912 fr = ast_frdup(&stereo_frame);
913 }
914
915 if ((*fs) && (fr)) {
916 struct ast_frame *cur;
917
918 for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
919 ast_writestream(*fs, cur);
920 }
921 }
923 }
924
925frame_cleanup:
926 /* All done! free it. */
927 if (fr) {
928 ast_frame_free(fr, 0);
929 }
930 if (fr_read) {
931 ast_frame_free(fr_read, 0);
932 }
933 if (fr_write) {
934 ast_frame_free(fr_write, 0);
935 }
936
937 fr = NULL;
938 fr_write = NULL;
939 fr_read = NULL;
940
942 }
943
945
950 }
951
953
954 /* Datastore cleanup. close the filestream and wait for ds destruction */
959 }
961
962 /* kill the audiohook */
964
966 ast_verb(2, "Executing [%s]\n", mixmonitor->post_process);
968 }
969
970 ast_verb(2, "End MixMonitor Recording %s\n", mixmonitor->name);
971 ast_test_suite_event_notify("MIXMONITOR_END", "File: %s\r\n", mixmonitor->filename);
972
974 if (ast_strlen_zero(fs_ext)) {
975 ast_log(LOG_ERROR, "No file extension set for Mixmonitor %s. Skipping copy to voicemail.\n",
976 mixmonitor -> name);
977 } else {
978 ast_verb(3, "Copying recordings for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
980 }
981 if (!ast_strlen_zero(fs_read_ext)) {
982 ast_verb(3, "Copying read recording for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
984 }
985 if (!ast_strlen_zero(fs_write_ext)) {
986 ast_verb(3, "Copying write recording for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
988 }
989 } else {
990 ast_debug(3, "No recipients to forward monitor to, moving on.\n");
991 }
992
994 ast_debug(3, "Deleting our copies of recording files\n");
995 if (!ast_strlen_zero(fs_ext)) {
997 }
998 if (!ast_strlen_zero(fs_read_ext)) {
1000 }
1001 if (!ast_strlen_zero(fs_write_ext)) {
1003 }
1004 }
1005
1007
1009 return NULL;
1010}
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
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition time.h:159

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

Referenced by launch_monitor_thread().

◆ mute_mixmonitor_instance()

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

Mute / unmute an individual MixMonitor by id.

Definition at line 1585 of file app_mixmonitor.c.

1587{
1588 struct ast_datastore *datastore = NULL;
1589 char *parse = "";
1591
1593 AST_APP_ARG(mixmonid);
1594 );
1595
1596 if (!ast_strlen_zero(data)) {
1597 parse = ast_strdupa(data);
1598 }
1599
1601
1602 ast_channel_lock(chan);
1603
1605 S_OR(args.mixmonid, NULL));
1606 if (!datastore) {
1607 ast_channel_unlock(chan);
1608 return -1;
1609 }
1610 mixmonitor_ds = datastore->data;
1611
1613
1614 if (mixmonitor_ds->audiohook) {
1615 if (clearmute) {
1617 } else {
1619 }
1620 }
1621
1623 ast_channel_unlock(chan);
1624
1625 return 0;
1626}
#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 1888 of file app_mixmonitor.c.

1889{
1893 };
1894
1896}
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 1012 of file app_mixmonitor.c.

1013{
1014 struct ast_datastore *datastore = NULL;
1016
1017 if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) {
1018 return -1;
1019 }
1020
1021 if (ast_asprintf(datastore_id, "%p", mixmonitor_ds) == -1) {
1022 ast_log(LOG_ERROR, "Failed to allocate memory for MixMonitor ID.\n");
1024 return -1;
1025 }
1026
1029
1030 if (!(datastore = ast_datastore_alloc(&mixmonitor_ds_info, *datastore_id))) {
1034 return -1;
1035 }
1036
1041 }
1042
1043 mixmonitor_ds->samp_rate = 8000;
1046 if (!ast_strlen_zero(beep_id)) {
1048 }
1049 datastore->data = mixmonitor_ds;
1050
1051 ast_channel_lock(chan);
1052 ast_channel_datastore_add(chan, datastore);
1053 ast_channel_unlock(chan);
1054
1056 return 0;
1057}
#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 1719 of file app_mixmonitor.c.

1720{
1721 char args[PATH_MAX];
1722
1723 if (ast_strlen_zero(options)) {
1724 snprintf(args, sizeof(args), "%s", filename);
1725 } else {
1726 snprintf(args, sizeof(args), "%s,%s", filename, options);
1727 }
1728
1729 return mixmonitor_exec(chan, args);
1730}

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

596{
597 if (!chan) {
598 return -1;
599 }
600
601 return ast_audiohook_attach(chan, audiohook);
602}
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 1732 of file app_mixmonitor.c.

1733{
1734 return stop_mixmonitor_full(chan, mixmonitor_id);
1735}

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

1511{
1512 stop_mixmonitor_full(chan, data);
1513 return 0;
1514}

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

1437{
1438 struct ast_datastore *datastore = NULL;
1439 char *parse = "";
1441 const char *beep_id = NULL;
1443
1445 AST_APP_ARG(mixmonid);
1446 );
1447
1448 if (!ast_strlen_zero(data)) {
1449 parse = ast_strdupa(data);
1450 }
1451
1453
1454 ast_channel_lock(chan);
1455
1457 S_OR(args.mixmonid, NULL));
1458 if (!datastore) {
1459 ast_channel_unlock(chan);
1460 return -1;
1461 }
1462 mixmonitor_ds = datastore->data;
1463
1465
1466 /* closing the filestream here guarantees the file is available to the dialplan
1467 * after calling StopMixMonitor */
1469
1470 /* The mixmonitor thread may be waiting on the audiohook trigger.
1471 * In order to exit from the mixmonitor loop before waiting on channel
1472 * destruction, poke the audiohook trigger. */
1473 if (mixmonitor_ds->audiohook) {
1476 }
1481 }
1482
1485 }
1486
1488
1489 /* Remove the datastore so the monitor thread can exit */
1490 if (!ast_channel_datastore_remove(chan, datastore)) {
1491 ast_datastore_free(datastore);
1492 }
1493
1494 ast_channel_unlock(chan);
1495
1496 if (!ast_strlen_zero(beep_id)) {
1497 ast_beep_stop(chan, beep_id);
1498 }
1499
1502 NULL);
1503 if (message) {
1505 }
1506
1507 return 0;
1508}
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 1903 of file app_mixmonitor.c.

1904{
1905 int res;
1906
1910 res |= ast_manager_unregister("MixMonitorMute");
1911 res |= ast_manager_unregister("MixMonitor");
1912 res |= ast_manager_unregister("StopMixMonitor");
1914 res |= clear_mixmonitor_methods();
1915
1916 return res;
1917}
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 1940 of file app_mixmonitor.c.

◆ app

const char* const app = "MixMonitor"
static

Definition at line 405 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 1940 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 1884 of file app_mixmonitor.c.

1884 {
1885 AST_CLI_DEFINE(handle_cli_mixmonitor, "Execute a MixMonitor command")
1886};
#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 576 of file app_mixmonitor.c.

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

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

1879 {
1880 .name = "MIXMONITOR",
1881 .read = func_mixmonitor_read,
1882};

Referenced by load_module(), and unload_module().

◆ mixmonitor_opts

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

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

Referenced by load_module(), and unload_module().