Asterisk - The Open Source Telephony Project  GIT-master-a24979a
Data Structures | Macros | Enumerations | Functions | Variables
app_mixmonitor.c File Reference

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

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

Go to the source code of this file.

Data Structures

struct  mixmonitor
 
struct  mixmonitor_ds
 
struct  vm_recipient
 

Macros

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

Enumerations

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

Functions

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

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Mixed Audio Monitoring Application" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .optional_modules = "func_periodic_hook", }
 
static const char *const app = "MixMonitor"
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static struct ast_cli_entry cli_mixmonitor []
 
static const struct ast_datastore_info mixmonitor_ds_info
 
static struct ast_custom_function mixmonitor_function
 
static const struct ast_app_option mixmonitor_opts [128] = { [ 'a' ] = { .flag = MUXFLAG_APPEND }, [ 'b' ] = { .flag = MUXFLAG_BRIDGED }, [ 'B' ] = { .flag = MUXFLAG_BEEP , .arg_index = OPT_ARG_BEEP_INTERVAL + 1 }, [ 'p' ] = { .flag = MUXFLAG_BEEP_START }, [ 'P' ] = { .flag = MUXFLAG_BEEP_STOP }, [ 'v' ] = { .flag = MUXFLAG_READVOLUME , .arg_index = OPT_ARG_READVOLUME + 1 }, [ 'V' ] = { .flag = MUXFLAG_WRITEVOLUME , .arg_index = OPT_ARG_WRITEVOLUME + 1 }, [ 'W' ] = { .flag = MUXFLAG_VOLUME , .arg_index = OPT_ARG_VOLUME + 1 }, [ 'r' ] = { .flag = MUXFLAG_READ , .arg_index = OPT_ARG_READNAME + 1 }, [ 't' ] = { .flag = MUXFLAG_WRITE , .arg_index = OPT_ARG_WRITENAME + 1 }, [ 'i' ] = { .flag = MUXFLAG_UID , .arg_index = OPT_ARG_UID + 1 }, [ 'm' ] = { .flag = MUXFLAG_VMRECIPIENTS , .arg_index = OPT_ARG_VMRECIPIENTS + 1 }, [ 'S' ] = { .flag = MUXFLAG_DEPRECATED_RWSYNC , .arg_index = OPT_ARG_DEPRECATED_RWSYNC + 1 }, [ 'n' ] = { .flag = MUXFLAG_NO_RWSYNC , .arg_index = OPT_ARG_NO_RWSYNC + 1 }, }
 
static const char *const mixmonitor_spy_type = "MixMonitor"
 
static const char *const stop_app = "StopMixMonitor"
 

Detailed Description

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

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

Definition in file app_mixmonitor.c.

Macro Definition Documentation

◆ get_volfactor

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

Definition at line 348 of file app_mixmonitor.c.

◆ SAMPLES_PER_FRAME

#define SAMPLES_PER_FRAME   160

Definition at line 602 of file app_mixmonitor.c.

Enumeration Type Documentation

◆ mixmonitor_args

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

Definition at line 412 of file app_mixmonitor.c.

412  {
413  OPT_ARG_READVOLUME = 0,
418  OPT_ARG_UID,
423  OPT_ARG_ARRAY_SIZE, /* Always last element of the enum */
424 };
@ 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 

Definition at line 394 of file app_mixmonitor.c.

394  {
395  MUXFLAG_APPEND = (1 << 1),
396  MUXFLAG_BRIDGED = (1 << 2),
397  MUXFLAG_VOLUME = (1 << 3),
398  MUXFLAG_READVOLUME = (1 << 4),
399  MUXFLAG_WRITEVOLUME = (1 << 5),
400  MUXFLAG_READ = (1 << 6),
401  MUXFLAG_WRITE = (1 << 7),
402  MUXFLAG_COMBINED = (1 << 8),
403  MUXFLAG_UID = (1 << 9),
404  MUXFLAG_VMRECIPIENTS = (1 << 10),
405  MUXFLAG_BEEP = (1 << 11),
406  MUXFLAG_BEEP_START = (1 << 12),
407  MUXFLAG_BEEP_STOP = (1 << 13),
408  MUXFLAG_DEPRECATED_RWSYNC = (1 << 14),
409  MUXFLAG_NO_RWSYNC = (1 << 15),
410 };
@ MUXFLAG_VMRECIPIENTS
@ MUXFLAG_READ
@ MUXFLAG_DEPRECATED_RWSYNC
@ MUXFLAG_WRITEVOLUME
@ MUXFLAG_NO_RWSYNC
@ MUXFLAG_VOLUME
@ MUXFLAG_BEEP_STOP
@ MUXFLAG_UID
@ MUXFLAG_APPEND
@ MUXFLAG_BEEP_START
@ MUXFLAG_WRITE
@ MUXFLAG_COMBINED
@ MUXFLAG_BEEP
@ MUXFLAG_BRIDGED
@ MUXFLAG_READVOLUME

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 1704 of file app_mixmonitor.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

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

545 {
546  /* recipients are in a single string with a format format resembling "mailbox@context/INBOX,mailbox2@context2,mailbox3@context3/Work" */
547  char *cur_mailbox = ast_strdupa(vm_recipients);
548  char *cur_context;
549  char *cur_folder;
550  char *next;
551  int elements_processed = 0;
552 
553  while (!ast_strlen_zero(cur_mailbox)) {
554  ast_debug(3, "attempting to add next element %d from %s\n", elements_processed, cur_mailbox);
555  if ((next = strchr(cur_mailbox, ',')) || (next = strchr(cur_mailbox, '&'))) {
556  *(next++) = '\0';
557  }
558 
559  if ((cur_folder = strchr(cur_mailbox, '/'))) {
560  *(cur_folder++) = '\0';
561  } else {
562  cur_folder = "INBOX";
563  }
564 
565  if ((cur_context = strchr(cur_mailbox, '@'))) {
566  *(cur_context++) = '\0';
567  } else {
568  cur_context = "default";
569  }
570 
571  if (!ast_strlen_zero(cur_mailbox) && !ast_strlen_zero(cur_context)) {
572  struct vm_recipient *recipient;
573  if (!(recipient = ast_malloc(sizeof(*recipient)))) {
574  ast_log(LOG_ERROR, "Failed to allocate recipient. Aborting function.\n");
575  return;
576  }
577  ast_copy_string(recipient->context, cur_context, sizeof(recipient->context));
578  ast_copy_string(recipient->mailbox, cur_mailbox, sizeof(recipient->mailbox));
579  ast_copy_string(recipient->folder, cur_folder, sizeof(recipient->folder));
580 
581  /* Add to list */
582  ast_verb(4, "Adding %s@%s to recipient list\n", recipient->mailbox, recipient->context);
584  } else {
585  ast_log(LOG_ERROR, "Failed to properly parse extension and/or context from element %d of recipient string: %s\n", elements_processed, vm_recipients);
586  }
587 
588  cur_mailbox = next;
589  elements_processed++;
590  }
591 }
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
#define ast_log
Definition: astobj2.c:42
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define ast_verb(level,...)
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:406
struct mixmonitor::@55 recipient_list
char mailbox[AST_MAX_CONTEXT]
char context[AST_MAX_EXTENSION]
struct vm_recipient * next
struct vm_recipient::@54 list
char folder[80]

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

◆ clear_mixmonitor_methods()

static int clear_mixmonitor_methods ( void  )
static

Definition at line 1662 of file app_mixmonitor.c.

1663 {
1665 }
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 593 of file app_mixmonitor.c.

594 {
595  struct vm_recipient *current;
597  /* Clear list element data */
598  ast_free(current);
599  }
600 }
#define ast_free(a)
Definition: astmm.h:180
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
size_t current
Definition: main/cli.c:113

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

Referenced by mixmonitor_free().

◆ copy_to_voicemail()

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

Definition at line 636 of file app_mixmonitor.c.

637 {
638  struct vm_recipient *recipient = NULL;
639  struct ast_vm_recording_data recording_data;
640  if (ast_string_field_init(&recording_data, 512)) {
641  ast_log(LOG_ERROR, "Failed to string_field_init, skipping copy_to_voicemail\n");
642  return;
643  }
644 
645  /* Copy strings to stringfields that will be used for all recipients */
646  ast_string_field_set(&recording_data, recording_file, filename);
647  ast_string_field_set(&recording_data, recording_ext, ext);
653  /* and call_priority gets copied too */
654  recording_data.call_priority = mixmonitor->call_priority;
655 
656  AST_LIST_TRAVERSE(&mixmonitor->recipient_list, recipient, list) {
657  /* context, mailbox, and folder need to be set per recipient */
658  ast_string_field_set(&recording_data, context, recipient->context);
659  ast_string_field_set(&recording_data, mailbox, recipient->mailbox);
660  ast_string_field_set(&recording_data, folder, recipient->folder);
661 
662  ast_verb(4, "MixMonitor attempting to send voicemail copy to %s@%s\n", recording_data.mailbox,
663  recording_data.context);
664  ast_app_copy_recording_to_vm(&recording_data);
665  }
666 
667  /* Free the string fields for recording_data before exiting the function. */
668  ast_string_field_free_memory(&recording_data);
669 }
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:120
static char mailbox[AST_MAX_MAILBOX_UNIQUEID]
Definition: chan_mgcp.c:207
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:666
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define NULL
Definition: resample.c:96
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
Structure used for ast_copy_recording_to_vm in order to cleanly supply data needed for making the rec...
const ast_string_field call_macrocontext
const ast_string_field recording_file
const ast_string_field call_callerchan
const ast_string_field folder
const ast_string_field call_callerid
const ast_string_field call_context
const ast_string_field recording_ext
const ast_string_field call_extension
const ast_string_field call_macrocontext
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_macrocontext, ast_vm_recording_data::call_macrocontext, mixmonitor::call_priority, ast_vm_recording_data::call_priority, context, vm_recipient::context, ast_vm_recording_data::context, ext, vm_recipient::folder, ast_vm_recording_data::folder, LOG_ERROR, vm_recipient::mailbox, 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 515 of file app_mixmonitor.c.

516 {
517  if (mixmonitor->mixmonitor_ds) {
521  }
522  /* kill the audiohook.*/
527 }
#define ast_audiohook_lock(ah)
Lock an audiohook.
Definition: audiohook.h:304
int ast_audiohook_detach(struct ast_audiohook *audiohook)
Detach audiohook from channel.
Definition: audiohook.c:528
int ast_audiohook_destroy(struct ast_audiohook *audiohook)
Destroys an audiohook structure.
Definition: audiohook.c:121
#define ast_audiohook_unlock(ah)
Unlock an audiohook.
Definition: audiohook.h:309
#define ast_mutex_unlock(a)
Definition: lock.h:188
#define ast_mutex_lock(a)
Definition: lock.h:187
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 1076 of file app_mixmonitor.c.

1077 {
1078  char *slash;
1079  char *ext;
1080 
1081  ast_assert(len > 0);
1082 
1083  if (ast_strlen_zero(filename)) {
1084  ast_log(LOG_WARNING, "No file name was provided for a file save option.\n");
1085  buffer[0] = 0;
1086  return buffer;
1087  }
1088 
1089  /* If we don't have an absolute path, make one */
1090  if (*filename != '/') {
1091  char *build = ast_alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(filename) + 3);
1092  sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, filename);
1093  filename = build;
1094  }
1095 
1096  ast_copy_string(buffer, filename, len);
1097 
1098  /* If the provided filename has a .wav49 extension, we need to convert it to .WAV to
1099  match the behavior of build_filename in main/file.c. Otherwise MIXMONITOR_FILENAME
1100  ends up referring to a file that does not/will not exist */
1101  ext = strrchr(buffer, '.');
1102  if (ext && !strcmp(ext, ".wav49")) {
1103  /* Change to WAV - we know we have at least 6 writeable bytes where 'ext' points,
1104  * so this is safe */
1105  memcpy(ext, ".WAV", sizeof(".WAV"));
1106  }
1107 
1108  if ((slash = strrchr(filename, '/'))) {
1109  *slash = '\0';
1110  }
1111  ast_mkdir(filename, 0777);
1112 
1113  return buffer;
1114 }
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define LOG_WARNING
const char * ast_config_AST_MONITOR_DIR
Definition: options.c:155
#define ast_assert(a)
Definition: utils.h:734
int ast_mkdir(const char *path, int mode)
Recursively create directory path.
Definition: main/utils.c:2377

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

1607 {
1608  struct ast_datastore *datastore;
1609  struct mixmonitor_ds *ds_data;
1611  AST_APP_ARG(id);
1612  AST_APP_ARG(key);
1613  );
1614 
1615  AST_STANDARD_APP_ARGS(args, data);
1616 
1617  if (ast_strlen_zero(args.id) || ast_strlen_zero(args.key)) {
1618  ast_log(LOG_WARNING, "Not enough arguments provided to %s. "
1619  "An ID and key must be provided\n", cmd);
1620  return -1;
1621  }
1622 
1623  ast_channel_lock(chan);
1624  datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, args.id);
1625  ast_channel_unlock(chan);
1626 
1627  if (!datastore) {
1628  ast_log(LOG_WARNING, "Could not find MixMonitor with ID %s\n", args.id);
1629  return -1;
1630  }
1631 
1632  ds_data = datastore->data;
1633 
1634  if (!strcasecmp(args.key, "filename")) {
1635  ast_copy_string(buf, ds_data->filename, len);
1636  } else {
1637  ast_log(LOG_WARNING, "Unrecognized %s option %s\n", cmd, args.key);
1638  return -1;
1639  }
1640  return 0;
1641 }
static const struct ast_datastore_info mixmonitor_ds_info
#define ast_channel_lock(chan)
Definition: channel.h:2922
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:2398
#define ast_channel_unlock(chan)
Definition: channel.h:2923
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
Structure for a data store object.
Definition: datastore.h:64
void * data
Definition: datastore.h:66
const char * args

◆ handle_cli_mixmonitor()

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

Definition at line 1338 of file app_mixmonitor.c.

1339 {
1340  struct ast_channel *chan;
1341  struct ast_datastore *datastore = NULL;
1342  struct mixmonitor_ds *mixmonitor_ds = NULL;
1343 
1344  switch (cmd) {
1345  case CLI_INIT:
1346  e->command = "mixmonitor {start|stop|list}";
1347  e->usage =
1348  "Usage: mixmonitor start <chan_name> [args]\n"
1349  " The optional arguments are passed to the MixMonitor application.\n"
1350  " mixmonitor stop <chan_name> [args]\n"
1351  " The optional arguments are passed to the StopMixMonitor application.\n"
1352  " mixmonitor list <chan_name>\n";
1353  return NULL;
1354  case CLI_GENERATE:
1355  return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
1356  }
1357 
1358  if (a->argc < 3) {
1359  return CLI_SHOWUSAGE;
1360  }
1361 
1362  if (!(chan = ast_channel_get_by_name_prefix(a->argv[2], strlen(a->argv[2])))) {
1363  ast_cli(a->fd, "No channel matching '%s' found.\n", a->argv[2]);
1364  /* Technically this is a failure, but we don't want 2 errors printing out */
1365  return CLI_SUCCESS;
1366  }
1367 
1368  if (!strcasecmp(a->argv[1], "start")) {
1369  mixmonitor_exec(chan, (a->argc >= 4) ? a->argv[3] : "");
1370  } else if (!strcasecmp(a->argv[1], "stop")){
1371  stop_mixmonitor_exec(chan, (a->argc >= 4) ? a->argv[3] : "");
1372  } else if (!strcasecmp(a->argv[1], "list")) {
1373  ast_cli(a->fd, "MixMonitor ID\tFile\tReceive File\tTransmit File\n");
1374  ast_cli(a->fd, "=========================================================================\n");
1375  ast_channel_lock(chan);
1376  AST_LIST_TRAVERSE(ast_channel_datastores(chan), datastore, entry) {
1377  if (datastore->info == &mixmonitor_ds_info) {
1378  char *filename = "";
1379  char *filename_read = "";
1380  char *filename_write = "";
1381 
1382  mixmonitor_ds = datastore->data;
1383  if (mixmonitor_ds->fs) {
1385  }
1386  if (mixmonitor_ds->fs_read) {
1387  filename_read = mixmonitor_ds->fs_read->filename;
1388  }
1389  if (mixmonitor_ds->fs_write) {
1390  filename_write = mixmonitor_ds->fs_write->filename;
1391  }
1392  ast_cli(a->fd, "%p\t%s\t%s\t%s\n", mixmonitor_ds, filename, filename_read, filename_write);
1393  }
1394  }
1395  ast_channel_unlock(chan);
1396  } else {
1397  chan = ast_channel_unref(chan);
1398  return CLI_SHOWUSAGE;
1399  }
1400 
1401  chan = ast_channel_unref(chan);
1402 
1403  return CLI_SUCCESS;
1404 }
static int mixmonitor_exec(struct ast_channel *chan, const char *data)
static int stop_mixmonitor_exec(struct ast_channel *chan, const char *data)
struct ast_channel * ast_channel_get_by_name_prefix(const char *name, size_t name_len)
Find a channel by a name prefix.
Definition: channel.c:1428
struct ast_datastore_list * ast_channel_datastores(struct ast_channel *chan)
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2958
#define CLI_SHOWUSAGE
Definition: cli.h:45
char * ast_complete_channels(const char *line, const char *word, int pos, int state, int rpos)
Command completion for the list of active channels.
Definition: main/cli.c:1862
#define CLI_SUCCESS
Definition: cli.h:44
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
Main Channel structure associated with a channel.
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
const struct ast_datastore_info * info
Definition: datastore.h:67
char * filename
Definition: mod_format.h:107
Definition: search.h:40
struct ast_filestream * fs_read
struct ast_filestream * fs_write
struct ast_filestream * fs
static struct test_val a

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

◆ launch_monitor_thread()

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

Definition at line 934 of file app_mixmonitor.c.

939 {
940  pthread_t thread;
941  struct mixmonitor *mixmonitor;
942  char postprocess2[1024] = "";
943  char *datastore_id = NULL;
944 
945  postprocess2[0] = 0;
946  /* If a post process system command is given attach it to the structure */
948  char *p1, *p2;
949 
951  for (p2 = p1; *p2; p2++) {
952  if (*p2 == '^' && *(p2+1) == '{') {
953  *p2 = '$';
954  }
955  }
956  ast_channel_lock(chan);
957  pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1);
958  ast_channel_unlock(chan);
959  }
960 
961  /* Pre-allocate mixmonitor structure and spy */
962  if (!(mixmonitor = ast_calloc(1, sizeof(*mixmonitor)))) {
963  return -1;
964  }
965 
966  /* Now that the struct has been calloced, go ahead and initialize the string fields. */
967  if (ast_string_field_init(mixmonitor, 512)) {
969  return -1;
970  }
971 
972  /* Setup the actual spy before creating our thread */
975  return -1;
976  }
977 
978  /* Copy over flags and channel name */
980  if (!(mixmonitor->autochan = ast_autochan_setup(chan))) {
982  return -1;
983  }
984 
985  if (!ast_strlen_zero(filename)) {
987  }
988 
991  }
992 
995  }
996 
997  if (setup_mixmonitor_ds(mixmonitor, chan, &datastore_id, beep_id)) {
1000  ast_free(datastore_id);
1001  return -1;
1002  }
1003 
1004  if (!ast_strlen_zero(uid_channel_var)) {
1005  if (datastore_id) {
1006  pbx_builtin_setvar_helper(chan, uid_channel_var, datastore_id);
1007  }
1008  }
1009 
1011 
1012  if (!ast_strlen_zero(postprocess2)) {
1013  mixmonitor->post_process = ast_strdup(postprocess2);
1014  }
1015 
1016  if (!ast_strlen_zero(recipients)) {
1017  char callerid[256];
1019 
1020  ast_channel_lock(chan);
1021 
1022  /* We use the connected line of the invoking channel for caller ID. */
1023 
1025  ast_debug(3, "Connected Line CID = %d - %s : %d - %s\n", connected->id.name.valid,
1026  connected->id.name.str, connected->id.number.valid,
1027  connected->id.number.str);
1028  ast_callerid_merge(callerid, sizeof(callerid),
1029  S_COR(connected->id.name.valid, connected->id.name.str, NULL),
1030  S_COR(connected->id.number.valid, connected->id.number.str, NULL),
1031  "Unknown");
1032 
1033  ast_string_field_set(mixmonitor, call_context, ast_channel_context(chan));
1034  ast_string_field_set(mixmonitor, call_macrocontext, ast_channel_macrocontext(chan));
1035  ast_string_field_set(mixmonitor, call_extension, ast_channel_exten(chan));
1036  ast_string_field_set(mixmonitor, call_callerchan, ast_channel_name(chan));
1037  ast_string_field_set(mixmonitor, call_callerid, callerid);
1039 
1040  ast_channel_unlock(chan);
1041 
1043  }
1044 
1048  }
1049 
1050  if (readvol)
1052  if (writevol)
1054 
1055  if (startmon(chan, &mixmonitor->audiohook)) {
1056  ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n",
1058  mixmonitor_ds_remove_and_free(chan, datastore_id);
1059  ast_free(datastore_id);
1063  return -1;
1064  }
1065 
1066  ast_free(datastore_id);
1067 
1068  /* reference be released at mixmonitor destruction */
1070 
1072 }
pthread_t thread
Definition: app_meetme.c:1091
static void * mixmonitor_thread(void *obj)
static void mixmonitor_free(struct mixmonitor *mixmonitor)
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)
#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
void ast_autochan_destroy(struct ast_autochan *autochan)
destroy an ast_autochan structure
Definition: autochan.c:64
struct ast_autochan * ast_autochan_setup(struct ast_channel *chan)
set up a new ast_autochan structure
Definition: autochan.c:38
char * ast_callerid_merge(char *buf, int bufsiz, const char *name, const char *num, const char *unknown)
Definition: callerid.c:1073
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
const char * ast_channel_context(const struct ast_channel *chan)
int ast_channel_priority(const struct ast_channel *chan)
const char * ast_channel_name(const struct ast_channel *chan)
const char * ast_channel_exten(const struct ast_channel *chan)
const char * ast_channel_macrocontext(const struct ast_channel *chan)
char connected
Definition: eagi_proxy.c:82
ast_callid ast_read_threadstorage_callid(void)
extracts the callerid from the thread
Definition: logger.c:2048
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
Definition: ael_main.c:211
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:87
struct ast_audiohook_options options
Definition: audiohook.h:119
Connected Line/Party information.
Definition: channel.h:456
char * filename_write
ast_callid callid
struct ast_autochan * autochan
char * post_process
char * filename_read
unsigned int flags
char * filename
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define ast_pthread_create_detached_background(a, b, c, d)
Definition: utils.h:592
#define ast_set_flag(p, flag)
Definition: utils.h:70

References add_vm_recipients_from_string(), ast_audiohook_destroy(), ast_audiohook_init(), AST_AUDIOHOOK_SUBSTITUTE_SILENCE, AST_AUDIOHOOK_TRIGGER_SYNC, AST_AUDIOHOOK_TYPE_SPY, ast_autochan_destroy(), ast_autochan_setup(), ast_callerid_merge(), ast_calloc, ast_channel_connected(), ast_channel_context(), ast_channel_exten(), ast_channel_lock, ast_channel_macrocontext(), 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, LOG_WARNING, mixmonitor_ds_remove_and_free(), mixmonitor_free(), mixmonitor_spy_type, mixmonitor_thread(), MUXFLAG_NO_RWSYNC, mixmonitor::name, NULL, ast_audiohook::options, pbx_builtin_setvar_helper(), pbx_substitute_variables_helper(), mixmonitor::post_process, ast_audiohook_options::read_volume, S_COR, setup_mixmonitor_ds(), startmon(), thread, and ast_audiohook_options::write_volume.

Referenced by mixmonitor_exec().

◆ load_module()

static int load_module ( void  )
static

Definition at line 1683 of file app_mixmonitor.c.

1684 {
1685  int res;
1686 
1694  res |= set_mixmonitor_methods();
1695 
1696  return res;
1697 }
static int manager_stop_mixmonitor(struct mansession *s, const struct message *m)
static struct ast_cli_entry cli_mixmonitor[]
static struct ast_custom_function mixmonitor_function
static int set_mixmonitor_methods(void)
static const char *const app
static int manager_mute_mixmonitor(struct mansession *s, const struct message *m)
Mute / unmute a MixMonitor channel.
static const char *const stop_app
static int manager_mixmonitor(struct mansession *s, const struct message *m)
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
#define EVENT_FLAG_SYSTEM
Definition: manager.h:75
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:191
#define EVENT_FLAG_CALL
Definition: manager.h:76
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1543
#define ARRAY_LEN(a)
Definition: utils.h:661

◆ manager_mixmonitor()

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

Definition at line 1501 of file app_mixmonitor.c.

1502 {
1503  struct ast_channel *c;
1504  const char *name = astman_get_header(m, "Channel");
1505  const char *id = astman_get_header(m, "ActionID");
1506  const char *file = astman_get_header(m, "File");
1507  const char *options = astman_get_header(m, "Options");
1508  const char *command = astman_get_header(m, "Command");
1509  char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
1510  struct ast_flags flags = { 0 };
1511  char *uid_channel_var = NULL;
1512  const char *mixmonitor_id = NULL;
1513  int res;
1514  char args[PATH_MAX];
1515 
1516  if (ast_strlen_zero(name)) {
1517  astman_send_error(s, m, "No channel specified");
1518  return AMI_SUCCESS;
1519  }
1520 
1522  if (!c) {
1523  astman_send_error(s, m, "No such channel");
1524  return AMI_SUCCESS;
1525  }
1526 
1527  if (!ast_strlen_zero(options)) {
1529  }
1530 
1531  snprintf(args, sizeof(args), "%s,%s,%s", file, options, command);
1532 
1533  res = mixmonitor_exec(c, args);
1534 
1535  if (ast_test_flag(&flags, MUXFLAG_UID)) {
1536  uid_channel_var = opts[OPT_ARG_UID];
1538  mixmonitor_id = pbx_builtin_getvar_helper(c, uid_channel_var);
1539  mixmonitor_id = ast_strdupa(S_OR(mixmonitor_id, ""));
1541  }
1542 
1543  if (res) {
1545  astman_send_error(s, m, "Could not start monitoring channel");
1546  return AMI_SUCCESS;
1547  }
1548 
1549  astman_append(s, "Response: Success\r\n");
1550 
1551  if (!ast_strlen_zero(id)) {
1552  astman_append(s, "ActionID: %s\r\n", id);
1553  }
1554 
1555  if (!ast_strlen_zero(mixmonitor_id)) {
1556  astman_append(s, "MixMonitorID: %s\r\n", mixmonitor_id);
1557  }
1558 
1559  astman_append(s, "\r\n");
1560 
1562 
1563  return AMI_SUCCESS;
1564 }
static const struct ast_app_option mixmonitor_opts[128]
#define PATH_MAX
Definition: asterisk.h:40
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1448
static const char name[]
Definition: format_mp3.c:68
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3166
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3087
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:2827
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:3126
#define AMI_SUCCESS
Definition: manager.h:66
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80
Structure used to handle boolean flags.
Definition: utils.h:199
unsigned int flags
Definition: utils.h:200
static struct test_options options
static struct test_val c

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

◆ manager_mute_mixmonitor()

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

Mute / unmute a MixMonitor channel.

Definition at line 1407 of file app_mixmonitor.c.

1408 {
1409  struct ast_channel *c;
1410  const char *name = astman_get_header(m, "Channel");
1411  const char *id = astman_get_header(m, "ActionID");
1412  const char *state = astman_get_header(m, "State");
1413  const char *direction = astman_get_header(m,"Direction");
1414  int clearmute = 1;
1417  RAII_VAR(struct ast_json *, stasis_message_blob, NULL, ast_json_unref);
1418 
1419  if (ast_strlen_zero(direction)) {
1420  astman_send_error(s, m, "No direction specified. Must be read, write or both");
1421  return AMI_SUCCESS;
1422  }
1423 
1424  if (!strcasecmp(direction, "read")) {
1426  } else if (!strcasecmp(direction, "write")) {
1428  } else if (!strcasecmp(direction, "both")) {
1430  } else {
1431  astman_send_error(s, m, "Invalid direction specified. Must be read, write or both");
1432  return AMI_SUCCESS;
1433  }
1434 
1435  if (ast_strlen_zero(name)) {
1436  astman_send_error(s, m, "No channel specified");
1437  return AMI_SUCCESS;
1438  }
1439 
1440  if (ast_strlen_zero(state)) {
1441  astman_send_error(s, m, "No state specified");
1442  return AMI_SUCCESS;
1443  }
1444 
1445  clearmute = ast_false(state);
1446 
1448  if (!c) {
1449  astman_send_error(s, m, "No such channel");
1450  return AMI_SUCCESS;
1451  }
1452 
1453  if (ast_audiohook_set_mute(c, mixmonitor_spy_type, flag, clearmute)) {
1455  astman_send_error(s, m, "Cannot set mute flag");
1456  return AMI_SUCCESS;
1457  }
1458 
1459  stasis_message_blob = ast_json_pack("{s: s, s: b}",
1460  "direction", direction,
1461  "state", ast_true(state));
1462 
1464  ast_channel_mixmonitor_mute_type(), stasis_message_blob);
1465 
1466  if (stasis_message) {
1468  }
1469 
1470  astman_append(s, "Response: Success\r\n");
1471 
1472  if (!ast_strlen_zero(id)) {
1473  astman_append(s, "ActionID: %s\r\n", id);
1474  }
1475 
1476  astman_append(s, "\r\n");
1477 
1479 
1480  return AMI_SUCCESS;
1481 }
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
int ast_audiohook_set_mute(struct ast_channel *chan, const char *source, enum ast_audiohook_flags flag, int clear)
Mute frames read from or written to a channel.
Definition: audiohook.c:1331
ast_audiohook_flags
Definition: audiohook.h:54
@ AST_AUDIOHOOK_MUTE_READ
Definition: audiohook.h:64
@ AST_AUDIOHOOK_MUTE_WRITE
Definition: audiohook.h:65
const char * ast_channel_uniqueid(const struct ast_channel *chan)
struct stasis_topic * ast_channel_topic(struct ast_channel *chan)
A topic which publishes the events for a particular channel.
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:591
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
Definition: stasis.c:1513
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: main/utils.c:2097
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"....
Definition: main/utils.c:2114
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:936

References AMI_SUCCESS, ao2_cleanup, AST_AUDIOHOOK_MUTE_READ, AST_AUDIOHOOK_MUTE_WRITE, ast_audiohook_set_mute(), 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, name, NULL, RAII_VAR, and stasis_publish().

◆ manager_stop_mixmonitor()

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

Definition at line 1566 of file app_mixmonitor.c.

1567 {
1568  struct ast_channel *c;
1569  const char *name = astman_get_header(m, "Channel");
1570  const char *id = astman_get_header(m, "ActionID");
1571  const char *mixmonitor_id = astman_get_header(m, "MixMonitorID");
1572  int res;
1573 
1574  if (ast_strlen_zero(name)) {
1575  astman_send_error(s, m, "No channel specified");
1576  return AMI_SUCCESS;
1577  }
1578 
1580  if (!c) {
1581  astman_send_error(s, m, "No such channel");
1582  return AMI_SUCCESS;
1583  }
1584 
1585  res = stop_mixmonitor_full(c, mixmonitor_id);
1586  if (res) {
1588  astman_send_error(s, m, "Could not stop monitoring channel");
1589  return AMI_SUCCESS;
1590  }
1591 
1592  astman_append(s, "Response: Success\r\n");
1593 
1594  if (!ast_strlen_zero(id)) {
1595  astman_append(s, "ActionID: %s\r\n", id);
1596  }
1597 
1598  astman_append(s, "\r\n");
1599 
1601 
1602  return AMI_SUCCESS;
1603 }
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().

◆ mixmonitor_autochan_is_bridged()

static int mixmonitor_autochan_is_bridged ( struct ast_autochan autochan)
static

Definition at line 700 of file app_mixmonitor.c.

701 {
702  int is_bridged;
703 
704  ast_autochan_channel_lock(autochan);
705  is_bridged = ast_channel_is_bridged(autochan->chan);
706  ast_autochan_channel_unlock(autochan);
707  return is_bridged;
708 }
#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:10731
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 467 of file app_mixmonitor.c.

468 {
469  unsigned char quitting = 0;
470 
471  if (mixmonitor_ds->fs) {
472  quitting = 1;
474  mixmonitor_ds->fs = NULL;
475  ast_verb(2, "MixMonitor close filestream (mixed)\n");
476  }
477 
478  if (mixmonitor_ds->fs_read) {
479  quitting = 1;
482  ast_verb(2, "MixMonitor close filestream (read)\n");
483  }
484 
485  if (mixmonitor_ds->fs_write) {
486  quitting = 1;
489  ast_verb(2, "MixMonitor close filestream (write)\n");
490  }
491 
492  if (quitting) {
493  mixmonitor_ds->fs_quit = 1;
494  }
495 }
int ast_closestream(struct ast_filestream *f)
Closes a stream.
Definition: file.c:1109

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

917 {
918  struct ast_datastore *datastore;
919 
920  ast_channel_lock(chan);
921 
922  datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, datastore_id);
923 
924  /*
925  * Currently the one place this function is called from guarantees a
926  * datastore is present, thus return checks can be avoided here.
927  */
928  ast_channel_datastore_remove(chan, datastore);
929  ast_datastore_free(datastore);
930 
931  ast_channel_unlock(chan);
932 }
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2393
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 1116 of file app_mixmonitor.c.

1117 {
1118  int x, readvol = 0, writevol = 0;
1119  char *filename_read = NULL;
1120  char *filename_write = NULL;
1121  char filename_buffer[1024] = "";
1122  char *uid_channel_var = NULL;
1123  char beep_id[64] = "";
1124 
1125  struct ast_flags flags = { 0 };
1126  char *recipients = NULL;
1127  char *parse;
1130  AST_APP_ARG(filename);
1132  AST_APP_ARG(post_process);
1133  );
1134 
1135  if (ast_strlen_zero(data)) {
1136  ast_log(LOG_WARNING, "MixMonitor requires an argument (filename or ,t(filename) and/or r(filename)\n");
1137  return -1;
1138  }
1139 
1140  parse = ast_strdupa(data);
1141 
1143 
1144  if (args.options) {
1145  char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
1146 
1147  ast_app_parse_options(mixmonitor_opts, &flags, opts, args.options);
1148 
1150  ast_log(LOG_NOTICE, "The synchronization behavior enabled by the 'S' option is now the default"
1151  " and does not need to be specified.\n");
1152  }
1153 
1155  if (ast_strlen_zero(opts[OPT_ARG_READVOLUME])) {
1156  ast_log(LOG_WARNING, "No volume level was provided for the heard volume ('v') option.\n");
1157  } else if ((sscanf(opts[OPT_ARG_READVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
1158  ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_READVOLUME]);
1159  } else {
1160  readvol = get_volfactor(x);
1161  }
1162  }
1163 
1165  if (ast_strlen_zero(opts[OPT_ARG_WRITEVOLUME])) {
1166  ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n");
1167  } else if ((sscanf(opts[OPT_ARG_WRITEVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
1168  ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_WRITEVOLUME]);
1169  } else {
1170  writevol = get_volfactor(x);
1171  }
1172  }
1173 
1175  if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) {
1176  ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n");
1177  } else if ((sscanf(opts[OPT_ARG_VOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
1178  ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]);
1179  } else {
1180  readvol = writevol = get_volfactor(x);
1181  }
1182  }
1183 
1186  ast_log(LOG_WARNING, "No voicemail recipients were specified for the vm copy ('m') option.\n");
1187  } else {
1188  recipients = ast_strdupa(opts[OPT_ARG_VMRECIPIENTS]);
1189  }
1190  }
1191 
1193  filename_write = ast_strdupa(filename_parse(opts[OPT_ARG_WRITENAME], filename_buffer, sizeof(filename_buffer)));
1194  }
1195 
1196  if (ast_test_flag(&flags, MUXFLAG_READ)) {
1197  filename_read = ast_strdupa(filename_parse(opts[OPT_ARG_READNAME], filename_buffer, sizeof(filename_buffer)));
1198  }
1199 
1200  if (ast_test_flag(&flags, MUXFLAG_UID)) {
1201  uid_channel_var = opts[OPT_ARG_UID];
1202  }
1203 
1204  if (ast_test_flag(&flags, MUXFLAG_BEEP)) {
1205  const char *interval_str = S_OR(opts[OPT_ARG_BEEP_INTERVAL], "15");
1206  unsigned int interval = 15;
1207 
1208  if (sscanf(interval_str, "%30u", &interval) != 1) {
1209  ast_log(LOG_WARNING, "Invalid interval '%s' for periodic beep. Using default of %u\n",
1210  interval_str, interval);
1211  }
1212 
1213  if (ast_beep_start(chan, interval, beep_id, sizeof(beep_id))) {
1214  ast_log(LOG_WARNING, "Unable to enable periodic beep, please ensure func_periodic_hook is loaded.\n");
1215  return -1;
1216  }
1217  }
1218  }
1219  /* If there are no file writing arguments/options for the mix monitor, send a warning message and return -1 */
1220 
1222  ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n");
1223  return -1;
1224  }
1225 
1226  /* If filename exists, try to create directories for it */
1227  if (!(ast_strlen_zero(args.filename))) {
1228  args.filename = ast_strdupa(filename_parse(args.filename, filename_buffer, sizeof(filename_buffer)));
1229  }
1230 
1231  pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename);
1232 
1233  /* If launch_monitor_thread works, the module reference must not be released until it is finished. */
1235  if (launch_monitor_thread(chan,
1236  args.filename,
1237  flags.flags,
1238  readvol,
1239  writevol,
1240  args.post_process,
1241  filename_write,
1242  filename_read,
1243  uid_channel_var,
1244  recipients,
1245  beep_id)) {
1247  }
1248 
1251  if (message) {
1253  }
1254 
1255  return 0;
1256 }
static int launch_monitor_thread(struct ast_channel *chan, const char *filename, unsigned int flags, int readvol, int writevol, const char *post_process, const char *filename_write, char *filename_read, const char *uid_channel_var, const char *recipients, const char *beep_id)
#define get_volfactor(x)
static char * filename_parse(char *filename, char *buffer, size_t len)
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1844
int AST_OPTIONAL_API_NAME() ast_beep_start(struct ast_channel *chan, unsigned int interval, char *beep_id, size_t len)
struct stasis_message_type * ast_channel_mixmonitor_start_type(void)
Message type for starting mixmonitor on a channel.
#define LOG_NOTICE
#define ast_module_unref(mod)
Release a reference to the module.
Definition: module.h:469
#define ast_module_ref(mod)
Hold a reference to the module.
Definition: module.h:443
struct ast_module * self
Definition: module.h:342

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

Referenced by handle_cli_mixmonitor(), 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 671 of file app_mixmonitor.c.

672 {
673  /* Initialize the file if not already done so */
674  char *last_slash = NULL;
675  if (!ast_strlen_zero(filename)) {
676  if (!*fs && !*errflag && !mixmonitor->mixmonitor_ds->fs_quit) {
677  *oflags = O_CREAT | O_WRONLY;
678  *oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC;
679 
680  last_slash = strrchr(filename, '/');
681 
682  if ((*ext = strrchr(filename, '.')) && (*ext > last_slash)) {
683  **ext = '\0';
684  *ext = *ext + 1;
685  } else {
686  *ext = "raw";
687  }
688 
689  if (!(*fs = ast_writefile(filename, *ext, NULL, *oflags, 0, 0666))) {
690  ast_log(LOG_ERROR, "Cannot open %s.%s\n", filename, *ext);
691  *errflag = 1;
692  } else {
693  struct ast_filestream *tmp = *fs;
695  }
696  }
697  }
698 }
static int tmp()
Definition: bt_open.c:389
struct ast_filestream * ast_writefile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
Starts writing a file.
Definition: file.c:1402
unsigned int ast_format_get_sample_rate(const struct ast_format *format)
Get the sample rate of a media format.
Definition: format.c:379
This structure is allocated by file.c in one chunk, together with buf_size and desc_size bytes of mem...
Definition: mod_format.h:101
unsigned int samp_rate
#define MAX(a, b)
Definition: utils.h:228

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

Referenced by mixmonitor_thread().

◆ mixmonitor_thread()

static void* mixmonitor_thread ( void *  obj)
static

Definition at line 710 of file app_mixmonitor.c.

711 {
712  struct mixmonitor *mixmonitor = obj;
713  char *fs_ext = "";
714  char *fs_read_ext = "";
715  char *fs_write_ext = "";
716 
717  struct ast_filestream **fs = NULL;
718  struct ast_filestream **fs_read = NULL;
719  struct ast_filestream **fs_write = NULL;
720 
721  unsigned int oflags;
722  int errflag = 0;
723  struct ast_format *format_slin;
724 
725  /* Keep callid association before any log messages */
726  if (mixmonitor->callid) {
728  }
729 
730  ast_verb(2, "Begin MixMonitor Recording %s\n", mixmonitor->name);
731 
732  fs = &mixmonitor->mixmonitor_ds->fs;
733  fs_read = &mixmonitor->mixmonitor_ds->fs_read;
734  fs_write = &mixmonitor->mixmonitor_ds->fs_write;
735 
737  mixmonitor_save_prep(mixmonitor, mixmonitor->filename, fs, &oflags, &errflag, &fs_ext);
738  mixmonitor_save_prep(mixmonitor, mixmonitor->filename_read, fs_read, &oflags, &errflag, &fs_read_ext);
739  mixmonitor_save_prep(mixmonitor, mixmonitor->filename_write, fs_write, &oflags, &errflag, &fs_write_ext);
740 
742 
744 
745  /* The audiohook must enter and exit the loop locked */
748  struct ast_frame *fr = NULL;
749  struct ast_frame *fr_read = NULL;
750  struct ast_frame *fr_write = NULL;
751 
753  &fr_read, &fr_write))) {
755 
757  break;
758  }
759  continue;
760  }
761 
762  /* audiohook lock is not required for the next block.
763  * Unlock it, but remember to lock it before looping or exiting */
765 
769 
770  /* Write out the frame(s) */
771  if ((*fs_read) && (fr_read)) {
772  struct ast_frame *cur;
773 
774  for (cur = fr_read; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
775  ast_writestream(*fs_read, cur);
776  }
777  }
778 
779  if ((*fs_write) && (fr_write)) {
780  struct ast_frame *cur;
781 
782  for (cur = fr_write; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
783  ast_writestream(*fs_write, cur);
784  }
785  }
786 
787  if ((*fs) && (fr)) {
788  struct ast_frame *cur;
789 
790  for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
791  ast_writestream(*fs, cur);
792  }
793  }
795  }
796  /* All done! free it. */
797  if (fr) {
798  ast_frame_free(fr, 0);
799  }
800  if (fr_read) {
801  ast_frame_free(fr_read, 0);
802  }
803  if (fr_write) {
804  ast_frame_free(fr_write, 0);
805  }
806 
807  fr = NULL;
808  fr_write = NULL;
809  fr_read = NULL;
810 
812  }
813 
815 
820  }
821 
823 
824  /* Datastore cleanup. close the filestream and wait for ds destruction */
829  }
831 
832  /* kill the audiohook */
834 
835  if (mixmonitor->post_process) {
836  ast_verb(2, "Executing [%s]\n", mixmonitor->post_process);
838  }
839 
840  ast_verb(2, "End MixMonitor Recording %s\n", mixmonitor->name);
841  ast_test_suite_event_notify("MIXMONITOR_END", "File: %s\r\n", mixmonitor->filename);
842 
844  if (ast_strlen_zero(fs_ext)) {
845  ast_log(LOG_ERROR, "No file extension set for Mixmonitor %s. Skipping copy to voicemail.\n",
846  mixmonitor -> name);
847  } else {
848  ast_verb(3, "Copying recordings for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
850  }
851  if (!ast_strlen_zero(fs_read_ext)) {
852  ast_verb(3, "Copying read recording for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
854  }
855  if (!ast_strlen_zero(fs_write_ext)) {
856  ast_verb(3, "Copying write recording for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
858  }
859  } else {
860  ast_debug(3, "No recipients to forward monitor to, moving on.\n");
861  }
862 
864 
866  return NULL;
867 }
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:429
void ast_audiohook_trigger_wait(struct ast_audiohook *audiohook)
Wait for audiohook trigger to be triggered.
Definition: audiohook.c:1072
@ AST_AUDIOHOOK_STATUS_RUNNING
Definition: audiohook.h:43
int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
Writes a frame to a stream.
Definition: file.c:244
int ast_stream_and_wait(struct ast_channel *chan, const char *file, const char *digits)
stream file until digit If the file name is non-empty, try to play it.
Definition: file.c:1855
struct ast_format * ast_format_cache_get_slin_by_rate(unsigned int rate)
Retrieve the best signed linear format given a sample rate.
Definition: format_cache.c:512
int ast_safe_system(const char *s)
Safely spawn an OS shell command while closing file descriptors.
Definition: extconf.c:829
void ast_frame_free(struct ast_frame *frame, int cache)
Frees a frame or list of frames.
Definition: main/frame.c:176
int ast_callid_threadassoc_add(ast_callid callid)
Adds a known callid to thread storage of the calling thread.
Definition: logger.c:2070
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:450
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:439
#define ast_cond_wait(cond, mutex)
Definition: lock.h:203
enum ast_audiohook_status status
Definition: audiohook.h:108
Definition of a media format.
Definition: format.c:43
Data structure associated with a single frame of data.
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:189

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

Referenced by launch_monitor_thread().

◆ set_mixmonitor_methods()

static int set_mixmonitor_methods ( void  )
static

Definition at line 1652 of file app_mixmonitor.c.

1653 {
1656  .stop = stop_mixmonitor_callback,
1657  };
1658 
1660 }
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().

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

870 {
871  struct ast_datastore *datastore = NULL;
873 
874  if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) {
875  return -1;
876  }
877 
878  if (ast_asprintf(datastore_id, "%p", mixmonitor_ds) == -1) {
879  ast_log(LOG_ERROR, "Failed to allocate memory for MixMonitor ID.\n");
881  return -1;
882  }
883 
886 
887  if (!(datastore = ast_datastore_alloc(&mixmonitor_ds_info, *datastore_id))) {
891  return -1;
892  }
893 
898  }
899 
900  mixmonitor_ds->samp_rate = 8000;
903  if (!ast_strlen_zero(beep_id)) {
905  }
906  datastore->data = mixmonitor_ds;
907 
908  ast_channel_lock(chan);
909  ast_channel_datastore_add(chan, datastore);
910  ast_channel_unlock(chan);
911 
913  return 0;
914 }
#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:2384
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:85
#define ast_cond_init(cond, attr)
Definition: lock.h:199
#define ast_mutex_init(pmutex)
Definition: lock.h:184

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

1484 {
1485  char args[PATH_MAX];
1486 
1487  if (ast_strlen_zero(options)) {
1488  snprintf(args, sizeof(args), "%s", filename);
1489  } else {
1490  snprintf(args, sizeof(args), "%s,%s", filename, options);
1491  }
1492 
1493  return mixmonitor_exec(chan, args);
1494 }

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

530 {
531  if (!chan) {
532  return -1;
533  }
534 
535  return ast_audiohook_attach(chan, audiohook);
536 }
int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
Attach audiohook to channel.
Definition: audiohook.c:462

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

1497 {
1498  return stop_mixmonitor_full(chan, mixmonitor_id);
1499 }

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

1333 {
1334  stop_mixmonitor_full(chan, data);
1335  return 0;
1336 }

References stop_mixmonitor_full().

Referenced by handle_cli_mixmonitor().

◆ stop_mixmonitor_full()

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

Definition at line 1258 of file app_mixmonitor.c.

1259 {
1260  struct ast_datastore *datastore = NULL;
1261  char *parse = "";
1262  struct mixmonitor_ds *mixmonitor_ds;
1263  const char *beep_id = NULL;
1265 
1267  AST_APP_ARG(mixmonid);
1268  );
1269 
1270  if (!ast_strlen_zero(data)) {
1271  parse = ast_strdupa(data);
1272  }
1273 
1275 
1276  ast_channel_lock(chan);
1277 
1279  S_OR(args.mixmonid, NULL));
1280  if (!datastore) {
1281  ast_channel_unlock(chan);
1282  return -1;
1283  }
1284  mixmonitor_ds = datastore->data;
1285 
1287 
1288  /* closing the filestream here guarantees the file is available to the dialplan
1289  * after calling StopMixMonitor */
1291 
1292  /* The mixmonitor thread may be waiting on the audiohook trigger.
1293  * In order to exit from the mixmonitor loop before waiting on channel
1294  * destruction, poke the audiohook trigger. */
1295  if (mixmonitor_ds->audiohook) {
1298  }
1303  }
1304 
1307  }
1308 
1310 
1311  /* Remove the datastore so the monitor thread can exit */
1312  if (!ast_channel_datastore_remove(chan, datastore)) {
1313  ast_datastore_free(datastore);
1314  }
1315 
1316  ast_channel_unlock(chan);
1317 
1318  if (!ast_strlen_zero(beep_id)) {
1319  ast_beep_stop(chan, beep_id);
1320  }
1321 
1324  NULL);
1325  if (message) {
1327  }
1328 
1329  return 0;
1330 }
void ast_audiohook_update_status(struct ast_audiohook *audiohook, enum ast_audiohook_status status)
Update audiohook's status.
Definition: audiohook.c:518
@ 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, parse(), 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 1667 of file app_mixmonitor.c.

1668 {
1669  int res;
1670 
1674  res |= ast_manager_unregister("MixMonitorMute");
1675  res |= ast_manager_unregister("MixMonitor");
1676  res |= ast_manager_unregister("StopMixMonitor");
1678  res |= clear_mixmonitor_methods();
1679 
1680  return res;
1681 }
static int clear_mixmonitor_methods(void)
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7268
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.

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

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Mixed Audio Monitoring Application" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .optional_modules = "func_periodic_hook", }
static

Definition at line 1683 of file app_mixmonitor.c.

◆ app

const char* const app = "MixMonitor"
static

Definition at line 350 of file app_mixmonitor.c.

Referenced by unload_module().

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

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

Referenced by 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 497 of file app_mixmonitor.c.

Referenced by handle_cli_mixmonitor(), mixmonitor_ds_remove_and_free(), 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 1605 of file app_mixmonitor.c.

Referenced by 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 }, [ 'p' ] = { .flag = MUXFLAG_BEEP_START }, [ 'P' ] = { .flag = MUXFLAG_BEEP_STOP }, [ 'v' ] = { .flag = MUXFLAG_READVOLUME , .arg_index = OPT_ARG_READVOLUME + 1 }, [ 'V' ] = { .flag = MUXFLAG_WRITEVOLUME , .arg_index = OPT_ARG_WRITEVOLUME + 1 }, [ 'W' ] = { .flag = MUXFLAG_VOLUME , .arg_index = OPT_ARG_VOLUME + 1 }, [ 'r' ] = { .flag = MUXFLAG_READ , .arg_index = OPT_ARG_READNAME + 1 }, [ 't' ] = { .flag = MUXFLAG_WRITE , .arg_index = OPT_ARG_WRITENAME + 1 }, [ 'i' ] = { .flag = MUXFLAG_UID , .arg_index = OPT_ARG_UID + 1 }, [ 'm' ] = { .flag = MUXFLAG_VMRECIPIENTS , .arg_index = OPT_ARG_VMRECIPIENTS + 1 }, [ 'S' ] = { .flag = MUXFLAG_DEPRECATED_RWSYNC , .arg_index = OPT_ARG_DEPRECATED_RWSYNC + 1 }, [ 'n' ] = { .flag = MUXFLAG_NO_RWSYNC , .arg_index = OPT_ARG_NO_RWSYNC + 1 }, }
static

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

Referenced by unload_module().