39 #include "asterisk/stasis_channels.h"
42 #define RECORDING_BUCKETS 127
45 #define RECORDING_COMMENT NULL
48 #define RECORDING_CHECK 0
82 if (!strcmp(state,
"recording")) {
83 type =
"RecordingStarted";
84 }
else if (!strcmp(state,
"done") || !strcasecmp(state,
"canceled")) {
85 type =
"RecordingFinished";
86 }
else if (!strcmp(state,
"failed")) {
87 type =
"RecordingFailed";
99 .to_json = recording_to_json,
102 static int recording_hash(
const void *obj,
int flags)
109 static int recording_cmp(
void *obj,
void *arg,
int flags)
144 static void recording_options_dtor(
void *obj)
157 options = ao2_alloc(
sizeof(*options), recording_options_dtor);
171 if (ast_strlen_zero(str)) {
172 return STASIS_APP_RECORDING_TERMINATE_NONE;
175 if (strcasecmp(str,
"none") == 0) {
176 return STASIS_APP_RECORDING_TERMINATE_NONE;
179 if (strcasecmp(str,
"any") == 0) {
180 return STASIS_APP_RECORDING_TERMINATE_ANY;
183 if (strcasecmp(str,
"#") == 0) {
187 if (strcasecmp(str,
"*") == 0) {
191 return STASIS_APP_RECORDING_TERMINATE_INVALID;
197 if (ast_strlen_zero(str)) {
202 if (strcasecmp(str,
"fail") == 0) {
206 if (strcasecmp(str,
"overwrite") == 0) {
210 if (strcasecmp(str,
"append") == 0) {
222 ast_assert(recording != NULL);
229 if (!ast_strlen_zero(cause)) {
232 if (!failure_cause) {
244 if (message == NULL) {
257 recording->
state = state;
258 recording_publish(recording, cause);
287 static void recording_cleanup(
void *data)
303 ast_assert(recording != NULL);
306 ast_log(LOG_ERROR,
"Cannot record channel while in bridge\n");
307 recording_fail(control, recording,
"Cannot record channel while in bridge");
312 case STASIS_APP_RECORDING_TERMINATE_NONE:
313 case STASIS_APP_RECORDING_TERMINATE_INVALID:
316 case STASIS_APP_RECORDING_TERMINATE_ANY:
317 acceptdtmf =
"#*0123456789abcd";
322 acceptdtmf[1] =
'\0';
328 ast_channel_uniqueid(chan));
329 recording_fail(control, recording,
"Failed to answer channel");
351 ast_debug(3,
"%s: Recording complete\n", ast_channel_uniqueid(chan));
361 static void recording_dtor(
void *obj)
366 ao2_cleanup(recording->
control);
367 ao2_cleanup(recording->
options);
379 if (options == NULL ||
380 ast_strlen_zero(options->
name) ||
381 ast_strlen_zero(options->
format) ||
388 ast_debug(3,
"%s: Sending record(%s.%s) command\n",
392 recording = ao2_alloc(
sizeof(*recording), recording_dtor);
401 ast_config_AST_RECORDING_DIR, options->
name);
428 ast_log(LOG_WARNING,
"Recording file '%s' already exists and ifExists option is failure.\n",
441 old_recording = ao2_find(recordings, options->
name,
445 "Recording %s already in progress\n",
464 return recording->
state;
475 return ao2_find(recordings, name,
OBJ_KEY);
483 if (recording == NULL) {
490 "state", state_to_string(recording->
state),
550 static int toggle_recording_mute(
struct stasis_app_recording *recording,
int desired_mute_state)
552 if (recording->
muted == desired_mute_state) {
557 recording->
muted = desired_mute_state;
565 return toggle_recording_mute(recording, 1);
570 return toggle_recording_mute(recording, 0);
594 recording_operation_cb cb;
598 ast_log(LOG_WARNING,
"Invalid recording state %u\n",
604 ast_log(LOG_WARNING,
"Invalid recording operation %u\n",
609 cb = operations[recording->
state][operation];
619 "Unhandled operation during recording: %u\n",
625 return cb(recording) ?
629 static int load_module(
void)
639 recording_hash, NULL, recording_cmp);
647 static int unload_module(
void)
649 ao2_cleanup(recordings);
655 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER,
"Stasis application recording support",
656 .support_level = AST_MODULE_SUPPORT_CORE,
658 .unload = unload_module,
659 .requires =
"res_stasis",
struct stasis_app_recording::@488 duration
struct ast_bridge * stasis_app_get_bridge(struct stasis_app_control *control)
Gets the bridge currently associated with a control object.
enum stasis_app_control_channel_result(* check_rule)(const struct stasis_app_control *control)
Checks to see if an operation is allowed on the control.
void stasis_app_control_publish(struct stasis_app_control *control, struct stasis_message *message)
Publish a message to the control's channel's topic.
Stasis Application Recording API. See StasisApplication API" for detailed documentation.
Main Channel structure associated with a channel.
enum stasis_app_recording_state state
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Asterisk main include file. File version handling, generic pbx functions.
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
stasis_app_recording_media_operation
int ast_auto_answer(struct ast_channel *chan)
Answer a channel, if it's not already answered.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
playback_operation_cb operations[STASIS_PLAYBACK_STATE_MAX][STASIS_PLAYBACK_MEDIA_OP_MAX]
A sparse array detailing how commands should be handled in the various playback states. Unset entries imply invalid operations.
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Convenient Signal Processing routines.
struct stasis_app_control * control
#define RECORDING_BUCKETS
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Assume that the ao2_container is already locked.
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
char stasis_app_recording_termination_parse(const char *str)
Parse a string into the recording termination enum.
int ast_filedelete(const char *filename, const char *fmt)
Deletes a file.
Structure containing callbacks for Stasis message sanitization.
int ast_json_object_set(struct ast_json *object, const char *key, struct ast_json *value)
Set a field in a JSON object.
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Blob of data associated with a channel.
const ast_string_field target
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
void stasis_app_control_register_add_rule(struct stasis_app_control *control, struct stasis_app_control_rule *rule)
Registers an add channel to bridge rule.
const char * stasis_app_recording_get_name(struct stasis_app_recording *recording)
Gets the unique name of a recording object.
stasis_app_control_channel_result
Result codes used when adding/removing channels to/from bridges.
Asterisk file paths, configured in asterisk.conf.
struct ast_json * ast_json_string_create(const char *value)
Construct a JSON string from value.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
const struct timeval * stasis_message_timestamp(const struct stasis_message *msg)
Get the time when a message was created.
struct stasis_app_recording_options * stasis_app_recording_options_create(const char *name, const char *format)
Allocate a recording options object.
int ast_play_and_record_full(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime_sec, const char *fmt, int *duration, int *sound_duration, int beep, int silencethreshold, int maxsilence_ms, const char *path, const char *acceptdtmf, const char *canceldtmf, int skip_confirmation_sound, enum ast_record_if_exists if_exists)
Record a file based on input from a channel This function will play "auth-thankyou" upon successful r...
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
int stasis_app_send_command_async(struct stasis_app_control *control, stasis_app_command_cb command, void *data, command_data_destructor_fn data_destructor)
Asynchronous version of stasis_app_send_command().
#define ast_debug(level,...)
Log a DEBUG message.
const ast_string_field name
Rule to check to see if an operation is allowed.
struct stasis_app_recording * stasis_app_control_record(struct stasis_app_control *control, struct stasis_app_recording_options *options)
Record media from a channel.
struct ast_json * ast_json_timeval(const struct timeval tv, const char *zone)
Construct a timeval as JSON.
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
struct stasis_app_recording_options * options
#define STASIS_MESSAGE_TYPE_DEFN(name,...)
Boiler-plate messaging macro for defining public message types.
struct stasis_app_recording * stasis_app_recording_find_by_name(const char *name)
Finds the recording object with the given name.
Backend API for implementing components of res_stasis.
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
const char * stasis_app_control_get_channel_id(const struct stasis_app_control *control)
Returns the uniqueid of the channel associated with this control.
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
enum stasis_app_recording_state stasis_app_recording_get_state(struct stasis_app_recording *recording)
Gets the current state of a recording operation.
stasis_app_recording_oper_results
Possible results from a recording operation.
struct stasis_message_type * stasis_app_recording_snapshot_type(void)
Message type for recording updates. The data is an ast_channel_blob.
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
int ast_safe_mkdir(const char *base_path, const char *path, int mode)
Recursively create directory path, but only if it resolves within the given base_path.
Module has failed to load, may be in an inconsistent state.
void stasis_app_control_unregister_add_rule(struct stasis_app_control *control, struct stasis_app_control_rule *rule)
UnRegister an add channel to bridge rule.
stasis_app_recording_state
struct stasis_message * ast_channel_blob_create_from_cache(const char *uniqueid, struct stasis_message_type *type, struct ast_json *blob)
Create a ast_channel_blob message, pulling channel state from the cache.
struct ast_json * stasis_app_recording_to_json(const struct stasis_app_recording *recording)
Construct a JSON model of a recording.
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
enum ast_record_if_exists if_exists
enum ast_record_if_exists stasis_app_recording_if_exists_parse(const char *str)
Parse a string into the if_exists enum.
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
enum stasis_app_recording_oper_results stasis_app_recording_operation(struct stasis_app_recording *recording, enum stasis_app_recording_media_operation operation)
Controls the media for a given recording operation.
int stasis_app_control_queue_control(struct stasis_app_control *control, enum ast_control_frame_type frame_type)
Queue a control frame without payload.
#define ao2_unlink_flags(container, obj, flags)
Remove an object from a container.
Abstract JSON element (object, array, string, int, ...).
const ast_string_field format
#define ASTERISK_GPL_KEY
The text the key() function should return.
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_string_field_free_memory(x)
free all memory - to be called before destroying the object
static struct ao2_container * recordings
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
struct ast_json * ast_json_integer_create(intmax_t value)
Create a JSON integer.
#define ao2_link(container, obj)
Add an object to a container.