diff --git a/CHANGES b/CHANGES index dc261055e9a17cac045ca42998e6414e2b5fa4db..f8712b38cdd320ba37f7adde7ce3c2c3c7a90f77 100644 --- a/CHANGES +++ b/CHANGES @@ -12,6 +12,23 @@ --- Functionality changes from Asterisk 12 to Asterisk 13 -------------------- ------------------------------------------------------------------------------ +------------------------------------------------------------------------------ +--- Functionality changes from Asterisk 12.2.0 to Asterisk 12.3.0 ------------ +------------------------------------------------------------------------------ + +ARI +------------------ + * A new Playback URI 'tone' has been added. Tones are specified either as + an indication name (e.g. 'tone:busy') from indications.conf or as a tone + pattern (e.g. 'tone:240/250,0/250'). Tones differ from normal playback + URIs in that they must be stopped manually and will continue to occupy + a channel's ARI control queue until they are stopped. They also can not + be rewound or fastforwarded. + +------------------------------------------------------------------------------ +--- Functionality changes from Asterisk 12.1.0 to Asterisk 12.2.0 ------------ +------------------------------------------------------------------------------ + Applications -------------------------- * Record application now has an option 'o' which allows 0 to act as an exit @@ -143,7 +160,7 @@ AMI used to set the UniqueId on creation. The other id is assigned to the second channel when dialing LOCAL, or defaults to appending ;2 if only the single Id is given. - + * The Mixmonitor action now has a "Command" header that can be used to indicate a post-process command to run once recording finishes. diff --git a/include/asterisk/app.h b/include/asterisk/app.h index 70cf7527091f76172da1836cb9bb9e40ec64584b..65d74dcd138ad3ebeae2d67ae5583c8e793e341a 100644 --- a/include/asterisk/app.h +++ b/include/asterisk/app.h @@ -879,6 +879,14 @@ 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); +/*! + * \brief Controls playback of a tone + * + * \retval 0 on success + * \retval Non-zero on failure + */ +int ast_control_tone(struct ast_channel *chan, const char *tone); + /*! * \brief Stream a file with fast forward, pause, reverse, restart. * \param chan diff --git a/main/app.c b/main/app.c index b6c9882583f28e98094511f1bc2e1ecadfb551d7..f7bb0048ca573f69073d081f8cb6b58c7b027b24 100644 --- a/main/app.c +++ b/main/app.c @@ -1070,6 +1070,143 @@ int ast_control_streamfile_lang(struct ast_channel *chan, const char *file, return control_streamfile(chan, file, fwd, rev, stop, suspend, restart, skipms, offsetms, lang, NULL); } +enum control_tone_frame_response_result { + CONTROL_TONE_RESPONSE_FAILED = -1, + CONTROL_TONE_RESPONSE_NORMAL = 0, + CONTROL_TONE_RESPONSE_FINISHED = 1, +}; + +static enum control_tone_frame_response_result control_tone_frame_response(struct ast_channel *chan, struct ast_frame *fr, struct ast_tone_zone_sound *ts, const char *tone, int *paused) +{ + switch (fr->subclass.integer) { + case AST_CONTROL_STREAM_STOP: + ast_playtones_stop(chan); + return CONTROL_TONE_RESPONSE_FINISHED; + case AST_CONTROL_STREAM_SUSPEND: + if (*paused) { + *paused = 0; + if (ast_playtones_start(chan, 0, ts ? ts->data : tone, 0)) { + return CONTROL_TONE_RESPONSE_FAILED; + } + } else { + *paused = 1; + ast_playtones_stop(chan); + } + return CONTROL_TONE_RESPONSE_NORMAL; + case AST_CONTROL_STREAM_RESTART: + ast_playtones_stop(chan); + if (ast_playtones_start(chan, 0, ts ? ts->data : tone, 0)) { + return CONTROL_TONE_RESPONSE_FAILED; + } + return CONTROL_TONE_RESPONSE_NORMAL; + case AST_CONTROL_STREAM_REVERSE: + ast_log(LOG_NOTICE, "Media control operation 'reverse' not supported for media type 'tone'\n"); + return CONTROL_TONE_RESPONSE_NORMAL; + case AST_CONTROL_STREAM_FORWARD: + ast_log(LOG_NOTICE, "Media control operation 'forward' not supported for media type 'tone'\n"); + return CONTROL_TONE_RESPONSE_NORMAL; + case AST_CONTROL_HANGUP: + case AST_CONTROL_BUSY: + case AST_CONTROL_CONGESTION: + return CONTROL_TONE_RESPONSE_FINISHED; + } + + return CONTROL_TONE_RESPONSE_NORMAL; +} + +static int parse_tone_uri(char *tone_parser, + const char **tone_indication, + const char **tone_zone) +{ + *tone_indication = strsep(&tone_parser, ";"); + + if (ast_strlen_zero(tone_parser)) { + /* Only the indication is included */ + return 0; + } + + if (!(strncmp(tone_parser, "tonezone=", 9))) { + *tone_zone = tone_parser + 9; + } else { + ast_log(LOG_ERROR, "Unexpected Tone URI component: %s\n", tone_parser); + return -1; + } + + return 0; +} + +int ast_control_tone(struct ast_channel *chan, const char *tone) +{ + struct ast_tone_zone *zone = NULL; + struct ast_tone_zone_sound *ts; + int paused = 0; + int res; + + const char *tone_indication = NULL; + const char *tone_zone = NULL; + char *tone_uri_parser; + + if (ast_strlen_zero(tone)) { + return -1; + } + + tone_uri_parser = ast_strdupa(tone); + + if (parse_tone_uri(tone_uri_parser, &tone_indication, &tone_zone)) { + return -1; + } + + if (tone_zone) { + zone = ast_get_indication_zone(tone_zone); + } + + ts = ast_get_indication_tone(zone ? zone : ast_channel_zone(chan), tone_indication); + + if (ast_playtones_start(chan, 0, ts ? ts->data : tone_indication, 0)) { + return -1; + } + + for (;;) { + struct ast_frame *fr; + int res; + + if (ast_waitfor(chan, -1) < 0) { + res = -1; + break; + } + + fr = ast_read_noaudio(chan); + + if (!fr) { + res = -1; + break; + } + + if (fr->frametype != AST_FRAME_CONTROL) { + continue; + } + + res = control_tone_frame_response(chan, fr, ts, tone_indication, &paused); + if (res == CONTROL_TONE_RESPONSE_FINISHED) { + res = 0; + break; + } else if (res == CONTROL_TONE_RESPONSE_FAILED) { + res = -1; + break; + } + } + + if (ts) { + ast_tone_zone_sound_unref(ts); + } + + if (zone) { + ast_tone_zone_unref(zone); + } + + return res; +} + int ast_play_and_wait(struct ast_channel *chan, const char *fn) { int d = 0; diff --git a/res/ari/resource_bridges.h b/res/ari/resource_bridges.h index 5dca82781198001e94690f03594f9fbbf7b80efa..404760c91414f501c23338bff1a0d79654022656 100644 --- a/res/ari/resource_bridges.h +++ b/res/ari/resource_bridges.h @@ -268,7 +268,7 @@ int ast_ari_bridges_play_parse_body( /*! * \brief Start playback of media on a bridge. * - * The media URI may be any of a number of URI's. Currently sound: and recording: URI's are supported. This operation creates a playback resource that can be used to control the playback of media (pause, rewind, fast forward, etc.) + * The media URI may be any of a number of URI's. Currently sound:, recording:, number:, digits:, characters:, and tone: URI's are supported. This operation creates a playback resource that can be used to control the playback of media (pause, rewind, fast forward, etc.) * * \param headers HTTP headers * \param args Swagger parameters diff --git a/res/ari/resource_channels.h b/res/ari/resource_channels.h index cf48cee7545fae5143a1301fc8fd4392d6c3051a..bc50c3da4cc9986b2891bd6aac0bfa1051ebefd3 100644 --- a/res/ari/resource_channels.h +++ b/res/ari/resource_channels.h @@ -460,7 +460,7 @@ int ast_ari_channels_play_parse_body( /*! * \brief Start playback of media. * - * The media URI may be any of a number of URI's. Currently sound: and recording: URI's are supported. This operation creates a playback resource that can be used to control the playback of media (pause, rewind, fast forward, etc.) + * The media URI may be any of a number of URI's. Currently sound:, recording:, number:, digits:, characters:, and tone: URI's are supported. This operation creates a playback resource that can be used to control the playback of media (pause, rewind, fast forward, etc.) * * \param headers HTTP headers * \param args Swagger parameters diff --git a/res/res_stasis_playback.c b/res/res_stasis_playback.c index 79c2bab9ce879ff24dde1dbfecce6e04a2c9f253..960f2e3342f6de0bc6798a68c282d099e447565a 100644 --- a/res/res_stasis_playback.c +++ b/res/res_stasis_playback.c @@ -48,6 +48,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/stringfields.h" #include "asterisk/uuid.h" #include "asterisk/say.h" +#include "asterisk/indications.h" /*! Number of hash buckets for playback container. Keep it prime! */ #define PLAYBACK_BUCKETS 127 @@ -60,6 +61,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #define NUMBER_URI_SCHEME "number:" #define DIGITS_URI_SCHEME "digits:" #define CHARACTERS_URI_SCHEME "characters:" +#define TONE_URI_SCHEME "tone:" /*! Container of all current playbacks */ static struct ao2_container *playbacks; @@ -323,6 +325,9 @@ static void play_on_channel(struct stasis_app_playback *playback, } else if (ast_begins_with(playback->media, CHARACTERS_URI_SCHEME)) { res = ast_say_character_str(chan, playback->media + strlen(CHARACTERS_URI_SCHEME), stop, playback->language, AST_SAY_CASE_NONE); + } else if (ast_begins_with(playback->media, TONE_URI_SCHEME)) { + playback->controllable = 1; + res = ast_control_tone(chan, playback->media + strlen(TONE_URI_SCHEME)); } else { /* Play URL */ ast_log(LOG_ERROR, "Attempted to play URI '%s' on channel '%s' but scheme is unsupported", diff --git a/rest-api/api-docs/bridges.json b/rest-api/api-docs/bridges.json index 56a7a941e07bfe4fbb87b1e3056ffb5abecdf25f..4d2c77cea71ad4bfac8565e6caa82c9bdf0b7b0a 100644 --- a/rest-api/api-docs/bridges.json +++ b/rest-api/api-docs/bridges.json @@ -314,7 +314,7 @@ { "httpMethod": "POST", "summary": "Start playback of media on a bridge.", - "notes": "The media URI may be any of a number of URI's. Currently sound: and recording: URI's are supported. This operation creates a playback resource that can be used to control the playback of media (pause, rewind, fast forward, etc.)", + "notes": "The media URI may be any of a number of URI's. Currently sound:, recording:, number:, digits:, characters:, and tone: URI's are supported. This operation creates a playback resource that can be used to control the playback of media (pause, rewind, fast forward, etc.)", "nickname": "play", "responseClass": "Playback", "parameters": [ diff --git a/rest-api/api-docs/channels.json b/rest-api/api-docs/channels.json index d940f438349ae318b0278aedb347cc54ec2f2cb9..cc7feb6a919e6f97152d4bc7a7a00712a6088dec 100644 --- a/rest-api/api-docs/channels.json +++ b/rest-api/api-docs/channels.json @@ -808,7 +808,7 @@ { "httpMethod": "POST", "summary": "Start playback of media.", - "notes": "The media URI may be any of a number of URI's. Currently sound: and recording: URI's are supported. This operation creates a playback resource that can be used to control the playback of media (pause, rewind, fast forward, etc.)", + "notes": "The media URI may be any of a number of URI's. Currently sound:, recording:, number:, digits:, characters:, and tone: URI's are supported. This operation creates a playback resource that can be used to control the playback of media (pause, rewind, fast forward, etc.)", "nickname": "play", "responseClass": "Playback", "parameters": [