Asterisk - The Open Source Telephony Project GIT-master-a358458
res_stasis_playback.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 playback support.
22 *
23 * \author David M. Lee, II <dlee@digium.com>
24 */
25
26/*** MODULEINFO
27 <depend type="module">res_stasis</depend>
28 <depend type="module">res_stasis_recording</depend>
29 <support_level>core</support_level>
30 ***/
31
32#include "asterisk.h"
33
34#include "asterisk/app.h"
35#include "asterisk/astobj2.h"
36#include "asterisk/bridge.h"
38#include "asterisk/file.h"
39#include "asterisk/logger.h"
40#include "asterisk/module.h"
41#include "asterisk/paths.h"
47#include "asterisk/uuid.h"
48#include "asterisk/say.h"
50
51/*! Number of hash buckets for playback container. Keep it prime! */
52#define PLAYBACK_BUCKETS 127
53
54/*! Default number of milliseconds of media to skip */
55#define PLAYBACK_DEFAULT_SKIPMS 3000
56
57#define SOUND_URI_SCHEME "sound:"
58#define RECORDING_URI_SCHEME "recording:"
59#define NUMBER_URI_SCHEME "number:"
60#define DIGITS_URI_SCHEME "digits:"
61#define CHARACTERS_URI_SCHEME "characters:"
62#define TONE_URI_SCHEME "tone:"
63
64/*! Container of all current playbacks */
65static struct ao2_container *playbacks;
66
67/*! Playback control object for res_stasis */
70 AST_STRING_FIELD(id); /*!< Playback unique id */
71 AST_STRING_FIELD(media); /*!< The current media playing */
72 AST_STRING_FIELD(language); /*!< Preferred language */
73 AST_STRING_FIELD(target); /*!< Playback device uri */
74 );
75 /*! The list of medias to play back */
76 AST_VECTOR(, char *) medias;
77
78 /*! The current index in \c medias we're playing */
80
81 /*! Control object for the channel we're playing back to */
83 /*! Number of milliseconds to skip before playing */
85 /*! Number of milliseconds to skip for forward/reverse operations */
86 int skipms;
87 /*! Number of milliseconds of media that has been played */
89 /*! Current playback state */
91 /*! Set when the playback can be controlled */
92 unsigned int controllable:1;
93};
94
96 const struct stasis_message_sanitizer *sanitize)
97{
98 struct ast_channel_blob *channel_blob = stasis_message_data(message);
99 struct ast_json *blob = channel_blob->blob;
100 const char *state =
102 const char *type;
103
104 if (!strcmp(state, "playing")) {
105 type = "PlaybackStarted";
106 } else if (!strcmp(state, "continuing")) {
107 type = "PlaybackContinuing";
108 } else if (!strcmp(state, "done")) {
109 type = "PlaybackFinished";
110 } else if (!strcmp(state, "failed")) {
111 type = "PlaybackFinished";
112 } else {
113 return NULL;
114 }
115
116 return ast_json_pack("{s: s, s: o?, s: O}",
117 "type", type,
119 "playback", blob);
120}
121
123 .to_json = playback_to_json,
124);
125
126static void playback_dtor(void *obj)
127{
128 struct stasis_app_playback *playback = obj;
129 int i;
130
131 for (i = 0; i < AST_VECTOR_SIZE(&playback->medias); i++) {
132 char *media = AST_VECTOR_GET(&playback->medias, i);
133
135 }
136 AST_VECTOR_FREE(&playback->medias);
137
138 ao2_cleanup(playback->control);
140}
141
143 struct stasis_app_control *control, const char *id)
144{
145 RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
146 char uuid[AST_UUID_STR_LEN];
147
148 if (!control) {
149 return NULL;
150 }
151
152 playback = ao2_alloc(sizeof(*playback), playback_dtor);
153 if (!playback || ast_string_field_init(playback, 128)) {
154 return NULL;
155 }
156
157 if (AST_VECTOR_INIT(&playback->medias, 8)) {
158 ao2_ref(playback, -1);
159 return NULL;
160 }
161
162 if (!ast_strlen_zero(id)) {
163 ast_string_field_set(playback, id, id);
164 } else {
165 ast_uuid_generate_str(uuid, sizeof(uuid));
166 ast_string_field_set(playback, id, uuid);
167 }
168
169 ao2_ref(control, +1);
170 playback->control = control;
171
172 ao2_ref(playback, +1);
173 return playback;
174}
175
176static int playback_hash(const void *obj, int flags)
177{
178 const struct stasis_app_playback *playback = obj;
179 const char *id = flags & OBJ_KEY ? obj : playback->id;
180 return ast_str_hash(id);
181}
182
183static int playback_cmp(void *obj, void *arg, int flags)
184{
185 struct stasis_app_playback *lhs = obj;
186 struct stasis_app_playback *rhs = arg;
187 const char *rhs_id = flags & OBJ_KEY ? arg : rhs->id;
188
189 if (strcmp(lhs->id, rhs_id) == 0) {
190 return CMP_MATCH | CMP_STOP;
191 } else {
192 return 0;
193 }
194}
195
197{
198 switch (state) {
200 return "queued";
202 return "playing";
204 return "paused";
206 return "continuing";
208 return "failed";
212 /* It doesn't really matter how we got here, but all of these
213 * states really just mean 'done' */
214 return "done";
216 break;
217 }
218
219 return "?";
220}
221
222static void playback_publish(struct stasis_app_playback *playback)
223{
224 RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
226
227 ast_assert(playback != NULL);
228
229 json = stasis_app_playback_to_json(playback);
230 if (json == NULL) {
231 return;
232 }
233
237 if (message == NULL) {
238 return;
239 }
240
242}
243
244static int playback_first_update(struct stasis_app_playback *playback,
245 const char *uniqueid)
246{
247 int res;
248 SCOPED_AO2LOCK(lock, playback);
249
250 if (playback->state == STASIS_PLAYBACK_STATE_CANCELED) {
251 ast_log(LOG_NOTICE, "%s: Playback canceled for %s\n",
252 uniqueid, playback->media);
253 res = -1;
254 } else {
255 res = 0;
257 }
258
259 playback_publish(playback);
260 return res;
261}
262
263static void playback_final_update(struct stasis_app_playback *playback,
264 long playedms, int res, int hangup, const char *uniqueid)
265{
266 SCOPED_AO2LOCK(lock, playback);
267
268 playback->playedms = playedms;
269 if (res == 0) {
270 if (playback->media_index == AST_VECTOR_SIZE(&playback->medias) - 1 || hangup ) {
272 } else {
274 }
275 } else {
276 if (playback->state == STASIS_PLAYBACK_STATE_STOPPED) {
277 ast_log(LOG_NOTICE, "%s: Playback stopped for %s\n",
278 uniqueid, playback->media);
279 } else {
280 ast_log(LOG_WARNING, "%s: Playback failed for %s\n",
281 uniqueid, playback->media);
282 if (playback->media_index == AST_VECTOR_SIZE(&playback->medias) - 1 || hangup ) {
284 } else {
286 }
287 }
288 }
289
290 playback_publish(playback);
291}
292
293static void play_on_channel(struct stasis_app_playback *playback,
294 struct ast_channel *chan)
295{
296 int res;
297 int hangup;
298 long offsetms;
299 size_t index;
300
301 /* Even though these local variables look fairly pointless, they avoid
302 * having a bunch of NULL's passed directly into
303 * ast_control_streamfile() */
304 const char *fwd = NULL;
305 const char *rev = NULL;
306 const char *stop = NULL;
307 const char *pause = NULL;
308 const char *restart = NULL;
309
310 ast_assert(playback != NULL);
311
312 if (ast_channel_state(chan) != AST_STATE_UP) {
314 }
315
316 offsetms = playback->offsetms;
317
318 for (index = 0; index < AST_VECTOR_SIZE(&playback->medias); index++) {
319 playback->media_index = index;
320
321 /* Set the current media to play */
322 ast_string_field_set(playback, media, AST_VECTOR_GET(&playback->medias, playback->media_index));
323
324 res = playback_first_update(playback, ast_channel_uniqueid(chan));
325 if (res != 0) {
326 return;
327 }
328
329 if (ast_begins_with(playback->media, SOUND_URI_SCHEME)) {
330 playback->controllable = 1;
331
332 /* Play sound */
333 res = ast_control_streamfile_lang(chan, playback->media + strlen(SOUND_URI_SCHEME),
334 fwd, rev, stop, pause, restart, playback->skipms, playback->language,
335 &offsetms);
336 } else if (ast_begins_with(playback->media, RECORDING_URI_SCHEME)) {
337 /* Play recording */
338 RAII_VAR(struct stasis_app_stored_recording *, recording, NULL,
340 const char *relname =
341 playback->media + strlen(RECORDING_URI_SCHEME);
342 recording = stasis_app_stored_recording_find_by_name(relname);
343
344 if (!recording) {
345 ast_log(LOG_ERROR, "Attempted to play recording '%s' on channel '%s' but recording does not exist",
346 relname, ast_channel_name(chan));
347 continue;
348 }
349
350 playback->controllable = 1;
351
353 stasis_app_stored_recording_get_file(recording), fwd, rev, stop, pause,
354 restart, playback->skipms, playback->language, &offsetms);
355 } else if (ast_begins_with(playback->media, NUMBER_URI_SCHEME)) {
356 int number;
357
358 if (sscanf(playback->media + strlen(NUMBER_URI_SCHEME), "%30d", &number) != 1) {
359 ast_log(LOG_ERROR, "Attempted to play number '%s' on channel '%s' but number is invalid",
360 playback->media + strlen(NUMBER_URI_SCHEME), ast_channel_name(chan));
361 continue;
362 }
363
364 res = ast_say_number(chan, number, stop, playback->language, NULL);
365 } else if (ast_begins_with(playback->media, DIGITS_URI_SCHEME)) {
366 res = ast_say_digit_str(chan, playback->media + strlen(DIGITS_URI_SCHEME),
367 stop, playback->language);
368 } else if (ast_begins_with(playback->media, CHARACTERS_URI_SCHEME)) {
369 res = ast_say_character_str(chan, playback->media + strlen(CHARACTERS_URI_SCHEME),
370 stop, playback->language, AST_SAY_CASE_NONE);
371 } else if (ast_begins_with(playback->media, TONE_URI_SCHEME)) {
372 playback->controllable = 1;
373 res = ast_control_tone(chan, playback->media + strlen(TONE_URI_SCHEME));
374 } else {
375 /* Play URL */
376 ast_log(LOG_ERROR, "Attempted to play URI '%s' on channel '%s' but scheme is unsupported\n",
377 playback->media, ast_channel_name(chan));
378 continue;
379 }
380
381 hangup = ast_check_hangup(chan);
382
383 playback_final_update(playback, offsetms, res, hangup,
385
386 if (hangup) {
387 ast_log(LOG_DEBUG, "Channel: %s already hangup, stop playback\n", ast_channel_name(chan));
388 break;
389 }
390
391 if (res == AST_CONTROL_STREAM_STOP) {
392 break;
393 }
394
395 /* Reset offset for any subsequent media */
396 offsetms = 0;
397 }
398 return;
399}
400
401/*!
402 * \brief Special case code to play while a channel is in a bridge.
403 *
404 * \param bridge_channel The channel's bridge_channel.
405 * \param playback_id Id of the playback to start.
406 */
407static void play_on_channel_in_bridge(struct ast_bridge_channel *bridge_channel,
408 const char *playback_id)
409{
410 RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
411
412 playback = stasis_app_playback_find_by_id(playback_id);
413 if (!playback) {
414 ast_log(LOG_ERROR, "Couldn't find playback %s\n",
415 playback_id);
416 return;
417 }
418
419 play_on_channel(playback, bridge_channel->chan);
420}
421
422/*!
423 * \brief \ref RAII_VAR function to remove a playback from the global list when
424 * leaving scope.
425 */
426static void remove_from_playbacks(void *data)
427{
428 struct stasis_app_playback *playback = data;
429
430 ao2_unlink_flags(playbacks, playback,
432 ao2_ref(playback, -1);
433}
434
436 struct ast_channel *chan, void *data)
437{
438 struct stasis_app_playback *playback = data;
439 struct ast_bridge *bridge;
440
441 if (!control) {
442 return -1;
443 }
444
445 bridge = stasis_app_get_bridge(control);
446 if (bridge) {
447 struct ast_bridge_channel *bridge_chan;
448
449 /* Queue up playback on the bridge */
451 bridge_chan = ao2_bump(bridge_find_channel(bridge, chan));
453 if (bridge_chan) {
455 bridge_chan,
457 playback->id,
458 NULL); /* moh_class */
459 }
460 ao2_cleanup(bridge_chan);
461 } else {
462 play_on_channel(playback, chan);
463 }
464
465 return 0;
466}
467
468static void set_target_uri(
469 struct stasis_app_playback *playback,
470 enum stasis_app_playback_target_type target_type,
471 const char *target_id)
472{
473 const char *type = NULL;
474 switch (target_type) {
476 type = "channel";
477 break;
479 type = "bridge";
480 break;
481 }
482
483 ast_assert(type != NULL);
484
485 ast_string_field_build(playback, target, "%s:%s", type, target_id);
486}
487
489 struct stasis_app_control *control, const char **media,
490 size_t media_count, const char *language, const char *target_id,
491 enum stasis_app_playback_target_type target_type,
492 int skipms, long offsetms, const char *id)
493{
494 struct stasis_app_playback *playback;
495 size_t i;
496
497 if (skipms < 0 || offsetms < 0 || media_count == 0) {
498 return NULL;
499 }
500
501 playback = playback_create(control, id);
502 if (!playback) {
503 return NULL;
504 }
505
506 for (i = 0; i < media_count; i++) {
507 char *media_uri;
508
509 if (ast_strlen_zero(media[i])) {
510 ast_log(LOG_ERROR, "Attempted to play media on channel '%s' but no media URI was provided.\n",
512 ao2_ref(playback, -1);
513 return NULL;
514 }
515
516 media_uri = ast_malloc(strlen(media[i]) + 1);
517 if (!media_uri) {
518 ao2_ref(playback, -1);
519 return NULL;
520 }
521
522 ast_debug(3, "%s: Sending play(%s) command\n",
524
525 /* safe */
526 strcpy(media_uri, media[i]);
527 if (AST_VECTOR_APPEND(&playback->medias, media_uri)) {
528 ao2_ref(playback, -1);
529 ast_free(media_uri);
530 return NULL;
531 }
532 }
533
534 if (skipms == 0) {
536 }
537
538 ast_string_field_set(playback, media, AST_VECTOR_GET(&playback->medias, 0));
540 set_target_uri(playback, target_type, target_id);
541 playback->skipms = skipms;
542 playback->offsetms = offsetms;
543 ao2_link(playbacks, playback);
544
546 playback_publish(playback);
547
549
550 return playback;
551}
552
555{
557 return control->state;
558}
559
562{
563 /* id is immutable; no lock needed */
564 return control->id;
565}
566
568{
569 return ao2_find(playbacks, id, OBJ_KEY);
570}
571
573 const struct stasis_app_playback *playback)
574{
575 RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
576
577 if (playback == NULL) {
578 return NULL;
579 }
580
581 if (playback->media_index == AST_VECTOR_SIZE(&playback->medias) - 1) {
582 json = ast_json_pack("{s: s, s: s, s: s, s: s, s: s}",
583 "id", playback->id,
584 "media_uri", playback->media,
585 "target_uri", playback->target,
586 "language", playback->language,
587 "state", state_to_string(playback->state));
588 } else {
589 json = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s}",
590 "id", playback->id,
591 "media_uri", playback->media,
592 "next_media_uri", AST_VECTOR_GET(&playback->medias, playback->media_index + 1),
593 "target_uri", playback->target,
594 "language", playback->language,
595 "state", state_to_string(playback->state));
596 }
597
598 return ast_json_ref(json);
599}
600
601typedef int (*playback_operation_cb)(struct stasis_app_playback *playback);
602
603static int playback_noop(struct stasis_app_playback *playback)
604{
605 return 0;
606}
607
608static int playback_cancel(struct stasis_app_playback *playback)
609{
610 SCOPED_AO2LOCK(lock, playback);
612 return 0;
613}
614
615static int playback_stop(struct stasis_app_playback *playback)
616{
617 SCOPED_AO2LOCK(lock, playback);
618
619 if (!playback->controllable) {
620 return -1;
621 }
622
626}
627
628static int playback_restart(struct stasis_app_playback *playback)
629{
630 SCOPED_AO2LOCK(lock, playback);
631
632 if (!playback->controllable) {
633 return -1;
634 }
635
638}
639
640static int playback_pause(struct stasis_app_playback *playback)
641{
642 SCOPED_AO2LOCK(lock, playback);
643
644 if (!playback->controllable) {
645 return -1;
646 }
647
649 playback_publish(playback);
650
653}
654
655static int playback_unpause(struct stasis_app_playback *playback)
656{
657 SCOPED_AO2LOCK(lock, playback);
658
659 if (!playback->controllable) {
660 return -1;
661 }
662
664 playback_publish(playback);
665
668}
669
670static int playback_reverse(struct stasis_app_playback *playback)
671{
672 SCOPED_AO2LOCK(lock, playback);
673
674 if (!playback->controllable) {
675 return -1;
676 }
677
680}
681
682static int playback_forward(struct stasis_app_playback *playback)
683{
684 SCOPED_AO2LOCK(lock, playback);
685
686 if (!playback->controllable) {
687 return -1;
688 }
689
692}
693
694/*!
695 * \brief A sparse array detailing how commands should be handled in the
696 * various playback states. Unset entries imply invalid operations.
697 */
701
708
715
719
724};
725
727 struct stasis_app_playback *playback,
729{
731 SCOPED_AO2LOCK(lock, playback);
732
733 ast_assert((unsigned int)playback->state < STASIS_PLAYBACK_STATE_MAX);
734
735 if (operation >= STASIS_PLAYBACK_MEDIA_OP_MAX) {
736 ast_log(LOG_ERROR, "Invalid playback operation %u\n", operation);
737 return -1;
738 }
739
740 cb = operations[playback->state][operation];
741
742 if (!cb) {
743 if (playback->state != STASIS_PLAYBACK_STATE_PLAYING) {
744 /* So we can be specific in our error message. */
746 } else {
747 /* And, really, all operations should be valid during
748 * playback */
750 "Unhandled operation during playback: %u\n",
751 operation);
753 }
754 }
755
756 return cb(playback) ?
758}
759
760static int load_module(void)
761{
762 int r;
763
765 if (r != 0) {
767 }
768
771 if (!playbacks) {
774 }
776}
777
778static int unload_module(void)
779{
781 playbacks = NULL;
783 return 0;
784}
785
786AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Stasis application playback support",
787 .support_level = AST_MODULE_SUPPORT_CORE,
788 .load = load_module,
789 .unload = unload_module,
790 .requires = "res_stasis,res_stasis_recording"
unsigned int stop
Definition: app_sla.c:336
ast_mutex_t lock
Definition: app_sla.c:331
static int skipms
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
#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_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.
#define ast_bridge_unlock(bridge)
Unlock the bridge.
Definition: bridge.h:481
#define ast_bridge_lock(bridge)
Lock the bridge.
Definition: bridge.h:470
int ast_bridge_channel_queue_playfile_sync(struct ast_bridge_channel *bridge_channel, ast_bridge_custom_play_fn custom_play, const char *playfile, const char *moh_class)
Synchronously queue a bridge action play file frame onto the bridge channel.
Private Bridging API.
struct ast_bridge_channel * bridge_find_channel(struct ast_bridge *bridge, struct ast_channel *chan)
Definition: bridge.c:1429
static char language[MAX_LANGUAGE]
Definition: chan_iax2.c:324
static const char type[]
Definition: chan_ooh323.c:109
static int hangup(void *data)
Definition: chan_pjsip.c:2516
const char * ast_channel_name(const struct ast_channel *chan)
const char * ast_channel_uniqueid(const struct ast_channel *chan)
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:445
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4277
ast_channel_state
ast_channel states
Definition: channelstate.h:35
@ AST_STATE_UP
Definition: channelstate.h:42
Generic File Format Support. Should be included by clients of the file handling routines....
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.
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
int ast_control_tone(struct ast_channel *chan, const char *tone)
Controls playback of a tone.
Definition: main/app.c:1545
int ast_control_streamfile_lang(struct ast_channel *chan, const char *file, const char *fwd, const char *rev, const char *stop, const char *suspend, const char *restart, int skipms, const char *lang, long *offsetms)
Version of ast_control_streamfile() which allows the language of the media file to be specified.
Definition: main/app.c:1473
@ AST_CONTROL_PROGRESS
@ AST_CONTROL_STREAM_RESTART
@ AST_CONTROL_STREAM_SUSPEND
@ AST_CONTROL_STREAM_REVERSE
@ AST_CONTROL_STREAM_STOP
@ AST_CONTROL_STREAM_FORWARD
Support for logging to various files, console and syslog Configuration in file logger....
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_DEBUG
#define LOG_ERROR
#define LOG_NOTICE
#define LOG_WARNING
Tone Indication Support.
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_ref(struct ast_json *value)
Increase refcount on value.
Definition: json.c:67
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:604
Asterisk module definitions.
@ AST_MODFLAG_GLOBAL_SYMBOLS
Definition: module.h:316
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:543
@ 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.
struct stasis_app_playback * stasis_app_playback_find_by_id(const char *id)
Finds the playback object with the given id.
static struct ast_json * playback_to_json(struct stasis_message *message, const struct stasis_message_sanitizer *sanitize)
STASIS_MESSAGE_TYPE_DEFN(stasis_app_playback_snapshot_type,.to_json=playback_to_json,)
static struct ao2_container * playbacks
#define NUMBER_URI_SCHEME
static int playback_forward(struct stasis_app_playback *playback)
static int playback_first_update(struct stasis_app_playback *playback, const char *uniqueid)
int(* playback_operation_cb)(struct stasis_app_playback *playback)
static int playback_restart(struct stasis_app_playback *playback)
static int playback_unpause(struct stasis_app_playback *playback)
static int playback_cmp(void *obj, void *arg, int flags)
static int playback_hash(const void *obj, int flags)
static void play_on_channel(struct stasis_app_playback *playback, struct ast_channel *chan)
#define PLAYBACK_DEFAULT_SKIPMS
#define RECORDING_URI_SCHEME
struct stasis_app_playback * stasis_app_control_play_uri(struct stasis_app_control *control, const char **media, size_t media_count, const char *language, const char *target_id, enum stasis_app_playback_target_type target_type, int skipms, long offsetms, const char *id)
Play a file to the control's channel.
static struct stasis_app_playback * playback_create(struct stasis_app_control *control, const char *id)
static int playback_cancel(struct stasis_app_playback *playback)
struct ast_json * stasis_app_playback_to_json(const struct stasis_app_playback *playback)
Convert a playback to its JSON representation.
static int play_uri(struct stasis_app_control *control, struct ast_channel *chan, void *data)
static void set_target_uri(struct stasis_app_playback *playback, enum stasis_app_playback_target_type target_type, const char *target_id)
static void playback_final_update(struct stasis_app_playback *playback, long playedms, int res, int hangup, const char *uniqueid)
const char * stasis_app_playback_get_id(struct stasis_app_playback *control)
Gets the unique id of a playback object.
static void remove_from_playbacks(void *data)
RAII_VAR function to remove a playback from the global list when leaving scope.
static int playback_pause(struct stasis_app_playback *playback)
static int playback_noop(struct stasis_app_playback *playback)
static const char * state_to_string(enum stasis_app_playback_state state)
#define CHARACTERS_URI_SCHEME
#define TONE_URI_SCHEME
#define DIGITS_URI_SCHEME
#define SOUND_URI_SCHEME
static int load_module(void)
static void playback_dtor(void *obj)
enum stasis_playback_oper_results stasis_app_playback_operation(struct stasis_app_playback *playback, enum stasis_app_playback_media_operation operation)
Controls the media for a given playback operation.
static int unload_module(void)
#define PLAYBACK_BUCKETS
enum stasis_app_playback_state stasis_app_playback_get_state(struct stasis_app_playback *control)
Gets the current state of a playback operation.
static int playback_reverse(struct stasis_app_playback *playback)
static void playback_publish(struct stasis_app_playback *playback)
static int playback_stop(struct stasis_app_playback *playback)
static void play_on_channel_in_bridge(struct ast_bridge_channel *bridge_channel, const char *playback_id)
Special case code to play while a channel is in a bridge.
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....
#define NULL
Definition: resample.c:96
Say numbers and dates (maybe words one day too)
int ast_say_character_str(struct ast_channel *chan, const char *num, const char *ints, const char *lang, enum ast_say_case_sensitivity sensitivity)
function to pronounce character and phonetic strings
Definition: channel.c:8271
int ast_say_number(struct ast_channel *chan, int num, const char *ints, const char *lang, const char *options)
says a number
Definition: channel.c:8235
@ AST_SAY_CASE_NONE
Definition: say.h:182
int ast_say_digit_str(struct ast_channel *chan, const char *num, const char *ints, const char *lang)
says digits of a string
Definition: channel.c:8259
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition: stasis.h:1515
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition: stasis.h:1493
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
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:1450
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:1465
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:1456
struct ast_bridge * stasis_app_get_bridge(struct stasis_app_control *control)
Gets the bridge currently associated with a control object.
Definition: control.c:951
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:924
Stasis Application Playback API. See StasisApplication API" for detailed documentation.
stasis_app_playback_target_type
@ STASIS_PLAYBACK_TARGET_BRIDGE
@ STASIS_PLAYBACK_TARGET_CHANNEL
stasis_playback_oper_results
@ STASIS_PLAYBACK_OPER_NOT_PLAYING
@ STASIS_PLAYBACK_OPER_FAILED
@ STASIS_PLAYBACK_OPER_OK
stasis_app_playback_state
@ STASIS_PLAYBACK_STATE_STOPPED
@ STASIS_PLAYBACK_STATE_MAX
@ STASIS_PLAYBACK_STATE_FAILED
@ STASIS_PLAYBACK_STATE_COMPLETE
@ STASIS_PLAYBACK_STATE_CONTINUING
@ STASIS_PLAYBACK_STATE_PAUSED
@ STASIS_PLAYBACK_STATE_PLAYING
@ STASIS_PLAYBACK_STATE_CANCELED
@ STASIS_PLAYBACK_STATE_QUEUED
struct stasis_message_type * stasis_app_playback_snapshot_type(void)
Message type for playback updates. The data is an ast_channel_blob.
stasis_app_playback_media_operation
@ STASIS_PLAYBACK_RESTART
@ STASIS_PLAYBACK_FORWARD
@ STASIS_PLAYBACK_MEDIA_OP_MAX
@ STASIS_PLAYBACK_REVERSE
@ STASIS_PLAYBACK_UNPAUSE
@ STASIS_PLAYBACK_PAUSE
@ STASIS_PLAYBACK_STOP
Stasis Application Recording API. See StasisApplication API" for detailed documentation.
const char * stasis_app_stored_recording_get_file(struct stasis_app_stored_recording *recording)
Returns the filename for this recording, for use with streamfile.
Definition: stored.c:53
struct stasis_app_stored_recording * stasis_app_stored_recording_find_by_name(const char *name)
Creates a stored recording object, with the given name.
Definition: stored.c:318
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:341
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:303
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_string_field_build(x, field, fmt, args...)
Set a field to a complex (built) value.
Definition: stringfields.h:555
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
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
static int force_inline attribute_pure ast_begins_with(const char *str, const char *prefix)
Checks whether a string begins with another.
Definition: strings.h:97
Generic container type.
Structure that contains information regarding a channel in a bridge.
struct ast_bridge * bridge
Bridge this channel is participating in.
struct ast_channel * chan
Structure that contains information about a bridge.
Definition: bridge.h:349
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, ...).
Number structure.
Definition: app_followme.c:154
const ast_string_field language
const ast_string_field media
const ast_string_field id
enum stasis_app_playback_state state
struct stasis_app_playback::@479 medias
const ast_string_field target
struct stasis_app_control * control
Structure containing callbacks for Stasis message sanitization.
Definition: stasis.h:200
#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_assert(a)
Definition: utils.h:739
Universally unique identifier support.
#define AST_UUID_STR_LEN
Definition: uuid.h:27
char * ast_uuid_generate_str(char *buf, size_t size)
Generate a UUID string.
Definition: uuid.c:141
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
#define AST_VECTOR(name, type)
Define a vector structure.
Definition: vector.h:44
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680