Asterisk - The Open Source Telephony Project GIT-master-d856a3e
res_stasis_snoop.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 * Joshua Colp <jcolp@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 Stasis application snoop control support.
22 *
23 * \author Joshua Colp <jcolp@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/module.h"
36#include "asterisk/audiohook.h"
37#include "asterisk/pbx.h"
38#include "asterisk/timing.h"
40#include "asterisk/json.h"
42
43/*! \brief The interval (in milliseconds) that the Snoop timer is triggered, also controls length of audio within frames */
44#define SNOOP_INTERVAL 20
45
46/*! \brief Index used to keep Snoop channel names unique */
47static unsigned int chan_idx;
48
49/*! \brief Structure which contains all of the snoop information */
51 /*! \brief Timer used for waking up Stasis thread */
53 /*! \brief Audiohook used to spy on the channel */
55 /*! \brief Direction for spying */
57 /*! \brief Number of samples to be read in when spying */
58 unsigned int spy_samples;
59 /*! \brief Format in use by the spy audiohook */
61 /*! \brief Audiohook used to whisper on the channel */
63 /*! \brief Direction for whispering */
65 /*! \brief Stasis application and arguments */
66 struct ast_str *app;
67 /*! \brief Snoop channel */
69 /*! \brief The channel that the Snoop channel is snooping on */
71 /*! \brief Whether the spy capability is active or not */
72 unsigned int spy_active:1;
73 /*! \brief Whether the whisper capability is active or not */
74 unsigned int whisper_active:1;
75 /*! \brief A frame of silence to use when the audiohook returns null */
77};
78
79/*! \brief Destructor for snoop structure */
80static void snoop_destroy(void *obj)
81{
82 struct stasis_app_snoop *snoop = obj;
83
84 if (snoop->timer) {
85 ast_timer_close(snoop->timer);
86 }
87
88 if (snoop->spy_active) {
90 }
91
92 if (snoop->whisper_active) {
94 }
95
96 if (snoop->silence.data.ptr) {
97 ast_free(snoop->silence.data.ptr);
98 snoop->silence.data.ptr = NULL;
99 }
100
101 ast_free(snoop->app);
102
105}
106
107/*! \internal
108 * \brief Publish the chanspy message over Stasis-Core
109 * \param snoop The snoop structure
110 * \param start If non-zero, the spying is starting. Otherwise, the spyer is
111 * finishing
112 */
113static void publish_chanspy_message(struct stasis_app_snoop *snoop, int start)
114{
115 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
116 RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
118 RAII_VAR(struct ast_channel_snapshot *, snoop_snapshot, NULL, ao2_cleanup);
119 RAII_VAR(struct ast_channel_snapshot *, spyee_snapshot, NULL, ao2_cleanup);
121
122 blob = ast_json_null();
123 if (!blob || !type) {
124 return;
125 }
126
127 payload = ast_multi_channel_blob_create(blob);
128 if (!payload) {
129 return;
130 }
131
133 if (!snoop_snapshot) {
134 return;
135 }
136 ast_multi_channel_blob_add_channel(payload, "spyer_channel", snoop_snapshot);
137
138 if (snoop->spyee_chan) {
142 if (spyee_snapshot) {
143 ast_multi_channel_blob_add_channel(payload, "spyee_channel", spyee_snapshot);
144 }
145 }
146
148 if (!message) {
149 return;
150 }
151
153}
154
155/*! \brief Callback function for writing to a Snoop whisper audiohook */
156static int snoop_write(struct ast_channel *chan, struct ast_frame *frame)
157{
159
160 if (!snoop->whisper_active) {
161 return 0;
162 }
163
168 } else {
170 }
172
173 return 0;
174}
175
176/*! \brief Callback function for reading from a Snoop channel */
177static struct ast_frame *snoop_read(struct ast_channel *chan)
178{
180 struct ast_frame *frame = NULL;
181
182 /* If we fail to ack the timer OR if any active audiohooks are done hangup */
183 if ((ast_timer_ack(snoop->timer, 1) < 0) ||
184 (snoop->spy_active && snoop->spy.status != AST_AUDIOHOOK_STATUS_RUNNING) ||
186 return NULL;
187 }
188
189 /* Only get audio from the spy audiohook if it is active */
190 if (!snoop->spy_active) {
191 return &ast_null_frame;
192 }
193
194 ast_audiohook_lock(&snoop->spy);
195
196 frame = ast_audiohook_read_frame(&snoop->spy, snoop->spy_samples, snoop->spy_direction, snoop->spy_format);
197
198 ast_audiohook_unlock(&snoop->spy);
199
200 return frame ? frame : &snoop->silence;
201}
202
203/*! \brief Callback function for hanging up a Snoop channel */
204static int snoop_hangup(struct ast_channel *chan)
205{
207
208 if (snoop->spy_active) {
209 ast_audiohook_lock(&snoop->spy);
210 ast_audiohook_detach(&snoop->spy);
211 ast_audiohook_unlock(&snoop->spy);
212 }
213
214 if (snoop->whisper_active) {
218 }
219
220 publish_chanspy_message(snoop, 0);
221
222 ao2_cleanup(snoop);
223
225
226 return 0;
227}
228
229static int snoop_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
230{
231 struct stasis_app_snoop *snoop = ast_channel_tech_pvt(oldchan);
232
233 if (snoop->chan != oldchan) {
234 return -1;
235 }
236
237 ast_channel_unref(snoop->chan);
238 ast_channel_ref(newchan);
239 snoop->chan = newchan;
240
241 return 0;
242}
243
244/*! \brief Channel interface declaration */
246 .type = "Snoop",
247 .description = "Snoop Channel Driver",
248 .write = snoop_write,
249 .read = snoop_read,
250 .hangup = snoop_hangup,
251 .fixup = snoop_fixup,
252};
253
254/*! \brief Thread used for running the Stasis application */
255static void *snoop_stasis_thread(void *obj)
256{
257 RAII_VAR(struct stasis_app_snoop *, snoop, obj, ao2_cleanup);
258
259 ast_pbx_exec_application(snoop->chan, "Stasis", ast_str_buffer(snoop->app));
260
261 ast_hangup(snoop->chan);
262
263 return NULL;
264}
265
266/*! \brief Internal helper function which sets up and attaches a snoop audiohook */
267static int snoop_setup_audiohook(struct ast_channel *chan, enum ast_audiohook_type type, enum stasis_app_snoop_direction requested_direction,
268 enum ast_audiohook_direction *direction, struct ast_audiohook *audiohook)
269{
270 ast_audiohook_init(audiohook, type, "Snoop", 0);
271
272 if (requested_direction == STASIS_SNOOP_DIRECTION_OUT) {
274 } else if (requested_direction == STASIS_SNOOP_DIRECTION_IN) {
276 } else if (requested_direction == STASIS_SNOOP_DIRECTION_BOTH) {
278 } else {
279 return -1;
280 }
281
282 /* Set the audiohook direction so we don't write unnecessary frames */
284 /* If we are unable to set direction, the audiohook either failed to init
285 or someone else started using it already. If we don't bail here, we risk
286 feeding frames that will never be read */
287 return -1;
288 }
289
290 return ast_audiohook_attach(chan, audiohook);
291}
292
293/*! \brief Helper function which gets the format for a Snoop channel based on the channel being snooped on */
294static void snoop_determine_format(struct ast_channel *chan, struct stasis_app_snoop *snoop)
295{
299
301}
302
305 const char *app, const char *app_args, const char *snoop_id)
306{
307 RAII_VAR(struct stasis_app_snoop *, snoop, NULL, ao2_cleanup);
308 struct ast_format_cap *caps;
309 pthread_t thread;
310 struct ast_assigned_ids assignedids = {
311 .uniqueid = snoop_id,
312 };
313
314 if (spy == STASIS_SNOOP_DIRECTION_NONE &&
315 whisper == STASIS_SNOOP_DIRECTION_NONE) {
316 return NULL;
317 }
318
320 if (!snoop) {
321 return NULL;
322 }
323
324 /* Allocate a buffer to store the Stasis application and arguments in */
325 snoop->app = ast_str_create(64);
326 if (!snoop->app) {
327 return NULL;
328 }
329
330 ast_str_set(&snoop->app, 0, "%s", app);
331 if (!ast_strlen_zero(app_args)) {
332 ast_str_append(&snoop->app, 0, ",%s", app_args);
333 }
334
335 /* Set up a timer for the Snoop channel so it wakes up at a specific interval */
336 snoop->timer = ast_timer_open();
337 if (!snoop->timer) {
338 return NULL;
339 }
340 ast_timer_set_rate(snoop->timer, 1000 / SNOOP_INTERVAL);
341
342 /* Determine which signed linear format should be used */
343 snoop_determine_format(chan, snoop);
344
345 /* Allocate a Snoop channel and set up various parameters */
346 snoop->chan = ast_channel_alloc(1, AST_STATE_UP, "", "", "", "", "", &assignedids, NULL, 0, "Snoop/%s-%08x", ast_channel_uniqueid(chan),
347 (unsigned)ast_atomic_fetchadd_int((int *)&chan_idx, +1));
348 if (!snoop->chan) {
349 return NULL;
350 }
351
352 /* To keep the channel valid on the Snoop structure until it is destroyed we bump the ref up here */
353 ast_channel_ref(snoop->chan);
354
355 ast_channel_tech_set(snoop->chan, &snoop_tech);
356 ao2_ref(snoop, +1);
357 ast_channel_tech_pvt_set(snoop->chan, snoop);
358 ast_channel_set_fd(snoop->chan, 0, ast_timer_fd(snoop->timer));
359
360 /* The format on the Snoop channel will be this signed linear format, and it will never change */
362 if (!caps) {
363 ast_channel_unlock(snoop->chan);
364 ast_hangup(snoop->chan);
365 return NULL;
366 }
367 ast_format_cap_append(caps, snoop->spy_format, 0);
368 ast_channel_nativeformats_set(snoop->chan, caps);
369 ao2_ref(caps, -1);
370
371 ast_channel_set_writeformat(snoop->chan, snoop->spy_format);
372 ast_channel_set_rawwriteformat(snoop->chan, snoop->spy_format);
373 ast_channel_set_readformat(snoop->chan, snoop->spy_format);
374 ast_channel_set_rawreadformat(snoop->chan, snoop->spy_format);
375
376 ast_channel_unlock(snoop->chan);
377
378 if (spy != STASIS_SNOOP_DIRECTION_NONE) {
379 if (snoop_setup_audiohook(chan, AST_AUDIOHOOK_TYPE_SPY, spy, &snoop->spy_direction, &snoop->spy)) {
380 ast_hangup(snoop->chan);
381 return NULL;
382 }
383
384 snoop->spy_samples = ast_format_get_sample_rate(snoop->spy_format) / (1000 / SNOOP_INTERVAL);
385 snoop->spy_active = 1;
386
387 snoop->silence.frametype = AST_FRAME_VOICE,
388 snoop->silence.datalen = snoop->spy_samples * sizeof(uint16_t),
389 snoop->silence.samples = snoop->spy_samples,
390 snoop->silence.mallocd = 0,
391 snoop->silence.offset = 0,
392 snoop->silence.src = __PRETTY_FUNCTION__,
393 snoop->silence.subclass.format = snoop->spy_format,
394 snoop->silence.data.ptr = ast_calloc(snoop->spy_samples, sizeof(uint16_t));
395 if (!snoop->silence.data.ptr) {
396 ast_hangup(snoop->chan);
397 return NULL;
398 }
399 }
400
401 /* If whispering is enabled set up the audiohook */
402 if (whisper != STASIS_SNOOP_DIRECTION_NONE) {
403 if (snoop_setup_audiohook(chan, AST_AUDIOHOOK_TYPE_WHISPER, whisper, &snoop->whisper_direction, &snoop->whisper)) {
404 ast_hangup(snoop->chan);
405 return NULL;
406 }
407
408 snoop->whisper_active = 1;
409 }
410
411 /* Create the thread which services the Snoop channel */
412 ao2_ref(snoop, +1);
414 ao2_cleanup(snoop);
415
416 /* No other thread is servicing this channel so we can immediately hang it up */
417 ast_hangup(snoop->chan);
418 return NULL;
419 }
420
421 /* Keep a reference to the channel we are spying on */
422 snoop->spyee_chan = ast_channel_ref(chan);
423
424 publish_chanspy_message(snoop, 1);
425
426 /* The caller of this has a reference as well */
427 return ast_channel_ref(snoop->chan);
428}
429
430static int load_module(void)
431{
433}
434
435static int unload_module(void)
436{
437 return 0;
438}
439
440AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Stasis application snoop support",
441 .support_level = AST_MODULE_SUPPORT_CORE,
442 .load = load_module,
443 .unload = unload_module,
444 .requires = "res_stasis",
static const char app[]
Definition: app_adsiprog.c:56
pthread_t thread
Definition: app_sla.c:329
ast_mutex_t lock
Definition: app_sla.c:331
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:404
Audiohooks Architecture.
int ast_audiohook_init(struct ast_audiohook *audiohook, enum ast_audiohook_type type, const char *source, enum ast_audiohook_init_flags flags)
Initialize an audiohook structure.
Definition: audiohook.c:100
struct ast_frame * ast_audiohook_read_frame(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, struct ast_format *format)
Reads a frame in from the audiohook structure.
Definition: audiohook.c:446
int ast_audiohook_write_frame(struct ast_audiohook *audiohook, enum ast_audiohook_direction direction, struct ast_frame *frame)
Writes a frame into the audiohook structure.
Definition: audiohook.c:167
ast_audiohook_direction
Definition: audiohook.h:48
@ AST_AUDIOHOOK_DIRECTION_READ
Definition: audiohook.h:49
@ AST_AUDIOHOOK_DIRECTION_WRITE
Definition: audiohook.h:50
@ AST_AUDIOHOOK_DIRECTION_BOTH
Definition: audiohook.h:51
#define ast_audiohook_lock(ah)
Lock an audiohook.
Definition: audiohook.h:313
int ast_audiohook_detach(struct ast_audiohook *audiohook)
Detach audiohook from channel.
Definition: audiohook.c:550
int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
Attach audiohook to channel.
Definition: audiohook.c:484
int ast_audiohook_destroy(struct ast_audiohook *audiohook)
Destroys an audiohook structure.
Definition: audiohook.c:124
#define ast_audiohook_unlock(ah)
Unlock an audiohook.
Definition: audiohook.h:318
ast_audiohook_type
Definition: audiohook.h:35
@ AST_AUDIOHOOK_TYPE_SPY
Definition: audiohook.h:36
@ AST_AUDIOHOOK_TYPE_WHISPER
Definition: audiohook.h:37
@ AST_AUDIOHOOK_STATUS_RUNNING
Definition: audiohook.h:43
int ast_audiohook_set_frame_feed_direction(struct ast_audiohook *audiohook, enum ast_audiohook_direction direction)
Sets direction on audiohook.
Definition: audiohook.c:150
static const char type[]
Definition: chan_ooh323.c:109
void * ast_channel_tech_pvt(const struct ast_channel *chan)
struct ast_format * ast_channel_rawreadformat(struct ast_channel *chan)
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2560
#define ast_channel_alloc(needqueue, state, cid_num, cid_name, acctcode, exten, context, assignedids, requestor, amaflag,...)
Create a channel structure.
Definition: channel.h:1299
void ast_channel_nativeformats_set(struct ast_channel *chan, struct ast_format_cap *value)
struct stasis_topic * ast_channel_topic(struct ast_channel *chan)
A topic which publishes the events for a particular channel.
#define ast_channel_lock(chan)
Definition: channel.h:2968
#define ast_channel_ref(c)
Increase channel reference count.
Definition: channel.h:2993
const char * ast_channel_uniqueid(const struct ast_channel *chan)
void ast_channel_set_rawreadformat(struct ast_channel *chan, struct ast_format *format)
void ast_channel_tech_pvt_set(struct ast_channel *chan, void *value)
struct ast_format * ast_channel_rawwriteformat(struct ast_channel *chan)
void ast_channel_set_rawwriteformat(struct ast_channel *chan, struct ast_format *format)
void ast_channel_set_readformat(struct ast_channel *chan, struct ast_format *format)
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:3004
void ast_channel_set_fd(struct ast_channel *chan, int which, int fd)
Definition: channel.c:2445
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition: channel.h:3015
void ast_channel_tech_set(struct ast_channel *chan, const struct ast_channel_tech *value)
#define ast_channel_unlock(chan)
Definition: channel.h:2969
void ast_channel_set_writeformat(struct ast_channel *chan, struct ast_format *format)
@ AST_STATE_UP
Definition: channelstate.h:42
unsigned int ast_format_get_sample_rate(const struct ast_format *format)
Get the sample rate of a media format.
Definition: format.c:379
Media Format Cache API.
struct ast_format * ast_format_cache_get_slin_by_rate(unsigned int rate)
Retrieve the best signed linear format given a sample rate.
Definition: format_cache.c:512
@ AST_FORMAT_CAP_FLAG_DEFAULT
Definition: format_cap.h:38
#define ast_format_cap_append(cap, format, framing)
Add format capability to capabilities structure.
Definition: format_cap.h:99
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition: format_cap.h:49
direction
struct ast_multi_channel_blob * ast_multi_channel_blob_create(struct ast_json *blob)
Create a ast_multi_channel_blob suitable for a stasis_message.
struct stasis_message_type * ast_channel_chanspy_start_type(void)
Message type for when a channel starts spying on another channel.
struct stasis_message_type * ast_channel_chanspy_stop_type(void)
Message type for when a channel stops spying on another channel.
struct ast_channel_snapshot * ast_channel_snapshot_get_latest(const char *uniqueid)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object,...
void ast_multi_channel_blob_add_channel(struct ast_multi_channel_blob *obj, const char *role, struct ast_channel_snapshot *snapshot)
Add a ast_channel_snapshot to a ast_multi_channel_blob object.
@ AST_FRAME_VOICE
struct ast_frame ast_null_frame
Definition: main/frame.c:79
Asterisk JSON abstraction layer.
struct ast_json * ast_json_null(void)
Get the JSON null value.
Definition: json.c:248
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:757
#define SCOPED_CHANNELLOCK(varname, chan)
scoped lock specialization for channels.
Definition: lock.h:619
Asterisk module definitions.
@ AST_MODFLAG_GLOBAL_SYMBOLS
Definition: module.h:330
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:557
@ 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
Core PBX routines and definitions.
int ast_pbx_exec_application(struct ast_channel *chan, const char *app_name, const char *app_args)
Execute an application.
Definition: pbx_app.c:501
static struct ast_frame * snoop_read(struct ast_channel *chan)
Callback function for reading from a Snoop channel.
static int snoop_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
struct ast_channel * stasis_app_control_snoop(struct ast_channel *chan, enum stasis_app_snoop_direction spy, enum stasis_app_snoop_direction whisper, const char *app, const char *app_args, const char *snoop_id)
Create a snoop on the provided channel.
static void publish_chanspy_message(struct stasis_app_snoop *snoop, int start)
static int snoop_setup_audiohook(struct ast_channel *chan, enum ast_audiohook_type type, enum stasis_app_snoop_direction requested_direction, enum ast_audiohook_direction *direction, struct ast_audiohook *audiohook)
Internal helper function which sets up and attaches a snoop audiohook.
static void snoop_destroy(void *obj)
Destructor for snoop structure.
static void * snoop_stasis_thread(void *obj)
Thread used for running the Stasis application.
static struct ast_channel_tech snoop_tech
Channel interface declaration.
static void snoop_determine_format(struct ast_channel *chan, struct stasis_app_snoop *snoop)
Helper function which gets the format for a Snoop channel based on the channel being snooped on.
static int load_module(void)
static int unload_module(void)
static int snoop_hangup(struct ast_channel *chan)
Callback function for hanging up a Snoop channel.
static unsigned int chan_idx
Index used to keep Snoop channel names unique.
static int snoop_write(struct ast_channel *chan, struct ast_frame *frame)
Callback function for writing to a Snoop whisper audiohook.
#define SNOOP_INTERVAL
The interval (in milliseconds) that the Snoop timer is triggered, also controls length of audio withi...
#define NULL
Definition: resample.c:96
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
Definition: stasis.c:1512
Backend API for implementing components of res_stasis.
Stasis Application Snoop API. See StasisApplication API" for detailed documentation.
stasis_app_snoop_direction
Directions for audio stream flow.
@ STASIS_SNOOP_DIRECTION_IN
Audio stream in from the channel.
@ STASIS_SNOOP_DIRECTION_OUT
Audio stream out to the channel.
@ STASIS_SNOOP_DIRECTION_NONE
No direction.
@ STASIS_SNOOP_DIRECTION_BOTH
Audio stream to AND from the channel.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
Structure to pass both assignedid values to channel drivers.
Definition: channel.h:606
const char * uniqueid
Definition: channel.h:607
enum ast_audiohook_status status
Definition: audiohook.h:108
Structure representing a snapshot of channel state.
Structure to describe a channel "technology", ie a channel driver See for examples:
Definition: channel.h:648
const char *const type
Definition: channel.h:649
Main Channel structure associated with a channel.
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
Definition of a media format.
Definition: format.c:43
Data structure associated with a single frame of data.
union ast_frame::@226 data
Abstract JSON element (object, array, string, int, ...).
A multi channel blob data structure for multi_channel_blob stasis messages.
Support for dynamic strings.
Definition: strings.h:623
Structure which contains all of the snoop information.
struct ast_format * spy_format
Format in use by the spy audiohook.
struct ast_str * app
Stasis application and arguments.
unsigned int spy_active
Whether the spy capability is active or not.
struct ast_audiohook spy
Audiohook used to spy on the channel.
unsigned int spy_samples
Number of samples to be read in when spying.
struct ast_audiohook whisper
Audiohook used to whisper on the channel.
enum ast_audiohook_direction whisper_direction
Direction for whispering.
struct ast_channel * chan
Snoop channel.
struct ast_channel * spyee_chan
The channel that the Snoop channel is snooping on.
struct ast_timer * timer
Timer used for waking up Stasis thread.
struct ast_frame silence
A frame of silence to use when the audiohook returns null.
unsigned int whisper_active
Whether the whisper capability is active or not.
enum ast_audiohook_direction spy_direction
Direction for spying.
Timing source management.
void ast_timer_close(struct ast_timer *handle)
Close an opened timing handle.
Definition: timing.c:154
int ast_timer_ack(const struct ast_timer *handle, unsigned int quantity)
Acknowledge a timer event.
Definition: timing.c:171
int ast_timer_set_rate(const struct ast_timer *handle, unsigned int rate)
Set the timing tick rate.
Definition: timing.c:166
struct ast_timer * ast_timer_open(void)
Open a timer.
Definition: timing.c:122
int ast_timer_fd(const struct ast_timer *handle)
Get a poll()-able file descriptor for a timer.
Definition: timing.c:161
#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:941
#define ast_pthread_create_detached_background(a, b, c, d)
Definition: utils.h:597
#define MAX(a, b)
Definition: utils.h:233