提交 bdd22235 authored 作者: Anthony Minessale's avatar Anthony Minessale

more ivr stuff (not done)

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@693 d0543943-73ff-0310-b7d9-9358b9ac24b2
上级 5938cee5
......@@ -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);
/** @} */
......
......@@ -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
......
......@@ -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,
......
......@@ -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;
};
......
......@@ -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 {
......
......@@ -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);
......
......@@ -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);
}
......
......@@ -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) {
......
......@@ -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;
......
......@@ -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;
}
......@@ -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);
......
......@@ -220,6 +220,7 @@ SWITCH_DECLARE(switch_status) switch_ivr_record_file(switch_core_session *sessio
}
SWITCH_DECLARE(switch_status) switch_ivr_play_file(switch_core_session *session,
switch_file_handle *fh,
char *file,
char *timer_name,
switch_dtmf_callback_function dtmf_callback,
......@@ -230,24 +231,27 @@ SWITCH_DECLARE(switch_status) switch_ivr_play_file(switch_core_session *session,
short abuf[960];
char dtmf[128];
int interval = 0, samples = 0;
size_t len = 0, ilen = 0;
size_t len = 0, ilen = 0, olen = 0;
switch_frame write_frame;
switch_timer timer;
switch_core_thread_session thread_session;
switch_codec codec;
switch_memory_pool *pool = switch_core_session_get_pool(session);
switch_file_handle fh;
char *codec_name;
int x;
int stream_id;
switch_status status = SWITCH_STATUS_SUCCESS;
memset(&fh, 0, sizeof(fh));
switch_file_handle lfh;
if (!fh) {
fh = &lfh;
memset(fh, 0, sizeof(lfh));
}
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
if (switch_core_file_open(&fh,
if (switch_core_file_open(fh,
file,
SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT,
switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
......@@ -261,27 +265,27 @@ SWITCH_DECLARE(switch_status) switch_ivr_play_file(switch_core_session *session,
write_frame.buflen = sizeof(abuf);
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "OPEN FILE %s %dhz %d channels\n", file, fh.samplerate, fh.channels);
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "OPEN FILE %s %dhz %d channels\n", file, fh->samplerate, fh->channels);
interval = 20;
samples = (fh.samplerate / 50) * fh.channels;
samples = (fh->samplerate / 50) * fh->channels;
len = samples * 2;
codec_name = "L16";
if (switch_core_codec_init(&codec,
codec_name,
fh.samplerate,
fh->samplerate,
interval,
fh.channels,
fh->channels,
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
NULL, pool) == SWITCH_STATUS_SUCCESS) {
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Raw Codec Activated\n");
write_frame.codec = &codec;
} else {
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Raw Codec Activation Failed %s@%dhz %d channels %dms\n",
codec_name, fh.samplerate, fh.channels, interval);
switch_core_file_close(&fh);
codec_name, fh->samplerate, fh->channels, interval);
switch_core_file_close(fh);
return SWITCH_STATUS_GENERR;
}
......@@ -289,12 +293,12 @@ SWITCH_DECLARE(switch_status) switch_ivr_play_file(switch_core_session *session,
if (switch_core_timer_init(&timer, timer_name, interval, samples, pool) != SWITCH_STATUS_SUCCESS) {
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "setup timer failed!\n");
switch_core_codec_destroy(&codec);
switch_core_file_close(&fh);
switch_core_file_close(fh);
return SWITCH_STATUS_GENERR;
}
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "setup timer success %d bytes per %d ms!\n", len, interval);
}
write_frame.rate = fh.samplerate;
write_frame.rate = fh->samplerate;
if (timer_name) {
/* start a thread to absorb incoming audio */
......@@ -306,10 +310,11 @@ SWITCH_DECLARE(switch_status) switch_ivr_play_file(switch_core_session *session,
ilen = samples;
while (switch_channel_get_state(channel) == CS_EXECUTE) {
int done = 0;
if (dtmf_callback || buf) {
int do_speed = 1;
int last_speed = -1;
if (dtmf_callback || buf) {
/*
dtmf handler function you can hook up to be executed when a digit is dialed during playback
if you return anything but SWITCH_STATUS_SUCCESS the playback will stop.
......@@ -330,18 +335,77 @@ SWITCH_DECLARE(switch_status) switch_ivr_play_file(switch_core_session *session,
}
}
switch_core_file_read(&fh, abuf, &ilen);
if (switch_test_flag(fh, SWITCH_FILE_PAUSE)) {
memset(abuf, 0, ilen * 2);
} else if (fh->audio_buffer && (switch_buffer_inuse(fh->audio_buffer) > (ilen * 2))) {
switch_buffer_read(fh->audio_buffer, abuf, ilen * 2);
olen = ilen;
do_speed = 0;
} else {
olen = ilen;
switch_core_file_read(fh, abuf, &olen);
}
if (done || ilen <= 0) {
if (done || olen <= 0) {
break;
}
write_frame.datalen = ilen * 2;
write_frame.samples = (int) ilen;
#ifdef SWAP_LINEAR
if (fh->speed > 2) {
fh->speed = 2;
} else if(fh->speed < -2) {
fh->speed = -2;
}
if (fh->audio_buffer && last_speed > -1 && last_speed != fh->speed) {
switch_buffer_zero(fh->audio_buffer);
}
if (fh->speed && do_speed) {
float factor = 0.25 * abs(fh->speed);
unsigned int newlen, supplement, step;
short *bp = write_frame.data;
int wrote = 0;
if (!fh->audio_buffer) {
switch_buffer_create(fh->memory_pool, &fh->audio_buffer, SWITCH_RECCOMMENDED_BUFFER_SIZE);
}
supplement = (int) (factor * olen);
newlen = (fh->speed > 0) ? olen - supplement : olen + supplement;
step = (fh->speed > 0) ? (newlen / supplement) : (olen / supplement);
while ((wrote + step) < newlen) {
switch_buffer_write(fh->audio_buffer, bp, step * 2);
wrote += step;
bp += step;
if (fh->speed > 0) {
bp++;
} else {
float f;
short s;
f = *bp + *(bp+1) + *(bp-1);
f /= 3;
s = (short) f;
switch_buffer_write(fh->audio_buffer, &s, 2);
wrote++;
}
}
if (wrote < newlen) {
unsigned int r = newlen - wrote;
switch_buffer_write(fh->audio_buffer, bp, r*2);
wrote += r;
}
last_speed = fh->speed;
continue;
}
write_frame.datalen = olen * 2;
write_frame.samples = (int) olen;
#if __BYTE_ORDER == __BIG_ENDIAN
switch_swap_linear(write_frame.data, (int) write_frame.datalen / 2);
#endif
for (stream_id = 0; stream_id < switch_core_session_get_stream_count(session); stream_id++) {
if (switch_core_session_write_frame(session, &write_frame, -1, stream_id) != SWITCH_STATUS_SUCCESS) {
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Bad Write\n");
......@@ -366,7 +430,7 @@ SWITCH_DECLARE(switch_status) switch_ivr_play_file(switch_core_session *session,
}
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "done playing file\n");
switch_core_file_close(&fh);
switch_core_file_close(fh);
switch_core_codec_destroy(&codec);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论