Asterisk - The Open Source Telephony Project GIT-master-70eff7f
Loading...
Searching...
No Matches
res_stasis_recording.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2013, Digium, Inc.
5 *
6 * David M. Lee, II <dlee@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*! \file
20 *
21 * \brief res_stasis recording support.
22 *
23 * \author David M. Lee, II <dlee@digium.com>
24 */
25
26/*** MODULEINFO
27 <depend type="module">res_stasis</depend>
28 <support_level>core</support_level>
29 ***/
30
31#include "asterisk.h"
32
33#include "asterisk/dsp.h"
34#include "asterisk/file.h"
35#include "asterisk/module.h"
36#include "asterisk/paths.h"
37#include "asterisk/bridge.h"
41
42/*! Number of hash buckets for recording container. Keep it prime! */
43#define RECORDING_BUCKETS 127
44
45/*! Comment is ignored by most formats, so we will ignore it, too. */
46#define RECORDING_COMMENT NULL
47
48/*! Recording check is unimplemented. le sigh */
49#define RECORDING_CHECK 0
50
51/*! Container of all current recordings */
53
55 /*! Recording options. */
57 /*! Absolute path (minus extension) of the recording */
59 /*! Control object for the channel we're recording */
61 /*! Current state of the recording. */
63 /*! Duration calculations */
64 struct {
65 /*! Total duration */
66 int total;
67 /*! Duration minus any silence */
70 /*! Indicates whether the recording is currently muted */
71 int muted:1;
72};
73
75 const struct stasis_message_sanitizer *sanitize)
76{
77 struct ast_channel_blob *channel_blob = stasis_message_data(message);
78 struct ast_json *blob = channel_blob->blob;
79 const char *state =
81 const char *type;
82
83 if (!strcmp(state, "recording")) {
84 type = "RecordingStarted";
85 } else if (!strcmp(state, "done") || !strcasecmp(state, "canceled")) {
86 type = "RecordingFinished";
87 } else if (!strcmp(state, "failed")) {
88 type = "RecordingFailed";
89 } else {
90 return NULL;
91 }
92
93 return ast_json_pack("{s: s, s: o?, s: O}",
94 "type", type,
96 "recording", blob);
97}
98
100 .to_json = recording_to_json,
101);
102
103static int recording_hash(const void *obj, int flags)
104{
105 const struct stasis_app_recording *recording = obj;
106 const char *id = flags & OBJ_KEY ? obj : recording->options->name;
107 return ast_str_hash(id);
108}
109
110static int recording_cmp(void *obj, void *arg, int flags)
111{
112 struct stasis_app_recording *lhs = obj;
113 struct stasis_app_recording *rhs = arg;
114 const char *rhs_id = flags & OBJ_KEY ? arg : rhs->options->name;
115
116 if (strcmp(lhs->options->name, rhs_id) == 0) {
117 return CMP_MATCH | CMP_STOP;
118 } else {
119 return 0;
120 }
121}
122
124{
125 switch (state) {
127 return "queued";
129 return "recording";
131 return "paused";
133 return "done";
135 return "failed";
137 return "canceled";
139 return "?";
140 }
141
142 return "?";
143}
144
145static void recording_options_dtor(void *obj)
146{
148
150}
151
169
171{
172 if (ast_strlen_zero(str)) {
174 }
175
176 if (strcasecmp(str, "none") == 0) {
178 }
179
180 if (strcasecmp(str, "any") == 0) {
182 }
183
184 if (strcasecmp(str, "#") == 0) {
185 return '#';
186 }
187
188 if (strcasecmp(str, "*") == 0) {
189 return '*';
190 }
191
193}
194
196 const char *str)
197{
198 if (ast_strlen_zero(str)) {
199 /* Default value */
201 }
202
203 if (strcasecmp(str, "fail") == 0) {
205 }
206
207 if (strcasecmp(str, "overwrite") == 0) {
209 }
210
211 if (strcasecmp(str, "append") == 0) {
213 }
214
216}
217
218static void recording_publish(struct stasis_app_recording *recording, const char *cause)
219{
220 RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
222
223 ast_assert(recording != NULL);
224
225 json = stasis_app_recording_to_json(recording);
226 if (json == NULL) {
227 return;
228 }
229
230 if (!ast_strlen_zero(cause)) {
231 struct ast_json *failure_cause = ast_json_string_create(cause);
232
233 if (!failure_cause) {
234 return;
235 }
236
237 if (ast_json_object_set(json, "cause", failure_cause)) {
238 return;
239 }
240 }
241
245 if (message == NULL) {
246 return;
247 }
248
250}
251
252
253static void recording_set_state(struct stasis_app_recording *recording,
255 const char *cause)
256{
257 SCOPED_AO2LOCK(lock, recording);
258 recording->state = state;
259 recording_publish(recording, cause);
260}
261
267
268/*
269 * XXX This only works because there is one and only one rule in
270 * the system so it can be added to any number of channels
271 * without issue. However, as soon as there is another rule then
272 * watch out for weirdness because of cross linked lists.
273 */
277
278static void recording_fail(struct stasis_app_control *control,
279 struct stasis_app_recording *recording,
280 const char *cause)
281{
283
285 recording, STASIS_APP_RECORDING_STATE_FAILED, cause);
286}
287
288static void recording_cleanup(void *data)
289{
290 struct stasis_app_recording *recording = data;
291
292 ao2_unlink_flags(recordings, recording,
294 ao2_ref(recording, -1);
295}
296
298 struct ast_channel *chan, void *data)
299{
300 struct stasis_app_recording *recording = data;
301 struct ast_bridge *bridge;
302 char *acceptdtmf;
303 int res;
304
305 ast_assert(recording != NULL);
306
307 /*
308 * Recording is not allowed while the channel is in a "real" bridge,
309 * but ARI places an originated channel into an internal, invisible
310 * holding bridge (the dial bridge) while dialing. That bridge is not
311 * a bridge the application created - it is flagged invisible - so
312 * recording must still be permitted there. Otherwise, channels.record
313 * fails with "Cannot record channel while in bridge" even though the
314 * application never joined the channel to a bridge of its own.
315 * See GH issue #2044.
316 */
317 bridge = stasis_app_get_bridge(control);
318 if (bridge && !ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_INVISIBLE)) {
319 ast_log(LOG_ERROR, "Cannot record channel while in bridge\n");
320 recording_fail(control, recording, "Cannot record channel while in bridge");
321 return -1;
322 }
323
324 switch (recording->options->terminate_on) {
327 acceptdtmf = "";
328 break;
330 acceptdtmf = "#*0123456789abcd";
331 break;
332 default:
333 acceptdtmf = ast_alloca(2);
334 acceptdtmf[0] = recording->options->terminate_on;
335 acceptdtmf[1] = '\0';
336 }
337
338 res = ast_auto_answer(chan);
339 if (res != 0) {
340 ast_debug(3, "%s: Failed to answer\n",
342 recording_fail(control, recording, "Failed to answer channel");
343 return -1;
344 }
345
349 NULL, /* playfile */
350 recording->absolute_name,
351 recording->options->max_duration_seconds,
352 recording->options->format,
353 &recording->duration.total,
354 recording->options->max_silence_seconds ? &recording->duration.energy_only : NULL,
355 recording->options->beep,
356 -1, /* silencethreshold */
357 recording->options->max_silence_seconds * 1000,
358 NULL, /* path */
359 acceptdtmf,
360 NULL, /* canceldtmf */
361 1, /* skip_confirmation_sound */
362 recording->options->if_exists);
363
364 ast_debug(3, "%s: Recording complete\n", ast_channel_uniqueid(chan));
365
368
370
371 return 0;
372}
373
374static void recording_dtor(void *obj)
375{
376 struct stasis_app_recording *recording = obj;
377
378 ast_free(recording->absolute_name);
379 ao2_cleanup(recording->control);
380 ao2_cleanup(recording->options);
381}
382
386{
387 struct stasis_app_recording *recording;
388 char *last_slash;
389
390 errno = 0;
391
392 if (options == NULL ||
393 ast_strlen_zero(options->name) ||
394 ast_strlen_zero(options->format) ||
395 options->max_silence_seconds < 0 ||
396 options->max_duration_seconds < 0) {
397 errno = EINVAL;
398 return NULL;
399 }
400
401 ast_debug(3, "%s: Sending record(%s.%s) command\n",
403 options->format);
404
405 recording = ao2_alloc(sizeof(*recording), recording_dtor);
406 if (!recording) {
407 errno = ENOMEM;
408 return NULL;
409 }
410 recording->duration.total = -1;
411 recording->duration.energy_only = -1;
412
413 ast_asprintf(&recording->absolute_name, "%s/%s",
415
416 if (recording->absolute_name == NULL) {
417 errno = ENOMEM;
418 ao2_ref(recording, -1);
419 return NULL;
420 }
421
422 if ((last_slash = strrchr(recording->absolute_name, '/'))) {
423 *last_slash = '\0';
425 recording->absolute_name, 0777) != 0) {
426 /* errno set by ast_mkdir */
427 ao2_ref(recording, -1);
428 return NULL;
429 }
430 *last_slash = '/';
431 }
432
433 ao2_ref(options, +1);
434 recording->options = options;
435 ao2_ref(control, +1);
436 recording->control = control;
438
439 if ((recording->options->if_exists == AST_RECORD_IF_EXISTS_FAIL) &&
440 (ast_fileexists(recording->absolute_name, NULL, NULL))) {
441 ast_log(LOG_WARNING, "Recording file '%s' already exists and ifExists option is failure.\n",
442 recording->absolute_name);
443 errno = EEXIST;
444 ao2_ref(recording, -1);
445 return NULL;
446 }
447
448 {
449 RAII_VAR(struct stasis_app_recording *, old_recording, NULL,
451
453
454 old_recording = ao2_find(recordings, options->name,
456 if (old_recording) {
458 "Recording %s already in progress\n",
459 recording->options->name);
460 errno = EEXIST;
461 ao2_ref(recording, -1);
462 return NULL;
463 }
464 ao2_link(recordings, recording);
465 }
466
468
470
471 return recording;
472}
473
475 struct stasis_app_recording *recording)
476{
477 return recording->state;
478}
479
481 struct stasis_app_recording *recording)
482{
483 return recording->options->name;
484}
485
490
492 const struct stasis_app_recording *recording)
493{
494 RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
495
496 if (recording == NULL) {
497 return NULL;
498 }
499
500 json = ast_json_pack("{s: s, s: s, s: s, s: s}",
501 "name", recording->options->name,
502 "format", recording->options->format,
503 "state", state_to_string(recording->state),
504 "target_uri", recording->options->target);
505 if (json && recording->duration.total > -1) {
506 ast_json_object_set(json, "duration",
508 }
509 if (json && recording->duration.energy_only > -1) {
510 ast_json_object_set(json, "talking_duration",
512 ast_json_object_set(json, "silence_duration",
514 }
515
516 return ast_json_ref(json);
517}
518
519typedef int (*recording_operation_cb)(struct stasis_app_recording *recording);
520
521static int recording_noop(struct stasis_app_recording *recording)
522{
523 return 0;
524}
525
526static int recording_disregard(struct stasis_app_recording *recording)
527{
529 return 0;
530}
531
532static int recording_cancel(struct stasis_app_recording *recording)
533{
534 int res = 0;
538 res |= ast_filedelete(recording->absolute_name, NULL);
539 return res;
540}
541
542static int recording_stop(struct stasis_app_recording *recording)
543{
547}
548
555
562
563static int toggle_recording_mute(struct stasis_app_recording *recording, int desired_mute_state)
564{
565 if (recording->muted == desired_mute_state) {
566 /* already in desired state */
567 return 0;
568 }
569
570 recording->muted = desired_mute_state;
571
574}
575
576static int recording_mute(struct stasis_app_recording *recording)
577{
578 return toggle_recording_mute(recording, 1);
579}
580
581static int recording_unmute(struct stasis_app_recording *recording)
582{
583 return toggle_recording_mute(recording, 0);
584}
585
602
604 struct stasis_app_recording *recording,
606{
608 SCOPED_AO2LOCK(lock, recording);
609
610 if ((unsigned int)recording->state >= STASIS_APP_RECORDING_STATE_MAX) {
611 ast_log(LOG_WARNING, "Invalid recording state %u\n",
612 recording->state);
613 return -1;
614 }
615
616 if ((unsigned int)operation >= STASIS_APP_RECORDING_OPER_MAX) {
617 ast_log(LOG_WARNING, "Invalid recording operation %u\n",
618 operation);
619 return -1;
620 }
621
622 cb = operations[recording->state][operation];
623
624 if (!cb) {
626 /* So we can be specific in our error message. */
628 } else {
629 /* And, really, all operations should be valid during
630 * recording */
632 "Unhandled operation during recording: %u\n",
633 operation);
635 }
636 }
637
638 return cb(recording) ?
640}
641
659
667
669 .support_level = AST_MODULE_SUPPORT_CORE,
670 .load = load_module,
671 .unload = unload_module,
672 .requires = "res_stasis",
673 .load_pri = AST_MODPRI_APP_DEPEND
const char * str
Definition app_jack.c:150
ast_mutex_t lock
Definition app_sla.c:337
Asterisk main include file. File version handling, generic pbx functions.
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition astmm.h:288
#define ast_free(a)
Definition astmm.h:180
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition astmm.h:267
#define ast_log
Definition astobj2.c:42
#define ao2_link(container, obj)
Add an object to a container.
Definition astobj2.h:1532
@ CMP_MATCH
Definition astobj2.h:1027
@ CMP_STOP
Definition astobj2.h:1028
#define OBJ_KEY
Definition astobj2.h:1151
#define OBJ_POINTER
Definition astobj2.h:1150
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition astobj2.h:363
#define ao2_cleanup(obj)
Definition astobj2.h:1934
#define ao2_unlink_flags(container, obj, flags)
Remove an object from a container.
Definition astobj2.h:1600
#define ao2_find(container, arg, flags)
Definition astobj2.h:1736
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition astobj2.h:480
@ OBJ_NOLOCK
Assume that the ao2_container is already locked.
Definition astobj2.h:1063
@ OBJ_NODATA
Definition astobj2.h:1044
@ OBJ_UNLINK
Definition astobj2.h:1039
#define ao2_alloc(data_size, destructor_fn)
Definition astobj2.h:409
#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.
Definition astobj2.h:1303
Bridging API.
@ AST_BRIDGE_FLAG_INVISIBLE
static const char type[]
int ast_auto_answer(struct ast_channel *chan)
Answer a channel, if it's not already answered.
Definition channel.c:2811
const char * ast_channel_uniqueid(const struct ast_channel *chan)
Convenient Signal Processing routines.
Generic File Format Support. Should be included by clients of the file handling routines....
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition file.c:1156
int ast_filedelete(const char *filename, const char *fmt)
Deletes a file.
Definition file.c:1168
static const char name[]
Definition format_mp3.c:68
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.
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...
Definition main/app.c:2150
@ AST_RECORD_IF_EXISTS_FAIL
@ AST_RECORD_IF_EXISTS_APPEND
@ AST_RECORD_IF_EXISTS_OVERWRITE
@ AST_RECORD_IF_EXISTS_ERROR
@ AST_CONTROL_RECORD_CANCEL
@ AST_CONTROL_RECORD_STOP
@ AST_CONTROL_RECORD_MUTE
@ AST_CONTROL_RECORD_SUSPEND
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define LOG_WARNING
struct ast_json * ast_json_string_create(const char *value)
Construct a JSON string from value.
Definition json.c:278
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition json.c:73
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition json.c:612
struct ast_json * ast_json_timeval(const struct timeval tv, const char *zone)
Construct a timeval as JSON.
Definition json.c:670
struct ast_json * ast_json_integer_create(intmax_t value)
Create a JSON integer.
Definition json.c:327
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Definition json.c:67
int ast_json_object_set(struct ast_json *object, const char *key, struct ast_json *value)
Set a field in a JSON object.
Definition json.c:414
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition json.c:283
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition json.c:407
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
Definition lock.h:611
int errno
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition module.h:331
@ AST_MODFLAG_GLOBAL_SYMBOLS
Definition module.h:330
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition module.h:557
@ AST_MODPRI_APP_DEPEND
Definition module.h:342
@ AST_MODULE_SUPPORT_CORE
Definition module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition module.h:78
Asterisk file paths, configured in asterisk.conf.
const char * ast_config_AST_RECORDING_DIR
Definition options.c:157
struct stasis_app_recording_options * stasis_app_recording_options_create(const char *name, const char *format)
Allocate a recording options object.
static void recording_cleanup(void *data)
static int recording_unpause(struct stasis_app_recording *recording)
static int recording_pause(struct stasis_app_recording *recording)
static struct ast_json * recording_to_json(struct stasis_message *message, const struct stasis_message_sanitizer *sanitize)
static int recording_noop(struct stasis_app_recording *recording)
struct ast_json * stasis_app_recording_to_json(const struct stasis_app_recording *recording)
Construct a JSON model of a recording.
static void recording_options_dtor(void *obj)
static void recording_dtor(void *obj)
static int recording_disregard(struct stasis_app_recording *recording)
enum stasis_app_recording_state stasis_app_recording_get_state(struct stasis_app_recording *recording)
Gets the current state of a recording operation.
static int recording_hash(const void *obj, int flags)
static int recording_mute(struct stasis_app_recording *recording)
static int recording_unmute(struct stasis_app_recording *recording)
static int record_file(struct stasis_app_control *control, struct ast_channel *chan, void *data)
struct stasis_app_recording * stasis_app_recording_find_by_name(const char *name)
Finds the recording object with the given name.
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(* recording_operation_cb)(struct stasis_app_recording *recording)
#define RECORDING_BUCKETS
recording_operation_cb operations[STASIS_APP_RECORDING_STATE_MAX][STASIS_APP_RECORDING_OPER_MAX]
static struct stasis_app_control_rule rule_recording
static enum stasis_app_control_channel_result check_rule_recording(const struct stasis_app_control *control)
struct stasis_app_recording * stasis_app_control_record(struct stasis_app_control *control, struct stasis_app_recording_options *options)
Record media from a channel.
static struct ao2_container * recordings
static int recording_cmp(void *obj, void *arg, int flags)
enum ast_record_if_exists stasis_app_recording_if_exists_parse(const char *str)
Parse a string into the if_exists enum.
static int toggle_recording_mute(struct stasis_app_recording *recording, int desired_mute_state)
char stasis_app_recording_termination_parse(const char *str)
Parse a string into the recording termination enum.
static int load_module(void)
static void recording_fail(struct stasis_app_control *control, struct stasis_app_recording *recording, const char *cause)
static int recording_stop(struct stasis_app_recording *recording)
static void recording_set_state(struct stasis_app_recording *recording, enum stasis_app_recording_state state, const char *cause)
static int unload_module(void)
const char * stasis_app_recording_get_name(struct stasis_app_recording *recording)
Gets the unique name of a recording object.
static const char * state_to_string(enum stasis_app_recording_state state)
static int recording_cancel(struct stasis_app_recording *recording)
static void recording_publish(struct stasis_app_recording *recording, const char *cause)
#define NULL
Definition resample.c:96
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition stasis.h:1546
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition stasis.h:1524
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
#define STASIS_MESSAGE_TYPE_DEFN(name,...)
Boiler-plate messaging macro for defining public message types.
Definition stasis.h:1471
const struct timeval * stasis_message_timestamp(const struct stasis_message *msg)
Get the time when a message was created.
const char * stasis_app_control_get_channel_id(const struct stasis_app_control *control)
Returns the uniqueid of the channel associated with this control.
Definition control.c:1503
int stasis_app_control_queue_control(struct stasis_app_control *control, enum ast_control_frame_type frame_type)
Queue a control frame without payload.
Definition control.c:1518
void stasis_app_control_publish(struct stasis_app_control *control, struct stasis_message *message)
Publish a message to the control's channel's topic.
Definition control.c:1509
struct ast_bridge * stasis_app_get_bridge(struct stasis_app_control *control)
Gets the bridge currently associated with a control object.
Definition control.c:993
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.
Definition control.c:232
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.
Definition control.c:225
stasis_app_control_channel_result
Result codes used when adding/removing channels to/from bridges.
Definition stasis_app.h:837
@ STASIS_APP_CHANNEL_RECORDING
Definition stasis_app.h:841
Backend API for implementing components of res_stasis.
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().
Definition control.c:966
Stasis Application Recording API. See StasisApplication API" for detailed documentation.
struct stasis_message_type * stasis_app_recording_snapshot_type(void)
Message type for recording updates. The data is an ast_channel_blob.
#define STASIS_APP_RECORDING_TERMINATE_NONE
#define STASIS_APP_RECORDING_TERMINATE_ANY
stasis_app_recording_oper_results
Possible results from a recording operation.
@ STASIS_APP_RECORDING_OPER_NOT_RECORDING
@ STASIS_APP_RECORDING_OPER_FAILED
@ STASIS_APP_RECORDING_OPER_OK
stasis_app_recording_state
@ STASIS_APP_RECORDING_STATE_CANCELED
@ STASIS_APP_RECORDING_STATE_FAILED
@ STASIS_APP_RECORDING_STATE_COMPLETE
@ STASIS_APP_RECORDING_STATE_RECORDING
@ STASIS_APP_RECORDING_STATE_PAUSED
@ STASIS_APP_RECORDING_STATE_QUEUED
@ STASIS_APP_RECORDING_STATE_MAX
#define STASIS_APP_RECORDING_TERMINATE_INVALID
stasis_app_recording_media_operation
@ STASIS_APP_RECORDING_PAUSE
@ STASIS_APP_RECORDING_UNPAUSE
@ STASIS_APP_RECORDING_UNMUTE
@ STASIS_APP_RECORDING_STOP
@ STASIS_APP_RECORDING_OPER_MAX
@ STASIS_APP_RECORDING_MUTE
@ STASIS_APP_RECORDING_CANCEL
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition strings.h:1259
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
Generic container type.
Structure that contains information about a bridge.
Definition bridge.h:355
struct ast_flags feature_flags
Definition bridge.h:375
Blob of data associated with a channel.
struct ast_json * blob
Main Channel structure associated with a channel.
Abstract JSON element (object, array, string, int, ...).
Rule to check to see if an operation is allowed.
Definition stasis_app.h:355
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.
Definition stasis_app.h:362
enum ast_record_if_exists if_exists
struct stasis_app_recording::@521 duration
struct stasis_app_recording_options * options
enum stasis_app_recording_state state
struct stasis_app_control * control
Structure containing callbacks for Stasis message sanitization.
Definition stasis.h:200
static struct test_options options
#define ast_test_flag(p, flag)
Definition utils.h:64
#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
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.
Definition utils.c:2618
#define ast_assert(a)
Definition utils.h:779