Merge git@git.freeswitch.org:freeswitch
This commit is contained in:
commit
d4bb8b019e
|
@ -71,18 +71,28 @@
|
|||
<macro name="voicemail_menu">
|
||||
<input pattern="^([0-9#*]):([0-9#*]):([0-9#*]):([0-9#*])$">
|
||||
<match>
|
||||
<action function="play-file" data="voicemail/vm-press.wav"/>
|
||||
<action function="say" data="$1" method="pronounced" type="name_spelled"/>
|
||||
<!-- To listen to new messages -->
|
||||
<action function="play-file" data="voicemail/vm-listen_new.wav"/>
|
||||
<action function="play-file" data="voicemail/vm-press.wav"/>
|
||||
<action function="say" data="$2" method="pronounced" type="name_spelled"/>
|
||||
<action function="say" data="$1" method="pronounced" type="name_spelled"/>
|
||||
<action function="execute" data="sleep(100)"/>
|
||||
|
||||
<!-- To listen to saved messages -->
|
||||
<action function="play-file" data="voicemail/vm-listen_saved.wav"/>
|
||||
<action function="play-file" data="voicemail/vm-press.wav"/>
|
||||
<action function="say" data="$3" method="pronounced" type="name_spelled"/>
|
||||
<action function="say" data="$2" method="pronounced" type="name_spelled"/>
|
||||
<action function="execute" data="sleep(100)"/>
|
||||
|
||||
<!-- For advanced options -->
|
||||
<action function="play-file" data="voicemail/vm-advanced.wav"/>
|
||||
<action function="play-file" data="voicemail/vm-press.wav"/>
|
||||
<action function="say" data="$4" method="pronounced" type="name_phonetic"/>
|
||||
<action function="say" data="$3" method="pronounced" type="name_spelled"/>
|
||||
<action function="execute" data="sleep(100)"/>
|
||||
|
||||
<!-- To exit -->
|
||||
<action function="play-file" data="voicemail/vm-to_exit.wav"/>
|
||||
<action function="play-file" data="voicemail/vm-press.wav"/>
|
||||
<action function="say" data="$4" method="pronounced" type="name_phonetic"/>
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
|
@ -90,21 +100,34 @@
|
|||
<macro name="voicemail_config_menu">
|
||||
<input pattern="^([0-9#*]):([0-9#*]):([0-9#*]):([0-9#*]):([0-9#*])$">
|
||||
<match>
|
||||
<action function="play-file" data="voicemail/vm-press.wav"/>
|
||||
<action function="say" data="$1" method="pronounced" type="name_spelled"/>
|
||||
<!-- To record a greeting -->
|
||||
<action function="play-file" data="voicemail/vm-to_record_greeting.wav"/>
|
||||
<action function="play-file" data="voicemail/vm-press.wav"/>
|
||||
<action function="say" data="$2" method="pronounced" type="name_spelled"/>
|
||||
<action function="say" data="$1" method="pronounced" type="name_spelled"/>
|
||||
<action function="execute" data="sleep(100)"/>
|
||||
|
||||
<!-- To choose greeting -->
|
||||
<action function="play-file" data="voicemail/vm-choose_greeting.wav"/>
|
||||
<action function="play-file" data="voicemail/vm-press.wav"/>
|
||||
<action function="say" data="$3" method="pronounced" type="name_spelled"/>
|
||||
<action function="say" data="$2" method="pronounced" type="name_spelled"/>
|
||||
<action function="execute" data="sleep(100)"/>
|
||||
|
||||
<!-- To record your name -->
|
||||
<action function="play-file" data="voicemail/vm-record_name2.wav"/>
|
||||
<action function="play-file" data="voicemail/vm-press.wav"/>
|
||||
<action function="say" data="$4" method="pronounced" type="name_spelled"/>
|
||||
<action function="say" data="$3" method="pronounced" type="name_spelled"/>
|
||||
<action function="execute" data="sleep(100)"/>
|
||||
|
||||
<!-- To change password -->
|
||||
<action function="play-file" data="voicemail/vm-change_password.wav"/>
|
||||
<action function="play-file" data="voicemail/vm-press.wav"/>
|
||||
<action function="say" data="$5" method="pronounced" type="name_spelled"/>
|
||||
<action function="say" data="$4" method="pronounced" type="name_spelled"/>
|
||||
<action function="execute" data="sleep(100)"/>
|
||||
|
||||
<!-- To return to main menu -->
|
||||
<action function="play-file" data="voicemail/vm-main_menu.wav"/>
|
||||
<action function="play-file" data="voicemail/vm-press.wav"/>
|
||||
<action function="say" data="$5" method="pronounced" type="name_spelled"/>
|
||||
</match>
|
||||
</input>
|
||||
</macro>
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
CC=gcc
|
||||
CFLAGS=-Wall -I/usr/local/freeswitch/include
|
||||
LDFLAGS=-L/usr/local/freeswitch/lib -lfreetdm
|
||||
|
||||
ftdmstart: ftdmstart.o
|
||||
|
||||
clean:
|
||||
rm -rf ftdmstart.o
|
||||
|
||||
|
|
@ -0,0 +1,476 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Sangoma Technologies
|
||||
* Moises Silva <moy@sangoma.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the original author; nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sample program for the boost signaling absraction.
|
||||
* Usage: testboostalone <spanno-1> <spanno-2> ... -d [number-to-dial-if-any]
|
||||
* compile this program linking to the freetdm library (ie -lfreetdm)
|
||||
**/
|
||||
|
||||
#ifndef __linux__
|
||||
#define _CRT_SECURE_NO_WARNINGS 1
|
||||
#endif
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#include "freetdm.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
/* arbitrary limit for max calls in this sample program */
|
||||
#define MAX_CALLS 255
|
||||
|
||||
/* some timers (in seconds) to fake responses in incoming calls */
|
||||
#define PROGRESS_TIMER 1
|
||||
#define ANSWER_TIMER 5
|
||||
#define HANGUP_TIMER 15
|
||||
|
||||
/* simple variable used to stop the application */
|
||||
static int app_running = 0;
|
||||
|
||||
typedef void (*expired_function_t)(ftdm_channel_t *channel);
|
||||
typedef struct dummy_timer_s {
|
||||
int time;
|
||||
ftdm_channel_t *channel;
|
||||
expired_function_t expired;
|
||||
} dummy_timer_t;
|
||||
|
||||
/* dummy second resolution timers */
|
||||
static dummy_timer_t g_timers[MAX_CALLS];
|
||||
|
||||
/* mutex to protect the timers (both, the test thread and the signaling thread may modify them) */
|
||||
static ftdm_mutex_t *g_schedule_mutex;
|
||||
|
||||
/* unique outgoing channel */
|
||||
static ftdm_channel_t *g_outgoing_channel = NULL;
|
||||
|
||||
static void interrupt_requested(int signal)
|
||||
{
|
||||
app_running = 0;
|
||||
}
|
||||
|
||||
static void schedule_timer(ftdm_channel_t *channel, int sec, expired_function_t expired)
|
||||
{
|
||||
int i;
|
||||
ftdm_mutex_lock(g_schedule_mutex);
|
||||
for (i = 0; i < sizeof(g_timers)/sizeof(g_timers[0]); i++) {
|
||||
/* check the timer slot is free to use */
|
||||
if (!g_timers[i].time) {
|
||||
g_timers[i].time = sec;
|
||||
g_timers[i].channel = channel;
|
||||
g_timers[i].expired = expired;
|
||||
ftdm_mutex_unlock(g_schedule_mutex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
ftdm_log(FTDM_LOG_ERROR, "Failed to schedule timer\n");
|
||||
ftdm_mutex_unlock(g_schedule_mutex);
|
||||
}
|
||||
|
||||
static void run_timers(void)
|
||||
{
|
||||
int i;
|
||||
void *channel;
|
||||
expired_function_t expired_func = NULL;
|
||||
ftdm_mutex_lock(g_schedule_mutex);
|
||||
for (i = 0; i < sizeof(g_timers)/sizeof(g_timers[0]); i++) {
|
||||
/* if there's time left, decrement */
|
||||
if (g_timers[i].time) {
|
||||
g_timers[i].time--;
|
||||
}
|
||||
|
||||
/* if time expired and we have an expired function, call it */
|
||||
if (!g_timers[i].time && g_timers[i].expired) {
|
||||
expired_func = g_timers[i].expired;
|
||||
channel = g_timers[i].channel;
|
||||
memset(&g_timers[i], 0, sizeof(g_timers[i]));
|
||||
expired_func(channel);
|
||||
}
|
||||
}
|
||||
ftdm_mutex_unlock(g_schedule_mutex);
|
||||
}
|
||||
|
||||
static void release_timers(ftdm_channel_t *channel)
|
||||
{
|
||||
int i;
|
||||
ftdm_mutex_lock(g_schedule_mutex);
|
||||
for (i = 0; i < sizeof(g_timers)/sizeof(g_timers[0]); i++) {
|
||||
/* clear any timer belonging to the given channel */
|
||||
if (g_timers[i].channel == channel) {
|
||||
memset(&g_timers[i], 0, sizeof(g_timers[i]));
|
||||
}
|
||||
}
|
||||
ftdm_mutex_unlock(g_schedule_mutex);
|
||||
}
|
||||
|
||||
/* hangup the call */
|
||||
static void send_hangup(ftdm_channel_t *channel)
|
||||
{
|
||||
int spanid = ftdm_channel_get_span_id(channel);
|
||||
int chanid = ftdm_channel_get_id(channel);
|
||||
ftdm_log(FTDM_LOG_NOTICE, "-- Requesting hangup in channel %d:%d\n", spanid, chanid);
|
||||
ftdm_channel_call_hangup(channel);
|
||||
}
|
||||
|
||||
/* send answer for an incoming call */
|
||||
static void send_answer(ftdm_channel_t *channel)
|
||||
{
|
||||
/* we move the channel signaling state machine to UP (answered) */
|
||||
int spanid = ftdm_channel_get_span_id(channel);
|
||||
int chanid = ftdm_channel_get_id(channel);
|
||||
ftdm_log(FTDM_LOG_NOTICE, "-- Requesting answer in channel %d:%d\n", spanid, chanid);
|
||||
ftdm_channel_call_answer(channel);
|
||||
schedule_timer(channel, HANGUP_TIMER, send_hangup);
|
||||
}
|
||||
|
||||
/* send progress for an incoming */
|
||||
static void send_progress(ftdm_channel_t *channel)
|
||||
{
|
||||
/* we move the channel signaling state machine to UP (answered) */
|
||||
int spanid = ftdm_channel_get_span_id(channel);
|
||||
int chanid = ftdm_channel_get_id(channel);
|
||||
ftdm_log(FTDM_LOG_NOTICE, "-- Requesting progress\n", spanid, chanid);
|
||||
ftdm_channel_call_indicate(channel, FTDM_CHANNEL_INDICATE_PROGRESS);
|
||||
schedule_timer(channel, ANSWER_TIMER, send_answer);
|
||||
}
|
||||
|
||||
/* This function will be called in an undetermined signaling thread, you must not do
|
||||
* any blocking operations here or the signaling stack may delay other call event processing
|
||||
* The arguments for this function are defined in FIO_SIGNAL_CB_FUNCTION prototype, I just
|
||||
* name them here for your convenience:
|
||||
* ftdm_sigmsg_t *sigmsg
|
||||
* - The sigmsg structure contains the ftdm_channel structure that represents the channel where
|
||||
* the event occurred and the event_id of the signaling event that just occurred.
|
||||
* */
|
||||
static FIO_SIGNAL_CB_FUNCTION(on_signaling_event)
|
||||
{
|
||||
switch (sigmsg->event_id) {
|
||||
/* This event signals the start of an incoming call */
|
||||
case FTDM_SIGEVENT_START:
|
||||
ftdm_log(FTDM_LOG_NOTICE, "Incoming call received in channel %d:%d\n", sigmsg->span_id, sigmsg->chan_id);
|
||||
schedule_timer(sigmsg->channel, PROGRESS_TIMER, send_progress);
|
||||
break;
|
||||
/* This event signals progress on an outgoing call */
|
||||
case FTDM_SIGEVENT_PROGRESS_MEDIA:
|
||||
ftdm_log(FTDM_LOG_NOTICE, "Progress message received in channel %d:%d\n", sigmsg->span_id, sigmsg->chan_id);
|
||||
break;
|
||||
/* This event signals answer in an outgoing call */
|
||||
case FTDM_SIGEVENT_UP:
|
||||
ftdm_log(FTDM_LOG_NOTICE, "Answer received in channel %d:%d\n", sigmsg->span_id, sigmsg->chan_id);
|
||||
/* now the channel is answered and we can use
|
||||
* ftdm_channel_wait() to wait for input/output in a channel (equivalent to poll() or select())
|
||||
* ftdm_channel_read() to read available data in a channel
|
||||
* ftdm_channel_write() to write to the channel */
|
||||
break;
|
||||
/* This event signals hangup from the other end */
|
||||
case FTDM_SIGEVENT_STOP:
|
||||
ftdm_log(FTDM_LOG_NOTICE, "Hangup received in channel %d:%d\n", sigmsg->span_id, sigmsg->chan_id);
|
||||
if (g_outgoing_channel == sigmsg->channel) {
|
||||
g_outgoing_channel = NULL;
|
||||
}
|
||||
/* release any timer for this channel */
|
||||
release_timers(sigmsg->channel);
|
||||
/* acknowledge the hangup */
|
||||
ftdm_channel_call_hangup(sigmsg->channel);
|
||||
break;
|
||||
default:
|
||||
ftdm_log(FTDM_LOG_WARNING, "Unhandled event %s in channel %d:%d\n", ftdm_signal_event2str(sigmsg->event_id),
|
||||
sigmsg->span_id, sigmsg->chan_id);
|
||||
break;
|
||||
}
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
static void place_call(const ftdm_span_t *span, const char *number)
|
||||
{
|
||||
ftdm_channel_t *ftdmchan = NULL;
|
||||
ftdm_caller_data_t caller_data = {{ 0 }};
|
||||
ftdm_status_t status = FTDM_FAIL;
|
||||
|
||||
/* set destiny number */
|
||||
ftdm_set_string(caller_data.dnis.digits, number);
|
||||
|
||||
/* set callerid */
|
||||
ftdm_set_string(caller_data.cid_name, "testsangomaboost");
|
||||
ftdm_set_string(caller_data.cid_num.digits, "1234");
|
||||
|
||||
/* request to search for an outgoing channel top down with the given caller data.
|
||||
* it is also an option to use ftdm_channel_open_by_group to let freetdm hunt
|
||||
* an available channel in a given group instead of per span
|
||||
* */
|
||||
status = ftdm_channel_open_by_span(ftdm_span_get_id(span), FTDM_TOP_DOWN, &caller_data, &ftdmchan);
|
||||
if (status != FTDM_SUCCESS) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Failed to originate call\n");
|
||||
return;
|
||||
}
|
||||
|
||||
g_outgoing_channel = ftdmchan;
|
||||
|
||||
/* set the caller data for the outgoing channel */
|
||||
ftdm_channel_set_caller_data(ftdmchan, &caller_data);
|
||||
|
||||
status = ftdm_channel_call_place(ftdmchan);
|
||||
if (status != FTDM_SUCCESS) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Failed to originate call\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* this is required to initialize the outgoing channel */
|
||||
ftdm_channel_init(ftdmchan);
|
||||
}
|
||||
|
||||
#define ARRLEN(arr) (sizeof(arr)/sizeof(arr[0]))
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
/* span names can be any null-terminated string, does not need to be a wanpipe port */
|
||||
int span_numbers[32];
|
||||
char span_names[ARRLEN(span_numbers)][ARRLEN(span_numbers)];
|
||||
const char *spanname = NULL;
|
||||
char wpchans[25];
|
||||
unsigned configured = 0;
|
||||
int i, spanno;
|
||||
int numspans = 0;
|
||||
ftdm_status_t status;
|
||||
ftdm_span_t *span_list[ARRLEN(span_numbers)];
|
||||
ftdm_span_t *span;
|
||||
ftdm_channel_config_t chan_config;
|
||||
ftdm_conf_parameter_t parameters[20];
|
||||
char *todial = NULL;
|
||||
int32_t ticks = 0;
|
||||
|
||||
/* register a handler to shutdown things properly */
|
||||
#ifdef _WIN64
|
||||
// still trying to figure this one out otherwise triggers error
|
||||
if (signal(SIGINT, interrupt_requested) < 0) {
|
||||
#else
|
||||
if (signal(SIGINT, interrupt_requested) == SIG_ERR) {
|
||||
#endif
|
||||
fprintf(stderr, "Could not set the SIGINT signal handler: %s\n", strerror(errno));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (argv[i][0] == '-' && argv[i][1] == 'd') {
|
||||
i++;
|
||||
if (i >= argc) {
|
||||
fprintf(stderr, "Error, -d specified but no number to dial!\n");
|
||||
exit(1);
|
||||
}
|
||||
todial = argv[i];
|
||||
if (!strlen(todial)) {
|
||||
todial = NULL;
|
||||
}
|
||||
printf("Number to dial: %s\n", todial);
|
||||
continue;
|
||||
}
|
||||
spanno = atoi(argv[i]);
|
||||
span_numbers[numspans] = spanno;
|
||||
snprintf(span_names[numspans], sizeof(span_names[numspans]), "wanpipe%d", spanno);
|
||||
numspans++;
|
||||
}
|
||||
|
||||
if (!numspans) {
|
||||
fprintf(stderr, "please specify a at least 1 wanpipe port number\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* clear any outstanding timers */
|
||||
memset(&g_timers, 0, sizeof(g_timers));
|
||||
|
||||
/* set the logging level to use */
|
||||
ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG);
|
||||
|
||||
/* this is optional.
|
||||
* cpu monitor is a default feature in freetdm that launches 1 thread
|
||||
* to monitor system-wide CPU usage. If it goes above a predefined threshold
|
||||
* it will stop accepting calls to try to protect the quality of current calls */
|
||||
ftdm_cpu_monitor_disable();
|
||||
|
||||
|
||||
/* Initialize the FTDM library */
|
||||
if (ftdm_global_init() != FTDM_SUCCESS) {
|
||||
fprintf(stderr, "Error loading FreeTDM\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* create the schedule mutex */
|
||||
ftdm_mutex_create(&g_schedule_mutex);
|
||||
|
||||
/* now we can start creating spans */
|
||||
memset(&chan_config, 0, sizeof(chan_config));
|
||||
strncpy(chan_config.group_name, "mygroup", sizeof(chan_config.group_name)-1);
|
||||
chan_config.group_name[sizeof(chan_config.group_name)-1] = 0;
|
||||
for (i = 0; i < numspans; i++) {
|
||||
spanname = span_names[i];
|
||||
/* "wanpipe" is the special I/O identifier for Sangoma devices */
|
||||
ftdm_log(FTDM_LOG_NOTICE, "Creating span %s\n", spanname);
|
||||
status = ftdm_span_create("wanpipe", spanname, &span_list[i]);
|
||||
if (status != FTDM_SUCCESS) {
|
||||
ftdm_log(FTDM_LOG_CRIT, "Failed to create span %s\n", spanname);
|
||||
goto done;
|
||||
}
|
||||
span = span_list[i];
|
||||
spanno = span_numbers[i];
|
||||
|
||||
/* set the trunk type for the span */
|
||||
ftdm_span_set_trunk_type(span_list[i], FTDM_TRUNK_T1);
|
||||
|
||||
/* configure B channels (syntax for wanpipe channels is span:low_chan-high_chan) */
|
||||
chan_config.type = FTDM_CHAN_TYPE_B;
|
||||
snprintf(wpchans, sizeof(wpchans), "%d:1-23", spanno);
|
||||
ftdm_configure_span_channels(span, wpchans, &chan_config, &configured);
|
||||
ftdm_log(FTDM_LOG_NOTICE, "registered %d b channels\n", configured);
|
||||
}
|
||||
|
||||
/* At this point FreeTDM is ready to be used, the spans defined in freetdm.conf have the basic I/O board configuration
|
||||
* but no telephony signaling configuration at all. */
|
||||
ftdm_log(FTDM_LOG_NOTICE, "FreeTDM loaded ...\n");
|
||||
|
||||
/* now we can start configuring signaling for the previously created spans */
|
||||
for (i = 0; i < numspans; i++) {
|
||||
spanname = span_names[i];
|
||||
|
||||
/* Retrieve a span by name (as specified in ftdm_span_create()) */
|
||||
if (ftdm_span_find_by_name(spanname, &span) != FTDM_SUCCESS) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM span %s\n", ftdm_span_get_name(span));
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* prepare the configuration parameters that will be sent down to the signaling stack, the array of paramters must be terminated by an
|
||||
* array element with a null .var member */
|
||||
|
||||
/* for sangoma_boost signaling (abstraction signaling used by Sangoma for PRI, BRI and SS7) the first parameter you must send
|
||||
* is sigmod, which must be either sangoma_prid, if you have the PRI stack available, or sangoma_brid for the BRI stack */
|
||||
parameters[0].var = "sigmod";
|
||||
parameters[0].val = "sangoma_prid";
|
||||
|
||||
/* following parameters are signaling stack specific, this ones are for PRI */
|
||||
parameters[1].var = "switchtype";
|
||||
parameters[1].val = "national";
|
||||
|
||||
parameters[2].var = "signalling";
|
||||
parameters[2].val = "pri_cpe";
|
||||
|
||||
/*
|
||||
* parameters[3].var = "nfas_primary";
|
||||
* parameters[3].val = "4"; //span number
|
||||
*
|
||||
* parameters[4].var = "nfas_secondary";
|
||||
* parameters[4].val = "2"; //span number
|
||||
*
|
||||
* parameters[5].var = "nfas_group";
|
||||
* parameters[5].val = "1";
|
||||
* */
|
||||
|
||||
|
||||
/* the last parameter .var member must be NULL! */
|
||||
parameters[3].var = NULL;
|
||||
|
||||
/* send the configuration values down to the stack */
|
||||
if (ftdm_configure_span_signaling(span, "sangoma_boost", on_signaling_event, parameters) != FTDM_SUCCESS) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Error configuring sangoma_boost signaling abstraction in span %s\n", ftdm_span_get_name(span));
|
||||
goto done;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* configuration succeeded, we can proceed now to start each span
|
||||
* This step will launch at least 1 background (may be more, depending on the signaling stack used)
|
||||
* to handle *ALL* signaling events for this span, your on_signaling_event callback will be called always
|
||||
* in one of those infraestructure threads and you MUST NOT block in that handler to avoid delays and errors
|
||||
* in the signaling processing for any call.
|
||||
* */
|
||||
for (i = 0; i < numspans; i++) {
|
||||
spanname = span_names[i];
|
||||
/* Retrieve a span by name (as specified in ftdm_span_create()) */
|
||||
if (ftdm_span_find_by_name(spanname, &span) != FTDM_SUCCESS) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM span %s\n", ftdm_span_get_name(span));
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (ftdm_span_start(span) != FTDM_SUCCESS) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Failing starting signaling on span %s\n", ftdm_span_get_name(span));
|
||||
goto done;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
app_running = 1;
|
||||
|
||||
/* Retrieve the first created span to place the call (if dialing was specified) */
|
||||
if (ftdm_span_find(1, &span) != FTDM_SUCCESS) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM span 1\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* The application thread can go on and do anything else, like waiting for a shutdown signal */
|
||||
while(ftdm_running() && app_running) {
|
||||
ftdm_sleep(1000);
|
||||
run_timers();
|
||||
ticks++;
|
||||
if (!(ticks % 10) && todial && !g_outgoing_channel) {
|
||||
ftdm_log(FTDM_LOG_NOTICE, "Originating call to number %s\n", todial);
|
||||
place_call(span, todial);
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
ftdm_log(FTDM_LOG_NOTICE, "Shutting down FreeTDM ...\n");
|
||||
|
||||
ftdm_mutex_destroy(&g_schedule_mutex);
|
||||
|
||||
/* whenever you're done, this function will shutdown the signaling threads in any span that was started */
|
||||
ftdm_global_destroy();
|
||||
|
||||
printf("Terminated!\n");
|
||||
|
||||
sleep(2);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4:
|
||||
*/
|
|
@ -27,11 +27,12 @@
|
|||
#include <stdio.h>
|
||||
|
||||
|
||||
FT_DECLARE(void) ftdm_dso_destroy(ftdm_dso_lib_t *lib) {
|
||||
FT_DECLARE(ftdm_status_t) ftdm_dso_destroy(ftdm_dso_lib_t *lib) {
|
||||
if (lib && *lib) {
|
||||
FreeLibrary(*lib);
|
||||
*lib = NULL;
|
||||
}
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
FT_DECLARE(ftdm_dso_lib_t) ftdm_dso_open(const char *path, char **err) {
|
||||
|
@ -78,11 +79,20 @@ FT_DECLARE(void*) ftdm_dso_func_sym(ftdm_dso_lib_t lib, const char *sym, char **
|
|||
|
||||
#include <dlfcn.h>
|
||||
|
||||
FT_DECLARE(void) ftdm_dso_destroy(ftdm_dso_lib_t *lib) {
|
||||
FT_DECLARE(ftdm_status_t) ftdm_dso_destroy(ftdm_dso_lib_t *lib) {
|
||||
int rc;
|
||||
if (lib && *lib) {
|
||||
dlclose(*lib);
|
||||
rc = dlclose(*lib);
|
||||
if (rc) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Failed to close lib %p: %s\n", *lib, dlerror());
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
ftdm_log(FTDM_LOG_DEBUG, "lib %p was closed with success\n", *lib);
|
||||
*lib = NULL;
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
ftdm_log(FTDM_LOG_ERROR, "Invalid pointer provided to ftdm_dso_destroy\n");
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
FT_DECLARE(ftdm_dso_lib_t) ftdm_dso_open(const char *path, char **err) {
|
||||
|
@ -93,7 +103,7 @@ FT_DECLARE(ftdm_dso_lib_t) ftdm_dso_open(const char *path, char **err) {
|
|||
return lib;
|
||||
}
|
||||
|
||||
FT_DECLARE(void*) ftdm_dso_func_sym(ftdm_dso_lib_t lib, const char *sym, char **err) {
|
||||
FT_DECLARE(void *) ftdm_dso_func_sym(ftdm_dso_lib_t lib, const char *sym, char **err) {
|
||||
void *func = dlsym(lib, sym);
|
||||
if (!func) {
|
||||
*err = ftdm_strdup(dlerror());
|
||||
|
|
|
@ -522,17 +522,41 @@ FT_DECLARE(ftdm_status_t) ftdm_span_stop(ftdm_span_t *span)
|
|||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
FT_DECLARE(ftdm_status_t) ftdm_span_create(ftdm_io_interface_t *fio, ftdm_span_t **span, const char *name)
|
||||
FT_DECLARE(ftdm_status_t) ftdm_span_create(const char *iotype, const char *name, ftdm_span_t **span)
|
||||
{
|
||||
ftdm_span_t *new_span = NULL;
|
||||
ftdm_io_interface_t *fio = NULL;
|
||||
ftdm_status_t status = FTDM_FAIL;
|
||||
char buf[128] = "";
|
||||
|
||||
ftdm_assert(fio != NULL, "No IO provided\n");
|
||||
ftdm_assert_return(iotype != NULL, FTDM_FAIL, "No IO type provided\n");
|
||||
ftdm_assert_return(name != NULL, FTDM_FAIL, "No span name provided\n");
|
||||
|
||||
*span = NULL;
|
||||
|
||||
ftdm_mutex_lock(globals.mutex);
|
||||
if (!(fio = (ftdm_io_interface_t *) hashtable_search(globals.interface_hash, (void *)iotype))) {
|
||||
ftdm_load_module_assume(iotype);
|
||||
if ((fio = (ftdm_io_interface_t *) hashtable_search(globals.interface_hash, (void *)iotype))) {
|
||||
ftdm_log(FTDM_LOG_INFO, "Auto-loaded I/O module '%s'\n", iotype);
|
||||
}
|
||||
}
|
||||
ftdm_mutex_unlock(globals.mutex);
|
||||
|
||||
if (!fio) {
|
||||
ftdm_log(FTDM_LOG_CRIT, "failure creating span, no such I/O type '%s'\n", iotype);
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
if (!fio->configure_span) {
|
||||
ftdm_log(FTDM_LOG_CRIT, "failure creating span, no configure_span method for I/O type '%s'\n", iotype);
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
ftdm_mutex_lock(globals.mutex);
|
||||
if (globals.span_index < FTDM_MAX_SPANS_INTERFACE) {
|
||||
new_span = ftdm_calloc(sizeof(*new_span), 1);
|
||||
|
||||
ftdm_assert(new_span, "allocating span failed\n");
|
||||
|
||||
status = ftdm_mutex_create(&new_span->mutex);
|
||||
|
@ -556,11 +580,11 @@ FT_DECLARE(ftdm_status_t) ftdm_span_create(ftdm_io_interface_t *fio, ftdm_span_t
|
|||
ftdm_mutex_unlock(globals.span_mutex);
|
||||
|
||||
if (!name) {
|
||||
char buf[128] = "";
|
||||
snprintf(buf, sizeof(buf), "span%d", new_span->span_id);
|
||||
name = buf;
|
||||
}
|
||||
new_span->name = ftdm_strdup(name);
|
||||
new_span->type = ftdm_strdup(iotype);
|
||||
ftdm_span_add(new_span);
|
||||
*span = new_span;
|
||||
status = FTDM_SUCCESS;
|
||||
|
@ -1657,6 +1681,16 @@ FT_DECLARE(const char *) ftdm_channel_get_span_name(const ftdm_channel_t *ftdmch
|
|||
return ftdmchan->span->name;
|
||||
}
|
||||
|
||||
FT_DECLARE(void) ftdm_span_set_trunk_type(ftdm_span_t *span, ftdm_trunk_type_t type)
|
||||
{
|
||||
span->trunk_type = type;
|
||||
}
|
||||
|
||||
FT_DECLARE(ftdm_trunk_type_t) ftdm_span_get_trunk_type(const ftdm_span_t *span)
|
||||
{
|
||||
return span->trunk_type;
|
||||
}
|
||||
|
||||
FT_DECLARE(uint32_t) ftdm_span_get_id(const ftdm_span_t *span)
|
||||
{
|
||||
return span->span_id;
|
||||
|
@ -3227,7 +3261,15 @@ static ftdm_status_t ftdm_set_channels_alarms(ftdm_span_t *span, int currindex)
|
|||
|
||||
FT_DECLARE(ftdm_status_t) ftdm_configure_span_channels(ftdm_span_t *span, const char* str, ftdm_channel_config_t *chan_config, unsigned *configured)
|
||||
{
|
||||
int currindex = span->chan_count;
|
||||
int currindex;
|
||||
|
||||
ftdm_assert_return(span != NULL, FTDM_EINVAL, "span is null\n");
|
||||
ftdm_assert_return(chan_config != NULL, FTDM_EINVAL, "config is null\n");
|
||||
ftdm_assert_return(configured != NULL, FTDM_EINVAL, "configured pointer is null\n");
|
||||
ftdm_assert_return(span->fio != NULL, FTDM_EINVAL, "span with no I/O configured\n");
|
||||
ftdm_assert_return(span->fio->configure_span != NULL, FTDM_NOTIMPL, "span I/O with no channel configuration implemented\n");
|
||||
|
||||
currindex = span->chan_count;
|
||||
*configured = 0;
|
||||
*configured = span->fio->configure_span(span, str, chan_config->type, chan_config->name, chan_config->number);
|
||||
if (!*configured) {
|
||||
|
@ -3235,18 +3277,24 @@ FT_DECLARE(ftdm_status_t) ftdm_configure_span_channels(ftdm_span_t *span, const
|
|||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
if (ftdm_group_add_channels(span, currindex, chan_config->group_name) != FTDM_SUCCESS) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "%d:Failed to add channels to group %s\n", span->span_id, chan_config->group_name);
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
if (ftdm_set_channels_alarms(span, currindex) != FTDM_SUCCESS) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "%d:Failed to set channel alarms\n", span->span_id);
|
||||
return FTDM_FAIL;
|
||||
if (chan_config->group_name[0]) {
|
||||
if (ftdm_group_add_channels(span, currindex, chan_config->group_name) != FTDM_SUCCESS) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "%d:Failed to add channels to group %s\n", span->span_id, chan_config->group_name);
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
if (ftdm_set_channels_gains(span, currindex, chan_config->rxgain, chan_config->txgain) != FTDM_SUCCESS) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "%d:Failed to set channel gains\n", span->span_id);
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
|
||||
if (ftdm_set_channels_alarms(span, currindex) != FTDM_SUCCESS) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "%d:Failed to set channel alarms\n", span->span_id);
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -3260,7 +3308,6 @@ static ftdm_status_t load_config(void)
|
|||
int intparam = 0;
|
||||
ftdm_span_t *span = NULL;
|
||||
unsigned configured = 0, d = 0;
|
||||
ftdm_io_interface_t *fio = NULL;
|
||||
ftdm_analog_start_type_t tmp;
|
||||
ftdm_size_t len = 0;
|
||||
ftdm_channel_config_t chan_config;
|
||||
|
@ -3271,7 +3318,7 @@ static ftdm_status_t load_config(void)
|
|||
if (!ftdm_config_open_file(&cfg, cfg_name)) {
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
ftdm_log(FTDM_LOG_DEBUG, "Reading FreeTDM configuration file\n");
|
||||
while (ftdm_config_next_pair(&cfg, &var, &val)) {
|
||||
if (*cfg.category == '#') {
|
||||
if (cfg.catno != catno) {
|
||||
|
@ -3300,33 +3347,9 @@ static ftdm_status_t load_config(void)
|
|||
*name++ = '\0';
|
||||
}
|
||||
|
||||
ftdm_mutex_lock(globals.mutex);
|
||||
if (!(fio = (ftdm_io_interface_t *) hashtable_search(globals.interface_hash, type))) {
|
||||
ftdm_load_module_assume(type);
|
||||
if ((fio = (ftdm_io_interface_t *) hashtable_search(globals.interface_hash, type))) {
|
||||
ftdm_log(FTDM_LOG_INFO, "auto-loaded '%s'\n", type);
|
||||
}
|
||||
}
|
||||
ftdm_mutex_unlock(globals.mutex);
|
||||
|
||||
if (!fio) {
|
||||
ftdm_log(FTDM_LOG_CRIT, "failure creating span, no such type '%s'\n", type);
|
||||
span = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!fio->configure_span) {
|
||||
ftdm_log(FTDM_LOG_CRIT, "failure creating span, no configure_span method for '%s'\n", type);
|
||||
span = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ftdm_span_create(fio, &span, name) == FTDM_SUCCESS) {
|
||||
span->type = ftdm_strdup(type);
|
||||
d = 0;
|
||||
|
||||
if (ftdm_span_create(type, name, &span) == FTDM_SUCCESS) {
|
||||
ftdm_log(FTDM_LOG_DEBUG, "created span %d (%s) of type %s\n", span->span_id, span->name, type);
|
||||
|
||||
d = 0;
|
||||
} else {
|
||||
ftdm_log(FTDM_LOG_CRIT, "failure creating span of type %s\n", type);
|
||||
span = NULL;
|
||||
|
@ -3341,8 +3364,9 @@ static ftdm_status_t load_config(void)
|
|||
ftdm_log(FTDM_LOG_DEBUG, "span %d [%s]=[%s]\n", span->span_id, var, val);
|
||||
|
||||
if (!strcasecmp(var, "trunk_type")) {
|
||||
span->trunk_type = ftdm_str2ftdm_trunk_type(val);
|
||||
ftdm_log(FTDM_LOG_DEBUG, "setting trunk type to '%s'\n", ftdm_trunk_type2str(span->trunk_type));
|
||||
ftdm_trunk_type_t trtype = ftdm_str2ftdm_trunk_type(val);
|
||||
ftdm_span_set_trunk_type(span, trtype);
|
||||
ftdm_log(FTDM_LOG_DEBUG, "setting trunk type to '%s'\n", ftdm_trunk_type2str(trtype));
|
||||
} else if (!strcasecmp(var, "name")) {
|
||||
if (!strcasecmp(val, "undef")) {
|
||||
chan_config.name[0] = '\0';
|
||||
|
@ -3371,7 +3395,7 @@ static ftdm_status_t load_config(void)
|
|||
ftdm_analog_start_type2str(span->start_type));
|
||||
}
|
||||
if (span->trunk_type == FTDM_TRUNK_FXO) {
|
||||
unsigned chans_configured = 0;
|
||||
unsigned chans_configured = 0;
|
||||
chan_config.type = FTDM_CHAN_TYPE_FXO;
|
||||
if (ftdm_configure_span_channels(span, val, &chan_config, &chans_configured) == FTDM_SUCCESS) {
|
||||
configured += chans_configured;
|
||||
|
|
|
@ -40,7 +40,8 @@
|
|||
|
||||
typedef enum {
|
||||
FTDM_SANGOMA_BOOST_RUNNING = (1 << 0),
|
||||
FTDM_SANGOMA_BOOST_RESTARTING = (1 << 1)
|
||||
FTDM_SANGOMA_BOOST_RESTARTING = (1 << 1),
|
||||
FTDM_SANGOMA_BOOST_EVENTS_RUNNING = (1 << 2),
|
||||
} ftdm_sangoma_boost_flag_t;
|
||||
|
||||
typedef struct ftdm_sangoma_boost_data {
|
||||
|
|
|
@ -1721,18 +1721,22 @@ static __inline__ ftdm_status_t check_events(ftdm_span_t *span, int ms_timeout)
|
|||
*/
|
||||
static void *ftdm_sangoma_events_run(ftdm_thread_t *me, void *obj)
|
||||
{
|
||||
ftdm_span_t *span = (ftdm_span_t *) obj;
|
||||
ftdm_span_t *span = (ftdm_span_t *) obj;
|
||||
ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
|
||||
unsigned errs = 0;
|
||||
|
||||
while (ftdm_test_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING) && ftdm_running()) {
|
||||
if (check_events(span,100) != FTDM_SUCCESS) {
|
||||
while (ftdm_test_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_EVENTS_RUNNING) && ftdm_running()) {
|
||||
if (check_events(span, 100) != FTDM_SUCCESS) {
|
||||
if (errs++ > 50) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Too many event errors, quitting sangoma events thread\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ftdm_log(FTDM_LOG_DEBUG, "Sangoma Boost Events thread ended.\n");
|
||||
|
||||
ftdm_clear_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_EVENTS_RUNNING);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -2138,12 +2142,13 @@ static FIO_SIG_UNLOAD_FUNCTION(ftdm_sangoma_boost_destroy)
|
|||
const void *key = NULL;
|
||||
void *val = NULL;
|
||||
ftdm_dso_lib_t lib;
|
||||
|
||||
ftdm_log(FTDM_LOG_DEBUG, "Destroying sangoma boost module\n");
|
||||
for (i = hashtable_first(g_boost_modules_hash); i; i = hashtable_next(i)) {
|
||||
hashtable_this(i, &key, NULL, &val);
|
||||
if (key && val) {
|
||||
sigmod = val;
|
||||
lib = sigmod->pvt;
|
||||
ftdm_log(FTDM_LOG_DEBUG, "destroying sigmod %s\n", sigmod->name);
|
||||
ftdm_dso_destroy(&lib);
|
||||
}
|
||||
}
|
||||
|
@ -2159,18 +2164,23 @@ static ftdm_status_t ftdm_sangoma_boost_start(ftdm_span_t *span)
|
|||
int err;
|
||||
|
||||
ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
|
||||
|
||||
ftdm_set_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING);
|
||||
err=ftdm_thread_create_detached(ftdm_sangoma_boost_run, span);
|
||||
err = ftdm_thread_create_detached(ftdm_sangoma_boost_run, span);
|
||||
if (err) {
|
||||
ftdm_clear_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING);
|
||||
return err;
|
||||
}
|
||||
|
||||
// launch the events thread to handle HW DTMF and possibly
|
||||
// other events in the future
|
||||
err=ftdm_thread_create_detached(ftdm_sangoma_events_run, span);
|
||||
ftdm_set_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_EVENTS_RUNNING);
|
||||
err = ftdm_thread_create_detached(ftdm_sangoma_events_run, span);
|
||||
if (err) {
|
||||
ftdm_clear_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_EVENTS_RUNNING);
|
||||
ftdm_clear_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -2179,12 +2189,16 @@ static ftdm_status_t ftdm_sangoma_boost_stop(ftdm_span_t *span)
|
|||
int cnt = 50;
|
||||
ftdm_status_t status = FTDM_SUCCESS;
|
||||
ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data;
|
||||
|
||||
if (sangoma_boost_data->sigmod) {
|
||||
/* I think stopping the span before destroying the queue makes sense
|
||||
otherwise may be boost events would still arrive when the queue is already destroyed! */
|
||||
status = sangoma_boost_data->sigmod->stop_span(span);
|
||||
if (status != FTDM_SUCCESS) {
|
||||
ftdm_log(FTDM_LOG_CRIT, "Failed to stop span %s boost signaling\n", span->name);
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
ftdm_queue_enqueue(sangoma_boost_data->boost_queue, NULL);
|
||||
return status;
|
||||
}
|
||||
|
||||
while (ftdm_test_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_RUNNING) && cnt-- > 0) {
|
||||
|
@ -2197,6 +2211,17 @@ static ftdm_status_t ftdm_sangoma_boost_stop(ftdm_span_t *span)
|
|||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
cnt = 50;
|
||||
while (ftdm_test_flag(sangoma_boost_data, FTDM_SANGOMA_BOOST_EVENTS_RUNNING) && cnt-- > 0) {
|
||||
ftdm_log(FTDM_LOG_DEBUG, "Waiting for boost events thread\n");
|
||||
ftdm_sleep(100);
|
||||
}
|
||||
|
||||
if (!cnt) {
|
||||
ftdm_log(FTDM_LOG_CRIT, "it seems boost events thread in span %s may be stuck, we may segfault :-(\n", span->name);
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
if (sangoma_boost_data->sigmod) {
|
||||
ftdm_queue_destroy(&sangoma_boost_data->boost_queue);
|
||||
}
|
||||
|
|
|
@ -67,7 +67,8 @@ typedef enum {
|
|||
FTDM_MEMERR, /*!< Memory error, most likely allocation failure */
|
||||
FTDM_TIMEOUT, /*!< Operation timed out (ie: polling on a device)*/
|
||||
FTDM_NOTIMPL, /*!< Operation not implemented */
|
||||
FTDM_BREAK /*!< Request the caller to perform a break (context-dependant, ie: stop getting DNIS/ANI) */
|
||||
FTDM_BREAK, /*!< Request the caller to perform a break (context-dependant, ie: stop getting DNIS/ANI) */
|
||||
FTDM_EINVAL /*!< Invalid argument */
|
||||
} ftdm_status_t;
|
||||
|
||||
/*! \brief FreeTDM bool type. */
|
||||
|
@ -299,6 +300,23 @@ typedef enum {
|
|||
/*! \brief Move from string to ftdm_signal_event_t and viceversa */
|
||||
FTDM_STR2ENUM_P(ftdm_str2ftdm_signal_event, ftdm_signal_event2str, ftdm_signal_event_t)
|
||||
|
||||
/*! \brief Span trunk types */
|
||||
typedef enum {
|
||||
FTDM_TRUNK_E1,
|
||||
FTDM_TRUNK_T1,
|
||||
FTDM_TRUNK_J1,
|
||||
FTDM_TRUNK_BRI,
|
||||
FTDM_TRUNK_BRI_PTMP,
|
||||
FTDM_TRUNK_FXO,
|
||||
FTDM_TRUNK_FXS,
|
||||
FTDM_TRUNK_EM,
|
||||
FTDM_TRUNK_NONE
|
||||
} ftdm_trunk_type_t;
|
||||
#define TRUNK_STRINGS "E1", "T1", "J1", "BRI", "BRI_PTMP", "FXO", "FXS", "EM", "NONE"
|
||||
|
||||
/*! \brief Move from string to ftdm_trunk_type_t and viceversa */
|
||||
FTDM_STR2ENUM_P(ftdm_str2ftdm_trunk_type, ftdm_trunk_type2str, ftdm_trunk_type_t)
|
||||
|
||||
/*! \brief Basic channel configuration provided to ftdm_configure_span_channels */
|
||||
typedef struct ftdm_channel_config {
|
||||
char name[FTDM_MAX_NAME_STR_SZ];
|
||||
|
@ -809,14 +827,18 @@ FT_DECLARE(const char *) ftdm_span_get_last_error(const ftdm_span_t *span);
|
|||
/*!
|
||||
* \brief Create a new span (not needed if you are using freetdm.conf)
|
||||
*
|
||||
* \param fio The I/O interface the span will use
|
||||
* \param span Pointer to store the create span
|
||||
* \param iotype The I/O interface type this span will use.
|
||||
* This depends on the available I/O modules
|
||||
* ftmod_wanpipe = "wanpipe" (Sangoma)
|
||||
* ftmod_zt = "zt" (DAHDI or Zaptel)
|
||||
* ftmod_pika "pika" (this one is most likely broken)
|
||||
* \param name Name for the span
|
||||
* \param span Pointer to store the create span
|
||||
*
|
||||
* \retval FTDM_SUCCESS success (the span was created)
|
||||
* \retval FTDM_FAIL failure (span was not created)
|
||||
*/
|
||||
FT_DECLARE(ftdm_status_t) ftdm_span_create(ftdm_io_interface_t *fio, ftdm_span_t **span, const char *name);
|
||||
FT_DECLARE(ftdm_status_t) ftdm_span_create(const char *iotype, const char *name, ftdm_span_t **span);
|
||||
|
||||
/*!
|
||||
* \brief Add a new channel to a span
|
||||
|
@ -1144,8 +1166,39 @@ FT_DECLARE(ftdm_status_t) ftdm_conf_node_add_param(ftdm_conf_node_t *node, const
|
|||
* \return FTDM_FAIL failure
|
||||
*/
|
||||
FT_DECLARE(ftdm_status_t) ftdm_conf_node_destroy(ftdm_conf_node_t *node);
|
||||
|
||||
/*!
|
||||
* \brief Create and configure channels in the given span
|
||||
*
|
||||
* \param span The span container
|
||||
* \param str The channel range null terminated string. "1-10", "24" etc
|
||||
* \param chan_config The basic channel configuration for each channel within the range
|
||||
* \param configured Pointer where the number of channels configured will be stored
|
||||
*
|
||||
* \return FTDM_SUCCESS success
|
||||
* \return FTDM_FAIL failure
|
||||
*/
|
||||
FT_DECLARE(ftdm_status_t) ftdm_configure_span_channels(ftdm_span_t *span, const char *str, ftdm_channel_config_t *chan_config, unsigned *configured);
|
||||
|
||||
/*!
|
||||
* \brief Set the trunk type for a span
|
||||
* This must be called before configuring any channels within the span
|
||||
*
|
||||
* \param span The span
|
||||
* \param type The trunk type
|
||||
*
|
||||
*/
|
||||
FT_DECLARE(void) ftdm_span_set_trunk_type(ftdm_span_t *span, ftdm_trunk_type_t type);
|
||||
|
||||
/*!
|
||||
* \brief Get the trunk type for a span
|
||||
*
|
||||
* \param span The span
|
||||
*
|
||||
* \return The span trunk type
|
||||
*/
|
||||
FT_DECLARE(ftdm_trunk_type_t) ftdm_span_get_trunk_type(const ftdm_span_t *span);
|
||||
|
||||
/*!
|
||||
* \brief Return the channel identified by the provided id
|
||||
*
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include "freetdm.h"
|
||||
|
||||
#ifndef _FTDM_DSO_H
|
||||
#define _FTDM_DSO_H
|
||||
|
@ -28,7 +29,7 @@ extern "C" {
|
|||
typedef void (*ftdm_func_ptr_t) (void);
|
||||
typedef void * ftdm_dso_lib_t;
|
||||
|
||||
FT_DECLARE(void) ftdm_dso_destroy(ftdm_dso_lib_t *lib);
|
||||
FT_DECLARE(ftdm_status_t) ftdm_dso_destroy(ftdm_dso_lib_t *lib);
|
||||
FT_DECLARE(ftdm_dso_lib_t) ftdm_dso_open(const char *path, char **err);
|
||||
FT_DECLARE(void *) ftdm_dso_func_sym(ftdm_dso_lib_t lib, const char *sym, char **err);
|
||||
|
||||
|
|
|
@ -111,20 +111,6 @@ typedef enum {
|
|||
#define TONEMAP_STRINGS "NONE", "DIAL", "RING", "BUSY", "FAIL1", "FAIL2", "FAIL3", "ATTN", "CALLWAITING-CAS", "CALLWAITING-SAS", "CALLWAITING-ACK", "INVALID"
|
||||
FTDM_STR2ENUM_P(ftdm_str2ftdm_tonemap, ftdm_tonemap2str, ftdm_tonemap_t)
|
||||
|
||||
typedef enum {
|
||||
FTDM_TRUNK_E1,
|
||||
FTDM_TRUNK_T1,
|
||||
FTDM_TRUNK_J1,
|
||||
FTDM_TRUNK_BRI,
|
||||
FTDM_TRUNK_BRI_PTMP,
|
||||
FTDM_TRUNK_FXO,
|
||||
FTDM_TRUNK_FXS,
|
||||
FTDM_TRUNK_EM,
|
||||
FTDM_TRUNK_NONE
|
||||
} ftdm_trunk_type_t;
|
||||
#define TRUNK_STRINGS "E1", "T1", "J1", "BRI", "BRI_PTMP", "FXO", "FXS", "EM", "NONE"
|
||||
FTDM_STR2ENUM_P(ftdm_str2ftdm_trunk_type, ftdm_trunk_type2str, ftdm_trunk_type_t)
|
||||
|
||||
typedef enum {
|
||||
FTDM_ANALOG_START_KEWL,
|
||||
FTDM_ANALOG_START_LOOP,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,50 +0,0 @@
|
|||
***************
|
||||
*** 3410,3420 ****
|
||||
}
|
||||
if (test_eflag(member->conference, EFLAG_VOLUME_IN_MEMBER) &&
|
||||
data && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
|
||||
conference_add_event_member_data(member, event);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "volume-in-member");
|
||||
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Volume-Level", "%u", member->volume_in_level);
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
--- 3410,3420 ----
|
||||
}
|
||||
if (test_eflag(member->conference, EFLAG_VOLUME_IN_MEMBER) &&
|
||||
data && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
|
||||
conference_add_event_member_data(member, event);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "volume-in-member");
|
||||
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Volume-Level", "%d", member->volume_in_level);
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
***************
|
||||
*** 3437,3447 ****
|
||||
}
|
||||
if (test_eflag(member->conference, EFLAG_VOLUME_OUT_MEMBER) && data &&
|
||||
switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
|
||||
conference_add_event_member_data(member, event);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "volume-out-member");
|
||||
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Volume-Level", "%u", member->volume_out_level);
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
--- 3437,3447 ----
|
||||
}
|
||||
if (test_eflag(member->conference, EFLAG_VOLUME_OUT_MEMBER) && data &&
|
||||
switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
|
||||
conference_add_event_member_data(member, event);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "volume-out-member");
|
||||
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Volume-Level", "%d", member->volume_out_level);
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
|
@ -50,10 +50,6 @@
|
|||
|
||||
#include <switch.h>
|
||||
|
||||
/* Defaults */
|
||||
static char SQL_LOOKUP[] = "SELECT %s AS nibble_balance FROM %s WHERE %s='%s'";
|
||||
static char SQL_SAVE[] = "UPDATE %s SET %s=%s-%f WHERE %s='%s'";
|
||||
|
||||
typedef struct {
|
||||
switch_time_t lastts; /* Last time we did any billing */
|
||||
float total; /* Total amount billed so far */
|
||||
|
@ -300,7 +296,6 @@ static void transfer_call(switch_core_session_t *session, char *destination)
|
|||
/* At this time, billing never succeeds if you don't have a database. */
|
||||
static switch_status_t bill_event(float billamount, const char *billaccount, switch_channel_t *channel)
|
||||
{
|
||||
switch_stream_handle_t sql_stream = { 0 };
|
||||
char *sql = NULL, *dsql = NULL;
|
||||
switch_odbc_statement_handle_t stmt = NULL;
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
|
@ -318,11 +313,9 @@ static switch_status_t bill_event(float billamount, const char *billaccount, swi
|
|||
sql = globals.custom_sql_save;
|
||||
}
|
||||
} else {
|
||||
SWITCH_STANDARD_STREAM(sql_stream);
|
||||
sql_stream.write_function(&sql_stream, SQL_SAVE, globals.db_table, globals.db_column_cash,
|
||||
globals.db_column_cash, billamount, globals.db_column_account, billaccount);
|
||||
|
||||
sql = (char *) sql_stream.data;
|
||||
sql = dsql = switch_mprintf("UPDATE %s SET %s=%s-%f WHERE %s='%s'", globals.db_table, globals.db_column_cash,
|
||||
globals.db_column_cash, billamount, globals.db_column_account, billaccount);
|
||||
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Doing update query\n[%s]\n", sql);
|
||||
|
@ -339,23 +332,18 @@ static switch_status_t bill_event(float billamount, const char *billaccount, swi
|
|||
}
|
||||
|
||||
switch_safe_free(dsql);
|
||||
switch_safe_free(sql_stream.data);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static float get_balance(const char *billaccount, switch_channel_t *channel)
|
||||
{
|
||||
switch_stream_handle_t sql_stream = { 0 };
|
||||
char *sql = NULL;
|
||||
char *dsql = NULL, *sql = NULL;
|
||||
nibblebill_results_t pdata;
|
||||
float balance = 0.00f;
|
||||
SWITCH_STANDARD_STREAM(sql_stream);
|
||||
|
||||
if (!switch_odbc_available()) {
|
||||
balance = -1.00f;
|
||||
goto end;
|
||||
return -1.00f;
|
||||
}
|
||||
|
||||
memset(&pdata, 0, sizeof(pdata));
|
||||
|
@ -363,13 +351,15 @@ static float get_balance(const char *billaccount, switch_channel_t *channel)
|
|||
if (globals.custom_sql_lookup) {
|
||||
if (switch_string_var_check_const(globals.custom_sql_lookup) || switch_string_has_escaped_data(globals.custom_sql_lookup)) {
|
||||
sql = switch_channel_expand_variables(channel, globals.custom_sql_lookup);
|
||||
if (sql != globals.custom_sql_lookup) dsql = sql;
|
||||
} else {
|
||||
sql = globals.custom_sql_lookup;
|
||||
}
|
||||
} else {
|
||||
sql_stream.write_function(&sql_stream, SQL_LOOKUP, globals.db_column_cash, globals.db_table, globals.db_column_account, billaccount);
|
||||
sql = sql_stream.data;
|
||||
sql = dsql = switch_mprintf("SELECT %s AS nibble_balance FROM %s WHERE %s='%s'",
|
||||
globals.db_column_cash, globals.db_table, globals.db_column_account, billaccount);
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Doing lookup query\n[%s]\n", sql);
|
||||
|
||||
if (switch_odbc_handle_callback_exec(globals.master_odbc, sql, nibblebill_callback, &pdata, NULL) != SWITCH_ODBC_SUCCESS) {
|
||||
|
@ -377,19 +367,13 @@ static float get_balance(const char *billaccount, switch_channel_t *channel)
|
|||
/* Return -1 for safety */
|
||||
|
||||
balance = -1.00f;
|
||||
goto end;
|
||||
} else {
|
||||
/* Successfully retrieved! */
|
||||
balance = pdata.balance;
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Retrieved current balance for account %s (balance = %f)\n", billaccount, balance);
|
||||
}
|
||||
|
||||
end:
|
||||
if (sql != globals.custom_sql_lookup && sql != sql_stream.data) {
|
||||
switch_safe_free(sql);
|
||||
}
|
||||
switch_safe_free(sql_stream.data);
|
||||
switch_safe_free(dsql);
|
||||
return balance;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,462 +0,0 @@
|
|||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2010, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
*
|
||||
* mod_sndfile.c -- Framework Demo Module
|
||||
*
|
||||
*/
|
||||
#include <switch.h>
|
||||
#include <sndfile.h>
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_sndfile_load);
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_sndfile_shutdown);
|
||||
SWITCH_MODULE_DEFINITION(mod_sndfile, mod_sndfile_load, mod_sndfile_shutdown, NULL);
|
||||
|
||||
static switch_memory_pool_t *module_pool = NULL;
|
||||
|
||||
static struct {
|
||||
switch_hash_t *format_hash;
|
||||
} globals;
|
||||
|
||||
struct format_map {
|
||||
char *ext;
|
||||
char *uext;
|
||||
uint32_t format;
|
||||
};
|
||||
|
||||
struct sndfile_context {
|
||||
SF_INFO sfinfo;
|
||||
SNDFILE *handle;
|
||||
};
|
||||
|
||||
typedef struct sndfile_context sndfile_context;
|
||||
|
||||
static switch_status_t sndfile_file_open(switch_file_handle_t *handle, const char *path)
|
||||
{
|
||||
sndfile_context *context;
|
||||
int mode = 0;
|
||||
char *ext;
|
||||
struct format_map *map = NULL;
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
char *alt_path = NULL, *last, *ldup = NULL;
|
||||
size_t alt_len = 0;
|
||||
int rates[4] = { 8000, 16000, 32000, 48000 };
|
||||
int i;
|
||||
#ifdef WIN32
|
||||
char ps = '\\';
|
||||
#else
|
||||
char ps = '/';
|
||||
#endif
|
||||
|
||||
if ((ext = strrchr(path, '.')) == 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Format\n");
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
ext++;
|
||||
|
||||
if (switch_test_flag(handle, SWITCH_FILE_FLAG_READ)) {
|
||||
mode += SFM_READ;
|
||||
}
|
||||
|
||||
if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) {
|
||||
if (switch_test_flag(handle, SWITCH_FILE_WRITE_APPEND)) {
|
||||
mode += SFM_RDWR;
|
||||
} else {
|
||||
mode += SFM_WRITE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mode) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Mode!\n");
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
|
||||
if ((context = switch_core_alloc(handle->memory_pool, sizeof(*context))) == 0) {
|
||||
return SWITCH_STATUS_MEMERR;
|
||||
}
|
||||
|
||||
map = switch_core_hash_find(globals.format_hash, ext);
|
||||
|
||||
if (mode & SFM_WRITE) {
|
||||
context->sfinfo.channels = handle->channels;
|
||||
context->sfinfo.samplerate = handle->samplerate;
|
||||
if (handle->samplerate == 8000 || handle->samplerate == 16000 ||
|
||||
handle->samplerate == 24000 || handle->samplerate == 32000 || handle->samplerate == 48000 ||
|
||||
handle->samplerate == 11025 || handle->samplerate == 22050 || handle->samplerate == 44100) {
|
||||
context->sfinfo.format |= SF_FORMAT_PCM_16;
|
||||
}
|
||||
}
|
||||
|
||||
if (map) {
|
||||
context->sfinfo.format |= map->format;
|
||||
}
|
||||
|
||||
if (!strcmp(ext, "r8") || !strcmp(ext, "raw")) {
|
||||
context->sfinfo.format = SF_FORMAT_RAW | SF_FORMAT_PCM_16;
|
||||
context->sfinfo.channels = 1;
|
||||
context->sfinfo.samplerate = 8000;
|
||||
} else if (!strcmp(ext, "r16")) {
|
||||
context->sfinfo.format = SF_FORMAT_RAW | SF_FORMAT_PCM_16;
|
||||
context->sfinfo.channels = 1;
|
||||
context->sfinfo.samplerate = 16000;
|
||||
} else if (!strcmp(ext, "r24")) {
|
||||
context->sfinfo.format = SF_FORMAT_RAW | SF_FORMAT_PCM_24;
|
||||
context->sfinfo.channels = 1;
|
||||
context->sfinfo.samplerate = 24000;
|
||||
} else if (!strcmp(ext, "r32")) {
|
||||
context->sfinfo.format = SF_FORMAT_RAW | SF_FORMAT_PCM_32;
|
||||
context->sfinfo.channels = 1;
|
||||
context->sfinfo.samplerate = 32000;
|
||||
} else if (!strcmp(ext, "gsm")) {
|
||||
context->sfinfo.format = SF_FORMAT_RAW | SF_FORMAT_GSM610;
|
||||
context->sfinfo.channels = 1;
|
||||
context->sfinfo.samplerate = 8000;
|
||||
} else if (!strcmp(ext, "ul")) {
|
||||
context->sfinfo.format = SF_FORMAT_RAW | SF_FORMAT_ULAW;
|
||||
context->sfinfo.channels = 1;
|
||||
context->sfinfo.samplerate = 8000;
|
||||
} else if (!strcmp(ext, "al")) {
|
||||
context->sfinfo.format = SF_FORMAT_RAW | SF_FORMAT_ALAW;
|
||||
context->sfinfo.channels = 1;
|
||||
context->sfinfo.samplerate = 8000;
|
||||
} else if (!strcmp(ext, "adpcm")) {
|
||||
context->sfinfo.format = SF_FORMAT_WAV | SF_FORMAT_IMA_ADPCM;
|
||||
context->sfinfo.channels = 1;
|
||||
context->sfinfo.samplerate = 8000;
|
||||
}
|
||||
|
||||
if ((mode & SFM_WRITE) && sf_format_check(&context->sfinfo) == 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error : file format is invalid (0x%08X).\n", context->sfinfo.format);
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
|
||||
alt_len = strlen(path) + 10;
|
||||
switch_zmalloc(alt_path, alt_len);
|
||||
|
||||
switch_copy_string(alt_path, path, alt_len);
|
||||
|
||||
/* This block attempts to add the sample rate to the path
|
||||
if the sample rate is already present in the path it does nothing
|
||||
and reverts to the original file name.
|
||||
*/
|
||||
if ((last = strrchr(alt_path, ps))) {
|
||||
last++;
|
||||
#ifdef WIN32
|
||||
if (strrchr(last, '/')) {
|
||||
last = strrchr(alt_path, '/'); /* do not swallow a forward slash if they are intermixed under windows */
|
||||
last++;
|
||||
}
|
||||
#endif
|
||||
ldup = strdup(last);
|
||||
switch_assert(ldup);
|
||||
switch_snprintf(last, alt_len - (last - alt_path), "%d%s%s", handle->samplerate, SWITCH_PATH_SEPARATOR, ldup);
|
||||
if ((context->handle = sf_open(alt_path, mode, &context->sfinfo))) {
|
||||
path = alt_path;
|
||||
} else {
|
||||
/* Try to find the file at the highest rate possible if we can't find one that matches the exact rate.
|
||||
If we don't find any, we will default back to the original file name.
|
||||
*/
|
||||
for (i = 3; i >= 0; i--) {
|
||||
switch_snprintf(last, alt_len - (last - alt_path), "%d%s%s", rates[i], SWITCH_PATH_SEPARATOR, ldup);
|
||||
if ((context->handle = sf_open(alt_path, mode, &context->sfinfo))) {
|
||||
path = alt_path;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!context->handle) {
|
||||
if ((context->handle = sf_open(path, mode, &context->sfinfo)) == 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening File [%s] [%s]\n", path, sf_strerror(context->handle));
|
||||
status = SWITCH_STATUS_GENERR;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
//switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Opening File [%s] rate %dhz\n", path, context->sfinfo.samplerate);
|
||||
handle->samples = (unsigned int) context->sfinfo.frames;
|
||||
handle->samplerate = context->sfinfo.samplerate;
|
||||
handle->channels = (uint8_t) context->sfinfo.channels;
|
||||
handle->format = context->sfinfo.format;
|
||||
handle->sections = context->sfinfo.sections;
|
||||
handle->seekable = context->sfinfo.seekable;
|
||||
handle->speed = 0;
|
||||
handle->private_info = context;
|
||||
|
||||
if (switch_test_flag(handle, SWITCH_FILE_WRITE_APPEND)) {
|
||||
handle->pos = sf_seek(context->handle, 0, SEEK_END);
|
||||
} else {
|
||||
sf_count_t frames = 0;
|
||||
sf_command(context->handle, SFC_FILE_TRUNCATE, &frames, sizeof(frames));
|
||||
}
|
||||
|
||||
|
||||
end:
|
||||
|
||||
switch_safe_free(alt_path);
|
||||
switch_safe_free(ldup);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static switch_status_t sndfile_file_truncate(switch_file_handle_t *handle, int64_t offset)
|
||||
{
|
||||
sndfile_context *context = handle->private_info;
|
||||
sf_command(context->handle, SFC_FILE_TRUNCATE, &offset, sizeof(offset));
|
||||
handle->pos = 0;
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static switch_status_t sndfile_file_close(switch_file_handle_t *handle)
|
||||
{
|
||||
sndfile_context *context = handle->private_info;
|
||||
|
||||
sf_close(context->handle);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static switch_status_t sndfile_file_seek(switch_file_handle_t *handle, unsigned int *cur_sample, int64_t samples, int whence)
|
||||
{
|
||||
sndfile_context *context = handle->private_info;
|
||||
|
||||
if (!handle->seekable) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "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;
|
||||
}
|
||||
|
||||
static switch_status_t sndfile_file_read(switch_file_handle_t *handle, void *data, size_t *len)
|
||||
{
|
||||
size_t inlen = *len;
|
||||
sndfile_context *context = handle->private_info;
|
||||
|
||||
if (switch_test_flag(handle, SWITCH_FILE_DATA_RAW)) {
|
||||
*len = (size_t) sf_read_raw(context->handle, data, inlen);
|
||||
} else if (switch_test_flag(handle, SWITCH_FILE_DATA_INT)) {
|
||||
*len = (size_t) sf_readf_int(context->handle, (int *) data, inlen);
|
||||
} else if (switch_test_flag(handle, SWITCH_FILE_DATA_SHORT)) {
|
||||
*len = (size_t) sf_readf_short(context->handle, (short *) data, inlen);
|
||||
} else if (switch_test_flag(handle, SWITCH_FILE_DATA_FLOAT)) {
|
||||
*len = (size_t) sf_readf_float(context->handle, (float *) data, inlen);
|
||||
} else if (switch_test_flag(handle, SWITCH_FILE_DATA_DOUBLE)) {
|
||||
*len = (size_t) sf_readf_double(context->handle, (double *) data, inlen);
|
||||
} else {
|
||||
*len = (size_t) sf_readf_int(context->handle, (int *) data, inlen);
|
||||
}
|
||||
|
||||
handle->pos += *len;
|
||||
handle->sample_count += *len;
|
||||
|
||||
return *len ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
static switch_status_t sndfile_file_write(switch_file_handle_t *handle, void *data, size_t *len)
|
||||
{
|
||||
size_t inlen = *len;
|
||||
sndfile_context *context = handle->private_info;
|
||||
|
||||
if (switch_test_flag(handle, SWITCH_FILE_DATA_RAW)) {
|
||||
*len = (size_t) sf_write_raw(context->handle, data, inlen);
|
||||
} else if (switch_test_flag(handle, SWITCH_FILE_DATA_INT)) {
|
||||
*len = (size_t) sf_writef_int(context->handle, (int *) data, inlen);
|
||||
} else if (switch_test_flag(handle, SWITCH_FILE_DATA_SHORT)) {
|
||||
*len = (size_t) sf_writef_short(context->handle, (short *) data, inlen);
|
||||
} else if (switch_test_flag(handle, SWITCH_FILE_DATA_FLOAT)) {
|
||||
*len = (size_t) sf_writef_float(context->handle, (float *) data, inlen);
|
||||
} else if (switch_test_flag(handle, SWITCH_FILE_DATA_DOUBLE)) {
|
||||
*len = (size_t) sf_writef_double(context->handle, (double *) data, inlen);
|
||||
} else {
|
||||
*len = (size_t) sf_writef_int(context->handle, (int *) data, inlen);
|
||||
}
|
||||
|
||||
handle->sample_count += *len;
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static switch_status_t sndfile_file_set_string(switch_file_handle_t *handle, switch_audio_col_t col, const char *string)
|
||||
{
|
||||
sndfile_context *context = handle->private_info;
|
||||
|
||||
return sf_set_string(context->handle, (int) col, string) ? SWITCH_STATUS_FALSE : SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static switch_status_t sndfile_file_get_string(switch_file_handle_t *handle, switch_audio_col_t col, const char **string)
|
||||
{
|
||||
sndfile_context *context = handle->private_info;
|
||||
const char *s;
|
||||
|
||||
if ((s = sf_get_string(context->handle, (int) col))) {
|
||||
*string = s;
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
/* Registration */
|
||||
|
||||
static char **supported_formats;
|
||||
|
||||
static switch_status_t setup_formats(void)
|
||||
{
|
||||
SF_FORMAT_INFO info;
|
||||
SF_INFO sfinfo;
|
||||
char buffer[128];
|
||||
int format, major_count, subtype_count, m, s;
|
||||
int len, x, skip;
|
||||
char *extras[] = { "r8", "r16", "r24", "r32", "gsm", "ul", "al", "adpcm", NULL };
|
||||
int exlen = (sizeof(extras) / sizeof(extras[0]));
|
||||
buffer[0] = 0;
|
||||
|
||||
sf_command(NULL, SFC_GET_LIB_VERSION, buffer, sizeof(buffer));
|
||||
if (strlen(buffer) < 1) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, "Line %d: could not retrieve lib version.\n", __LINE__);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "\nLibSndFile Version : %s Supported Formats\n", buffer);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "================================================================================\n");
|
||||
sf_command(NULL, SFC_GET_FORMAT_MAJOR_COUNT, &major_count, sizeof(int));
|
||||
sf_command(NULL, SFC_GET_FORMAT_SUBTYPE_COUNT, &subtype_count, sizeof(int));
|
||||
|
||||
sfinfo.channels = 1;
|
||||
len = ((major_count + (exlen + 2)) * sizeof(char *));
|
||||
supported_formats = switch_core_permanent_alloc(len);
|
||||
|
||||
len = 0;
|
||||
for (m = 0; m < major_count; m++) {
|
||||
skip = 0;
|
||||
info.format = m;
|
||||
sf_command(NULL, SFC_GET_FORMAT_MAJOR, &info, sizeof(info));
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_INFO, "%s (extension \"%s\")\n", info.name, info.extension);
|
||||
for (x = 0; x < len; x++) {
|
||||
if (supported_formats[x] == info.extension) {
|
||||
skip++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!skip) {
|
||||
char *p;
|
||||
struct format_map *map = switch_core_permanent_alloc(sizeof(*map));
|
||||
switch_assert(map);
|
||||
|
||||
map->ext = switch_core_permanent_strdup(info.extension);
|
||||
map->uext = switch_core_permanent_strdup(info.extension);
|
||||
map->format = info.format;
|
||||
if (map->ext) {
|
||||
for (p = map->ext; *p; p++) {
|
||||
*p = (char) switch_tolower(*p);
|
||||
}
|
||||
switch_core_hash_insert(globals.format_hash, map->ext, map);
|
||||
}
|
||||
if (map->uext) {
|
||||
for (p = map->uext; *p; p++) {
|
||||
*p = (char) switch_toupper(*p);
|
||||
}
|
||||
switch_core_hash_insert(globals.format_hash, map->uext, map);
|
||||
}
|
||||
supported_formats[len++] = (char *) info.extension;
|
||||
}
|
||||
format = info.format;
|
||||
|
||||
for (s = 0; s < subtype_count; s++) {
|
||||
info.format = s;
|
||||
sf_command(NULL, SFC_GET_FORMAT_SUBTYPE, &info, sizeof(info));
|
||||
format = (format & SF_FORMAT_TYPEMASK) | info.format;
|
||||
sfinfo.format = format;
|
||||
/*
|
||||
if (sf_format_check(&sfinfo)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, " %s\n", info.name);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
for (m = 0; m < exlen; m++) {
|
||||
supported_formats[len++] = extras[m];
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_NOTICE, "================================================================================\n");
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_sndfile_load)
|
||||
{
|
||||
switch_file_interface_t *file_interface;
|
||||
|
||||
if (switch_core_new_memory_pool(&module_pool) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "OH OH no pool\n");
|
||||
return SWITCH_STATUS_TERM;
|
||||
}
|
||||
|
||||
switch_core_hash_init(&globals.format_hash, module_pool);
|
||||
|
||||
if (setup_formats() != SWITCH_STATUS_SUCCESS) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
/* connect my internal structure to the blank pointer passed to me */
|
||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||
file_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_FILE_INTERFACE);
|
||||
file_interface->interface_name = modname;
|
||||
file_interface->extens = supported_formats;
|
||||
file_interface->file_open = sndfile_file_open;
|
||||
file_interface->file_close = sndfile_file_close;
|
||||
file_interface->file_truncate = sndfile_file_truncate;
|
||||
file_interface->file_read = sndfile_file_read;
|
||||
file_interface->file_write = sndfile_file_write;
|
||||
file_interface->file_seek = sndfile_file_seek;
|
||||
file_interface->file_set_string = sndfile_file_set_string;
|
||||
file_interface->file_get_string = sndfile_file_get_string;
|
||||
|
||||
/* indicate that the module should continue to be loaded */
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_sndfile_shutdown)
|
||||
{
|
||||
switch_core_hash_destroy(&globals.format_hash);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4:
|
||||
*/
|
|
@ -1,38 +0,0 @@
|
|||
***************
|
||||
*** 5555,5561 ****
|
||||
SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "EventConsumer_pop" "', argument " "2"" of type '" "int""'");
|
||||
}
|
||||
arg2 = static_cast< int >(val2);
|
||||
result = (Event *)(arg1)->pop(arg2);
|
||||
resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_Event, SWIG_POINTER_OWN | 0 );
|
||||
return resultobj;
|
||||
fail:
|
||||
--- 5555,5563 ----
|
||||
SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "EventConsumer_pop" "', argument " "2"" of type '" "int""'");
|
||||
}
|
||||
arg2 = static_cast< int >(val2);
|
||||
+ Py_BEGIN_ALLOW_THREADS;
|
||||
result = (Event *)(arg1)->pop(arg2);
|
||||
+ Py_END_ALLOW_THREADS;
|
||||
resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_Event, SWIG_POINTER_OWN | 0 );
|
||||
return resultobj;
|
||||
fail:
|
||||
***************
|
||||
*** 5577,5583 ****
|
||||
SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "EventConsumer_pop" "', argument " "1"" of type '" "EventConsumer *""'");
|
||||
}
|
||||
arg1 = reinterpret_cast< EventConsumer * >(argp1);
|
||||
result = (Event *)(arg1)->pop();
|
||||
resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_Event, SWIG_POINTER_OWN | 0 );
|
||||
return resultobj;
|
||||
fail:
|
||||
--- 5579,5587 ----
|
||||
SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "EventConsumer_pop" "', argument " "1"" of type '" "EventConsumer *""'");
|
||||
}
|
||||
arg1 = reinterpret_cast< EventConsumer * >(argp1);
|
||||
+ Py_BEGIN_ALLOW_THREADS;
|
||||
result = (Event *)(arg1)->pop();
|
||||
+ Py_END_ALLOW_THREADS;
|
||||
resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_Event, SWIG_POINTER_OWN | 0 );
|
||||
return resultobj;
|
||||
fail:
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1331,7 +1331,7 @@ static const char *switch_inet_ntop4(const unsigned char *src, char *dst, size_t
|
|||
return strcpy(dst, tmp);
|
||||
}
|
||||
|
||||
#if HAVE_SIN6 || (defined(NTDDI_VERSION) && (NTDDI_VERSION < NTDDI_VISTA))
|
||||
#if HAVE_SIN6 || defined(NTDDI_VERSION)
|
||||
/* const char *
|
||||
* inet_ntop6(src, dst, size)
|
||||
* convert IPv6 binary address into presentation (printable) format
|
||||
|
@ -1488,7 +1488,7 @@ SWITCH_DECLARE(char *) get_addr6(char *buf, switch_size_t len, struct sockaddr_i
|
|||
*buf = '\0';
|
||||
|
||||
if (sa) {
|
||||
#if defined(NTDDI_VERSION) && (NTDDI_VERSION < NTDDI_VISTA)
|
||||
#if defined(NTDDI_VERSION)
|
||||
switch_inet_ntop6((unsigned char*)sa, buf, len);
|
||||
#else
|
||||
inet_ntop(AF_INET6, sa, buf, len);
|
||||
|
|
Loading…
Reference in New Issue