Asterisk - The Open Source Telephony Project GIT-master-57e2743
Loading...
Searching...
No Matches
Data Structures | Macros | Enumerations | Functions | Variables
app_mixmonitor.c File Reference

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

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

Go to the source code of this file.

Data Structures

struct  mixmonitor
 
struct  mixmonitor_ds
 
struct  vm_recipient
 

Macros

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

Enumerations

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

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
static void add_vm_recipients_from_string (struct mixmonitor *mixmonitor, const char *vm_recipients)
 
struct ast_module * AST_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 void fill_frame_buffer (struct ast_frame *source_frame, struct ast_format *target_format, struct ast_format **last_source_format, struct ast_trans_pvt **translator_path, short *dest_buf, size_t dest_buf_size, const char *direction)
 
static int func_mixmonitor_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 
static char * handle_cli_mixmonitor (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static int launch_monitor_thread (struct ast_channel *chan, const char *filename, unsigned int flags, int readvol, int writevol, const char *post_process, const char *filename_write, char *filename_read, const char *uid_channel_var, const char *recipients, const char *beep_id, double skip_seconds)
 
static int load_module (void)
 
static int manager_mixmonitor (struct mansession *s, const struct message *m)
 
static int manager_mute_mixmonitor (struct mansession *s, const struct message *m)
 Mute / unmute a MixMonitor channel.
 
static int manager_stop_mixmonitor (struct mansession *s, const struct message *m)
 
static int mixmonitor_autochan_is_bridged (struct ast_autochan *autochan)
 
static void mixmonitor_ds_close_fs (struct mixmonitor_ds *mixmonitor_ds)
 
static void mixmonitor_ds_destroy (void *data)
 
static void mixmonitor_ds_remove_and_free (struct ast_channel *chan, const char *datastore_id)
 
static int mixmonitor_exec (struct ast_channel *chan, const char *data)
 
static void mixmonitor_free (struct mixmonitor *mixmonitor)
 
static void mixmonitor_save_prep (struct mixmonitor *mixmonitor, char *filename, struct ast_filestream **fs, unsigned int *oflags, int *errflag, char **ext)
 
static void * mixmonitor_thread (void *obj)
 
static int mute_mixmonitor_instance (struct ast_channel *chan, const char *data, enum ast_audiohook_flags flag, int clearmute)
 Mute / unmute an individual MixMonitor by id.
 
static int set_mixmonitor_methods (void)
 
static int setup_mixmonitor_ds (struct mixmonitor *mixmonitor, struct ast_channel *chan, char **datastore_id, const char *beep_id)
 
static int start_mixmonitor_callback (struct ast_channel *chan, const char *filename, const char *options)
 
static int startmon (struct ast_channel *chan, struct ast_audiohook *audiohook)
 
static int stop_mixmonitor_callback (struct ast_channel *chan, const char *mixmonitor_id)
 
static int stop_mixmonitor_exec (struct ast_channel *chan, const char *data)
 
static int stop_mixmonitor_full (struct ast_channel *chan, const char *data)
 
static int unload_module (void)
 

Variables

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

Detailed Description

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

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

Definition in file app_mixmonitor.c.

Macro Definition Documentation

◆ get_volfactor

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

Definition at line 402 of file app_mixmonitor.c.

◆ MIN_SKIP_SECONDS

#define MIN_SKIP_SECONDS   1

Definition at line 404 of file app_mixmonitor.c.

◆ SAMPLES_PER_FRAME

#define SAMPLES_PER_FRAME   160

Definition at line 671 of file app_mixmonitor.c.

Enumeration Type Documentation

◆ mixmonitor_args

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

Definition at line 474 of file app_mixmonitor.c.

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

◆ mixmonitor_flags

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

Definition at line 452 of file app_mixmonitor.c.

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

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 2066 of file app_mixmonitor.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

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

614{
615 /* recipients are in a single string with a format format resembling "mailbox@context/INBOX,mailbox2@context2,mailbox3@context3/Work" */
616 char *cur_mailbox = ast_strdupa(vm_recipients);
617 char *cur_context;
618 char *cur_folder;
619 char *next;
620 int elements_processed = 0;
621
622 while (!ast_strlen_zero(cur_mailbox)) {
623 ast_debug(3, "attempting to add next element %d from %s\n", elements_processed, cur_mailbox);
624 if ((next = strchr(cur_mailbox, ',')) || (next = strchr(cur_mailbox, '&'))) {
625 *(next++) = '\0';
626 }
627
628 if ((cur_folder = strchr(cur_mailbox, '/'))) {
629 *(cur_folder++) = '\0';
630 } else {
631 cur_folder = "INBOX";
632 }
633
634 if ((cur_context = strchr(cur_mailbox, '@'))) {
635 *(cur_context++) = '\0';
636 } else {
637 cur_context = "default";
638 }
639
640 if (!ast_strlen_zero(cur_mailbox) && !ast_strlen_zero(cur_context)) {
641 struct vm_recipient *recipient;
642 if (!(recipient = ast_malloc(sizeof(*recipient)))) {
643 ast_log(LOG_ERROR, "Failed to allocate recipient. Aborting function.\n");
644 return;
645 }
646 ast_copy_string(recipient->context, cur_context, sizeof(recipient->context));
647 ast_copy_string(recipient->mailbox, cur_mailbox, sizeof(recipient->mailbox));
648 ast_copy_string(recipient->folder, cur_folder, sizeof(recipient->folder));
649
650 /* Add to list */
651 ast_verb(4, "Adding %s@%s to recipient list\n", recipient->mailbox, recipient->context);
653 } else {
654 ast_log(LOG_ERROR, "Failed to properly parse extension and/or context from element %d of recipient string: %s\n", elements_processed, vm_recipients);
655 }
656
657 cur_mailbox = next;
658 elements_processed++;
659 }
660}
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
#define ast_malloc(len)
A wrapper for malloc()
Definition astmm.h:191
#define ast_log
Definition astobj2.c:42
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define ast_verb(level,...)
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition strings.h:425
struct mixmonitor::@43 recipient_list
char mailbox[AST_MAX_CONTEXT]
char context[AST_MAX_EXTENSION]
struct vm_recipient::@42 list
struct vm_recipient * next

References ast_copy_string(), ast_debug, AST_LIST_INSERT_HEAD, ast_log, ast_malloc, ast_strdupa, ast_strlen_zero(), ast_verb, vm_recipient::context, vm_recipient::folder, vm_recipient::list, LOG_ERROR, vm_recipient::mailbox, vm_recipient::next, and mixmonitor::recipient_list.

Referenced by launch_monitor_thread().

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 2066 of file app_mixmonitor.c.

◆ clear_mixmonitor_methods()

static int clear_mixmonitor_methods ( void  )
static

Definition at line 2024 of file app_mixmonitor.c.

2025{
2027}
int ast_clear_mixmonitor_methods(void)
Clear the MixMonitor virtual methods table. Use this to cleanup function pointers provided by a modul...
Definition mixmonitor.c:59

References ast_clear_mixmonitor_methods().

Referenced by unload_module().

◆ clear_mixmonitor_recipient_list()

static void clear_mixmonitor_recipient_list ( struct mixmonitor *  mixmonitor)
static

Definition at line 662 of file app_mixmonitor.c.

663{
664 struct vm_recipient *current;
666 /* Clear list element data */
668 }
669}
#define ast_free(a)
Definition astmm.h:180
size_t current
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.

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

Referenced by mixmonitor_free().

◆ copy_to_voicemail()

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

Definition at line 780 of file app_mixmonitor.c.

781{
782 struct vm_recipient *recipient = NULL;
785 ast_log(LOG_ERROR, "Failed to string_field_init, skipping copy_to_voicemail\n");
786 return;
787 }
788
789 /* Copy strings to stringfields that will be used for all recipients */
796 /* and call_priority gets copied too */
797 recording_data.call_priority = mixmonitor->call_priority;
798
799 AST_LIST_TRAVERSE(&mixmonitor->recipient_list, recipient, list) {
800 /* context, mailbox, and folder need to be set per recipient */
804
805 ast_verb(4, "MixMonitor attempting to send voicemail copy to %s@%s\n", recording_data.mailbox,
806 recording_data.context);
808 }
809
810 /* Free the string fields for recording_data before exiting the function. */
812}
const char * ext
Definition http.c:151
int ast_app_copy_recording_to_vm(struct ast_vm_recording_data *vm_rec_data)
param[in] vm_rec_data Contains data needed to make the recording. retval 0 voicemail successfully cre...
Definition main/app.c:596
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define NULL
Definition resample.c:96
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Structure used for ast_copy_recording_to_vm in order to cleanly supply data needed for making the rec...
const ast_string_field recording_file
const ast_string_field call_callerchan
const ast_string_field context
const ast_string_field folder
const ast_string_field call_callerid
const ast_string_field call_context
const ast_string_field recording_ext
const ast_string_field call_extension
const ast_string_field mailbox
const ast_string_field call_callerchan
const ast_string_field call_callerid
const ast_string_field call_context
const ast_string_field call_extension

References ast_app_copy_recording_to_vm(), AST_LIST_TRAVERSE, ast_log, ast_string_field_free_memory, ast_string_field_init, ast_string_field_set, ast_verb, mixmonitor::call_callerchan, ast_vm_recording_data::call_callerchan, mixmonitor::call_callerid, ast_vm_recording_data::call_callerid, mixmonitor::call_context, ast_vm_recording_data::call_context, mixmonitor::call_extension, ast_vm_recording_data::call_extension, mixmonitor::call_priority, vm_recipient::context, ast_vm_recording_data::context, ext, vm_recipient::folder, ast_vm_recording_data::folder, LOG_ERROR, vm_recipient::mailbox, ast_vm_recording_data::mailbox, NULL, mixmonitor::recipient_list, ast_vm_recording_data::recording_ext, and ast_vm_recording_data::recording_file.

Referenced by mixmonitor_thread().

◆ destroy_monitor_audiohook()

static void destroy_monitor_audiohook ( struct mixmonitor *  mixmonitor)
static

Definition at line 584 of file app_mixmonitor.c.

585{
590 }
591 /* kill the audiohook.*/
596}
#define ast_audiohook_lock(ah)
Lock an audiohook.
Definition audiohook.h:316
int ast_audiohook_detach(struct ast_audiohook *audiohook)
Detach audiohook from channel.
Definition audiohook.c:895
int ast_audiohook_destroy(struct ast_audiohook *audiohook)
Destroys an audiohook structure.
Definition audiohook.c:422
#define ast_audiohook_unlock(ah)
Unlock an audiohook.
Definition audiohook.h:321
#define ast_mutex_unlock(a)
Definition lock.h:197
#define ast_mutex_lock(a)
Definition lock.h:196
struct ast_audiohook * audiohook
ast_mutex_t lock
struct ast_audiohook audiohook
struct mixmonitor_ds * mixmonitor_ds

References ast_audiohook_destroy(), ast_audiohook_detach(), ast_audiohook_lock, ast_audiohook_unlock, ast_mutex_lock, ast_mutex_unlock, mixmonitor::audiohook, mixmonitor_ds::audiohook, mixmonitor_ds::lock, mixmonitor::mixmonitor_ds, and NULL.

Referenced by mixmonitor_thread().

◆ filename_parse()

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

Definition at line 1362 of file app_mixmonitor.c.

1363{
1364 char *slash;
1365 char *ext;
1366
1367 ast_assert(len > 0);
1368
1369 if (ast_strlen_zero(filename)) {
1370 ast_log(LOG_WARNING, "No file name was provided for a file save option.\n");
1371 buffer[0] = 0;
1372 return buffer;
1373 }
1374
1375 /* If we don't have an absolute path, make one */
1376 if (*filename != '/') {
1377 char *build = ast_alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(filename) + 3);
1378 sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, filename);
1379 filename = build;
1380 }
1381
1382 ast_copy_string(buffer, filename, len);
1383
1384 /* If the provided filename has a .wav49 extension, we need to convert it to .WAV to
1385 match the behavior of build_filename in main/file.c. Otherwise MIXMONITOR_FILENAME
1386 ends up referring to a file that does not/will not exist */
1387 ext = strrchr(buffer, '.');
1388 if (ext && !strcmp(ext, ".wav49")) {
1389 /* Change to WAV - we know we have at least 6 writeable bytes where 'ext' points,
1390 * so this is safe */
1391 memcpy(ext, ".WAV", sizeof(".WAV"));
1392 }
1393
1394 if ((slash = strrchr(filename, '/'))) {
1395 *slash = '\0';
1396 }
1397 ast_mkdir(filename, 0777);
1398
1399 return buffer;
1400}
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition astmm.h:288
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define LOG_WARNING
const char * ast_config_AST_MONITOR_DIR
Definition options.c:156
#define ast_assert(a)
Definition utils.h:779
int ast_mkdir(const char *path, int mode)
Recursively create directory path.
Definition utils.c:2513

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

Referenced by mixmonitor_exec().

◆ fill_frame_buffer()

static void fill_frame_buffer ( struct ast_frame *  source_frame,
struct ast_format *  target_format,
struct ast_format **  last_source_format,
struct ast_trans_pvt **  translator_path,
short *  dest_buf,
size_t  dest_buf_size,
const char *  direction 
)
static

Definition at line 674 of file app_mixmonitor.c.

681{
682 struct ast_frame *converted_frame = NULL;
683
684 if (!source_frame) {
685 memset(dest_buf, 0, dest_buf_size);
686 return;
687 }
688
689 /*
690 * We only need to worry about translating if the frame format does not match
691 * the expected format of the frame we are writing.
692 */
693 if (ast_format_cmp(target_format, source_frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
694 /*
695 * If the format changed from the last frame or if this is the first frame
696 * that does not match the native format, we need to set up a new
697 * translator path.
698 */
699 if (ast_format_cmp(*last_source_format, source_frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL
700 || !*translator_path) {
701 ast_debug(3, "%s frame format changed from %s to %s, building translator path to %s\n",
702 direction,
703 *last_source_format ? ast_format_get_name(*last_source_format) : "none",
704 ast_format_get_name(source_frame->subclass.format),
705 ast_format_get_name(target_format));
706
707 if (*translator_path) {
709 }
710
711 *translator_path = ast_translator_build_path(target_format, source_frame->subclass.format);
712 }
713
714 if (*translator_path) {
715 converted_frame = ast_translate(*translator_path, source_frame, 0);
716 }
717
718 /*
719 * If creating the translated frame or translator path failed, write silence for this frame. We will
720 * try rebuilding the translator path later if it is still needed.
721 */
722 if (converted_frame) {
723 memcpy(dest_buf, converted_frame->data.ptr, dest_buf_size);
724 ast_frame_free(converted_frame, 1);
725 } else {
726 memset(dest_buf, 0, dest_buf_size);
727 }
728 } else {
729 memcpy(dest_buf, source_frame->data.ptr, dest_buf_size);
730
731 /*
732 * If we are doing native frame copying, we can free the translator path if
733 * it exists. We will create a new one later if needed.
734 */
735 if (*translator_path) {
738 ast_debug(3, "%s frame format changed from %s to %s, translator path no longer needed\n",
739 direction,
740 *last_source_format ? ast_format_get_name(*last_source_format) : "none",
741 ast_format_get_name(source_frame->subclass.format));
742 }
743 }
744
745 *last_source_format = source_frame->subclass.format;
746}
enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
Compare two formats.
Definition format.c:201
@ AST_FORMAT_CMP_NOT_EQUAL
Definition format.h:38
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition format.c:334
direction
void ast_frame_free(struct ast_frame *frame, int cache)
Frees a frame or list of frames.
Definition main/frame.c:176
struct ast_format * format
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
union ast_frame::@237 data
struct ast_frame * ast_translate(struct ast_trans_pvt *tr, struct ast_frame *f, int consume)
translates one or more frames Apply an input frame into the translator and receive zero or one output...
Definition translate.c:623
void ast_translator_free_path(struct ast_trans_pvt *tr)
Frees a translator path Frees the given translator path structure.
Definition translate.c:533
struct ast_trans_pvt * ast_translator_build_path(struct ast_format *dest, struct ast_format *source)
Builds a translator path Build a path (possibly NULL) from source to dest.
Definition translate.c:543

References ast_debug, ast_format_cmp(), AST_FORMAT_CMP_NOT_EQUAL, ast_format_get_name(), ast_frame_free(), ast_translate(), ast_translator_build_path(), ast_translator_free_path(), ast_frame::data, ast_frame_subclass::format, NULL, ast_frame::ptr, and ast_frame::subclass.

Referenced by mixmonitor_thread().

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

1969{
1970 struct ast_datastore *datastore;
1971 struct mixmonitor_ds *ds_data;
1973 AST_APP_ARG(id);
1974 AST_APP_ARG(key);
1975 );
1976
1978
1979 if (ast_strlen_zero(args.id) || ast_strlen_zero(args.key)) {
1980 ast_log(LOG_WARNING, "Not enough arguments provided to %s. "
1981 "An ID and key must be provided\n", cmd);
1982 return -1;
1983 }
1984
1985 ast_channel_lock(chan);
1986 datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, args.id);
1987 ast_channel_unlock(chan);
1988
1989 if (!datastore) {
1990 ast_log(LOG_WARNING, "Could not find MixMonitor with ID %s\n", args.id);
1991 return -1;
1992 }
1993
1994 ds_data = datastore->data;
1995
1996 if (!strcasecmp(args.key, "filename")) {
1997 ast_copy_string(buf, ds_data->filename, len);
1998 } else {
1999 ast_log(LOG_WARNING, "Unrecognized %s option %s\n", cmd, args.key);
2000 return -1;
2001 }
2002 return 0;
2003}
static const struct ast_datastore_info mixmonitor_ds_info
#define ast_channel_lock(chan)
Definition channel.h:2983
#define ast_channel_unlock(chan)
Definition channel.h:2984
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:2390
char buf[BUFSIZE]
Definition eagi_proxy.c:66
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
static struct @523 args
Structure for a data store object.
Definition datastore.h:64
void * data
Definition datastore.h:66

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

◆ handle_cli_mixmonitor()

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

Definition at line 1642 of file app_mixmonitor.c.

1643{
1644 struct ast_channel *chan;
1645 struct ast_datastore *datastore = NULL;
1647
1648 switch (cmd) {
1649 case CLI_INIT:
1650 e->command = "mixmonitor {start|stop|list}";
1651 e->usage =
1652 "Usage: mixmonitor start <chan_name> [args]\n"
1653 " The optional arguments are passed to the MixMonitor application.\n"
1654 " mixmonitor stop <chan_name> [args]\n"
1655 " The optional arguments are passed to the StopMixMonitor application.\n"
1656 " mixmonitor list <chan_name>\n";
1657 return NULL;
1658 case CLI_GENERATE:
1659 return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
1660 }
1661
1662 if (a->argc < 3) {
1663 return CLI_SHOWUSAGE;
1664 }
1665
1666 if (!(chan = ast_channel_get_by_name_prefix(a->argv[2], strlen(a->argv[2])))) {
1667 ast_cli(a->fd, "No channel matching '%s' found.\n", a->argv[2]);
1668 /* Technically this is a failure, but we don't want 2 errors printing out */
1669 return CLI_SUCCESS;
1670 }
1671
1672 if (!strcasecmp(a->argv[1], "start")) {
1673 mixmonitor_exec(chan, (a->argc >= 4) ? a->argv[3] : "");
1674 } else if (!strcasecmp(a->argv[1], "stop")){
1675 stop_mixmonitor_exec(chan, (a->argc >= 4) ? a->argv[3] : "");
1676 } else if (!strcasecmp(a->argv[1], "list")) {
1677 ast_cli(a->fd, "MixMonitor ID\tFile\tReceive File\tTransmit File\n");
1678 ast_cli(a->fd, "=========================================================================\n");
1679 ast_channel_lock(chan);
1680 AST_LIST_TRAVERSE(ast_channel_datastores(chan), datastore, entry) {
1681 if (datastore->info == &mixmonitor_ds_info) {
1682 char *filename = "";
1683 char *filename_read = "";
1684 char *filename_write = "";
1685
1686 mixmonitor_ds = datastore->data;
1687 if (mixmonitor_ds->fs) {
1689 }
1690 if (mixmonitor_ds->fs_read) {
1691 filename_read = mixmonitor_ds->fs_read->filename;
1692 }
1693 if (mixmonitor_ds->fs_write) {
1694 filename_write = mixmonitor_ds->fs_write->filename;
1695 }
1696 ast_cli(a->fd, "%p\t%s\t%s\t%s\n", mixmonitor_ds, filename, filename_read, filename_write);
1697 }
1698 }
1699 ast_channel_unlock(chan);
1700 } else {
1701 chan = ast_channel_unref(chan);
1702 return CLI_SHOWUSAGE;
1703 }
1704
1705 chan = ast_channel_unref(chan);
1706
1707 return CLI_SUCCESS;
1708}
static int mixmonitor_exec(struct ast_channel *chan, const char *data)
static int stop_mixmonitor_exec(struct ast_channel *chan, const char *data)
struct ast_channel * ast_channel_get_by_name_prefix(const char *name, size_t name_len)
Find a channel by a name prefix.
Definition channel.c:1400
#define ast_channel_unref(c)
Decrease channel reference count.
Definition channel.h:3019
struct ast_datastore_list * ast_channel_datastores(struct ast_channel *chan)
#define CLI_SHOWUSAGE
Definition cli.h:45
#define CLI_SUCCESS
Definition cli.h:44
void ast_cli(int fd, const char *fmt,...)
Definition clicompat.c:6
char * ast_complete_channels(const char *line, const char *word, int pos, int state, int rpos)
Command completion for the list of active channels.
Definition main/cli.c:1950
@ CLI_INIT
Definition cli.h:152
@ CLI_GENERATE
Definition cli.h:153
Main Channel structure associated with a channel.
char * command
Definition cli.h:186
const char * usage
Definition cli.h:177
const struct ast_datastore_info * info
Definition datastore.h:67
struct ast_filestream * fs_read
struct ast_filestream * fs_write
struct ast_filestream * fs
static struct test_val a

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

◆ launch_monitor_thread()

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

Definition at line 1203 of file app_mixmonitor.c.

1208{
1209 pthread_t thread;
1210 struct mixmonitor *mixmonitor;
1211 char postprocess2[1024] = "";
1212 char *datastore_id = NULL;
1213
1214 postprocess2[0] = 0;
1215 /* If a post process system command is given attach it to the structure */
1217 char *p1, *p2;
1218
1220 for (p2 = p1; *p2; p2++) {
1221 if (*p2 == '^' && *(p2+1) == '{') {
1222 *p2 = '$';
1223 }
1224 }
1225 ast_channel_lock(chan);
1226 pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1);
1227 ast_channel_unlock(chan);
1228 }
1229
1230 /* Pre-allocate mixmonitor structure and spy */
1231 if (!(mixmonitor = ast_calloc(1, sizeof(*mixmonitor)))) {
1232 return -1;
1233 }
1234
1235 /* Now that the struct has been calloced, go ahead and initialize the string fields. */
1238 return -1;
1239 }
1240
1241 /* Setup the actual spy before creating our thread */
1244 return -1;
1245 }
1246
1247 /* Copy over flags and channel name */
1250 if (!(mixmonitor->autochan = ast_autochan_setup(chan))) {
1252 return -1;
1253 }
1254
1255 if (!ast_strlen_zero(filename)) {
1257 }
1258
1261 }
1262
1265 }
1266
1267 if (setup_mixmonitor_ds(mixmonitor, chan, &datastore_id, beep_id)) {
1270 ast_free(datastore_id);
1271 return -1;
1272 }
1273
1274 if (!ast_strlen_zero(uid_channel_var)) {
1275 if (datastore_id) {
1276 pbx_builtin_setvar_helper(chan, uid_channel_var, datastore_id);
1277 }
1278 }
1279
1281
1282 if (!ast_strlen_zero(postprocess2)) {
1283 mixmonitor->post_process = ast_strdup(postprocess2);
1284 }
1285
1286 if (!ast_strlen_zero(recipients)) {
1287 char callerid[256];
1288
1289 ast_channel_lock(chan);
1290
1291 /* We use the connected line of the invoking channel for caller ID,
1292 * unless we've been told to use the Caller ID.
1293 * The initial use for this relied on Connected Line to get the
1294 * actual number for recording with Digium phones,
1295 * but in generic use the Caller ID is likely what people want.
1296 */
1297
1299 struct ast_party_caller *caller;
1300 caller = ast_channel_caller(chan);
1301 ast_debug(3, "Caller ID = %d - %s : %d - %s\n", caller->id.name.valid,
1302 caller->id.name.str, caller->id.number.valid,
1303 caller->id.number.str);
1304 ast_callerid_merge(callerid, sizeof(callerid),
1305 S_COR(caller->id.name.valid, caller->id.name.str, NULL),
1306 S_COR(caller->id.number.valid, caller->id.number.str, NULL),
1307 "Unknown");
1308 } else {
1311 ast_debug(3, "Connected Line CID = %d - %s : %d - %s\n", connected->id.name.valid,
1312 connected->id.name.str, connected->id.number.valid,
1313 connected->id.number.str);
1314 ast_callerid_merge(callerid, sizeof(callerid),
1315 S_COR(connected->id.name.valid, connected->id.name.str, NULL),
1316 S_COR(connected->id.number.valid, connected->id.number.str, NULL),
1317 "Unknown");
1318 }
1319
1321 ast_string_field_set(mixmonitor, call_extension, ast_channel_exten(chan));
1322 ast_string_field_set(mixmonitor, call_callerchan, ast_channel_name(chan));
1323 ast_string_field_set(mixmonitor, call_callerid, callerid);
1325
1326 ast_channel_unlock(chan);
1327
1329 }
1330
1334 }
1335
1336 if (readvol)
1338 if (writevol)
1340
1341 if (startmon(chan, &mixmonitor->audiohook)) {
1342 ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n",
1344 mixmonitor_ds_remove_and_free(chan, datastore_id);
1345 ast_free(datastore_id);
1349 return -1;
1350 }
1351
1352 mixmonitor->mixmonitor_ds->datastore_id = datastore_id; /* Steal the reference */
1353
1354 /* reference be released at mixmonitor destruction */
1356
1358}
static void mixmonitor_free(struct mixmonitor *mixmonitor)
static void * mixmonitor_thread(void *obj)
static void mixmonitor_ds_remove_and_free(struct ast_channel *chan, const char *datastore_id)
static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel *chan, char **datastore_id, const char *beep_id)
static int startmon(struct ast_channel *chan, struct ast_audiohook *audiohook)
static const char *const mixmonitor_spy_type
static void add_vm_recipients_from_string(struct mixmonitor *mixmonitor, const char *vm_recipients)
pthread_t thread
Definition app_sla.c:335
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
#define ast_calloc(num, len)
A wrapper for calloc()
Definition astmm.h:202
int ast_audiohook_init(struct ast_audiohook *audiohook, enum ast_audiohook_type type, const char *source, enum ast_audiohook_init_flags flags)
Initialize an audiohook structure.
Definition audiohook.c:398
@ AST_AUDIOHOOK_SUBSTITUTE_SILENCE
Definition audiohook.h:68
@ AST_AUDIOHOOK_TRIGGER_SYNC
Definition audiohook.h:59
@ AST_AUDIOHOOK_TYPE_SPY
Definition audiohook.h:36
struct ast_autochan * ast_autochan_setup(struct ast_channel *chan)
set up a new ast_autochan structure
Definition autochan.c:38
void ast_autochan_destroy(struct ast_autochan *autochan)
destroy an ast_autochan structure
Definition autochan.c:64
char * ast_callerid_merge(char *buf, int bufsiz, const char *name, const char *num, const char *unknown)
Definition callerid.c:1273
static int connected
Definition cdr_pgsql.c:73
const char * ast_channel_name(const struct ast_channel *chan)
int ast_channel_priority(const struct ast_channel *chan)
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
const char * ast_channel_context(const struct ast_channel *chan)
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
const char * ast_channel_exten(const struct ast_channel *chan)
ast_callid ast_read_threadstorage_callid(void)
extracts the callid from the thread
Definition logger.c:2287
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
Definition ael_main.c:211
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition strings.h:87
struct ast_audiohook_options options
Definition audiohook.h:119
Caller Party information.
Definition channel.h:420
struct ast_party_id id
Caller party ID.
Definition channel.h:422
Connected Line/Party information.
Definition channel.h:458
struct ast_party_name name
Subscriber name.
Definition channel.h:342
struct ast_party_number number
Subscriber phone number.
Definition channel.h:344
unsigned char valid
TRUE if the name information is valid/present.
Definition channel.h:281
char * str
Subscriber name (Malloced)
Definition channel.h:266
unsigned char valid
TRUE if the number information is valid/present.
Definition channel.h:299
char * str
Subscriber phone number (Malloced)
Definition channel.h:293
char * filename_write
ast_callid callid
struct ast_autochan * autochan
char * post_process
char * filename_read
double skip_seconds
unsigned int flags
#define ast_test_flag(p, flag)
Definition utils.h:64
#define ast_pthread_create_detached_background(a, b, c, d)
Definition utils.h:637
#define ast_set_flag(p, flag)
Definition utils.h:71

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

Referenced by mixmonitor_exec().

◆ load_module()

static int load_module ( void  )
static

Definition at line 2045 of file app_mixmonitor.c.

2046{
2047 int res;
2048
2056 res |= set_mixmonitor_methods();
2057
2058 return res;
2059}
static int manager_stop_mixmonitor(struct mansession *s, const struct message *m)
static struct ast_cli_entry cli_mixmonitor[]
static struct ast_custom_function mixmonitor_function
static int set_mixmonitor_methods(void)
static const char *const app
static int manager_mute_mixmonitor(struct mansession *s, const struct message *m)
Mute / unmute a MixMonitor channel.
static const char *const stop_app
static int manager_mixmonitor(struct mansession *s, const struct message *m)
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition cli.h:265
#define EVENT_FLAG_SYSTEM
Definition manager.h:75
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition manager.h:193
#define EVENT_FLAG_CALL
Definition manager.h:76
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition module.h:640
#define ast_custom_function_register(acf)
Register a custom function.
Definition pbx.h:1563
#define ARRAY_LEN(a)
Definition utils.h:706

References app, ARRAY_LEN, ast_cli_register_multiple, ast_custom_function_register, ast_manager_register_xml, ast_register_application_xml, cli_mixmonitor, EVENT_FLAG_CALL, EVENT_FLAG_SYSTEM, manager_mixmonitor(), manager_mute_mixmonitor(), manager_stop_mixmonitor(), mixmonitor_exec(), mixmonitor_function, set_mixmonitor_methods(), ast_mixmonitor_methods::start, stop_app, and stop_mixmonitor_exec().

◆ manager_mixmonitor()

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

Definition at line 1863 of file app_mixmonitor.c.

1864{
1865 struct ast_channel *c;
1866 const char *name = astman_get_header(m, "Channel");
1867 const char *id = astman_get_header(m, "ActionID");
1868 const char *file = astman_get_header(m, "File");
1869 const char *options = astman_get_header(m, "Options");
1870 const char *command = astman_get_header(m, "Command");
1871 char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
1872 struct ast_flags flags = { 0 };
1873 char *uid_channel_var = NULL;
1874 const char *mixmonitor_id = NULL;
1875 int res;
1876 char args[PATH_MAX];
1877
1878 if (ast_strlen_zero(name)) {
1879 astman_send_error(s, m, "No channel specified");
1880 return AMI_SUCCESS;
1881 }
1882
1884 if (!c) {
1885 astman_send_error(s, m, "No such channel");
1886 return AMI_SUCCESS;
1887 }
1888
1889 if (!ast_strlen_zero(options)) {
1891 }
1892
1893 snprintf(args, sizeof(args), "%s,%s,%s", file, options, command);
1894
1895 res = mixmonitor_exec(c, args);
1896
1898 uid_channel_var = opts[OPT_ARG_UID];
1900 mixmonitor_id = pbx_builtin_getvar_helper(c, uid_channel_var);
1901 mixmonitor_id = ast_strdupa(S_OR(mixmonitor_id, ""));
1903 }
1904
1905 if (res) {
1907 astman_send_error(s, m, "Could not start monitoring channel");
1908 return AMI_SUCCESS;
1909 }
1910
1911 astman_append(s, "Response: Success\r\n");
1912
1913 if (!ast_strlen_zero(id)) {
1914 astman_append(s, "ActionID: %s\r\n", id);
1915 }
1916
1917 if (!ast_strlen_zero(mixmonitor_id)) {
1918 astman_append(s, "MixMonitorID: %s\r\n", mixmonitor_id);
1919 }
1920
1921 astman_append(s, "\r\n");
1922
1924
1925 return AMI_SUCCESS;
1926}
static const struct ast_app_option mixmonitor_opts[128]
#define PATH_MAX
Definition asterisk.h:40
struct ast_channel * ast_channel_get_by_name(const char *search)
Find a channel by name or uniqueid.
Definition channel.c:1417
static const char name[]
Definition format_mp3.c:68
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition manager.c:1921
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition manager.c:1582
void astman_append(struct mansession *s, const char *fmt,...)
Definition manager.c:1842
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:3067
#define AMI_SUCCESS
Definition manager.h:66
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition strings.h:80
Structure used to handle boolean flags.
Definition utils.h:220
unsigned int flags
Definition utils.h:221
static struct test_options options
static struct test_val c

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

Referenced by load_module().

◆ manager_mute_mixmonitor()

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

Mute / unmute a MixMonitor channel.

Definition at line 1755 of file app_mixmonitor.c.

1756{
1757 struct ast_channel *c;
1758 const char *name = astman_get_header(m, "Channel");
1759 const char *id = astman_get_header(m, "ActionID");
1760 const char *state = astman_get_header(m, "State");
1761 const char *direction = astman_get_header(m,"Direction");
1762 const char *mixmonitor_id = astman_get_header(m, "MixMonitorID");
1763 int clearmute = 1, mutedcount = 0;
1766 RAII_VAR(struct ast_json *, stasis_message_blob, NULL, ast_json_unref);
1767
1769 astman_send_error(s, m, "No direction specified. Must be read, write or both");
1770 return AMI_SUCCESS;
1771 }
1772
1773 if (!strcasecmp(direction, "read")) {
1775 } else if (!strcasecmp(direction, "write")) {
1777 } else if (!strcasecmp(direction, "both")) {
1779 } else {
1780 astman_send_error(s, m, "Invalid direction specified. Must be read, write or both");
1781 return AMI_SUCCESS;
1782 }
1783
1784 if (ast_strlen_zero(name)) {
1785 astman_send_error(s, m, "No channel specified");
1786 return AMI_SUCCESS;
1787 }
1788
1789 if (ast_strlen_zero(state)) {
1790 astman_send_error(s, m, "No state specified");
1791 return AMI_SUCCESS;
1792 }
1793
1794 clearmute = ast_false(state);
1795
1797 if (!c) {
1798 astman_send_error(s, m, "No such channel");
1799 return AMI_SUCCESS;
1800 }
1801
1802 if (ast_strlen_zero(mixmonitor_id)) {
1803 mutedcount = ast_audiohook_set_mute_all(c, mixmonitor_spy_type, flag, clearmute);
1804 if (mutedcount < 0) {
1806 astman_send_error(s, m, "Cannot set mute flag");
1807 return AMI_SUCCESS;
1808 }
1809 } else {
1810 if (mute_mixmonitor_instance(c, mixmonitor_id, flag, clearmute)) {
1812 astman_send_error(s, m, "Cannot set mute flag");
1813 return AMI_SUCCESS;
1814 }
1815 mutedcount = 1;
1816 }
1817
1818
1819 stasis_message_blob = ast_json_pack("{s: s, s: b, s: s, s: i}",
1820 "direction", direction,
1821 "state", ast_true(state),
1822 "mixmonitorid", mixmonitor_id,
1823 "count", mutedcount);
1824
1826 ast_channel_mixmonitor_mute_type(), stasis_message_blob);
1827
1828 if (stasis_message) {
1830 }
1831
1832 astman_append(s, "Response: Success\r\n");
1833
1834 if (!ast_strlen_zero(id)) {
1835 astman_append(s, "ActionID: %s\r\n", id);
1836 }
1837
1838 astman_append(s, "\r\n");
1839
1841
1842 return AMI_SUCCESS;
1843}
static int mute_mixmonitor_instance(struct ast_channel *chan, const char *data, enum ast_audiohook_flags flag, int clearmute)
Mute / unmute an individual MixMonitor by id.
#define ao2_cleanup(obj)
Definition astobj2.h:1934
int ast_audiohook_set_mute_all(struct ast_channel *chan, const char *source, enum ast_audiohook_flags flag, int clear)
Mute frames read from or written for all audiohooks on a channel.
Definition audiohook.c:1763
ast_audiohook_flags
Definition audiohook.h:54
@ AST_AUDIOHOOK_MUTE_READ
Definition audiohook.h:64
@ AST_AUDIOHOOK_MUTE_WRITE
Definition audiohook.h:65
struct stasis_topic * ast_channel_topic(struct ast_channel *chan)
A topic which publishes the events for a particular channel.
const char * ast_channel_uniqueid(const struct ast_channel *chan)
long int flag
Definition f2c.h:83
struct stasis_message_type * ast_channel_mixmonitor_mute_type(void)
Message type for muting or unmuting mixmonitor on a channel.
struct stasis_message * ast_channel_blob_create_from_cache(const char *uniqueid, struct stasis_message_type *type, struct ast_json *blob)
Create a ast_channel_blob message, pulling channel state from the cache.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition json.c:73
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition json.c:612
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
Definition stasis.c:1589
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition utils.c:2233
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"....
Definition utils.c:2250
Abstract JSON element (object, array, string, int, ...).
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition utils.h:981

References AMI_SUCCESS, ao2_cleanup, AST_AUDIOHOOK_MUTE_READ, AST_AUDIOHOOK_MUTE_WRITE, ast_audiohook_set_mute_all(), ast_channel_blob_create_from_cache(), ast_channel_get_by_name(), ast_channel_mixmonitor_mute_type(), ast_channel_topic(), ast_channel_uniqueid(), ast_channel_unref, ast_false(), ast_json_pack(), ast_json_unref(), ast_strlen_zero(), ast_true(), astman_append(), astman_get_header(), astman_send_error(), c, mixmonitor_spy_type, mute_mixmonitor_instance(), name, NULL, RAII_VAR, and stasis_publish().

Referenced by load_module().

◆ manager_stop_mixmonitor()

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

Definition at line 1928 of file app_mixmonitor.c.

1929{
1930 struct ast_channel *c;
1931 const char *name = astman_get_header(m, "Channel");
1932 const char *id = astman_get_header(m, "ActionID");
1933 const char *mixmonitor_id = astman_get_header(m, "MixMonitorID");
1934 int res;
1935
1936 if (ast_strlen_zero(name)) {
1937 astman_send_error(s, m, "No channel specified");
1938 return AMI_SUCCESS;
1939 }
1940
1942 if (!c) {
1943 astman_send_error(s, m, "No such channel");
1944 return AMI_SUCCESS;
1945 }
1946
1947 res = stop_mixmonitor_full(c, mixmonitor_id);
1948 if (res) {
1950 astman_send_error(s, m, "Could not stop monitoring channel");
1951 return AMI_SUCCESS;
1952 }
1953
1954 astman_append(s, "Response: Success\r\n");
1955
1956 if (!ast_strlen_zero(id)) {
1957 astman_append(s, "ActionID: %s\r\n", id);
1958 }
1959
1960 astman_append(s, "\r\n");
1961
1963
1964 return AMI_SUCCESS;
1965}
static int stop_mixmonitor_full(struct ast_channel *chan, const char *data)

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

Referenced by load_module().

◆ mixmonitor_autochan_is_bridged()

static int mixmonitor_autochan_is_bridged ( struct ast_autochan *  autochan)
static

Definition at line 843 of file app_mixmonitor.c.

844{
845 int is_bridged;
846
848 is_bridged = ast_channel_is_bridged(autochan->chan);
850 return is_bridged;
851}
#define ast_autochan_channel_lock(autochan)
Lock the autochan's channel lock.
Definition autochan.h:75
#define ast_autochan_channel_unlock(autochan)
Definition autochan.h:84
int ast_channel_is_bridged(const struct ast_channel *chan)
Determine if a channel is in a bridge.
Definition channel.c:10725
struct ast_channel * chan
Definition autochan.h:33

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

Referenced by mixmonitor_thread().

◆ mixmonitor_ds_close_fs()

static void mixmonitor_ds_close_fs ( struct mixmonitor_ds *  mixmonitor_ds)
static

Definition at line 535 of file app_mixmonitor.c.

536{
537 unsigned char quitting = 0;
538
539 if (mixmonitor_ds->fs) {
540 quitting = 1;
543 ast_verb(2, "MixMonitor close filestream (mixed)\n");
544 }
545
546 if (mixmonitor_ds->fs_read) {
547 quitting = 1;
550 ast_verb(2, "MixMonitor close filestream (read)\n");
551 }
552
553 if (mixmonitor_ds->fs_write) {
554 quitting = 1;
557 ast_verb(2, "MixMonitor close filestream (write)\n");
558 }
559
560 if (quitting) {
562 }
563}
int ast_closestream(struct ast_filestream *f)
Closes a stream.
Definition file.c:1200

References ast_closestream(), ast_verb, mixmonitor_ds::fs, mixmonitor_ds::fs_quit, mixmonitor_ds::fs_read, mixmonitor_ds::fs_write, and NULL.

Referenced by mixmonitor_thread(), and stop_mixmonitor_full().

◆ mixmonitor_ds_destroy()

static void mixmonitor_ds_destroy ( void *  data)
static

◆ mixmonitor_ds_remove_and_free()

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

Definition at line 1187 of file app_mixmonitor.c.

1188{
1189 struct ast_datastore *datastore;
1190
1191 ast_channel_lock(chan);
1192
1193 datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, datastore_id);
1194
1195 if (datastore) {
1196 ast_channel_datastore_remove(chan, datastore);
1197 ast_datastore_free(datastore);
1198 }
1199
1200 ast_channel_unlock(chan);
1201}
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition channel.c:2385
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition datastore.c:68

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

Referenced by launch_monitor_thread(), and mixmonitor_thread().

◆ mixmonitor_exec()

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

Definition at line 1402 of file app_mixmonitor.c.

1403{
1404 int x, readvol = 0, writevol = 0;
1405 double skip_seconds = 0.0;
1406 char *filename_read = NULL;
1407 char *filename_write = NULL;
1408 char filename_buffer[1024] = "";
1409 char *uid_channel_var = NULL;
1410 char beep_id[64] = "";
1411
1412 struct ast_flags flags = { 0 };
1413 char *recipients = NULL;
1414 char *parse;
1417 AST_APP_ARG(filename);
1419 AST_APP_ARG(post_process);
1420 );
1421
1422 if (ast_strlen_zero(data)) {
1423 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename or ,t(filename) and/or r(filename)\n");
1424 return -1;
1425 }
1426
1427 parse = ast_strdupa(data);
1428
1430
1431 if (args.options) {
1432 char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
1433
1435
1437 ast_log(LOG_NOTICE, "The synchronization behavior enabled by the 'S' option is now the default"
1438 " and does not need to be specified.\n");
1439 }
1440
1443 ast_log(LOG_WARNING, "No volume level was provided for the heard volume ('v') option.\n");
1444 } else if ((sscanf(opts[OPT_ARG_READVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
1445 ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_READVOLUME]);
1446 } else {
1447 readvol = get_volfactor(x);
1448 }
1449 }
1450
1453 ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n");
1454 } else if ((sscanf(opts[OPT_ARG_WRITEVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
1455 ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_WRITEVOLUME]);
1456 } else {
1457 writevol = get_volfactor(x);
1458 }
1459 }
1460
1462 if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) {
1463 ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n");
1464 } else if ((sscanf(opts[OPT_ARG_VOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
1465 ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]);
1466 } else {
1467 readvol = writevol = get_volfactor(x);
1468 }
1469 }
1470
1473 ast_log(LOG_WARNING, "No voicemail recipients were specified for the vm copy ('m') option.\n");
1474 } else {
1475 recipients = ast_strdupa(opts[OPT_ARG_VMRECIPIENTS]);
1476 }
1477 }
1478
1480 filename_write = ast_strdupa(filename_parse(opts[OPT_ARG_WRITENAME], filename_buffer, sizeof(filename_buffer)));
1481 }
1482
1484 filename_read = ast_strdupa(filename_parse(opts[OPT_ARG_READNAME], filename_buffer, sizeof(filename_buffer)));
1485 }
1486
1488 uid_channel_var = opts[OPT_ARG_UID];
1489 }
1490
1492 const char *interval_str = S_OR(opts[OPT_ARG_BEEP_INTERVAL], "15");
1493 unsigned int interval = 15;
1494
1495 if (sscanf(interval_str, "%30u", &interval) != 1) {
1496 ast_log(LOG_WARNING, "Invalid interval '%s' for periodic beep. Using default of %u\n",
1497 interval_str, interval);
1498 }
1499
1500 if (ast_beep_start(chan, interval, beep_id, sizeof(beep_id))) {
1501 ast_log(LOG_WARNING, "Unable to enable periodic beep, please ensure func_periodic_hook is loaded.\n");
1502 return -1;
1503 }
1504 }
1505
1507 if (ast_strlen_zero(opts[OPT_ARG_SKIP])) {
1508 ast_log(LOG_WARNING, "No skip value provided for the 's' (skip) option; skipping will be ignored as no default exists.\n");
1509 } else {
1510 char *endptr = NULL;
1511 double val = strtod(opts[OPT_ARG_SKIP], &endptr);
1512 if (endptr == opts[OPT_ARG_SKIP] || *endptr != '\0') {
1513 ast_log(LOG_WARNING, "Skip value '%s' is not a valid number; ignoring skip.\n", opts[OPT_ARG_SKIP]);
1514 } else if (val < (double) MIN_SKIP_SECONDS) {
1515 ast_log(LOG_WARNING, "Skip value %.3f is below minimum %d; ignoring skip.\n", val, MIN_SKIP_SECONDS);
1516 } else {
1517 skip_seconds = val;
1518 }
1519 }
1520 }
1521 }
1522 /* If there are no file writing arguments/options for the mix monitor, send a warning message and return -1 */
1523
1525 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n");
1526 return -1;
1527 }
1528
1529 /* If filename exists, try to create directories for it */
1530 if (!(ast_strlen_zero(args.filename))) {
1531 args.filename = ast_strdupa(filename_parse(args.filename, filename_buffer, sizeof(filename_buffer)));
1532 }
1533
1534 pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename);
1535
1536 /* If launch_monitor_thread works, the module reference must not be released until it is finished. */
1538 if (launch_monitor_thread(chan,
1539 args.filename,
1540 flags.flags,
1541 readvol,
1542 writevol,
1543 args.post_process,
1544 filename_write,
1545 filename_read,
1546 uid_channel_var,
1547 recipients,
1548 beep_id,
1549 skip_seconds)) {
1551 }
1552
1555 if (message) {
1557 }
1558
1559 return 0;
1560}
static char * filename_parse(char *filename, char *buffer, size_t len)
#define get_volfactor(x)
#define MIN_SKIP_SECONDS
static int launch_monitor_thread(struct ast_channel *chan, const char *filename, unsigned int flags, int readvol, int writevol, const char *post_process, const char *filename_write, char *filename_read, const char *uid_channel_var, const char *recipients, const char *beep_id, double skip_seconds)
int AST_OPTIONAL_API_NAME() ast_beep_start(struct ast_channel *chan, unsigned int interval, char *beep_id, size_t len)
struct stasis_message_type * ast_channel_mixmonitor_start_type(void)
Message type for starting mixmonitor on a channel.
#define LOG_NOTICE
#define ast_module_unref(mod)
Release a reference to the module.
Definition module.h:483
#define ast_module_ref(mod)
Hold a reference to the module.
Definition module.h:457
struct ast_module * self
Definition module.h:356

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

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

◆ mixmonitor_free()

static void mixmonitor_free ( struct mixmonitor *  mixmonitor)
static

◆ mixmonitor_save_prep()

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

Definition at line 814 of file app_mixmonitor.c.

815{
816 /* Initialize the file if not already done so */
817 char *last_slash = NULL;
818 if (!ast_strlen_zero(filename)) {
819 if (!*fs && !*errflag && !mixmonitor->mixmonitor_ds->fs_quit) {
820 *oflags = O_CREAT | O_WRONLY;
821 *oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC;
822
823 last_slash = strrchr(filename, '/');
824
825 if ((*ext = strrchr(filename, '.')) && (*ext > last_slash)) {
826 **ext = '\0';
827 *ext = *ext + 1;
828 } else {
829 *ext = "raw";
830 }
831
832 if (!(*fs = ast_writefile(filename, *ext, NULL, *oflags, 0, 0666))) {
833 ast_log(LOG_ERROR, "Cannot open %s.%s\n", filename, *ext);
834 *errflag = 1;
835 } else {
836 struct ast_filestream *tmp = *fs;
838 }
839 }
840 }
841}
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:1527
unsigned int ast_format_get_sample_rate(const struct ast_format *format)
Get the sample rate of a media format.
Definition format.c:379
This structure is allocated by file.c in one chunk, together with buf_size and desc_size bytes of mem...
Definition mod_format.h:101
struct ast_format_def * fmt
Definition mod_format.h:103
struct ast_format * format
Definition mod_format.h:48
unsigned int samp_rate
#define MAX(a, b)
Definition utils.h:254

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

Referenced by mixmonitor_thread().

◆ mixmonitor_thread()

static void * mixmonitor_thread ( void *  obj)
static

Definition at line 856 of file app_mixmonitor.c.

857{
858 struct mixmonitor *mixmonitor = obj;
859 char *fs_ext = "";
860 char *fs_read_ext = "";
861 char *fs_write_ext = "";
862
863 struct ast_filestream **fs = NULL;
864 struct ast_filestream **fs_read = NULL;
865 struct ast_filestream **fs_write = NULL;
866
867 struct ast_format *last_format_read = NULL;
868 struct ast_format *last_format_write = NULL;
869 struct ast_trans_pvt *trans_pvt_read = NULL;
870 struct ast_trans_pvt *trans_pvt_write = NULL;
871
872 unsigned int oflags;
873 int errflag = 0;
874 struct ast_format *format_slin;
875
876 struct timeval skip_start = ast_tvnow();
877
878 /* Keep callid association before any log messages */
879 if (mixmonitor->callid) {
881 }
882
884 fs_read = &mixmonitor->mixmonitor_ds->fs_read;
885 fs_write = &mixmonitor->mixmonitor_ds->fs_write;
886
888 mixmonitor_save_prep(mixmonitor, mixmonitor->filename, fs, &oflags, &errflag, &fs_ext);
889 mixmonitor_save_prep(mixmonitor, mixmonitor->filename_read, fs_read, &oflags, &errflag, &fs_read_ext);
890 mixmonitor_save_prep(mixmonitor, mixmonitor->filename_write, fs_write, &oflags, &errflag, &fs_write_ext);
891
893
894 if (errflag) {
895 /* Tear everything down and exit. */
898
900
903
907
911 }
913
916
918 return NULL;
919 }
920
921 ast_verb(2, "Begin MixMonitor Recording %s\n", mixmonitor->name);
922
924
925 if (mixmonitor->skip_seconds > 0.0) {
926 ast_debug(3, "%s skipping initial %.3f seconds\n",
928 }
929
930 /* The audiohook must enter and exit the loop locked */
933 struct ast_frame *fr = NULL;
934 struct ast_frame *fr_read = NULL;
935 struct ast_frame *fr_write = NULL;
936
938 &fr_read, &fr_write))) {
940
942 break;
943 }
944 continue;
945 }
946
947 /* audiohook lock is not required for the next block.
948 * Unlock it, but remember to lock it before looping or exiting */
950
954
955 /* Skip writing audio for the first N seconds */
956 if (mixmonitor->skip_seconds > 0.0) {
957 struct timeval now = ast_tvnow();
958 double elapsed = ast_tvdiff_ms(now, skip_start) / 1000.0;
959
960 if (elapsed < mixmonitor->skip_seconds) {
962 /* Skip this frame and continue */
963 goto frame_cleanup;
964 } else {
965 ast_debug(3, "%s skip period %.3f seconds elapsed; starting to write audio\n",
968 }
969 }
970
971 /* Write out the frame(s) */
972 if ((*fs_read) && (fr_read)) {
973 struct ast_frame *cur;
974
975 for (cur = fr_read; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
976 ast_writestream(*fs_read, cur);
977 }
978 }
979
980 if ((*fs_write) && (fr_write)) {
981 struct ast_frame *cur;
982
983 for (cur = fr_write; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
984 ast_writestream(*fs_write, cur);
985 }
986 }
987
989 /* The 'D' option is set, so mix the frame as an interleaved dual channel frame */
990 int i;
991 /*
992 * We are fed by a call to ast_audiohook_read_frame_all specifying format_slin. However
993 * we may get frames back in a different format. Either way, we we will translate them
994 * to the format with the correct frame size before writing into these buffers.
995 */
996 short read_buf[SAMPLES_PER_FRAME];
998 short stereo_buf[SAMPLES_PER_FRAME * 2];
999 struct ast_frame stereo_frame = {
1001 .datalen = sizeof(stereo_buf),
1003 };
1004
1005 if (fr) {
1006 ast_frame_free(fr, 0);
1007 fr = NULL;
1008 }
1009
1010 /*
1011 * Depending on the input codec's rate (which may change during the call) we may get frames in
1012 * a slin format that does not match the native format_slin of the mixmonitor. In that case
1013 * we need to translate.
1014 */
1015 fill_frame_buffer(fr_read, format_slin, &last_format_read, &trans_pvt_read,
1016 read_buf, sizeof(read_buf), "Read");
1017
1018 fill_frame_buffer(fr_write, format_slin, &last_format_write, &trans_pvt_write,
1019 write_buf, sizeof(write_buf), "Write");
1020
1021 for (i = 0; i < SAMPLES_PER_FRAME; i++) {
1022 stereo_buf[i * 2] = read_buf[i];
1023 stereo_buf[i * 2 + 1] = write_buf[i];
1024 }
1025
1026 stereo_frame.data.ptr = stereo_buf;
1027 stereo_frame.subclass.format = format_slin;
1028
1029 fr = ast_frdup(&stereo_frame);
1030 }
1031
1032 if ((*fs) && (fr)) {
1033 struct ast_frame *cur;
1034
1035 for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
1036 ast_writestream(*fs, cur);
1037 }
1038 }
1040 }
1041
1042frame_cleanup:
1043 /* All done! free it. */
1044 if (fr) {
1045 ast_frame_free(fr, 0);
1046 }
1047 if (fr_read) {
1048 ast_frame_free(fr_read, 0);
1049 }
1050 if (fr_write) {
1051 ast_frame_free(fr_write, 0);
1052 }
1053
1054 fr = NULL;
1055 fr_write = NULL;
1056 fr_read = NULL;
1057
1059 }
1060
1062
1067 }
1068
1070
1071 /* Datastore cleanup. close the filestream and wait for ds destruction */
1076 }
1077
1079
1080 /* Free the translate paths */
1081 if (trans_pvt_read) {
1082 ast_translator_free_path(trans_pvt_read);
1083 trans_pvt_read = NULL;
1084 }
1085 if (trans_pvt_write) {
1086 ast_translator_free_path(trans_pvt_write);
1087 trans_pvt_write = NULL;
1088 }
1089
1090 /* kill the audiohook */
1092
1093 if (mixmonitor->post_process) {
1094 ast_verb(2, "Executing [%s]\n", mixmonitor->post_process);
1096 }
1097
1098 ast_verb(2, "End MixMonitor Recording %s\n", mixmonitor->name);
1099 ast_test_suite_event_notify("MIXMONITOR_END", "File: %s\r\n", mixmonitor->filename);
1100
1102 if (ast_strlen_zero(fs_ext)) {
1103 ast_log(LOG_ERROR, "No file extension set for Mixmonitor %s. Skipping copy to voicemail.\n",
1104 mixmonitor -> name);
1105 } else {
1106 ast_verb(3, "Copying recordings for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
1108 }
1109 if (!ast_strlen_zero(fs_read_ext)) {
1110 ast_verb(3, "Copying read recording for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
1112 }
1113 if (!ast_strlen_zero(fs_write_ext)) {
1114 ast_verb(3, "Copying write recording for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
1116 }
1117 } else {
1118 ast_debug(3, "No recipients to forward monitor to, moving on.\n");
1119 }
1120
1122 ast_debug(3, "Deleting our copies of recording files\n");
1123 if (!ast_strlen_zero(fs_ext)) {
1125 }
1126 if (!ast_strlen_zero(fs_read_ext)) {
1128 }
1129 if (!ast_strlen_zero(fs_write_ext)) {
1131 }
1132 }
1133
1135
1137 return NULL;
1138}
static void destroy_monitor_audiohook(struct mixmonitor *mixmonitor)
static void mixmonitor_save_prep(struct mixmonitor *mixmonitor, char *filename, struct ast_filestream **fs, unsigned int *oflags, int *errflag, char **ext)
static int mixmonitor_autochan_is_bridged(struct ast_autochan *autochan)
static void copy_to_voicemail(struct mixmonitor *mixmonitor, const char *ext, const char *filename)
#define SAMPLES_PER_FRAME
static void mixmonitor_ds_close_fs(struct mixmonitor_ds *mixmonitor_ds)
static void fill_frame_buffer(struct ast_frame *source_frame, struct ast_format *target_format, struct ast_format **last_source_format, struct ast_trans_pvt **translator_path, short *dest_buf, size_t dest_buf_size, const char *direction)
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:786
int ast_audiohook_remove(struct ast_channel *chan, struct ast_audiohook *audiohook)
Remove an audiohook from a specified channel.
Definition audiohook.c:1074
void ast_audiohook_trigger_wait(struct ast_audiohook *audiohook)
Wait for audiohook trigger to be triggered.
Definition audiohook.c:1462
@ AST_AUDIOHOOK_STATUS_RUNNING
Definition audiohook.h:43
void write_buf(int file, char *buffer, int num)
Definition eagi_proxy.c:312
int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
Writes a frame to a stream.
Definition file.c:265
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:1982
int ast_filedelete(const char *filename, const char *fmt)
Deletes a file.
Definition file.c:1230
struct ast_format * ast_format_cache_get_slin_by_rate(unsigned int rate)
Retrieve the best signed linear format given a sample rate.
int ast_safe_system(const char *s)
Safely spawn an OS shell command while closing file descriptors.
Definition extconf.c:827
#define ast_frdup(fr)
Copies a frame.
int ast_callid_threadassoc_add(ast_callid callid)
Adds a known callid to thread storage of the calling thread.
Definition logger.c:2309
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
#define ast_cond_wait(cond, mutex)
Definition lock.h:212
enum ast_audiohook_status status
Definition audiohook.h:108
Definition of a media format.
Definition format.c:43
enum ast_frame_type frametype
Default structure for translators, with the basic fields and buffers, all allocated as part of the sa...
Definition translate.h:213
#define ast_test_suite_event_notify(s, f,...)
Definition test.h:189
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition time.h:159

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

Referenced by launch_monitor_thread().

◆ mute_mixmonitor_instance()

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

Mute / unmute an individual MixMonitor by id.

Definition at line 1711 of file app_mixmonitor.c.

1713{
1714 struct ast_datastore *datastore = NULL;
1715 char *parse = "";
1717
1719 AST_APP_ARG(mixmonid);
1720 );
1721
1722 if (!ast_strlen_zero(data)) {
1723 parse = ast_strdupa(data);
1724 }
1725
1727
1728 ast_channel_lock(chan);
1729
1731 S_OR(args.mixmonid, NULL));
1732 if (!datastore) {
1733 ast_channel_unlock(chan);
1734 return -1;
1735 }
1736 mixmonitor_ds = datastore->data;
1737
1739
1740 if (mixmonitor_ds->audiohook) {
1741 if (clearmute) {
1743 } else {
1745 }
1746 }
1747
1749 ast_channel_unlock(chan);
1750
1751 return 0;
1752}
#define ast_clear_flag(p, flag)
Definition utils.h:78

References args, AST_APP_ARG, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_clear_flag, AST_DECLARE_APP_ARGS, ast_mutex_lock, ast_mutex_unlock, ast_set_flag, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), mixmonitor_ds::audiohook, ast_datastore::data, mixmonitor_ds::lock, mixmonitor_ds_info, NULL, and S_OR.

Referenced by manager_mute_mixmonitor().

◆ set_mixmonitor_methods()

static int set_mixmonitor_methods ( void  )
static

Definition at line 2014 of file app_mixmonitor.c.

2015{
2019 };
2020
2022}
static int start_mixmonitor_callback(struct ast_channel *chan, const char *filename, const char *options)
static int stop_mixmonitor_callback(struct ast_channel *chan, const char *mixmonitor_id)
static struct ast_mixmonitor_methods mixmonitor_methods
Definition mixmonitor.c:40
int ast_set_mixmonitor_methods(struct ast_mixmonitor_methods *vmethod_table)
Setup MixMonitor virtual methods table. Use this to provide the MixMonitor functionality from a loada...
Definition mixmonitor.c:43
MixMonitor virtual methods table definition.
Definition mixmonitor.h:58
ast_mixmonitor_start_fn start
Definition mixmonitor.h:59

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

Referenced by load_module().

◆ setup_mixmonitor_ds()

static int setup_mixmonitor_ds ( struct mixmonitor *  mixmonitor,
struct ast_channel *  chan,
char **  datastore_id,
const char *  beep_id 
)
static

Definition at line 1140 of file app_mixmonitor.c.

1141{
1142 struct ast_datastore *datastore = NULL;
1144
1145 if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) {
1146 return -1;
1147 }
1148
1149 if (ast_asprintf(datastore_id, "%p", mixmonitor_ds) == -1) {
1150 ast_log(LOG_ERROR, "Failed to allocate memory for MixMonitor ID.\n");
1152 return -1;
1153 }
1154
1157
1158 if (!(datastore = ast_datastore_alloc(&mixmonitor_ds_info, *datastore_id))) {
1162 return -1;
1163 }
1164
1169 }
1170
1171 mixmonitor_ds->samp_rate = 8000;
1174 if (!ast_strlen_zero(beep_id)) {
1176 }
1177 datastore->data = mixmonitor_ds;
1178
1179 ast_channel_lock(chan);
1180 ast_channel_datastore_add(chan, datastore);
1181 ast_channel_unlock(chan);
1182
1184 return 0;
1185}
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition astmm.h:267
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition channel.c:2376
#define ast_datastore_alloc(info, uid)
Definition datastore.h:85
#define ast_cond_init(cond, attr)
Definition lock.h:208
#define ast_mutex_init(pmutex)
Definition lock.h:193

References ast_asprintf, ast_autochan_channel_lock, ast_autochan_channel_unlock, ast_calloc, ast_channel_datastore_add(), ast_channel_lock, ast_channel_unlock, ast_cond_destroy, ast_cond_init, ast_datastore_alloc, ast_free, ast_log, ast_mutex_destroy, ast_mutex_init, ast_strdup, ast_stream_and_wait(), ast_strlen_zero(), ast_test_flag, mixmonitor::audiohook, mixmonitor_ds::audiohook, mixmonitor::autochan, mixmonitor_ds::beep_id, ast_autochan::chan, ast_datastore::data, mixmonitor_ds::datastore_id, mixmonitor_ds::destruction_condition, mixmonitor::filename, mixmonitor_ds::filename, mixmonitor_ds::lock, LOG_ERROR, mixmonitor::mixmonitor_ds, mixmonitor_ds_info, MUXFLAG_BEEP_START, NULL, and mixmonitor_ds::samp_rate.

Referenced by launch_monitor_thread().

◆ start_mixmonitor_callback()

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

Definition at line 1845 of file app_mixmonitor.c.

1846{
1847 char args[PATH_MAX];
1848
1849 if (ast_strlen_zero(options)) {
1850 snprintf(args, sizeof(args), "%s", filename);
1851 } else {
1852 snprintf(args, sizeof(args), "%s,%s", filename, options);
1853 }
1854
1855 return mixmonitor_exec(chan, args);
1856}

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

Referenced by set_mixmonitor_methods().

◆ startmon()

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

Definition at line 598 of file app_mixmonitor.c.

599{
600 if (!chan) {
601 return -1;
602 }
603
604 return ast_audiohook_attach(chan, audiohook);
605}
int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
Attach audiohook to channel.
Definition audiohook.c:819

References ast_audiohook_attach().

Referenced by launch_monitor_thread().

◆ stop_mixmonitor_callback()

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

Definition at line 1858 of file app_mixmonitor.c.

1859{
1860 return stop_mixmonitor_full(chan, mixmonitor_id);
1861}

References stop_mixmonitor_full().

Referenced by set_mixmonitor_methods().

◆ stop_mixmonitor_exec()

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

Definition at line 1636 of file app_mixmonitor.c.

1637{
1638 stop_mixmonitor_full(chan, data);
1639 return 0;
1640}

References stop_mixmonitor_full().

Referenced by handle_cli_mixmonitor(), and load_module().

◆ stop_mixmonitor_full()

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

Definition at line 1562 of file app_mixmonitor.c.

1563{
1564 struct ast_datastore *datastore = NULL;
1565 char *parse = "";
1567 const char *beep_id = NULL;
1569
1571 AST_APP_ARG(mixmonid);
1572 );
1573
1574 if (!ast_strlen_zero(data)) {
1575 parse = ast_strdupa(data);
1576 }
1577
1579
1580 ast_channel_lock(chan);
1581
1583 S_OR(args.mixmonid, NULL));
1584 if (!datastore) {
1585 ast_channel_unlock(chan);
1586 return -1;
1587 }
1588 mixmonitor_ds = datastore->data;
1589
1591
1592 /* closing the filestream here guarantees the file is available to the dialplan
1593 * after calling StopMixMonitor */
1595
1596 /* The mixmonitor thread may be waiting on the audiohook trigger.
1597 * In order to exit from the mixmonitor loop before waiting on channel
1598 * destruction, poke the audiohook trigger. */
1599 if (mixmonitor_ds->audiohook) {
1602 }
1607 }
1608
1611 }
1612
1614
1615 /* Remove the datastore so the monitor thread can exit */
1616 if (!ast_channel_datastore_remove(chan, datastore)) {
1617 ast_datastore_free(datastore);
1618 }
1619
1620 ast_channel_unlock(chan);
1621
1622 if (!ast_strlen_zero(beep_id)) {
1623 ast_beep_stop(chan, beep_id);
1624 }
1625
1628 NULL);
1629 if (message) {
1631 }
1632
1633 return 0;
1634}
void ast_audiohook_update_status(struct ast_audiohook *audiohook, enum ast_audiohook_status status)
Update audiohook's status.
Definition audiohook.c:885
@ AST_AUDIOHOOK_STATUS_DONE
Definition audiohook.h:45
@ AST_AUDIOHOOK_STATUS_SHUTDOWN
Definition audiohook.h:44
int AST_OPTIONAL_API_NAME() ast_beep_stop(struct ast_channel *chan, const char *beep_id)
struct stasis_message_type * ast_channel_mixmonitor_stop_type(void)
Message type for stopping mixmonitor on a channel.
ast_cond_t trigger
Definition audiohook.h:106

References ao2_cleanup, args, AST_APP_ARG, ast_audiohook_lock, AST_AUDIOHOOK_STATUS_DONE, AST_AUDIOHOOK_STATUS_SHUTDOWN, ast_audiohook_unlock, ast_audiohook_update_status(), ast_beep_stop(), ast_channel_blob_create_from_cache(), ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_mixmonitor_stop_type(), ast_channel_topic(), ast_channel_uniqueid(), ast_channel_unlock, ast_cond_signal, ast_datastore_free(), AST_DECLARE_APP_ARGS, ast_mutex_lock, ast_mutex_unlock, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), mixmonitor_ds::audiohook, mixmonitor_ds::beep_id, ast_datastore::data, mixmonitor_ds::lock, mixmonitor_ds_close_fs(), mixmonitor_ds_info, NULL, RAII_VAR, S_OR, stasis_publish(), ast_audiohook::status, and ast_audiohook::trigger.

Referenced by manager_stop_mixmonitor(), stop_mixmonitor_callback(), and stop_mixmonitor_exec().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 2029 of file app_mixmonitor.c.

2030{
2031 int res;
2032
2036 res |= ast_manager_unregister("MixMonitorMute");
2037 res |= ast_manager_unregister("MixMonitor");
2038 res |= ast_manager_unregister("StopMixMonitor");
2040 res |= clear_mixmonitor_methods();
2041
2042 return res;
2043}
void ast_cli_unregister_multiple(void)
Definition ael_main.c:408
static int clear_mixmonitor_methods(void)
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition manager.c:7782
int ast_unregister_application(const char *app)
Unregister an application.
Definition pbx_app.c:404
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.

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

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Mixed Audio Monitoring Application" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .optional_modules = "func_periodic_hook", }
static

Definition at line 2066 of file app_mixmonitor.c.

◆ app

const char* const app = "MixMonitor"
static

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

2010 {
2011 AST_CLI_DEFINE(handle_cli_mixmonitor, "Execute a MixMonitor command")
2012};
#define AST_CLI_DEFINE(fn, txt,...)
Definition cli.h:197

Referenced by load_module(), and unload_module().

◆ mixmonitor_ds_info

const struct ast_datastore_info mixmonitor_ds_info
static
Initial value:
= {
.type = "mixmonitor",
}
static void mixmonitor_ds_destroy(void *data)

Definition at line 579 of file app_mixmonitor.c.

579 {
580 .type = "mixmonitor",
581 .destroy = mixmonitor_ds_destroy,
582};

Referenced by func_mixmonitor_read(), handle_cli_mixmonitor(), mixmonitor_ds_remove_and_free(), mute_mixmonitor_instance(), setup_mixmonitor_ds(), and stop_mixmonitor_full().

◆ mixmonitor_function

struct ast_custom_function mixmonitor_function
static
Initial value:
= {
.name = "MIXMONITOR",
}
static int func_mixmonitor_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)

Definition at line 2005 of file app_mixmonitor.c.

2005 {
2006 .name = "MIXMONITOR",
2007 .read = func_mixmonitor_read,
2008};

Referenced by load_module(), and unload_module().

◆ mixmonitor_opts

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

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

Referenced by load_module(), and unload_module().