Asterisk - The Open Source Telephony Project GIT-master-5963e62
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
Data Structures | Macros | Enumerations | Functions | Variables
app_record.c File Reference

Trivial application to record a sound file. More...

#include "asterisk.h"
#include "asterisk/file.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/app.h"
#include "asterisk/channel.h"
#include "asterisk/dsp.h"
#include "asterisk/format_cache.h"
#include "asterisk/paths.h"
Include dependency graph for app_record.c:

Go to the source code of this file.

Data Structures

struct  recording_data
 

Macros

#define OPERATOR_KEY   '0'
 

Enumerations

enum  {
  OPTION_APPEND = (1 << 0) , OPTION_NOANSWER = (1 << 1) , OPTION_QUIET = (1 << 2) , OPTION_SKIP = (1 << 3) ,
  OPTION_STAR_TERMINATE = (1 << 4) , OPTION_IGNORE_TERMINATE = (1 << 5) , OPTION_KEEP = (1 << 6) , OPTION_ANY_TERMINATE = (1 << 7) ,
  OPTION_OPERATOR_EXIT = (1 << 8) , OPTION_NO_TRUNCATE = (1 << 9)
}
 
enum  dtmf_response { RESPONSE_NO_MATCH = 0 , RESPONSE_OPERATOR , RESPONSE_DTMF }
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static int create_destination_directory (const char *path)
 
static int load_module (void)
 
static enum dtmf_response record_dtmf_response (struct ast_channel *chan, struct ast_flags *flags, int dtmf_integer, int terminator)
 
static int record_exec (struct ast_channel *chan, const char *data)
 
static void recording_data_free (void *data)
 
static int recording_info_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, .support_level = AST_MODULE_SUPPORT_CORE, }
 
static struct ast_custom_function acf_recording_info
 
static char * app = "Record"
 
static const struct ast_app_option app_opts [128] = { [ 'a' ] = { .flag = OPTION_APPEND }, [ 'k' ] = { .flag = OPTION_KEEP }, [ 'n' ] = { .flag = OPTION_NOANSWER }, [ 'o' ] = { .flag = OPTION_OPERATOR_EXIT }, [ 'q' ] = { .flag = OPTION_QUIET }, [ 's' ] = { .flag = OPTION_SKIP }, [ 't' ] = { .flag = OPTION_STAR_TERMINATE }, [ 'u' ] = { .flag = OPTION_NO_TRUNCATE }, [ 'y' ] = { .flag = OPTION_ANY_TERMINATE }, [ 'x' ] = { .flag = OPTION_IGNORE_TERMINATE }, }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static const struct ast_datastore_info recording_data_info
 

Detailed Description

Trivial application to record a sound file.

Author
Matthew Fredrickson cresl.nosp@m.in@d.nosp@m.igium.nosp@m..com

Definition in file app_record.c.

Macro Definition Documentation

◆ OPERATOR_KEY

#define OPERATOR_KEY   '0'

Definition at line 150 of file app_record.c.

Enumeration Type Documentation

◆ anonymous enum

anonymous enum
Enumerator
OPTION_APPEND 
OPTION_NOANSWER 
OPTION_QUIET 
OPTION_SKIP 
OPTION_STAR_TERMINATE 
OPTION_IGNORE_TERMINATE 
OPTION_KEEP 
OPTION_ANY_TERMINATE 
OPTION_OPERATOR_EXIT 
OPTION_NO_TRUNCATE 

Definition at line 154 of file app_record.c.

154 {
155 OPTION_APPEND = (1 << 0),
156 OPTION_NOANSWER = (1 << 1),
157 OPTION_QUIET = (1 << 2),
158 OPTION_SKIP = (1 << 3),
159 OPTION_STAR_TERMINATE = (1 << 4),
160 OPTION_IGNORE_TERMINATE = (1 << 5),
161 OPTION_KEEP = (1 << 6),
162 OPTION_ANY_TERMINATE = (1 << 7),
163 OPTION_OPERATOR_EXIT = (1 << 8),
164 OPTION_NO_TRUNCATE = (1 << 9),
165};
@ OPTION_NOANSWER
Definition: app_record.c:156
@ OPTION_STAR_TERMINATE
Definition: app_record.c:159
@ OPTION_KEEP
Definition: app_record.c:161
@ OPTION_NO_TRUNCATE
Definition: app_record.c:164
@ OPTION_QUIET
Definition: app_record.c:157
@ OPTION_OPERATOR_EXIT
Definition: app_record.c:163
@ OPTION_IGNORE_TERMINATE
Definition: app_record.c:160
@ OPTION_ANY_TERMINATE
Definition: app_record.c:162
@ OPTION_SKIP
Definition: app_record.c:158
@ OPTION_APPEND
Definition: app_record.c:155

◆ dtmf_response

Enumerator
RESPONSE_NO_MATCH 
RESPONSE_OPERATOR 
RESPONSE_DTMF 

Definition at line 167 of file app_record.c.

167 {
171};
@ RESPONSE_OPERATOR
Definition: app_record.c:169
@ RESPONSE_DTMF
Definition: app_record.c:170
@ RESPONSE_NO_MATCH
Definition: app_record.c:168

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 660 of file app_record.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 660 of file app_record.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 660 of file app_record.c.

◆ create_destination_directory()

static int create_destination_directory ( const char *  path)
static

Definition at line 214 of file app_record.c.

215{
216 int res;
217 char directory[PATH_MAX], *file_sep;
218
219 if (!(file_sep = strrchr(path, '/'))) {
220 /* No directory to create */
221 return 0;
222 }
223
224 /* Overwrite temporarily */
225 *file_sep = '\0';
226
227 /* Absolute path? */
228 if (path[0] == '/') {
229 res = ast_mkdir(path, 0777);
230 *file_sep = '/';
231 return res;
232 }
233
234 /* Relative path */
235 res = snprintf(directory, sizeof(directory), "%s/sounds/%s",
237
238 *file_sep = '/';
239
240 if (res >= sizeof(directory)) {
241 /* We truncated, so we fail */
242 return -1;
243 }
244
245 return ast_mkdir(directory, 0777);
246}
#define PATH_MAX
Definition: asterisk.h:40
const char * ast_config_AST_DATA_DIR
Definition: options.c:159
int ast_mkdir(const char *path, int mode)
Recursively create directory path.
Definition: utils.c:2479

References ast_config_AST_DATA_DIR, ast_mkdir(), and PATH_MAX.

Referenced by record_exec().

◆ load_module()

static int load_module ( void  )
static

Definition at line 652 of file app_record.c.

653{
654 int res;
657 return res;
658}
static int record_exec(struct ast_channel *chan, const char *data)
Definition: app_record.c:298
static struct ast_custom_function acf_recording_info
Definition: app_record.c:639
static char * app
Definition: app_record.c:152
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:640
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1562

References acf_recording_info, app, ast_custom_function_register, ast_register_application_xml, and record_exec().

◆ record_dtmf_response()

static enum dtmf_response record_dtmf_response ( struct ast_channel chan,
struct ast_flags flags,
int  dtmf_integer,
int  terminator 
)
static

Definition at line 198 of file app_record.c.

200{
201 if ((dtmf_integer == OPERATOR_KEY) &&
203 return RESPONSE_OPERATOR;
204 }
205
206 if ((dtmf_integer == terminator) ||
208 return RESPONSE_DTMF;
209 }
210
211 return RESPONSE_NO_MATCH;
212}
#define OPERATOR_KEY
Definition: app_record.c:150
#define ast_test_flag(p, flag)
Definition: utils.h:63

References ast_test_flag, OPERATOR_KEY, OPTION_ANY_TERMINATE, OPTION_OPERATOR_EXIT, RESPONSE_DTMF, RESPONSE_NO_MATCH, and RESPONSE_OPERATOR.

Referenced by record_exec().

◆ record_exec()

static int record_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 298 of file app_record.c.

299{
300 struct ast_datastore *ds;
301 int res = 0;
302 char *ext = NULL, *opts[0];
303 char *parse;
304 int i = 0;
305 char tmp[PATH_MAX];
306 struct recording_data *recdata;
307
308 struct ast_filestream *s = NULL;
309 struct ast_frame *f = NULL;
310
311 struct ast_dsp *sildet = NULL; /* silence detector dsp */
312 int totalsilence = 0;
313 int dspsilence = 0;
314 int silence = 0; /* amount of silence to allow */
315 int gotsilence = 0; /* did we timeout for silence? */
316 int truncate_silence = 1; /* truncate on complete silence recording */
317 int maxduration = 0; /* max duration of recording in milliseconds */
318 int gottimeout = 0; /* did we timeout for maxduration exceeded? */
319 int terminator = '#';
320 RAII_VAR(struct ast_format *, rfmt, NULL, ao2_cleanup);
321 int ioflags;
322 struct ast_silence_generator *silgen = NULL;
323 struct ast_flags flags = { 0, };
325 AST_APP_ARG(filename);
326 AST_APP_ARG(silence);
327 AST_APP_ARG(maxduration);
329 );
330 int ms;
331 struct timeval start;
332 const char *status_response = "ERROR";
333
334 /* Retrieve or create the datastore */
335 ast_channel_lock(chan);
338 ast_log(LOG_ERROR, "Unable to allocate new datastore.\n");
339 ast_channel_unlock(chan);
340 return -1;
341 }
342
343 if (!(recdata = ast_calloc(1, sizeof(*recdata)))) {
345 ast_channel_unlock(chan);
346 return -1;
347 }
348
349 ds->data = recdata;
351 } else {
352 recdata = ds->data;
353 }
354 ast_channel_unlock(chan);
355
356 /* Reset, in case already set */
357 recdata->duration = 0;
358
359 /* The next few lines of code parse out the filename and header from the input string */
360 if (ast_strlen_zero(data)) { /* no data implies no filename or anything is present */
361 ast_log(LOG_WARNING, "Record requires an argument (filename)\n");
362 pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "ERROR");
363 return -1;
364 }
365
366 parse = ast_strdupa(data);
368 if (args.argc == 4)
369 ast_app_parse_options(app_opts, &flags, opts, args.options);
370
371 if (!ast_strlen_zero(args.filename)) {
372 ext = strrchr(args.filename, '.'); /* to support filename with a . in the filename, not format */
373 if (!ext)
374 ext = strchr(args.filename, ':');
375 if (ext) {
376 *ext = '\0';
377 ext++;
378 }
379 }
380 if (!ext) {
381 ast_log(LOG_WARNING, "No extension specified to filename!\n");
382 pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "ERROR");
383 return -1;
384 }
385 if (args.silence) {
386 if ((sscanf(args.silence, "%30d", &i) == 1) && (i > -1)) {
387 silence = i * 1000;
388 } else if (!ast_strlen_zero(args.silence)) {
389 ast_log(LOG_WARNING, "'%s' is not a valid silence duration\n", args.silence);
390 }
391 }
392
394 truncate_silence = 0;
395
396 if (args.maxduration) {
397 if ((sscanf(args.maxduration, "%30d", &i) == 1) && (i > -1))
398 /* Convert duration to milliseconds */
399 maxduration = i * 1000;
400 else if (!ast_strlen_zero(args.maxduration))
401 ast_log(LOG_WARNING, "'%s' is not a valid maximum duration\n", args.maxduration);
402 }
403
405 terminator = '*';
407 terminator = '\0';
408
409 /*
410 If a '%d' is specified as part of the filename, we replace that token with
411 sequentially incrementing numbers until we find a unique filename.
412 */
413 if (strchr(args.filename, '%')) {
414 size_t src, dst, count = 0;
415 size_t src_len = strlen(args.filename);
416 size_t dst_len = sizeof(tmp) - 1;
417
418 do {
419 for (src = 0, dst = 0; src < src_len && dst < dst_len; src++) {
420 if (!strncmp(&args.filename[src], "%d", 2)) {
421 int s = snprintf(&tmp[dst], PATH_MAX - dst, "%zu", count);
422 if (s >= PATH_MAX - dst) {
423 /* We truncated, so we need to bail */
424 ast_log(LOG_WARNING, "Failed to create unique filename from template: %s\n", args.filename);
425 pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "ERROR");
426 return -1;
427 }
428 dst += s;
429 src++;
430 } else {
431 tmp[dst] = args.filename[src];
432 tmp[++dst] = '\0';
433 }
434 }
435 count++;
436 } while (ast_fileexists(tmp, ext, ast_channel_language(chan)) > 0);
437 } else
438 ast_copy_string(tmp, args.filename, sizeof(tmp));
439
440 pbx_builtin_setvar_helper(chan, "RECORDED_FILE", tmp);
441
442 if (ast_channel_state(chan) != AST_STATE_UP) {
443 if (ast_test_flag(&flags, OPTION_SKIP)) {
444 /* At the user's option, skip if the line is not up */
445 pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "SKIP");
446 return 0;
447 } else if (!ast_test_flag(&flags, OPTION_NOANSWER)) {
448 /* Otherwise answer unless we're supposed to record while on-hook */
449 res = ast_answer(chan);
450 }
451 }
452
453 if (res) {
454 ast_log(LOG_WARNING, "Could not answer channel '%s'\n", ast_channel_name(chan));
455 status_response = "ERROR";
456 goto out;
457 }
458
459 if (!ast_test_flag(&flags, OPTION_QUIET)) {
460 /* Some code to play a nice little beep to signify the start of the record operation */
461 res = ast_streamfile(chan, "beep", ast_channel_language(chan));
462 if (!res) {
463 res = ast_waitstream(chan, "");
464 } else {
465 ast_log(LOG_WARNING, "ast_streamfile(beep) failed on %s\n", ast_channel_name(chan));
466 res = 0;
467 }
468 ast_stopstream(chan);
469 }
470
471 /* The end of beep code. Now the recording starts */
472
473 if (silence > 0) {
474 rfmt = ao2_bump(ast_channel_readformat(chan));
476 if (res < 0) {
477 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
478 pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "ERROR");
479 return -1;
480 }
481 sildet = ast_dsp_new();
482 if (!sildet) {
483 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
484 pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "ERROR");
485 return -1;
486 }
488 }
489
491 ast_log(LOG_WARNING, "Could not create directory for file %s\n", args.filename);
492 status_response = "ERROR";
493 goto out;
494 }
495
496 ioflags = ast_test_flag(&flags, OPTION_APPEND) ? O_CREAT|O_APPEND|O_WRONLY : O_CREAT|O_TRUNC|O_WRONLY;
497 s = ast_writefile(tmp, ext, NULL, ioflags, 0, AST_FILE_MODE);
498
499 if (!s) {
500 ast_log(LOG_WARNING, "Could not create file %s\n", args.filename);
501 status_response = "ERROR";
502 goto out;
503 }
504
507
508 /* Request a video update */
510
511 if (maxduration <= 0)
512 maxduration = -1;
513
514 start = ast_tvnow();
515 while ((ms = ast_remaining_ms(start, maxduration))) {
516 ms = ast_waitfor(chan, ms);
517 if (ms < 0) {
518 break;
519 }
520
521 if (maxduration > 0 && ms == 0) {
522 break;
523 }
524
525 f = ast_read(chan);
526 if (!f) {
527 res = -1;
528 break;
529 }
530 if (f->frametype == AST_FRAME_VOICE) {
531 res = ast_writestream(s, f);
532
533 if (res) {
534 ast_log(LOG_WARNING, "Problem writing frame\n");
535 ast_frfree(f);
536 status_response = "ERROR";
537 break;
538 }
539
540 if (silence > 0) {
541 dspsilence = 0;
542 ast_dsp_silence(sildet, f, &dspsilence);
543 if (dspsilence) {
544 totalsilence = dspsilence;
545 } else {
546 totalsilence = 0;
547 }
548 if (totalsilence > silence) {
549 /* Ended happily with silence */
550 ast_frfree(f);
551 gotsilence = 1;
552 status_response = "SILENCE";
553 break;
554 }
555 }
556 } else if (f->frametype == AST_FRAME_VIDEO) {
557 res = ast_writestream(s, f);
558
559 if (res) {
560 ast_log(LOG_WARNING, "Problem writing frame\n");
561 status_response = "ERROR";
562 ast_frfree(f);
563 break;
564 }
565 } else if (f->frametype == AST_FRAME_DTMF) {
566 enum dtmf_response rc =
567 record_dtmf_response(chan, &flags, f->subclass.integer, terminator);
568 switch(rc) {
570 break;
572 status_response = "OPERATOR";
573 ast_debug(1, "Got OPERATOR\n");
574 break;
575 case RESPONSE_DTMF:
576 status_response = "DTMF";
577 ast_debug(1, "Got DTMF\n");
578 break;
579 }
580 if (rc != RESPONSE_NO_MATCH) {
581 ast_frfree(f);
582 break;
583 }
584 }
585 ast_frfree(f);
586 }
587
588 if (maxduration > 0 && !ms) {
589 gottimeout = 1;
590 status_response = "TIMEOUT";
591 }
592
593 if (!f) {
594 ast_debug(1, "Got hangup\n");
595 res = -1;
596 status_response = "HANGUP";
597 if (!ast_test_flag(&flags, OPTION_KEEP)) {
598 ast_filedelete(args.filename, NULL);
599 }
600 }
601
602 if (gotsilence && truncate_silence) {
603 ast_stream_rewind(s, silence - 1000);
605 } else if (!gottimeout && f) {
606 /*
607 * Strip off the last 1/4 second of it, if we didn't end because of a timeout,
608 * or a hangup. This must mean we ended because of a DTMF tone and while this
609 * 1/4 second stripping is very old code the most likely explanation is that it
610 * relates to stripping a partial DTMF tone.
611 */
612 ast_stream_rewind(s, 250);
614 }
616
617 if (silgen)
619
620out:
621 recdata->duration = ast_tvdiff_ms(ast_tvnow(), start);
622
623 if ((silence > 0) && rfmt) {
624 res = ast_set_read_format(chan, rfmt);
625 if (res) {
626 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", ast_channel_name(chan));
627 }
628 }
629
630 if (sildet) {
631 ast_dsp_free(sildet);
632 }
633
634 pbx_builtin_setvar_helper(chan, "RECORD_STATUS", status_response);
635
636 return res;
637}
static enum dtmf_response record_dtmf_response(struct ast_channel *chan, struct ast_flags *flags, int dtmf_integer, int terminator)
Definition: app_record.c:198
static int create_destination_directory(const char *path)
Definition: app_record.c:214
static const struct ast_app_option app_opts[128]
Definition: app_record.c:184
static const struct ast_datastore_info recording_data_info
Definition: app_record.c:257
dtmf_response
Definition: app_record.c:167
#define AST_FILE_MODE
Definition: asterisk.h:32
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_log
Definition: astobj2.c:42
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
const char * ast_channel_name(const struct ast_channel *chan)
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2354
#define ast_channel_lock(chan)
Definition: channel.h:2972
struct ast_silence_generator * ast_channel_start_silence_generator(struct ast_channel *chan)
Starts a silence generator on the given channel.
Definition: channel.c:8165
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3130
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.
Definition: channel.c:8211
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4210
int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
Sets read format on channel chan.
Definition: channel.c:5717
const char * ast_channel_language(const struct ast_channel *chan)
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2774
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4230
#define ast_channel_unlock(chan)
Definition: channel.h:2973
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2368
struct ast_format * ast_channel_readformat(struct ast_channel *chan)
ast_channel_state
ast_channel states
Definition: channelstate.h:35
@ AST_STATE_UP
Definition: channelstate.h:42
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:85
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
void ast_dsp_set_threshold(struct ast_dsp *dsp, int threshold)
Set the minimum average magnitude threshold to determine talking by the DSP.
Definition: dsp.c:1788
void ast_dsp_free(struct ast_dsp *dsp)
Definition: dsp.c:1783
@ THRESHOLD_SILENCE
Definition: dsp.h:73
int ast_dsp_silence(struct ast_dsp *dsp, struct ast_frame *f, int *totalsilence)
Process the audio frame for silence.
Definition: dsp.c:1488
int ast_dsp_get_threshold_from_settings(enum threshold which)
Get silence threshold from dsp.conf.
Definition: dsp.c:2009
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
Definition: dsp.c:1758
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:222
int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
Writes a frame to a stream.
Definition: file.c:244
int ast_stream_rewind(struct ast_filestream *fs, off_t ms)
Rewind stream ms.
Definition: file.c:1108
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:1301
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.
Definition: file.c:1431
int ast_truncstream(struct ast_filestream *fs)
Trunc stream at current location.
Definition: file.c:1088
int ast_closestream(struct ast_filestream *f)
Closes a stream.
Definition: file.c:1119
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:1137
int ast_filedelete(const char *filename, const char *fmt)
Deletes a file.
Definition: file.c:1149
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1848
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
const char * ext
Definition: http.c:150
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
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.
Definition: main/app.c:3066
#define AST_FRAME_DTMF
#define ast_frfree(fr)
@ AST_FRAME_VIDEO
@ AST_FRAME_VOICE
@ AST_CONTROL_VIDUPDATE
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define LOG_WARNING
#define ast_opt_transmit_silence
Definition: options.h:125
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.
#define NULL
Definition: resample.c:96
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
Structure for a data store object.
Definition: datastore.h:64
void * data
Definition: datastore.h:66
Definition: dsp.c:407
int totalsilence
Definition: dsp.c:411
This structure is allocated by file.c in one chunk, together with buf_size and desc_size bytes of mem...
Definition: mod_format.h:101
Structure used to handle boolean flags.
Definition: utils.h:199
unsigned int flags
Definition: utils.h:200
Definition of a media format.
Definition: format.c:43
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
enum ast_frame_type frametype
unsigned long duration
Definition: app_record.c:249
const char * args
static struct test_options options
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
Definition: utils.c:2281
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
FILE * out
Definition: utils/frame.c:33
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:947

References ao2_bump, ao2_cleanup, app_opts, args, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_language(), ast_channel_lock, ast_channel_name(), ast_channel_readformat(), ast_channel_start_silence_generator(), ast_channel_stop_silence_generator(), ast_channel_unlock, ast_closestream(), AST_CONTROL_VIDUPDATE, ast_copy_string(), ast_datastore_alloc, ast_datastore_free(), ast_debug, AST_DECLARE_APP_ARGS, ast_dsp_free(), ast_dsp_get_threshold_from_settings(), ast_dsp_new(), ast_dsp_set_threshold(), ast_dsp_silence(), AST_FILE_MODE, ast_filedelete(), ast_fileexists(), ast_format_slin, AST_FRAME_DTMF, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree, ast_indicate(), ast_log, ast_opt_transmit_silence, ast_read(), ast_remaining_ms(), ast_set_read_format(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_stopstream(), ast_strdupa, ast_stream_rewind(), ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_truncstream(), ast_tvdiff_ms(), ast_tvnow(), ast_waitfor(), ast_waitstream(), ast_writefile(), ast_writestream(), create_destination_directory(), ast_datastore::data, recording_data::duration, ext, ast_flags::flags, ast_frame::frametype, ast_frame_subclass::integer, LOG_ERROR, LOG_WARNING, NULL, OPTION_APPEND, OPTION_IGNORE_TERMINATE, OPTION_KEEP, OPTION_NO_TRUNCATE, OPTION_NOANSWER, OPTION_QUIET, OPTION_SKIP, OPTION_STAR_TERMINATE, options, out, PATH_MAX, pbx_builtin_setvar_helper(), RAII_VAR, record_dtmf_response(), recording_data_info, RESPONSE_DTMF, RESPONSE_NO_MATCH, RESPONSE_OPERATOR, ast_frame::subclass, THRESHOLD_SILENCE, and ast_dsp::totalsilence.

Referenced by load_module().

◆ recording_data_free()

static void recording_data_free ( void *  data)
static

Definition at line 252 of file app_record.c.

253{
254 ast_free(data);
255}
#define ast_free(a)
Definition: astmm.h:180

References ast_free.

◆ recording_info_read()

static int recording_info_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
)
static

Definition at line 262 of file app_record.c.

263{
264 struct ast_datastore *ds;
265 struct recording_data *recdata;
266
267 *buf = '\0';
268
269 if (!chan) {
270 ast_log(LOG_ERROR, "%s() can only be executed on a channel\n", cmd);
271 return -1;
272 } else if (ast_strlen_zero(data)) {
273 ast_log(LOG_ERROR, "%s() requires an argument\n", cmd);
274 return -1;
275 }
276
277 ast_channel_lock(chan);
279 ast_channel_unlock(chan);
280
281 if (!ds) {
282 ast_log(LOG_ERROR, "No recordings have completed on channel %s\n", ast_channel_name(chan));
283 return -1;
284 }
285
286 recdata = ds->data;
287
288 if (!strcasecmp(data, "duration")) {
289 snprintf(buf, len, "%ld", recdata->duration);
290 } else {
291 ast_log(LOG_ERROR, "Invalid property type: %s\n", data);
292 return -1;
293 }
294
295 return 0;
296}
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)

References ast_channel_datastore_find(), ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_log, ast_strlen_zero(), buf, ast_datastore::data, recording_data::duration, len(), LOG_ERROR, NULL, and recording_data_info.

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 644 of file app_record.c.

645{
646 int res;
649 return res;
650}
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.

References acf_recording_info, app, ast_custom_function_unregister(), and ast_unregister_application().

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, .support_level = AST_MODULE_SUPPORT_CORE, }
static

Definition at line 660 of file app_record.c.

◆ acf_recording_info

struct ast_custom_function acf_recording_info
static
Initial value:
= {
.name = "RECORDING_INFO",
}
static int recording_info_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: app_record.c:262

Definition at line 639 of file app_record.c.

Referenced by load_module(), and unload_module().

◆ app

char* app = "Record"
static

Definition at line 152 of file app_record.c.

Referenced by load_module(), and unload_module().

◆ app_opts

const struct ast_app_option app_opts[128] = { [ 'a' ] = { .flag = OPTION_APPEND }, [ 'k' ] = { .flag = OPTION_KEEP }, [ 'n' ] = { .flag = OPTION_NOANSWER }, [ 'o' ] = { .flag = OPTION_OPERATOR_EXIT }, [ 'q' ] = { .flag = OPTION_QUIET }, [ 's' ] = { .flag = OPTION_SKIP }, [ 't' ] = { .flag = OPTION_STAR_TERMINATE }, [ 'u' ] = { .flag = OPTION_NO_TRUNCATE }, [ 'y' ] = { .flag = OPTION_ANY_TERMINATE }, [ 'x' ] = { .flag = OPTION_IGNORE_TERMINATE }, }
static

Definition at line 184 of file app_record.c.

Referenced by record_exec().

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 660 of file app_record.c.

◆ recording_data_info

const struct ast_datastore_info recording_data_info
static
Initial value:
= {
.type = "RECORDING_INFO",
.destroy = recording_data_free,
}
static void recording_data_free(void *data)
Definition: app_record.c:252

Definition at line 257 of file app_record.c.

Referenced by record_exec(), and recording_info_read().