#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"
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. | |
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 | |
char * | app = "Record" |
char * | descrip |
LOCAL_USER_DECL | |
STANDARD_LOCAL_USER | |
char * | synopsis = "Record to a file" |
char * | tdesc = "Trivial Record Application" |
Definition in file app_record.c.
|
Provides a description of the module.
Definition at line 362 of file app_record.c. 00363 {
00364 return tdesc;
00365 }
|
|
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 374 of file app_record.c. 00375 {
00376 return ASTERISK_GPL_KEY;
00377 }
|
|
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 357 of file app_record.c. References app, ast_register_application(), descrip, record_exec(), and synopsis. 00358 { 00359 return ast_register_application(app, record_exec, synopsis, descrip); 00360 }
|
|
Definition at line 77 of file app_record.c. References ast_channel::_state, ast_answer(), ast_channel_start_silence_generator(), ast_channel_stop_silence_generator(), ast_closestream(), AST_CONTROL_VIDUPDATE, ast_dsp_free(), ast_dsp_new(), ast_dsp_set_threshold(), ast_dsp_silence(), ast_fileexists(), AST_FORMAT_SLINEAR, ast_frfree(), ast_indicate(), ast_log(), ast_read(), ast_set_read_format(), ast_stopstream(), ast_strdupa, ast_stream_rewind(), ast_streamfile(), ast_strlen_zero(), ast_truncstream(), ast_waitfor(), ast_waitstream(), ast_writefile(), ast_writestream(), ast_frame::frametype, ast_channel::language, LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_DEBUG, LOG_ERROR, LOG_WARNING, ast_channel::name, option_quiet, pbx_builtin_setvar_helper(), ast_channel::readformat, s, strsep(), and ast_frame::subclass. Referenced by load_module(). 00078 { 00079 int res = 0; 00080 int count = 0; 00081 int percentflag = 0; 00082 char *filename, *ext = NULL, *silstr, *maxstr, *options; 00083 char *vdata, *p; 00084 int i = 0; 00085 char tmp[256]; 00086 00087 struct ast_filestream *s = '\0'; 00088 struct localuser *u; 00089 struct ast_frame *f = NULL; 00090 00091 struct ast_dsp *sildet = NULL; /* silence detector dsp */ 00092 int totalsilence = 0; 00093 int dspsilence = 0; 00094 int silence = 0; /* amount of silence to allow */ 00095 int gotsilence = 0; /* did we timeout for silence? */ 00096 int maxduration = 0; /* max duration of recording in milliseconds */ 00097 int gottimeout = 0; /* did we timeout for maxduration exceeded? */ 00098 int option_skip = 0; 00099 int option_noanswer = 0; 00100 int option_append = 0; 00101 int terminator = '#'; 00102 int option_quiet = 0; 00103 int rfmt = 0; 00104 int flags; 00105 int waitres; 00106 struct ast_silence_generator *silgen = NULL; 00107 00108 /* The next few lines of code parse out the filename and header from the input string */ 00109 if (ast_strlen_zero(data)) { /* no data implies no filename or anything is present */ 00110 ast_log(LOG_WARNING, "Record requires an argument (filename)\n"); 00111 return -1; 00112 } 00113 00114 LOCAL_USER_ADD(u); 00115 00116 /* Yay for strsep being easy */ 00117 vdata = ast_strdupa(data); 00118 if (!vdata) { 00119 ast_log(LOG_ERROR, "Out of memory\n"); 00120 LOCAL_USER_REMOVE(u); 00121 return -1; 00122 } 00123 00124 p = vdata; 00125 filename = strsep(&p, "|"); 00126 silstr = strsep(&p, "|"); 00127 maxstr = strsep(&p, "|"); 00128 options = strsep(&p, "|"); 00129 00130 if (filename) { 00131 if (strstr(filename, "%d")) 00132 percentflag = 1; 00133 ext = strrchr(filename, '.'); /* to support filename with a . in the filename, not format */ 00134 if (!ext) 00135 ext = strchr(filename, ':'); 00136 if (ext) { 00137 *ext = '\0'; 00138 ext++; 00139 } 00140 } 00141 if (!ext) { 00142 ast_log(LOG_WARNING, "No extension specified to filename!\n"); 00143 LOCAL_USER_REMOVE(u); 00144 return -1; 00145 } 00146 if (silstr) { 00147 if ((sscanf(silstr, "%d", &i) == 1) && (i > -1)) { 00148 silence = i * 1000; 00149 } else if (!ast_strlen_zero(silstr)) { 00150 ast_log(LOG_WARNING, "'%s' is not a valid silence duration\n", silstr); 00151 } 00152 } 00153 00154 if (maxstr) { 00155 if ((sscanf(maxstr, "%d", &i) == 1) && (i > -1)) 00156 /* Convert duration to milliseconds */ 00157 maxduration = i * 1000; 00158 else if (!ast_strlen_zero(maxstr)) 00159 ast_log(LOG_WARNING, "'%s' is not a valid maximum duration\n", maxstr); 00160 } 00161 if (options) { 00162 /* Retain backwards compatibility with old style options */ 00163 if (!strcasecmp(options, "skip")) 00164 option_skip = 1; 00165 else if (!strcasecmp(options, "noanswer")) 00166 option_noanswer = 1; 00167 else { 00168 if (strchr(options, 's')) 00169 option_skip = 1; 00170 if (strchr(options, 'n')) 00171 option_noanswer = 1; 00172 if (strchr(options, 'a')) 00173 option_append = 1; 00174 if (strchr(options, 't')) 00175 terminator = '*'; 00176 if (strchr(options, 'q')) 00177 option_quiet = 1; 00178 } 00179 } 00180 00181 /* done parsing */ 00182 00183 /* these are to allow the use of the %d in the config file for a wild card of sort to 00184 create a new file with the inputed name scheme */ 00185 if (percentflag) { 00186 do { 00187 snprintf(tmp, sizeof(tmp), filename, count); 00188 count++; 00189 } while ( ast_fileexists(tmp, ext, chan->language) != -1 ); 00190 pbx_builtin_setvar_helper(chan, "RECORDED_FILE", tmp); 00191 } else 00192 strncpy(tmp, filename, sizeof(tmp)-1); 00193 /* end of routine mentioned */ 00194 00195 00196 00197 if (chan->_state != AST_STATE_UP) { 00198 if (option_skip) { 00199 /* At the user's option, skip if the line is not up */ 00200 LOCAL_USER_REMOVE(u); 00201 return 0; 00202 } else if (!option_noanswer) { 00203 /* Otherwise answer unless we're supposed to record while on-hook */ 00204 res = ast_answer(chan); 00205 } 00206 } 00207 00208 if (res) { 00209 ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name); 00210 goto out; 00211 } 00212 00213 if (!option_quiet) { 00214 /* Some code to play a nice little beep to signify the start of the record operation */ 00215 res = ast_streamfile(chan, "beep", chan->language); 00216 if (!res) { 00217 res = ast_waitstream(chan, ""); 00218 } else { 00219 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", chan->name); 00220 } 00221 ast_stopstream(chan); 00222 } 00223 00224 /* The end of beep code. Now the recording starts */ 00225 00226 if (silence > 0) { 00227 rfmt = chan->readformat; 00228 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR); 00229 if (res < 0) { 00230 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n"); 00231 LOCAL_USER_REMOVE(u); 00232 return -1; 00233 } 00234 sildet = ast_dsp_new(); 00235 if (!sildet) { 00236 ast_log(LOG_WARNING, "Unable to create silence detector :(\n"); 00237 LOCAL_USER_REMOVE(u); 00238 return -1; 00239 } 00240 ast_dsp_set_threshold(sildet, 256); 00241 } 00242 00243 00244 flags = option_append ? O_CREAT|O_APPEND|O_WRONLY : O_CREAT|O_TRUNC|O_WRONLY; 00245 s = ast_writefile( tmp, ext, NULL, flags , 0, 0644); 00246 00247 if (!s) { 00248 ast_log(LOG_WARNING, "Could not create file %s\n", filename); 00249 goto out; 00250 } 00251 00252 if (option_transmit_silence_during_record) 00253 silgen = ast_channel_start_silence_generator(chan); 00254 00255 /* Request a video update */ 00256 ast_indicate(chan, AST_CONTROL_VIDUPDATE); 00257 00258 if (maxduration <= 0) 00259 maxduration = -1; 00260 00261 while ((waitres = ast_waitfor(chan, maxduration)) > -1) { 00262 if (maxduration > 0) { 00263 if (waitres == 0) { 00264 gottimeout = 1; 00265 break; 00266 } 00267 maxduration = waitres; 00268 } 00269 00270 f = ast_read(chan); 00271 if (!f) { 00272 res = -1; 00273 break; 00274 } 00275 if (f->frametype == AST_FRAME_VOICE) { 00276 res = ast_writestream(s, f); 00277 00278 if (res) { 00279 ast_log(LOG_WARNING, "Problem writing frame\n"); 00280 ast_frfree(f); 00281 break; 00282 } 00283 00284 if (silence > 0) { 00285 dspsilence = 0; 00286 ast_dsp_silence(sildet, f, &dspsilence); 00287 if (dspsilence) { 00288 totalsilence = dspsilence; 00289 } else { 00290 totalsilence = 0; 00291 } 00292 if (totalsilence > silence) { 00293 /* Ended happily with silence */ 00294 ast_frfree(f); 00295 gotsilence = 1; 00296 break; 00297 } 00298 } 00299 } else if (f->frametype == AST_FRAME_VIDEO) { 00300 res = ast_writestream(s, f); 00301 00302 if (res) { 00303 ast_log(LOG_WARNING, "Problem writing frame\n"); 00304 ast_frfree(f); 00305 break; 00306 } 00307 } else if ((f->frametype == AST_FRAME_DTMF) && 00308 (f->subclass == terminator)) { 00309 ast_frfree(f); 00310 break; 00311 } 00312 ast_frfree(f); 00313 } 00314 if (!f) { 00315 ast_log(LOG_DEBUG, "Got hangup\n"); 00316 res = -1; 00317 } 00318 00319 if (gotsilence) { 00320 ast_stream_rewind(s, silence-1000); 00321 ast_truncstream(s); 00322 } else if (!gottimeout) { 00323 /* Strip off the last 1/4 second of it */ 00324 ast_stream_rewind(s, 250); 00325 ast_truncstream(s); 00326 } 00327 ast_closestream(s); 00328 00329 if (silgen) 00330 ast_channel_stop_silence_generator(chan, silgen); 00331 00332 out: 00333 if ((silence > 0) && rfmt) { 00334 res = ast_set_read_format(chan, rfmt); 00335 if (res) 00336 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name); 00337 if (sildet) 00338 ast_dsp_free(sildet); 00339 } 00340 00341 LOCAL_USER_REMOVE(u); 00342 00343 return res; 00344 }
|
|
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 346 of file app_record.c. References app, and ast_unregister_application(). 00347 { 00348 int res; 00349 00350 res = ast_unregister_application(app); 00351 00352 STANDARD_HANGUP_LOCALUSERS; 00353 00354 return res; 00355 }
|
|
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 367 of file app_record.c. References STANDARD_USECOUNT. 00368 { 00369 int res; 00370 STANDARD_USECOUNT(res); 00371 return res; 00372 }
|
|
Definition at line 47 of file app_record.c. Referenced by load_module(), and unload_module(). |
|
Definition at line 51 of file app_record.c. Referenced by load_module(). |
|
Definition at line 75 of file app_record.c. |
|
Definition at line 73 of file app_record.c. |
|
Definition at line 49 of file app_record.c. Referenced by load_module(). |
|
Definition at line 45 of file app_record.c. |