Asterisk - The Open Source Telephony Project GIT-master-27fb039
Loading...
Searching...
No Matches
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 = ASTERISK_GPL_KEY , .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:2515

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:64

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:2375
#define ast_channel_lock(chan)
Definition channel.h:2982
struct ast_silence_generator * ast_channel_start_silence_generator(struct ast_channel *chan)
Starts a silence generator on the given channel.
Definition channel.c:8208
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition channel.c:3159
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:8254
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition channel.c:4250
int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
Sets read format on channel chan.
Definition channel.c:5757
const char * ast_channel_language(const struct ast_channel *chan)
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition channel.c:2803
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition channel.c:4270
#define ast_channel_unlock(chan)
Definition channel.h:2983
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:2389
struct ast_format * ast_channel_readformat(struct ast_channel *chan)
ast_channel_state
ast_channel states
@ AST_STATE_UP
#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:1792
void ast_dsp_free(struct ast_dsp *dsp)
Definition dsp.c:1787
@ 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:1492
int ast_dsp_get_threshold_from_settings(enum threshold which)
Get silence threshold from dsp.conf.
Definition dsp.c:2013
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
Definition dsp.c:1762
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition file.c:223
int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
Writes a frame to a stream.
Definition file.c:255
int ast_stream_rewind(struct ast_filestream *fs, off_t ms)
Rewind stream ms.
Definition file.c:1119
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition file.c:1312
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:1457
int ast_truncstream(struct ast_filestream *fs)
Trunc stream at current location.
Definition file.c:1099
int ast_closestream(struct ast_filestream *f)
Closes a stream.
Definition file.c:1130
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition file.c:1148
int ast_filedelete(const char *filename, const char *fmt)
Deletes a file.
Definition file.c:1160
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition file.c:1874
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
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_CONTROL_VIDUPDATE
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define LOG_WARNING
#define ast_opt_transmit_silence
Definition options.h:134
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.
static struct @519 args
#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:220
unsigned int flags
Definition utils.h:221
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
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:2317
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:981

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 = ASTERISK_GPL_KEY , .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.

639 {
640 .name = "RECORDING_INFO",
641 .read = recording_info_read,
642};

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.

257 {
258 .type = "RECORDING_INFO",
259 .destroy = recording_data_free,
260};

Referenced by record_exec(), and recording_info_read().