]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
more ivr stuff (not done)
authorAnthony Minessale <anthony.minessale@gmail.com>
Tue, 28 Feb 2006 02:08:42 +0000 (02:08 +0000)
committerAnthony Minessale <anthony.minessale@gmail.com>
Tue, 28 Feb 2006 02:08:42 +0000 (02:08 +0000)
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@693 d0543943-73ff-0310-b7d9-9358b9ac24b2

13 files changed:
src/include/switch_buffer.h
src/include/switch_core.h
src/include/switch_ivr.h
src/include/switch_module_interfaces.h
src/include/switch_types.h
src/mod/applications/mod_ivrtest/mod_ivrtest.c
src/mod/applications/mod_playback/mod_playback.c
src/mod/endpoints/mod_exosip/mod_exosip.c
src/mod/formats/mod_sndfile/mod_sndfile.c
src/mod/languages/mod_spidermonkey/mod_spidermonkey.c
src/switch_buffer.c
src/switch_core.c
src/switch_ivr.c

index 6461e1bc1d561ce4fb85f88a915518bf067b52d0..fd0366ef1665dcfbb29d922f43d5cb675fc67528 100644 (file)
@@ -104,6 +104,11 @@ SWITCH_DECLARE(int) switch_buffer_write(switch_buffer *buffer, void *data, size_
  * \return int size of buffer, or 0 if unable to toss that much data
  */
 SWITCH_DECLARE(int) switch_buffer_toss(switch_buffer *buffer, size_t datalen);
+
+/*! \brief Remove all data from the buffer
+ * \param buffer any buffer of type switch_buffer
+ */
+SWITCH_DECLARE(void) switch_buffer_zero(switch_buffer *buffer);
 /** @} */
 
 
index fe54a0c527d2b6afed1262e1c96b18dad997239a..f3c6f4cdf57b5ede75f9cc2431f5b25004a8f413 100644 (file)
@@ -743,7 +743,7 @@ SWITCH_DECLARE(switch_status) switch_core_file_write(switch_file_handle *fh, voi
   \param whence the indicator (see traditional seek)
   \return SWITCH_STATUS_SUCCESS with cur_pos adjusted to new position
 */
-SWITCH_DECLARE(switch_status) switch_core_file_seek(switch_file_handle *fh, unsigned int *cur_pos, unsigned int samples, int whence);
+SWITCH_DECLARE(switch_status) switch_core_file_seek(switch_file_handle *fh, unsigned int *cur_pos, int64_t samples, int whence);
 
 /*! 
   \brief Close an open file handle
index 8a48ae1c314d381092b7b6333a0a861feba56134..c8409dd836afb2fbc34eba17c572e714c8c75097 100644 (file)
@@ -85,6 +85,7 @@ SWITCH_DECLARE(switch_status) switch_ivr_collect_digits_count(switch_core_sessio
 /*!
   \brief play a file from the disk to the session
   \param session the session to play the file too
+  \param pointer to file handle to use (NULL for builtin one)
   \param file the path to the file
   \param timer_name the name of a timer to use input will be absorbed (NULL to time off the session input).
   \param dtmf_callback code to execute if any dtmf is dialed during the playback
@@ -94,6 +95,7 @@ SWITCH_DECLARE(switch_status) switch_ivr_collect_digits_count(switch_core_sessio
   \note passing a NULL dtmf_callback nad a not NULL buf indicates to copy any dtmf to buf and stop playback.
 */
 SWITCH_DECLARE(switch_status) switch_ivr_play_file(switch_core_session *session,
+                                                                                                  switch_file_handle *fh,
                                                                                                   char *file,
                                                                                                   char *timer_name,
                                                                                                   switch_dtmf_callback_function dtmf_callback,
index 3f42b4d3ebb988d44a88b011058b3e1aa8b66bdb..39712cd0bd8d43dd3b2f20b195e06729ab0c4cc7 100644 (file)
@@ -245,7 +245,7 @@ struct switch_file_interface {
        /*! function to write from the file */
        switch_status (*file_write)(switch_file_handle *, void *data, size_t *len);
        /*! function to seek to a certian position in the file */
-       switch_status (*file_seek)(switch_file_handle *, unsigned int *cur_pos, unsigned int samples, int whence);
+       switch_status (*file_seek)(switch_file_handle *, unsigned int *cur_pos, int64_t samples, int whence);
        /*! list of supported file extensions */
        char **extens;
        const struct switch_file_interface *next;
@@ -273,10 +273,14 @@ struct switch_file_handle {
        int seekable;
        /*! the sample count of the file */
        unsigned int sample_count;
+       /*! the speed of the file playback*/
+       int speed;
        /*! the handle's memory pool */
        switch_memory_pool *memory_pool;
        /*! private data for the format module to store handle specific info */
        void *private_info;
+       int64_t pos;
+       switch_buffer *audio_buffer;
 };
 
 
index 524bb0baf61fce8d0cb83cafe9d3a5a14d448dc8..be1a4eb4be11f9ef4dfee05190c7c0473a48e8e5 100644 (file)
@@ -319,6 +319,7 @@ SWITCH_FILE_DATA_INT =          (1 <<  4) - Read data in ints
 SWITCH_FILE_DATA_FLOAT =        (1 <<  5) - Read data in floats
 SWITCH_FILE_DATA_DOUBLE =       (1 <<  6) - Read data in doubles
 SWITCH_FILE_DATA_RAW =          (1 <<  7) - Read data as is
+SWITCH_FILE_PAUSE =             (1 <<  8) - Pause
 </pre>
  */
 typedef enum {
@@ -330,6 +331,7 @@ typedef enum {
        SWITCH_FILE_DATA_FLOAT =                (1 <<  5),
        SWITCH_FILE_DATA_DOUBLE =               (1 <<  6),
        SWITCH_FILE_DATA_RAW =                  (1 <<  7),
+       SWITCH_FILE_PAUSE =                             (1 <<  8)
 } switch_file_flag;
 
 typedef enum {
index e44cc167d07fcf18a11e21fade4109853aaac018..f617b1d9b00dee668d89baa6dcf55b590e38d51c 100644 (file)
@@ -149,7 +149,7 @@ static void ivrtest_function(switch_core_session *session, char *data)
                        /* you could have passed NULL instead of on_dtmf to get this exact behaviour (copy the digits to buf and stop playing)
                           but you may want to pass the function if you have something cooler to do...
                        */
-                       status = switch_ivr_play_file(session, data, NULL, on_dtmf, buf, sizeof(buf));
+                       status = switch_ivr_play_file(session, NULL, data, NULL, on_dtmf, buf, sizeof(buf));
                        
                        if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) {
                                switch_channel_hangup(channel);
index d56da492bed7b11256ccd6938cc319b693a13382..e7c35de991395048431c2f8b76202eb2989d57f5 100644 (file)
@@ -64,7 +64,7 @@ static void playback_function(switch_core_session *session, char *data)
        channel = switch_core_session_get_channel(session);
     assert(channel != NULL);
 
-       if (switch_ivr_play_file(session, file_name, timer_name, on_dtmf, NULL, 0) != SWITCH_STATUS_SUCCESS) {
+       if (switch_ivr_play_file(session, NULL, file_name, timer_name, on_dtmf, NULL, 0) != SWITCH_STATUS_SUCCESS) {
                switch_channel_hangup(channel);
        }
        
index 6dbe77b9dc52b8dc46bf5b573f3c97e9f9300fd9..43b09558304194a83ce643a952c4edc3b56b926f 100644 (file)
@@ -117,6 +117,8 @@ struct private_object {
        char call_id[50];
        int ssrc;
        char last_digit;
+       unsigned int dc;
+       time_t last_digit_time;
        switch_mutex_t *rtp_lock;
        switch_queue_t *dtmf_queue;
        char out_digit;
@@ -480,6 +482,8 @@ static switch_status exosip_answer_channel(switch_core_session *session)
        struct private_object *tech_pvt;
        switch_channel *channel = NULL;
 
+       assert(session != NULL);
+
        channel = switch_core_session_get_channel(session);
        assert(channel != NULL);
 
@@ -554,11 +558,24 @@ static switch_status exosip_read_frame(switch_core_session *session, switch_fram
                                int duration = (packet[2]<<8) + packet[3];
                                char key = switch_rfc2833_to_char(packet[0]);
 
-                               if (duration && end && key != tech_pvt->last_digit) {
-                                       char digit_str[] = {key, 0};
-                                       switch_channel_queue_dtmf(channel, digit_str);
-                                       tech_pvt->last_digit = key;
+                               /* SHEESH.... Curse you RFC2833 inventors!!!!*/
+                               if ((time(NULL) - tech_pvt->last_digit_time) > 2) {
+                                       tech_pvt->last_digit = 0;
+                                       tech_pvt->dc = 0;
                                }
+                               if (duration && end) {
+                                       if (key != tech_pvt->last_digit) {
+                                               char digit_str[] = {key, 0};
+                                               time(&tech_pvt->last_digit_time);
+                                               switch_channel_queue_dtmf(channel, digit_str);
+                                       }
+                                       if (++tech_pvt->dc >= 3) {
+                                               tech_pvt->last_digit = 0;
+                                               tech_pvt->dc = 0;
+                                       } else {
+                                               tech_pvt->last_digit = key;
+                                       }
+                               } 
                        }
 
                        if (globals.supress_telephony_events && payload != tech_pvt->payload_num) {
index 27d825595755f4009b0c5356b5cc32424315c8c2..0d1b1dc7deb0767719fb5fc1f1c139ccc4c894bc 100644 (file)
@@ -138,7 +138,7 @@ switch_status sndfile_file_open(switch_file_handle *handle, char *path)
        handle->format = context->sfinfo.format;
        handle->sections = context->sfinfo.sections;
        handle->seekable = context->sfinfo.seekable;
-
+       handle->speed = 0;
        handle->private_info = context;
 
        return SWITCH_STATUS_SUCCESS;
@@ -153,15 +153,17 @@ switch_status sndfile_file_close(switch_file_handle *handle)
        return SWITCH_STATUS_SUCCESS;
 }
 
-switch_status sndfile_file_seek(switch_file_handle *handle, unsigned int *cur_sample, unsigned int samples, int whence)
+switch_status sndfile_file_seek(switch_file_handle *handle, unsigned int *cur_sample, int64_t samples, int whence)
 {
        sndfile_context *context = handle->private_info;
 
        if (!handle->seekable) {
+               switch_console_printf(SWITCH_CHANNEL_CONSOLE, "File is not seekable\n");
                return SWITCH_STATUS_NOTIMPL;
        }
 
        *cur_sample = (unsigned int) sf_seek(context->handle, samples, whence);
+       handle->pos = *cur_sample;
 
        return SWITCH_STATUS_SUCCESS;
 
index a21867c9b56d28a154fe53286f7a939604509d6b..7cd4534f9517912391051db327a089cd4239733b 100644 (file)
@@ -53,6 +53,7 @@
 
 static const char modname[] = "mod_spidermonkey";
 
+static int eval_some_js(char *code, JSContext *cx, JSObject *obj, jsval *rval);
 
 static struct {
        size_t gStackChunkSize;
@@ -74,8 +75,20 @@ static JSClass global_class = {
 };
 
 
-struct jchan {
+struct dtmf_callback_state {
+       struct js_session *session_state;
+       char code_buffer[1024];
+       int code_buffer_len;
+       char ret_buffer[1024];
+       int ret_buffer_len;
+       int digit_count;
+       void *extra;
+};
+
+struct js_session {
        switch_core_session *session;
+       JSContext *cx;
+       JSObject *obj;
        unsigned int flags;
 };
 
@@ -110,33 +123,177 @@ static switch_status init_js(void)
 
 }
 
-static JSBool chan_streamfile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+static switch_status js_dtmf_callback(switch_core_session *session, char *dtmf, void *buf, unsigned int buflen)
 {
-       struct jchan *jc = JS_GetPrivate(cx, obj);
-    JSString *str = NULL;
-       char *filename = NULL;
-       char buf[25] = "";
+       char code[2048];
+       struct dtmf_callback_state *cb_state = buf;
+       struct js_session *jss = cb_state->session_state;
+       switch_file_handle *fh = cb_state->extra;
+       jsval rval;
+       char *ret;
+       
+       if(!jss) {
+               return SWITCH_STATUS_FALSE;
+       }
+       
+       if (cb_state->digit_count || (cb_state->code_buffer[0] > 47 && cb_state->code_buffer[0] < 58)) {
+               char *d;
+               if (!cb_state->digit_count) {
+                       cb_state->digit_count = atoi(cb_state->code_buffer);
+               }
+
+               for(d = dtmf; *d; d++) {
+                       cb_state->ret_buffer[cb_state->ret_buffer_len++] = *d;
+                       if ((cb_state->ret_buffer_len > cb_state->digit_count)||
+                               (cb_state->ret_buffer_len > sizeof(cb_state->ret_buffer))||
+                               (cb_state->ret_buffer_len >= cb_state->digit_count)
+                               ) {
+                               return SWITCH_STATUS_FALSE;
+                       }
+               }
+               return SWITCH_STATUS_SUCCESS;
+       } else {
+               snprintf(code, sizeof(code), "~%s(\"%s\")", cb_state->code_buffer, dtmf);
+               eval_some_js(code, jss->cx, jss->obj, &rval);
+               ret = JS_GetStringBytes(JS_ValueToString(jss->cx, rval));
+
+               if (*ret == 'F') {
+                       int step;
+                       ret++;
+                       
+                       step = *ret ? atoi(ret) : 1;
+                       fh->speed += step ? step : 1;
+                       return SWITCH_STATUS_SUCCESS;
+               }
+
+               if (*ret == 'S') {
+                       int step;
+            ret++;
+
+                       step = *ret ? atoi(ret) : 1;
+            fh->speed -= step ? step : 1;
+                       return SWITCH_STATUS_SUCCESS;
+               }
+
+               if (*ret == 'N') {
+                       fh->speed = 0;
+                       return SWITCH_STATUS_SUCCESS;
+               }
+               
+               if (*ret == 'P') {
+                       if (switch_test_flag(fh, SWITCH_FILE_PAUSE)) {
+                               printf("unpause\n");
+                               switch_clear_flag(fh, SWITCH_FILE_PAUSE);
+                       } else {
+                               printf("pause\n");
+                               switch_set_flag(fh, SWITCH_FILE_PAUSE);
+                               fh->speed = 0;
+                       }
+                       return SWITCH_STATUS_SUCCESS;
+               }
+
+               if (*ret == 'R') {
+                       unsigned int pos = 0;
+                       fh->speed = 0;
+                       switch_core_file_seek(fh, &pos, 0, SEEK_SET);
+                       return SWITCH_STATUS_SUCCESS;
+               }
+
+               if (*ret == '+' || *ret == '-') {
+                       switch_codec *codec;
+                       codec = switch_core_session_get_read_codec(jss->session);
+                       unsigned int samps = 0;
+                       unsigned int pos = 0;
+                       if (*ret == '+') {
+                               ret++;
+                               samps = atoi(ret) * (codec->implementation->samples_per_second / 1000);
+                               switch_core_file_seek(fh, &pos, samps, SEEK_CUR);
+                       } else {
+                               samps = atoi(ret) * (codec->implementation->samples_per_second / 1000);
+                               switch_core_file_seek(fh, &pos, fh->pos - samps, SEEK_SET);
+                       }
+
+                       return SWITCH_STATUS_SUCCESS;
+               }
+
+               if (!strcmp(ret, "true") || !strcmp(ret, "undefined")) {
+                       return SWITCH_STATUS_SUCCESS;
+               }
+       
+               if (ret) {
+                       switch_copy_string(cb_state->ret_buffer, ret, sizeof(cb_state->ret_buffer));
+               }
+       }
+
+       return SWITCH_STATUS_FALSE;
+}
 
+static JSBool chan_streamfile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+       struct js_session *jss = JS_GetPrivate(cx, obj);
+    switch_channel *channel;
+       char *file_name = NULL;
+       char *timer_name = NULL;
+       char *dtmf_callback = NULL;
+       void *bp = NULL;
+       int len = 0;
+       switch_dtmf_callback_function dtmf_func = NULL;
+       struct dtmf_callback_state cb_state = {0};
+       switch_file_handle fh;
+
+       channel = switch_core_session_get_channel(jss->session);
+    assert(channel != NULL);
+       
        if (argc > 0) {
-        if ((str = JS_ValueToString(cx, argv[0])) && (filename = JS_GetStringBytes(str))) {
-                       switch_ivr_play_file(jc->session, filename, NULL, NULL, buf, sizeof(buf));
-                       *rval = STRING_TO_JSVAL ( JS_NewStringCopyZ(cx, buf) );
+               file_name = JS_GetStringBytes(JS_ValueToString(cx, argv[0]));
+               if (switch_strlen_zero(file_name)) {
+                       return JS_FALSE;
                }
        }
-       return JS_FALSE;
+       if (argc > 1) {
+               timer_name = JS_GetStringBytes(JS_ValueToString(cx, argv[1]));
+               if (switch_strlen_zero(timer_name)) {
+                       timer_name = NULL;
+               }
+       }
+       if (argc > 2) {
+               dtmf_callback = JS_GetStringBytes(JS_ValueToString(cx, argv[2]));
+               if (switch_strlen_zero(dtmf_callback)) {
+                       dtmf_callback = NULL;
+               } else {
+                       memset(&cb_state, 0, sizeof(cb_state));
+                       switch_copy_string(cb_state.code_buffer, dtmf_callback, sizeof(cb_state.code_buffer));
+                       cb_state.code_buffer_len = strlen(cb_state.code_buffer);
+                       cb_state.session_state = jss;
+                       dtmf_func = js_dtmf_callback;
+                       bp = &cb_state;
+                       len = sizeof(cb_state);
+               }
+       }
+
+       memset(&fh, 0, sizeof(fh));
+       cb_state.extra = &fh;
+
+       switch_ivr_play_file(jss->session, &fh, file_name, timer_name, dtmf_func, bp, len);
+       *rval = STRING_TO_JSVAL (JS_NewStringCopyZ(cx, cb_state.ret_buffer));
+
+       return (switch_channel_get_state(channel) == CS_EXECUTE) ? JS_TRUE : JS_FALSE;
 }
 
 static JSBool chan_speak(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
-       struct jchan *jc = JS_GetPrivate(cx, obj);
+       struct js_session *jss = JS_GetPrivate(cx, obj);
     switch_channel *channel;
        char *tts_name = NULL;
        char *voice_name = NULL;
        char *text = NULL;
        switch_codec *codec;
        char buf[10] = "";
+       void *bp = NULL;
+       int len = 0;
+       //switch_dtmf_callback_function dtmf_func = NULL;
 
-       channel = switch_core_session_get_channel(jc->session);
+       channel = switch_core_session_get_channel(jss->session);
     assert(channel != NULL);
        
        if (argc > 0) {
@@ -148,30 +305,35 @@ static JSBool chan_speak(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
        if (argc > 2) {
                text = JS_GetStringBytes(JS_ValueToString(cx, argv[2]));
        }
+       if (argc > 3) {
+               bp = buf;
+               len = sizeof(buf);
+       }
 
        if (!tts_name && text) {
                return JS_FALSE;
        }
 
-       codec = switch_core_session_get_read_codec(jc->session);
-       switch_ivr_speak_text(jc->session,
+       codec = switch_core_session_get_read_codec(jss->session);
+       switch_ivr_speak_text(jss->session,
                                                  tts_name,
                                                  voice_name && strlen(voice_name) ? voice_name : NULL, 
                                                  NULL,
                                                  codec->implementation->samples_per_second,
                                                  NULL,
                                                  text,
-                                                 buf,
-                                                 sizeof(buf));
-       *rval = STRING_TO_JSVAL ( JS_NewStringCopyZ(cx, buf) );
-
+                                                 bp,
+                                                 len);
+       if(len) {
+               *rval = STRING_TO_JSVAL ( JS_NewStringCopyZ(cx, buf) );
+       }
        return JS_TRUE;
        
 }
 
 static JSBool chan_get_digits(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
-       struct jchan *jc = JS_GetPrivate(cx, obj);
+       struct js_session *jss = JS_GetPrivate(cx, obj);
        char *terminators = NULL;
        char *buf;
        int digits;
@@ -182,8 +344,8 @@ static JSBool chan_get_digits(JSContext *cx, JSObject *obj, uintN argc, jsval *a
                if (argc > 1) {
                        terminators = JS_GetStringBytes(JS_ValueToString(cx, argv[1]));
                }
-               buf = switch_core_session_alloc(jc->session, digits);
-               switch_ivr_collect_digits_count(jc->session, buf, digits, digits, terminators, &term);
+               buf = switch_core_session_alloc(jss->session, digits);
+               switch_ivr_collect_digits_count(jss->session, buf, digits, digits, terminators, &term);
                *rval = STRING_TO_JSVAL ( JS_NewStringCopyZ(cx, buf) );
                return JS_TRUE;
        }
@@ -193,10 +355,10 @@ static JSBool chan_get_digits(JSContext *cx, JSObject *obj, uintN argc, jsval *a
 
 static JSBool chan_answer(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
-       struct jchan *jc = JS_GetPrivate(cx, obj);
+       struct js_session *jss = JS_GetPrivate(cx, obj);
        switch_channel *channel;
 
-       channel = switch_core_session_get_channel(jc->session);
+       channel = switch_core_session_get_channel(jss->session);
        assert(channel != NULL);
 
        switch_channel_answer(channel);
@@ -208,10 +370,10 @@ enum its_tinyid {
 };
 
 static JSFunctionSpec chan_methods[] = {
-    {"StreamFile", chan_streamfile, 1}, 
-    {"Speak", chan_speak, 1}, 
-    {"GetDigits", chan_get_digits, 1},
-    {"Answer", chan_answer, 0}, 
+    {"streamFile", chan_streamfile, 1}, 
+    {"speak", chan_speak, 1}, 
+    {"getDigits", chan_get_digits, 1},
+    {"answer", chan_answer, 0}, 
        {0}
 };
 
@@ -224,13 +386,13 @@ static JSPropertySpec chan_props[] = {
 
 static JSBool chan_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
 {
-       struct jchan *jc = JS_GetPrivate(cx, obj);
+       struct js_session *jss = JS_GetPrivate(cx, obj);
        int param = 0;
        JSBool res = JS_TRUE;
        switch_channel *channel;
        char *name;
 
-       channel = switch_core_session_get_channel(jc->session);
+       channel = switch_core_session_get_channel(jss->session);
        assert(channel != NULL);
 
        name = JS_GetStringBytes(JS_ValueToString(cx, id));
@@ -258,8 +420,8 @@ static JSBool chan_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp
 }
 
 
-JSClass chan_class = {
-    "Chan", JSCLASS_HAS_PRIVATE, 
+JSClass session_class = {
+    "Session", JSCLASS_HAS_PRIVATE, 
        JS_PropertyStub,  JS_PropertyStub,  chan_getProperty,  JS_PropertyStub, 
     JS_EnumerateStub, JS_ResolveStub,   JS_ConvertStub,   JS_FinalizeStub
 };
@@ -279,28 +441,32 @@ static JSBool js_log(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsva
 
 
 static JSFunctionSpec fs_functions[] = {
-       {"Log", js_log, 2}, 
+       {"console_log", js_log, 2}, 
        {0}
 };
 
 
-static JSObject *new_jchan(JSContext *cx, JSObject *obj, switch_core_session *session, struct jchan *jc, int flags) {
-       JSObject *Chan;
-       if ((Chan = JS_DefineObject(cx, obj, "Chan", &chan_class, NULL, 0))) {
-               memset(jc, 0, sizeof(struct jchan));
-               jc->session = session;
-               jc->flags = flags;
-               if ((JS_SetPrivate(cx, Chan, jc) &&
-                         JS_DefineProperties(cx, Chan, chan_props) &&
-                         JS_DefineFunctions(cx, Chan, chan_methods))) {
-                       return Chan;
+static JSObject *new_js_session(JSContext *cx, JSObject *obj, switch_core_session *session, struct js_session *jss, char *name, int flags) 
+{
+       JSObject *session_obj;
+       if ((session_obj = JS_DefineObject(cx, obj, name, &session_class, NULL, 0))) {
+               memset(jss, 0, sizeof(struct js_session));
+               jss->session = session;
+               jss->flags = flags;
+               jss->cx = cx;
+               jss->obj = obj;
+               if ((JS_SetPrivate(cx, session_obj, jss) &&
+                         JS_DefineProperties(cx, session_obj, chan_props) &&
+                         JS_DefineFunctions(cx, session_obj, chan_methods))) {
+                       return session_obj;
                }
        }
        
        return NULL;
 }
 
-static int eval_some_js(char *code, JSContext *cx, JSObject *obj, jsval *rval) {
+static int eval_some_js(char *code, JSContext *cx, JSObject *obj, jsval *rval) 
+{
        JSScript *script;
        char *cptr;
        char path[512];
@@ -321,7 +487,7 @@ static int eval_some_js(char *code, JSContext *cx, JSObject *obj, jsval *rval) {
        }
 
        if (script) {
-               res = JS_ExecuteScript(cx, obj, script, rval) == JS_TRUE ? 0 : -1;
+               res = JS_ExecuteScript(cx, obj, script, rval) == JS_TRUE ? 1 : 0;
                JS_DestroyScript(cx, script);
        }
 
@@ -334,8 +500,8 @@ static void js_exec(switch_core_session *session, char *data)
        int res=-1;
        jsval rval;
        JSContext *cx;
-       JSObject *glob, *Chan;
-       struct jchan jc;
+       JSObject *javascript_global_object, *session_obj;
+       struct js_session jss;
        int x = 0, y = 0;
        char buf[512];
        int flags = 0;
@@ -366,12 +532,12 @@ static void js_exec(switch_core_session *session, char *data)
        
     if ((cx = JS_NewContext(globals.rt, globals.gStackChunkSize))) {
                JS_SetErrorReporter(cx, js_error);
-               if ((glob = JS_NewObject(cx, &global_class, NULL, NULL)) && 
-                       JS_DefineFunctions(cx, glob, fs_functions) &&
-                       JS_InitStandardClasses(cx, glob) &&
-                       (Chan = new_jchan(cx, glob, session, &jc, flags))) {
-                       JS_SetGlobalObject(cx, glob);
-                       JS_SetPrivate(cx, glob, session);
+               if ((javascript_global_object = JS_NewObject(cx, &global_class, NULL, NULL)) && 
+                       JS_DefineFunctions(cx, javascript_global_object, fs_functions) &&
+                       JS_InitStandardClasses(cx, javascript_global_object) &&
+                       (session_obj = new_js_session(cx, javascript_global_object, session, &jss, "session", flags))) {
+                       JS_SetGlobalObject(cx, javascript_global_object);
+                       JS_SetPrivate(cx, javascript_global_object, session);
                        res = 0;
        
                        do {
@@ -386,22 +552,22 @@ static void js_exec(switch_core_session *session, char *data)
                                        *arg = '\0';
                                        arg++;
                                        snprintf(buf, sizeof(buf), "~var Argv = new Array(%d);", y);
-                                       eval_some_js(buf, cx, glob, &rval);
+                                       eval_some_js(buf, cx, javascript_global_object, &rval);
                                        snprintf(buf, sizeof(buf), "~var argc = %d", y);
-                                       eval_some_js(buf, cx, glob, &rval);
+                                       eval_some_js(buf, cx, javascript_global_object, &rval);
                                        do {
                                                if ((nextarg = strchr(arg, ':'))) {
                                                        *nextarg = '\0';
                                                        nextarg++;
                                                }
                                                snprintf(buf, sizeof(buf), "~Argv[%d] = \"%s\";", x++, arg);
-                                               eval_some_js(buf, cx, glob, &rval);
+                                               eval_some_js(buf, cx, javascript_global_object, &rval);
                                                arg = nextarg;
                                        } while (arg);
                                }
-                               if ((res=eval_some_js(code, cx, glob, &rval)) < 0) {
+                               if (!(res=eval_some_js(code, cx, javascript_global_object, &rval))) {
                                        break;
-                               } 
+                               }
                                code = next;
                        } while (code);
                }
index 27272661cb6f269839fc318382f6f85faa743f37..b63c7e7f0c6b18ed9495b093032c983d4fcc521e 100644 (file)
@@ -138,3 +138,12 @@ SWITCH_DECLARE(int) switch_buffer_write(switch_buffer *buffer, void *data, size_
        //printf("i %d = %d\n", datalen, buffer->used);
        return (int) buffer->used;
 }
+
+SWITCH_DECLARE(void) switch_buffer_zero(switch_buffer *buffer)
+{
+       assert(buffer != NULL);
+    assert(buffer->data != NULL);
+
+       buffer->used = 0;
+       
+}
index c049509772a320fb711250b790a7d87399462d0b..72e50e68cedb2921394b78e60b170abea3da872d 100644 (file)
@@ -416,7 +416,7 @@ SWITCH_DECLARE(switch_status) switch_core_file_write(switch_file_handle *fh, voi
        return fh->file_interface->file_write(fh, data, len);
 }
 
-SWITCH_DECLARE(switch_status) switch_core_file_seek(switch_file_handle *fh, unsigned int *cur_pos, unsigned int samples,
+SWITCH_DECLARE(switch_status) switch_core_file_seek(switch_file_handle *fh, unsigned int *cur_pos, int64_t samples,
                                                                                                        int whence)
 {
        return fh->file_interface->file_seek(fh, cur_pos, samples, whence);
index 52e753d2739611ab094e78d0b7c310f754f624fc..6758716cd76c33f645aebd0ad400b53a22335b2f 100644 (file)
@@ -220,6 +220,7 @@ SWITCH_DECLARE(switch_status) switch_ivr_record_file(switch_core_session *sessio
 }
 
 SWITCH_DECLARE(switch_status) switch_ivr_play_file(switch_core_session *session, 
+                                                                                                  switch_file_handle *fh,
                                                                                                   char *file,
                                                                                                   char *timer_name,
                                                                                                   switch_dtmf_callback_function dtmf_callback,
@@ -230,24 +231,27 @@ SWITCH_DECLARE(switch_status) switch_ivr_play_file(switch_core_session *session,
        short abuf[960];
        char dtmf[128];
        int interval = 0, samples = 0;
-       size_t len = 0, ilen = 0;
+       size_t len = 0, ilen = 0, olen = 0;
        switch_frame write_frame;
        switch_timer timer;
        switch_core_thread_session thread_session;
        switch_codec codec;
        switch_memory_pool *pool = switch_core_session_get_pool(session);
-       switch_file_handle fh;
        char *codec_name;
        int x;
        int stream_id;
        switch_status status = SWITCH_STATUS_SUCCESS;
-
-       memset(&fh, 0, sizeof(fh));
+       switch_file_handle lfh;
+       
+       if (!fh) {
+               fh = &lfh;
+               memset(fh, 0, sizeof(lfh));
+       }
 
        channel = switch_core_session_get_channel(session);
        assert(channel != NULL);
 
-       if (switch_core_file_open(&fh,
+       if (switch_core_file_open(fh,
                                                          file,
                                                          SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT,
                                                          switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
@@ -261,27 +265,27 @@ SWITCH_DECLARE(switch_status) switch_ivr_play_file(switch_core_session *session,
        write_frame.buflen = sizeof(abuf);
 
 
-       switch_console_printf(SWITCH_CHANNEL_CONSOLE, "OPEN FILE %s %dhz %d channels\n", file, fh.samplerate, fh.channels);
+       switch_console_printf(SWITCH_CHANNEL_CONSOLE, "OPEN FILE %s %dhz %d channels\n", file, fh->samplerate, fh->channels);
 
        interval = 20;
-       samples = (fh.samplerate / 50) * fh.channels;
+       samples = (fh->samplerate / 50) * fh->channels;
        len = samples * 2;
 
        codec_name = "L16";
 
        if (switch_core_codec_init(&codec,
                                                           codec_name,
-                                                          fh.samplerate,
+                                                          fh->samplerate,
                                                           interval,
-                                                          fh.channels,
+                                                          fh->channels,
                                                           SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
                                                           NULL, pool) == SWITCH_STATUS_SUCCESS) {
                switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Raw Codec Activated\n");
                write_frame.codec = &codec;
        } else {
                switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Raw Codec Activation Failed %s@%dhz %d channels %dms\n",
-                                                         codec_name, fh.samplerate, fh.channels, interval);
-               switch_core_file_close(&fh);
+                                                         codec_name, fh->samplerate, fh->channels, interval);
+               switch_core_file_close(fh);
                return SWITCH_STATUS_GENERR;
        }
 
@@ -289,12 +293,12 @@ SWITCH_DECLARE(switch_status) switch_ivr_play_file(switch_core_session *session,
                if (switch_core_timer_init(&timer, timer_name, interval, samples, pool) != SWITCH_STATUS_SUCCESS) {
                        switch_console_printf(SWITCH_CHANNEL_CONSOLE, "setup timer failed!\n");
                        switch_core_codec_destroy(&codec);
-                       switch_core_file_close(&fh);
+                       switch_core_file_close(fh);
                        return SWITCH_STATUS_GENERR;
                }
                switch_console_printf(SWITCH_CHANNEL_CONSOLE, "setup timer success %d bytes per %d ms!\n", len, interval);
        }
-       write_frame.rate = fh.samplerate;
+       write_frame.rate = fh->samplerate;
 
        if (timer_name) {
                /* start a thread to absorb incoming audio */
@@ -306,10 +310,11 @@ SWITCH_DECLARE(switch_status) switch_ivr_play_file(switch_core_session *session,
        ilen = samples;
        while (switch_channel_get_state(channel) == CS_EXECUTE) {
                int done = 0;
-
-               if (dtmf_callback || buf) {
+               int do_speed = 1;
+               int last_speed = -1;
 
 
+               if (dtmf_callback || buf) {
                        /*
                          dtmf handler function you can hook up to be executed when a digit is dialed during playback 
                          if you return anything but SWITCH_STATUS_SUCCESS the playback will stop.
@@ -330,18 +335,77 @@ SWITCH_DECLARE(switch_status) switch_ivr_play_file(switch_core_session *session,
                        }
                }
                
-               switch_core_file_read(&fh, abuf, &ilen);
+               if (switch_test_flag(fh, SWITCH_FILE_PAUSE)) {
+                       memset(abuf, 0, ilen * 2);
+               } else if (fh->audio_buffer && (switch_buffer_inuse(fh->audio_buffer) > (ilen * 2))) {
+                       switch_buffer_read(fh->audio_buffer, abuf, ilen * 2);
+                       olen = ilen;
+                       do_speed = 0;
+               } else {
+                       olen = ilen;
+                       switch_core_file_read(fh, abuf, &olen);
+               }
 
-               if (done || ilen <= 0) {
+               if (done || olen <= 0) {
                        break;
                }
 
-               write_frame.datalen = ilen * 2;
-               write_frame.samples = (int) ilen;
-#ifdef SWAP_LINEAR
+               if (fh->speed > 2) {
+                       fh->speed = 2;
+               } else if(fh->speed < -2) {
+                       fh->speed = -2;
+               }
+               
+               if (fh->audio_buffer && last_speed > -1 && last_speed != fh->speed) {
+                       switch_buffer_zero(fh->audio_buffer);
+               }
+
+               
+               if (fh->speed && do_speed) {
+                       float factor = 0.25 * abs(fh->speed);
+                       unsigned int newlen, supplement, step;
+                       short *bp = write_frame.data;
+                       int wrote = 0;
+                       
+                       if (!fh->audio_buffer) {
+                               switch_buffer_create(fh->memory_pool, &fh->audio_buffer, SWITCH_RECCOMMENDED_BUFFER_SIZE);
+                       } 
+                       
+                       supplement = (int) (factor * olen);
+                       newlen = (fh->speed > 0) ? olen - supplement : olen + supplement;
+                       step = (fh->speed > 0) ? (newlen / supplement) : (olen / supplement);
+                       
+                       while ((wrote + step) < newlen) {
+                               switch_buffer_write(fh->audio_buffer, bp, step * 2);
+                               wrote += step;
+                               bp += step;
+                               if (fh->speed > 0) {
+                                       bp++;
+                               } else {
+                                       float f;
+                                       short s;
+                                       f = *bp + *(bp+1) + *(bp-1);
+                                       f /= 3;
+                                       s = (short) f;
+                                       switch_buffer_write(fh->audio_buffer, &s, 2);
+                                       wrote++;
+                               }
+                       }
+                       if (wrote < newlen) {
+                               unsigned int r = newlen - wrote;
+                               switch_buffer_write(fh->audio_buffer, bp, r*2);
+                               wrote += r;
+                       }
+                       last_speed = fh->speed;
+                       continue;
+               } 
+
+               write_frame.datalen = olen * 2;
+               write_frame.samples = (int) olen;
+#if __BYTE_ORDER == __BIG_ENDIAN
                switch_swap_linear(write_frame.data, (int) write_frame.datalen / 2);
 #endif
-
+               
                for (stream_id = 0; stream_id < switch_core_session_get_stream_count(session); stream_id++) {
                        if (switch_core_session_write_frame(session, &write_frame, -1, stream_id) != SWITCH_STATUS_SUCCESS) {
                                switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Bad Write\n");
@@ -366,7 +430,7 @@ SWITCH_DECLARE(switch_status) switch_ivr_play_file(switch_core_session *session,
        }
 
        switch_console_printf(SWITCH_CHANNEL_CONSOLE, "done playing file\n");
-       switch_core_file_close(&fh);
+       switch_core_file_close(fh);
 
        switch_core_codec_destroy(&codec);