res_stasis_playback: Add 'number', 'digits', and 'characters' URI scheme implementations.
[asterisk/asterisk.git] / res / res_stasis_playback.c
index f78ccf0..ce29de1 100644 (file)
@@ -47,6 +47,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/stasis_channels.h"
 #include "asterisk/stringfields.h"
 #include "asterisk/uuid.h"
+#include "asterisk/say.h"
 
 /*! Number of hash buckets for playback container. Keep it prime! */
 #define PLAYBACK_BUCKETS 127
@@ -56,6 +57,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #define SOUND_URI_SCHEME "sound:"
 #define RECORDING_URI_SCHEME "recording:"
+#define NUMBER_URI_SCHEME "number:"
+#define DIGITS_URI_SCHEME "digits:"
+#define CHARACTERS_URI_SCHEME "characters:"
 
 /*! Container of all current playbacks */
 static struct ao2_container *playbacks;
@@ -74,15 +78,16 @@ struct stasis_app_playback {
        long offsetms;
        /*! Number of milliseconds to skip for forward/reverse operations */
        int skipms;
-
-       /*! Set when playback has been completed */
-       int done;
        /*! Condition for waiting on done to be set */
        ast_cond_t done_cond;
        /*! Number of milliseconds of media that has been played */
        long playedms;
        /*! Current playback state */
        enum stasis_app_playback_state state;
+       /*! Set when playback has been completed */
+       unsigned int done:1;
+       /*! Set when the playback can be controlled */
+       unsigned int controllable:1;
 };
 
 static struct ast_json *playback_to_json(struct stasis_message *message,
@@ -272,8 +277,6 @@ static void play_on_channel(struct stasis_app_playback *playback,
 {
        RAII_VAR(struct stasis_app_playback *, mark_when_done, playback,
                mark_as_done);
-       RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
-       RAII_VAR(char *, file, NULL, ast_free);
        int res;
        long offsetms;
 
@@ -301,8 +304,12 @@ static void play_on_channel(struct stasis_app_playback *playback,
        }
 
        if (ast_begins_with(playback->media, SOUND_URI_SCHEME)) {
+               playback->controllable = 1;
+
                /* Play sound */
-               file = ast_strdup(playback->media + strlen(SOUND_URI_SCHEME));
+               res = ast_control_streamfile_lang(chan, playback->media + strlen(SOUND_URI_SCHEME),
+                               fwd, rev, stop, pause, restart, playback->skipms, playback->language,
+                               &offsetms);
        } else if (ast_begins_with(playback->media, RECORDING_URI_SCHEME)) {
                /* Play recording */
                RAII_VAR(struct stasis_app_stored_recording *, recording, NULL,
@@ -310,23 +317,41 @@ static void play_on_channel(struct stasis_app_playback *playback,
                const char *relname =
                        playback->media + strlen(RECORDING_URI_SCHEME);
                recording = stasis_app_stored_recording_find_by_name(relname);
-               if (recording) {
-                       file = ast_strdup(stasis_app_stored_recording_get_file(
-                                       recording));
+
+               if (!recording) {
+                       ast_log(LOG_ERROR, "Attempted to play recording '%s' on channel '%s' but recording does not exist",
+                               ast_channel_name(chan), relname);
+                       return;
                }
+
+               playback->controllable = 1;
+
+               res = ast_control_streamfile_lang(chan,
+                       stasis_app_stored_recording_get_file(recording), fwd, rev, stop, pause,
+                       restart, playback->skipms, playback->language, &offsetms);
+       } else if (ast_begins_with(playback->media, NUMBER_URI_SCHEME)) {
+               int number;
+
+               if (sscanf(playback->media + strlen(NUMBER_URI_SCHEME), "%30d", &number) != 1) {
+                       ast_log(LOG_ERROR, "Attempted to play number '%s' on channel '%s' but number is invalid",
+                               ast_channel_name(chan), playback->media + strlen(NUMBER_URI_SCHEME));
+                       return;
+               }
+
+               res = ast_say_number(chan, number, stop, playback->language, NULL);
+       } else if (ast_begins_with(playback->media, DIGITS_URI_SCHEME)) {
+               res = ast_say_digit_str(chan, playback->media + strlen(DIGITS_URI_SCHEME),
+                       stop, playback->language);
+       } 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 {
                /* Play URL */
-               ast_log(LOG_ERROR, "Unimplemented\n");
+               ast_log(LOG_ERROR, "Attempted to play URI '%s' on channel '%s' but scheme is unsupported",
+                       ast_channel_name(chan), playback->media);
                return;
        }
 
-       if (!file) {
-               return;
-       }
-
-       res = ast_control_streamfile_lang(chan, file, fwd, rev, stop, pause,
-               restart, playback->skipms, playback->language, &offsetms);
-
        playback_final_update(playback, offsetms, res,
                ast_channel_uniqueid(chan));
 
@@ -527,6 +552,11 @@ static int playback_cancel(struct stasis_app_playback *playback)
 static int playback_stop(struct stasis_app_playback *playback)
 {
        SCOPED_AO2LOCK(lock, playback);
+
+       if (!playback->controllable) {
+               return -1;
+       }
+
        playback->state = STASIS_PLAYBACK_STATE_STOPPED;
        return stasis_app_control_queue_control(playback->control,
                AST_CONTROL_STREAM_STOP);
@@ -534,6 +564,12 @@ static int playback_stop(struct stasis_app_playback *playback)
 
 static int playback_restart(struct stasis_app_playback *playback)
 {
+       SCOPED_AO2LOCK(lock, playback);
+
+       if (!playback->controllable) {
+               return -1;
+       }
+
        return stasis_app_control_queue_control(playback->control,
                AST_CONTROL_STREAM_RESTART);
 }
@@ -541,8 +577,14 @@ static int playback_restart(struct stasis_app_playback *playback)
 static int playback_pause(struct stasis_app_playback *playback)
 {
        SCOPED_AO2LOCK(lock, playback);
+
+       if (!playback->controllable) {
+               return -1;
+       }
+
        playback->state = STASIS_PLAYBACK_STATE_PAUSED;
        playback_publish(playback);
+
        return stasis_app_control_queue_control(playback->control,
                AST_CONTROL_STREAM_SUSPEND);
 }
@@ -550,20 +592,38 @@ static int playback_pause(struct stasis_app_playback *playback)
 static int playback_unpause(struct stasis_app_playback *playback)
 {
        SCOPED_AO2LOCK(lock, playback);
+
+       if (!playback->controllable) {
+               return -1;
+       }
+
        playback->state = STASIS_PLAYBACK_STATE_PLAYING;
        playback_publish(playback);
+
        return stasis_app_control_queue_control(playback->control,
                AST_CONTROL_STREAM_SUSPEND);
 }
 
 static int playback_reverse(struct stasis_app_playback *playback)
 {
+       SCOPED_AO2LOCK(lock, playback);
+
+       if (!playback->controllable) {
+               return -1;
+       }
+
        return stasis_app_control_queue_control(playback->control,
                AST_CONTROL_STREAM_REVERSE);
 }
 
 static int playback_forward(struct stasis_app_playback *playback)
 {
+       SCOPED_AO2LOCK(lock, playback);
+
+       if (!playback->controllable) {
+               return -1;
+       }
+
        return stasis_app_control_queue_control(playback->control,
                AST_CONTROL_STREAM_FORWARD);
 }