123 #define OPERATOR_KEY '0'
125 static char *app =
"Record";
128 OPTION_APPEND = (1 << 0),
129 OPTION_NOANSWER = (1 << 1),
130 OPTION_QUIET = (1 << 2),
131 OPTION_SKIP = (1 << 3),
132 OPTION_STAR_TERMINATE = (1 << 4),
133 OPTION_IGNORE_TERMINATE = (1 << 5),
134 OPTION_KEEP = (1 << 6),
135 OPTION_ANY_TERMINATE = (1 << 7),
136 OPTION_OPERATOR_EXIT = (1 << 8),
137 OPTION_NO_TRUNCATE = (1 << 9),
141 RESPONSE_NO_MATCH = 0,
171 static enum dtmf_response record_dtmf_response(
struct ast_channel *chan,
172 struct ast_flags *flags,
int dtmf_integer,
int terminator)
174 if ((dtmf_integer == OPERATOR_KEY) &&
175 (ast_test_flag(flags, OPTION_OPERATOR_EXIT))) {
176 return RESPONSE_OPERATOR;
179 if ((dtmf_integer == terminator) ||
180 (ast_test_flag(flags, OPTION_ANY_TERMINATE))) {
181 return RESPONSE_DTMF;
184 return RESPONSE_NO_MATCH;
187 static int create_destination_directory(
const char *path)
190 char directory[PATH_MAX], *file_sep;
192 if (!(file_sep = strrchr(path,
'/'))) {
201 if (path[0] ==
'/') {
208 res = snprintf(directory,
sizeof(directory),
"%s/sounds/%s",
209 ast_config_AST_DATA_DIR, path);
213 if (res >=
sizeof(directory)) {
221 static int record_exec(
struct ast_channel *chan,
const char *data)
224 char *ext = NULL, *opts[0];
237 int truncate_silence = 1;
240 int terminator =
'#';
252 struct timeval start;
253 const char *status_response =
"ERROR";
256 if (ast_strlen_zero(data)) {
257 ast_log(LOG_WARNING,
"Record requires an argument (filename)\n");
267 if (!ast_strlen_zero(args.filename)) {
268 ext = strrchr(args.filename,
'.');
270 ext = strchr(args.filename,
':');
277 ast_log(LOG_WARNING,
"No extension specified to filename!\n");
282 if ((sscanf(args.silence,
"%30d", &i) == 1) && (i > -1)) {
284 }
else if (!ast_strlen_zero(args.silence)) {
285 ast_log(LOG_WARNING,
"'%s' is not a valid silence duration\n", args.silence);
289 if (ast_test_flag(&flags, OPTION_NO_TRUNCATE))
290 truncate_silence = 0;
292 if (args.maxduration) {
293 if ((sscanf(args.maxduration,
"%30d", &i) == 1) && (i > -1))
295 maxduration = i * 1000;
296 else if (!ast_strlen_zero(args.maxduration))
297 ast_log(LOG_WARNING,
"'%s' is not a valid maximum duration\n", args.maxduration);
300 if (ast_test_flag(&flags, OPTION_STAR_TERMINATE))
302 if (ast_test_flag(&flags, OPTION_IGNORE_TERMINATE))
309 if (strchr(args.filename,
'%')) {
310 size_t src, dst, count = 0;
311 size_t src_len = strlen(args.filename);
312 size_t dst_len =
sizeof(tmp) - 1;
315 for (src = 0, dst = 0; src < src_len && dst < dst_len; src++) {
316 if (!strncmp(&args.filename[src],
"%d", 2)) {
317 int s = snprintf(&tmp[dst], PATH_MAX - dst,
"%zu", count);
318 if (s >= PATH_MAX - dst) {
320 ast_log(LOG_WARNING,
"Failed to create unique filename from template: %s\n", args.filename);
327 tmp[dst] = args.filename[src];
332 }
while (
ast_fileexists(tmp, ext, ast_channel_language(chan)) > 0);
339 if (ast_test_flag(&flags, OPTION_SKIP)) {
343 }
else if (!ast_test_flag(&flags, OPTION_NOANSWER)) {
350 ast_log(LOG_WARNING,
"Could not answer channel '%s'\n", ast_channel_name(chan));
351 status_response =
"ERROR";
355 if (!ast_test_flag(&flags, OPTION_QUIET)) {
361 ast_log(LOG_WARNING,
"ast_streamfile(beep) failed on %s\n", ast_channel_name(chan));
370 rfmt =
ao2_bump(ast_channel_readformat(chan));
373 ast_log(LOG_WARNING,
"Unable to set to linear mode, giving up\n");
379 ast_log(LOG_WARNING,
"Unable to create silence detector :(\n");
386 if (create_destination_directory(tmp)) {
387 ast_log(LOG_WARNING,
"Could not create directory for file %s\n", args.filename);
388 status_response =
"ERROR";
392 ioflags = ast_test_flag(&flags, OPTION_APPEND) ? O_CREAT|O_APPEND|O_WRONLY : O_CREAT|O_TRUNC|O_WRONLY;
393 s =
ast_writefile(tmp, ext, NULL, ioflags, 0, AST_FILE_MODE);
396 ast_log(LOG_WARNING,
"Could not create file %s\n", args.filename);
397 status_response =
"ERROR";
401 if (ast_opt_transmit_silence)
407 if (maxduration <= 0)
417 if (maxduration > 0 && ms == 0) {
430 ast_log(LOG_WARNING,
"Problem writing frame\n");
432 status_response =
"ERROR";
440 totalsilence = dspsilence;
444 if (totalsilence > silence) {
448 status_response =
"SILENCE";
456 ast_log(LOG_WARNING,
"Problem writing frame\n");
457 status_response =
"ERROR";
461 }
else if (f->
frametype == AST_FRAME_DTMF) {
462 enum dtmf_response rc =
465 case RESPONSE_NO_MATCH:
467 case RESPONSE_OPERATOR:
468 status_response =
"OPERATOR";
472 status_response =
"DTMF";
476 if (rc != RESPONSE_NO_MATCH) {
484 if (maxduration > 0 && !ms) {
486 status_response =
"TIMEOUT";
492 status_response =
"HANGUP";
493 if (!ast_test_flag(&flags, OPTION_KEEP)) {
498 if (gotsilence && truncate_silence) {
501 }
else if (!gottimeout && f) {
517 if ((silence > 0) && rfmt) {
520 ast_log(LOG_WARNING,
"Unable to restore read format on '%s'\n", ast_channel_name(chan));
525 ast_dsp_free(sildet);
533 static int unload_module(
void)
538 static int load_module(
void)
Main Channel structure associated with a channel.
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Asterisk main include file. File version handling, generic pbx functions.
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Convenient Signal Processing routines.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
ast_channel_state
ast_channel states
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
int ast_filedelete(const char *filename, const char *fmt)
Deletes a file.
int ast_unregister_application(const char *app)
Unregister an application.
struct ast_frame_subclass subclass
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
General Asterisk PBX channel definitions.
Asterisk file paths, configured in asterisk.conf.
int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
Sets read format on channel chan.
#define ast_strdupa(s)
duplicate a string in memory from the stack
#define ast_debug(level,...)
Log a DEBUG message.
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Core PBX routines and definitions.
void ast_dsp_set_threshold(struct ast_dsp *dsp, int threshold)
Set the minimum average magnitude threshold to determine talking by the DSP.
struct ast_silence_generator * ast_channel_start_silence_generator(struct ast_channel *chan)
Starts a silence generator on the given channel.
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
int ast_stream_rewind(struct ast_filestream *fs, off_t ms)
Rewind stream ms.
struct ast_filestream * ast_writefile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
Starts writing a file.
void ast_channel_stop_silence_generator(struct ast_channel *chan, struct ast_silence_generator *state)
Stops a previously-started silence generator on the given channel.
int ast_closestream(struct ast_filestream *f)
Closes a stream.
Structure used to handle boolean flags.
int ast_truncstream(struct ast_filestream *fs)
Trunc stream at current location.
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
int ast_dsp_silence(struct ast_dsp *dsp, struct ast_frame *f, int *totalsilence)
Process the audio frame for silence.
This structure is allocated by file.c in one chunk, together with buf_size and desc_size bytes of mem...
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
Writes a frame to a stream.
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
int ast_answer(struct ast_channel *chan)
Answer a channel.
Data structure associated with a single frame of data.
enum ast_frame_type frametype
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
#define ASTERISK_GPL_KEY
The text the key() function should return.
int ast_dsp_get_threshold_from_settings(enum threshold which)
Get silence threshold from dsp.conf.
Asterisk module definitions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
int ast_stopstream(struct ast_channel *c)
Stops a stream.
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
#define AST_APP_ARG(name)
Define an application argument.
int ast_mkdir(const char *path, int mode)
Recursively create directory path.