more ivr stuff (not done)

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@693 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Anthony Minessale 2006-02-28 02:08:42 +00:00
parent 5938cee550
commit bdd2223542
13 changed files with 362 additions and 91 deletions

View 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 * \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); 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);
/** @} */ /** @} */

View 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) \param whence the indicator (see traditional seek)
\return SWITCH_STATUS_SUCCESS with cur_pos adjusted to new position \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 \brief Close an open file handle

View 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 \brief play a file from the disk to the session
\param session the session to play the file too \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 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 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 \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. \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_DECLARE(switch_status) switch_ivr_play_file(switch_core_session *session,
switch_file_handle *fh,
char *file, char *file,
char *timer_name, char *timer_name,
switch_dtmf_callback_function dtmf_callback, switch_dtmf_callback_function dtmf_callback,

View File

@ -245,7 +245,7 @@ struct switch_file_interface {
/*! function to write from the file */ /*! function to write from the file */
switch_status (*file_write)(switch_file_handle *, void *data, size_t *len); switch_status (*file_write)(switch_file_handle *, void *data, size_t *len);
/*! function to seek to a certian position in the file */ /*! 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 */ /*! list of supported file extensions */
char **extens; char **extens;
const struct switch_file_interface *next; const struct switch_file_interface *next;
@ -273,10 +273,14 @@ struct switch_file_handle {
int seekable; int seekable;
/*! the sample count of the file */ /*! the sample count of the file */
unsigned int sample_count; unsigned int sample_count;
/*! the speed of the file playback*/
int speed;
/*! the handle's memory pool */ /*! the handle's memory pool */
switch_memory_pool *memory_pool; switch_memory_pool *memory_pool;
/*! private data for the format module to store handle specific info */ /*! private data for the format module to store handle specific info */
void *private_info; void *private_info;
int64_t pos;
switch_buffer *audio_buffer;
}; };

View 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_FLOAT = (1 << 5) - Read data in floats
SWITCH_FILE_DATA_DOUBLE = (1 << 6) - Read data in doubles SWITCH_FILE_DATA_DOUBLE = (1 << 6) - Read data in doubles
SWITCH_FILE_DATA_RAW = (1 << 7) - Read data as is SWITCH_FILE_DATA_RAW = (1 << 7) - Read data as is
SWITCH_FILE_PAUSE = (1 << 8) - Pause
</pre> </pre>
*/ */
typedef enum { typedef enum {
@ -330,6 +331,7 @@ typedef enum {
SWITCH_FILE_DATA_FLOAT = (1 << 5), SWITCH_FILE_DATA_FLOAT = (1 << 5),
SWITCH_FILE_DATA_DOUBLE = (1 << 6), SWITCH_FILE_DATA_DOUBLE = (1 << 6),
SWITCH_FILE_DATA_RAW = (1 << 7), SWITCH_FILE_DATA_RAW = (1 << 7),
SWITCH_FILE_PAUSE = (1 << 8)
} switch_file_flag; } switch_file_flag;
typedef enum { typedef enum {

View 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) /* 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... 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) { if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) {
switch_channel_hangup(channel); switch_channel_hangup(channel);

View File

@ -64,7 +64,7 @@ static void playback_function(switch_core_session *session, char *data)
channel = switch_core_session_get_channel(session); channel = switch_core_session_get_channel(session);
assert(channel != NULL); 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); switch_channel_hangup(channel);
} }

View File

@ -117,6 +117,8 @@ struct private_object {
char call_id[50]; char call_id[50];
int ssrc; int ssrc;
char last_digit; char last_digit;
unsigned int dc;
time_t last_digit_time;
switch_mutex_t *rtp_lock; switch_mutex_t *rtp_lock;
switch_queue_t *dtmf_queue; switch_queue_t *dtmf_queue;
char out_digit; char out_digit;
@ -480,6 +482,8 @@ static switch_status exosip_answer_channel(switch_core_session *session)
struct private_object *tech_pvt; struct private_object *tech_pvt;
switch_channel *channel = NULL; switch_channel *channel = NULL;
assert(session != NULL);
channel = switch_core_session_get_channel(session); channel = switch_core_session_get_channel(session);
assert(channel != NULL); 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]; int duration = (packet[2]<<8) + packet[3];
char key = switch_rfc2833_to_char(packet[0]); char key = switch_rfc2833_to_char(packet[0]);
if (duration && end && key != tech_pvt->last_digit) { /* SHEESH.... Curse you RFC2833 inventors!!!!*/
char digit_str[] = {key, 0}; if ((time(NULL) - tech_pvt->last_digit_time) > 2) {
switch_channel_queue_dtmf(channel, digit_str); tech_pvt->last_digit = 0;
tech_pvt->last_digit = key; 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) { if (globals.supress_telephony_events && payload != tech_pvt->payload_num) {

View File

@ -138,7 +138,7 @@ switch_status sndfile_file_open(switch_file_handle *handle, char *path)
handle->format = context->sfinfo.format; handle->format = context->sfinfo.format;
handle->sections = context->sfinfo.sections; handle->sections = context->sfinfo.sections;
handle->seekable = context->sfinfo.seekable; handle->seekable = context->sfinfo.seekable;
handle->speed = 0;
handle->private_info = context; handle->private_info = context;
return SWITCH_STATUS_SUCCESS; return SWITCH_STATUS_SUCCESS;
@ -153,15 +153,17 @@ switch_status sndfile_file_close(switch_file_handle *handle)
return SWITCH_STATUS_SUCCESS; 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; sndfile_context *context = handle->private_info;
if (!handle->seekable) { if (!handle->seekable) {
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "File is not seekable\n");
return SWITCH_STATUS_NOTIMPL; return SWITCH_STATUS_NOTIMPL;
} }
*cur_sample = (unsigned int) sf_seek(context->handle, samples, whence); *cur_sample = (unsigned int) sf_seek(context->handle, samples, whence);
handle->pos = *cur_sample;
return SWITCH_STATUS_SUCCESS; return SWITCH_STATUS_SUCCESS;

View File

@ -53,6 +53,7 @@
static const char modname[] = "mod_spidermonkey"; static const char modname[] = "mod_spidermonkey";
static int eval_some_js(char *code, JSContext *cx, JSObject *obj, jsval *rval);
static struct { static struct {
size_t gStackChunkSize; 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; switch_core_session *session;
JSContext *cx;
JSObject *obj;
unsigned int flags; 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); char code[2048];
JSString *str = NULL; struct dtmf_callback_state *cb_state = buf;
char *filename = NULL; struct js_session *jss = cb_state->session_state;
char buf[25] = ""; 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);
}
if (argc > 0) { for(d = dtmf; *d; d++) {
if ((str = JS_ValueToString(cx, argv[0])) && (filename = JS_GetStringBytes(str))) { cb_state->ret_buffer[cb_state->ret_buffer_len++] = *d;
switch_ivr_play_file(jc->session, filename, NULL, NULL, buf, sizeof(buf)); if ((cb_state->ret_buffer_len > cb_state->digit_count)||
*rval = STRING_TO_JSVAL ( JS_NewStringCopyZ(cx, buf) ); (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 JS_FALSE;
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) {
file_name = JS_GetStringBytes(JS_ValueToString(cx, argv[0]));
if (switch_strlen_zero(file_name)) {
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) 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; switch_channel *channel;
char *tts_name = NULL; char *tts_name = NULL;
char *voice_name = NULL; char *voice_name = NULL;
char *text = NULL; char *text = NULL;
switch_codec *codec; switch_codec *codec;
char buf[10] = ""; 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); assert(channel != NULL);
if (argc > 0) { if (argc > 0) {
@ -148,30 +305,35 @@ static JSBool chan_speak(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
if (argc > 2) { if (argc > 2) {
text = JS_GetStringBytes(JS_ValueToString(cx, argv[2])); text = JS_GetStringBytes(JS_ValueToString(cx, argv[2]));
} }
if (argc > 3) {
bp = buf;
len = sizeof(buf);
}
if (!tts_name && text) { if (!tts_name && text) {
return JS_FALSE; return JS_FALSE;
} }
codec = switch_core_session_get_read_codec(jc->session); codec = switch_core_session_get_read_codec(jss->session);
switch_ivr_speak_text(jc->session, switch_ivr_speak_text(jss->session,
tts_name, tts_name,
voice_name && strlen(voice_name) ? voice_name : NULL, voice_name && strlen(voice_name) ? voice_name : NULL,
NULL, NULL,
codec->implementation->samples_per_second, codec->implementation->samples_per_second,
NULL, NULL,
text, text,
buf, bp,
sizeof(buf)); len);
*rval = STRING_TO_JSVAL ( JS_NewStringCopyZ(cx, buf) ); if(len) {
*rval = STRING_TO_JSVAL ( JS_NewStringCopyZ(cx, buf) );
}
return JS_TRUE; return JS_TRUE;
} }
static JSBool chan_get_digits(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) 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 *terminators = NULL;
char *buf; char *buf;
int digits; int digits;
@ -182,8 +344,8 @@ static JSBool chan_get_digits(JSContext *cx, JSObject *obj, uintN argc, jsval *a
if (argc > 1) { if (argc > 1) {
terminators = JS_GetStringBytes(JS_ValueToString(cx, argv[1])); terminators = JS_GetStringBytes(JS_ValueToString(cx, argv[1]));
} }
buf = switch_core_session_alloc(jc->session, digits); buf = switch_core_session_alloc(jss->session, digits);
switch_ivr_collect_digits_count(jc->session, buf, digits, digits, terminators, &term); switch_ivr_collect_digits_count(jss->session, buf, digits, digits, terminators, &term);
*rval = STRING_TO_JSVAL ( JS_NewStringCopyZ(cx, buf) ); *rval = STRING_TO_JSVAL ( JS_NewStringCopyZ(cx, buf) );
return JS_TRUE; 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) 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; switch_channel *channel;
channel = switch_core_session_get_channel(jc->session); channel = switch_core_session_get_channel(jss->session);
assert(channel != NULL); assert(channel != NULL);
switch_channel_answer(channel); switch_channel_answer(channel);
@ -208,10 +370,10 @@ enum its_tinyid {
}; };
static JSFunctionSpec chan_methods[] = { static JSFunctionSpec chan_methods[] = {
{"StreamFile", chan_streamfile, 1}, {"streamFile", chan_streamfile, 1},
{"Speak", chan_speak, 1}, {"speak", chan_speak, 1},
{"GetDigits", chan_get_digits, 1}, {"getDigits", chan_get_digits, 1},
{"Answer", chan_answer, 0}, {"answer", chan_answer, 0},
{0} {0}
}; };
@ -224,13 +386,13 @@ static JSPropertySpec chan_props[] = {
static JSBool chan_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) 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; int param = 0;
JSBool res = JS_TRUE; JSBool res = JS_TRUE;
switch_channel *channel; switch_channel *channel;
char *name; char *name;
channel = switch_core_session_get_channel(jc->session); channel = switch_core_session_get_channel(jss->session);
assert(channel != NULL); assert(channel != NULL);
name = JS_GetStringBytes(JS_ValueToString(cx, id)); 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 = { JSClass session_class = {
"Chan", JSCLASS_HAS_PRIVATE, "Session", JSCLASS_HAS_PRIVATE,
JS_PropertyStub, JS_PropertyStub, chan_getProperty, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, chan_getProperty, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub 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[] = { static JSFunctionSpec fs_functions[] = {
{"Log", js_log, 2}, {"console_log", js_log, 2},
{0} {0}
}; };
static JSObject *new_jchan(JSContext *cx, JSObject *obj, switch_core_session *session, struct jchan *jc, int flags) { static JSObject *new_js_session(JSContext *cx, JSObject *obj, switch_core_session *session, struct js_session *jss, char *name, int flags)
JSObject *Chan; {
if ((Chan = JS_DefineObject(cx, obj, "Chan", &chan_class, NULL, 0))) { JSObject *session_obj;
memset(jc, 0, sizeof(struct jchan)); if ((session_obj = JS_DefineObject(cx, obj, name, &session_class, NULL, 0))) {
jc->session = session; memset(jss, 0, sizeof(struct js_session));
jc->flags = flags; jss->session = session;
if ((JS_SetPrivate(cx, Chan, jc) && jss->flags = flags;
JS_DefineProperties(cx, Chan, chan_props) && jss->cx = cx;
JS_DefineFunctions(cx, Chan, chan_methods))) { jss->obj = obj;
return Chan; 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; 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; JSScript *script;
char *cptr; char *cptr;
char path[512]; char path[512];
@ -321,7 +487,7 @@ static int eval_some_js(char *code, JSContext *cx, JSObject *obj, jsval *rval) {
} }
if (script) { 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); JS_DestroyScript(cx, script);
} }
@ -334,8 +500,8 @@ static void js_exec(switch_core_session *session, char *data)
int res=-1; int res=-1;
jsval rval; jsval rval;
JSContext *cx; JSContext *cx;
JSObject *glob, *Chan; JSObject *javascript_global_object, *session_obj;
struct jchan jc; struct js_session jss;
int x = 0, y = 0; int x = 0, y = 0;
char buf[512]; char buf[512];
int flags = 0; 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))) { if ((cx = JS_NewContext(globals.rt, globals.gStackChunkSize))) {
JS_SetErrorReporter(cx, js_error); JS_SetErrorReporter(cx, js_error);
if ((glob = JS_NewObject(cx, &global_class, NULL, NULL)) && if ((javascript_global_object = JS_NewObject(cx, &global_class, NULL, NULL)) &&
JS_DefineFunctions(cx, glob, fs_functions) && JS_DefineFunctions(cx, javascript_global_object, fs_functions) &&
JS_InitStandardClasses(cx, glob) && JS_InitStandardClasses(cx, javascript_global_object) &&
(Chan = new_jchan(cx, glob, session, &jc, flags))) { (session_obj = new_js_session(cx, javascript_global_object, session, &jss, "session", flags))) {
JS_SetGlobalObject(cx, glob); JS_SetGlobalObject(cx, javascript_global_object);
JS_SetPrivate(cx, glob, session); JS_SetPrivate(cx, javascript_global_object, session);
res = 0; res = 0;
do { do {
@ -386,22 +552,22 @@ static void js_exec(switch_core_session *session, char *data)
*arg = '\0'; *arg = '\0';
arg++; arg++;
snprintf(buf, sizeof(buf), "~var Argv = new Array(%d);", y); 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); 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 { do {
if ((nextarg = strchr(arg, ':'))) { if ((nextarg = strchr(arg, ':'))) {
*nextarg = '\0'; *nextarg = '\0';
nextarg++; nextarg++;
} }
snprintf(buf, sizeof(buf), "~Argv[%d] = \"%s\";", x++, arg); 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; arg = nextarg;
} while (arg); } while (arg);
} }
if ((res=eval_some_js(code, cx, glob, &rval)) < 0) { if (!(res=eval_some_js(code, cx, javascript_global_object, &rval))) {
break; break;
} }
code = next; code = next;
} while (code); } while (code);
} }

View 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); //printf("i %d = %d\n", datalen, buffer->used);
return (int) 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;
}

View 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); 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) int whence)
{ {
return fh->file_interface->file_seek(fh, cur_pos, samples, whence); return fh->file_interface->file_seek(fh, cur_pos, samples, whence);

View 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_DECLARE(switch_status) switch_ivr_play_file(switch_core_session *session,
switch_file_handle *fh,
char *file, char *file,
char *timer_name, char *timer_name,
switch_dtmf_callback_function dtmf_callback, 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]; short abuf[960];
char dtmf[128]; char dtmf[128];
int interval = 0, samples = 0; int interval = 0, samples = 0;
size_t len = 0, ilen = 0; size_t len = 0, ilen = 0, olen = 0;
switch_frame write_frame; switch_frame write_frame;
switch_timer timer; switch_timer timer;
switch_core_thread_session thread_session; switch_core_thread_session thread_session;
switch_codec codec; switch_codec codec;
switch_memory_pool *pool = switch_core_session_get_pool(session); switch_memory_pool *pool = switch_core_session_get_pool(session);
switch_file_handle fh;
char *codec_name; char *codec_name;
int x; int x;
int stream_id; int stream_id;
switch_status status = SWITCH_STATUS_SUCCESS; switch_status status = SWITCH_STATUS_SUCCESS;
switch_file_handle lfh;
memset(&fh, 0, sizeof(fh));
if (!fh) {
fh = &lfh;
memset(fh, 0, sizeof(lfh));
}
channel = switch_core_session_get_channel(session); channel = switch_core_session_get_channel(session);
assert(channel != NULL); assert(channel != NULL);
if (switch_core_file_open(&fh, if (switch_core_file_open(fh,
file, file,
SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT,
switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { 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); 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; interval = 20;
samples = (fh.samplerate / 50) * fh.channels; samples = (fh->samplerate / 50) * fh->channels;
len = samples * 2; len = samples * 2;
codec_name = "L16"; codec_name = "L16";
if (switch_core_codec_init(&codec, if (switch_core_codec_init(&codec,
codec_name, codec_name,
fh.samplerate, fh->samplerate,
interval, interval,
fh.channels, fh->channels,
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
NULL, pool) == SWITCH_STATUS_SUCCESS) { NULL, pool) == SWITCH_STATUS_SUCCESS) {
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Raw Codec Activated\n"); switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Raw Codec Activated\n");
write_frame.codec = &codec; write_frame.codec = &codec;
} else { } else {
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Raw Codec Activation Failed %s@%dhz %d channels %dms\n", switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Raw Codec Activation Failed %s@%dhz %d channels %dms\n",
codec_name, fh.samplerate, fh.channels, interval); codec_name, fh->samplerate, fh->channels, interval);
switch_core_file_close(&fh); switch_core_file_close(fh);
return SWITCH_STATUS_GENERR; 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) { 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_console_printf(SWITCH_CHANNEL_CONSOLE, "setup timer failed!\n");
switch_core_codec_destroy(&codec); switch_core_codec_destroy(&codec);
switch_core_file_close(&fh); switch_core_file_close(fh);
return SWITCH_STATUS_GENERR; return SWITCH_STATUS_GENERR;
} }
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "setup timer success %d bytes per %d ms!\n", len, interval); 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) { if (timer_name) {
/* start a thread to absorb incoming audio */ /* 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; ilen = samples;
while (switch_channel_get_state(channel) == CS_EXECUTE) { while (switch_channel_get_state(channel) == CS_EXECUTE) {
int done = 0; int done = 0;
int do_speed = 1;
int last_speed = -1;
if (dtmf_callback || buf) { if (dtmf_callback || buf) {
/* /*
dtmf handler function you can hook up to be executed when a digit is dialed during playback 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. 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; break;
} }
write_frame.datalen = ilen * 2; if (fh->speed > 2) {
write_frame.samples = (int) ilen; fh->speed = 2;
#ifdef SWAP_LINEAR } 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); switch_swap_linear(write_frame.data, (int) write_frame.datalen / 2);
#endif #endif
for (stream_id = 0; stream_id < switch_core_session_get_stream_count(session); stream_id++) { 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) { if (switch_core_session_write_frame(session, &write_frame, -1, stream_id) != SWITCH_STATUS_SUCCESS) {
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Bad Write\n"); 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_console_printf(SWITCH_CHANNEL_CONSOLE, "done playing file\n");
switch_core_file_close(&fh); switch_core_file_close(fh);
switch_core_codec_destroy(&codec); switch_core_codec_destroy(&codec);