Channel monitoring. More...
#include "asterisk/channel.h"

Go to the source code of this file.
Data Structures | |
| struct | ast_channel_monitor |
Defines | |
| #define | X_JOIN 4 |
| #define | X_REC_IN 1 |
| #define | X_REC_OUT 2 |
Enumerations | |
| enum | AST_MONITORING_STATE { AST_MONITOR_RUNNING, AST_MONITOR_PAUSED } |
Functions | |
| int | ast_monitor_change_fname (struct ast_channel *chan, const char *fname_base, int need_lock) attribute_weak |
| Change monitored filename of channel. | |
| int | ast_monitor_pause (struct ast_channel *chan) attribute_weak |
| Pause monitoring of channel. | |
| void | ast_monitor_setjoinfiles (struct ast_channel *chan, int turnon) attribute_weak |
| int | ast_monitor_start (struct ast_channel *chan, const char *format_spec, const char *fname_base, int need_lock, int stream_action) attribute_weak |
| Start monitoring a channel. | |
| int | ast_monitor_stop (struct ast_channel *chan, int need_lock) attribute_weak |
| Stop monitoring channel. | |
| int | ast_monitor_unpause (struct ast_channel *chan) attribute_weak |
| Unpause monitoring of channel. | |
Channel monitoring.
Definition in file monitor.h.
| #define X_JOIN 4 |
Definition at line 36 of file monitor.h.
Referenced by start_monitor_exec().
| #define X_REC_IN 1 |
Definition at line 34 of file monitor.h.
Referenced by __agent_start_monitoring(), ast_monitor_start(), start_monitor_action(), start_monitor_exec(), and try_calling().
| #define X_REC_OUT 2 |
Definition at line 35 of file monitor.h.
Referenced by __agent_start_monitoring(), ast_monitor_start(), start_monitor_action(), start_monitor_exec(), and try_calling().
| enum AST_MONITORING_STATE |
Definition at line 28 of file monitor.h.
00028 { 00029 AST_MONITOR_RUNNING, 00030 AST_MONITOR_PAUSED 00031 };
| int ast_monitor_change_fname | ( | struct ast_channel * | chan, | |
| const char * | fname_base, | |||
| int | need_lock | |||
| ) |
Change monitored filename of channel.
| chan | ||
| fname_base | new filename | |
| need_lock |
| 0 | on success. | |
| -1 | on failure. |
Remember, also, that we're using the basename of the file (i.e. the file without the format suffix), so it does not already exist and we aren't interfering with the recording itself.
Definition at line 414 of file res_monitor.c.
References ast_config_AST_MONITOR_DIR, ast_copy_string(), ast_debug, ast_log(), ast_mkdir(), ast_strdupa, ast_strlen_zero(), errno, ast_channel_monitor::filename_base, ast_channel_monitor::filename_changed, LOCK_IF_NEEDED, LOG_ERROR, LOG_WARNING, ast_channel::monitor, name, and UNLOCK_IF_NEEDED.
Referenced by change_monitor_action(), change_monitor_exec(), start_monitor_action(), and start_monitor_exec().
00415 { 00416 if (ast_strlen_zero(fname_base)) { 00417 ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to null\n", chan->name); 00418 return -1; 00419 } 00420 00421 LOCK_IF_NEEDED(chan, need_lock); 00422 00423 if (chan->monitor) { 00424 int directory = strchr(fname_base, '/') ? 1 : 0; 00425 const char *absolute = *fname_base == '/' ? "" : ast_config_AST_MONITOR_DIR; 00426 char tmpstring[sizeof(chan->monitor->filename_base)] = ""; 00427 int i, fd[2] = { -1, -1 }, doexit = 0; 00428 00429 /* before continuing, see if we're trying to rename the file to itself... */ 00430 snprintf(tmpstring, sizeof(tmpstring), "%s/%s", absolute, fname_base); 00431 00432 /*!\note We cannot just compare filenames, due to symlinks, relative 00433 * paths, and other possible filesystem issues. We could use 00434 * realpath(3), but its use is discouraged. However, if we try to 00435 * create the same file from two different paths, the second will 00436 * fail, and so we have our notification that the filenames point to 00437 * the same path. 00438 * 00439 * Remember, also, that we're using the basename of the file (i.e. 00440 * the file without the format suffix), so it does not already exist 00441 * and we aren't interfering with the recording itself. 00442 */ 00443 ast_debug(2, "comparing tmpstring %s to filename_base %s\n", tmpstring, chan->monitor->filename_base); 00444 00445 if ((fd[0] = open(tmpstring, O_CREAT | O_WRONLY, 0644)) < 0 || 00446 (fd[1] = open(chan->monitor->filename_base, O_CREAT | O_EXCL | O_WRONLY, 0644)) < 0) { 00447 if (fd[0] < 0) { 00448 ast_log(LOG_ERROR, "Unable to compare filenames: %s\n", strerror(errno)); 00449 } else { 00450 ast_debug(2, "No need to rename monitor filename to itself\n"); 00451 } 00452 doexit = 1; 00453 } 00454 00455 /* Cleanup temporary files */ 00456 for (i = 0; i < 2; i++) { 00457 if (fd[i] >= 0) { 00458 while (close(fd[i]) < 0 && errno == EINTR); 00459 } 00460 } 00461 unlink(tmpstring); 00462 unlink(chan->monitor->filename_base); 00463 00464 if (doexit) { 00465 UNLOCK_IF_NEEDED(chan, need_lock); 00466 return 0; 00467 } 00468 00469 /* try creating the directory just in case it doesn't exist */ 00470 if (directory) { 00471 char *name = ast_strdupa(fname_base); 00472 ast_mkdir(dirname(name), 0777); 00473 } 00474 00475 ast_copy_string(chan->monitor->filename_base, tmpstring, sizeof(chan->monitor->filename_base)); 00476 chan->monitor->filename_changed = 1; 00477 } else { 00478 ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to %s, monitoring not started\n", chan->name, fname_base); 00479 } 00480 00481 UNLOCK_IF_NEEDED(chan, need_lock); 00482 00483 return 0; 00484 }
| int ast_monitor_pause | ( | struct ast_channel * | chan | ) |
Pause monitoring of channel.
Definition at line 383 of file res_monitor.c.
References AST_MONITOR_PAUSED, and ast_monitor_set_state().
Referenced by do_pause_or_unpause(), and pause_monitor_exec().
00384 { 00385 return ast_monitor_set_state(chan, AST_MONITOR_PAUSED); 00386 }
| void ast_monitor_setjoinfiles | ( | struct ast_channel * | chan, | |
| int | turnon | |||
| ) |
Definition at line 715 of file res_monitor.c.
References ast_channel_monitor::joinfiles, and ast_channel::monitor.
Referenced by __agent_start_monitoring(), start_monitor_action(), start_monitor_exec(), and try_calling().
| int ast_monitor_start | ( | struct ast_channel * | chan, | |
| const char * | format_spec, | |||
| const char * | fname_base, | |||
| int | need_lock, | |||
| int | stream_action | |||
| ) |
Start monitoring a channel.
| chan | ast_channel struct to record | |
| format_spec | file format to use for recording | |
| fname_base | filename base to record to | |
| need_lock | whether to lock the channel mutex | |
| stream_action | whether to record the input and/or output streams. X_REC_IN | X_REC_OUT is most often used Creates the file to record, if no format is specified it assumes WAV It also sets channel variable __MONITORED=yes |
| 0 | on success | |
| -1 | on failure |
Definition at line 147 of file res_monitor.c.
References ast_calloc, ast_closestream(), ast_config_AST_MONITOR_DIR, ast_debug, AST_FILE_MODE, ast_filedelete(), ast_fileexists(), ast_free, ast_log(), ast_mkdir(), AST_MONITOR_RUNNING, ast_monitor_set_state(), ast_monitor_stop(), ast_mutex_lock(), ast_mutex_unlock(), ast_strdup, ast_strdupa, ast_strlen_zero(), ast_writefile(), EVENT_FLAG_CALL, ast_channel_monitor::filename_base, ast_channel_monitor::filename_changed, FILENAME_MAX, ast_channel_monitor::format, LOCK_IF_NEEDED, LOG_WARNING, manager_event, monitor, ast_channel::monitor, monitorlock, name, pbx_builtin_setvar_helper(), ast_channel_monitor::read_filename, ast_channel_monitor::read_stream, ast_channel_monitor::stop, UNLOCK_IF_NEEDED, ast_channel_monitor::write_filename, ast_channel_monitor::write_stream, X_REC_IN, and X_REC_OUT.
Referenced by __agent_start_monitoring(), start_monitor_action(), start_monitor_exec(), and try_calling().
00149 { 00150 int res = 0; 00151 00152 LOCK_IF_NEEDED(chan, need_lock); 00153 00154 if (!(chan->monitor)) { 00155 struct ast_channel_monitor *monitor; 00156 char *channel_name, *p; 00157 00158 /* Create monitoring directory if needed */ 00159 ast_mkdir(ast_config_AST_MONITOR_DIR, 0777); 00160 00161 if (!(monitor = ast_calloc(1, sizeof(*monitor)))) { 00162 UNLOCK_IF_NEEDED(chan, need_lock); 00163 return -1; 00164 } 00165 00166 /* Determine file names */ 00167 if (!ast_strlen_zero(fname_base)) { 00168 int directory = strchr(fname_base, '/') ? 1 : 0; 00169 const char *absolute = *fname_base == '/' ? "" : ast_config_AST_MONITOR_DIR; 00170 00171 snprintf(monitor->read_filename, FILENAME_MAX, "%s/%s-in", 00172 absolute, fname_base); 00173 snprintf(monitor->write_filename, FILENAME_MAX, "%s/%s-out", 00174 absolute, fname_base); 00175 snprintf(monitor->filename_base, FILENAME_MAX, "%s/%s", 00176 absolute, fname_base); 00177 00178 /* try creating the directory just in case it doesn't exist */ 00179 if (directory) { 00180 char *name = ast_strdupa(monitor->filename_base); 00181 ast_mkdir(dirname(name), 0777); 00182 } 00183 } else { 00184 ast_mutex_lock(&monitorlock); 00185 snprintf(monitor->read_filename, FILENAME_MAX, "%s/audio-in-%ld", 00186 ast_config_AST_MONITOR_DIR, seq); 00187 snprintf(monitor->write_filename, FILENAME_MAX, "%s/audio-out-%ld", 00188 ast_config_AST_MONITOR_DIR, seq); 00189 seq++; 00190 ast_mutex_unlock(&monitorlock); 00191 00192 channel_name = ast_strdupa(chan->name); 00193 while ((p = strchr(channel_name, '/'))) { 00194 *p = '-'; 00195 } 00196 snprintf(monitor->filename_base, FILENAME_MAX, "%s/%d-%s", 00197 ast_config_AST_MONITOR_DIR, (int)time(NULL), channel_name); 00198 monitor->filename_changed = 1; 00199 } 00200 00201 monitor->stop = ast_monitor_stop; 00202 00203 /* Determine file format */ 00204 if (!ast_strlen_zero(format_spec)) { 00205 monitor->format = ast_strdup(format_spec); 00206 } else { 00207 monitor->format = ast_strdup("wav"); 00208 } 00209 00210 /* open files */ 00211 if (stream_action & X_REC_IN) { 00212 if (ast_fileexists(monitor->read_filename, NULL, NULL) > 0) 00213 ast_filedelete(monitor->read_filename, NULL); 00214 if (!(monitor->read_stream = ast_writefile(monitor->read_filename, 00215 monitor->format, NULL, 00216 O_CREAT|O_TRUNC|O_WRONLY, 0, AST_FILE_MODE))) { 00217 ast_log(LOG_WARNING, "Could not create file %s\n", 00218 monitor->read_filename); 00219 ast_free(monitor); 00220 UNLOCK_IF_NEEDED(chan, need_lock); 00221 return -1; 00222 } 00223 } else 00224 monitor->read_stream = NULL; 00225 00226 if (stream_action & X_REC_OUT) { 00227 if (ast_fileexists(monitor->write_filename, NULL, NULL) > 0) { 00228 ast_filedelete(monitor->write_filename, NULL); 00229 } 00230 if (!(monitor->write_stream = ast_writefile(monitor->write_filename, 00231 monitor->format, NULL, 00232 O_CREAT|O_TRUNC|O_WRONLY, 0, AST_FILE_MODE))) { 00233 ast_log(LOG_WARNING, "Could not create file %s\n", 00234 monitor->write_filename); 00235 ast_closestream(monitor->read_stream); 00236 ast_free(monitor); 00237 UNLOCK_IF_NEEDED(chan, need_lock); 00238 return -1; 00239 } 00240 } else 00241 monitor->write_stream = NULL; 00242 00243 chan->monitor = monitor; 00244 ast_monitor_set_state(chan, AST_MONITOR_RUNNING); 00245 /* so we know this call has been monitored in case we need to bill for it or something */ 00246 pbx_builtin_setvar_helper(chan, "__MONITORED","true"); 00247 00248 manager_event(EVENT_FLAG_CALL, "MonitorStart", 00249 "Channel: %s\r\n" 00250 "Uniqueid: %s\r\n", 00251 chan->name, 00252 chan->uniqueid 00253 ); 00254 } else { 00255 ast_debug(1,"Cannot start monitoring %s, already monitored\n", chan->name); 00256 res = -1; 00257 } 00258 00259 UNLOCK_IF_NEEDED(chan, need_lock); 00260 00261 return res; 00262 }
| int ast_monitor_stop | ( | struct ast_channel * | chan, | |
| int | need_lock | |||
| ) |
Stop monitoring channel.
| chan | ||
| need_lock | Stop the recording, close any open streams, mix in/out channels if required |
Definition at line 290 of file res_monitor.c.
References ast_closestream(), ast_config_AST_MONITOR_DIR, ast_copy_string(), ast_debug, ast_filedelete(), ast_fileexists(), ast_filerename(), ast_free, ast_log(), ast_safe_system(), ast_strlen_zero(), dir, EVENT_FLAG_CALL, ast_channel_monitor::filename_base, ast_channel_monitor::filename_changed, FILENAME_MAX, format, ast_channel_monitor::format, get_soxmix_format(), ast_channel_monitor::joinfiles, LOCK_IF_NEEDED, LOG_WARNING, manager_event, ast_channel::monitor, name, pbx_builtin_getvar_helper(), ast_channel_monitor::read_filename, ast_channel_monitor::read_stream, UNLOCK_IF_NEEDED, ast_channel_monitor::write_filename, and ast_channel_monitor::write_stream.
Referenced by ast_monitor_start(), stop_monitor_action(), and stop_monitor_exec().
00291 { 00292 int delfiles = 0; 00293 00294 LOCK_IF_NEEDED(chan, need_lock); 00295 00296 if (chan->monitor) { 00297 char filename[ FILENAME_MAX ]; 00298 00299 if (chan->monitor->read_stream) { 00300 ast_closestream(chan->monitor->read_stream); 00301 } 00302 if (chan->monitor->write_stream) { 00303 ast_closestream(chan->monitor->write_stream); 00304 } 00305 00306 if (chan->monitor->filename_changed && !ast_strlen_zero(chan->monitor->filename_base)) { 00307 if (ast_fileexists(chan->monitor->read_filename,NULL,NULL) > 0) { 00308 snprintf(filename, FILENAME_MAX, "%s-in", chan->monitor->filename_base); 00309 if (ast_fileexists(filename, NULL, NULL) > 0) { 00310 ast_filedelete(filename, NULL); 00311 } 00312 ast_filerename(chan->monitor->read_filename, filename, chan->monitor->format); 00313 } else { 00314 ast_log(LOG_WARNING, "File %s not found\n", chan->monitor->read_filename); 00315 } 00316 00317 if (ast_fileexists(chan->monitor->write_filename,NULL,NULL) > 0) { 00318 snprintf(filename, FILENAME_MAX, "%s-out", chan->monitor->filename_base); 00319 if (ast_fileexists(filename, NULL, NULL) > 0) { 00320 ast_filedelete(filename, NULL); 00321 } 00322 ast_filerename(chan->monitor->write_filename, filename, chan->monitor->format); 00323 } else { 00324 ast_log(LOG_WARNING, "File %s not found\n", chan->monitor->write_filename); 00325 } 00326 } 00327 00328 if (chan->monitor->joinfiles && !ast_strlen_zero(chan->monitor->filename_base)) { 00329 char tmp[1024]; 00330 char tmp2[1024]; 00331 const char *format = !strcasecmp(chan->monitor->format,"wav49") ? "WAV" : chan->monitor->format; 00332 char *name = chan->monitor->filename_base; 00333 int directory = strchr(name, '/') ? 1 : 0; 00334 const char *dir = directory ? "" : ast_config_AST_MONITOR_DIR; 00335 const char *execute, *execute_args; 00336 const char *absolute = *name == '/' ? "" : "/"; 00337 00338 /* Set the execute application */ 00339 execute = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC"); 00340 if (ast_strlen_zero(execute)) { 00341 #ifdef HAVE_SOXMIX 00342 execute = "nice -n 19 soxmix"; 00343 #else 00344 execute = "nice -n 19 sox -m"; 00345 #endif 00346 format = get_soxmix_format(format); 00347 delfiles = 1; 00348 } 00349 execute_args = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC_ARGS"); 00350 if (ast_strlen_zero(execute_args)) { 00351 execute_args = ""; 00352 } 00353 00354 snprintf(tmp, sizeof(tmp), "%s \"%s%s%s-in.%s\" \"%s%s%s-out.%s\" \"%s%s%s.%s\" %s &", execute, dir, absolute, name, format, dir, absolute, name, format, dir, absolute, name, format,execute_args); 00355 if (delfiles) { 00356 snprintf(tmp2,sizeof(tmp2), "( %s& rm -f \"%s%s%s-\"* ) &",tmp, dir, absolute, name); /* remove legs when done mixing */ 00357 ast_copy_string(tmp, tmp2, sizeof(tmp)); 00358 } 00359 ast_debug(1,"monitor executing %s\n",tmp); 00360 if (ast_safe_system(tmp) == -1) 00361 ast_log(LOG_WARNING, "Execute of %s failed.\n",tmp); 00362 } 00363 00364 ast_free(chan->monitor->format); 00365 ast_free(chan->monitor); 00366 chan->monitor = NULL; 00367 00368 manager_event(EVENT_FLAG_CALL, "MonitorStop", 00369 "Channel: %s\r\n" 00370 "Uniqueid: %s\r\n", 00371 chan->name, 00372 chan->uniqueid 00373 ); 00374 } 00375 00376 UNLOCK_IF_NEEDED(chan, need_lock); 00377 00378 return 0; 00379 }
| int ast_monitor_unpause | ( | struct ast_channel * | chan | ) |
Unpause monitoring of channel.
Definition at line 389 of file res_monitor.c.
References AST_MONITOR_RUNNING, and ast_monitor_set_state().
Referenced by do_pause_or_unpause(), and unpause_monitor_exec().
00390 { 00391 return ast_monitor_set_state(chan, AST_MONITOR_RUNNING); 00392 }
1.6.1