Asterisk - The Open Source Telephony Project  18.5.0
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 = "30ef0c93b36035ec78c9cfd712d36d9b" , .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.

Referenced by mixmonitor_exec().

◆ SAMPLES_PER_FRAME

#define SAMPLES_PER_FRAME   160

Definition at line 602 of file app_mixmonitor.c.

Referenced by mixmonitor_thread().

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.

◆ 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.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 1703 of file app_mixmonitor.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1703 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.

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

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);
583  AST_LIST_INSERT_HEAD(&mixmonitor->recipient_list, recipient, list);
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 }
char mailbox[AST_MAX_CONTEXT]
#define ast_verb(level,...)
Definition: logger.h:463
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:193
#define LOG_ERROR
Definition: logger.h:285
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:710
struct vm_recipient::@57 list
char folder[80]
struct vm_recipient * next
struct minivm_account * next
Definition: app_minivm.c:621
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
char context[AST_MAX_EXTENSION]
struct mixmonitor::@58 recipient_list

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

Definition at line 1703 of file app_mixmonitor.c.

◆ clear_mixmonitor_methods()

static int clear_mixmonitor_methods ( void  )
static

Definition at line 1661 of file app_mixmonitor.c.

References ast_clear_mixmonitor_methods().

Referenced by unload_module().

1662 {
1664 }
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

◆ clear_mixmonitor_recipient_list()

static void clear_mixmonitor_recipient_list ( struct mixmonitor mixmonitor)
static

Definition at line 593 of file app_mixmonitor.c.

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

Referenced by mixmonitor_free().

594 {
595  struct vm_recipient *current;
596  while ((current = AST_LIST_REMOVE_HEAD(&mixmonitor->recipient_list, list))) {
597  /* Clear list element data */
598  ast_free(current);
599  }
600 }
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
#define ast_free(a)
Definition: astmm.h:182
struct vm_recipient::@57 list
struct mixmonitor::@58 recipient_list

◆ copy_to_voicemail()

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

Definition at line 635 of file app_mixmonitor.c.

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, ast_vm_recording_data::call_callerchan, mixmonitor::call_callerchan, ast_vm_recording_data::call_callerid, mixmonitor::call_callerid, ast_vm_recording_data::call_context, mixmonitor::call_context, ast_vm_recording_data::call_extension, mixmonitor::call_extension, ast_vm_recording_data::call_macrocontext, mixmonitor::call_macrocontext, ast_vm_recording_data::call_priority, mixmonitor::call_priority, ast_vm_recording_data::context, vm_recipient::context, vm_recipient::folder, vm_recipient::list, LOG_ERROR, ast_vm_recording_data::mailbox, vm_recipient::mailbox, NULL, mixmonitor::recipient_list, ast_vm_recording_data::recording_ext, and ast_vm_recording_data::recording_file.

Referenced by mixmonitor_thread().

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

◆ destroy_monitor_audiohook()

static void destroy_monitor_audiohook ( struct mixmonitor mixmonitor)
static

Definition at line 515 of file app_mixmonitor.c.

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

516 {
517  if (mixmonitor->mixmonitor_ds) {
518  ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
519  mixmonitor->mixmonitor_ds->audiohook = NULL;
520  ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
521  }
522  /* kill the audiohook.*/
523  ast_audiohook_lock(&mixmonitor->audiohook);
524  ast_audiohook_detach(&mixmonitor->audiohook);
525  ast_audiohook_unlock(&mixmonitor->audiohook);
526  ast_audiohook_destroy(&mixmonitor->audiohook);
527 }
#define ast_mutex_lock(a)
Definition: lock.h:187
struct mixmonitor_ds * mixmonitor_ds
#define NULL
Definition: resample.c:96
int ast_audiohook_destroy(struct ast_audiohook *audiohook)
Destroys an audiohook structure.
Definition: audiohook.c:133
#define ast_audiohook_unlock(ah)
Unlock an audiohook.
Definition: audiohook.h:300
int ast_audiohook_detach(struct ast_audiohook *audiohook)
Detach audiohook from channel.
Definition: audiohook.c:579
ast_mutex_t lock
struct ast_audiohook * audiohook
struct ast_audiohook audiohook
#define ast_audiohook_lock(ah)
Lock an audiohook.
Definition: audiohook.h:295
#define ast_mutex_unlock(a)
Definition: lock.h:188

◆ filename_parse()

static char* filename_parse ( char *  filename,
char *  buffer,
size_t  len 
)
static

Definition at line 1075 of file app_mixmonitor.c.

References ast_alloca, ast_assert, ast_config_AST_MONITOR_DIR, ast_copy_string(), ast_log, ast_mkdir(), ast_strlen_zero, ext, and LOG_WARNING.

Referenced by mixmonitor_exec().

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

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

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, ast_datastore::data, mixmonitor_ds::filename, and LOG_WARNING.

1606 {
1607  struct ast_datastore *datastore;
1608  struct mixmonitor_ds *ds_data;
1610  AST_APP_ARG(id);
1611  AST_APP_ARG(key);
1612  );
1613 
1614  AST_STANDARD_APP_ARGS(args, data);
1615 
1616  if (ast_strlen_zero(args.id) || ast_strlen_zero(args.key)) {
1617  ast_log(LOG_WARNING, "Not enough arguments provided to %s. "
1618  "An ID and key must be provided\n", cmd);
1619  return -1;
1620  }
1621 
1622  ast_channel_lock(chan);
1623  datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, args.id);
1624  ast_channel_unlock(chan);
1625 
1626  if (!datastore) {
1627  ast_log(LOG_WARNING, "Could not find MixMonitor with ID %s\n", args.id);
1628  return -1;
1629  }
1630 
1631  ds_data = datastore->data;
1632 
1633  if (!strcasecmp(args.key, "filename")) {
1634  ast_copy_string(buf, ds_data->filename, len);
1635  } else {
1636  ast_log(LOG_WARNING, "Unrecognized %s option %s\n", cmd, args.key);
1637  return -1;
1638  }
1639  return 0;
1640 }
#define ast_channel_lock(chan)
Definition: channel.h:2945
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define LOG_WARNING
Definition: logger.h:274
Structure for a data store object.
Definition: datastore.h:68
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:2404
const char * args
static const struct ast_datastore_info mixmonitor_ds_info
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define ast_channel_unlock(chan)
Definition: channel.h:2946
void * data
Definition: datastore.h:70
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define AST_APP_ARG(name)
Define an application argument.

◆ handle_cli_mixmonitor()

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

Definition at line 1337 of file app_mixmonitor.c.

References ast_cli_args::argc, ast_cli_args::argv, 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, ast_cli_args::fd, ast_filestream::filename, mixmonitor_ds::fs, mixmonitor_ds::fs_read, mixmonitor_ds::fs_write, ast_datastore::info, ast_cli_args::line, mixmonitor_exec(), ast_cli_args::n, NULL, ast_cli_args::pos, stop_mixmonitor_exec(), ast_cli_entry::usage, and ast_cli_args::word.

1338 {
1339  struct ast_channel *chan;
1340  struct ast_datastore *datastore = NULL;
1341  struct mixmonitor_ds *mixmonitor_ds = NULL;
1342 
1343  switch (cmd) {
1344  case CLI_INIT:
1345  e->command = "mixmonitor {start|stop|list}";
1346  e->usage =
1347  "Usage: mixmonitor start <chan_name> [args]\n"
1348  " The optional arguments are passed to the MixMonitor application.\n"
1349  " mixmonitor stop <chan_name> [args]\n"
1350  " The optional arguments are passed to the StopMixMonitor application.\n"
1351  " mixmonitor list <chan_name>\n";
1352  return NULL;
1353  case CLI_GENERATE:
1354  return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
1355  }
1356 
1357  if (a->argc < 3) {
1358  return CLI_SHOWUSAGE;
1359  }
1360 
1361  if (!(chan = ast_channel_get_by_name_prefix(a->argv[2], strlen(a->argv[2])))) {
1362  ast_cli(a->fd, "No channel matching '%s' found.\n", a->argv[2]);
1363  /* Technically this is a failure, but we don't want 2 errors printing out */
1364  return CLI_SUCCESS;
1365  }
1366 
1367  if (!strcasecmp(a->argv[1], "start")) {
1368  mixmonitor_exec(chan, (a->argc >= 4) ? a->argv[3] : "");
1369  } else if (!strcasecmp(a->argv[1], "stop")){
1370  stop_mixmonitor_exec(chan, (a->argc >= 4) ? a->argv[3] : "");
1371  } else if (!strcasecmp(a->argv[1], "list")) {
1372  ast_cli(a->fd, "MixMonitor ID\tFile\tReceive File\tTransmit File\n");
1373  ast_cli(a->fd, "=========================================================================\n");
1374  ast_channel_lock(chan);
1375  AST_LIST_TRAVERSE(ast_channel_datastores(chan), datastore, entry) {
1376  if (datastore->info == &mixmonitor_ds_info) {
1377  char *filename = "";
1378  char *filename_read = "";
1379  char *filename_write = "";
1380 
1381  mixmonitor_ds = datastore->data;
1382  if (mixmonitor_ds->fs) {
1383  filename = mixmonitor_ds->fs->filename;
1384  }
1385  if (mixmonitor_ds->fs_read) {
1386  filename_read = mixmonitor_ds->fs_read->filename;
1387  }
1388  if (mixmonitor_ds->fs_write) {
1389  filename_write = mixmonitor_ds->fs_write->filename;
1390  }
1391  ast_cli(a->fd, "%p\t%s\t%s\t%s\n", mixmonitor_ds, filename, filename_read, filename_write);
1392  }
1393  }
1394  ast_channel_unlock(chan);
1395  } else {
1396  chan = ast_channel_unref(chan);
1397  return CLI_SHOWUSAGE;
1398  }
1399 
1400  chan = ast_channel_unref(chan);
1401 
1402  return CLI_SUCCESS;
1403 }
static int stop_mixmonitor_exec(struct ast_channel *chan, const char *data)
#define ast_channel_lock(chan)
Definition: channel.h:2945
Main Channel structure associated with a channel.
struct ast_filestream * fs_read
struct ast_filestream * fs
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2981
const int argc
Definition: cli.h:160
Definition: cli.h:152
Structure for a data store object.
Definition: datastore.h:68
#define NULL
Definition: resample.c:96
static const struct ast_datastore_info mixmonitor_ds_info
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
const char * line
Definition: cli.h:162
static int 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:1434
const int fd
Definition: cli.h:159
const int n
Definition: cli.h:165
struct ast_datastore_list * ast_channel_datastores(struct ast_channel *chan)
const struct ast_datastore_info * info
Definition: datastore.h:71
const char *const * argv
Definition: cli.h:161
#define CLI_SHOWUSAGE
Definition: cli.h:45
struct ast_filestream * fs_write
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define ast_channel_unlock(chan)
Definition: channel.h:2946
char * command
Definition: cli.h:186
const char * word
Definition: cli.h:163
const char * usage
Definition: cli.h:177
#define CLI_SUCCESS
Definition: cli.h:44
void * data
Definition: datastore.h:70
char * filename
Definition: mod_format.h:107
const int pos
Definition: cli.h:164
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:1830
Definition: search.h:40

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

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, ast_party_connected_line::id, LOG_WARNING, mixmonitor_ds_remove_and_free(), mixmonitor_free(), mixmonitor_spy_type, mixmonitor_thread(), MUXFLAG_NO_RWSYNC, ast_party_id::name, mixmonitor::name, NULL, ast_party_id::number, ast_audiohook::options, pbx_builtin_setvar_helper(), pbx_substitute_variables_helper(), mixmonitor::post_process, ast_audiohook_options::read_volume, S_COR, setup_mixmonitor_ds(), startmon(), ast_party_name::str, ast_party_number::str, thread, ast_party_name::valid, ast_party_number::valid, and ast_audiohook_options::write_volume.

Referenced by mixmonitor_exec().

938 {
939  pthread_t thread;
940  struct mixmonitor *mixmonitor;
941  char postprocess2[1024] = "";
942  char *datastore_id = NULL;
943 
944  postprocess2[0] = 0;
945  /* If a post process system command is given attach it to the structure */
947  char *p1, *p2;
948 
950  for (p2 = p1; *p2; p2++) {
951  if (*p2 == '^' && *(p2+1) == '{') {
952  *p2 = '$';
953  }
954  }
955  ast_channel_lock(chan);
956  pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1);
957  ast_channel_unlock(chan);
958  }
959 
960  /* Pre-allocate mixmonitor structure and spy */
961  if (!(mixmonitor = ast_calloc(1, sizeof(*mixmonitor)))) {
962  return -1;
963  }
964 
965  /* Now that the struct has been calloced, go ahead and initialize the string fields. */
966  if (ast_string_field_init(mixmonitor, 512)) {
967  mixmonitor_free(mixmonitor);
968  return -1;
969  }
970 
971  /* Setup the actual spy before creating our thread */
973  mixmonitor_free(mixmonitor);
974  return -1;
975  }
976 
977  /* Copy over flags and channel name */
978  mixmonitor->flags = flags;
979  if (!(mixmonitor->autochan = ast_autochan_setup(chan))) {
980  mixmonitor_free(mixmonitor);
981  return -1;
982  }
983 
984  if (!ast_strlen_zero(filename)) {
985  mixmonitor->filename = ast_strdup(filename);
986  }
987 
990  }
991 
993  mixmonitor->filename_read = ast_strdup(filename_read);
994  }
995 
996  if (setup_mixmonitor_ds(mixmonitor, chan, &datastore_id, beep_id)) {
997  ast_autochan_destroy(mixmonitor->autochan);
998  mixmonitor_free(mixmonitor);
999  ast_free(datastore_id);
1000  return -1;
1001  }
1002 
1003  if (!ast_strlen_zero(uid_channel_var)) {
1004  if (datastore_id) {
1005  pbx_builtin_setvar_helper(chan, uid_channel_var, datastore_id);
1006  }
1007  }
1008 
1009  mixmonitor->name = ast_strdup(ast_channel_name(chan));
1010 
1011  if (!ast_strlen_zero(postprocess2)) {
1012  mixmonitor->post_process = ast_strdup(postprocess2);
1013  }
1014 
1015  if (!ast_strlen_zero(recipients)) {
1016  char callerid[256];
1018 
1019  ast_channel_lock(chan);
1020 
1021  /* We use the connected line of the invoking channel for caller ID. */
1022 
1023  connected = ast_channel_connected(chan);
1024  ast_debug(3, "Connected Line CID = %d - %s : %d - %s\n", connected->id.name.valid,
1025  connected->id.name.str, connected->id.number.valid,
1026  connected->id.number.str);
1027  ast_callerid_merge(callerid, sizeof(callerid),
1028  S_COR(connected->id.name.valid, connected->id.name.str, NULL),
1029  S_COR(connected->id.number.valid, connected->id.number.str, NULL),
1030  "Unknown");
1031 
1032  ast_string_field_set(mixmonitor, call_context, ast_channel_context(chan));
1033  ast_string_field_set(mixmonitor, call_macrocontext, ast_channel_macrocontext(chan));
1034  ast_string_field_set(mixmonitor, call_extension, ast_channel_exten(chan));
1035  ast_string_field_set(mixmonitor, call_callerchan, ast_channel_name(chan));
1036  ast_string_field_set(mixmonitor, call_callerid, callerid);
1037  mixmonitor->call_priority = ast_channel_priority(chan);
1038 
1039  ast_channel_unlock(chan);
1040 
1041  add_vm_recipients_from_string(mixmonitor, recipients);
1042  }
1043 
1045  if (!ast_test_flag(mixmonitor, MUXFLAG_NO_RWSYNC)) {
1047  }
1048 
1049  if (readvol)
1050  mixmonitor->audiohook.options.read_volume = readvol;
1051  if (writevol)
1052  mixmonitor->audiohook.options.write_volume = writevol;
1053 
1054  if (startmon(chan, &mixmonitor->audiohook)) {
1055  ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n",
1057  mixmonitor_ds_remove_and_free(chan, datastore_id);
1058  ast_free(datastore_id);
1059  ast_autochan_destroy(mixmonitor->autochan);
1060  ast_audiohook_destroy(&mixmonitor->audiohook);
1061  mixmonitor_free(mixmonitor);
1062  return -1;
1063  }
1064 
1065  ast_free(datastore_id);
1066 
1067  /* reference be released at mixmonitor destruction */
1068  mixmonitor->callid = ast_read_threadstorage_callid();
1069 
1070  return ast_pthread_create_detached_background(&thread, NULL, mixmonitor_thread, mixmonitor);
1071 }
pthread_t thread
Definition: app_meetme.c:1089
#define ast_channel_lock(chan)
Definition: channel.h:2945
char * str
Subscriber phone number (Malloced)
Definition: channel.h:292
char * filename_read
struct ast_party_id id
Connected party ID.
Definition: channel.h:459
ast_callid callid
#define ast_test_flag(p, flag)
Definition: utils.h:63
struct ast_party_name name
Subscriber name.
Definition: channel.h:341
static void add_vm_recipients_from_string(struct mixmonitor *mixmonitor, const char *vm_recipients)
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define LOG_WARNING
Definition: logger.h:274
static int startmon(struct ast_channel *chan, struct ast_audiohook *audiohook)
char * str
Subscriber name (Malloced)
Definition: channel.h:265
static void mixmonitor_ds_remove_and_free(struct ast_channel *chan, const char *datastore_id)
char * post_process
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define NULL
Definition: resample.c:96
int ast_audiohook_destroy(struct ast_audiohook *audiohook)
Destroys an audiohook structure.
Definition: audiohook.c:133
int ast_channel_priority(const struct ast_channel *chan)
#define ast_pthread_create_detached_background(a, b, c, d)
Definition: utils.h:572
ast_callid ast_read_threadstorage_callid(void)
extracts the callerid from the thread
Definition: logger.c:1962
#define ast_strlen_zero(foo)
Definition: strings.h:52
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:108
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
static void mixmonitor_free(struct mixmonitor *mixmonitor)
char * ast_callerid_merge(char *buf, int bufsiz, const char *name, const char *num, const char *unknown)
Definition: callerid.c:1073
static const char *const mixmonitor_spy_type
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:353
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
#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:85
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
const char * ast_channel_exten(const struct ast_channel *chan)
char * filename_write
Connected Line/Party information.
Definition: channel.h:457
#define ast_channel_unlock(chan)
Definition: channel.h:2946
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
char * filename
void ast_autochan_destroy(struct ast_autochan *autochan)
destroy an ast_autochan structure
Definition: autochan.c:64
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...
struct ast_autochan * ast_autochan_setup(struct ast_channel *chan)
set up a new ast_autochan structure
Definition: autochan.c:38
struct ast_audiohook_options options
Definition: audiohook.h:118
static void * mixmonitor_thread(void *obj)
unsigned int flags
const char * ast_channel_name(const struct ast_channel *chan)
static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel *chan, char **datastore_id, const char *beep_id)
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
Definition: ael_main.c:211
const char * ast_channel_context(const struct ast_channel *chan)
unsigned char valid
TRUE if the name information is valid/present.
Definition: channel.h:280
const char * ast_channel_macrocontext(const struct ast_channel *chan)
struct ast_audiohook audiohook
char connected
Definition: eagi_proxy.c:82
struct ast_autochan * autochan
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:298
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:514
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:343

◆ load_module()

static int load_module ( void  )
static

Definition at line 1682 of file app_mixmonitor.c.

References app, ARRAY_LEN, ast_cli_register_multiple, ast_custom_function_register, ast_manager_register_xml, AST_MODFLAG_DEFAULT, AST_MODULE_INFO(), AST_MODULE_SUPPORT_CORE, ast_register_application_xml, ASTERISK_GPL_KEY, EVENT_FLAG_CALL, EVENT_FLAG_SYSTEM, manager_mixmonitor(), manager_mute_mixmonitor(), manager_stop_mixmonitor(), mixmonitor_exec(), set_mixmonitor_methods(), stop_app, stop_mixmonitor_exec(), and unload_module().

1683 {
1684  int res;
1685 
1693  res |= set_mixmonitor_methods();
1694 
1695  return res;
1696 }
static int set_mixmonitor_methods(void)
static int stop_mixmonitor_exec(struct ast_channel *chan, const char *data)
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
static int manager_stop_mixmonitor(struct mansession *s, const struct message *m)
#define EVENT_FLAG_CALL
Definition: manager.h:72
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
static int manager_mute_mixmonitor(struct mansession *s, const struct message *m)
Mute / unmute a MixMonitor channel.
static int mixmonitor_exec(struct ast_channel *chan, const char *data)
#define EVENT_FLAG_SYSTEM
Definition: manager.h:71
static const char *const stop_app
static const char *const app
static int manager_mixmonitor(struct mansession *s, const struct message *m)
static struct ast_custom_function mixmonitor_function
static struct ast_cli_entry cli_mixmonitor[]
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:186
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1508
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626

◆ manager_mixmonitor()

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

Definition at line 1500 of file app_mixmonitor.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, mixmonitor_exec(), mixmonitor_opts, MUXFLAG_UID, NULL, OPT_ARG_ARRAY_SIZE, OPT_ARG_UID, options, PATH_MAX, pbx_builtin_getvar_helper(), and S_OR.

Referenced by load_module().

1501 {
1502  struct ast_channel *c;
1503  const char *name = astman_get_header(m, "Channel");
1504  const char *id = astman_get_header(m, "ActionID");
1505  const char *file = astman_get_header(m, "File");
1506  const char *options = astman_get_header(m, "Options");
1507  const char *command = astman_get_header(m, "Command");
1508  char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
1509  struct ast_flags flags = { 0 };
1510  char *uid_channel_var = NULL;
1511  const char *mixmonitor_id = NULL;
1512  int res;
1513  char args[PATH_MAX];
1514 
1515  if (ast_strlen_zero(name)) {
1516  astman_send_error(s, m, "No channel specified");
1517  return AMI_SUCCESS;
1518  }
1519 
1520  c = ast_channel_get_by_name(name);
1521  if (!c) {
1522  astman_send_error(s, m, "No such channel");
1523  return AMI_SUCCESS;
1524  }
1525 
1526  if (!ast_strlen_zero(options)) {
1527  ast_app_parse_options(mixmonitor_opts, &flags, opts, ast_strdupa(options));
1528  }
1529 
1530  snprintf(args, sizeof(args), "%s,%s,%s", file, options, command);
1531 
1532  res = mixmonitor_exec(c, args);
1533 
1534  if (ast_test_flag(&flags, MUXFLAG_UID)) {
1535  uid_channel_var = opts[OPT_ARG_UID];
1536  ast_channel_lock(c);
1537  mixmonitor_id = pbx_builtin_getvar_helper(c, uid_channel_var);
1538  mixmonitor_id = ast_strdupa(S_OR(mixmonitor_id, ""));
1539  ast_channel_unlock(c);
1540  }
1541 
1542  if (res) {
1543  ast_channel_unref(c);
1544  astman_send_error(s, m, "Could not start monitoring channel");
1545  return AMI_SUCCESS;
1546  }
1547 
1548  astman_append(s, "Response: Success\r\n");
1549 
1550  if (!ast_strlen_zero(id)) {
1551  astman_append(s, "ActionID: %s\r\n", id);
1552  }
1553 
1554  if (!ast_strlen_zero(mixmonitor_id)) {
1555  astman_append(s, "MixMonitorID: %s\r\n", mixmonitor_id);
1556  }
1557 
1558  astman_append(s, "\r\n");
1559 
1560  ast_channel_unref(c);
1561 
1562  return AMI_SUCCESS;
1563 }
#define ast_channel_lock(chan)
Definition: channel.h:2945
Main Channel structure associated with a channel.
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3080
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2981
#define ast_test_flag(p, flag)
Definition: utils.h:63
unsigned int flags
Definition: utils.h:200
static struct test_val c
const char * args
#define NULL
Definition: resample.c:96
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
static int mixmonitor_exec(struct ast_channel *chan, const char *data)
static const struct ast_app_option mixmonitor_opts[128]
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
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:2906
#define ast_channel_unlock(chan)
Definition: channel.h:2946
static const char name[]
Definition: cdr_mysql.c:74
Structure used to handle boolean flags.
Definition: utils.h:199
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
#define PATH_MAX
Definition: asterisk.h:40
static struct test_options options
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1454
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3159
#define AMI_SUCCESS
Definition: manager.h:65

◆ manager_mute_mixmonitor()

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

Mute / unmute a MixMonitor channel.

Definition at line 1406 of file app_mixmonitor.c.

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, NULL, RAII_VAR, and stasis_publish().

Referenced by load_module().

1407 {
1408  struct ast_channel *c;
1409  const char *name = astman_get_header(m, "Channel");
1410  const char *id = astman_get_header(m, "ActionID");
1411  const char *state = astman_get_header(m, "State");
1412  const char *direction = astman_get_header(m,"Direction");
1413  int clearmute = 1;
1416  RAII_VAR(struct ast_json *, stasis_message_blob, NULL, ast_json_unref);
1417 
1418  if (ast_strlen_zero(direction)) {
1419  astman_send_error(s, m, "No direction specified. Must be read, write or both");
1420  return AMI_SUCCESS;
1421  }
1422 
1423  if (!strcasecmp(direction, "read")) {
1424  flag = AST_AUDIOHOOK_MUTE_READ;
1425  } else if (!strcasecmp(direction, "write")) {
1426  flag = AST_AUDIOHOOK_MUTE_WRITE;
1427  } else if (!strcasecmp(direction, "both")) {
1429  } else {
1430  astman_send_error(s, m, "Invalid direction specified. Must be read, write or both");
1431  return AMI_SUCCESS;
1432  }
1433 
1434  if (ast_strlen_zero(name)) {
1435  astman_send_error(s, m, "No channel specified");
1436  return AMI_SUCCESS;
1437  }
1438 
1439  if (ast_strlen_zero(state)) {
1440  astman_send_error(s, m, "No state specified");
1441  return AMI_SUCCESS;
1442  }
1443 
1444  clearmute = ast_false(state);
1445 
1446  c = ast_channel_get_by_name(name);
1447  if (!c) {
1448  astman_send_error(s, m, "No such channel");
1449  return AMI_SUCCESS;
1450  }
1451 
1452  if (ast_audiohook_set_mute(c, mixmonitor_spy_type, flag, clearmute)) {
1453  ast_channel_unref(c);
1454  astman_send_error(s, m, "Cannot set mute flag");
1455  return AMI_SUCCESS;
1456  }
1457 
1458  stasis_message_blob = ast_json_pack("{s: s, s: b}",
1459  "direction", direction,
1460  "state", ast_true(state));
1461 
1463  ast_channel_mixmonitor_mute_type(), stasis_message_blob);
1464 
1465  if (stasis_message) {
1467  }
1468 
1469  astman_append(s, "Response: Success\r\n");
1470 
1471  if (!ast_strlen_zero(id)) {
1472  astman_append(s, "ActionID: %s\r\n", id);
1473  }
1474 
1475  astman_append(s, "\r\n");
1476 
1477  ast_channel_unref(c);
1478 
1479  return AMI_SUCCESS;
1480 }
Main Channel structure associated with a channel.
ast_audiohook_flags
Definition: audiohook.h:54
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3080
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:591
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2981
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
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:1424
static struct test_val c
#define NULL
Definition: resample.c:96
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
#define ast_strlen_zero(foo)
Definition: strings.h:52
static const char *const mixmonitor_spy_type
#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:911
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.
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
long int flag
Definition: f2c.h:83
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic&#39;s subscribers.
Definition: stasis.c:1511
static const char name[]
Definition: cdr_mysql.c:74
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.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
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:1968
Abstract JSON element (object, array, string, int, ...).
direction
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1454
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3159
#define AMI_SUCCESS
Definition: manager.h:65
struct stasis_message_type * ast_channel_mixmonitor_mute_type(void)
Message type for muting or unmuting mixmonitor on a channel.

◆ manager_stop_mixmonitor()

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

Definition at line 1565 of file app_mixmonitor.c.

References AMI_SUCCESS, ast_channel_get_by_name(), ast_channel_unref, ast_strlen_zero, astman_append(), astman_get_header(), astman_send_error(), c, and stop_mixmonitor_full().

Referenced by load_module().

1566 {
1567  struct ast_channel *c;
1568  const char *name = astman_get_header(m, "Channel");
1569  const char *id = astman_get_header(m, "ActionID");
1570  const char *mixmonitor_id = astman_get_header(m, "MixMonitorID");
1571  int res;
1572 
1573  if (ast_strlen_zero(name)) {
1574  astman_send_error(s, m, "No channel specified");
1575  return AMI_SUCCESS;
1576  }
1577 
1578  c = ast_channel_get_by_name(name);
1579  if (!c) {
1580  astman_send_error(s, m, "No such channel");
1581  return AMI_SUCCESS;
1582  }
1583 
1584  res = stop_mixmonitor_full(c, mixmonitor_id);
1585  if (res) {
1586  ast_channel_unref(c);
1587  astman_send_error(s, m, "Could not stop monitoring channel");
1588  return AMI_SUCCESS;
1589  }
1590 
1591  astman_append(s, "Response: Success\r\n");
1592 
1593  if (!ast_strlen_zero(id)) {
1594  astman_append(s, "ActionID: %s\r\n", id);
1595  }
1596 
1597  astman_append(s, "\r\n");
1598 
1599  ast_channel_unref(c);
1600 
1601  return AMI_SUCCESS;
1602 }
Main Channel structure associated with a channel.
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3080
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2981
static struct test_val c
static int stop_mixmonitor_full(struct ast_channel *chan, const char *data)
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
#define ast_strlen_zero(foo)
Definition: strings.h:52
static const char name[]
Definition: cdr_mysql.c:74
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1454
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3159
#define AMI_SUCCESS
Definition: manager.h:65

◆ mixmonitor_autochan_is_bridged()

static int mixmonitor_autochan_is_bridged ( struct ast_autochan autochan)
static

Definition at line 699 of file app_mixmonitor.c.

References ast_autochan_channel_lock, ast_autochan_channel_unlock, ast_channel_is_bridged(), and ast_autochan::chan.

Referenced by mixmonitor_thread().

700 {
701  int is_bridged;
702 
703  ast_autochan_channel_lock(autochan);
704  is_bridged = ast_channel_is_bridged(autochan->chan);
705  ast_autochan_channel_unlock(autochan);
706  return is_bridged;
707 }
#define ast_autochan_channel_lock(autochan)
Lock the autochan&#39;s channel lock.
Definition: autochan.h:75
struct ast_channel * chan
Definition: autochan.h:33
int ast_channel_is_bridged(const struct ast_channel *chan)
Determine if a channel is in a bridge.
Definition: channel.c:10746
#define ast_autochan_channel_unlock(autochan)
Definition: autochan.h:84

◆ 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.

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

468 {
469  unsigned char quitting = 0;
470 
471  if (mixmonitor_ds->fs) {
472  quitting = 1;
473  ast_closestream(mixmonitor_ds->fs);
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;
480  ast_closestream(mixmonitor_ds->fs_read);
481  mixmonitor_ds->fs_read = NULL;
482  ast_verb(2, "MixMonitor close filestream (read)\n");
483  }
484 
485  if (mixmonitor_ds->fs_write) {
486  quitting = 1;
487  ast_closestream(mixmonitor_ds->fs_write);
488  mixmonitor_ds->fs_write = NULL;
489  ast_verb(2, "MixMonitor close filestream (write)\n");
490  }
491 
492  if (quitting) {
493  mixmonitor_ds->fs_quit = 1;
494  }
495 }
struct ast_filestream * fs_read
struct ast_filestream * fs
#define NULL
Definition: resample.c:96
#define ast_verb(level,...)
Definition: logger.h:463
struct ast_filestream * fs_write
int ast_closestream(struct ast_filestream *f)
Closes a stream.
Definition: file.c:1068

◆ mixmonitor_ds_destroy()

static void mixmonitor_ds_destroy ( void *  data)
static

Definition at line 497 of file app_mixmonitor.c.

References ast_cond_signal, ast_free, ast_mutex_lock, ast_mutex_unlock, mixmonitor_ds::audiohook, mixmonitor_ds::beep_id, mixmonitor_ds::destruction_condition, mixmonitor_ds::destruction_ok, mixmonitor_ds::filename, mixmonitor_ds::lock, and NULL.

498 {
499  struct mixmonitor_ds *mixmonitor_ds = data;
500 
501  ast_mutex_lock(&mixmonitor_ds->lock);
502  mixmonitor_ds->audiohook = NULL;
503  mixmonitor_ds->destruction_ok = 1;
504  ast_free(mixmonitor_ds->filename);
505  ast_free(mixmonitor_ds->beep_id);
506  ast_cond_signal(&mixmonitor_ds->destruction_condition);
507  ast_mutex_unlock(&mixmonitor_ds->lock);
508 }
unsigned int destruction_ok
#define ast_mutex_lock(a)
Definition: lock.h:187
#define NULL
Definition: resample.c:96
#define ast_cond_signal(cond)
Definition: lock.h:201
ast_cond_t destruction_condition
ast_mutex_t lock
#define ast_free(a)
Definition: astmm.h:182
struct ast_audiohook * audiohook
#define ast_mutex_unlock(a)
Definition: lock.h:188

◆ mixmonitor_ds_remove_and_free()

static void mixmonitor_ds_remove_and_free ( struct ast_channel chan,
const char *  datastore_id 
)
static

Definition at line 915 of file app_mixmonitor.c.

References ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_unlock, and ast_datastore_free().

Referenced by launch_monitor_thread().

916 {
917  struct ast_datastore *datastore;
918 
919  ast_channel_lock(chan);
920 
921  datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, datastore_id);
922 
923  /*
924  * Currently the one place this function is called from guarantees a
925  * datastore is present, thus return checks can be avoided here.
926  */
927  ast_channel_datastore_remove(chan, datastore);
928  ast_datastore_free(datastore);
929 
930  ast_channel_unlock(chan);
931 }
#define ast_channel_lock(chan)
Definition: channel.h:2945
Structure for a data store object.
Definition: datastore.h:68
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:2404
static const struct ast_datastore_info mixmonitor_ds_info
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
#define ast_channel_unlock(chan)
Definition: channel.h:2946
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2399

◆ mixmonitor_exec()

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

Definition at line 1115 of file app_mixmonitor.c.

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(), load_module(), manager_mixmonitor(), and start_mixmonitor_callback().

1116 {
1117  int x, readvol = 0, writevol = 0;
1118  char *filename_read = NULL;
1119  char *filename_write = NULL;
1120  char filename_buffer[1024] = "";
1121  char *uid_channel_var = NULL;
1122  char beep_id[64] = "";
1123 
1124  struct ast_flags flags = { 0 };
1125  char *recipients = NULL;
1126  char *parse;
1129  AST_APP_ARG(filename);
1131  AST_APP_ARG(post_process);
1132  );
1133 
1134  if (ast_strlen_zero(data)) {
1135  ast_log(LOG_WARNING, "MixMonitor requires an argument (filename or ,t(filename) and/or r(filename)\n");
1136  return -1;
1137  }
1138 
1139  parse = ast_strdupa(data);
1140 
1141  AST_STANDARD_APP_ARGS(args, parse);
1142 
1143  if (args.options) {
1144  char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
1145 
1146  ast_app_parse_options(mixmonitor_opts, &flags, opts, args.options);
1147 
1149  ast_log(LOG_NOTICE, "The synchronization behavior enabled by the 'S' option is now the default"
1150  " and does not need to be specified.\n");
1151  }
1152 
1153  if (ast_test_flag(&flags, MUXFLAG_READVOLUME)) {
1154  if (ast_strlen_zero(opts[OPT_ARG_READVOLUME])) {
1155  ast_log(LOG_WARNING, "No volume level was provided for the heard volume ('v') option.\n");
1156  } else if ((sscanf(opts[OPT_ARG_READVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
1157  ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_READVOLUME]);
1158  } else {
1159  readvol = get_volfactor(x);
1160  }
1161  }
1162 
1163  if (ast_test_flag(&flags, MUXFLAG_WRITEVOLUME)) {
1164  if (ast_strlen_zero(opts[OPT_ARG_WRITEVOLUME])) {
1165  ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n");
1166  } else if ((sscanf(opts[OPT_ARG_WRITEVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
1167  ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_WRITEVOLUME]);
1168  } else {
1169  writevol = get_volfactor(x);
1170  }
1171  }
1172 
1173  if (ast_test_flag(&flags, MUXFLAG_VOLUME)) {
1174  if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) {
1175  ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n");
1176  } else if ((sscanf(opts[OPT_ARG_VOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
1177  ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]);
1178  } else {
1179  readvol = writevol = get_volfactor(x);
1180  }
1181  }
1182 
1183  if (ast_test_flag(&flags, MUXFLAG_VMRECIPIENTS)) {
1185  ast_log(LOG_WARNING, "No voicemail recipients were specified for the vm copy ('m') option.\n");
1186  } else {
1187  recipients = ast_strdupa(opts[OPT_ARG_VMRECIPIENTS]);
1188  }
1189  }
1190 
1191  if (ast_test_flag(&flags, MUXFLAG_WRITE)) {
1192  filename_write = ast_strdupa(filename_parse(opts[OPT_ARG_WRITENAME], filename_buffer, sizeof(filename_buffer)));
1193  }
1194 
1195  if (ast_test_flag(&flags, MUXFLAG_READ)) {
1196  filename_read = ast_strdupa(filename_parse(opts[OPT_ARG_READNAME], filename_buffer, sizeof(filename_buffer)));
1197  }
1198 
1199  if (ast_test_flag(&flags, MUXFLAG_UID)) {
1200  uid_channel_var = opts[OPT_ARG_UID];
1201  }
1202 
1203  if (ast_test_flag(&flags, MUXFLAG_BEEP)) {
1204  const char *interval_str = S_OR(opts[OPT_ARG_BEEP_INTERVAL], "15");
1205  unsigned int interval = 15;
1206 
1207  if (sscanf(interval_str, "%30u", &interval) != 1) {
1208  ast_log(LOG_WARNING, "Invalid interval '%s' for periodic beep. Using default of %u\n",
1209  interval_str, interval);
1210  }
1211 
1212  if (ast_beep_start(chan, interval, beep_id, sizeof(beep_id))) {
1213  ast_log(LOG_WARNING, "Unable to enable periodic beep, please ensure func_periodic_hook is loaded.\n");
1214  return -1;
1215  }
1216  }
1217  }
1218  /* If there are no file writing arguments/options for the mix monitor, send a warning message and return -1 */
1219 
1220  if (!ast_test_flag(&flags, MUXFLAG_WRITE) && !ast_test_flag(&flags, MUXFLAG_READ) && ast_strlen_zero(args.filename)) {
1221  ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n");
1222  return -1;
1223  }
1224 
1225  /* If filename exists, try to create directories for it */
1226  if (!(ast_strlen_zero(args.filename))) {
1227  args.filename = ast_strdupa(filename_parse(args.filename, filename_buffer, sizeof(filename_buffer)));
1228  }
1229 
1230  pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename);
1231 
1232  /* If launch_monitor_thread works, the module reference must not be released until it is finished. */
1234  if (launch_monitor_thread(chan,
1235  args.filename,
1236  flags.flags,
1237  readvol,
1238  writevol,
1239  args.post_process,
1240  filename_write,
1241  filename_read,
1242  uid_channel_var,
1243  recipients,
1244  beep_id)) {
1246  }
1247 
1250  if (message) {
1252  }
1253 
1254  return 0;
1255 }
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define LOG_WARNING
Definition: logger.h:274
static char * filename_parse(char *filename, char *buffer, size_t len)
unsigned int flags
Definition: utils.h:200
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)
const char * args
#define NULL
Definition: resample.c:96
static const struct ast_app_option mixmonitor_opts[128]
#define ast_module_unref(mod)
Release a reference to the module.
Definition: module.h:469
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define get_volfactor(x)
#define ast_log
Definition: astobj2.c:42
struct ast_module * self
Definition: module.h:342
#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:911
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
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:2906
int AST_OPTIONAL_API_NAME() ast_beep_start(struct ast_channel *chan, unsigned int interval, char *beep_id, size_t len)
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.
struct stasis_message_type * ast_channel_mixmonitor_start_type(void)
Message type for starting mixmonitor on a channel.
#define LOG_NOTICE
Definition: logger.h:263
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic&#39;s subscribers.
Definition: stasis.c:1511
Structure used to handle boolean flags.
Definition: utils.h:199
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.
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...
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
static struct test_options options
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define AST_APP_ARG(name)
Define an application argument.
#define ast_module_ref(mod)
Hold a reference to the module.
Definition: module.h:443

◆ mixmonitor_free()

static void mixmonitor_free ( struct mixmonitor mixmonitor)
static

Definition at line 604 of file app_mixmonitor.c.

References ast_cond_destroy, ast_free, ast_mutex_destroy, ast_string_field_free_memory, clear_mixmonitor_recipient_list(), mixmonitor_ds::destruction_condition, mixmonitor::filename, mixmonitor::filename_read, mixmonitor::filename_write, mixmonitor_ds::lock, mixmonitor::mixmonitor_ds, mixmonitor::name, and mixmonitor::post_process.

Referenced by launch_monitor_thread(), and mixmonitor_thread().

605 {
606  if (mixmonitor) {
607  if (mixmonitor->mixmonitor_ds) {
608  ast_mutex_destroy(&mixmonitor->mixmonitor_ds->lock);
610  ast_free(mixmonitor->mixmonitor_ds);
611  }
612 
613  ast_free(mixmonitor->name);
614  ast_free(mixmonitor->post_process);
615  ast_free(mixmonitor->filename);
616  ast_free(mixmonitor->filename_write);
617  ast_free(mixmonitor->filename_read);
618 
619  /* Free everything in the recipient list */
621 
622  /* clean stringfields */
623  ast_string_field_free_memory(mixmonitor);
624 
625  ast_free(mixmonitor);
626  }
627 }
char * filename_read
char * post_process
struct mixmonitor_ds * mixmonitor_ds
ast_cond_t destruction_condition
char * filename_write
#define ast_cond_destroy(cond)
Definition: lock.h:200
ast_mutex_t lock
#define ast_free(a)
Definition: astmm.h:182
char * filename
static void clear_mixmonitor_recipient_list(struct mixmonitor *mixmonitor)
#define ast_mutex_destroy(a)
Definition: lock.h:186
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:368

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

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

Referenced by mixmonitor_thread().

671 {
672  /* Initialize the file if not already done so */
673  char *last_slash = NULL;
674  if (!ast_strlen_zero(filename)) {
675  if (!*fs && !*errflag && !mixmonitor->mixmonitor_ds->fs_quit) {
676  *oflags = O_CREAT | O_WRONLY;
677  *oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC;
678 
679  last_slash = strrchr(filename, '/');
680 
681  if ((*ext = strrchr(filename, '.')) && (*ext > last_slash)) {
682  **ext = '\0';
683  *ext = *ext + 1;
684  } else {
685  *ext = "raw";
686  }
687 
688  if (!(*fs = ast_writefile(filename, *ext, NULL, *oflags, 0, 0666))) {
689  ast_log(LOG_ERROR, "Cannot open %s.%s\n", filename, *ext);
690  *errflag = 1;
691  } else {
692  struct ast_filestream *tmp = *fs;
694  }
695  }
696  }
697 }
#define ast_test_flag(p, flag)
Definition: utils.h:63
static int tmp()
Definition: bt_open.c:389
struct mixmonitor_ds * mixmonitor_ds
#define NULL
Definition: resample.c:96
unsigned int samp_rate
const char * ext
Definition: http.c:147
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
#define MAX(a, b)
Definition: utils.h:228
struct ast_format_def * fmt
Definition: mod_format.h:103
struct ast_format * format
Definition: mod_format.h:48
#define LOG_ERROR
Definition: logger.h:285
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:1361
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 ast_format_get_sample_rate(const struct ast_format *format)
Get the sample rate of a media format.
Definition: format.c:379

◆ mixmonitor_thread()

static void* mixmonitor_thread ( void *  obj)
static

Definition at line 709 of file app_mixmonitor.c.

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

710 {
711  struct mixmonitor *mixmonitor = obj;
712  char *fs_ext = "";
713  char *fs_read_ext = "";
714  char *fs_write_ext = "";
715 
716  struct ast_filestream **fs = NULL;
717  struct ast_filestream **fs_read = NULL;
718  struct ast_filestream **fs_write = NULL;
719 
720  unsigned int oflags;
721  int errflag = 0;
722  struct ast_format *format_slin;
723 
724  /* Keep callid association before any log messages */
725  if (mixmonitor->callid) {
726  ast_callid_threadassoc_add(mixmonitor->callid);
727  }
728 
729  ast_verb(2, "Begin MixMonitor Recording %s\n", mixmonitor->name);
730 
731  fs = &mixmonitor->mixmonitor_ds->fs;
732  fs_read = &mixmonitor->mixmonitor_ds->fs_read;
733  fs_write = &mixmonitor->mixmonitor_ds->fs_write;
734 
735  ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
736  mixmonitor_save_prep(mixmonitor, mixmonitor->filename, fs, &oflags, &errflag, &fs_ext);
737  mixmonitor_save_prep(mixmonitor, mixmonitor->filename_read, fs_read, &oflags, &errflag, &fs_read_ext);
738  mixmonitor_save_prep(mixmonitor, mixmonitor->filename_write, fs_write, &oflags, &errflag, &fs_write_ext);
739 
740  format_slin = ast_format_cache_get_slin_by_rate(mixmonitor->mixmonitor_ds->samp_rate);
741 
742  ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
743 
744  /* The audiohook must enter and exit the loop locked */
745  ast_audiohook_lock(&mixmonitor->audiohook);
746  while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING && !mixmonitor->mixmonitor_ds->fs_quit) {
747  struct ast_frame *fr = NULL;
748  struct ast_frame *fr_read = NULL;
749  struct ast_frame *fr_write = NULL;
750 
751  if (!(fr = ast_audiohook_read_frame_all(&mixmonitor->audiohook, SAMPLES_PER_FRAME, format_slin,
752  &fr_read, &fr_write))) {
754 
755  if (mixmonitor->audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
756  break;
757  }
758  continue;
759  }
760 
761  /* audiohook lock is not required for the next block.
762  * Unlock it, but remember to lock it before looping or exiting */
763  ast_audiohook_unlock(&mixmonitor->audiohook);
764 
765  if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED)
766  || mixmonitor_autochan_is_bridged(mixmonitor->autochan)) {
767  ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
768 
769  /* Write out the frame(s) */
770  if ((*fs_read) && (fr_read)) {
771  struct ast_frame *cur;
772 
773  for (cur = fr_read; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
774  ast_writestream(*fs_read, cur);
775  }
776  }
777 
778  if ((*fs_write) && (fr_write)) {
779  struct ast_frame *cur;
780 
781  for (cur = fr_write; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
782  ast_writestream(*fs_write, cur);
783  }
784  }
785 
786  if ((*fs) && (fr)) {
787  struct ast_frame *cur;
788 
789  for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
790  ast_writestream(*fs, cur);
791  }
792  }
793  ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
794  }
795  /* All done! free it. */
796  if (fr) {
797  ast_frame_free(fr, 0);
798  }
799  if (fr_read) {
800  ast_frame_free(fr_read, 0);
801  }
802  if (fr_write) {
803  ast_frame_free(fr_write, 0);
804  }
805 
806  fr = NULL;
807  fr_write = NULL;
808  fr_read = NULL;
809 
810  ast_audiohook_lock(&mixmonitor->audiohook);
811  }
812 
813  ast_audiohook_unlock(&mixmonitor->audiohook);
814 
815  if (ast_test_flag(mixmonitor, MUXFLAG_BEEP_STOP)) {
816  ast_autochan_channel_lock(mixmonitor->autochan);
817  ast_stream_and_wait(mixmonitor->autochan->chan, "beep", "");
819  }
820 
821  ast_autochan_destroy(mixmonitor->autochan);
822 
823  /* Datastore cleanup. close the filestream and wait for ds destruction */
824  ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
826  if (!mixmonitor->mixmonitor_ds->destruction_ok) {
828  }
829  ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
830 
831  /* kill the audiohook */
832  destroy_monitor_audiohook(mixmonitor);
833 
834  if (mixmonitor->post_process) {
835  ast_verb(2, "Executing [%s]\n", mixmonitor->post_process);
836  ast_safe_system(mixmonitor->post_process);
837  }
838 
839  ast_verb(2, "End MixMonitor Recording %s\n", mixmonitor->name);
840  ast_test_suite_event_notify("MIXMONITOR_END", "File: %s\r\n", mixmonitor->filename);
841 
842  if (!AST_LIST_EMPTY(&mixmonitor->recipient_list)) {
843  if (ast_strlen_zero(fs_ext)) {
844  ast_log(LOG_ERROR, "No file extension set for Mixmonitor %s. Skipping copy to voicemail.\n",
845  mixmonitor -> name);
846  } else {
847  ast_verb(3, "Copying recordings for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
848  copy_to_voicemail(mixmonitor, fs_ext, mixmonitor->filename);
849  }
850  if (!ast_strlen_zero(fs_read_ext)) {
851  ast_verb(3, "Copying read recording for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
852  copy_to_voicemail(mixmonitor, fs_read_ext, mixmonitor->filename_read);
853  }
854  if (!ast_strlen_zero(fs_write_ext)) {
855  ast_verb(3, "Copying write recording for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
856  copy_to_voicemail(mixmonitor, fs_write_ext, mixmonitor->filename_write);
857  }
858  } else {
859  ast_debug(3, "No recipients to forward monitor to, moving on.\n");
860  }
861 
862  mixmonitor_free(mixmonitor);
863 
865  return NULL;
866 }
struct ast_filestream * fs_read
char * filename_read
#define ast_autochan_channel_lock(autochan)
Lock the autochan&#39;s channel lock.
Definition: autochan.h:75
static void destroy_monitor_audiohook(struct mixmonitor *mixmonitor)
ast_callid callid
struct ast_filestream * fs
#define ast_test_flag(p, flag)
Definition: utils.h:63
unsigned int destruction_ok
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:438
Definition of a media format.
Definition: format.c:43
#define ast_cond_wait(cond, mutex)
Definition: lock.h:203
struct ast_channel * chan
Definition: autochan.h:33
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:449
char * post_process
#define ast_mutex_lock(a)
Definition: lock.h:187
struct mixmonitor_ds * mixmonitor_ds
void ast_frame_free(struct ast_frame *fr, int cache)
Requests a frame to be allocated.
Definition: main/frame.c:176
#define NULL
Definition: resample.c:96
unsigned int samp_rate
#define ast_verb(level,...)
Definition: logger.h:463
#define ast_module_unref(mod)
Release a reference to the module.
Definition: module.h:469
#define ast_strlen_zero(foo)
Definition: strings.h:52
ast_cond_t destruction_condition
int ast_callid_threadassoc_add(ast_callid callid)
Adds a known callid to thread storage of the calling thread.
Definition: logger.c:1984
#define ast_audiohook_unlock(ah)
Unlock an audiohook.
Definition: audiohook.h:300
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
static void mixmonitor_free(struct mixmonitor *mixmonitor)
struct ast_module * self
Definition: module.h:342
static void mixmonitor_save_prep(struct mixmonitor *mixmonitor, char *filename, struct ast_filestream **fs, unsigned int *oflags, int *errflag, char **ext)
char * filename_write
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:196
#define LOG_ERROR
Definition: logger.h:285
static void mixmonitor_ds_close_fs(struct mixmonitor_ds *mixmonitor_ds)
int ast_safe_system(const char *s)
Safely spawn an OS shell command while closing file descriptors.
Definition: extconf.c:829
struct ast_filestream * fs_write
static void copy_to_voicemail(struct mixmonitor *mixmonitor, const char *ext, const char *filename)
ast_mutex_t lock
static const char name[]
Definition: cdr_mysql.c:74
char * filename
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:1814
#define SAMPLES_PER_FRAME
void ast_autochan_destroy(struct ast_autochan *autochan)
destroy an ast_autochan structure
Definition: autochan.c:64
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:463
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
int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
Writes a frame to a stream.
Definition: file.c:209
Data structure associated with a single frame of data.
enum ast_audiohook_status status
Definition: audiohook.h:107
#define ast_autochan_channel_unlock(autochan)
Definition: autochan.h:84
static int mixmonitor_autochan_is_bridged(struct ast_autochan *autochan)
struct ast_audiohook audiohook
#define ast_audiohook_lock(ah)
Lock an audiohook.
Definition: audiohook.h:295
struct ast_autochan * autochan
void ast_audiohook_trigger_wait(struct ast_audiohook *audiohook)
Wait for audiohook trigger to be triggered.
Definition: audiohook.c:1142
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:520
#define ast_mutex_unlock(a)
Definition: lock.h:188
struct mixmonitor::@58 recipient_list

◆ set_mixmonitor_methods()

static int set_mixmonitor_methods ( void  )
static

Definition at line 1651 of file app_mixmonitor.c.

References ast_set_mixmonitor_methods(), ast_mixmonitor_methods::start, start_mixmonitor_callback(), and stop_mixmonitor_callback().

Referenced by load_module().

1652 {
1655  .stop = stop_mixmonitor_callback,
1656  };
1657 
1658  return ast_set_mixmonitor_methods(&mixmonitor_methods);
1659 }
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
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
ast_mixmonitor_start_fn start
Definition: mixmonitor.h:59

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

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, MUXFLAG_BEEP_START, NULL, and mixmonitor_ds::samp_rate.

Referenced by launch_monitor_thread().

869 {
870  struct ast_datastore *datastore = NULL;
872 
873  if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) {
874  return -1;
875  }
876 
877  if (ast_asprintf(datastore_id, "%p", mixmonitor_ds) == -1) {
878  ast_log(LOG_ERROR, "Failed to allocate memory for MixMonitor ID.\n");
879  ast_free(mixmonitor_ds);
880  return -1;
881  }
882 
883  ast_mutex_init(&mixmonitor_ds->lock);
884  ast_cond_init(&mixmonitor_ds->destruction_condition, NULL);
885 
886  if (!(datastore = ast_datastore_alloc(&mixmonitor_ds_info, *datastore_id))) {
887  ast_mutex_destroy(&mixmonitor_ds->lock);
888  ast_cond_destroy(&mixmonitor_ds->destruction_condition);
889  ast_free(mixmonitor_ds);
890  return -1;
891  }
892 
893  if (ast_test_flag(mixmonitor, MUXFLAG_BEEP_START)) {
894  ast_autochan_channel_lock(mixmonitor->autochan);
895  ast_stream_and_wait(mixmonitor->autochan->chan, "beep", "");
897  }
898 
899  mixmonitor_ds->samp_rate = 8000;
900  mixmonitor_ds->audiohook = &mixmonitor->audiohook;
901  mixmonitor_ds->filename = ast_strdup(mixmonitor->filename);
902  if (!ast_strlen_zero(beep_id)) {
903  mixmonitor_ds->beep_id = ast_strdup(beep_id);
904  }
905  datastore->data = mixmonitor_ds;
906 
907  ast_channel_lock(chan);
908  ast_channel_datastore_add(chan, datastore);
909  ast_channel_unlock(chan);
910 
911  mixmonitor->mixmonitor_ds = mixmonitor_ds;
912  return 0;
913 }
#define ast_channel_lock(chan)
Definition: channel.h:2945
#define ast_autochan_channel_lock(autochan)
Lock the autochan&#39;s channel lock.
Definition: autochan.h:75
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define ast_cond_init(cond, attr)
Definition: lock.h:199
struct ast_channel * chan
Definition: autochan.h:33
struct mixmonitor_ds * mixmonitor_ds
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
Structure for a data store object.
Definition: datastore.h:68
#define NULL
Definition: resample.c:96
static const struct ast_datastore_info mixmonitor_ds_info
unsigned int samp_rate
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:269
#define ast_strlen_zero(foo)
Definition: strings.h:52
ast_cond_t destruction_condition
#define ast_log
Definition: astobj2.c:42
#define LOG_ERROR
Definition: logger.h:285
#define ast_cond_destroy(cond)
Definition: lock.h:200
#define ast_channel_unlock(chan)
Definition: channel.h:2946
ast_mutex_t lock
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
char * filename
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:1814
void * data
Definition: datastore.h:70
struct ast_audiohook * audiohook
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:89
#define ast_autochan_channel_unlock(autochan)
Definition: autochan.h:84
#define ast_mutex_init(pmutex)
Definition: lock.h:184
#define ast_mutex_destroy(a)
Definition: lock.h:186
struct ast_audiohook audiohook
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2390
struct ast_autochan * autochan

◆ start_mixmonitor_callback()

static int start_mixmonitor_callback ( struct ast_channel chan,
const char *  filename,
const char *  options 
)
static

Definition at line 1482 of file app_mixmonitor.c.

References args, ast_strlen_zero, mixmonitor_exec(), and PATH_MAX.

Referenced by set_mixmonitor_methods().

1483 {
1484  char args[PATH_MAX];
1485 
1486  if (ast_strlen_zero(options)) {
1487  snprintf(args, sizeof(args), "%s", filename);
1488  } else {
1489  snprintf(args, sizeof(args), "%s,%s", filename, options);
1490  }
1491 
1492  return mixmonitor_exec(chan, args);
1493 }
const char * args
static int mixmonitor_exec(struct ast_channel *chan, const char *data)
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define PATH_MAX
Definition: asterisk.h:40
static struct test_options options

◆ startmon()

static int startmon ( struct ast_channel chan,
struct ast_audiohook audiohook 
)
static

Definition at line 529 of file app_mixmonitor.c.

References ast_audiohook_attach().

Referenced by launch_monitor_thread().

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:501

◆ stop_mixmonitor_callback()

static int stop_mixmonitor_callback ( struct ast_channel chan,
const char *  mixmonitor_id 
)
static

Definition at line 1495 of file app_mixmonitor.c.

References stop_mixmonitor_full().

Referenced by set_mixmonitor_methods().

1496 {
1497  return stop_mixmonitor_full(chan, mixmonitor_id);
1498 }
static int stop_mixmonitor_full(struct ast_channel *chan, const char *data)

◆ stop_mixmonitor_exec()

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

Definition at line 1331 of file app_mixmonitor.c.

References stop_mixmonitor_full().

Referenced by handle_cli_mixmonitor(), and load_module().

1332 {
1333  stop_mixmonitor_full(chan, data);
1334  return 0;
1335 }
static int stop_mixmonitor_full(struct ast_channel *chan, const char *data)

◆ stop_mixmonitor_full()

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

Definition at line 1257 of file app_mixmonitor.c.

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

1258 {
1259  struct ast_datastore *datastore = NULL;
1260  char *parse = "";
1261  struct mixmonitor_ds *mixmonitor_ds;
1262  const char *beep_id = NULL;
1264 
1266  AST_APP_ARG(mixmonid);
1267  );
1268 
1269  if (!ast_strlen_zero(data)) {
1270  parse = ast_strdupa(data);
1271  }
1272 
1273  AST_STANDARD_APP_ARGS(args, parse);
1274 
1275  ast_channel_lock(chan);
1276 
1278  S_OR(args.mixmonid, NULL));
1279  if (!datastore) {
1280  ast_channel_unlock(chan);
1281  return -1;
1282  }
1283  mixmonitor_ds = datastore->data;
1284 
1285  ast_mutex_lock(&mixmonitor_ds->lock);
1286 
1287  /* closing the filestream here guarantees the file is available to the dialplan
1288  * after calling StopMixMonitor */
1289  mixmonitor_ds_close_fs(mixmonitor_ds);
1290 
1291  /* The mixmonitor thread may be waiting on the audiohook trigger.
1292  * In order to exit from the mixmonitor loop before waiting on channel
1293  * destruction, poke the audiohook trigger. */
1294  if (mixmonitor_ds->audiohook) {
1295  if (mixmonitor_ds->audiohook->status != AST_AUDIOHOOK_STATUS_DONE) {
1297  }
1298  ast_audiohook_lock(mixmonitor_ds->audiohook);
1299  ast_cond_signal(&mixmonitor_ds->audiohook->trigger);
1300  ast_audiohook_unlock(mixmonitor_ds->audiohook);
1301  mixmonitor_ds->audiohook = NULL;
1302  }
1303 
1304  if (!ast_strlen_zero(mixmonitor_ds->beep_id)) {
1305  beep_id = ast_strdupa(mixmonitor_ds->beep_id);
1306  }
1307 
1308  ast_mutex_unlock(&mixmonitor_ds->lock);
1309 
1310  /* Remove the datastore so the monitor thread can exit */
1311  if (!ast_channel_datastore_remove(chan, datastore)) {
1312  ast_datastore_free(datastore);
1313  }
1314 
1315  ast_channel_unlock(chan);
1316 
1317  if (!ast_strlen_zero(beep_id)) {
1318  ast_beep_stop(chan, beep_id);
1319  }
1320 
1323  NULL);
1324  if (message) {
1326  }
1327 
1328  return 0;
1329 }
#define ast_channel_lock(chan)
Definition: channel.h:2945
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
void ast_audiohook_update_status(struct ast_audiohook *audiohook, enum ast_audiohook_status status)
Update audiohook&#39;s status.
Definition: audiohook.c:565
int AST_OPTIONAL_API_NAME() ast_beep_stop(struct ast_channel *chan, const char *beep_id)
#define ast_mutex_lock(a)
Definition: lock.h:187
Structure for a data store object.
Definition: datastore.h:68
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:2404
const char * args
#define NULL
Definition: resample.c:96
static const struct ast_datastore_info mixmonitor_ds_info
#define ast_cond_signal(cond)
Definition: lock.h:201
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_audiohook_unlock(ah)
Unlock an audiohook.
Definition: audiohook.h:300
#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:911
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
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.
static void mixmonitor_ds_close_fs(struct mixmonitor_ds *mixmonitor_ds)
struct stasis_message_type * ast_channel_mixmonitor_stop_type(void)
Message type for stopping mixmonitor on a channel.
#define ast_channel_unlock(chan)
Definition: channel.h:2946
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic&#39;s subscribers.
Definition: stasis.c:1511
ast_mutex_t lock
ast_cond_t trigger
Definition: audiohook.h:105
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 * data
Definition: datastore.h:70
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
struct ast_audiohook * audiohook
enum ast_audiohook_status status
Definition: audiohook.h:107
#define ast_audiohook_lock(ah)
Lock an audiohook.
Definition: audiohook.h:295
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2399
#define ast_mutex_unlock(a)
Definition: lock.h:188
#define AST_APP_ARG(name)
Define an application argument.

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 1666 of file app_mixmonitor.c.

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

Referenced by load_module().

1667 {
1668  int res;
1669 
1673  res |= ast_manager_unregister("MixMonitorMute");
1674  res |= ast_manager_unregister("MixMonitor");
1675  res |= ast_manager_unregister("StopMixMonitor");
1677  res |= clear_mixmonitor_methods();
1678 
1679  return res;
1680 }
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
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.
static const char *const stop_app
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7258
static int clear_mixmonitor_methods(void)
static const char *const app
static struct ast_custom_function mixmonitor_function
static struct ast_cli_entry cli_mixmonitor[]

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 = "30ef0c93b36035ec78c9cfd712d36d9b" , .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .optional_modules = "func_periodic_hook", }
static

Definition at line 1703 of file app_mixmonitor.c.

◆ app

const char* const app = "MixMonitor"
static

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

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

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

◆ 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 441 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 load_module(), and unload_module().