From: Naveen Albert Date: Mon, 22 Jan 2024 12:23:47 +0000 (-0500) Subject: app_record: Add RECORDING_INFO function. X-Git-Tag: 21.10.0-rc1~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5863873d10ed7c0333cb549c6ee704410dfcbb51;p=thirdparty%2Fasterisk.git app_record: Add RECORDING_INFO function. Add a function that can be used to retrieve info about a previous recording, such as its duration. This is being added as a function to avoid possibly trampling on dialplan variables, and could be extended to provide other information in the future. Resolves: #548 UserNote: The RECORDING_INFO function can now be used to retrieve the duration of a recording. (cherry picked from commit 47250b716c7fc8b80a945e91dbc4b2889d659c1d) --- diff --git a/apps/app_record.c b/apps/app_record.c index b275957de7..156be0fad3 100644 --- a/apps/app_record.c +++ b/apps/app_record.c @@ -119,8 +119,32 @@ + + RECORDING_INFO + - + + + Retrieve information about a recording previously created using the Record application + + + + The property about the recording to retrieve. + + + The duration, in milliseconds, of the recording. + + + + + + Returns information about the previous recording created by Record. + This function cannot be used if no recordings have yet been completed. + + + Record + + ***/ #define OPERATOR_KEY '0' @@ -221,13 +245,65 @@ static int create_destination_directory(const char *path) return ast_mkdir(directory, 0777); } +struct recording_data { + unsigned long duration; /* Duration, in ms */ +}; + +static void recording_data_free(void *data) +{ + ast_free(data); +} + +static const struct ast_datastore_info recording_data_info = { + .type = "RECORDING_INFO", + .destroy = recording_data_free, +}; + +static int recording_info_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) +{ + struct ast_datastore *ds; + struct recording_data *recdata; + + *buf = '\0'; + + if (!chan) { + ast_log(LOG_ERROR, "%s() can only be executed on a channel\n", cmd); + return -1; + } else if (ast_strlen_zero(data)) { + ast_log(LOG_ERROR, "%s() requires an argument\n", cmd); + return -1; + } + + ast_channel_lock(chan); + ds = ast_channel_datastore_find(chan, &recording_data_info, NULL); + ast_channel_unlock(chan); + + if (!ds) { + ast_log(LOG_ERROR, "No recordings have completed on channel %s\n", ast_channel_name(chan)); + return -1; + } + + recdata = ds->data; + + if (!strcasecmp(data, "duration")) { + snprintf(buf, len, "%ld", recdata->duration); + } else { + ast_log(LOG_ERROR, "Invalid property type: %s\n", data); + return -1; + } + + return 0; +} + static int record_exec(struct ast_channel *chan, const char *data) { + struct ast_datastore *ds; int res = 0; char *ext = NULL, *opts[0]; char *parse; int i = 0; char tmp[PATH_MAX]; + struct recording_data *recdata; struct ast_filestream *s = NULL; struct ast_frame *f = NULL; @@ -255,6 +331,31 @@ static int record_exec(struct ast_channel *chan, const char *data) struct timeval start; const char *status_response = "ERROR"; + /* Retrieve or create the datastore */ + ast_channel_lock(chan); + if (!(ds = ast_channel_datastore_find(chan, &recording_data_info, NULL))) { + if (!(ds = ast_datastore_alloc(&recording_data_info, NULL))) { + ast_log(LOG_ERROR, "Unable to allocate new datastore.\n"); + ast_channel_unlock(chan); + return -1; + } + + if (!(recdata = ast_calloc(1, sizeof(*recdata)))) { + ast_datastore_free(ds); + ast_channel_unlock(chan); + return -1; + } + + ds->data = recdata; + ast_channel_datastore_add(chan, ds); + } else { + recdata = ds->data; + } + ast_channel_unlock(chan); + + /* Reset, in case already set */ + recdata->duration = 0; + /* The next few lines of code parse out the filename and header from the input string */ if (ast_strlen_zero(data)) { /* no data implies no filename or anything is present */ ast_log(LOG_WARNING, "Record requires an argument (filename)\n"); @@ -517,6 +618,8 @@ static int record_exec(struct ast_channel *chan, const char *data) ast_channel_stop_silence_generator(chan, silgen); out: + recdata->duration = ast_tvdiff_ms(ast_tvnow(), start); + if ((silence > 0) && rfmt) { res = ast_set_read_format(chan, rfmt); if (res) { @@ -533,14 +636,25 @@ out: return res; } +static struct ast_custom_function acf_recording_info = { + .name = "RECORDING_INFO", + .read = recording_info_read, +}; + static int unload_module(void) { - return ast_unregister_application(app); + int res; + res = ast_custom_function_unregister(&acf_recording_info); + res |= ast_unregister_application(app); + return res; } static int load_module(void) { - return ast_register_application_xml(app, record_exec); + int res; + res = ast_register_application_xml(app, record_exec); + res |= ast_custom_function_register(&acf_recording_info); + return res; } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Trivial Record Application");