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