45 #include "asterisk/stasis_channels.h"
52 #define PLAYBACK_BUCKETS 127
55 #define PLAYBACK_DEFAULT_SKIPMS 3000
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:"
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";
123 .to_json = playback_to_json,
126 static void playback_dtor(
void *obj)
138 ao2_cleanup(playback->
control);
146 char uuid[AST_UUID_STR_LEN];
152 playback = ao2_alloc(
sizeof(*playback), playback_dtor);
162 if (!ast_strlen_zero(
id)) {
176 static int playback_hash(
const void *obj,
int flags)
179 const char *
id = flags &
OBJ_KEY ? obj : playback->
id;
183 static int playback_cmp(
void *obj,
void *arg,
int flags)
187 const char *rhs_id = flags &
OBJ_KEY ? arg : rhs->
id;
189 if (strcmp(lhs->
id, rhs_id) == 0) {
227 ast_assert(playback != NULL);
245 const char *uniqueid)
251 ast_log(LOG_NOTICE,
"%s: Playback canceled for %s\n",
252 uniqueid, playback->
media);
259 playback_publish(playback);
264 long playedms,
int res,
int hangup,
const char *uniqueid)
277 ast_log(LOG_NOTICE,
"%s: Playback stopped for %s\n",
278 uniqueid, playback->
media);
280 ast_log(LOG_WARNING,
"%s: Playback failed for %s\n",
281 uniqueid, playback->
media);
290 playback_publish(playback);
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;
310 ast_assert(playback != NULL);
324 res = playback_first_update(playback, ast_channel_uniqueid(chan));
334 fwd, rev, stop, pause, restart, playback->
skipms, playback->
language,
340 const char *relname =
341 playback->
media + strlen(RECORDING_URI_SCHEME);
345 ast_log(LOG_ERROR,
"Attempted to play recording '%s' on channel '%s' but recording does not exist",
346 relname, ast_channel_name(chan));
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));
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));
383 playback_final_update(playback, offsetms, res, hangup,
384 ast_channel_uniqueid(chan));
387 ast_log(LOG_DEBUG,
"Channel: %s already hangup, stop playback\n", ast_channel_name(chan));
408 const char *playback_id)
414 ast_log(LOG_ERROR,
"Couldn't find playback %s\n",
419 play_on_channel(playback, bridge_channel->
chan);
451 bridge_chan =
ao2_bump(bridge_find_channel(bridge, chan));
460 ao2_cleanup(bridge_chan);
462 play_on_channel(playback, chan);
468 static void set_target_uri(
471 const char *target_id)
473 const char *type = NULL;
474 switch (target_type) {
483 ast_assert(type != NULL);
490 size_t media_count,
const char *
language,
const char *target_id,
492 int skipms,
long offsetms,
const char *
id)
497 if (skipms < 0 || offsetms < 0 || media_count == 0) {
501 playback = playback_create(control,
id);
506 for (i = 0; i < media_count; i++) {
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",
522 ast_debug(3,
"%s: Sending play(%s) command\n",
526 strcpy(media_uri, media[i]);
540 set_target_uri(playback, target_type, target_id);
546 playback_publish(playback);
557 return control->
state;
569 return ao2_find(playbacks,
id,
OBJ_KEY);
577 if (playback == NULL) {
584 "media_uri", playback->
media,
585 "target_uri", playback->
target,
587 "state", state_to_string(playback->
state));
591 "media_uri", playback->
media,
593 "target_uri", playback->
target,
595 "state", state_to_string(playback->
state));
649 playback_publish(playback);
664 playback_publish(playback);
730 playback_operation_cb cb;
736 ast_log(LOG_ERROR,
"Invalid playback operation %u\n", operation);
740 cb = operations[playback->
state][operation];
745 return STASIS_PLAYBACK_OPER_NOT_PLAYING;
750 "Unhandled operation during playback: %u\n",
752 return STASIS_PLAYBACK_OPER_FAILED;
756 return cb(playback) ?
757 STASIS_PLAYBACK_OPER_FAILED : STASIS_PLAYBACK_OPER_OK;
760 static int load_module(
void)
770 playback_hash, NULL, playback_cmp);
778 static int unload_module(
void)
780 ao2_cleanup(playbacks);
786 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS,
"Stasis application playback support",
787 .support_level = AST_MODULE_SUPPORT_CORE,
789 .unload = unload_module,
790 .requires =
"res_stasis,res_stasis_recording"
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
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.
struct ast_bridge * stasis_app_get_bridge(struct stasis_app_control *control)
Gets the bridge currently associated with a control object.
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.
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_playback_target_type
stasis_app_playback_media_operation
unsigned int controllable
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...
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
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.
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.
static struct ao2_container * playbacks
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Universally unique identifier support.
const char * stasis_app_stored_recording_get_file(struct stasis_app_stored_recording *recording)
Returns the filename for this recording, for use with streamfile.
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
int ast_say_digit_str(struct ast_channel *chan, const char *num, const char *ints, const char *lang)
says digits of a string
int ast_control_tone(struct ast_channel *chan, const char *tone)
Controls playback of a tone.
ast_channel_state
ast_channel states
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
enum stasis_app_playback_state stasis_app_playback_get_state(struct stasis_app_playback *control)
Gets the current state of a playback operation.
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
#define PLAYBACK_DEFAULT_SKIPMS
Structure containing callbacks for Stasis message sanitization.
const char * stasis_app_playback_get_id(struct stasis_app_playback *control)
Gets the unique id of a playback object.
const ast_string_field target
const ast_string_field id
Blob of data associated with a channel.
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
struct stasis_app_control * control
const ast_string_field media
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Asterisk file paths, configured in asterisk.conf.
enum stasis_app_playback_state state
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
struct stasis_app_playback * stasis_app_playback_find_by_id(const char *id)
Finds the playback object with the given id.
#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.
#define AST_STRING_FIELD(name)
Declare a string field.
struct stasis_message_type * stasis_app_playback_snapshot_type(void)
Message type for playback updates. The data is an ast_channel_blob.
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
#define ast_malloc(len)
A wrapper for malloc()
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.
#define AST_VECTOR(name, type)
Define a vector structure.
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
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
struct ast_json * ast_json_timeval(const struct timeval tv, const char *zone)
Construct a timeval as JSON.
#define STASIS_MESSAGE_TYPE_DEFN(name,...)
Boiler-plate messaging macro for defining public message types.
Structure that contains information about a bridge.
static void remove_from_playbacks(void *data)
RAII_VAR function to remove a playback from the global list when leaving scope.
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.
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.
#define ast_bridge_unlock(bridge)
Unlock the bridge.
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
char * ast_uuid_generate_str(char *buf, size_t size)
Generate a UUID string.
Support for logging to various files, console and syslog Configuration in file logger.conf.
Module has failed to load, may be in an inconsistent state.
#define ast_string_field_build(x, field, fmt, args...)
Set a field to a complex (built) value.
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.
#define ast_bridge_lock(bridge)
Lock the bridge.
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
struct ast_channel * chan
struct stasis_app_playback::@487 medias
Structure that contains information regarding a channel in a bridge.
Stasis Application Playback API. See StasisApplication API" for detailed documentation.
int ast_say_number(struct ast_channel *chan, int num, const char *ints, const char *lang, const char *options)
says a number
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
struct stasis_app_stored_recording * stasis_app_stored_recording_find_by_name(const char *name)
Creates a stored recording object, with the given name.
int stasis_app_control_queue_control(struct stasis_app_control *control, enum ast_control_frame_type frame_type)
Queue a control frame without payload.
stasis_app_playback_state
#define ao2_unlink_flags(container, obj, flags)
Remove an object from a container.
static int force_inline attribute_pure ast_begins_with(const char *str, const char *prefix)
Checks whether a string begins with another.
Abstract JSON element (object, array, string, int, ...).
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.
const ast_string_field language
Say numbers and dates (maybe words one day too)
#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
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
struct ast_json * stasis_app_playback_to_json(const struct stasis_app_playback *playback)
Convert a playback to its JSON representation.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
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.
#define ao2_link(container, obj)
Add an object to a container.