mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-04-13 15:50:59 +00:00
Ringback (sponsored by Front Logic)
This addition lets you set artifical ringback on a channel that is waiting for an originated call to be answered. the syntax is <action application="set" data="ringback=[data]"/> where data is either the full path to an audio file or a teletone generation script.. syntax of teletone scripts LEGEND: 0-9,a-d,*,# (standard dtmf tones) variables: c,r,d,v,>,<,+,w,l,L,% c (channels) - Sets the number of channels. r (rate) - Sets the sample rate. d (duration) - Sets the default tone duration. v (volume) - Sets the default volume. > (decrease vol) - factor to decrease volume by per frame (0 for even decrease across duration). < (increase vol) - factor to increase volume by per frame (0 for even increase across duration). + (step) - factor to step by used by < and >. w (wait) - default silence after each tone. l (loops) - number of times to repeat each tone in the script. L (LOOPS) - number of times to repeat the the whole script. % (manual tone) - a generic tone specified by a duration, a wait and a list of frequencies. standard tones can have custom duration per use with the () modifier 7(1000, 500) to generate DTMF 7 for 1 second then pause .5 seconds EXAMPLES UK Ring Tone [400+450 hz on for 400ms off for 200ms then 400+450 hz on for 400ms off for 2200ms] %(400,200,400,450);%(400,2200,400,450) US Ring Tone [440+480 hz on for 2000ms off for 4000ms] %(2000,4000,440,480) ATT BONG [volume level 4000, even decay, step by 2, # key for 60ms with no wait, volume level 2000, 350+440hz {us dialtone} for 940ms v=4000;>=0;+=2;#(60,0);v=2000;%(940,0,350,440) SIT Tone 913.8 hz for 274 ms with no wait, 1370.6 hz for 274 ms with no wait, 1776.7 hz for 380ms with no wait %(274,0,913.8);%(274,0,1370.6);%(380,0,1776.7) ATTN TONE (phone's off the hook!) 1400+2060+2450+2600 hz for 100ms with 100ms wait %(100,100,1400,2060,2450,2600) git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3408 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
parent
0984933c36
commit
d7baa16132
@ -8,6 +8,12 @@
|
||||
<!--Most channels to allow at once -->
|
||||
<param name="max-sessions" value="1000"/>
|
||||
</settings>
|
||||
<!--Any variables defined here will be available in every channel, in the dialplan etc -->
|
||||
<variables>
|
||||
<variable name="uk-ring" value="%(400,200,400,450);%(400,2200,400,450)"/>
|
||||
<variable name="us-ring" value="%(2000, 4000, 440.0, 480.0)"/>
|
||||
<variable name="bong-ring" value="v=4000;>=0;+=2;#(60,0);v=2000;%(940,0,350,440)"/>
|
||||
</variables>
|
||||
</configuration>
|
||||
|
||||
<configuration name="modules.conf" description="Modules">
|
||||
@ -429,6 +435,9 @@
|
||||
|
||||
<extension name="testmusic">
|
||||
<condition field="destination_number" expression="^1234$">
|
||||
<!-- Request a certain tone/file to be played while you wait for the call to be answered-->
|
||||
<action application="set" data="ringback=${us-ring}"/>
|
||||
<!--<action application="set" data="ringback=/home/ring.wav"/>-->
|
||||
<action application="bridge" data="sofia/test/1234@66.250.68.194"/>
|
||||
</condition>
|
||||
</extension>
|
||||
|
@ -84,11 +84,14 @@ int teletone_init_session(teletone_generation_session_t *ts, int buflen, tone_ha
|
||||
ts->user_data = user_data;
|
||||
ts->volume = 1500;
|
||||
ts->decay_step = 0;
|
||||
if ((ts->buffer = calloc(buflen, sizeof(teletone_audio_t))) == 0) {
|
||||
return -1;
|
||||
if (buflen) {
|
||||
if ((ts->buffer = calloc(buflen, sizeof(teletone_audio_t))) == 0) {
|
||||
return -1;
|
||||
}
|
||||
ts->datalen = buflen;
|
||||
} else {
|
||||
ts->dynamic = 1024;
|
||||
}
|
||||
ts->datalen = buflen;
|
||||
|
||||
/* Add Standard DTMF Tones */
|
||||
teletone_set_tone(ts, '1', 697.0, 1209.0, 0.0);
|
||||
teletone_set_tone(ts, '2', 697.0, 1336.0, 0.0);
|
||||
@ -120,8 +123,21 @@ int teletone_destroy_session(teletone_generation_session_t *ts)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Generate a specified number of samples containing the three specified
|
||||
* frequencies (in hertz) and dump to the file descriptor audio_fd. */
|
||||
static int ensure_buffer(teletone_generation_session_t *ts, int need)
|
||||
{
|
||||
need += ts->samples;
|
||||
need *= sizeof(teletone_audio_t);
|
||||
need *= ts->channels;
|
||||
|
||||
if (need > ts->datalen) {
|
||||
ts->datalen = need + ts->dynamic;
|
||||
if (!(ts->buffer = realloc(ts->buffer, ts->datalen))) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int teletone_mux_tones(teletone_generation_session_t *ts, teletone_tone_map_t *map)
|
||||
{
|
||||
@ -159,6 +175,11 @@ int teletone_mux_tones(teletone_generation_session_t *ts, teletone_tone_map_t *m
|
||||
duration *= ts->channels;
|
||||
}
|
||||
|
||||
if (ts->dynamic) {
|
||||
if (ensure_buffer(ts, duration)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
for (ts->samples = 0; ts->samples < ts->datalen && ts->samples < duration; ts->samples++) {
|
||||
if (ts->decay_step && !(ts->samples % ts->decay_step) && ts->volume > 0 && ts->samples > decay) {
|
||||
ts->volume += ts->decay_direction;
|
||||
@ -179,6 +200,11 @@ int teletone_mux_tones(teletone_generation_session_t *ts, teletone_tone_map_t *m
|
||||
|
||||
}
|
||||
}
|
||||
if (ts->dynamic) {
|
||||
if (ensure_buffer(ts, wait)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
for (c = 0; c < ts->channels; c++) {
|
||||
for (i = 0; i < wait && ts->samples < ts->datalen; i++) {
|
||||
ts->buffer[ts->samples++] = 0;
|
||||
@ -211,19 +237,37 @@ int teletone_mux_tones(teletone_generation_session_t *ts, teletone_tone_map_t *m
|
||||
return ts->samples;
|
||||
}
|
||||
|
||||
/* don't ask */
|
||||
static char *my_strdup (const char *s)
|
||||
{
|
||||
size_t len = strlen (s) + 1;
|
||||
void *new = malloc (len);
|
||||
|
||||
if (new == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (char *) memcpy (new, s, len);
|
||||
}
|
||||
|
||||
int teletone_run(teletone_generation_session_t *ts, char *cmd)
|
||||
{
|
||||
char *data, *cur, *end;
|
||||
char *data = NULL, *cur = NULL, *end = NULL;
|
||||
int var = 0, LOOPING = 0;
|
||||
|
||||
if (!cmd) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
do {
|
||||
data = strdup(cmd);
|
||||
if (!(data = my_strdup(cmd))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
cur = data;
|
||||
|
||||
|
||||
while (*cur) {
|
||||
var = 0;
|
||||
|
||||
if (*cur == ' ' || *cur == '\r' || *cur == '\n') {
|
||||
cur++;
|
||||
continue;
|
||||
|
@ -56,7 +56,7 @@ extern "C" {
|
||||
This module is responsible for tone generation specifics
|
||||
*/
|
||||
|
||||
typedef short teletone_audio_t;
|
||||
typedef int16_t teletone_audio_t;
|
||||
struct teletone_generation_session;
|
||||
typedef int (*tone_handler)(struct teletone_generation_session *ts, teletone_tone_map_t *map);
|
||||
|
||||
@ -101,6 +101,7 @@ struct teletone_generation_session {
|
||||
/*! In-Use size of the buffer */
|
||||
int samples;
|
||||
/*! Callback function called during generation */
|
||||
int dynamic;
|
||||
tone_handler handler;
|
||||
};
|
||||
|
||||
|
@ -183,6 +183,7 @@ typedef apr_file_t switch_file_t;
|
||||
*/
|
||||
DoxyDefine(apr_status_t switch_file_open(switch_file_t **newf, const char *fname, apr_int32_t flag, switch_fileperms_t perm, switch_pool_t *pool);)
|
||||
#define switch_file_open apr_file_open
|
||||
#define switch_file_seek apr_file_seek
|
||||
|
||||
/**
|
||||
* Close the specified file.
|
||||
|
@ -417,6 +417,13 @@ SWITCH_DECLARE(char *) switch_core_session_get_uuid(switch_core_session_t *sessi
|
||||
*/
|
||||
SWITCH_DECLARE(switch_core_session_t *) switch_core_session_locate(char *uuid_str);
|
||||
|
||||
/*!
|
||||
\brief Retrieve a global variable from the core
|
||||
\param varname the name of the variable
|
||||
\return the value of the desired variable
|
||||
*/
|
||||
SWITCH_DECLARE(char *) switch_core_get_variable(char *varname);
|
||||
|
||||
/*!
|
||||
\brief Hangup All Sessions
|
||||
\param cause the hangup cause to apply to the hungup channels
|
||||
|
@ -151,7 +151,7 @@ static switch_caller_extension_t *directory_dialplan_hunt(switch_core_session_t
|
||||
if (extension) {
|
||||
switch_channel_set_state(channel, CS_EXECUTE);
|
||||
} else {
|
||||
switch_channel_hangup(channel, SWITCH_CAUSE_MESSAGE_TYPE_NONEXIST);
|
||||
switch_channel_hangup(channel, SWITCH_CAUSE_NO_ROUTE_DESTINATION);
|
||||
}
|
||||
|
||||
return extension;
|
||||
|
@ -296,7 +296,7 @@ static switch_caller_extension_t *dialplan_hunt(switch_core_session_t *session)
|
||||
if (!(xcontext = switch_xml_find_child(cfg, "context", "name", context))) {
|
||||
if (!(xcontext = switch_xml_find_child(cfg, "context", "name", "global"))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "context %s not found\n", context);
|
||||
switch_channel_hangup(channel, SWITCH_CAUSE_MESSAGE_TYPE_NONEXIST);
|
||||
switch_channel_hangup(channel, SWITCH_CAUSE_NO_ROUTE_DESTINATION);
|
||||
switch_xml_free(xml);
|
||||
return NULL;
|
||||
}
|
||||
@ -325,7 +325,7 @@ static switch_caller_extension_t *dialplan_hunt(switch_core_session_t *session)
|
||||
if (extension) {
|
||||
switch_channel_set_state(channel, CS_EXECUTE);
|
||||
} else {
|
||||
switch_channel_hangup(channel, SWITCH_CAUSE_MESSAGE_TYPE_NONEXIST);
|
||||
switch_channel_hangup(channel, SWITCH_CAUSE_NO_ROUTE_DESTINATION);
|
||||
}
|
||||
|
||||
return extension;
|
||||
|
@ -75,7 +75,7 @@ static switch_status_t native_file_file_open(switch_file_handle_t *handle, char
|
||||
handle->channels = 1;
|
||||
handle->format = 0;
|
||||
handle->sections = 0;
|
||||
handle->seekable = 0;
|
||||
handle->seekable = 1;
|
||||
handle->speed = 0;
|
||||
handle->private_info = context;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Opening File [%s] %dhz\n", path, handle->samplerate);
|
||||
@ -98,8 +98,10 @@ static switch_status_t native_file_file_close(switch_file_handle_t *handle)
|
||||
|
||||
static switch_status_t native_file_file_seek(switch_file_handle_t *handle, unsigned int *cur_sample, int64_t samples, int whence)
|
||||
{
|
||||
//native_file_context *context = handle->private_info;
|
||||
|
||||
native_file_context *context = handle->private_info;
|
||||
|
||||
switch_file_seek(context->fd, whence, &samples);
|
||||
|
||||
return SWITCH_STATUS_FALSE;
|
||||
|
||||
}
|
||||
|
@ -75,7 +75,6 @@ static int teletone_handler(teletone_generation_session_t *ts, teletone_tone_map
|
||||
/*********************************************************************************/
|
||||
static JSBool teletone_construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
int32 memory = 65535;
|
||||
JSObject *session_obj;
|
||||
struct teletone_obj *tto = NULL;
|
||||
struct js_session *jss = NULL;
|
||||
@ -101,12 +100,6 @@ static JSBool teletone_construct(JSContext *cx, JSObject *obj, uintN argc, jsval
|
||||
timer_name = JS_GetStringBytes(JS_ValueToString(cx, argv[1]));
|
||||
}
|
||||
|
||||
if (argc > 2) {
|
||||
if (!JS_ValueToInt32(cx, argv[2], &memory)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot Convert to INT\n");
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
switch_core_new_memory_pool(&pool);
|
||||
|
||||
if (!(tto = switch_core_alloc(pool, sizeof(*tto)))) {
|
||||
@ -149,7 +142,7 @@ static JSBool teletone_construct(JSContext *cx, JSObject *obj, uintN argc, jsval
|
||||
tto->obj = obj;
|
||||
tto->cx = cx;
|
||||
tto->session = jss->session;
|
||||
teletone_init_session(&tto->ts, memory, teletone_handler, tto);
|
||||
teletone_init_session(&tto->ts, 0, teletone_handler, tto);
|
||||
JS_SetPrivate(cx, obj, tto);
|
||||
|
||||
return JS_TRUE;
|
||||
|
@ -344,7 +344,7 @@ SWITCH_DECLARE(void) switch_channel_presence(switch_channel_t *channel, char *rp
|
||||
|
||||
SWITCH_DECLARE(char *) switch_channel_get_variable(switch_channel_t *channel, char *varname)
|
||||
{
|
||||
char *v;
|
||||
char *v = NULL;
|
||||
assert(channel != NULL);
|
||||
|
||||
if (!(v=switch_core_hash_find(channel->variables, varname))) {
|
||||
@ -352,6 +352,7 @@ SWITCH_DECLARE(char *) switch_channel_get_variable(switch_channel_t *channel, ch
|
||||
if (!strcmp(varname, "base_dir")) {
|
||||
return SWITCH_GLOBAL_dirs.base_dir;
|
||||
}
|
||||
v = switch_core_get_variable(varname);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1113,7 +1114,7 @@ SWITCH_DECLARE(char *) switch_channel_expand_variables(switch_channel_t *channel
|
||||
{
|
||||
char *p, *c;
|
||||
char *data, *indup;
|
||||
size_t sp = 0, len = 0, olen = 0, vtype = 0, br = 0, vnamepos, vvalpos, cpos, ppos, block = 128;
|
||||
size_t sp = 0, len = 0, olen = 0, vtype = 0, br = 0, cpos, block = 128;
|
||||
char *sub_val = NULL, *func_val = NULL;
|
||||
|
||||
if (!strchr(in, '$') && !strchr(in, '&')) {
|
||||
@ -1195,36 +1196,35 @@ SWITCH_DECLARE(char *) switch_channel_expand_variables(switch_channel_t *channel
|
||||
return in;
|
||||
}
|
||||
}
|
||||
nlen = strlen(sub_val);
|
||||
nlen = sub_val ? strlen(sub_val) : 0;
|
||||
|
||||
if (len + nlen >= olen) {
|
||||
olen += block;
|
||||
olen = (olen + len + nlen + block);
|
||||
cpos = c - data;
|
||||
ppos = p - data;
|
||||
vnamepos = vname - data;
|
||||
vvalpos = vval - data;
|
||||
data = realloc(data, olen);
|
||||
|
||||
c = data + cpos;
|
||||
p = data + ppos;
|
||||
vname = data + vnamepos;
|
||||
vname = data + vvalpos;
|
||||
memset(c, 0, olen - cpos);
|
||||
}
|
||||
|
||||
len += nlen;
|
||||
strcat(c, sub_val);
|
||||
c += nlen;
|
||||
|
||||
if (func_val) {
|
||||
free(func_val);
|
||||
func_val = NULL;
|
||||
if (nlen) {
|
||||
len += nlen;
|
||||
strcat(c, sub_val);
|
||||
c += nlen;
|
||||
}
|
||||
|
||||
switch_safe_free(func_val);
|
||||
}
|
||||
if (sp) {
|
||||
*c++ = ' ';
|
||||
sp = 0;
|
||||
len++;
|
||||
}
|
||||
*c++ = *p;
|
||||
len++;
|
||||
|
||||
if (*p == '$' || *p == '&') {
|
||||
p--;
|
||||
} else {
|
||||
*c++ = *p;
|
||||
len++;
|
||||
}
|
||||
}
|
||||
}
|
||||
free(indup);
|
||||
|
@ -120,6 +120,7 @@ struct switch_core_runtime {
|
||||
uint32_t session_id;
|
||||
apr_pool_t *memory_pool;
|
||||
switch_hash_t *session_table;
|
||||
switch_hash_t *global_vars;
|
||||
switch_mutex_t *session_table_mutex;
|
||||
#ifdef CRASH_PROT
|
||||
switch_hash_t *stack_table;
|
||||
@ -558,6 +559,11 @@ SWITCH_DECLARE(void) switch_core_session_rwunlock(switch_core_session_t *session
|
||||
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(char *) switch_core_get_variable(char *varname)
|
||||
{
|
||||
return (char *) switch_core_hash_find(runtime.global_vars, varname);
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(switch_core_session_t *) switch_core_session_locate(char *uuid_str)
|
||||
{
|
||||
switch_core_session_t *session;
|
||||
@ -3849,6 +3855,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_init(char *console, const char **err
|
||||
return SWITCH_STATUS_MEMERR;
|
||||
}
|
||||
|
||||
switch_core_hash_init(&runtime.global_vars, runtime.memory_pool);
|
||||
|
||||
if (switch_xml_init(runtime.memory_pool, err) != SWITCH_STATUS_SUCCESS) {
|
||||
apr_terminate();
|
||||
return SWITCH_STATUS_MEMERR;
|
||||
@ -3868,6 +3876,18 @@ SWITCH_DECLARE(switch_status_t) switch_core_init(char *console, const char **err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((settings = switch_xml_child(cfg, "variables"))) {
|
||||
for (param = switch_xml_child(settings, "variable"); param; param = param->next) {
|
||||
char *var = (char *) switch_xml_attr_soft(param, "name");
|
||||
char *val = (char *) switch_xml_attr_soft(param, "value");
|
||||
char *varr = NULL, *vall = NULL;
|
||||
|
||||
varr = switch_core_strdup(runtime.memory_pool, var);
|
||||
vall = switch_core_strdup(runtime.memory_pool, val);
|
||||
switch_core_hash_insert(runtime.global_vars, varr, vall);
|
||||
}
|
||||
}
|
||||
switch_xml_free(xml);
|
||||
}
|
||||
|
||||
|
154
src/switch_ivr.c
154
src/switch_ivr.c
@ -32,6 +32,7 @@
|
||||
*/
|
||||
#include <switch.h>
|
||||
#include <switch_ivr.h>
|
||||
#include <libteletone.h>
|
||||
|
||||
static const switch_state_handler_table_t audio_bridge_peer_state_handlers;
|
||||
|
||||
@ -2198,6 +2199,31 @@ static uint8_t check_channel_status(switch_channel_t **peer_channels,
|
||||
|
||||
}
|
||||
|
||||
struct ringback {
|
||||
switch_buffer_t *audio_buffer;
|
||||
switch_buffer_t *loop_buffer;
|
||||
teletone_generation_session_t ts;
|
||||
switch_file_handle_t fhb;
|
||||
switch_file_handle_t *fh;
|
||||
uint8_t asis;
|
||||
};
|
||||
|
||||
typedef struct ringback ringback_t;
|
||||
|
||||
static int teletone_handler(teletone_generation_session_t *ts, teletone_tone_map_t *map)
|
||||
{
|
||||
ringback_t *tto = ts->user_data;
|
||||
int wrote;
|
||||
|
||||
if (!tto) {
|
||||
return -1;
|
||||
}
|
||||
wrote = teletone_mux_tones(ts, map);
|
||||
switch_buffer_write(tto->audio_buffer, ts->buffer, wrote * 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MAX_PEERS 256
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *session,
|
||||
switch_core_session_t **bleg,
|
||||
@ -2220,6 +2246,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
|
||||
switch_caller_profile_t *caller_profiles[MAX_PEERS] = {0}, *caller_caller_profile;
|
||||
char *chan_type = NULL, *chan_data;
|
||||
switch_channel_t *peer_channel = NULL, *peer_channels[MAX_PEERS] = {0};
|
||||
ringback_t ringback = {0};
|
||||
time_t start;
|
||||
switch_frame_t *read_frame = NULL;
|
||||
switch_memory_pool_t *pool = NULL;
|
||||
@ -2231,6 +2258,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
|
||||
char *file = NULL, *key = NULL, *odata, *var;
|
||||
switch_call_cause_t reason = SWITCH_CAUSE_UNALLOCATED;
|
||||
uint8_t to = 0;
|
||||
char *ringback_data = NULL;
|
||||
switch_codec_t *read_codec = NULL;
|
||||
|
||||
write_frame.data = fdata;
|
||||
|
||||
*bleg = NULL;
|
||||
@ -2261,6 +2291,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
|
||||
caller_channel = switch_core_session_get_channel(session);
|
||||
assert(caller_channel != NULL);
|
||||
|
||||
ringback_data = switch_channel_get_variable(caller_channel, "ringback");
|
||||
switch_channel_set_variable(caller_channel, "originate_disposition", "failure");
|
||||
|
||||
if ((var = switch_channel_get_variable(caller_channel, "group_confirm_key"))) {
|
||||
@ -2449,12 +2480,15 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
|
||||
|
||||
}
|
||||
endfor1:
|
||||
|
||||
if (session && !switch_channel_test_flag(caller_channel, CF_NOMEDIA)) {
|
||||
switch_codec_t *read_codec = NULL;
|
||||
|
||||
if (ringback_data && !switch_channel_test_flag(caller_channel, CF_ANSWERED) && !switch_channel_test_flag(caller_channel, CF_EARLY_MEDIA)) {
|
||||
switch_channel_pre_answer(caller_channel);
|
||||
}
|
||||
|
||||
if (session && !switch_channel_test_flag(caller_channel, CF_NOMEDIA)) {
|
||||
read_codec = switch_core_session_get_read_codec(session);
|
||||
assert(read_codec != NULL);
|
||||
|
||||
if (!(pass = (uint8_t)switch_test_flag(read_codec, SWITCH_CODEC_FLAG_PASSTHROUGH))) {
|
||||
if (switch_core_codec_init(&write_codec,
|
||||
"L16",
|
||||
@ -2465,6 +2499,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
|
||||
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
|
||||
NULL,
|
||||
pool) == SWITCH_STATUS_SUCCESS) {
|
||||
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Raw Codec Activation Success L16@%uhz 1 channel %dms\n",
|
||||
read_codec->implementation->samples_per_second,
|
||||
read_codec->implementation->microseconds_per_frame / 1000);
|
||||
@ -2472,9 +2508,60 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
|
||||
write_frame.datalen = read_codec->implementation->bytes_per_frame;
|
||||
write_frame.samples = write_frame.datalen / 2;
|
||||
memset(write_frame.data, 255, write_frame.datalen);
|
||||
|
||||
if (ringback_data) {
|
||||
switch_buffer_create_dynamic(&ringback.audio_buffer, 512, 1024, 0);
|
||||
switch_buffer_create_dynamic(&ringback.loop_buffer, 512, 1024, 0);
|
||||
char *tmp_data = NULL;
|
||||
|
||||
if (*ringback_data == '/') {
|
||||
char *ext;
|
||||
|
||||
if ((ext = strrchr(ringback_data, '.'))) {
|
||||
switch_core_session_set_read_codec(session, &write_codec);
|
||||
ext++;
|
||||
} else {
|
||||
ringback.asis++;
|
||||
write_frame.codec = read_codec;
|
||||
ext = read_codec->implementation->iananame;
|
||||
tmp_data = switch_mprintf("%s.%s", ringback_data, ext);
|
||||
ringback_data = tmp_data;
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Play Ringback File [%s]\n", ringback_data);
|
||||
|
||||
ringback.fhb.channels = read_codec->implementation->number_of_channels;
|
||||
ringback.fhb.samplerate = read_codec->implementation->samples_per_second;
|
||||
if (switch_core_file_open(&ringback.fhb,
|
||||
ringback_data,
|
||||
SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT,
|
||||
switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Playing File\n");
|
||||
switch_safe_free(tmp_data);
|
||||
goto notready;
|
||||
}
|
||||
ringback.fh = &ringback.fhb;
|
||||
|
||||
|
||||
} else {
|
||||
teletone_init_session(&ringback.ts, 0, teletone_handler, &ringback);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Play Ringback Tone [%s]\n", ringback_data);
|
||||
//ringback.ts.debug = 1;
|
||||
//ringback.ts.debug_stream = switch_core_get_console();
|
||||
if (teletone_run(&ringback.ts, ringback_data)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Playing Tone\n");
|
||||
teletone_destroy_session(&ringback.ts);
|
||||
switch_buffer_destroy(&ringback.audio_buffer);
|
||||
switch_buffer_destroy(&ringback.loop_buffer);
|
||||
ringback_data = NULL;
|
||||
}
|
||||
}
|
||||
switch_safe_free(tmp_data);
|
||||
}
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Codec Error!");
|
||||
switch_channel_hangup(caller_channel, SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE);
|
||||
read_codec = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2505,10 +2592,56 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
|
||||
if (!SWITCH_READ_ACCEPTABLE(status)) {
|
||||
break;
|
||||
}
|
||||
if (read_frame && !pass) {
|
||||
if (read_frame && !pass && !switch_test_flag(read_frame, SFF_CNG) && read_frame->datalen > 1) {
|
||||
if (ringback.fh) {
|
||||
uint8_t abuf[1024];
|
||||
switch_size_t mlen, olen;
|
||||
unsigned int pos = 0;
|
||||
|
||||
if (ringback.asis) {
|
||||
mlen = read_frame->datalen;
|
||||
} else {
|
||||
mlen = read_frame->datalen / 2;
|
||||
}
|
||||
|
||||
olen = mlen;
|
||||
switch_core_file_read(ringback.fh, abuf, &olen);
|
||||
|
||||
if (olen == 0) {
|
||||
olen = mlen;
|
||||
ringback.fh->speed = 0;
|
||||
switch_core_file_seek(ringback.fh, &pos, 0, SEEK_SET);
|
||||
switch_core_file_read(ringback.fh, abuf, &olen);
|
||||
if (olen == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
write_frame.data = abuf;
|
||||
write_frame.datalen = (uint32_t) ringback.asis ? olen : olen * 2;
|
||||
if (switch_core_session_write_frame(session, &write_frame, 1000, 0) != SWITCH_STATUS_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
} else if (ringback.audio_buffer) {
|
||||
if ((write_frame.datalen = (uint32_t)switch_buffer_read(ringback.audio_buffer,
|
||||
write_frame.data,
|
||||
write_frame.codec->implementation->bytes_per_frame)) <= 0) {
|
||||
switch_buffer_t *tmp;
|
||||
tmp = ringback.audio_buffer;
|
||||
ringback.audio_buffer = ringback.loop_buffer;
|
||||
ringback.loop_buffer = tmp;
|
||||
if ((write_frame.datalen = (uint32_t)switch_buffer_read(ringback.audio_buffer,
|
||||
write_frame.data,
|
||||
write_frame.codec->implementation->bytes_per_frame)) <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (switch_core_session_write_frame(session, &write_frame, 1000, 0) != SWITCH_STATUS_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
if (ringback.loop_buffer) {
|
||||
switch_buffer_write(ringback.loop_buffer, write_frame.data, write_frame.datalen);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
@ -2617,6 +2750,19 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
|
||||
switch_core_codec_destroy(&write_codec);
|
||||
}
|
||||
|
||||
if (ringback.fh) {
|
||||
switch_core_file_close(ringback.fh);
|
||||
ringback.fh = NULL;
|
||||
if (read_codec && !ringback.asis) {
|
||||
switch_core_session_set_read_codec(session, read_codec);
|
||||
switch_core_session_reset(session);
|
||||
}
|
||||
} else if (ringback.audio_buffer) {
|
||||
teletone_destroy_session(&ringback.ts);
|
||||
switch_buffer_destroy(&ringback.audio_buffer);
|
||||
switch_buffer_destroy(&ringback.loop_buffer);
|
||||
}
|
||||
|
||||
for (i = 0; i < and_argc; i++) {
|
||||
if (!peer_channels[i]) {
|
||||
continue;
|
||||
|
Loading…
x
Reference in New Issue
Block a user