Asterisk - The Open Source Telephony Project GIT-master-4f2b068
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 1938 of file app_mixmonitor.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

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

◆ clear_mixmonitor_methods()

static int clear_mixmonitor_methods ( void  )
static

Definition at line 1896 of file app_mixmonitor.c.

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

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

1841{
1842 struct ast_datastore *datastore;
1843 struct mixmonitor_ds *ds_data;
1845 AST_APP_ARG(id);
1846 AST_APP_ARG(key);
1847 );
1848
1850
1851 if (ast_strlen_zero(args.id) || ast_strlen_zero(args.key)) {
1852 ast_log(LOG_WARNING, "Not enough arguments provided to %s. "
1853 "An ID and key must be provided\n", cmd);
1854 return -1;
1855 }
1856
1857 ast_channel_lock(chan);
1858 datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, args.id);
1859 ast_channel_unlock(chan);
1860
1861 if (!datastore) {
1862 ast_log(LOG_WARNING, "Could not find MixMonitor with ID %s\n", args.id);
1863 return -1;
1864 }
1865
1866 ds_data = datastore->data;
1867
1868 if (!strcasecmp(args.key, "filename")) {
1869 ast_copy_string(buf, ds_data->filename, len);
1870 } else {
1871 ast_log(LOG_WARNING, "Unrecognized %s option %s\n", cmd, args.key);
1872 return -1;
1873 }
1874 return 0;
1875}
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 @522 args
Structure for a data store object.
Definition datastore.h:64
void * data
Definition datastore.h:66

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

◆ handle_cli_mixmonitor()

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

Definition at line 1514 of file app_mixmonitor.c.

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

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

◆ launch_monitor_thread()

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

Definition at line 1075 of file app_mixmonitor.c.

1080{
1081 pthread_t thread;
1082 struct mixmonitor *mixmonitor;
1083 char postprocess2[1024] = "";
1084 char *datastore_id = NULL;
1085
1086 postprocess2[0] = 0;
1087 /* If a post process system command is given attach it to the structure */
1089 char *p1, *p2;
1090
1092 for (p2 = p1; *p2; p2++) {
1093 if (*p2 == '^' && *(p2+1) == '{') {
1094 *p2 = '$';
1095 }
1096 }
1097 ast_channel_lock(chan);
1098 pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1);
1099 ast_channel_unlock(chan);
1100 }
1101
1102 /* Pre-allocate mixmonitor structure and spy */
1103 if (!(mixmonitor = ast_calloc(1, sizeof(*mixmonitor)))) {
1104 return -1;
1105 }
1106
1107 /* Now that the struct has been calloced, go ahead and initialize the string fields. */
1110 return -1;
1111 }
1112
1113 /* Setup the actual spy before creating our thread */
1116 return -1;
1117 }
1118
1119 /* Copy over flags and channel name */
1122 if (!(mixmonitor->autochan = ast_autochan_setup(chan))) {
1124 return -1;
1125 }
1126
1127 if (!ast_strlen_zero(filename)) {
1129 }
1130
1133 }
1134
1137 }
1138
1139 if (setup_mixmonitor_ds(mixmonitor, chan, &datastore_id, beep_id)) {
1142 ast_free(datastore_id);
1143 return -1;
1144 }
1145
1146 if (!ast_strlen_zero(uid_channel_var)) {
1147 if (datastore_id) {
1148 pbx_builtin_setvar_helper(chan, uid_channel_var, datastore_id);
1149 }
1150 }
1151
1153
1154 if (!ast_strlen_zero(postprocess2)) {
1155 mixmonitor->post_process = ast_strdup(postprocess2);
1156 }
1157
1158 if (!ast_strlen_zero(recipients)) {
1159 char callerid[256];
1160
1161 ast_channel_lock(chan);
1162
1163 /* We use the connected line of the invoking channel for caller ID,
1164 * unless we've been told to use the Caller ID.
1165 * The initial use for this relied on Connected Line to get the
1166 * actual number for recording with Digium phones,
1167 * but in generic use the Caller ID is likely what people want.
1168 */
1169
1171 struct ast_party_caller *caller;
1172 caller = ast_channel_caller(chan);
1173 ast_debug(3, "Caller ID = %d - %s : %d - %s\n", caller->id.name.valid,
1174 caller->id.name.str, caller->id.number.valid,
1175 caller->id.number.str);
1176 ast_callerid_merge(callerid, sizeof(callerid),
1177 S_COR(caller->id.name.valid, caller->id.name.str, NULL),
1178 S_COR(caller->id.number.valid, caller->id.number.str, NULL),
1179 "Unknown");
1180 } else {
1183 ast_debug(3, "Connected Line CID = %d - %s : %d - %s\n", connected->id.name.valid,
1184 connected->id.name.str, connected->id.number.valid,
1185 connected->id.number.str);
1186 ast_callerid_merge(callerid, sizeof(callerid),
1187 S_COR(connected->id.name.valid, connected->id.name.str, NULL),
1188 S_COR(connected->id.number.valid, connected->id.number.str, NULL),
1189 "Unknown");
1190 }
1191
1193 ast_string_field_set(mixmonitor, call_extension, ast_channel_exten(chan));
1194 ast_string_field_set(mixmonitor, call_callerchan, ast_channel_name(chan));
1195 ast_string_field_set(mixmonitor, call_callerid, callerid);
1197
1198 ast_channel_unlock(chan);
1199
1201 }
1202
1206 }
1207
1208 if (readvol)
1210 if (writevol)
1212
1213 if (startmon(chan, &mixmonitor->audiohook)) {
1214 ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n",
1216 mixmonitor_ds_remove_and_free(chan, datastore_id);
1217 ast_free(datastore_id);
1221 return -1;
1222 }
1223
1224 ast_free(datastore_id);
1225
1226 /* reference be released at mixmonitor destruction */
1228
1230}
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 1917 of file app_mixmonitor.c.

1918{
1919 int res;
1920
1928 res |= set_mixmonitor_methods();
1929
1930 return res;
1931}
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 1735 of file app_mixmonitor.c.

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

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

1801{
1802 struct ast_channel *c;
1803 const char *name = astman_get_header(m, "Channel");
1804 const char *id = astman_get_header(m, "ActionID");
1805 const char *mixmonitor_id = astman_get_header(m, "MixMonitorID");
1806 int res;
1807
1808 if (ast_strlen_zero(name)) {
1809 astman_send_error(s, m, "No channel specified");
1810 return AMI_SUCCESS;
1811 }
1812
1814 if (!c) {
1815 astman_send_error(s, m, "No such channel");
1816 return AMI_SUCCESS;
1817 }
1818
1819 res = stop_mixmonitor_full(c, mixmonitor_id);
1820 if (res) {
1822 astman_send_error(s, m, "Could not stop monitoring channel");
1823 return AMI_SUCCESS;
1824 }
1825
1826 astman_append(s, "Response: Success\r\n");
1827
1828 if (!ast_strlen_zero(id)) {
1829 astman_append(s, "ActionID: %s\r\n", id);
1830 }
1831
1832 astman_append(s, "\r\n");
1833
1835
1836 return AMI_SUCCESS;
1837}
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 if (datastore) {
1068 ast_channel_datastore_remove(chan, datastore);
1069 ast_datastore_free(datastore);
1070 }
1071
1072 ast_channel_unlock(chan);
1073}
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 1274 of file app_mixmonitor.c.

1275{
1276 int x, readvol = 0, writevol = 0;
1277 double skip_seconds = 0.0;
1278 char *filename_read = NULL;
1279 char *filename_write = NULL;
1280 char filename_buffer[1024] = "";
1281 char *uid_channel_var = NULL;
1282 char beep_id[64] = "";
1283
1284 struct ast_flags flags = { 0 };
1285 char *recipients = NULL;
1286 char *parse;
1289 AST_APP_ARG(filename);
1291 AST_APP_ARG(post_process);
1292 );
1293
1294 if (ast_strlen_zero(data)) {
1295 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename or ,t(filename) and/or r(filename)\n");
1296 return -1;
1297 }
1298
1299 parse = ast_strdupa(data);
1300
1302
1303 if (args.options) {
1304 char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
1305
1307
1309 ast_log(LOG_NOTICE, "The synchronization behavior enabled by the 'S' option is now the default"
1310 " and does not need to be specified.\n");
1311 }
1312
1315 ast_log(LOG_WARNING, "No volume level was provided for the heard volume ('v') option.\n");
1316 } else if ((sscanf(opts[OPT_ARG_READVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
1317 ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_READVOLUME]);
1318 } else {
1319 readvol = get_volfactor(x);
1320 }
1321 }
1322
1325 ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n");
1326 } else if ((sscanf(opts[OPT_ARG_WRITEVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
1327 ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_WRITEVOLUME]);
1328 } else {
1329 writevol = get_volfactor(x);
1330 }
1331 }
1332
1334 if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) {
1335 ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n");
1336 } else if ((sscanf(opts[OPT_ARG_VOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
1337 ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]);
1338 } else {
1339 readvol = writevol = get_volfactor(x);
1340 }
1341 }
1342
1345 ast_log(LOG_WARNING, "No voicemail recipients were specified for the vm copy ('m') option.\n");
1346 } else {
1347 recipients = ast_strdupa(opts[OPT_ARG_VMRECIPIENTS]);
1348 }
1349 }
1350
1352 filename_write = ast_strdupa(filename_parse(opts[OPT_ARG_WRITENAME], filename_buffer, sizeof(filename_buffer)));
1353 }
1354
1356 filename_read = ast_strdupa(filename_parse(opts[OPT_ARG_READNAME], filename_buffer, sizeof(filename_buffer)));
1357 }
1358
1360 uid_channel_var = opts[OPT_ARG_UID];
1361 }
1362
1364 const char *interval_str = S_OR(opts[OPT_ARG_BEEP_INTERVAL], "15");
1365 unsigned int interval = 15;
1366
1367 if (sscanf(interval_str, "%30u", &interval) != 1) {
1368 ast_log(LOG_WARNING, "Invalid interval '%s' for periodic beep. Using default of %u\n",
1369 interval_str, interval);
1370 }
1371
1372 if (ast_beep_start(chan, interval, beep_id, sizeof(beep_id))) {
1373 ast_log(LOG_WARNING, "Unable to enable periodic beep, please ensure func_periodic_hook is loaded.\n");
1374 return -1;
1375 }
1376 }
1377
1379 if (ast_strlen_zero(opts[OPT_ARG_SKIP])) {
1380 ast_log(LOG_WARNING, "No skip value provided for the 's' (skip) option; skipping will be ignored as no default exists.\n");
1381 } else {
1382 char *endptr = NULL;
1383 double val = strtod(opts[OPT_ARG_SKIP], &endptr);
1384 if (endptr == opts[OPT_ARG_SKIP] || *endptr != '\0') {
1385 ast_log(LOG_WARNING, "Skip value '%s' is not a valid number; ignoring skip.\n", opts[OPT_ARG_SKIP]);
1386 } else if (val < (double) MIN_SKIP_SECONDS) {
1387 ast_log(LOG_WARNING, "Skip value %.3f is below minimum %d; ignoring skip.\n", val, MIN_SKIP_SECONDS);
1388 } else {
1389 skip_seconds = val;
1390 }
1391 }
1392 }
1393 }
1394 /* If there are no file writing arguments/options for the mix monitor, send a warning message and return -1 */
1395
1397 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n");
1398 return -1;
1399 }
1400
1401 /* If filename exists, try to create directories for it */
1402 if (!(ast_strlen_zero(args.filename))) {
1403 args.filename = ast_strdupa(filename_parse(args.filename, filename_buffer, sizeof(filename_buffer)));
1404 }
1405
1406 pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename);
1407
1408 /* If launch_monitor_thread works, the module reference must not be released until it is finished. */
1410 if (launch_monitor_thread(chan,
1411 args.filename,
1412 flags.flags,
1413 readvol,
1414 writevol,
1415 args.post_process,
1416 filename_write,
1417 filename_read,
1418 uid_channel_var,
1419 recipients,
1420 beep_id,
1421 skip_seconds)) {
1423 }
1424
1427 if (message) {
1429 }
1430
1431 return 0;
1432}
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 1583 of file app_mixmonitor.c.

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

1887{
1891 };
1892
1894}
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 1717 of file app_mixmonitor.c.

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

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

1731{
1732 return stop_mixmonitor_full(chan, mixmonitor_id);
1733}

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

1509{
1510 stop_mixmonitor_full(chan, data);
1511 return 0;
1512}

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

1435{
1436 struct ast_datastore *datastore = NULL;
1437 char *parse = "";
1439 const char *beep_id = NULL;
1441
1443 AST_APP_ARG(mixmonid);
1444 );
1445
1446 if (!ast_strlen_zero(data)) {
1447 parse = ast_strdupa(data);
1448 }
1449
1451
1452 ast_channel_lock(chan);
1453
1455 S_OR(args.mixmonid, NULL));
1456 if (!datastore) {
1457 ast_channel_unlock(chan);
1458 return -1;
1459 }
1460 mixmonitor_ds = datastore->data;
1461
1463
1464 /* closing the filestream here guarantees the file is available to the dialplan
1465 * after calling StopMixMonitor */
1467
1468 /* The mixmonitor thread may be waiting on the audiohook trigger.
1469 * In order to exit from the mixmonitor loop before waiting on channel
1470 * destruction, poke the audiohook trigger. */
1471 if (mixmonitor_ds->audiohook) {
1474 }
1479 }
1480
1483 }
1484
1486
1487 /* Remove the datastore so the monitor thread can exit */
1488 if (!ast_channel_datastore_remove(chan, datastore)) {
1489 ast_datastore_free(datastore);
1490 }
1491
1492 ast_channel_unlock(chan);
1493
1494 if (!ast_strlen_zero(beep_id)) {
1495 ast_beep_stop(chan, beep_id);
1496 }
1497
1500 NULL);
1501 if (message) {
1503 }
1504
1505 return 0;
1506}
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 1901 of file app_mixmonitor.c.

1902{
1903 int res;
1904
1908 res |= ast_manager_unregister("MixMonitorMute");
1909 res |= ast_manager_unregister("MixMonitor");
1910 res |= ast_manager_unregister("StopMixMonitor");
1912 res |= clear_mixmonitor_methods();
1913
1914 return res;
1915}
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 1938 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 1938 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 1882 of file app_mixmonitor.c.

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

1877 {
1878 .name = "MIXMONITOR",
1879 .read = func_mixmonitor_read,
1880};

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