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:
Anthony Minessale 2006-11-19 01:05:06 +00:00
parent 0984933c36
commit d7baa16132
12 changed files with 273 additions and 50 deletions

View File

@ -8,6 +8,12 @@
<!--Most channels to allow at once --> <!--Most channels to allow at once -->
<param name="max-sessions" value="1000"/> <param name="max-sessions" value="1000"/>
</settings> </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>
<configuration name="modules.conf" description="Modules"> <configuration name="modules.conf" description="Modules">
@ -429,6 +435,9 @@
<extension name="testmusic"> <extension name="testmusic">
<condition field="destination_number" expression="^1234$"> <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"/> <action application="bridge" data="sofia/test/1234@66.250.68.194"/>
</condition> </condition>
</extension> </extension>

View File

@ -84,11 +84,14 @@ int teletone_init_session(teletone_generation_session_t *ts, int buflen, tone_ha
ts->user_data = user_data; ts->user_data = user_data;
ts->volume = 1500; ts->volume = 1500;
ts->decay_step = 0; ts->decay_step = 0;
if ((ts->buffer = calloc(buflen, sizeof(teletone_audio_t))) == 0) { if (buflen) {
return -1; 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 */ /* Add Standard DTMF Tones */
teletone_set_tone(ts, '1', 697.0, 1209.0, 0.0); teletone_set_tone(ts, '1', 697.0, 1209.0, 0.0);
teletone_set_tone(ts, '2', 697.0, 1336.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; return 0;
} }
/** Generate a specified number of samples containing the three specified static int ensure_buffer(teletone_generation_session_t *ts, int need)
* frequencies (in hertz) and dump to the file descriptor audio_fd. */ {
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) 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; 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++) { 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) { if (ts->decay_step && !(ts->samples % ts->decay_step) && ts->volume > 0 && ts->samples > decay) {
ts->volume += ts->decay_direction; 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 (c = 0; c < ts->channels; c++) {
for (i = 0; i < wait && ts->samples < ts->datalen; i++) { for (i = 0; i < wait && ts->samples < ts->datalen; i++) {
ts->buffer[ts->samples++] = 0; 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; 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) 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; int var = 0, LOOPING = 0;
if (!cmd) {
return -1;
}
do { do {
data = strdup(cmd); if (!(data = my_strdup(cmd))) {
return -1;
}
cur = data; cur = data;
while (*cur) { while (*cur) {
var = 0; var = 0;
if (*cur == ' ' || *cur == '\r' || *cur == '\n') { if (*cur == ' ' || *cur == '\r' || *cur == '\n') {
cur++; cur++;
continue; continue;

View File

@ -56,7 +56,7 @@ extern "C" {
This module is responsible for tone generation specifics This module is responsible for tone generation specifics
*/ */
typedef short teletone_audio_t; typedef int16_t teletone_audio_t;
struct teletone_generation_session; struct teletone_generation_session;
typedef int (*tone_handler)(struct teletone_generation_session *ts, teletone_tone_map_t *map); 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 */ /*! In-Use size of the buffer */
int samples; int samples;
/*! Callback function called during generation */ /*! Callback function called during generation */
int dynamic;
tone_handler handler; tone_handler handler;
}; };

View File

@ -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);) 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_open apr_file_open
#define switch_file_seek apr_file_seek
/** /**
* Close the specified file. * Close the specified file.

View 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); 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 \brief Hangup All Sessions
\param cause the hangup cause to apply to the hungup channels \param cause the hangup cause to apply to the hungup channels

View File

@ -151,7 +151,7 @@ static switch_caller_extension_t *directory_dialplan_hunt(switch_core_session_t
if (extension) { if (extension) {
switch_channel_set_state(channel, CS_EXECUTE); switch_channel_set_state(channel, CS_EXECUTE);
} else { } else {
switch_channel_hangup(channel, SWITCH_CAUSE_MESSAGE_TYPE_NONEXIST); switch_channel_hangup(channel, SWITCH_CAUSE_NO_ROUTE_DESTINATION);
} }
return extension; return extension;

View File

@ -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", context))) {
if (!(xcontext = switch_xml_find_child(cfg, "context", "name", "global"))) { 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_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); switch_xml_free(xml);
return NULL; return NULL;
} }
@ -325,7 +325,7 @@ static switch_caller_extension_t *dialplan_hunt(switch_core_session_t *session)
if (extension) { if (extension) {
switch_channel_set_state(channel, CS_EXECUTE); switch_channel_set_state(channel, CS_EXECUTE);
} else { } else {
switch_channel_hangup(channel, SWITCH_CAUSE_MESSAGE_TYPE_NONEXIST); switch_channel_hangup(channel, SWITCH_CAUSE_NO_ROUTE_DESTINATION);
} }
return extension; return extension;

View File

@ -75,7 +75,7 @@ static switch_status_t native_file_file_open(switch_file_handle_t *handle, char
handle->channels = 1; handle->channels = 1;
handle->format = 0; handle->format = 0;
handle->sections = 0; handle->sections = 0;
handle->seekable = 0; handle->seekable = 1;
handle->speed = 0; handle->speed = 0;
handle->private_info = context; handle->private_info = context;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Opening File [%s] %dhz\n", path, handle->samplerate); 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) 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; return SWITCH_STATUS_FALSE;
} }

View File

@ -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) static JSBool teletone_construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{ {
int32 memory = 65535;
JSObject *session_obj; JSObject *session_obj;
struct teletone_obj *tto = NULL; struct teletone_obj *tto = NULL;
struct js_session *jss = 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])); 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); switch_core_new_memory_pool(&pool);
if (!(tto = switch_core_alloc(pool, sizeof(*tto)))) { 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->obj = obj;
tto->cx = cx; tto->cx = cx;
tto->session = jss->session; 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); JS_SetPrivate(cx, obj, tto);
return JS_TRUE; return JS_TRUE;

View File

@ -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) SWITCH_DECLARE(char *) switch_channel_get_variable(switch_channel_t *channel, char *varname)
{ {
char *v; char *v = NULL;
assert(channel != NULL); assert(channel != NULL);
if (!(v=switch_core_hash_find(channel->variables, varname))) { 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")) { if (!strcmp(varname, "base_dir")) {
return SWITCH_GLOBAL_dirs.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 *p, *c;
char *data, *indup; 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; char *sub_val = NULL, *func_val = NULL;
if (!strchr(in, '$') && !strchr(in, '&')) { if (!strchr(in, '$') && !strchr(in, '&')) {
@ -1195,36 +1196,35 @@ SWITCH_DECLARE(char *) switch_channel_expand_variables(switch_channel_t *channel
return in; return in;
} }
} }
nlen = strlen(sub_val); nlen = sub_val ? strlen(sub_val) : 0;
if (len + nlen >= olen) { if (len + nlen >= olen) {
olen += block; olen = (olen + len + nlen + block);
cpos = c - data; cpos = c - data;
ppos = p - data;
vnamepos = vname - data;
vvalpos = vval - data;
data = realloc(data, olen); data = realloc(data, olen);
c = data + cpos; c = data + cpos;
p = data + ppos; memset(c, 0, olen - cpos);
vname = data + vnamepos;
vname = data + vvalpos;
} }
if (nlen) {
len += nlen; len += nlen;
strcat(c, sub_val); strcat(c, sub_val);
c += nlen; c += nlen;
if (func_val) {
free(func_val);
func_val = NULL;
} }
switch_safe_free(func_val);
} }
if (sp) { if (sp) {
*c++ = ' '; *c++ = ' ';
sp = 0; sp = 0;
len++;
} }
*c++ = *p;
len++; if (*p == '$' || *p == '&') {
p--;
} else {
*c++ = *p;
len++;
}
} }
} }
free(indup); free(indup);

View File

@ -120,6 +120,7 @@ struct switch_core_runtime {
uint32_t session_id; uint32_t session_id;
apr_pool_t *memory_pool; apr_pool_t *memory_pool;
switch_hash_t *session_table; switch_hash_t *session_table;
switch_hash_t *global_vars;
switch_mutex_t *session_table_mutex; switch_mutex_t *session_table_mutex;
#ifdef CRASH_PROT #ifdef CRASH_PROT
switch_hash_t *stack_table; 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_DECLARE(switch_core_session_t *) switch_core_session_locate(char *uuid_str)
{ {
switch_core_session_t *session; 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; 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) { if (switch_xml_init(runtime.memory_pool, err) != SWITCH_STATUS_SUCCESS) {
apr_terminate(); apr_terminate();
return SWITCH_STATUS_MEMERR; 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); switch_xml_free(xml);
} }

View File

@ -32,6 +32,7 @@
*/ */
#include <switch.h> #include <switch.h>
#include <switch_ivr.h> #include <switch_ivr.h>
#include <libteletone.h>
static const switch_state_handler_table_t audio_bridge_peer_state_handlers; 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 #define MAX_PEERS 256
SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *session, SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *session,
switch_core_session_t **bleg, 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; switch_caller_profile_t *caller_profiles[MAX_PEERS] = {0}, *caller_caller_profile;
char *chan_type = NULL, *chan_data; char *chan_type = NULL, *chan_data;
switch_channel_t *peer_channel = NULL, *peer_channels[MAX_PEERS] = {0}; switch_channel_t *peer_channel = NULL, *peer_channels[MAX_PEERS] = {0};
ringback_t ringback = {0};
time_t start; time_t start;
switch_frame_t *read_frame = NULL; switch_frame_t *read_frame = NULL;
switch_memory_pool_t *pool = 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; char *file = NULL, *key = NULL, *odata, *var;
switch_call_cause_t reason = SWITCH_CAUSE_UNALLOCATED; switch_call_cause_t reason = SWITCH_CAUSE_UNALLOCATED;
uint8_t to = 0; uint8_t to = 0;
char *ringback_data = NULL;
switch_codec_t *read_codec = NULL;
write_frame.data = fdata; write_frame.data = fdata;
*bleg = NULL; *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); caller_channel = switch_core_session_get_channel(session);
assert(caller_channel != NULL); assert(caller_channel != NULL);
ringback_data = switch_channel_get_variable(caller_channel, "ringback");
switch_channel_set_variable(caller_channel, "originate_disposition", "failure"); switch_channel_set_variable(caller_channel, "originate_disposition", "failure");
if ((var = switch_channel_get_variable(caller_channel, "group_confirm_key"))) { 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: 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); read_codec = switch_core_session_get_read_codec(session);
assert(read_codec != NULL); assert(read_codec != NULL);
if (!(pass = (uint8_t)switch_test_flag(read_codec, SWITCH_CODEC_FLAG_PASSTHROUGH))) { if (!(pass = (uint8_t)switch_test_flag(read_codec, SWITCH_CODEC_FLAG_PASSTHROUGH))) {
if (switch_core_codec_init(&write_codec, if (switch_core_codec_init(&write_codec,
"L16", "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, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
NULL, NULL,
pool) == SWITCH_STATUS_SUCCESS) { pool) == SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Raw Codec Activation Success L16@%uhz 1 channel %dms\n", 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->samples_per_second,
read_codec->implementation->microseconds_per_frame / 1000); 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.datalen = read_codec->implementation->bytes_per_frame;
write_frame.samples = write_frame.datalen / 2; write_frame.samples = write_frame.datalen / 2;
memset(write_frame.data, 255, write_frame.datalen); 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 { } else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Codec Error!"); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Codec Error!");
switch_channel_hangup(caller_channel, SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE); 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)) { if (!SWITCH_READ_ACCEPTABLE(status)) {
break; 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) { if (switch_core_session_write_frame(session, &write_frame, 1000, 0) != SWITCH_STATUS_SUCCESS) {
break; break;
} }
if (ringback.loop_buffer) {
switch_buffer_write(ringback.loop_buffer, write_frame.data, write_frame.datalen);
}
} }
} else { } else {
@ -2617,6 +2750,19 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
switch_core_codec_destroy(&write_codec); 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++) { for (i = 0; i < and_argc; i++) {
if (!peer_channels[i]) { if (!peer_channels[i]) {
continue; continue;