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:
parent
5938cee550
commit
bdd2223542
|
@ -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);
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
108
src/switch_ivr.c
108
src/switch_ivr.c
|
@ -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);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue