#include "asterisk.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.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 | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static int | load_module (void) |
static int | record_exec (struct ast_channel *chan, void *data) |
static int | unload_module (void) |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .description = "Trivial Record Application" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, } |
static char * | app = "Record" |
static const struct ast_module_info * | ast_module_info = &__mod_info |
static char * | descrip |
static char * | synopsis = "Record to a file" |
Definition in file app_record.c.
static void __reg_module | ( | void | ) | [static] |
Definition at line 386 of file app_record.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 386 of file app_record.c.
static int load_module | ( | void | ) | [static] |
Definition at line 381 of file app_record.c.
References ast_register_application(), and record_exec().
00382 { 00383 return ast_register_application(app, record_exec, synopsis, descrip); 00384 }
static int record_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 78 of file app_record.c.
References AST_APP_ARG, ast_copy_string(), AST_DECLARE_APP_ARGS, ast_fileexists(), ast_log(), ast_module_user_add, ast_module_user_remove, AST_NONSTANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ext, f, ast_channel::language, LOG_WARNING, pbx_builtin_setvar_helper(), s, silence, 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 ast_module_user *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 u = ast_module_user_add(chan); 00116 00117 /* Yay for strsep being easy */ 00118 vdata = ast_strdupa(data); 00119 00120 p = vdata; 00121 filename = strsep(&p, "|"); 00122 silstr = strsep(&p, "|"); 00123 maxstr = strsep(&p, "|"); 00124 options = strsep(&p, "|"); 00125 00126 if (filename) { 00127 if (strstr(filename, "%d")) 00128 percentflag = 1; 00129 ext = strrchr(filename, '.'); /* to support filename with a . in the filename, not format */ 00130 if (!ext) 00131 ext = strchr(filename, ':'); 00132 if (ext) { 00133 *ext = '\0'; 00134 ext++; 00135 } 00136 } 00137 if (!ext) { 00138 ast_log(LOG_WARNING, "No extension specified to filename!\n"); 00139 ast_module_user_remove(u); 00140 return -1; 00141 } 00142 if (silstr) { 00143 if ((sscanf(silstr, "%30d", &i) == 1) && (i > -1)) { 00144 silence = i * 1000; 00145 } else if (!ast_strlen_zero(silstr)) { 00146 ast_log(LOG_WARNING, "'%s' is not a valid silence duration\n", silstr); 00147 } 00148 } 00149 00150 if (maxstr) { 00151 if ((sscanf(maxstr, "%30d", &i) == 1) && (i > -1)) 00152 /* Convert duration to milliseconds */ 00153 maxduration = i * 1000; 00154 else if (!ast_strlen_zero(maxstr)) 00155 ast_log(LOG_WARNING, "'%s' is not a valid maximum duration\n", maxstr); 00156 } 00157 if (options) { 00158 /* Retain backwards compatibility with old style options */ 00159 if (!strcasecmp(options, "skip")) 00160 option_skip = 1; 00161 else if (!strcasecmp(options, "noanswer")) 00162 option_noanswer = 1; 00163 else { 00164 if (strchr(options, 's')) 00165 option_skip = 1; 00166 if (strchr(options, 'n')) 00167 option_noanswer = 1; 00168 if (strchr(options, 'a')) 00169 option_append = 1; 00170 if (strchr(options, 't')) 00171 terminator = '*'; 00172 if (strchr(options, 'x')) 00173 terminator = 0; 00174 if (strchr(options, 'q')) 00175 option_quiet = 1; 00176 } 00177 } 00178 00179 /* done parsing */ 00180 00181 /* these are to allow the use of the %d in the config file for a wild card of sort to 00182 create a new file with the inputed name scheme */ 00183 if (percentflag) { 00184 AST_DECLARE_APP_ARGS(fname, 00185 AST_APP_ARG(piece)[100]; 00186 ); 00187 char *tmp2 = ast_strdupa(filename); 00188 char countstring[15]; 00189 int i; 00190 00191 /* Separate each piece out by the format specifier */ 00192 AST_NONSTANDARD_APP_ARGS(fname, tmp2, '%'); 00193 do { 00194 int tmplen; 00195 /* First piece has no leading percent, so it's copied verbatim */ 00196 ast_copy_string(tmp, fname.piece[0], sizeof(tmp)); 00197 tmplen = strlen(tmp); 00198 for (i = 1; i < fname.argc; i++) { 00199 if (fname.piece[i][0] == 'd') { 00200 /* Substitute the count */ 00201 snprintf(countstring, sizeof(countstring), "%d", count); 00202 ast_copy_string(tmp + tmplen, countstring, sizeof(tmp) - tmplen); 00203 tmplen += strlen(countstring); 00204 } else if (tmplen + 2 < sizeof(tmp)) { 00205 /* Unknown format specifier - just copy it verbatim */ 00206 tmp[tmplen++] = '%'; 00207 tmp[tmplen++] = fname.piece[i][0]; 00208 } 00209 /* Copy the remaining portion of the piece */ 00210 ast_copy_string(tmp + tmplen, &(fname.piece[i][1]), sizeof(tmp) - tmplen); 00211 } 00212 count++; 00213 } while (ast_fileexists(tmp, ext, chan->language) > 0); 00214 pbx_builtin_setvar_helper(chan, "RECORDED_FILE", tmp); 00215 } else 00216 ast_copy_string(tmp, filename, sizeof(tmp)); 00217 /* end of routine mentioned */ 00218 00219 00220 00221 if (chan->_state != AST_STATE_UP) { 00222 if (option_skip) { 00223 /* At the user's option, skip if the line is not up */ 00224 ast_module_user_remove(u); 00225 return 0; 00226 } else if (!option_noanswer) { 00227 /* Otherwise answer unless we're supposed to record while on-hook */ 00228 res = ast_answer(chan); 00229 } 00230 } 00231 00232 if (res) { 00233 ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name); 00234 goto out; 00235 } 00236 00237 if (!option_quiet) { 00238 /* Some code to play a nice little beep to signify the start of the record operation */ 00239 res = ast_streamfile(chan, "beep", chan->language); 00240 if (!res) { 00241 res = ast_waitstream(chan, ""); 00242 } else { 00243 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", chan->name); 00244 } 00245 ast_stopstream(chan); 00246 } 00247 00248 /* The end of beep code. Now the recording starts */ 00249 00250 if (silence > 0) { 00251 rfmt = chan->readformat; 00252 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR); 00253 if (res < 0) { 00254 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n"); 00255 ast_module_user_remove(u); 00256 return -1; 00257 } 00258 sildet = ast_dsp_new(); 00259 if (!sildet) { 00260 ast_log(LOG_WARNING, "Unable to create silence detector :(\n"); 00261 ast_module_user_remove(u); 00262 return -1; 00263 } 00264 ast_dsp_set_threshold(sildet, 256); 00265 } 00266 00267 00268 flags = option_append ? O_CREAT|O_APPEND|O_WRONLY : O_CREAT|O_TRUNC|O_WRONLY; 00269 s = ast_writefile( tmp, ext, NULL, flags , 0, 0644); 00270 00271 if (!s) { 00272 ast_log(LOG_WARNING, "Could not create file %s\n", filename); 00273 goto out; 00274 } 00275 00276 if (ast_opt_transmit_silence) 00277 silgen = ast_channel_start_silence_generator(chan); 00278 00279 /* Request a video update */ 00280 ast_indicate(chan, AST_CONTROL_VIDUPDATE); 00281 00282 if (maxduration <= 0) 00283 maxduration = -1; 00284 00285 while ((waitres = ast_waitfor(chan, maxduration)) > -1) { 00286 if (maxduration > 0) { 00287 if (waitres == 0) { 00288 gottimeout = 1; 00289 break; 00290 } 00291 maxduration = waitres; 00292 } 00293 00294 f = ast_read(chan); 00295 if (!f) { 00296 res = -1; 00297 break; 00298 } 00299 if (f->frametype == AST_FRAME_VOICE) { 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 00308 if (silence > 0) { 00309 dspsilence = 0; 00310 ast_dsp_silence(sildet, f, &dspsilence); 00311 if (dspsilence) { 00312 totalsilence = dspsilence; 00313 } else { 00314 totalsilence = 0; 00315 } 00316 if (totalsilence > silence) { 00317 /* Ended happily with silence */ 00318 ast_frfree(f); 00319 gotsilence = 1; 00320 break; 00321 } 00322 } 00323 } else if (f->frametype == AST_FRAME_VIDEO) { 00324 res = ast_writestream(s, f); 00325 00326 if (res) { 00327 ast_log(LOG_WARNING, "Problem writing frame\n"); 00328 ast_frfree(f); 00329 break; 00330 } 00331 } else if ((f->frametype == AST_FRAME_DTMF) && 00332 (f->subclass == terminator)) { 00333 ast_frfree(f); 00334 break; 00335 } 00336 ast_frfree(f); 00337 } 00338 if (!f) { 00339 ast_log(LOG_DEBUG, "Got hangup\n"); 00340 res = -1; 00341 } 00342 00343 if (gotsilence) { 00344 ast_stream_rewind(s, silence-1000); 00345 ast_truncstream(s); 00346 } else if (!gottimeout) { 00347 /* Strip off the last 1/4 second of it */ 00348 ast_stream_rewind(s, 250); 00349 ast_truncstream(s); 00350 } 00351 ast_closestream(s); 00352 00353 if (silgen) 00354 ast_channel_stop_silence_generator(chan, silgen); 00355 00356 out: 00357 if ((silence > 0) && rfmt) { 00358 res = ast_set_read_format(chan, rfmt); 00359 if (res) 00360 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name); 00361 if (sildet) 00362 ast_dsp_free(sildet); 00363 } 00364 00365 ast_module_user_remove(u); 00366 00367 return res; 00368 }
static int unload_module | ( | void | ) | [static] |
Definition at line 370 of file app_record.c.
References ast_module_user_hangup_all, and ast_unregister_application().
00371 { 00372 int res; 00373 00374 res = ast_unregister_application(app); 00375 00376 ast_module_user_hangup_all(); 00377 00378 return res; 00379 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .description = "Trivial Record Application" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, } [static] |
Definition at line 386 of file app_record.c.
char* app = "Record" [static] |
Definition at line 49 of file app_record.c.
const struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 386 of file app_record.c.
char* descrip [static] |
Definition at line 53 of file app_record.c.
char* synopsis = "Record to a file" [static] |
Definition at line 51 of file app_record.c.