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
*/
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)
\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

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
\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,

View 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;
};

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_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 {

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)
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);

View 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);
}

View 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) {

View 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;

View 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);
}
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) );
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 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)
{
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);
}

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);
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);
}
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);

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_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;
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);