mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-31 02:37:10 +00:00 
			
		
		
		
	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 47250b716c)
			
			
This commit is contained in:
		
				
					committed by
					
						 George Joseph
						George Joseph
					
				
			
			
				
	
			
			
			
						parent
						
							6d2e05da56
						
					
				
				
					commit
					5863873d10
				
			| @@ -119,8 +119,32 @@ | ||||
| 				</variable> | ||||
| 			</variablelist> | ||||
| 		</description> | ||||
| 		<see-also> | ||||
| 			<ref type="function">RECORDING_INFO</ref> | ||||
| 		</see-also> | ||||
| 	</application> | ||||
|  | ||||
| 	<function name="RECORDING_INFO" language="en_US"> | ||||
| 		<synopsis> | ||||
| 			Retrieve information about a recording previously created using the Record application | ||||
| 		</synopsis> | ||||
| 		<syntax> | ||||
| 			<parameter name="property" required="true"> | ||||
| 				<para>The property about the recording to retrieve.</para> | ||||
| 				<enumlist> | ||||
| 					<enum name="duration"> | ||||
| 						<para>The duration, in milliseconds, of the recording.</para> | ||||
| 					</enum> | ||||
| 				</enumlist> | ||||
| 			</parameter> | ||||
| 		</syntax> | ||||
| 		<description> | ||||
| 			<para>Returns information about the previous recording created by <literal>Record</literal>. | ||||
| 			This function cannot be used if no recordings have yet been completed.</para> | ||||
| 		</description> | ||||
| 		<see-also> | ||||
| 			<ref type="application">Record</ref> | ||||
| 		</see-also> | ||||
| 	</function> | ||||
|  ***/ | ||||
|  | ||||
| #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"); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user