#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "asterisk.h"
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/dsp.h"
#include "asterisk/utils.h"
#include "asterisk/options.h"
#include "asterisk/app.h"
Go to the source code of this file.
Functions | |
char * | description (void) |
Provides a description of the module. | |
char * | key () |
Returns the ASTERISK_GPL_KEY. | |
int | load_module (void) |
Initialize the module. | |
static int | record_exec (struct ast_channel *chan, void *data) |
int | unload_module (void) |
Cleanup all module structures, sockets, etc. | |
int | usecount (void) |
Provides a usecount. | |
Variables | |
static char * | app = "Record" |
static char * | descrip |
LOCAL_USER_DECL | |
STANDARD_LOCAL_USER | |
static char * | synopsis = "Record to a file" |
static char * | tdesc = "Trivial Record Application" |
Definition in file app_record.c.
|
Provides a description of the module.
Definition at line 390 of file app_record.c. 00391 { 00392 return tdesc; 00393 }
|
|
Returns the ASTERISK_GPL_KEY. This returns the ASTERISK_GPL_KEY, signifiying that you agree to the terms of the GPL stated in the ASTERISK_GPL_KEY. Your module will not load if it does not return the EXACT message:
char *key(void) { return ASTERISK_GPL_KEY; }
Definition at line 402 of file app_record.c. References ASTERISK_GPL_KEY. 00403 { 00404 return ASTERISK_GPL_KEY; 00405 }
|
|
Initialize the module. Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other thing it registers applications, cli commands and reads the cofiguration file.
Definition at line 385 of file app_record.c. References ast_register_application(), and record_exec(). 00386 { 00387 return ast_register_application(app, record_exec, synopsis, descrip); 00388 }
|
|
Definition at line 78 of file app_record.c. References AST_APP_ARG, ast_app_separate_args(), AST_DECLARE_APP_ARGS, ast_log(), ast_strdupa, ast_strlen_zero(), LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_ERROR, LOG_WARNING, option_quiet, s, silence, strsep(), and ast_dsp::totalsilence. Referenced by load_module(). 00079 { 00080 int res = 0; 00081 int count = 0; 00082 int percentflag = 0; 00083 char *filename, *ext = NULL, *silstr, *maxstr, *options; 00084 char *vdata, *p; 00085 int i = 0; 00086 char tmp[256]; 00087 00088 struct ast_filestream *s = '\0'; 00089 struct localuser *u; 00090 struct ast_frame *f = NULL; 00091 00092 struct ast_dsp *sildet = NULL; /* silence detector dsp */ 00093 int totalsilence = 0; 00094 int dspsilence = 0; 00095 int silence = 0; /* amount of silence to allow */ 00096 int gotsilence = 0; /* did we timeout for silence? */ 00097 int maxduration = 0; /* max duration of recording in milliseconds */ 00098 int gottimeout = 0; /* did we timeout for maxduration exceeded? */ 00099 int option_skip = 0; 00100 int option_noanswer = 0; 00101 int option_append = 0; 00102 int terminator = '#'; 00103 int option_quiet = 0; 00104 int rfmt = 0; 00105 int flags; 00106 int waitres; 00107 struct ast_silence_generator *silgen = NULL; 00108 00109 /* The next few lines of code parse out the filename and header from the input string */ 00110 if (ast_strlen_zero(data)) { /* no data implies no filename or anything is present */ 00111 ast_log(LOG_WARNING, "Record requires an argument (filename)\n"); 00112 return -1; 00113 } 00114 00115 LOCAL_USER_ADD(u); 00116 00117 /* Yay for strsep being easy */ 00118 vdata = ast_strdupa(data); 00119 if (!vdata) { 00120 ast_log(LOG_ERROR, "Out of memory\n"); 00121 LOCAL_USER_REMOVE(u); 00122 return -1; 00123 } 00124 00125 p = vdata; 00126 filename = strsep(&p, "|"); 00127 silstr = strsep(&p, "|"); 00128 maxstr = strsep(&p, "|"); 00129 options = strsep(&p, "|"); 00130 00131 if (filename) { 00132 if (strstr(filename, "%d")) 00133 percentflag = 1; 00134 ext = strrchr(filename, '.'); /* to support filename with a . in the filename, not format */ 00135 if (!ext) 00136 ext = strchr(filename, ':'); 00137 if (ext) { 00138 *ext = '\0'; 00139 ext++; 00140 } 00141 } 00142 if (!ext) { 00143 ast_log(LOG_WARNING, "No extension specified to filename!\n"); 00144 LOCAL_USER_REMOVE(u); 00145 return -1; 00146 } 00147 if (silstr) { 00148 if ((sscanf(silstr, "%d", &i) == 1) && (i > -1)) { 00149 silence = i * 1000; 00150 } else if (!ast_strlen_zero(silstr)) { 00151 ast_log(LOG_WARNING, "'%s' is not a valid silence duration\n", silstr); 00152 } 00153 } 00154 00155 if (maxstr) { 00156 if ((sscanf(maxstr, "%d", &i) == 1) && (i > -1)) 00157 /* Convert duration to milliseconds */ 00158 maxduration = i * 1000; 00159 else if (!ast_strlen_zero(maxstr)) 00160 ast_log(LOG_WARNING, "'%s' is not a valid maximum duration\n", maxstr); 00161 } 00162 if (options) { 00163 /* Retain backwards compatibility with old style options */ 00164 if (!strcasecmp(options, "skip")) 00165 option_skip = 1; 00166 else if (!strcasecmp(options, "noanswer")) 00167 option_noanswer = 1; 00168 else { 00169 if (strchr(options, 's')) 00170 option_skip = 1; 00171 if (strchr(options, 'n')) 00172 option_noanswer = 1; 00173 if (strchr(options, 'a')) 00174 option_append = 1; 00175 if (strchr(options, 't')) 00176 terminator = '*'; 00177 if (strchr(options, 'q')) 00178 option_quiet = 1; 00179 } 00180 } 00181 00182 /* done parsing */ 00183 00184 /* these are to allow the use of the %d in the config file for a wild card of sort to 00185 create a new file with the inputed name scheme */ 00186 if (percentflag) { 00187 AST_DECLARE_APP_ARGS(fname, 00188 AST_APP_ARG(piece)[100]; 00189 ); 00190 char *tmp2 = ast_strdupa(filename); 00191 char countstring[15]; 00192 int i; 00193 00194 /* Separate each piece out by the format specifier */ 00195 /* AST_NONSTANDARD_APP_ARGS(fname, tmp2, '%'); */ 00196 fname.argc = ast_app_separate_args(tmp2, '%', fname.argv, (sizeof(fname) - sizeof(fname.argc)) / sizeof(fname.argv[0])); 00197 do { 00198 int tmplen; 00199 /* First piece has no leading percent, so it's copied verbatim */ 00200 ast_copy_string(tmp, fname.piece[0], sizeof(tmp)); 00201 tmplen = strlen(tmp); 00202 for (i = 1; i < fname.argc; i++) { 00203 if (fname.piece[i][0] == 'd') { 00204 /* Substitute the count */ 00205 snprintf(countstring, sizeof(countstring), "%d", count); 00206 ast_copy_string(tmp + tmplen, countstring, sizeof(tmp) - tmplen); 00207 tmplen += strlen(countstring); 00208 } else if (tmplen + 2 < sizeof(tmp)) { 00209 /* Unknown format specifier - just copy it verbatim */ 00210 tmp[tmplen++] = '%'; 00211 tmp[tmplen++] = fname.piece[i][0]; 00212 } 00213 /* Copy the remaining portion of the piece */ 00214 ast_copy_string(tmp + tmplen, &(fname.piece[i][1]), sizeof(tmp) - tmplen); 00215 } 00216 count++; 00217 } while ( ast_fileexists(tmp, ext, chan->language) != -1 ); 00218 pbx_builtin_setvar_helper(chan, "RECORDED_FILE", tmp); 00219 } else 00220 strncpy(tmp, filename, sizeof(tmp)-1); 00221 /* end of routine mentioned */ 00222 00223 00224 00225 if (chan->_state != AST_STATE_UP) { 00226 if (option_skip) { 00227 /* At the user's option, skip if the line is not up */ 00228 LOCAL_USER_REMOVE(u); 00229 return 0; 00230 } else if (!option_noanswer) { 00231 /* Otherwise answer unless we're supposed to record while on-hook */ 00232 res = ast_answer(chan); 00233 } 00234 } 00235 00236 if (res) { 00237 ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name); 00238 goto out; 00239 } 00240 00241 if (!option_quiet) { 00242 /* Some code to play a nice little beep to signify the start of the record operation */ 00243 res = ast_streamfile(chan, "beep", chan->language); 00244 if (!res) { 00245 res = ast_waitstream(chan, ""); 00246 } else { 00247 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", chan->name); 00248 } 00249 ast_stopstream(chan); 00250 } 00251 00252 /* The end of beep code. Now the recording starts */ 00253 00254 if (silence > 0) { 00255 rfmt = chan->readformat; 00256 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR); 00257 if (res < 0) { 00258 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n"); 00259 LOCAL_USER_REMOVE(u); 00260 return -1; 00261 } 00262 sildet = ast_dsp_new(); 00263 if (!sildet) { 00264 ast_log(LOG_WARNING, "Unable to create silence detector :(\n"); 00265 LOCAL_USER_REMOVE(u); 00266 return -1; 00267 } 00268 ast_dsp_set_threshold(sildet, 256); 00269 } 00270 00271 00272 flags = option_append ? O_CREAT|O_APPEND|O_WRONLY : O_CREAT|O_TRUNC|O_WRONLY; 00273 s = ast_writefile( tmp, ext, NULL, flags , 0, 0644); 00274 00275 if (!s) { 00276 ast_log(LOG_WARNING, "Could not create file %s\n", filename); 00277 goto out; 00278 } 00279 00280 if (option_transmit_silence_during_record) 00281 silgen = ast_channel_start_silence_generator(chan); 00282 00283 /* Request a video update */ 00284 ast_indicate(chan, AST_CONTROL_VIDUPDATE); 00285 00286 if (maxduration <= 0) 00287 maxduration = -1; 00288 00289 while ((waitres = ast_waitfor(chan, maxduration)) > -1) { 00290 if (maxduration > 0) { 00291 if (waitres == 0) { 00292 gottimeout = 1; 00293 break; 00294 } 00295 maxduration = waitres; 00296 } 00297 00298 f = ast_read(chan); 00299 if (!f) { 00300 res = -1; 00301 break; 00302 } 00303 if (f->frametype == AST_FRAME_VOICE) { 00304 res = ast_writestream(s, f); 00305 00306 if (res) { 00307 ast_log(LOG_WARNING, "Problem writing frame\n"); 00308 ast_frfree(f); 00309 break; 00310 } 00311 00312 if (silence > 0) { 00313 dspsilence = 0; 00314 ast_dsp_silence(sildet, f, &dspsilence); 00315 if (dspsilence) { 00316 totalsilence = dspsilence; 00317 } else { 00318 totalsilence = 0; 00319 } 00320 if (totalsilence > silence) { 00321 /* Ended happily with silence */ 00322 ast_frfree(f); 00323 gotsilence = 1; 00324 break; 00325 } 00326 } 00327 } else if (f->frametype == AST_FRAME_VIDEO) { 00328 res = ast_writestream(s, f); 00329 00330 if (res) { 00331 ast_log(LOG_WARNING, "Problem writing frame\n"); 00332 ast_frfree(f); 00333 break; 00334 } 00335 } else if ((f->frametype == AST_FRAME_DTMF) && 00336 (f->subclass == terminator)) { 00337 ast_frfree(f); 00338 break; 00339 } 00340 ast_frfree(f); 00341 } 00342 if (!f) { 00343 ast_log(LOG_DEBUG, "Got hangup\n"); 00344 res = -1; 00345 } 00346 00347 if (gotsilence) { 00348 ast_stream_rewind(s, silence-1000); 00349 ast_truncstream(s); 00350 } else if (!gottimeout) { 00351 /* Strip off the last 1/4 second of it */ 00352 ast_stream_rewind(s, 250); 00353 ast_truncstream(s); 00354 } 00355 ast_closestream(s); 00356 00357 if (silgen) 00358 ast_channel_stop_silence_generator(chan, silgen); 00359 00360 out: 00361 if ((silence > 0) && rfmt) { 00362 res = ast_set_read_format(chan, rfmt); 00363 if (res) 00364 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name); 00365 if (sildet) 00366 ast_dsp_free(sildet); 00367 } 00368 00369 LOCAL_USER_REMOVE(u); 00370 00371 return res; 00372 }
|
|
Cleanup all module structures, sockets, etc. This is called at exit. Any registrations and memory allocations need to be unregistered and free'd here. Nothing else will do these for you (until exit).
Definition at line 374 of file app_record.c. References ast_unregister_application(), and STANDARD_HANGUP_LOCALUSERS. 00375 { 00376 int res; 00377 00378 res = ast_unregister_application(app); 00379 00380 STANDARD_HANGUP_LOCALUSERS; 00381 00382 return res; 00383 }
|
|
Provides a usecount. This function will be called by various parts of asterisk. Basically, all it has to do is to return a usecount when called. You will need to maintain your usecount within the module somewhere. The usecount should be how many channels provided by this module are in use.
Definition at line 395 of file app_record.c. References STANDARD_USECOUNT. 00396 { 00397 int res; 00398 STANDARD_USECOUNT(res); 00399 return res; 00400 }
|
|
Definition at line 48 of file app_record.c. |
|
Definition at line 52 of file app_record.c. |
|
Definition at line 76 of file app_record.c. |
|
Definition at line 74 of file app_record.c. |
|
Definition at line 50 of file app_record.c. |
|
Definition at line 46 of file app_record.c. |